toybox/toys/other/makedevs.c
<<
>>
Prefs
   1/* makedevs.c - Make ranges of device files.
   2 *
   3 * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
   4 * Copyright 2014 Kyungwan Han <asura321@gmail.com>
   5 *
   6 * No Standard
   7 
   8USE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN))
   9
  10config MAKEDEVS
  11  bool "makedevs"
  12  default y
  13  help
  14    usage: makedevs [-d device_table] rootdir
  15
  16    Create a range of special files as specified in a device table.
  17
  18    -d  File containing device table (default reads from stdin)
  19
  20    Each line of the device table has the fields:
  21    <name> <type> <mode> <uid> <gid> <major> <minor> <start> <increment> <count>
  22    Where name is the file name, and type is one of the following:
  23
  24    b   Block device
  25    c   Character device
  26    d   Directory
  27    f   Regular file
  28    p   Named pipe (fifo)
  29
  30    Other fields specify permissions, user and group id owning the file,
  31    and additional fields for device special files. Use '-' for blank entries,
  32    unspecified fields are treated as '-'.
  33*/
  34
  35#define FOR_makedevs
  36#include "toys.h"
  37
  38GLOBALS(
  39  char *d;
  40)
  41
  42void makedevs_main()
  43{
  44  int fd = 0, line_no, i;
  45  char *line = NULL;
  46
  47  // Open file and chdir, verbosely
  48  xprintf("rootdir = %s\n", *toys.optargs);
  49  if ((toys.optflags & FLAG_d) && strcmp(TT.d, "-")) {
  50    fd = xopenro(TT.d);
  51    xprintf("table = %s\n", TT.d);
  52  } else xprintf("table = <stdin>\n");
  53  xchdir(*toys.optargs);
  54
  55  for (line_no = 0; (line = get_line(fd)); free(line)) {
  56    char type=0, user[64], group[64], *node, *ptr = line;
  57    unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0, 
  58                 st_val = 0;
  59    uid_t uid;
  60    gid_t gid;
  61    struct stat st;
  62
  63    line_no++;
  64    while (isspace(*ptr)) ptr++;
  65    if (!*ptr || *ptr == '#') continue;
  66    node = ptr;
  67
  68    while (*ptr && !isspace(*ptr)) ptr++;
  69    if (*ptr) *(ptr++) = 0;
  70    *user = *group = 0;
  71    sscanf(ptr, "%c %o %63s %63s %u %u %u %u %u", &type, &mode,
  72           user, group, &major, &minor, &st_val, &incr, &cnt);
  73
  74    // type order here needs to line up with actions[] order.
  75    i = stridx("pcbdf", type);
  76    if (i == -1) {
  77      error_msg("line %d: bad type %c", line_no, type);
  78      continue;
  79    } else mode |= (mode_t[]){S_IFIFO, S_IFCHR, S_IFBLK, 0, 0}[i];
  80
  81    uid = *user ? xgetuid(user) : getuid();
  82    gid = *group ? xgetgid(group) : getgid();
  83
  84    while (*node == '/') node++; // using relative path
  85
  86    for (i = 0; (!cnt && !i) || i < cnt; i++) {
  87      if (cnt>1) {
  88        snprintf(toybuf, sizeof(toybuf), "%.999s%u", node, st_val + i);
  89        ptr = toybuf;
  90      } else ptr = node;
  91
  92      if (type == 'd') {
  93        if (mkpathat(AT_FDCWD, ptr, mode, MKPATHAT_MKLAST | MKPATHAT_MAKE))  {
  94          perror_msg("can't create directory '%s'", ptr);
  95          continue;
  96        }
  97      } else if (type == 'f') {
  98        if (stat(ptr, &st) || !S_ISREG(st.st_mode)) {
  99          perror_msg("line %d: file '%s' does not exist", line_no, ptr);
 100          continue;
 101        }
 102      } else if (mknod(ptr, mode, dev_makedev(major, minor + i*incr))) {
 103        perror_msg("line %d: can't create node '%s'", line_no, ptr);
 104        continue;
 105      }
 106
 107      if (chown(ptr, uid, gid) || chmod(ptr, mode)) 
 108        perror_msg("line %d: can't chown/chmod '%s'", line_no, ptr);
 109    }
 110  }
 111  xclose(fd);
 112}
 113