diff options
author | Ron Yorston <rmy@pobox.com> | 2015-05-18 09:36:27 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2015-05-18 09:36:27 +0100 |
commit | 60063627a6d540871061854a362047e6517f821c (patch) | |
tree | 0de228630450c64e085f2e3f5141b5ba17eccab3 /util-linux | |
parent | ec39cb770ddd5c0e085d5c4ee10be65bab5e7a44 (diff) | |
parent | 9a595bb36ded308e6d4336aef2c1cd3ac738a398 (diff) | |
download | busybox-w32-60063627a6d540871061854a362047e6517f821c.tar.gz busybox-w32-60063627a6d540871061854a362047e6517f821c.tar.bz2 busybox-w32-60063627a6d540871061854a362047e6517f821c.zip |
Merge branch 'busybox' into mergeFRP
Diffstat (limited to 'util-linux')
-rw-r--r-- | util-linux/mdev.c | 39 | ||||
-rw-r--r-- | util-linux/uevent.c | 127 | ||||
-rw-r--r-- | util-linux/volume_id/get_devname.c | 2 |
3 files changed, 157 insertions, 11 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index ccc00d365..ca4b91510 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -283,7 +283,7 @@ struct globals { | |||
283 | unsigned rule_idx; | 283 | unsigned rule_idx; |
284 | #endif | 284 | #endif |
285 | struct rule cur_rule; | 285 | struct rule cur_rule; |
286 | char timestr[sizeof("60.123456")]; | 286 | char timestr[sizeof("HH:MM:SS.123456")]; |
287 | } FIX_ALIASING; | 287 | } FIX_ALIASING; |
288 | #define G (*(struct globals*)&bb_common_bufsiz1) | 288 | #define G (*(struct globals*)&bb_common_bufsiz1) |
289 | #define INIT_G() do { \ | 289 | #define INIT_G() do { \ |
@@ -923,7 +923,11 @@ static char *curtime(void) | |||
923 | { | 923 | { |
924 | struct timeval tv; | 924 | struct timeval tv; |
925 | gettimeofday(&tv, NULL); | 925 | gettimeofday(&tv, NULL); |
926 | sprintf(G.timestr, "%u.%06u", (unsigned)tv.tv_sec % 60, (unsigned)tv.tv_usec); | 926 | sprintf( |
927 | strftime_HHMMSS(G.timestr, sizeof(G.timestr), &tv.tv_sec), | ||
928 | ".%06u", | ||
929 | (unsigned)tv.tv_usec | ||
930 | ); | ||
927 | return G.timestr; | 931 | return G.timestr; |
928 | } | 932 | } |
929 | 933 | ||
@@ -943,7 +947,7 @@ static void open_mdev_log(const char *seq, unsigned my_pid) | |||
943 | * Active mdev pokes us with SIGCHLD to check the new file. | 947 | * Active mdev pokes us with SIGCHLD to check the new file. |
944 | */ | 948 | */ |
945 | static int | 949 | static int |
946 | wait_for_seqfile(const char *seq) | 950 | wait_for_seqfile(unsigned expected_seq) |
947 | { | 951 | { |
948 | /* We time out after 2 sec */ | 952 | /* We time out after 2 sec */ |
949 | static const struct timespec ts = { 0, 32*1000*1000 }; | 953 | static const struct timespec ts = { 0, 32*1000*1000 }; |
@@ -958,12 +962,14 @@ wait_for_seqfile(const char *seq) | |||
958 | 962 | ||
959 | for (;;) { | 963 | for (;;) { |
960 | int seqlen; | 964 | int seqlen; |
961 | char seqbuf[sizeof(int)*3 + 2]; | 965 | char seqbuf[sizeof(long)*3 + 2]; |
966 | unsigned seqbufnum; | ||
962 | 967 | ||
963 | if (seq_fd < 0) { | 968 | if (seq_fd < 0) { |
964 | seq_fd = open("mdev.seq", O_RDWR); | 969 | seq_fd = open("mdev.seq", O_RDWR); |
965 | if (seq_fd < 0) | 970 | if (seq_fd < 0) |
966 | break; | 971 | break; |
972 | close_on_exec_on(seq_fd); | ||
967 | } | 973 | } |
968 | seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); | 974 | seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); |
969 | if (seqlen < 0) { | 975 | if (seqlen < 0) { |
@@ -974,17 +980,25 @@ wait_for_seqfile(const char *seq) | |||
974 | seqbuf[seqlen] = '\0'; | 980 | seqbuf[seqlen] = '\0'; |
975 | if (seqbuf[0] == '\n' || seqbuf[0] == '\0') { | 981 | if (seqbuf[0] == '\n' || seqbuf[0] == '\0') { |
976 | /* seed file: write out seq ASAP */ | 982 | /* seed file: write out seq ASAP */ |
977 | xwrite_str(seq_fd, seq); | 983 | xwrite_str(seq_fd, utoa(expected_seq)); |
978 | xlseek(seq_fd, 0, SEEK_SET); | 984 | xlseek(seq_fd, 0, SEEK_SET); |
979 | dbg2("first seq written"); | 985 | dbg2("first seq written"); |
980 | break; | 986 | break; |
981 | } | 987 | } |
982 | if (strcmp(seq, seqbuf) == 0) { | 988 | seqbufnum = atoll(seqbuf); |
989 | if (seqbufnum == expected_seq) { | ||
983 | /* correct idx */ | 990 | /* correct idx */ |
984 | break; | 991 | break; |
985 | } | 992 | } |
993 | if (seqbufnum > expected_seq) { | ||
994 | /* a later mdev runs already (this was seen by users to happen) */ | ||
995 | /* do not overwrite seqfile on exit */ | ||
996 | close(seq_fd); | ||
997 | seq_fd = -1; | ||
998 | break; | ||
999 | } | ||
986 | if (do_once) { | 1000 | if (do_once) { |
987 | dbg2("%s waiting for '%s'", curtime(), seqbuf); | 1001 | dbg2("%s mdev.seq='%s', need '%u'", curtime(), seqbuf, expected_seq); |
988 | do_once = 0; | 1002 | do_once = 0; |
989 | } | 1003 | } |
990 | if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { | 1004 | if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { |
@@ -992,7 +1006,7 @@ wait_for_seqfile(const char *seq) | |||
992 | continue; /* don't decrement timeout! */ | 1006 | continue; /* don't decrement timeout! */ |
993 | } | 1007 | } |
994 | if (--timeout == 0) { | 1008 | if (--timeout == 0) { |
995 | dbg1("%s waiting for '%s'", "timed out", seqbuf); | 1009 | dbg1("%s mdev.seq='%s'", "timed out", seqbuf); |
996 | break; | 1010 | break; |
997 | } | 1011 | } |
998 | } | 1012 | } |
@@ -1075,6 +1089,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
1075 | char *env_devname; | 1089 | char *env_devname; |
1076 | char *env_devpath; | 1090 | char *env_devpath; |
1077 | unsigned my_pid; | 1091 | unsigned my_pid; |
1092 | unsigned seqnum = seqnum; /* for compiler */ | ||
1078 | int seq_fd; | 1093 | int seq_fd; |
1079 | smalluint op; | 1094 | smalluint op; |
1080 | 1095 | ||
@@ -1096,7 +1111,11 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
1096 | my_pid = getpid(); | 1111 | my_pid = getpid(); |
1097 | open_mdev_log(seq, my_pid); | 1112 | open_mdev_log(seq, my_pid); |
1098 | 1113 | ||
1099 | seq_fd = seq ? wait_for_seqfile(seq) : -1; | 1114 | seq_fd = -1; |
1115 | if (seq) { | ||
1116 | seqnum = atoll(seq); | ||
1117 | seq_fd = wait_for_seqfile(seqnum); | ||
1118 | } | ||
1100 | 1119 | ||
1101 | dbg1("%s " | 1120 | dbg1("%s " |
1102 | "ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%s" | 1121 | "ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%s" |
@@ -1124,7 +1143,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
1124 | 1143 | ||
1125 | dbg1("%s exiting", curtime()); | 1144 | dbg1("%s exiting", curtime()); |
1126 | if (seq_fd >= 0) { | 1145 | if (seq_fd >= 0) { |
1127 | xwrite_str(seq_fd, utoa(xatou(seq) + 1)); | 1146 | xwrite_str(seq_fd, utoa(seqnum + 1)); |
1128 | signal_mdevs(my_pid); | 1147 | signal_mdevs(my_pid); |
1129 | } | 1148 | } |
1130 | } | 1149 | } |
diff --git a/util-linux/uevent.c b/util-linux/uevent.c new file mode 100644 index 000000000..fb98b4845 --- /dev/null +++ b/util-linux/uevent.c | |||
@@ -0,0 +1,127 @@ | |||
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 <linux/netlink.h> | ||
29 | |||
30 | #define BUFFER_SIZE 16*1024 | ||
31 | |||
32 | #define env ((char **)&bb_common_bufsiz1) | ||
33 | enum { | ||
34 | MAX_ENV = COMMON_BUFSIZE / sizeof(env[0]) - 1, | ||
35 | }; | ||
36 | |||
37 | #ifndef SO_RCVBUFFORCE | ||
38 | #define SO_RCVBUFFORCE 33 | ||
39 | #endif | ||
40 | static const int RCVBUF = 2 * 1024 * 1024; | ||
41 | |||
42 | int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
43 | int uevent_main(int argc UNUSED_PARAM, char **argv) | ||
44 | { | ||
45 | struct sockaddr_nl sa; | ||
46 | int fd; | ||
47 | |||
48 | argv++; | ||
49 | |||
50 | // Subscribe for UEVENT kernel messages | ||
51 | sa.nl_family = AF_NETLINK; | ||
52 | sa.nl_pad = 0; | ||
53 | sa.nl_pid = getpid(); | ||
54 | sa.nl_groups = 1 << 0; | ||
55 | fd = xsocket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); | ||
56 | xbind(fd, (struct sockaddr *) &sa, sizeof(sa)); | ||
57 | close_on_exec_on(fd); | ||
58 | |||
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 | // | ||
65 | // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl | ||
66 | setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &RCVBUF, sizeof(RCVBUF)); | ||
67 | setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &RCVBUF, sizeof(RCVBUF)); | ||
68 | if (0) { | ||
69 | int z; | ||
70 | socklen_t zl = sizeof(z); | ||
71 | getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &z, &zl); | ||
72 | bb_error_msg("SO_RCVBUF:%d", z); | ||
73 | } | ||
74 | |||
75 | for (;;) { | ||
76 | char *netbuf; | ||
77 | char *s, *end; | ||
78 | ssize_t len; | ||
79 | int idx; | ||
80 | |||
81 | // In many cases, a system sits for *days* waiting | ||
82 | // for a new uevent notification to come in. | ||
83 | // We use a fresh mmap so that buffer is not allocated | ||
84 | // until kernel actually starts filling it. | ||
85 | netbuf = mmap(NULL, BUFFER_SIZE, | ||
86 | PROT_READ | PROT_WRITE, | ||
87 | MAP_PRIVATE | MAP_ANON, | ||
88 | /* ignored: */ -1, 0); | ||
89 | if (netbuf == MAP_FAILED) | ||
90 | bb_perror_msg_and_die("mmap"); | ||
91 | |||
92 | // Here we block, possibly for a very long time | ||
93 | len = safe_read(fd, netbuf, BUFFER_SIZE - 1); | ||
94 | if (len < 0) | ||
95 | bb_perror_msg_and_die("read"); | ||
96 | end = netbuf + len; | ||
97 | *end = '\0'; | ||
98 | |||
99 | // Each netlink message starts with "ACTION@/path" | ||
100 | // (which we currently ignore), | ||
101 | // followed by environment variables. | ||
102 | if (!argv[0]) | ||
103 | putchar('\n'); | ||
104 | idx = 0; | ||
105 | s = netbuf; | ||
106 | while (s < end) { | ||
107 | if (!argv[0]) | ||
108 | puts(s); | ||
109 | if (strchr(s, '=') && idx < MAX_ENV) | ||
110 | env[idx++] = s; | ||
111 | s += strlen(s) + 1; | ||
112 | } | ||
113 | env[idx] = NULL; | ||
114 | |||
115 | idx = 0; | ||
116 | while (env[idx]) | ||
117 | putenv(env[idx++]); | ||
118 | if (argv[0]) | ||
119 | spawn_and_wait(argv); | ||
120 | idx = 0; | ||
121 | while (env[idx]) | ||
122 | bb_unsetenv(env[idx++]); | ||
123 | munmap(netbuf, BUFFER_SIZE); | ||
124 | } | ||
125 | |||
126 | return 0; // not reached | ||
127 | } | ||
diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c index 53bdbdf09..6b97df113 100644 --- a/util-linux/volume_id/get_devname.c +++ b/util-linux/volume_id/get_devname.c | |||
@@ -304,7 +304,7 @@ int resolve_mount_spec(char **fsname) | |||
304 | 304 | ||
305 | if (is_prefixed_with(*fsname, "UUID=")) | 305 | if (is_prefixed_with(*fsname, "UUID=")) |
306 | tmp = get_devname_from_uuid(*fsname + 5); | 306 | tmp = get_devname_from_uuid(*fsname + 5); |
307 | else if (is_prefixed_with(*fsname, "LABEL=") == 0) | 307 | else if (is_prefixed_with(*fsname, "LABEL=")) |
308 | tmp = get_devname_from_label(*fsname + 6); | 308 | tmp = get_devname_from_label(*fsname + 6); |
309 | 309 | ||
310 | if (tmp == *fsname) | 310 | if (tmp == *fsname) |