From 99ab52101ce8d3e19fe20614d718e8f006cc3c8a Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Wed, 4 Jan 2023 10:33:18 +0000 Subject: [PATCH] mkbootfs: Add support for a dev node list file Let mkbootfs create a list of dev nodes and directories, based on a file: $ mkbootfs -n node_file initramfs/ > initramfs.cpio This file is following the same format as the kernel usr/ cpio list: $ cat node_file # My device nodes dir dev 0755 0 0 nod dev/null 0600 0 0 c 1 5 Bug: 254835242 Change-Id: Ieb75b1d1026a9426581b6f2b3aa692a05722ba0d --- mkbootfs/mkbootfs.c | 113 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) diff --git a/mkbootfs/mkbootfs.c b/mkbootfs/mkbootfs.c index 1b9678827..907cad3fb 100644 --- a/mkbootfs/mkbootfs.c +++ b/mkbootfs/mkbootfs.c @@ -1,4 +1,6 @@ +#include +#include #include #include #include @@ -14,6 +16,8 @@ #include #include +#include + #include #include @@ -335,21 +339,123 @@ static void read_canned_config(char* filename) fclose(f); } +static void devnodes_desc_error(const char* filename, unsigned long line_num, + const char* msg) +{ + error(EXIT_FAILURE, 0, "failed to read nodes desc file '%s' line %lu: %s", + filename, line_num, msg); +} + +static int append_devnodes_desc_dir(char* path, char* args) +{ + struct stat s; + + if (sscanf(args, "%o %d %d", &s.st_mode, &s.st_uid, &s.st_gid) != 3) return -1; + + s.st_mode |= S_IFDIR; + + _eject(&s, path, strlen(path), NULL, 0); + + return 0; +} + +static int append_devnodes_desc_nod(char* path, char* args) +{ + int minor, major; + struct stat s; + char dev; + + if (sscanf(args, "%o %d %d %c %d %d", &s.st_mode, &s.st_uid, &s.st_gid, + &dev, &major, &minor) != 6) return -1; + + s.st_rdev = MKDEV(major, minor); + switch (dev) { + case 'b': + s.st_mode |= S_IFBLK; + break; + case 'c': + s.st_mode |= S_IFCHR; + break; + default: + return -1; + } + + _eject(&s, path, strlen(path), NULL, 0); + + return 0; +} + +static void append_devnodes_desc(const char* filename) +{ + FILE* f = fopen(filename, "re"); + if (!f) error(EXIT_FAILURE, errno, + "failed to open nodes description file '%s'", filename); + + char *line, *args, *type, *path; + unsigned long line_num = 0; + size_t allocated_len; + + while (getline(&line, &allocated_len, f) != -1) { + char* type; + + line_num++; + + if (*line == '#') continue; + + if (!(type = strtok(line, " \t"))) { + devnodes_desc_error(filename, line_num, "a type is missing"); + } + + if (*type == '\n') continue; + + if (!(path = strtok(NULL, " \t"))) { + devnodes_desc_error(filename, line_num, "a path is missing"); + } + + if (!(args = strtok(NULL, "\n"))) { + devnodes_desc_error(filename, line_num, "args are missing"); + } + + if (!strcmp(type, "dir")) { + if (append_devnodes_desc_dir(path, args)) { + devnodes_desc_error(filename, line_num, "bad arguments for dir"); + } + } else if (!strcmp(type, "nod")) { + if (append_devnodes_desc_nod(path, args)) { + devnodes_desc_error(filename, line_num, "bad arguments for nod"); + } + } else { + devnodes_desc_error(filename, line_num, "type unknown"); + } + } + + free(line); + fclose(f); +} + static const struct option long_options[] = { { "dirname", required_argument, NULL, 'd' }, { "file", required_argument, NULL, 'f' }, { "help", no_argument, NULL, 'h' }, + { "nodes", required_argument, NULL, 'n' }, { NULL, 0, NULL, 0 }, }; static void usage(void) { fprintf(stderr, - "Usage: mkbootfs [-d DIR|-F FILE] DIR...\n" + "Usage: mkbootfs [-n FILE] [-d DIR|-F FILE] DIR...\n" "\n" "\t-d, --dirname=DIR: fs-config directory\n" "\t-f, --file=FILE: Canned configuration file\n" "\t-h, --help: Print this help\n" + "\t-n, --nodes=FILE: Dev nodes description file\n" + "\nDev nodes description:\n" + "\t[dir|nod] [perms] [uid] [gid] [c|b] [minor] [major]\n" + "\tExample:\n" + "\t\t# My device nodes\n" + "\t\tdir dev 0755 0 0\n" + "\t\tnod dev/null 0600 0 0 c 1 5\n" ); } @@ -357,7 +463,7 @@ int main(int argc, char *argv[]) { int opt, unused; - while ((opt = getopt_long(argc, argv, "hd:f:", long_options, &unused)) != -1) { + while ((opt = getopt_long(argc, argv, "hd:f:n:", long_options, &unused)) != -1) { switch (opt) { case 'd': target_out_path = argv[optind - 1]; @@ -368,6 +474,9 @@ int main(int argc, char *argv[]) case 'h': usage(); return 0; + case 'n': + append_devnodes_desc(argv[optind - 1]); + break; default: usage(); die("Unknown option %s", argv[optind - 1]);