1303 files changed, 32187 insertions, 57138 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index e80b58f..a59115d 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -97,6 +97,7 @@ //usage: "If /dev/mdev.log file exists, debug log will be appended to it." #include "libbb.h" +#include "common_bufsiz.h" #include "xregex.h" /* "mdev -s" scans /sys/class/xxx, looking for directories which have dev @@ -283,10 +284,11 @@ struct globals { unsigned rule_idx; #endif struct rule cur_rule; - char timestr[sizeof("60.123456")]; + char timestr[sizeof("HH:MM:SS.123456")]; } FIX_ALIASING; -#define G (*(struct globals*)&bb_common_bufsiz1) +#define G (*(struct globals*)bb_common_bufsiz1) #define INIT_G() do { \ + setup_common_bufsiz(); \ IF_NOT_FEATURE_MDEV_CONF(G.cur_rule.maj = -1;) \ IF_NOT_FEATURE_MDEV_CONF(G.cur_rule.mode = 0660;) \ } while (0) @@ -400,13 +402,13 @@ static void parse_next_rule(void) } /* 2nd field: uid:gid - device ownership */ - if (get_uidgid(&G.cur_rule.ugid, tokens[1], /*allow_numeric:*/ 1) == 0) { + if (get_uidgid(&G.cur_rule.ugid, tokens[1]) == 0) { bb_error_msg("unknown user/group '%s' on line %d", tokens[1], G.parser->lineno); goto next_rule; } /* 3rd field: mode - device permissions */ - bb_parse_mode(tokens[2], &G.cur_rule.mode); + G.cur_rule.mode = bb_parse_mode(tokens[2], G.cur_rule.mode); /* 4th field (opt): ">|=alias" or "!" to not create the node */ val = tokens[3]; @@ -471,7 +473,7 @@ static const struct rule *next_rule(void) if (G.parser) { parse_next_rule(); if (G.rule_vec) { /* mdev -s */ - rule = memcpy(xmalloc(sizeof(G.cur_rule)), &G.cur_rule, sizeof(G.cur_rule)); + rule = xmemdup(&G.cur_rule, sizeof(G.cur_rule)); G.rule_vec = xrealloc_vector(G.rule_vec, 4, G.rule_idx); G.rule_vec[G.rule_idx++] = rule; dbg3("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); @@ -541,8 +543,7 @@ static char *build_alias(char *alias, const char *device_name) /* mknod in /dev based on a path like "/sys/block/hda/hda1" * NB1: path parameter needs to have SCRATCH_SIZE scratch bytes - * after NUL, but we promise to not mangle (IOW: to restore NUL if needed) - * path string. + * after NUL, but we promise to not mangle it (IOW: to restore NUL if needed). * NB2: "mdev -s" may call us many times, do not leak memory/fds! * * device_name = $DEVNAME (may be NULL) @@ -610,7 +611,7 @@ static void make_device(char *device_name, char *path, int operation) * We use strstr("/block/") to forestall future surprises. */ type = S_IFCHR; - if (strstr(path, "/block/") || (G.subsystem && strncmp(G.subsystem, "block", 5) == 0)) + if (strstr(path, "/block/") || (G.subsystem && is_prefixed_with(G.subsystem, "block"))) type = S_IFBLK; #if ENABLE_FEATURE_MDEV_CONF @@ -808,41 +809,39 @@ static void make_device(char *device_name, char *path, int operation) } /* for (;;) */ } -/* File callback for /sys/ traversal */ +/* File callback for /sys/ traversal. + * We act only on "/sys/.../dev" (pseudo)file + */ static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf UNUSED_PARAM, void *userData, int depth UNUSED_PARAM) { size_t len = strlen(fileName) - 4; /* can't underflow */ - char *scratch = userData; - - /* len check is for paranoid reasons */ - if (strcmp(fileName + len, "/dev") != 0 || len >= PATH_MAX) - return FALSE; - - strcpy(scratch, fileName); - scratch[len] = '\0'; - make_device(/*DEVNAME:*/ NULL, scratch, OP_add); - - return TRUE; -} - -/* Directory callback for /sys/ traversal */ -static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, - struct stat *statbuf UNUSED_PARAM, - void *userData UNUSED_PARAM, - int depth) -{ - /* Extract device subsystem -- the name of the directory - * under /sys/class/ */ - if (1 == depth) { + char *path = userData; /* char array[PATH_MAX + SCRATCH_SIZE] */ + char subsys[PATH_MAX]; + int res; + + /* Is it a ".../dev" file? (len check is for paranoid reasons) */ + if (strcmp(fileName + len, "/dev") != 0 || len >= PATH_MAX - 32) + return FALSE; /* not .../dev */ + + strcpy(path, fileName); + path[len] = '\0'; + + /* Read ".../subsystem" symlink in the same directory where ".../dev" is */ + strcpy(subsys, path); + strcpy(subsys + len, "/subsystem"); + res = readlink(subsys, subsys, sizeof(subsys)-1); + if (res > 0) { + subsys[res] = '\0'; free(G.subsystem); if (G.subsys_env) { bb_unsetenv_and_free(G.subsys_env); G.subsys_env = NULL; } - G.subsystem = strrchr(fileName, '/'); + /* Set G.subsystem and $SUBSYSTEM from symlink's last component */ + G.subsystem = strrchr(subsys, '/'); if (G.subsystem) { G.subsystem = xstrdup(G.subsystem + 1); G.subsys_env = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); @@ -850,6 +849,17 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, } } + make_device(/*DEVNAME:*/ NULL, path, OP_add); + + return TRUE; +} + +/* Directory callback for /sys/ traversal */ +static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, + struct stat *statbuf UNUSED_PARAM, + void *userData UNUSED_PARAM, + int depth) +{ return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); } @@ -870,8 +880,9 @@ static void load_firmware(const char *firmware, const char *sysfs_path) int firmware_fd, loading_fd; /* check for /lib/firmware/$FIRMWARE */ - xchdir("/lib/firmware"); - firmware_fd = open(firmware, O_RDONLY); /* can fail */ + firmware_fd = -1; + if (chdir("/lib/firmware") == 0) + firmware_fd = open(firmware, O_RDONLY); /* can fail */ /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */ xchdir(sysfs_path); @@ -923,7 +934,11 @@ static char *curtime(void) { struct timeval tv; gettimeofday(&tv, NULL); - sprintf(G.timestr, "%u.%06u", (unsigned)tv.tv_sec % 60, (unsigned)tv.tv_usec); + sprintf( + strftime_HHMMSS(G.timestr, sizeof(G.timestr), &tv.tv_sec), + ".%06u", + (unsigned)tv.tv_usec + ); return G.timestr; } @@ -943,7 +958,7 @@ static void open_mdev_log(const char *seq, unsigned my_pid) * Active mdev pokes us with SIGCHLD to check the new file. */ static int -wait_for_seqfile(const char *seq) +wait_for_seqfile(unsigned expected_seq) { /* We time out after 2 sec */ static const struct timespec ts = { 0, 32*1000*1000 }; @@ -958,12 +973,14 @@ wait_for_seqfile(const char *seq) for (;;) { int seqlen; - char seqbuf[sizeof(int)*3 + 2]; + char seqbuf[sizeof(long)*3 + 2]; + unsigned seqbufnum; if (seq_fd < 0) { seq_fd = open("mdev.seq", O_RDWR); if (seq_fd < 0) break; + close_on_exec_on(seq_fd); } seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); if (seqlen < 0) { @@ -972,19 +989,27 @@ wait_for_seqfile(const char *seq) break; } seqbuf[seqlen] = '\0'; - if (seqbuf[0] == '\n') { + if (seqbuf[0] == '\n' || seqbuf[0] == '\0') { /* seed file: write out seq ASAP */ - xwrite_str(seq_fd, seq); + xwrite_str(seq_fd, utoa(expected_seq)); xlseek(seq_fd, 0, SEEK_SET); dbg2("first seq written"); break; } - if (strcmp(seq, seqbuf) == 0) { + seqbufnum = atoll(seqbuf); + if (seqbufnum == expected_seq) { /* correct idx */ break; } + if (seqbufnum > expected_seq) { + /* a later mdev runs already (this was seen by users to happen) */ + /* do not overwrite seqfile on exit */ + close(seq_fd); + seq_fd = -1; + break; + } if (do_once) { - dbg2("%s waiting for '%s'", curtime(), seqbuf); + dbg2("%s mdev.seq='%s', need '%u'", curtime(), seqbuf, expected_seq); do_once = 0; } if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { @@ -992,7 +1017,7 @@ wait_for_seqfile(const char *seq) continue; /* don't decrement timeout! */ } if (--timeout == 0) { - dbg1("%s waiting for '%s'", "timed out", seqbuf); + dbg1("%s mdev.seq='%s'", "timed out", seqbuf); break; } } @@ -1049,25 +1074,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) putenv((char*)"ACTION=add"); - /* ACTION_FOLLOWLINKS is needed since in newer kernels - * /sys/block/loop* (for example) are symlinks to dirs, - * not real directories. - * (kernel's CONFIG_SYSFS_DEPRECATED makes them real dirs, - * but we can't enforce that on users) - */ - if (access("/sys/class/block", F_OK) != 0) { - /* Scan obsolete /sys/block only if /sys/class/block - * doesn't exist. Otherwise we'll have dupes. - * Also, do not complain if it doesn't exist. - * Some people configure kernel to have no blockdevs. - */ - recursive_action("/sys/block", - ACTION_RECURSE | ACTION_FOLLOWLINKS | ACTION_QUIET, - fileAction, dirAction, temp, 0); - } - recursive_action("/sys/class", - ACTION_RECURSE | ACTION_FOLLOWLINKS, - fileAction, dirAction, temp, 0); + /* Create all devices from /sys/dev hierarchy */ + recursive_action("/sys/dev", + ACTION_RECURSE | ACTION_FOLLOWLINKS, + fileAction, dirAction, temp, 0); } else { char *fw; char *seq; @@ -1075,6 +1085,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) char *env_devname; char *env_devpath; unsigned my_pid; + unsigned seqnum = seqnum; /* for compiler */ int seq_fd; smalluint op; @@ -1096,7 +1107,11 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) my_pid = getpid(); open_mdev_log(seq, my_pid); - seq_fd = seq ? wait_for_seqfile(seq) : -1; + seq_fd = -1; + if (seq) { + seqnum = atoll(seq); + seq_fd = wait_for_seqfile(seqnum); + } dbg1("%s " "ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%s" @@ -1124,7 +1139,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) dbg1("%s exiting", curtime()); if (seq_fd >= 0) { - xwrite_str(seq_fd, utoa(xatou(seq) + 1)); + xwrite_str(seq_fd, utoa(seqnum + 1)); signal_mdevs(my_pid); } } |