/* makedevs.c - Make ranges of device files. * * Copyright 2014 Bilal Qureshi * Copyright 2014 Kyungwan Han * * 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: 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, "-")) ? "": TT.fname); fd = (!strcmp(TT.fname, "-")) ? 0 : xopen(TT.fname, O_RDONLY); } else xprintf("rootdir = %s\ntable = %s\n", *toys.optargs, ""); 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); }