On Tue, Apr 16, 2013 at 5:39 PM, Tom Gundersen <teg@xxxxxxx> wrote: > 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. > > Tools that used to read /lib/modules/`uname -r`/modules.devname directly, can > now move to reading 'kmod static-nodes devname'. > > --- > > v4: refactor to make it easier to add more formats, added the legacy 'devname' > format as an example. > > Makefile.am | 3 +- > tools/kmod.c | 1 + > tools/kmod.h | 1 + > tools/static-nodes.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 250 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..94a48c6 > --- /dev/null > +++ b/tools/static-nodes.c > @@ -0,0 +1,246 @@ > +/* > + * 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" > + > +struct static_nodes_format { > + const char *name; > + int (*write)(FILE *, char[], char[], char, unsigned int, unsigned int); > + const char *description; > +}; > + > +static const struct static_nodes_format static_nodes_format_human; > +static const struct static_nodes_format static_nodes_format_tmpfiles; > +static const struct static_nodes_format static_nodes_format_devname; > + > +static const struct static_nodes_format *static_nodes_formats[] = { > + &static_nodes_format_human, > + &static_nodes_format_tmpfiles, > + &static_nodes_format_devname, > +}; > + > +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 int write_human(FILE *out, char modname[], char devname[], char type, unsigned int maj, unsigned int min) > +{ > + int ret; > + > + ret = fprintf(out, > + "Module: %s\n" > + "\tDevice node: /dev/%s\n" > + "\t\tType: %s device\n" > + "\t\tMajor: %u\n" > + "\t\tMinor: %u\n", > + modname, devname, (type == 'c') ? "character" : "block", maj, min); > + if (ret >= 0) > + return EXIT_SUCCESS; > + else > + return EXIT_FAILURE; > +} > + > +static const struct static_nodes_format static_nodes_format_human = { > + .name = "human", > + .write = write_human, > + .description = "(default) a human readable format. Do not parse.", > +}; > + > + > +static int write_tmpfiles(FILE *out, char modname[], char devname[], char type, unsigned int maj, unsigned int min) > +{ > + int ret; > + > + ret = fprintf(out, "%c /dev/%s 0600 - - - %u:%u\n", type, devname, maj, min); > + if (ret >= 0) > + return EXIT_SUCCESS; > + else > + return EXIT_FAILURE; > +} > + > +static const struct static_nodes_format static_nodes_format_tmpfiles = { > + .name = "tmpfiles", > + .write = write_tmpfiles, > + .description = "the tmpfiles.d(5) format used by systemd-tmpfiles.", > +}; > + > +static int write_devname(FILE *out, char modname[], char devname[], char type, unsigned int maj, unsigned int min) > +{ > + int ret; > + > + ret = fprintf(out, "%s %s %c%u:%u\n", modname, devname, type, maj, min); > + if (ret >= 0) > + return EXIT_SUCCESS; > + else > + return EXIT_FAILURE; > +} > + > +static const struct static_nodes_format static_nodes_format_devname = { > + .name = "devname", > + .write = write_devname, > + .description = "the modules.devname format.", > +}; > + > +static void help(void) > +{ > + size_t i; > + > + 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", > + program_invocation_short_name); > + > + for (i = 0; i < ARRAY_SIZE(static_nodes_formats); i++) { > + if (static_nodes_formats[i]->description != NULL) { > + printf("\t%-12s %s\n", static_nodes_formats[i]->name, > + static_nodes_formats[i]->description); > + } > + } > +} > + > +static int do_static_nodes(int argc, char *argv[]) > +{ > + struct utsname kernel; > + char modules[PATH_MAX]; > + FILE *in = NULL, *out = stdout; > + const struct static_nodes_format *format = &static_nodes_format_human; > + char buf[4096]; > + int ret = EXIT_SUCCESS; > + > + for (;;) { > + int c, idx = 0, valid; > + size_t i; > + > + 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': > + valid = 0; > + > + for (i = 0; i < ARRAY_SIZE(static_nodes_formats); i++) { > + if (streq(static_nodes_formats[i]->name, optarg)) { > + format = static_nodes_formats[i]; > + valid = 1; > + } > + } > + > + if (!valid) { > + fprintf(stderr, "Unknown format: '%s'.\n", optarg); > + help(); > + ret = EXIT_FAILURE; > + goto finish; > + } > + 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 modname[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", modname, devname, &type, &maj, &min); > + if (matches != 5 || (type != 'c' && type != 'b')) { > + fprintf(stderr, "Error: invalid devname entry: %s", buf); > + ret = EXIT_FAILURE; > + continue; > + } > + > + format->write(out, modname, 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 installed with the currently running kernel", > +}; > -- > 1.8.2.1 Patch has been applied. After applying it I had to make a small fix. Please take a look on 279b177de62cd9778ed6b111a11d93d8e18fa169 Thanks Lucas De Marchi -- 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