aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/makedevs.c
blob: a8e42e895aa6843d42e719dcb6eedeee6f932e36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/* makedevs.c - Make ranges of device files.
 *
 * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
 * Copyright 2014 Kyungwan Han <asura321@gmail.com>
 *
 * No Standard
 
USE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN))

config MAKEDEVS
  bool "makedevs"
  default n
  help
    usage: makedevs [-d device_table] rootdir
    Create a range of special files as specified in a device table.
    Device table entries take the following form:
    <name> <type> <mode> <uid> <gid> <major> <minor> <start> <increment> <count>
    Where name is the file name, type can be one of the following:
    b    Block device
    c    Character device
    d    Directory
    f    Regular file
    p    Fifo (named pipe)

    uid is the user id and gid is the group id for the target file.
    The rest of the entries (major, minor, etc.) apply to device 
    special files. A '-' may be used for blank entries.
*/
#define FOR_makedevs
#include "toys.h"

GLOBALS(
  char *fname;
)

void makedevs_main()
{
  int value, fd = 0, line_no;
  char *line = NULL;

  if (toys.optflags & FLAG_d) {
    xprintf("rootdir = %s\ntable = %s\n", *toys.optargs, 
        (!strcmp(TT.fname, "-")) ? "<stdin>": TT.fname);
    fd = (!strcmp(TT.fname, "-")) ? 0 : xopen(TT.fname, O_RDONLY);
  } else xprintf("rootdir = %s\ntable = %s\n", *toys.optargs, "<stdin>");

  xchdir(*toys.optargs);  // root dir
  for (line_no = 0; (line = get_line(fd)); free(line)) {
    char type, str[64], user[64], group [64], *node = str, *ptr = line;
    unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0, 
                 st_val = 0, i;
    uid_t uid;
    gid_t gid;
    dev_t dev;
    struct stat st;

    line_no++;
    while (*ptr == ' ' || *ptr == '\t') ptr++;
    if (!*ptr || *ptr == '#') continue;
    sscanf(line, "%63s %c %o %63s %63s %u %u %u %u %u", node, &type, &mode,
        user, group, &major, &minor, &st_val, &incr, &cnt);
    if ((major | minor | st_val | cnt | incr) > 255) {
      error_msg("invalid line %d: '%s'", line_no, line);
      continue;
    }

    if (*user) {
      struct passwd *usr;

      if (!(usr = getpwnam(user)) && isdigit(*user)) {
        sscanf (user, "%d", &value);
        usr = xgetpwuid(value);
      }
      if (!usr) error_exit("bad user '%s'", user);
      uid = usr->pw_uid;
    } else uid = getuid();

    if (*group) {
      struct group *grp;

      if (!(grp = getgrnam(group)) && isdigit(*group)) {
        sscanf (group, "%d", &value);
        grp = getgrgid(value);
      }
      if (!grp) error_exit("bad group '%s'", group);
      gid = grp->gr_gid;
    } else gid = getgid();

    if (*node == '/') node++; // using relative path
    switch (type) {
      case 'd':
        if (mkpathat(AT_FDCWD, node, mode, 3)) 
          perror_msg("can't create directory '%s'", node);
        else if (chown(node, uid, gid) || chmod(node, mode)) 
          perror_msg("line %d: can't chown/chmod '%s'", line_no, node);
        break;
      case 'f': 
        if ((stat(node, &st) || !S_ISREG(st.st_mode)))
          perror_msg("line %d: regular file '%s' does not exist",
              line_no, node);
        else if (chown(node, uid, gid) || chmod(node, mode))
          perror_msg("line %d: can't chown/chmod '%s'", line_no, node);
        break;
      case 'p': mode |= S_IFIFO; goto CREATENODE;
      case 'c': mode |= S_IFCHR; goto CREATENODE;
      case 'b': mode |= S_IFBLK;
CREATENODE:
        if (cnt) --cnt;
        for (i = st_val; i <= st_val + cnt; i++) {
          sprintf(toybuf, cnt ? "%s%u" : "%s", node, i);
          dev = makedev(major, minor + (i - st_val) * incr);
          if (mknod(toybuf, mode, dev)) 
            perror_msg("line %d: can't create node '%s'", line_no, toybuf);
          else if (chown(toybuf, uid, gid) || chmod(toybuf, mode)) 
            perror_msg("line %d: can't chown/chmod '%s'", line_no, toybuf);
        }
        break;
      default: 
        error_msg("line %d: file type %c is unsupported", line_no, type);
        break;
    }
  }
  xclose(fd);
}