root/samples/cgroup/cgroup_event_listener.c
// SPDX-License-Identifier: GPL-2.0
/*
 * cgroup_event_listener.c - Simple listener of cgroup events
 *
 * Copyright (C) Kirill A. Shutemov <kirill@shutemov.name>
 */

#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <sys/eventfd.h>

#define USAGE_STR "Usage: cgroup_event_listener <path-to-control-file> <args>"

int main(int argc, char **argv)
{
        int efd = -1;
        int cfd = -1;
        int event_control = -1;
        char event_control_path[PATH_MAX];
        char line[LINE_MAX];
        int ret;

        if (argc != 3)
                errx(1, "%s", USAGE_STR);

        cfd = open(argv[1], O_RDONLY);
        if (cfd == -1)
                err(1, "Cannot open %s", argv[1]);

        ret = snprintf(event_control_path, PATH_MAX, "%s/cgroup.event_control",
                        dirname(argv[1]));
        if (ret >= PATH_MAX)
                errx(1, "Path to cgroup.event_control is too long");

        event_control = open(event_control_path, O_WRONLY);
        if (event_control == -1)
                err(1, "Cannot open %s", event_control_path);

        efd = eventfd(0, 0);
        if (efd == -1)
                err(1, "eventfd() failed");

        ret = snprintf(line, LINE_MAX, "%d %d %s", efd, cfd, argv[2]);
        if (ret >= LINE_MAX)
                errx(1, "Arguments string is too long");

        ret = write(event_control, line, strlen(line) + 1);
        if (ret == -1)
                err(1, "Cannot write to cgroup.event_control");

        while (1) {
                uint64_t result;

                ret = read(efd, &result, sizeof(result));
                if (ret == -1) {
                        if (errno == EINTR)
                                continue;
                        err(1, "Cannot read from eventfd");
                }
                assert(ret == sizeof(result));

                ret = access(event_control_path, W_OK);
                if ((ret == -1) && (errno == ENOENT)) {
                        puts("The cgroup seems to have removed.");
                        break;
                }

                if (ret == -1)
                        err(1, "cgroup.event_control is not accessible any more");

                printf("%s %s: crossed\n", argv[1], argv[2]);
        }

        return 0;
}