10f66f451Sopenharmony_ci/* makedevs.c - Make ranges of device files.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
40f66f451Sopenharmony_ci * Copyright 2014 Kyungwan Han <asura321@gmail.com>
50f66f451Sopenharmony_ci *
60f66f451Sopenharmony_ci * No Standard
70f66f451Sopenharmony_ci
80f66f451Sopenharmony_ciUSE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN))
90f66f451Sopenharmony_ci
100f66f451Sopenharmony_ciconfig MAKEDEVS
110f66f451Sopenharmony_ci  bool "makedevs"
120f66f451Sopenharmony_ci  default y
130f66f451Sopenharmony_ci  help
140f66f451Sopenharmony_ci    usage: makedevs [-d device_table] rootdir
150f66f451Sopenharmony_ci
160f66f451Sopenharmony_ci    Create a range of special files as specified in a device table.
170f66f451Sopenharmony_ci
180f66f451Sopenharmony_ci    -d	File containing device table (default reads from stdin)
190f66f451Sopenharmony_ci
200f66f451Sopenharmony_ci    Each line of the device table has the fields:
210f66f451Sopenharmony_ci    <name> <type> <mode> <uid> <gid> <major> <minor> <start> <increment> <count>
220f66f451Sopenharmony_ci    Where name is the file name, and type is one of the following:
230f66f451Sopenharmony_ci
240f66f451Sopenharmony_ci    b	Block device
250f66f451Sopenharmony_ci    c	Character device
260f66f451Sopenharmony_ci    d	Directory
270f66f451Sopenharmony_ci    f	Regular file
280f66f451Sopenharmony_ci    p	Named pipe (fifo)
290f66f451Sopenharmony_ci
300f66f451Sopenharmony_ci    Other fields specify permissions, user and group id owning the file,
310f66f451Sopenharmony_ci    and additional fields for device special files. Use '-' for blank entries,
320f66f451Sopenharmony_ci    unspecified fields are treated as '-'.
330f66f451Sopenharmony_ci*/
340f66f451Sopenharmony_ci
350f66f451Sopenharmony_ci#define FOR_makedevs
360f66f451Sopenharmony_ci#include "toys.h"
370f66f451Sopenharmony_ci
380f66f451Sopenharmony_ciGLOBALS(
390f66f451Sopenharmony_ci  char *d;
400f66f451Sopenharmony_ci)
410f66f451Sopenharmony_ci
420f66f451Sopenharmony_civoid makedevs_main(void)
430f66f451Sopenharmony_ci{
440f66f451Sopenharmony_ci  FILE *fp = stdin;
450f66f451Sopenharmony_ci  char *line = NULL;
460f66f451Sopenharmony_ci  size_t allocated_length = 0;
470f66f451Sopenharmony_ci  int line_no = 0, i;
480f66f451Sopenharmony_ci
490f66f451Sopenharmony_ci  // Open file and chdir, verbosely
500f66f451Sopenharmony_ci  xprintf("rootdir = %s\n", *toys.optargs);
510f66f451Sopenharmony_ci  if (FLAG(d) && strcmp(TT.d, "-")) {
520f66f451Sopenharmony_ci    fp = xfopen(TT.d, "r");
530f66f451Sopenharmony_ci    xprintf("table = %s\n", TT.d);
540f66f451Sopenharmony_ci  } else xprintf("table = <stdin>\n");
550f66f451Sopenharmony_ci  xchdir(*toys.optargs);
560f66f451Sopenharmony_ci
570f66f451Sopenharmony_ci  while (getline(&line, &allocated_length, fp) > 0) {
580f66f451Sopenharmony_ci    char type=0, user[64], group[64], *node, *ptr = line;
590f66f451Sopenharmony_ci    unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0,
600f66f451Sopenharmony_ci                 st_val = 0;
610f66f451Sopenharmony_ci    uid_t uid;
620f66f451Sopenharmony_ci    gid_t gid;
630f66f451Sopenharmony_ci    struct stat st;
640f66f451Sopenharmony_ci
650f66f451Sopenharmony_ci    line_no++;
660f66f451Sopenharmony_ci    while (isspace(*ptr)) ptr++;
670f66f451Sopenharmony_ci    if (!*ptr || *ptr == '#') continue;
680f66f451Sopenharmony_ci    node = ptr;
690f66f451Sopenharmony_ci
700f66f451Sopenharmony_ci    while (*ptr && !isspace(*ptr)) ptr++;
710f66f451Sopenharmony_ci    if (*ptr) *(ptr++) = 0;
720f66f451Sopenharmony_ci    *user = *group = 0;
730f66f451Sopenharmony_ci    sscanf(ptr, "%c %o %63s %63s %u %u %u %u %u", &type, &mode,
740f66f451Sopenharmony_ci           user, group, &major, &minor, &st_val, &incr, &cnt);
750f66f451Sopenharmony_ci
760f66f451Sopenharmony_ci    // type order here needs to line up with actions[] order.
770f66f451Sopenharmony_ci    i = stridx("pcbdf", type);
780f66f451Sopenharmony_ci    if (i == -1) {
790f66f451Sopenharmony_ci      error_msg("line %d: bad type %c", line_no, type);
800f66f451Sopenharmony_ci      continue;
810f66f451Sopenharmony_ci    } else mode |= (mode_t[]){S_IFIFO, S_IFCHR, S_IFBLK, 0, 0}[i];
820f66f451Sopenharmony_ci
830f66f451Sopenharmony_ci    uid = *user ? xgetuid(user) : getuid();
840f66f451Sopenharmony_ci    gid = *group ? xgetgid(group) : getgid();
850f66f451Sopenharmony_ci
860f66f451Sopenharmony_ci    while (*node == '/') node++; // using relative path
870f66f451Sopenharmony_ci
880f66f451Sopenharmony_ci    for (i = 0; (!cnt && !i) || i < cnt; i++) {
890f66f451Sopenharmony_ci      if (cnt>1) {
900f66f451Sopenharmony_ci        snprintf(toybuf, sizeof(toybuf), "%.999s%u", node, st_val + i);
910f66f451Sopenharmony_ci        ptr = toybuf;
920f66f451Sopenharmony_ci      } else ptr = node;
930f66f451Sopenharmony_ci
940f66f451Sopenharmony_ci      if (type == 'd') {
950f66f451Sopenharmony_ci        if (mkpathat(AT_FDCWD, ptr, mode, MKPATHAT_MKLAST | MKPATHAT_MAKE))  {
960f66f451Sopenharmony_ci          perror_msg("can't create directory '%s'", ptr);
970f66f451Sopenharmony_ci          continue;
980f66f451Sopenharmony_ci        }
990f66f451Sopenharmony_ci      } else if (type == 'f') {
1000f66f451Sopenharmony_ci        if (stat(ptr, &st) || !S_ISREG(st.st_mode)) {
1010f66f451Sopenharmony_ci          perror_msg("line %d: file '%s' does not exist", line_no, ptr);
1020f66f451Sopenharmony_ci          continue;
1030f66f451Sopenharmony_ci        }
1040f66f451Sopenharmony_ci      } else if (mknod(ptr, mode, dev_makedev(major, minor + i*incr))) {
1050f66f451Sopenharmony_ci        perror_msg("line %d: can't create node '%s'", line_no, ptr);
1060f66f451Sopenharmony_ci        continue;
1070f66f451Sopenharmony_ci      }
1080f66f451Sopenharmony_ci
1090f66f451Sopenharmony_ci      if (chown(ptr, uid, gid) || chmod(ptr, mode))
1100f66f451Sopenharmony_ci        perror_msg("line %d: can't chown/chmod '%s'", line_no, ptr);
1110f66f451Sopenharmony_ci    }
1120f66f451Sopenharmony_ci  }
1130f66f451Sopenharmony_ci  free(line);
1140f66f451Sopenharmony_ci  if (fp != stdin) fclose(fp);
1150f66f451Sopenharmony_ci}
116