1/* 2 * Copyright 2015 Denys Vlasenko 3 * 4 * Licensed under GPLv2, see file LICENSE in this source tree. 5 */ 6//config:config UEVENT 7//config: bool "uevent (3.1 kb)" 8//config: default y 9//config: help 10//config: uevent is a netlink listener for kernel uevent notifications 11//config: sent via netlink. It is usually used for dynamic device creation. 12 13//applet:IF_UEVENT(APPLET(uevent, BB_DIR_SBIN, BB_SUID_DROP)) 14 15//kbuild:lib-$(CONFIG_UEVENT) += uevent.o 16 17//usage:#define uevent_trivial_usage 18//usage: "[PROG ARGS]" 19//usage:#define uevent_full_usage "\n\n" 20//usage: "uevent runs PROG for every netlink notification." 21//usage: "\n""PROG's environment contains data passed from the kernel." 22//usage: "\n""Typical usage (daemon for dynamic device node creation):" 23//usage: "\n"" # uevent mdev & mdev -s" 24 25#include "libbb.h" 26#include "common_bufsiz.h" 27#include <linux/netlink.h> 28 29#define env ((char **)bb_common_bufsiz1) 30#define INIT_G() do { setup_common_bufsiz(); } while (0) 31enum { 32 MAX_ENV = COMMON_BUFSIZE / sizeof(char*) - 1, 33 // ^^^sizeof(env[0]) instead of sizeof(char*) 34 // makes gcc-6.3.0 emit "strict-aliasing" warning. 35 36 // socket receive buffer of 2MiB proved to be too small: 37 // http://lists.busybox.net/pipermail/busybox/2019-December/087665.html 38 // udevd seems to use a whooping 128MiB. 39 // The socket receive buffer size is just a resource limit. 40 // The buffers are allocated lazily so the memory is not wasted. 41 KERN_RCVBUF = 128 * 1024 * 1024, 42 43 // Might be made smaller: the kernel v5.4 passes up to 32 environment 44 // variables with a total of 2kb on each event. 45 // On top of that the action string and device path are added. 46 USER_RCVBUF = 16 * 1024, 47}; 48 49int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 50int uevent_main(int argc UNUSED_PARAM, char **argv) 51{ 52 int fd; 53 54 INIT_G(); 55 56 argv++; 57 58 // Subscribe for UEVENT kernel messages. 59 // Without a sufficiently big RCVBUF, a ton of simultaneous events 60 // can trigger ENOBUFS on read, which is unrecoverable. 61 // Reproducer: 62 // uevent mdev & 63 // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';' 64 reopen: 65 fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, /*groups:*/ 1 << 0, KERN_RCVBUF); 66 67 for (;;) { 68 char *netbuf; 69 char *s, *end; 70 ssize_t len; 71 int idx; 72 73 // In many cases, a system sits for *days* waiting 74 // for a new uevent notification to come in. 75 // We use a fresh mmap so that buffer is not allocated 76 // until kernel actually starts filling it. 77 netbuf = xmmap_anon(USER_RCVBUF); 78 79 // Here we block, possibly for a very long time 80 len = safe_read(fd, netbuf, USER_RCVBUF - 1); 81 if (len < 0) { 82 if (errno == ENOBUFS) { 83 // Ran out of socket receive buffer 84 bb_simple_error_msg("uevent overrun"); 85 close(fd); 86 munmap(netbuf, USER_RCVBUF); 87 goto reopen; 88 } 89 bb_simple_perror_msg_and_die("read"); 90 } 91 end = netbuf + len; 92 *end = '\0'; 93 94 // Each netlink message starts with "ACTION@/path" 95 // (which we currently ignore), 96 // followed by environment variables. 97 if (!argv[0]) 98 putchar('\n'); 99 idx = 0; 100 s = netbuf; 101 while (s < end) { 102 if (!argv[0]) 103 puts(s); 104 if (strchr(s, '=') && idx < MAX_ENV) 105 env[idx++] = s; 106 s += strlen(s) + 1; 107 } 108 env[idx] = NULL; 109 110 if (argv[0]) { 111 idx = 0; 112 while (env[idx]) 113 putenv(env[idx++]); 114 spawn_and_wait(argv); 115 idx = 0; 116 while (env[idx]) 117 bb_unsetenv(env[idx++]); 118 } 119 munmap(netbuf, USER_RCVBUF); 120 } 121 122 return 0; // not reached 123} 124