[PATCH v3] tools: add static-nodes tool

Tom Gundersen <[email protected]>
Newsgroups gmane.linux.hotplug.devel,gmane.linux.kernel.modules,gmane.comp.sysutils.systemd.devel
Message-ID <[email protected]>
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: <[email protected]>
Cc: <[email protected]>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 <[email protected]>
+ * Copyright (C) 2011-2013  ProFUSION embedded systems
+ * Copyright (C) 2013 Tom Gundersen <[email protected]>
+ *
+ * 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-hotplug" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.