diff options
Diffstat (limited to 'package/busybox/busybox-1.10.1-mdev.patch')
-rw-r--r-- | package/busybox/busybox-1.10.1-mdev.patch | 510 |
1 files changed, 510 insertions, 0 deletions
diff --git a/package/busybox/busybox-1.10.1-mdev.patch b/package/busybox/busybox-1.10.1-mdev.patch new file mode 100644 index 000000000..b5788829a --- /dev/null +++ b/package/busybox/busybox-1.10.1-mdev.patch @@ -0,0 +1,510 @@ +--- busybox-1.10.1/util-linux/mdev.c Sat Apr 19 05:50:39 2008 ++++ busybox-1.10.1-mdev/util-linux/mdev.c Sat Apr 26 17:15:54 2008 +@@ -12,6 +12,8 @@ + #include "libbb.h" + #include "xregex.h" + ++#define ENABLE_FEATURE_MDEV_RENAME_REGEXP 1 ++ + struct globals { + int root_major, root_minor; + }; +@@ -21,7 +23,21 @@ + + #define MAX_SYSFS_DEPTH 3 /* prevent infinite loops in /sys symlinks */ + ++/* We use additional 64+ bytes in make_device() */ ++#define SCRATCH_SIZE 80 ++ ++static char *next_field(char *s) ++{ ++ char *end = skip_non_whitespace(s); ++ s = skip_whitespace(end); ++ *end = '\0'; ++ if (*s == '\0') ++ s = NULL; ++ return s; ++} ++ + /* mknod in /dev based on a path like "/sys/block/hda/hda1" */ ++/* NB: "mdev -s" may call us many times, do not leak memory/fds! */ + static void make_device(char *path, int delete) + { + const char *device_name; +@@ -29,7 +45,7 @@ + int mode = 0660; + uid_t uid = 0; + gid_t gid = 0; +- char *temp = path + strlen(path); ++ char *dev_maj_min = path + strlen(path); + char *command = NULL; + char *alias = NULL; + +@@ -42,156 +58,177 @@ + * also depend on path having writeable space after it. + */ + if (!delete) { +- strcat(path, "/dev"); +- len = open_read_close(path, temp + 1, 64); +- *temp++ = 0; ++ strcpy(dev_maj_min, "/dev"); ++ len = open_read_close(path, dev_maj_min + 1, 64); ++ *dev_maj_min++ = '\0'; + if (len < 1) { +- if (ENABLE_FEATURE_MDEV_EXEC) +- /* no "dev" file, so just try to run script */ +- *temp = 0; +- else ++ if (!ENABLE_FEATURE_MDEV_EXEC) + return; ++ /* no "dev" file, so just try to run script */ ++ *dev_maj_min = '\0'; + } + } + + /* Determine device name, type, major and minor */ + device_name = bb_basename(path); +- type = (path[5] == 'c' ? S_IFCHR : S_IFBLK); ++ /* http://kernel.org/doc/pending/hotplug.txt says that only ++ * "/sys/block/..." is for block devices. "sys/bus" etc is not! */ ++ type = (strncmp(&path[5], "block/", 6) == 0 ? S_IFBLK : S_IFCHR); + + if (ENABLE_FEATURE_MDEV_CONF) { + FILE *fp; +- char *line, *vline; ++ char *line, *val, *next; + unsigned lineno = 0; + +- /* If we have a config file, look up the user settings */ ++ /* If we have config file, look up user settings */ + fp = fopen_or_warn("/etc/mdev.conf", "r"); + if (!fp) + goto end_parse; + +- while ((vline = line = xmalloc_getline(fp)) != NULL) { +- int field; ++ while ((line = xmalloc_getline(fp)) != NULL) { ++ regmatch_t off[1+9*ENABLE_FEATURE_MDEV_RENAME_REGEXP]; + +- /* A pristine copy for command execution. */ +- char *orig_line; +- if (ENABLE_FEATURE_MDEV_EXEC) +- orig_line = xstrdup(line); +- + ++lineno; ++ trim(line); ++ if (!line[0]) ++ goto next_line; + +- /* Three fields: regex, uid:gid, mode */ +- for (field = 0; field < (3 + ENABLE_FEATURE_MDEV_RENAME + ENABLE_FEATURE_MDEV_EXEC); ++field) { ++ /* Fields: regex uid:gid mode [alias] [cmd] */ + +- /* Find a non-empty field */ +- char *val; +- do { +- val = strtok(vline, " \t"); +- vline = NULL; +- } while (val && !*val); +- if (!val) { +- if (field) +- break; +- else +- goto next_line; +- } ++ /* 1st field: regex to match this device */ ++ next = next_field(line); ++ { ++ regex_t match; ++ int result; + +- if (field == 0) { ++ /* Is this it? */ ++ xregcomp(&match, line, REG_EXTENDED); ++ result = regexec(&match, device_name, ARRAY_SIZE(off), off, 0); ++ regfree(&match); + +- /* Regex to match this device */ +- regex_t match; +- regmatch_t off; +- int result; ++ //bb_error_msg("matches:"); ++ //for (int i = 0; i < ARRAY_SIZE(off); i++) { ++ // if (off[i].rm_so < 0) continue; ++ // bb_error_msg("match %d: '%.*s'\n", i, ++ // (int)(off[i].rm_eo - off[i].rm_so), ++ // device_name + off[i].rm_so); ++ //} + +- /* Is this it? */ +- xregcomp(&match, val, REG_EXTENDED); +- result = regexec(&match, device_name, 1, &off, 0); +- regfree(&match); ++ /* If not this device, skip rest of line */ ++ /* (regexec returns whole pattern as "range" 0) */ ++ if (result || off[0].rm_so || off[0].rm_eo != strlen(device_name)) ++ goto next_line; ++ } + +- /* If not this device, skip rest of line */ +- if (result || off.rm_so || off.rm_eo != strlen(device_name)) +- goto next_line; ++ /* This line matches: stop parsing the file ++ * after parsing the rest of fields */ + +- } else if (field == 1) { ++ /* 2nd field: uid:gid - device ownership */ ++ if (!next) /* field must exist */ ++ bb_error_msg_and_die("bad line %u", lineno); ++ val = next; ++ next = next_field(val); ++ { ++ struct passwd *pass; ++ struct group *grp; ++ char *str_uid = val; ++ char *str_gid = strchrnul(val, ':'); + +- /* uid:gid device ownership */ +- struct passwd *pass; +- struct group *grp; ++ if (*str_gid) ++ *str_gid++ = '\0'; ++ /* Parse UID */ ++ pass = getpwnam(str_uid); ++ if (pass) ++ uid = pass->pw_uid; ++ else ++ uid = strtoul(str_uid, NULL, 10); ++ /* Parse GID */ ++ grp = getgrnam(str_gid); ++ if (grp) ++ gid = grp->gr_gid; ++ else ++ gid = strtoul(str_gid, NULL, 10); ++ } + +- char *str_uid = val; +- char *str_gid = strchr(val, ':'); +- if (str_gid) +- *str_gid = '\0', ++str_gid; ++ /* 3rd field: mode - device permissions */ ++ if (!next) /* field must exist */ ++ bb_error_msg_and_die("bad line %u", lineno); ++ val = next; ++ next = next_field(val); ++ mode = strtoul(val, NULL, 8); + +- /* Parse UID */ +- pass = getpwnam(str_uid); +- if (pass) +- uid = pass->pw_uid; +- else +- uid = strtoul(str_uid, NULL, 10); ++ /* 4th field (opt): >alias */ ++ if (ENABLE_FEATURE_MDEV_RENAME) { ++ if (!next) ++ break; ++ val = next; ++ next = next_field(val); ++ if (*val == '>') { ++#if ENABLE_FEATURE_MDEV_RENAME_REGEXP ++ /* substitute %1..9 with off[1..9], if any */ ++ char *s, *p; ++ unsigned i, n; + +- /* parse GID */ +- grp = getgrnam(str_gid); +- if (grp) +- gid = grp->gr_gid; +- else +- gid = strtoul(str_gid, NULL, 10); ++ n = 0; ++ s = val; ++ while (*s && *s++ == '%') ++ n++; + +- } else if (field == 2) { +- +- /* Mode device permissions */ +- mode = strtoul(val, NULL, 8); +- +- } else if (ENABLE_FEATURE_MDEV_RENAME && field == 3) { +- +- if (*val != '>') +- ++field; +- else +- alias = xstrdup(val + 1); +- ++ p = alias = xzalloc(strlen(val) + n * strlen(device_name)); ++ s = val + 1; ++ while (*s) { ++ *p = *s; ++ if ('%' == *s) { ++ i = (s[1] - '0'); ++ if (i <= 9 && off[i].rm_so >= 0) { ++ n = off[i].rm_eo - off[i].rm_so; ++ strncpy(p, device_name + off[i].rm_so, n); ++ p += n - 1; ++ s++; ++ } ++ } ++ p++; ++ s++; ++ } ++#else ++ alias = xstrdup(val + 1); ++#endif + } ++ } + +- if (ENABLE_FEATURE_MDEV_EXEC && field == 3 + ENABLE_FEATURE_MDEV_RENAME) { ++ /* The rest (opt): command to run */ ++ if (!next) ++ break; ++ val = next; ++ if (ENABLE_FEATURE_MDEV_EXEC) { ++ const char *s = "@$*"; ++ const char *s2 = strchr(s, *val); + +- /* Optional command to run */ +- const char *s = "@$*"; +- const char *s2 = strchr(s, *val); ++ if (!s2) ++ bb_error_msg_and_die("bad line %u", lineno); + +- if (!s2) { +- /* Force error */ +- field = 1; +- break; +- } +- +- /* Correlate the position in the "@$*" with the delete +- * step so that we get the proper behavior. +- */ +- if ((s2 - s + 1) & (1 << delete)) +- command = xstrdup(orig_line + (val + 1 - line)); ++ /* Correlate the position in the "@$*" with the delete ++ * step so that we get the proper behavior: ++ * @cmd: run on create ++ * $cmd: run on delete ++ * *cmd: run on both ++ */ ++ if ((s2 - s + 1) /*1/2/3*/ & /*1/2*/ (1 + delete)) { ++ command = xstrdup(val + 1); + } + } +- +- /* Did everything parse happily? */ +- if (field <= 2) +- bb_error_msg_and_die("bad line %u", lineno); +- ++ /* end of field parsing */ ++ break; /* we found matching line, stop */ + next_line: + free(line); +- if (ENABLE_FEATURE_MDEV_EXEC) +- free(orig_line); +- } ++ } /* end of "while line is read from /etc/mdev.conf" */ + +- if (ENABLE_FEATURE_CLEAN_UP) +- fclose(fp); +- +- end_parse: /* nothing */ ; ++ free(line); /* in case we used "break" to get here */ ++ fclose(fp); + } ++ end_parse: + +- if (!delete) { +- if (sscanf(temp, "%d:%d", &major, &minor) != 2) { +- if (ENABLE_FEATURE_MDEV_EXEC) +- goto skip_creation; +- else +- return; +- } ++ if (!delete && sscanf(dev_maj_min, "%u:%u", &major, &minor) == 2) { + + if (ENABLE_FEATURE_MDEV_RENAME) + unlink(device_name); +@@ -208,39 +245,44 @@ + if (ENABLE_FEATURE_MDEV_RENAME && alias) { + char *dest; + +- temp = strrchr(alias, '/'); +- if (temp) { +- if (temp[1] != '\0') +- /* given a file name, so rename it */ +- *temp = '\0'; ++ /* ">bar/": rename to bar/device_name */ ++ /* ">bar[/]baz": rename to bar[/]baz */ ++ dest = strrchr(alias, '/'); ++ if (dest) { /* ">bar/[baz]" ? */ ++ *dest = '\0'; /* mkdir bar */ + bb_make_directory(alias, 0755, FILEUTILS_RECUR); +- dest = concat_path_file(alias, device_name); +- } else +- dest = alias; ++ *dest = '/'; ++ if (dest[1] == '\0') { /* ">bar/" => ">bar/device_name" */ ++ dest = alias; ++ alias = concat_path_file(alias, device_name); ++ free(dest); ++ } ++ } + +- rename(device_name, dest); // TODO: xrename? +- symlink(dest, device_name); ++ /* recreate device_name as a symlink to moved device node */ ++ if (rename(device_name, alias) == 0) { ++ symlink(alias, device_name); ++ } + +- if (alias != dest) +- free(alias); +- free(dest); ++ free(alias); + } + } +- skip_creation: /* nothing */ ; + } ++ + if (ENABLE_FEATURE_MDEV_EXEC && command) { +- /* setenv will leak memory, so use putenv */ ++ /* setenv will leak memory, use putenv/unsetenv/free */ + char *s = xasprintf("MDEV=%s", device_name); + putenv(s); + if (system(command) == -1) +- bb_perror_msg_and_die("cannot run %s", command); ++ bb_perror_msg_and_die("can't run '%s'", command); + s[4] = '\0'; + unsetenv(s); + free(s); + free(command); + } ++ + if (delete) +- remove_file(device_name, FILEUTILS_FORCE); ++ unlink(device_name); + } + + /* File callback for /sys/ traversal */ +@@ -249,14 +291,15 @@ + void *userData, + int depth ATTRIBUTE_UNUSED) + { +- size_t len = strlen(fileName) - 4; ++ size_t len = strlen(fileName) - 4; /* can't underflow */ + char *scratch = userData; + +- if (strcmp(fileName + len, "/dev")) ++ /* len check is for paranoid reasons */ ++ if (strcmp(fileName + len, "/dev") || len >= PATH_MAX) + return FALSE; + + strcpy(scratch, fileName); +- scratch[len] = 0; ++ scratch[len] = '\0'; + make_device(scratch, 0); + + return TRUE; +@@ -287,12 +330,6 @@ + int cnt; + int firmware_fd, loading_fd, data_fd; + +- /* check for $FIRMWARE from kernel */ +- /* XXX: dont bother: open(NULL) works same as open("no-such-file") +- * if (!firmware) +- * return; +- */ +- + /* check for /lib/firmware/$FIRMWARE */ + xchdir("/lib/firmware"); + firmware_fd = xopen(firmware, O_RDONLY); +@@ -304,16 +341,15 @@ + xchdir(sysfs_path); + for (cnt = 0; cnt < 30; ++cnt) { + loading_fd = open("loading", O_WRONLY); +- if (loading_fd == -1) +- sleep(1); +- else +- break; ++ if (loading_fd != -1) ++ goto loading; ++ sleep(1); + } +- if (loading_fd == -1) +- goto out; ++ goto out; + ++ loading: + /* tell kernel we're loading by `echo 1 > /sys/$DEVPATH/loading` */ +- if (write(loading_fd, "1", 1) != 1) ++ if (full_write(loading_fd, "1", 1) != 1) + goto out; + + /* load firmware by `cat /lib/firmware/$FIRMWARE > /sys/$DEVPATH/data */ +@@ -324,9 +360,9 @@ + + /* tell kernel result by `echo [0|-1] > /sys/$DEVPATH/loading` */ + if (cnt > 0) +- write(loading_fd, "0", 1); ++ full_write(loading_fd, "0", 1); + else +- write(loading_fd, "-1", 2); ++ full_write(loading_fd, "-1", 2); + + out: + if (ENABLE_FEATURE_CLEAN_UP) { +@@ -341,16 +377,14 @@ + { + char *action; + char *env_path; +- RESERVE_CONFIG_BUFFER(temp,PATH_MAX); ++ RESERVE_CONFIG_BUFFER(temp, PATH_MAX + SCRATCH_SIZE); + + xchdir("/dev"); + +- if (argc == 2 && !strcmp(argv[1],"-s")) { +- ++ if (argc == 2 && !strcmp(argv[1], "-s")) { + /* Scan: + * mdev -s + */ +- + struct stat st; + + xstat("/", &st); +@@ -366,26 +400,27 @@ + fileAction, dirAction, temp, 0); + + } else { +- + /* Hotplug: + * env ACTION=... DEVPATH=... mdev + * ACTION can be "add" or "remove" + * DEVPATH is like "/block/sda" or "/class/input/mice" + */ +- + action = getenv("ACTION"); + env_path = getenv("DEVPATH"); + if (!action || !env_path) + bb_show_usage(); + +- sprintf(temp, "/sys%s", env_path); ++ snprintf(temp, PATH_MAX, "/sys%s", env_path); + if (!strcmp(action, "remove")) + make_device(temp, 1); + else if (!strcmp(action, "add")) { + make_device(temp, 0); + +- if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) +- load_firmware(getenv("FIRMWARE"), temp); ++ if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { ++ char *fw = getenv("FIRMWARE"); ++ if (fw) ++ load_firmware(fw, temp); ++ } + } + } + |