• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 * d;)38 GLOBALS(
39   char *d;
40 )
41 
42 void makedevs_main(void)
43 {
44   FILE *fp = stdin;
45   char *line = NULL;
46   size_t allocated_length = 0;
47   int line_no = 0, i;
48 
49   // Open file and chdir, verbosely
50   xprintf("rootdir = %s\n", *toys.optargs);
51   if (FLAG(d) && strcmp(TT.d, "-")) {
52     fp = xfopen(TT.d, "r");
53     xprintf("table = %s\n", TT.d);
54   } else xprintf("table = <stdin>\n");
55   xchdir(*toys.optargs);
56 
57   while (getline(&line, &allocated_length, fp) > 0) {
58     char type=0, user[64], group[64], *node, *ptr = line;
59     unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0,
60                  st_val = 0;
61     uid_t uid;
62     gid_t gid;
63     struct stat st;
64 
65     line_no++;
66     while (isspace(*ptr)) ptr++;
67     if (!*ptr || *ptr == '#') continue;
68     node = ptr;
69 
70     while (*ptr && !isspace(*ptr)) ptr++;
71     if (*ptr) *(ptr++) = 0;
72     *user = *group = 0;
73     sscanf(ptr, "%c %o %63s %63s %u %u %u %u %u", &type, &mode,
74            user, group, &major, &minor, &st_val, &incr, &cnt);
75 
76     // type order here needs to line up with actions[] order.
77     i = stridx("pcbdf", type);
78     if (i == -1) {
79       error_msg("line %d: bad type %c", line_no, type);
80       continue;
81     } else mode |= (mode_t[]){S_IFIFO, S_IFCHR, S_IFBLK, 0, 0}[i];
82 
83     uid = *user ? xgetuid(user) : getuid();
84     gid = *group ? xgetgid(group) : getgid();
85 
86     while (*node == '/') node++; // using relative path
87 
88     for (i = 0; (!cnt && !i) || i < cnt; i++) {
89       if (cnt>1) {
90         snprintf(toybuf, sizeof(toybuf), "%.999s%u", node, st_val + i);
91         ptr = toybuf;
92       } else ptr = node;
93 
94       if (type == 'd') {
95         if (mkpathat(AT_FDCWD, ptr, mode, MKPATHAT_MKLAST | MKPATHAT_MAKE))  {
96           perror_msg("can't create directory '%s'", ptr);
97           continue;
98         }
99       } else if (type == 'f') {
100         if (stat(ptr, &st) || !S_ISREG(st.st_mode)) {
101           perror_msg("line %d: file '%s' does not exist", line_no, ptr);
102           continue;
103         }
104       } else if (mknod(ptr, mode, dev_makedev(major, minor + i*incr))) {
105         perror_msg("line %d: can't create node '%s'", line_no, ptr);
106         continue;
107       }
108 
109       if (chown(ptr, uid, gid) || chmod(ptr, mode))
110         perror_msg("line %d: can't chown/chmod '%s'", line_no, ptr);
111     }
112   }
113   free(line);
114   if (fp != stdin) fclose(fp);
115 }
116