diff options
Diffstat (limited to 'util-linux/uevent.c')
-rw-r--r-- | util-linux/uevent.c | 41 |
1 files changed, 12 insertions, 29 deletions
diff --git a/util-linux/uevent.c b/util-linux/uevent.c index 761743f45..7a1d7d4a7 100644 --- a/util-linux/uevent.c +++ b/util-linux/uevent.c | |||
@@ -46,37 +46,19 @@ enum { RCVBUF = 2 * 1024 * 1024 }; | |||
46 | int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 46 | int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
47 | int uevent_main(int argc UNUSED_PARAM, char **argv) | 47 | int uevent_main(int argc UNUSED_PARAM, char **argv) |
48 | { | 48 | { |
49 | struct sockaddr_nl sa; | ||
50 | int fd; | 49 | int fd; |
51 | 50 | ||
52 | INIT_G(); | 51 | INIT_G(); |
53 | 52 | ||
54 | argv++; | 53 | argv++; |
55 | 54 | ||
56 | // Subscribe for UEVENT kernel messages | 55 | // Subscribe for UEVENT kernel messages. |
57 | sa.nl_family = AF_NETLINK; | ||
58 | sa.nl_pad = 0; | ||
59 | sa.nl_pid = getpid(); | ||
60 | sa.nl_groups = 1 << 0; | ||
61 | fd = xsocket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); | ||
62 | xbind(fd, (struct sockaddr *) &sa, sizeof(sa)); | ||
63 | close_on_exec_on(fd); | ||
64 | |||
65 | // Without a sufficiently big RCVBUF, a ton of simultaneous events | 56 | // Without a sufficiently big RCVBUF, a ton of simultaneous events |
66 | // can trigger ENOBUFS on read, which is unrecoverable. | 57 | // can trigger ENOBUFS on read, which is unrecoverable. |
67 | // Reproducer: | 58 | // Reproducer: |
68 | // uevent mdev & | 59 | // uevent mdev & |
69 | // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';' | 60 | // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';' |
70 | // | 61 | fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, /*groups:*/ 1 << 0, RCVBUF); |
71 | // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl | ||
72 | setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, RCVBUF); | ||
73 | setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, RCVBUF); | ||
74 | if (0) { | ||
75 | int z; | ||
76 | socklen_t zl = sizeof(z); | ||
77 | getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &z, &zl); | ||
78 | bb_error_msg("SO_RCVBUF:%d", z); | ||
79 | } | ||
80 | 62 | ||
81 | for (;;) { | 63 | for (;;) { |
82 | char *netbuf; | 64 | char *netbuf; |
@@ -93,12 +75,12 @@ int uevent_main(int argc UNUSED_PARAM, char **argv) | |||
93 | MAP_PRIVATE | MAP_ANON, | 75 | MAP_PRIVATE | MAP_ANON, |
94 | /* ignored: */ -1, 0); | 76 | /* ignored: */ -1, 0); |
95 | if (netbuf == MAP_FAILED) | 77 | if (netbuf == MAP_FAILED) |
96 | bb_perror_msg_and_die("mmap"); | 78 | bb_simple_perror_msg_and_die("mmap"); |
97 | 79 | ||
98 | // Here we block, possibly for a very long time | 80 | // Here we block, possibly for a very long time |
99 | len = safe_read(fd, netbuf, BUFFER_SIZE - 1); | 81 | len = safe_read(fd, netbuf, BUFFER_SIZE - 1); |
100 | if (len < 0) | 82 | if (len < 0) |
101 | bb_perror_msg_and_die("read"); | 83 | bb_simple_perror_msg_and_die("read"); |
102 | end = netbuf + len; | 84 | end = netbuf + len; |
103 | *end = '\0'; | 85 | *end = '\0'; |
104 | 86 | ||
@@ -118,14 +100,15 @@ int uevent_main(int argc UNUSED_PARAM, char **argv) | |||
118 | } | 100 | } |
119 | env[idx] = NULL; | 101 | env[idx] = NULL; |
120 | 102 | ||
121 | idx = 0; | 103 | if (argv[0]) { |
122 | while (env[idx]) | 104 | idx = 0; |
123 | putenv(env[idx++]); | 105 | while (env[idx]) |
124 | if (argv[0]) | 106 | putenv(env[idx++]); |
125 | spawn_and_wait(argv); | 107 | spawn_and_wait(argv); |
126 | idx = 0; | 108 | idx = 0; |
127 | while (env[idx]) | 109 | while (env[idx]) |
128 | bb_unsetenv(env[idx++]); | 110 | bb_unsetenv(env[idx++]); |
111 | } | ||
129 | munmap(netbuf, BUFFER_SIZE); | 112 | munmap(netbuf, BUFFER_SIZE); |
130 | } | 113 | } |
131 | 114 | ||