source: MondoRescue/branches/3.3/mindi-busybox/util-linux/uevent.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 3.3 KB
Line 
1/*
2 * Copyright 2015 Denys Vlasenko
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6
7//config:config UEVENT
8//config: bool "uevent"
9//config: default y
10//config: select PLATFORM_LINUX
11//config: help
12//config: uevent is a netlink listener for kernel uevent notifications
13//config: sent via netlink. It is usually used for dynamic device creation.
14
15//applet:IF_UEVENT(APPLET(uevent, BB_DIR_SBIN, BB_SUID_DROP))
16
17//kbuild:lib-$(CONFIG_UEVENT) += uevent.o
18
19//usage:#define uevent_trivial_usage
20//usage: "[PROG [ARGS]]"
21//usage:#define uevent_full_usage "\n\n"
22//usage: "uevent runs PROG for every netlink notification."
23//usage: "\n""PROG's environment contains data passed from the kernel."
24//usage: "\n""Typical usage (daemon for dynamic device node creation):"
25//usage: "\n"" # uevent mdev & mdev -s"
26
27#include "libbb.h"
28#include "common_bufsiz.h"
29#include <linux/netlink.h>
30
31#define BUFFER_SIZE 16*1024
32
33#define env ((char **)bb_common_bufsiz1)
34#define INIT_G() do { setup_common_bufsiz(); } while (0)
35enum {
36 MAX_ENV = COMMON_BUFSIZE / sizeof(env[0]) - 1,
37};
38
39#ifndef SO_RCVBUFFORCE
40#define SO_RCVBUFFORCE 33
41#endif
42enum { RCVBUF = 2 * 1024 * 1024 };
43
44int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
45int uevent_main(int argc UNUSED_PARAM, char **argv)
46{
47 struct sockaddr_nl sa;
48 int fd;
49
50 INIT_G();
51
52 argv++;
53
54 // Subscribe for UEVENT kernel messages
55 sa.nl_family = AF_NETLINK;
56 sa.nl_pad = 0;
57 sa.nl_pid = getpid();
58 sa.nl_groups = 1 << 0;
59 fd = xsocket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
60 xbind(fd, (struct sockaddr *) &sa, sizeof(sa));
61 close_on_exec_on(fd);
62
63 // Without a sufficiently big RCVBUF, a ton of simultaneous events
64 // can trigger ENOBUFS on read, which is unrecoverable.
65 // Reproducer:
66 // uevent mdev &
67 // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';'
68 //
69 // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl
70 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, RCVBUF);
71 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, RCVBUF);
72 if (0) {
73 int z;
74 socklen_t zl = sizeof(z);
75 getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &z, &zl);
76 bb_error_msg("SO_RCVBUF:%d", z);
77 }
78
79 for (;;) {
80 char *netbuf;
81 char *s, *end;
82 ssize_t len;
83 int idx;
84
85 // In many cases, a system sits for *days* waiting
86 // for a new uevent notification to come in.
87 // We use a fresh mmap so that buffer is not allocated
88 // until kernel actually starts filling it.
89 netbuf = mmap(NULL, BUFFER_SIZE,
90 PROT_READ | PROT_WRITE,
91 MAP_PRIVATE | MAP_ANON,
92 /* ignored: */ -1, 0);
93 if (netbuf == MAP_FAILED)
94 bb_perror_msg_and_die("mmap");
95
96 // Here we block, possibly for a very long time
97 len = safe_read(fd, netbuf, BUFFER_SIZE - 1);
98 if (len < 0)
99 bb_perror_msg_and_die("read");
100 end = netbuf + len;
101 *end = '\0';
102
103 // Each netlink message starts with "ACTION@/path"
104 // (which we currently ignore),
105 // followed by environment variables.
106 if (!argv[0])
107 putchar('\n');
108 idx = 0;
109 s = netbuf;
110 while (s < end) {
111 if (!argv[0])
112 puts(s);
113 if (strchr(s, '=') && idx < MAX_ENV)
114 env[idx++] = s;
115 s += strlen(s) + 1;
116 }
117 env[idx] = NULL;
118
119 idx = 0;
120 while (env[idx])
121 putenv(env[idx++]);
122 if (argv[0])
123 spawn_and_wait(argv);
124 idx = 0;
125 while (env[idx])
126 bb_unsetenv(env[idx++]);
127 munmap(netbuf, BUFFER_SIZE);
128 }
129
130 return 0; // not reached
131}
Note: See TracBrowser for help on using the repository browser.