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