Home | History | Annotate | Download | only in other
      1 /* makedevs.c - Make ranges of device files.
      2  *
      3  * Copyright 2014 Bilal Qureshi <bilal.jmi (at) gmail.com>
      4  * Copyright 2014 Kyungwan Han <asura321 (at) gmail.com>
      5  *
      6  * No Standard
      7 
      8 USE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN))
      9 
     10 config 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 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 
     38 GLOBALS(
     39   char *fname;
     40 )
     41 
     42 void 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.fname, "-")) {
     50     fd = xopenro(TT.fname);
     51     xprintf("table = %s\n", TT.fname);
     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, 3))  {
     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