| /* 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 y |
| help |
| usage: makedevs [-d device_table] rootdir |
| |
| Create a range of special files as specified in a device table. |
| |
| -d file containing device table (default reads from stdin) |
| |
| Each line of of the device table has the fields: |
| <name> <type> <mode> <uid> <gid> <major> <minor> <start> <increment> <count> |
| Where name is the file name, and type is one of the following: |
| |
| b Block device |
| c Character device |
| d Directory |
| f Regular file |
| p Named pipe (fifo) |
| |
| Other fields specify permissions, user and group id owning the file, |
| and additional fields for device special files. Use '-' for blank entries, |
| unspecified fields are treated as '-'. |
| */ |
| |
| #define FOR_makedevs |
| #include "toys.h" |
| |
| GLOBALS( |
| char *fname; |
| ) |
| |
| void makedevs_main() |
| { |
| int fd = 0, line_no, i; |
| char *line = NULL; |
| |
| // Open file and chdir, verbosely |
| xprintf("rootdir = %s\n", *toys.optargs); |
| if (toys.optflags & FLAG_d && strcmp(TT.fname, "-")) { |
| fd = xopenro(TT.fname); |
| xprintf("table = %s\n", TT.fname); |
| } else xprintf("table = <stdin>\n"); |
| xchdir(*toys.optargs); |
| |
| for (line_no = 0; (line = get_line(fd)); free(line)) { |
| char type=0, user[64], group[64], *node, *ptr = line; |
| unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0, |
| st_val = 0; |
| uid_t uid; |
| gid_t gid; |
| struct stat st; |
| |
| line_no++; |
| while (isspace(*ptr)) ptr++; |
| if (!*ptr || *ptr == '#') continue; |
| node = ptr; |
| |
| while (*ptr && !isspace(*ptr)) ptr++; |
| if (*ptr) *(ptr++) = 0; |
| *user = *group = 0; |
| sscanf(ptr, "%c %o %63s %63s %u %u %u %u %u", &type, &mode, |
| user, group, &major, &minor, &st_val, &incr, &cnt); |
| |
| // type order here needs to line up with actions[] order. |
| i = stridx("pcbdf", type); |
| if (i == -1) { |
| error_msg("line %d: bad type %c", line_no, type); |
| continue; |
| } else mode |= (mode_t[]){S_IFIFO, S_IFCHR, S_IFBLK, 0, 0}[i]; |
| |
| uid = *user ? xgetuid(user) : getuid(); |
| gid = *group ? xgetgid(group) : getgid(); |
| |
| while (*node == '/') node++; // using relative path |
| |
| for (i = 0; (!cnt && !i) || i < cnt; i++) { |
| if (cnt>1) { |
| snprintf(toybuf, sizeof(toybuf), "%.999s%u", node, st_val + i); |
| ptr = toybuf; |
| } else ptr = node; |
| |
| if (type == 'd') { |
| if (mkpathat(AT_FDCWD, ptr, mode, 3)) { |
| perror_msg("can't create directory '%s'", ptr); |
| continue; |
| } |
| } else if (type == 'f') { |
| if (stat(ptr, &st) || !S_ISREG(st.st_mode)) { |
| perror_msg("line %d: file '%s' does not exist", line_no, ptr); |
| continue; |
| } |
| } else if (mknod(ptr, mode, dev_makedev(major, minor + i*incr))) { |
| perror_msg("line %d: can't create node '%s'", line_no, ptr); |
| continue; |
| } |
| |
| if (chown(ptr, uid, gid) || chmod(ptr, mode)) |
| perror_msg("line %d: can't chown/chmod '%s'", line_no, ptr); |
| } |
| } |
| xclose(fd); |
| } |