Linux:在磁盘空间不足的情况下触发实时警报

wea*_*ver 5 linux filesystems

我想订阅一个 inotify 风格的守护进程,以便在给定文件系统上的可用空间低于一定百分比时收到通知。这可能吗?

Mat*_*Ife 4

这是一种基于事件的机制。我没有长时间运行它,所以不能保证它的稳定性。

这使用了一个名为 fanotify 的最新系统调用 API。可能需要 2.6.37 或更高版本的内核才能运行它(例如,EL5 就不可能)。如果您收到投诉,它无法编译,则可能是内核太旧了。

它编译为:

gcc -o 通知程序notifier.c

它的工作方式是这样的:-

./notifier /home/文件 /dev/shm/monit 10

论据如下:

  1. 您要监视的文件系统上的文件。
  2. 超过阈值时将创建的文件的路径(如果低于阈值则被删除)
  3. 应低于阈值的可用空间百分比。

这将设置监视器。文件系统上打开写入标志的每个关闭的文件句柄都会启动事件检查。

#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);
}
Run Code Online (Sandbox Code Playgroud)

从那里您可以使用 inotify 来监视要创建/删除的文件以了解结果。

要进行测试,请将阈值设置为您现在知道违反的阈值,然后触摸受影响的文件系统上的文件。您应该创建监视器文件。

显然,最好将监视器文件放在不在同一文件系统上的某个位置(/dev/shm 是一个好地方)。