diff options
| -rw-r--r-- | toys/pending/mdev.c | 398 | 
1 files changed, 91 insertions, 307 deletions
| diff --git a/toys/pending/mdev.c b/toys/pending/mdev.c index 2aa09bc8..2d98c257 100644 --- a/toys/pending/mdev.c +++ b/toys/pending/mdev.c @@ -29,23 +29,16 @@ config MDEV_CONF      matching devies.  */ -#define FOR_mdev  #include "toys.h"  // todo, open() block devices to trigger partition scanning. -GLOBALS( -  char *devname; -  int root_maj, root_min, verbose; -) - -  // mknod in /dev based on a path like "/sys/block/hda/hda1" -static void make_device(char *path, char *operation) +static void make_device(char *path)  { -  char *device_name, *s, *temp, *alias = NULL, *cmd = NULL, buf[PATH_MAX]; -  char sign = 0, op_pref = 0, *str2 = NULL, *ln = NULL; -  int major, minor, type, len, fd, ufd, mode = 0660; +  char *device_name, *s, *temp; +  int major, minor, type, len, fd; +  int mode = 0660;    uid_t uid = 0;    gid_t gid = 0; @@ -53,32 +46,19 @@ static void make_device(char *path, char *operation)    temp = strrchr(path, '/');    fd = open(path, O_RDONLY); -  *temp = 0; +  *temp=0;    temp = toybuf;    len = read(fd, temp, 64);    close(fd); -  if (!strcmp(operation, "add") && len < 1) return; +  if (len<1) return;    temp[len] = 0; + +  // Determine device name, type, major and minor + +  device_name = strrchr(path, '/') + 1; +  type = path[5]=='c' ? S_IFCHR : S_IFBLK;    major = minor = 0; -  if (sscanf(temp, "%u:%u", &major, &minor) != 2) major = -1; - -  memset(buf, 0, sizeof(buf)); -  device_name = TT.devname; -  if (!device_name) { -    sprintf(buf,"%s/uevent", path); -    if ((ufd = open(buf, O_RDONLY)) >= 0) { -      for (; (ln = get_line(ufd)); free(ln)) { -        if (strstr(ln, "DEVNAME=")) { -          device_name = ln + strlen("DEVNAME=") ; -          break; -        }   -      } -      close(ufd); -    } -  } -  if (!device_name) device_name = strrchr(path, '/') + 1; -  type = S_IFCHR; -  if (strstr(path, "/block/")) type =  S_IFBLK; +  sscanf(temp, "%u:%u", &major, &minor);    // If we have a config file, look up permissions for this device @@ -86,145 +66,96 @@ static void make_device(char *path, char *operation)      char *conf, *pos, *end;      // mmap the config file -    if (-1 != (fd = open("/etc/mdev.conf", O_RDONLY))) { +    if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) {        len = fdlength(fd);        conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);        if (conf) {          int line = 0;          // Loop through lines in mmaped file -        for (pos = conf; pos-conf < len;) { +        for (pos = conf; pos-conf<len;) {            int field;            char *end2;            line++;            // find end of this line -          for(end = pos; end-conf < len && *end != '\n'; end++); +          for(end = pos; end-conf<len && *end!='\n'; end++); -          // Fields: regex uid:gid mode [alias] [cmd] -          for (field = 3; field >= 0; field--) { +          // Three fields: regex, uid:gid, mode +          for (field = 3; field; field--) {              // Skip whitespace -            while (pos < end && isspace(*pos)) pos++; -            if (pos == end || *pos == '#') break; +            while (pos<end && isspace(*pos)) pos++; +            if (pos==end || *pos=='#') break;              for (end2 = pos; -                end2 < end && !isspace(*end2) && *end2 != '#'; end2++); +              end2<end && !isspace(*end2) && *end2!='#'; end2++);              switch(field) {                // Regex to match this device                case 3: -                { -                  char *str = strndup(pos, end2-pos), *regex; -                  regex_t match; -                  regmatch_t off; -                  int result; - -                  if (*str == '$') { -                    char *p = strchr(str, '='); - -                    if (!p) { -                      free(str); -                      error_msg("bad $envvar=regex"); -                      goto end_line; -                    } else { -                      p++; -                      regex = xstrdup(p); -                      free(str); -                    } -                  } else { -                    regex = xstrdup(str); -                    free(str); -                  } -                  // Is this it? -                  if (*regex == '@') { -                    int maj, min1, min2; - -                    int ret = sscanf(regex, "@%u,%u-%u", &maj, &min1, &min2); -                    free(regex); -                    if (ret < 2 || maj < 0) { -                      error_msg("bad @maj,min @line %d",line); -                      goto end_line; -                    } -                    if (ret == 2) min2 = min1; -                    if (!(major == maj && ( min1 <= minor || minor <= min2))) -                      goto end_line; -                  } else { -                    xregcomp(&match, regex, REG_EXTENDED); -                    result = regexec(&match, device_name, 1, &off, 0); -                    regfree(&match); -                    free(regex); - -                    // If not this device, skip rest of line -                    if (result || off.rm_so -                        || off.rm_eo != strlen(device_name)) -                      goto end_line; -                  } -                  break; -                } -                // uid:gid +              { +                char *regex = strndup(pos, end2-pos); +                regex_t match; +                regmatch_t off; +                int result; + +                // Is this it? +                xregcomp(&match, regex, REG_EXTENDED); +                result=regexec(&match, device_name, 1, &off, 0); +                regfree(&match); +                free(regex); + +                // If not this device, skip rest of line +                if (result || off.rm_so +                  || off.rm_eo!=strlen(device_name)) +                    goto end_line; + +                break; +              } +              // uid:gid                case 2: -                { -                  char *s2; - -                  // Find : -                  for(s = pos; s < end2 && *s != ':'; s++); -                  if (s == end2) goto end_line; - -                  // Parse UID -                  uid = strtoul(pos,&s2,10); -                  if (s != s2) { -                    struct passwd *pass; -                    char *str = xstrndup(pos, s-pos); - -                    pass = getpwnam(str); -                    free(str); -                    if (!pass) goto end_line; -                    uid = pass->pw_uid; -                  } -                  s++; -                  // parse GID -                  gid = strtoul(s,&s2,10); -                  if (end2 != s2) { -                    struct group *grp; -                    char *str = xstrndup(s, end2-s); - -                    grp = getgrnam(str); -                    free(str); -                    if (!grp) goto end_line; -                    gid = grp->gr_gid; -                  } -                  break; -                } -                // mode -              case 1: -                { -                  mode = strtoul(pos, &pos, 8); -                  if (pos != end2) goto end_line; -                  //goto found_device; -                  break; +              { +                char *s2; + +                // Find : +                for(s = pos; s<end2 && *s!=':'; s++); +                if (s==end2) goto end_line; + +                // Parse UID +                uid = strtoul(pos,&s2,10); +                if (s!=s2) { +                  struct passwd *pass; +                  char *str = strndup(pos, s-pos); +                  pass = getpwnam(str); +                  free(str); +                  if (!pass) goto end_line; +                  uid = pass->pw_uid;                  } -                // handle 4th and 5th field -              case 0: -                { -                  char *str1 = NULL;  - -                  str2 = xstrndup(pos, end-pos); -                  if (strchr(">=!", str2[0])) { -                    str1 = strtok(str2, " "); -                    sign = str1[0]; -                    alias = str1 + 1; -                    str1 += strlen(alias) +2; -                  } else str1 = str2; -                  if (str1 && strchr("$@*",str1[0])) { -                    op_pref = str1[0]; -                    cmd = str1 + 1; -                  } else error_exit("Bad Line %d", line);  -                  goto found_device; +                s++; +                // parse GID +                gid = strtoul(s,&s2,10); +                if (end2!=s2) { +                  struct group *grp; +                  char *str = strndup(s, end2-s); +                  grp = getgrnam(str); +                  free(str); +                  if (!grp) goto end_line; +                  gid = grp->gr_gid;                  } +                break; +              } +              // mode +              case 1: +              { +                mode = strtoul(pos, &pos, 8); +                if (pos!=end2) goto end_line; +                goto found_device; +              }              } -            pos = end2; +            pos=end2;            }  end_line:            // Did everything parse happily? -          if (field && field != 3) error_exit("bad line %d", line); +          if (field && field!=3) error_exit("Bad line %d", line); +            // Next line            pos = ++end;          } @@ -235,46 +166,11 @@ found_device:      }    } -  if (operation && !((op_pref == '@' && !strcmp(operation, "add")) || -        (op_pref == '$' && !strcmp(operation, "remove")) || (op_pref == '*'))) -    cmd = NULL; - -  if (alias) { -    if (alias[strlen(alias)-1] == '/') sprintf(temp,"%s%s",alias, device_name); -    else sprintf(temp,"%s",alias); -  } -  if (sign != '!' && operation && !strcmp(operation, "add")) { //not to create device otherwise - -    if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) -      perror_msg("mknod /dev/%s failed", device_name); -    if (CFG_MDEV_CONF)  {  -      chmod(device_name, mode); -      chown(device_name, uid, gid); -    } - -    if (TT.root_maj == major && TT.root_min == minor) symlink(device_name, "root"); - -    if (alias && (sign == '>' || sign == '=')) { -      mkpathat(AT_FDCWD, alias, 0, 2); -      if (rename(device_name, temp)) perror_exit("rename temp"); -      if (sign == '>') symlink(temp, device_name); -    } -  } -  if (cmd) { -    char *str = xmprintf("%s=%s", "MDEV", device_name); - -    putenv(str); -    if (system(cmd) == -1) perror_msg("can't run '%s'", cmd); -    unsetenv(str); -    free(str); -  } +  sprintf(temp, "/dev/%s", device_name); +  if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST) +    perror_exit("mknod %s failed", temp); -  if (operation && !strcmp(operation, "remove") && major >= -1) { -    if (alias && sign == '>') unlink(temp); -    unlink(device_name); -  } -  free(str2); -  free(ln); +  if (CFG_MDEV_CONF) mode=chown(temp, uid, gid);  }  static int callback(struct dirtree *node) @@ -282,143 +178,31 @@ static int callback(struct dirtree *node)    // Entries in /sys/class/block aren't char devices, so skip 'em.  (We'll    // get block devices out of /sys/block.)    if(!strcmp(node->name, "block")) return 0; -  if (!dirtree_notdotdot(node)) return 0;    // Does this directory have a "dev" entry in it?    // This is path based because the hotplug callbacks are    if (S_ISDIR(node->st.st_mode) || S_ISLNK(node->st.st_mode)) { -    int len = 4; +    int len=4;      char *dev = dirtree_path(node, &len);      strcpy(dev+len, "/dev"); -    if (!access(dev, R_OK)) make_device(dev, "add"); +    if (!access(dev, R_OK)) make_device(dev);      free(dev);    }    // Circa 2.6.25 the entries more than 2 deep are all either redundant    // (mouse#, event#) or unnamed (every usb_* entry is called "device"). -  return (node->parent && node->parent->parent) ? 0 : -    DIRTREE_RECURSE|DIRTREE_SYMFOLLOW; -} - -#if 0 -static int sequence_file(char *seq) -{ -  static struct timespec tspec = { 0, 32*1000*1000 }; // time out after 2 secs -  int time_out = 2000 / 32, fd = -1; -  sigset_t sg; - -  sigemptyset(&sg); -  sigaddset(&sg, SIGCHLD); -  sigprocmask(SIG_BLOCK, &sg, NULL); - -  for (;;) { -    ssize_t slen; -    char buf[sizeof(int)*3 + 2]; - -    if (fd < 0 && (fd = open("/dev/mdev.seq", O_RDWR)) < 0) break; -    if ((slen = pread(fd, buf, sizeof(buf) - 1, 0)) < 0) { -      close(fd); -      fd = -1; -      break; -    } -    buf[slen] = '\0'; -    if (buf[0] == '\n') { -      xwrite(fd, seq, strlen(seq)); -      xlseek(fd, 0, SEEK_SET); -      break; -    } -    if (!strcmp(seq, buf)) break; -    if (sigtimedwait(&sg, NULL, &tspec) >= 0) continue; -    if (!--time_out) break; -  } -  sigprocmask(SIG_UNBLOCK, &sg, NULL); -  return fd; -} -#endif - -static void firmware_load(char *fware, char *sysfs_path) -{ -  int count, fd, lfd, dfd; - -  xchdir("/lib/firmware"); -  fd = open(fware, O_RDONLY); -  // check for /sys/$DEVPATH/loading ... give 30 seconds to appear -  xchdir(sysfs_path); -  for (count = 0; count < 30; ++count) { -    lfd = open("loading", O_WRONLY); -    if (lfd >= 0) goto load; -    sleep(1); -  } -  goto end; - -load: -  if (fd >= 0) { -    if (writeall(lfd, "1", 1) != 1) goto end; -    dfd = open("data", O_WRONLY); -    if (dfd < 0) goto end; -    xsendfile(fd, dfd); -    close(dfd); -  } -  if (fd >= 0) writeall(lfd, "0", 1); -  else writeall(lfd, "-1", 2); - -end: -  xchdir("/dev"); -  close(lfd); -  close(fd); +  return (node->parent && node->parent->parent) ? 0 : DIRTREE_RECURSE;  }  void mdev_main(void)  { +  // Handle -s -  char buf[PATH_MAX]; -  struct dirtree *root; - -  umask(0); -  xchdir("/dev"); -  if (toys.optflags & FLAG_s) { -    struct stat st; - -    xstat("/", &st); -    TT.root_maj = major(st.st_dev); -    TT.root_min = minor(st.st_dev); -    putenv((char*)"ACTION=add"); - -    root = dirtree_add_node(0, "/sys/class", 1); -    if (root) dirtree_handle_callback(root, callback); - -    root = dirtree_add_node(0, "/sys/block", 1); -    if (root) dirtree_handle_callback(root, callback); -  } else {  // Hotplug handling -    char *fware, *action, *devpath; -    int logfd; - -    action = getenv("ACTION"); -    TT.devname = getenv("DEVNAME"); -    devpath = getenv("DEVPATH"); - -    if (!action || !devpath) { -      toys.exithelp++; -      error_exit("env var action/devpath not found"); -    } -    fware = getenv("FIRMWARE"); - -    if ((logfd = open("/dev/mdev.log", O_WRONLY | O_APPEND)) >= 0) { -      dup2(logfd, 2);  // 2 -> STDERR_FILENO -      TT.verbose = 1; -    } -    //TODO give sequencei file support. - -    //    seqfd = seq_num ? sequence_file(seq_num) : -1; -    snprintf(buf, PATH_MAX, "/sys%s/dev", devpath); -    if (action && !strcmp("remove", action) && !fware) -      make_device(buf, action); -    else { -      make_device(buf, action); -      buf[strlen(buf) - 4] = '\0'; //remove /dev from end. -      if (action && !strcmp("add", action) && fware) -        firmware_load(fware, buf); -    } +  if (toys.optflags) { +    dirtree_read("/sys/class", callback); +    dirtree_read("/sys/block", callback);    } + +  // hotplug support goes here  } | 
