19f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma/* makedevs.c - Make ranges of device files.
29f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma *
39f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
49f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma * Copyright 2014 Kyungwan Han <asura321@gmail.com>
59f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma *
69f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma * No Standard
79f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma
89f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini SharmaUSE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN))
99f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma
109f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharmaconfig MAKEDEVS
119f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma  bool "makedevs"
129bf93edd68742bbc9e814ec49c8a3a31ca8d3fffRob Landley  default y
139f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma  help
149f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    usage: makedevs [-d device_table] rootdir
156ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley
169f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    Create a range of special files as specified in a device table.
176ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley
186ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    -d	file containing device table (default reads from stdin)
196ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley
206ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    Each line of of the device table has the fields:
219f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    <name> <type> <mode> <uid> <gid> <major> <minor> <start> <increment> <count>
226ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    Where name is the file name, and type is one of the following:
236ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley
246ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    b	Block device
256ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    c	Character device
266ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    d	Directory
276ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    f	Regular file
286ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    p	Named pipe (fifo)
296ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley
306ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    Other fields specify permissions, user and group id owning the file,
316ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    and additional fields for device special files. Use '-' for blank entries,
326ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    unspecified fields are treated as '-'.
339f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma*/
346ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley
359f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma#define FOR_makedevs
369f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma#include "toys.h"
379f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma
389f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini SharmaGLOBALS(
399f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma  char *fname;
409f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma)
419f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma
429f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharmavoid makedevs_main()
439f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma{
44be4048dd2509f2b9e968a4d03c06050d847971d3Rob Landley  int fd = 0, line_no, i;
459f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma  char *line = NULL;
469f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma
476ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley  // Open file and chdir, verbosely
486ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley  xprintf("rootdir = %s\n", *toys.optargs);
496ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley  if (toys.optflags & FLAG_d && strcmp(TT.fname, "-")) {
50027a73a903af306449710ce12bc09e0e3550c6c9Rob Landley    fd = xopenro(TT.fname);
516ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    xprintf("table = %s\n", TT.fname);
52936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley  } else xprintf("table = <stdin>\n");
536ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley  xchdir(*toys.optargs);
549f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma
559f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma  for (line_no = 0; (line = get_line(fd)); free(line)) {
56936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley    char type=0, user[64], group[64], *node, *ptr = line;
579f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0,
586ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley                 st_val = 0;
599f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    uid_t uid;
609f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    gid_t gid;
619f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    struct stat st;
629f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma
639f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    line_no++;
646ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    while (isspace(*ptr)) ptr++;
659f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    if (!*ptr || *ptr == '#') continue;
66936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley    node = ptr;
676ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley
686ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    while (*ptr && !isspace(*ptr)) ptr++;
69936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley    if (*ptr) *(ptr++) = 0;
706ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    *user = *group = 0;
716ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    sscanf(ptr, "%c %o %63s %63s %u %u %u %u %u", &type, &mode,
726ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley           user, group, &major, &minor, &st_val, &incr, &cnt);
736ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley
746ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    // type order here needs to line up with actions[] order.
756ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    i = stridx("pcbdf", type);
766ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    if (i == -1) {
776ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley      error_msg("line %d: bad type %c", line_no, type);
789f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma      continue;
796ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    } else mode |= (mode_t[]){S_IFIFO, S_IFCHR, S_IFBLK, 0, 0}[i];
809f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma
813d64b0cc95c5957e53474c3e50f143c61a057104Rob Landley    uid = *user ? xgetuid(user) : getuid();
823d64b0cc95c5957e53474c3e50f143c61a057104Rob Landley    gid = *group ? xgetgid(group) : getgid();
839f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma
846ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley    while (*node == '/') node++; // using relative path
85936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley
86936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley    for (i = 0; (!cnt && !i) || i < cnt; i++) {
87a829b89dbd324bcc005a5873fddf3faa81ea0536Rob Landley      if (cnt>1) {
88a829b89dbd324bcc005a5873fddf3faa81ea0536Rob Landley        snprintf(toybuf, sizeof(toybuf), "%.999s%u", node, st_val + i);
89936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley        ptr = toybuf;
90936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley      } else ptr = node;
91936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley
92936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley      if (type == 'd') {
93936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley        if (mkpathat(AT_FDCWD, ptr, mode, 3))  {
94936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley          perror_msg("can't create directory '%s'", ptr);
95936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley          continue;
96936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley        }
97936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley      } else if (type == 'f') {
98936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley        if (stat(ptr, &st) || !S_ISREG(st.st_mode)) {
99936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley          perror_msg("line %d: file '%s' does not exist", line_no, ptr);
1006ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley          continue;
1019f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma        }
1027ca5dc4232b9ac5ee5cd25c8b5b33a58904cd251Rob Landley      } else if (mknod(ptr, mode, dev_makedev(major, minor + i*incr))) {
103936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley        perror_msg("line %d: can't create node '%s'", line_no, ptr);
104936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley        continue;
1056ad3207b65438870dfc9f76a3dcf4bb04096297eRob Landley      }
106936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley
107936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley      if (chown(ptr, uid, gid) || chmod(ptr, mode))
108936ab6d68b747ed7a315ef9c27bb9b90088686f3Rob Landley        perror_msg("line %d: can't chown/chmod '%s'", line_no, ptr);
1099f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma    }
1109f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma  }
1119f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma  xclose(fd);
1129f1a00a859d1b085fdf7a1a5f66e51f41c6217eeAshwini Sharma}
113