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 <errno.h>
9 #include <fcntl.h>
10 #include <libgen.h>
11 #include <limits.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 
16 #include <sys/eventfd.h>
17 
18 #define USAGE_STR "Usage: cgroup_event_listener <path-to-control-file> <args>\n"
19 
main(int argc,char ** argv)20 int main(int argc, char **argv)
21 {
22 	int efd = -1;
23 	int cfd = -1;
24 	int event_control = -1;
25 	char event_control_path[PATH_MAX];
26 	char line[LINE_MAX];
27 	int ret;
28 
29 	if (argc != 3) {
30 		fputs(USAGE_STR, stderr);
31 		return 1;
32 	}
33 
34 	cfd = open(argv[1], O_RDONLY);
35 	if (cfd == -1) {
36 		fprintf(stderr, "Cannot open %s: %s\n", argv[1],
37 				strerror(errno));
38 		goto out;
39 	}
40 
41 	ret = snprintf(event_control_path, PATH_MAX, "%s/cgroup.event_control",
42 			dirname(argv[1]));
43 	if (ret >= PATH_MAX) {
44 		fputs("Path to cgroup.event_control is too long\n", stderr);
45 		goto out;
46 	}
47 
48 	event_control = open(event_control_path, O_WRONLY);
49 	if (event_control == -1) {
50 		fprintf(stderr, "Cannot open %s: %s\n", event_control_path,
51 				strerror(errno));
52 		goto out;
53 	}
54 
55 	efd = eventfd(0, 0);
56 	if (efd == -1) {
57 		perror("eventfd() failed");
58 		goto out;
59 	}
60 
61 	ret = snprintf(line, LINE_MAX, "%d %d %s", efd, cfd, argv[2]);
62 	if (ret >= LINE_MAX) {
63 		fputs("Arguments string is too long\n", stderr);
64 		goto out;
65 	}
66 
67 	ret = write(event_control, line, strlen(line) + 1);
68 	if (ret == -1) {
69 		perror("Cannot write to cgroup.event_control");
70 		goto out;
71 	}
72 
73 	while (1) {
74 		uint64_t result;
75 
76 		ret = read(efd, &result, sizeof(result));
77 		if (ret == -1) {
78 			if (errno == EINTR)
79 				continue;
80 			perror("Cannot read from eventfd");
81 			break;
82 		}
83 		assert(ret == sizeof(result));
84 
85 		ret = access(event_control_path, W_OK);
86 		if ((ret == -1) && (errno == ENOENT)) {
87 				puts("The cgroup seems to have removed.");
88 				ret = 0;
89 				break;
90 		}
91 
92 		if (ret == -1) {
93 			perror("cgroup.event_control "
94 					"is not accessible any more");
95 			break;
96 		}
97 
98 		printf("%s %s: crossed\n", argv[1], argv[2]);
99 	}
100 
101 out:
102 	if (efd >= 0)
103 		close(efd);
104 	if (event_control >= 0)
105 		close(event_control);
106 	if (cfd >= 0)
107 		close(cfd);
108 
109 	return (ret != 0);
110 }
111