This tool reads modules.devname from the current kernel directory and outputs the information. By default in a human-readable format, and optionally in machine-readable formats. For now only the tmpfiles.d(5) format is supported, but more could easily be added in the future if there is a need. This means nothing but kmod needs to reads the private files under /lib/modules/. In particular systemd-udevd can stop reading modules.devname. Cc: <linux-hotplug@xxxxxxxxxxxxxxx> Cc: <systemd-devel@xxxxxxxxxxxxxxxxxxxxx>tools: static-nodes --- v3: dropped the systemd integration for now, we can decide on that separately added human-readable format and use this by default added a --format= switch to get the tmpfiles format Makefile.am | 3 +- tools/kmod.c | 1 + tools/kmod.h | 1 + tools/static-nodes.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 tools/static-nodes.c diff --git a/Makefile.am b/Makefile.am index fe4c769..b1bfd59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -110,7 +110,8 @@ noinst_SCRIPTS = tools/insmod tools/rmmod tools/lsmod \ tools_kmod_SOURCES = tools/kmod.c tools/kmod.h tools/lsmod.c \ tools/rmmod.c tools/insmod.c \ tools/modinfo.c tools/modprobe.c \ - tools/depmod.c tools/log.h tools/log.c + tools/depmod.c tools/log.h tools/log.c \ + tools/static-nodes.c tools_kmod_LDADD = libkmod/libkmod-util.la \ libkmod/libkmod.la diff --git a/tools/kmod.c b/tools/kmod.c index ebb8875..347bb7d 100644 --- a/tools/kmod.c +++ b/tools/kmod.c @@ -37,6 +37,7 @@ static const struct kmod_cmd kmod_cmd_help; static const struct kmod_cmd *kmod_cmds[] = { &kmod_cmd_help, &kmod_cmd_list, + &kmod_cmd_static_nodes, }; static const struct kmod_cmd *kmod_compat_cmds[] = { diff --git a/tools/kmod.h b/tools/kmod.h index 80fa4c2..68a646a 100644 --- a/tools/kmod.h +++ b/tools/kmod.h @@ -35,5 +35,6 @@ extern const struct kmod_cmd kmod_cmd_compat_modprobe; extern const struct kmod_cmd kmod_cmd_compat_depmod; extern const struct kmod_cmd kmod_cmd_list; +extern const struct kmod_cmd kmod_cmd_static_nodes; #include "log.h" diff --git a/tools/static-nodes.c b/tools/static-nodes.c new file mode 100644 index 0000000..3d0582a --- /dev/null +++ b/tools/static-nodes.c @@ -0,0 +1,176 @@ +/* + * kmod-static-nodes - manage modules.devname + * + * Copyright (C) 2004-2012 Kay Sievers <kay@xxxxxxxx> + * Copyright (C) 2011-2013 ProFUSION embedded systems + * Copyright (C) 2013 Tom Gundersen <teg@xxxxxxx> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <getopt.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> +#include <sys/utsname.h> +#include <sys/stat.h> +#include <sys/types.h> +#include "libkmod-util.h" + +#include "kmod.h" + +static const char cmdopts_s[] = "o:f:h"; +static const struct option cmdopts[] = { + { "output", required_argument, 0, 'o'}, + { "format", required_argument, 0, 'f'}, + { "help", no_argument, 0, 'h'}, + { }, +}; + +static void help(void) +{ + printf("Usage:\n" + "\t%s static-nodes [options]\n" + "\n" + "kmod static-nodes outputs the static-node information of the currently running kernel.\n" + "\n" + "Options:\n" + "\t-f, --format=FORMAT use a machine-readable format\n" + "\t-o, --output=FILE write output to file\n" + "\t-h, --help show this help\n" + "\n" + "Formats:\n" + " tmpfiles the tmpfiles.d(5) format used by systemd-tmpfiles.\n", + program_invocation_short_name); +} + +static void write_human(FILE *out, char module[], char devname[], char type, unsigned int maj, unsigned int min) +{ + fprintf(out, + "Module: %s\n" + "\tDevice node: /dev/%s\n" + "\t\tType: %s device\n" + "\t\tMajor: %u\n" + "\t\tMinor: %u\n", + module, devname, (type == 'c') ? "character" : "block", maj, min); + return; +} + +static void write_tmpfile(FILE *out, char devname[], char type, unsigned int maj, unsigned int min) +{ + fprintf(out, "%c /dev/%s 0600 - - - %u:%u\n", type, devname, maj, min); + return; +} + +static int do_static_nodes(int argc, char *argv[]) +{ + struct utsname kernel; + char modules[PATH_MAX]; + FILE *in = NULL, *out = stdout; + bool human_readable = 1; + char buf[4096]; + int ret = EXIT_SUCCESS; + + for (;;) { + int c, idx = 0; + + c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx); + if (c == -1) { + break; + } + switch (c) { + case 'o': + out = fopen(optarg, "we"); + if (out == NULL) { + fprintf(stderr, "Error: could not create %s!\n", optarg); + ret = EXIT_FAILURE; + goto finish; + } + break; + case 'f': + if (!streq(optarg, "tmpfiles")) { + fprintf(stderr, "Unknown format: '%s'.\n", argv[1]); + help(); + ret = EXIT_FAILURE; + goto finish; + } + human_readable = 0; + break; + case 'h': + help(); + goto finish; + case '?': + ret = EXIT_FAILURE; + goto finish; + default: + fprintf(stderr, "Unexpected commandline option '%c'.\n", c); + help(); + ret = EXIT_FAILURE; + goto finish; + } + } + + if (uname(&kernel) < 0) { + fputs("Error: uname failed!\n", stderr); + ret = EXIT_FAILURE; + goto finish; + } + snprintf(modules, sizeof(modules), "/lib/modules/%s/modules.devname", kernel.release); + in = fopen(modules, "re"); + if (in == NULL && errno != ENOENT) { + fprintf(stderr, "Error: could not open /lib/modules/%s/modules.devname!\n", kernel.release); + ret = EXIT_FAILURE; + goto finish; + } + + while (fgets(buf, sizeof(buf), in) != NULL) { + char module[PATH_MAX]; + char devname[PATH_MAX]; + char type; + unsigned int maj, min; + int matches; + + if (buf[0] == '#') + continue; + + matches = sscanf(buf, "%s %s %c%u:%u", module, devname, &type, &maj, &min); + if (matches != 5 || (type != 'c' && type != 'b')) { + fprintf(stderr, "Error: invalid devname entry: %s", buf); + ret = EXIT_FAILURE; + continue; + } + + if (human_readable) + write_human(out, module, devname, type, maj, min); + else + write_tmpfile(out, devname, type, maj, min); + } + +finish: + if (in) + fclose(in); + if (out) + fclose(out); + return ret; +} + +const struct kmod_cmd kmod_cmd_static_nodes = { + .name = "static-nodes", + .cmd = do_static_nodes, + .help = "outputs the static-node information of the currently running kernel", +}; -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-modules" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html