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 8USE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN)) 9 10config 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 38GLOBALS( 39 char *d; 40) 41 42void 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