--- /dev/null
+/* 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 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:
+ <name> <type> <mode> <uid> <gid> <major> <minor> <start> <increment> <count>
+ 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, "-")) ? "<stdin>": TT.fname);
+ fd = (!strcmp(TT.fname, "-")) ? 0 : xopen(TT.fname, O_RDONLY);
+ } else xprintf("rootdir = %s\ntable = %s\n", *toys.optargs, "<stdin>");
+
+ 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);
+}