1/*
2 * cgroup_event_listener.c - Simple listener of cgroup events
3 *
4 * Copyright (C) Kirill A. Shutemov <kirill@shutemov.name>
5 */
6
7#include <assert.h>
8#include <err.h>
9#include <errno.h>
10#include <fcntl.h>
11#include <libgen.h>
12#include <limits.h>
13#include <stdio.h>
14#include <string.h>
15#include <unistd.h>
16
17#include <sys/eventfd.h>
18
19#define USAGE_STR "Usage: cgroup_event_listener <path-to-control-file> <args>"
20
21int main(int argc, char **argv)
22{
23	int efd = -1;
24	int cfd = -1;
25	int event_control = -1;
26	char event_control_path[PATH_MAX];
27	char line[LINE_MAX];
28	int ret;
29
30	if (argc != 3)
31		errx(1, "%s", USAGE_STR);
32
33	cfd = open(argv[1], O_RDONLY);
34	if (cfd == -1)
35		err(1, "Cannot open %s", argv[1]);
36
37	ret = snprintf(event_control_path, PATH_MAX, "%s/cgroup.event_control",
38			dirname(argv[1]));
39	if (ret >= PATH_MAX)
40		errx(1, "Path to cgroup.event_control is too long");
41
42	event_control = open(event_control_path, O_WRONLY);
43	if (event_control == -1)
44		err(1, "Cannot open %s", event_control_path);
45
46	efd = eventfd(0, 0);
47	if (efd == -1)
48		err(1, "eventfd() failed");
49
50	ret = snprintf(line, LINE_MAX, "%d %d %s", efd, cfd, argv[2]);
51	if (ret >= LINE_MAX)
52		errx(1, "Arguments string is too long");
53
54	ret = write(event_control, line, strlen(line) + 1);
55	if (ret == -1)
56		err(1, "Cannot write to cgroup.event_control");
57
58	while (1) {
59		uint64_t result;
60
61		ret = read(efd, &result, sizeof(result));
62		if (ret == -1) {
63			if (errno == EINTR)
64				continue;
65			err(1, "Cannot read from eventfd");
66		}
67		assert(ret == sizeof(result));
68
69		ret = access(event_control_path, W_OK);
70		if ((ret == -1) && (errno == ENOENT)) {
71			puts("The cgroup seems to have removed.");
72			break;
73		}
74
75		if (ret == -1)
76			err(1, "cgroup.event_control is not accessible any more");
77
78		printf("%s %s: crossed\n", argv[1], argv[2]);
79	}
80
81	return 0;
82}
83