Il s'agit d'un mécanisme basé sur les événements. Je ne l'ai pas utilisé pendant de longues périodes et ne peux donc pas garantir sa stabilité.
Cela utilise une API d'appel système très récente appelée fanotify. Vous aurez probablement besoin d'un noyau 2.6.37 ou plus pour l'exécuter (donc EL5 est hors de question, par exemple). Si vous obtenez des plaintes qu'il ne compile pas, c'est probablement que le noyau est trop ancien.
Il compile avec :
gcc -o notifier notifier.c
Le mode de fonctionnement est le suivant:-
./notifier /home/file /dev/shm/monit 10
Les arguments sont les suivants :
- Un fichier sur le système de fichiers que vous voulez surveiller.
- Un chemin vers un fichier qui sera créé si vous dépassez le seuil (et sera supprimé si vous êtes en dessous).
- Un pourcentage d'espace libre qui devrait être disponible pour être sous le seuil.
Ceci va configurer le moniteur. Chaque handle de fichier fermé sur le système de fichiers qui avait un drapeau d'écriture ouvert initie la vérification de l'événement.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <linux/fanotify.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <fcntl.h>
int main(const int argc, const char **argv) {
if (argc < 4) {
fprintf(stderr, "Supply a path to a file on the mountpoint to listen to, a monitor file and a free %% threshold..\n");
exit(1);
}
if (access(argv[1], R_OK) < 0) {
fprintf(stderr, "Unable to read file: %s\n", strerror(errno));
exit(1);
}
int len, rc;
unsigned char donestat = 0, alerted = 0;
const char *path = argv[1];
const char *monpath = argv[2];
int threshold = atoi(argv[3]);
char buf[4096];
struct fanotify_event_metadata *fem = NULL;
int fan_fd = -1;
uint64_t mask = FAN_CLOSE_WRITE;
struct statvfs sfs;
float bfree;
memset(&sfs, 0, sizeof(sfs));
unlink(monpath);
if (threshold <= 0 || threshold >= 100) {
fprintf(stderr, "Incorrect threshold provided");
rc = 1;
goto end;
}
fan_fd = fanotify_init(FAN_CLASS_NOTIF, FAN_CLOEXEC);
if (fan_fd < 0) {
perror("fanotify_init");
rc = 1;
goto end;
}
rc = fanotify_mark(fan_fd, FAN_MARK_ADD|FAN_MARK_MOUNT, mask, AT_FDCWD, path);
if (rc < 0) {
perror("fanotify_mark");
rc = 1;
goto end;
}
while ((len = read(fan_fd, buf, sizeof(buf))) > 0) {
fem = (void *)buf;
donestat = 0;
while (FAN_EVENT_OK(fem, len)) {
if (fem->vers < 2) {
fprintf(stderr, "fanotify is too old\n");
goto end;
}
if (!donestat) {
rc = fstatvfs(fem->fd, &sfs);
if (rc < 0) {
perror("fstatvfs");
rc = 1;
goto end;
}
bfree = 100 - (((float)(sfs.f_blocks - ((sfs.f_blocks - sfs.f_bfree))) / (float)(sfs.f_blocks)) * 100);
if ((bfree < (float)threshold)) {
if (!alerted) {
creat(monpath, S_IRUSR|S_IWUSR);
alerted = 1;
}
}
else {
if (alerted) {
unlink(monpath);
alerted = 0;
}
}
}
donestat = 1;
close(fem->fd);
fem = FAN_EVENT_NEXT(fem, len);
}
}
if (len < 0) {
perror("Read fan_fd");
rc = 1;
goto end;
}
end:
close(fan_fd);
exit(rc);
}
À partir de là, vous pouvez utiliser inotify pour surveiller la création/suppression du fichier et connaître le résultat.
Pour le tester, fixez le seuil à une valeur que vous savez dépassée, puis touchez un fichier sur le système de fichiers concerné. Vous devriez obtenir la création de votre fichier de surveillance.
De toute évidence, il est préférable de placer le fichier de surveillance à un endroit qui n'est pas sur le même système de fichiers (/dev/shm est un bon endroit).
0 votes
Il n'existe pas d'interface dans les noyaux par défaut pour générer des événements qui font cela. Le mieux que vous puissiez faire est d'interroger un fichier fréquemment.
0 votes
Il pourrait y avoir une nouvelle façon de faire cet événement je mettrai à jour avec une réponse si je peux faire une preuve de concept.
0 votes
Qui fera ce que vous voulez mais vous devrez ajouter un effort supplémentaire de votre part pour que inotify fasse <tout ce que vous voulez> lorsque l'événement se réalise.
0 votes
Ce n'est pas une réponse, mais un commentaire pour répondre de MIfe (ce truc idiot de "réputation" ne me permet pas d'ajouter des commentaires). La ligne suivante semble être incorrecte : fanotify_init(FAN_CLASS_NOTIF, FAN_CLOEXEC) Voir la page de manuel : spinics.net/lists/linux-man/msg02302.html Voir aussi les échantillons à : lanedo.com/~aleksander/fanotify qui contient la ligne suivante : fanotify_init(FAN_CLOEXEC, O_RDONLY | O_CLOEXEC | O_LARGEFILE)