diff options
author | Gustavo Zacarias <gustavo@zacarias.com.ar> | 2013-04-23 04:13:18 +0000 |
---|---|---|
committer | Peter Korsgaard <jacmet@sunsite.dk> | 2013-04-23 20:39:23 +0200 |
commit | 1cb4f40a097211687dd7ec0c48508c91b6d819c9 (patch) | |
tree | 0ad4c5516e8bc7da855cc94784c6af126ae43aca /package/busybox | |
parent | 85ffab574935ae07c090e05b5d720e1fb76569c7 (diff) | |
download | buildroot-novena-1cb4f40a097211687dd7ec0c48508c91b6d819c9.tar.gz buildroot-novena-1cb4f40a097211687dd7ec0c48508c91b6d819c9.zip |
busybox 1.21.0: update mdev patch
Update the mdev patch so that subsystem matching is reintroduced.
Signed-off-by: Gustavo Zacarias <gustavo@zacarias.com.ar>
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Diffstat (limited to 'package/busybox')
-rw-r--r-- | package/busybox/1.21.0/busybox-1.21.0-mdev.patch | 640 |
1 files changed, 624 insertions, 16 deletions
diff --git a/package/busybox/1.21.0/busybox-1.21.0-mdev.patch b/package/busybox/1.21.0/busybox-1.21.0-mdev.patch index cb873fafc..8f6c8d80e 100644 --- a/package/busybox/1.21.0/busybox-1.21.0-mdev.patch +++ b/package/busybox/1.21.0/busybox-1.21.0-mdev.patch @@ -1,15 +1,429 @@ --- busybox-1.21.0/util-linux/mdev.c +++ busybox-1.21.0-mdev/util-linux/mdev.c -@@ -661,6 +661,8 @@ static void make_device(char *device_nam +@@ -80,7 +80,7 @@ + //usage: IF_FEATURE_MDEV_CONF( + //usage: "\n" + //usage: "It uses /etc/mdev.conf with lines\n" +-//usage: " [-]DEVNAME UID:GID PERM" ++//usage: " [-][ENV=regex;]...DEVNAME UID:GID PERM" + //usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]") + //usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") + //usage: "\n" +@@ -230,9 +230,34 @@ + * SUBSYSTEM=block + */ + +-static const char keywords[] ALIGN1 = "add\0remove\0change\0"; ++#define DEBUG_LVL 2 ++ ++#if DEBUG_LVL >= 1 ++# define dbg1(...) do { if (G.verbose) bb_error_msg(__VA_ARGS__); } while(0) ++#else ++# define dbg1(...) ((void)0) ++#endif ++#if DEBUG_LVL >= 2 ++# define dbg2(...) do { if (G.verbose >= 2) bb_error_msg(__VA_ARGS__); } while(0) ++#else ++# define dbg2(...) ((void)0) ++#endif ++#if DEBUG_LVL >= 3 ++# define dbg3(...) do { if (G.verbose >= 3) bb_error_msg(__VA_ARGS__); } while(0) ++#else ++# define dbg3(...) ((void)0) ++#endif ++ ++ ++static const char keywords[] ALIGN1 = "add\0remove\0"; // "change\0" + enum { OP_add, OP_remove }; + ++struct envmatch { ++ struct envmatch *next; ++ char *envname; ++ regex_t match; ++}; ++ + struct rule { + bool keep_matching; + bool regex_compiled; +@@ -243,12 +268,14 @@ struct rule { + char *ren_mov; + IF_FEATURE_MDEV_EXEC(char *r_cmd;) + regex_t match; ++ struct envmatch *envmatch; + }; + + struct globals { + int root_major, root_minor; + smallint verbose; + char *subsystem; ++ char *subsys_env; /* for putenv("SUBSYSTEM=subsystem") */ + #if ENABLE_FEATURE_MDEV_CONF + const char *filename; + parser_t *parser; +@@ -256,6 +283,7 @@ struct globals { + unsigned rule_idx; + #endif + struct rule cur_rule; ++ char timestr[sizeof("60.123456")]; + } FIX_ALIASING; + #define G (*(struct globals*)&bb_common_bufsiz1) + #define INIT_G() do { \ +@@ -270,13 +298,6 @@ struct globals { + /* We use additional 64+ bytes in make_device() */ + #define SCRATCH_SIZE 80 + +-#if 0 +-# define dbg(...) bb_error_msg(__VA_ARGS__) +-#else +-# define dbg(...) ((void)0) +-#endif +- +- + #if ENABLE_FEATURE_MDEV_CONF + + static void make_default_cur_rule(void) +@@ -288,14 +309,65 @@ static void make_default_cur_rule(void) + + static void clean_up_cur_rule(void) + { ++ struct envmatch *e; ++ + free(G.cur_rule.envvar); ++ free(G.cur_rule.ren_mov); + if (G.cur_rule.regex_compiled) + regfree(&G.cur_rule.match); +- free(G.cur_rule.ren_mov); + IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) ++ e = G.cur_rule.envmatch; ++ while (e) { ++ free(e->envname); ++ regfree(&e->match); ++ e = e->next; ++ } + make_default_cur_rule(); + } + ++/* In later versions, endofname is in libbb */ ++#define endofname mdev_endofname ++static ++const char* FAST_FUNC ++endofname(const char *name) ++{ ++#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) ++#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) ++ if (!is_name(*name)) ++ return name; ++ while (*++name) { ++ if (!is_in_name(*name)) ++ break; ++ } ++ return name; ++} ++ ++static char *parse_envmatch_pfx(char *val) ++{ ++ struct envmatch **nextp = &G.cur_rule.envmatch; ++ ++ for (;;) { ++ struct envmatch *e; ++ char *semicolon; ++ char *eq = strchr(val, '='); ++ if (!eq /* || eq == val? */) ++ return val; ++ if (endofname(val) != eq) ++ return val; ++ semicolon = strchr(eq, ';'); ++ if (!semicolon) ++ return val; ++ /* ENVVAR=regex;... */ ++ *nextp = e = xzalloc(sizeof(*e)); ++ nextp = &e->next; ++ e->envname = xstrndup(val, eq - val); ++ *semicolon = '\0'; ++ xregcomp(&e->match, eq + 1, REG_EXTENDED); ++ *semicolon = ';'; ++ val = semicolon + 1; ++ } ++} ++ + static void parse_next_rule(void) + { + /* Note: on entry, G.cur_rule is set to default */ +@@ -308,12 +380,13 @@ static void parse_next_rule(void) + break; + + /* Fields: [-]regex uid:gid mode [alias] [cmd] */ +- dbg("token1:'%s'", tokens[1]); ++ dbg3("token1:'%s'", tokens[1]); + + /* 1st field */ + val = tokens[0]; + G.cur_rule.keep_matching = ('-' == val[0]); + val += G.cur_rule.keep_matching; /* swallow leading dash */ ++ val = parse_envmatch_pfx(val); + if (val[0] == '@') { + /* @major,minor[-minor2] */ + /* (useful when name is ambiguous: +@@ -328,8 +401,10 @@ static void parse_next_rule(void) + if (sc == 2) + G.cur_rule.min1 = G.cur_rule.min0; + } else { ++ char *eq = strchr(val, '='); + if (val[0] == '$') { +- char *eq = strchr(++val, '='); ++ /* $ENVVAR=regex ... */ ++ val++; + if (!eq) { + bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); + goto next_rule; +@@ -373,7 +448,7 @@ static void parse_next_rule(void) + clean_up_cur_rule(); + } /* while (config_read) */ + +- dbg("config_close(G.parser)"); ++ dbg3("config_close(G.parser)"); + config_close(G.parser); + G.parser = NULL; + +@@ -390,7 +465,7 @@ static const struct rule *next_rule(void + + /* Open conf file if we didn't do it yet */ + if (!G.parser && G.filename) { +- dbg("config_open('%s')", G.filename); ++ dbg3("config_open('%s')", G.filename); + G.parser = config_open2(G.filename, fopen_for_read); + G.filename = NULL; + } +@@ -399,7 +474,7 @@ static const struct rule *next_rule(void + /* mdev -s */ + /* Do we have rule parsed already? */ + if (G.rule_vec[G.rule_idx]) { +- dbg("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); ++ dbg3("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); + return G.rule_vec[G.rule_idx++]; + } + make_default_cur_rule(); +@@ -416,13 +491,28 @@ static const struct rule *next_rule(void + rule = memcpy(xmalloc(sizeof(G.cur_rule)), &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; +- dbg("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); ++ dbg3("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); + } + } + + return rule; + } + ++static int env_matches(struct envmatch *e) ++{ ++ while (e) { ++ int r; ++ char *val = getenv(e->envname); ++ if (!val) ++ return 0; ++ r = regexec(&e->match, val, /*size*/ 0, /*range[]*/ NULL, /*eflags*/ 0); ++ if (r != 0) /* no match */ ++ return 0; ++ e = e->next; ++ } ++ return 1; ++} ++ + #else + + # define next_rule() (&G.cur_rule) +@@ -479,9 +569,6 @@ static void make_device(char *device_nam + { + int major, minor, type, len; + +- if (G.verbose) +- bb_error_msg("device: %s, %s", device_name, path); +- + /* Try to read major/minor string. Note that the kernel puts \n after + * the data, so we don't need to worry about null terminating the string + * because sscanf() will stop at the first nondigit, which \n is. +@@ -500,8 +587,7 @@ static void make_device(char *device_nam + /* no "dev" file, but we can still run scripts + * based on device name */ + } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) { +- if (G.verbose) +- bb_error_msg("maj,min: %u,%u", major, minor); ++ dbg1("dev %u,%u", major, minor); + } else { + major = -1; + } +@@ -511,7 +597,8 @@ static void make_device(char *device_nam + /* Determine device name, type, major and minor */ + if (!device_name) + device_name = (char*) bb_basename(path); +- /* http://kernel.org/doc/pending/hotplug.txt says that only ++ /* ++ * http://kernel.org/doc/pending/hotplug.txt says that only + * "/sys/block/..." is for block devices. "/sys/bus" etc is not. + * But since 2.6.25 block devices are also in /sys/class/block. + * We use strstr("/block/") to forestall future surprises. +@@ -537,6 +624,8 @@ static void make_device(char *device_nam + rule = next_rule(); + + #if ENABLE_FEATURE_MDEV_CONF ++ if (!env_matches(rule->envmatch)) ++ continue; + if (rule->maj >= 0) { /* @maj,min rule */ + if (major != rule->maj) + continue; +@@ -547,7 +636,7 @@ static void make_device(char *device_nam + } + if (rule->envvar) { /* $envvar=regex rule */ + str_to_match = getenv(rule->envvar); +- dbg("getenv('%s'):'%s'", rule->envvar, str_to_match); ++ dbg3("getenv('%s'):'%s'", rule->envvar, str_to_match); + if (!str_to_match) + continue; + } +@@ -555,7 +644,7 @@ static void make_device(char *device_nam + + if (rule->regex_compiled) { + int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); +- dbg("regex_match for '%s':%d", str_to_match, regex_match); ++ dbg3("regex_match for '%s':%d", str_to_match, regex_match); + //bb_error_msg("matches:"); + //for (int i = 0; i < ARRAY_SIZE(off); i++) { + // if (off[i].rm_so < 0) continue; +@@ -574,9 +663,8 @@ static void make_device(char *device_nam + } + /* else: it's final implicit "match-all" rule */ + rule_matches: ++ dbg2("rule matched, line %d", G.parser ? G.parser->lineno : -1); + #endif +- dbg("rule matched"); +- + /* Build alias name */ + alias = NULL; + if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) { +@@ -619,34 +707,30 @@ static void make_device(char *device_nam + } + } + } +- dbg("alias:'%s'", alias); ++ dbg3("alias:'%s'", alias); + + command = NULL; + IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;) + if (command) { +- const char *s = "$@*"; +- const char *s2 = strchr(s, command[0]); +- + /* Are we running this command now? +- * Run $cmd on delete, @cmd on create, *cmd on both ++ * Run @cmd on create, $cmd on delete, *cmd on any + */ +- if (s2 - s != (operation == OP_remove) || *s2 == '*') { +- /* We are here if: '*', +- * or: '@' and delete = 0, +- * or: '$' and delete = 1 +- */ ++ if ((command[0] == '@' && operation == OP_add) ++ || (command[0] == '$' && operation == OP_remove) ++ || (command[0] == '*') ++ ) { + command++; + } else { + command = NULL; + } + } +- dbg("command:'%s'", command); ++ dbg3("command:'%s'", command); + + /* "Execute" the line we found */ + node_name = device_name; + if (ENABLE_FEATURE_MDEV_RENAME && alias) { + node_name = alias = build_alias(alias, device_name); +- dbg("alias2:'%s'", alias); ++ dbg3("alias2:'%s'", alias); + } + + if (operation == OP_add && major >= 0) { +@@ -656,8 +740,17 @@ static void make_device(char *device_nam + mkdir_recursive(node_name); + *slash = '/'; + } +- if (G.verbose) +- bb_error_msg("mknod: %s (%d,%d) %o", node_name, major, minor, rule->mode | type); ++ if (ENABLE_FEATURE_MDEV_CONF) { ++ dbg1("mknod %s (%d,%d) %o" ++ " %u:%u", ++ node_name, major, minor, rule->mode | type, ++ rule->ugid.uid, rule->ugid.gid ++ ); ++ } else { ++ dbg1("mknod %s (%d,%d) %o", ++ node_name, major, minor, rule->mode | type ++ ); ++ } if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) bb_perror_msg("can't create '%s'", node_name); if (ENABLE_FEATURE_MDEV_CONF) { -+ if (G.verbose) -+ bb_error_msg("chmod: %o chown: %u:%u", rule->mode, rule->ugid.uid, rule->ugid.gid); - chmod(node_name, rule->mode); - chown(node_name, rule->ugid.uid, rule->ugid.gid); +@@ -671,8 +764,7 @@ static void make_device(char *device_nam + //TODO: on devtmpfs, device_name already exists and symlink() fails. + //End result is that instead of symlink, we have two nodes. + //What should be done? +- if (G.verbose) +- bb_error_msg("symlink: %s", device_name); ++ dbg1("symlink: %s", device_name); + symlink(node_name, device_name); + } + } +@@ -681,27 +773,21 @@ static void make_device(char *device_nam + if (ENABLE_FEATURE_MDEV_EXEC && command) { + /* setenv will leak memory, use putenv/unsetenv/free */ + char *s = xasprintf("%s=%s", "MDEV", node_name); +- char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); + putenv(s); +- putenv(s1); +- if (G.verbose) +- bb_error_msg("running: %s", command); ++ dbg1("running: %s", command); + if (system(command) == -1) + bb_perror_msg("can't run '%s'", command); +- bb_unsetenv_and_free(s1); + bb_unsetenv_and_free(s); + } + + if (operation == OP_remove && major >= -1) { + if (ENABLE_FEATURE_MDEV_RENAME && alias) { + if (aliaslink == '>') { +- if (G.verbose) +- bb_error_msg("unlink: %s", device_name); ++ dbg1("unlink: %s", device_name); + unlink(device_name); + } } -@@ -813,6 +815,7 @@ static void load_firmware(const char *fi +- if (G.verbose) +- bb_error_msg("unlink: %s", node_name); ++ dbg1("unlink: %s", node_name); + unlink(node_name); + } + +@@ -746,9 +832,16 @@ static int FAST_FUNC dirAction(const cha + * under /sys/class/ */ + if (1 == depth) { + free(G.subsystem); ++ if (G.subsys_env) { ++ bb_unsetenv_and_free(G.subsys_env); ++ G.subsys_env = NULL; ++ } + G.subsystem = strrchr(fileName, '/'); +- if (G.subsystem) ++ if (G.subsystem) { + G.subsystem = xstrdup(G.subsystem + 1); ++ G.subsys_env = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); ++ putenv(G.subsys_env); ++ } + } + + return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); +@@ -813,12 +906,107 @@ static void load_firmware(const char *fi full_write(loading_fd, "-1", 2); out: @@ -17,19 +431,213 @@ if (ENABLE_FEATURE_CLEAN_UP) { close(firmware_fd); close(loading_fd); -@@ -919,11 +922,13 @@ int mdev_main(int argc UNUSED_PARAM, cha - } + } + } + ++static char *curtime(void) ++{ ++ struct timeval tv; ++ gettimeofday(&tv, NULL); ++ sprintf(G.timestr, "%u.%06u", (unsigned)tv.tv_sec % 60, (unsigned)tv.tv_usec); ++ return G.timestr; ++} ++ ++static void open_mdev_log(const char *seq, unsigned my_pid) ++{ ++ int logfd = open("mdev.log", O_WRONLY | O_APPEND); ++ if (logfd >= 0) { ++ xmove_fd(logfd, STDERR_FILENO); ++ G.verbose = 2; ++ applet_name = xasprintf("%s[%s]", applet_name, seq ? seq : utoa(my_pid)); ++ } ++} ++ ++/* If it exists, does /dev/mdev.seq match $SEQNUM? ++ * If it does not match, earlier mdev is running ++ * in parallel, and we need to wait. ++ * Active mdev pokes us with SIGCHLD to check the new file. ++ */ ++static int ++wait_for_seqfile(const char *seq) ++{ ++ /* We time out after 2 sec */ ++ static const struct timespec ts = { 0, 32*1000*1000 }; ++ int timeout = 2000 / 32; ++ int seq_fd = -1; ++ int do_once = 1; ++ sigset_t set_CHLD; ++ ++ sigemptyset(&set_CHLD); ++ sigaddset(&set_CHLD, SIGCHLD); ++ sigprocmask(SIG_BLOCK, &set_CHLD, NULL); ++ ++ for (;;) { ++ int seqlen; ++ char seqbuf[sizeof(int)*3 + 2]; ++ ++ if (seq_fd < 0) { ++ seq_fd = open("mdev.seq", O_RDWR); ++ if (seq_fd < 0) ++ break; ++ } ++ seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); ++ if (seqlen < 0) { ++ close(seq_fd); ++ seq_fd = -1; ++ break; ++ } ++ seqbuf[seqlen] = '\0'; ++ if (seqbuf[0] == '\n') { ++ /* seed file: write out seq ASAP */ ++ xwrite_str(seq_fd, seq); ++ xlseek(seq_fd, 0, SEEK_SET); ++ dbg2("first seq written"); ++ break; ++ } ++ if (strcmp(seq, seqbuf) == 0) { ++ /* correct idx */ ++ break; ++ } ++ if (do_once) { ++ dbg2("%s waiting for '%s'", curtime(), seqbuf); ++ do_once = 0; ++ } ++ if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { ++ dbg3("woken up"); ++ continue; /* don't decrement timeout! */ ++ } ++ if (--timeout == 0) { ++ dbg1("%s waiting for '%s'", "timed out", seqbuf); ++ break; ++ } ++ } ++ sigprocmask(SIG_UNBLOCK, &set_CHLD, NULL); ++ return seq_fd; ++} ++ ++static void signal_mdevs(unsigned my_pid) ++{ ++ procps_status_t* p = NULL; ++ while ((p = procps_scan(p, PSSCAN_ARGV0)) != NULL) { ++ if (p->pid != my_pid ++ && p->argv0 ++ && strcmp(bb_basename(p->argv0), "mdev") == 0 ++ ) { ++ kill(p->pid, SIGCHLD); ++ } ++ } ++} ++ + int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; + int mdev_main(int argc UNUSED_PARAM, char **argv) + { +@@ -840,8 +1028,8 @@ int mdev_main(int argc UNUSED_PARAM, cha + xchdir("/dev"); + + if (argv[1] && strcmp(argv[1], "-s") == 0) { +- /* Scan: +- * mdev -s ++ /* ++ * Scan: mdev -s + */ + struct stat st; + +@@ -853,6 +1041,8 @@ int mdev_main(int argc UNUSED_PARAM, cha + G.root_major = major(st.st_dev); + G.root_minor = minor(st.st_dev); - { ++ putenv((char*)"ACTION=add"); ++ + /* ACTION_FOLLOWLINKS is needed since in newer kernels + * /sys/block/loop* (for example) are symlinks to dirs, + * not real directories. +@@ -878,11 +1068,13 @@ int mdev_main(int argc UNUSED_PARAM, cha + char *action; + char *env_devname; + char *env_devpath; ++ unsigned my_pid; ++ int seq_fd; + smalluint op; + + /* Hotplug: + * env ACTION=... DEVPATH=... SUBSYSTEM=... [SEQNUM=...] mdev +- * ACTION can be "add" or "remove" ++ * ACTION can be "add", "remove", "change" + * DEVPATH is like "/block/sda" or "/class/input/mice" + */ + action = getenv("ACTION"); +@@ -893,39 +1085,20 @@ int mdev_main(int argc UNUSED_PARAM, cha + if (!action || !env_devpath /*|| !G.subsystem*/) + bb_show_usage(); + fw = getenv("FIRMWARE"); +- /* If it exists, does /dev/mdev.seq match $SEQNUM? +- * If it does not match, earlier mdev is running +- * in parallel, and we need to wait */ + seq = getenv("SEQNUM"); +- if (seq) { +- int timeout = 2000 / 32; /* 2000 msec */ +- do { +- int seqlen; +- char seqbuf[sizeof(int)*3 + 2]; +- +- seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf) - 1); +- if (seqlen < 0) { +- seq = NULL; +- break; +- } +- seqbuf[seqlen] = '\0'; +- if (seqbuf[0] == '\n' /* seed file? */ +- || strcmp(seq, seqbuf) == 0 /* correct idx? */ +- ) { +- break; +- } +- usleep(32*1000); +- } while (--timeout); +- } + +- { - int logfd = open("/dev/mdev.log", O_WRONLY | O_APPEND); -+ int logfd = open("mdev.log", O_WRONLY | O_APPEND); - if (logfd >= 0) { - xmove_fd(logfd, STDERR_FILENO); - G.verbose = 1; +- if (logfd >= 0) { +- xmove_fd(logfd, STDERR_FILENO); +- G.verbose = 1; - bb_error_msg("seq: %s action: %s", seq, action); -+ if (seq) -+ applet_name = xasprintf("%s[%s]", applet_name, seq); -+ bb_error_msg("action: %s", action); +- } +- } ++ my_pid = getpid(); ++ open_mdev_log(seq, my_pid); ++ ++ seq_fd = seq ? wait_for_seqfile(seq) : -1; ++ ++ dbg1("%s " ++ "ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%s" ++ "%s%s", ++ curtime(), ++ action, G.subsystem, env_devname, env_devpath, ++ fw ? " FW:" : "", fw ? fw : "" ++ ); + + snprintf(temp, PATH_MAX, "/sys%s", env_devpath); + if (op == OP_remove) { +@@ -935,16 +1108,18 @@ int mdev_main(int argc UNUSED_PARAM, cha + if (!fw) + make_device(env_devname, temp, op); + } +- else if (op == OP_add) { ++ else { + make_device(env_devname, temp, op); + if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { +- if (fw) ++ if (op == OP_add && fw) + load_firmware(fw, temp); } } +- if (seq) { +- xopen_xwrite_close("mdev.seq", utoa(xatou(seq) + 1)); ++ dbg1("%s exiting", curtime()); ++ if (seq_fd >= 0) { ++ xwrite_str(seq_fd, utoa(xatou(seq) + 1)); ++ signal_mdevs(my_pid); + } + } + |