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
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
GLOBALS(char * fname;)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 = xopen(TT.fname, O_RDONLY);
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 ? xgetpwnamid(user)->pw_uid : getuid();
82 gid = *group ? xgetgrnamid(group)->gr_gid : 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, 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