aboutsummaryrefslogtreecommitdiff
path: root/util-linux
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2015-05-18 09:36:27 +0100
committerRon Yorston <rmy@pobox.com>2015-05-18 09:36:27 +0100
commit60063627a6d540871061854a362047e6517f821c (patch)
tree0de228630450c64e085f2e3f5141b5ba17eccab3 /util-linux
parentec39cb770ddd5c0e085d5c4ee10be65bab5e7a44 (diff)
parent9a595bb36ded308e6d4336aef2c1cd3ac738a398 (diff)
downloadbusybox-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.c39
-rw-r--r--util-linux/uevent.c127
-rw-r--r--util-linux/volume_id/get_devname.c2
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 */
945static int 949static int
946wait_for_seqfile(const char *seq) 950wait_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)
33enum {
34 MAX_ENV = COMMON_BUFSIZE / sizeof(env[0]) - 1,
35};
36
37#ifndef SO_RCVBUFFORCE
38#define SO_RCVBUFFORCE 33
39#endif
40static const int RCVBUF = 2 * 1024 * 1024;
41
42int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
43int 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)