/
githubmirror
/
kmod
Обзор
Документация
Войти
/
githubmirror
/
kmod
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tools/static-nodes.c
281 строка
7 KB
Emil Velikov
Manually handle unrecognised getopt arguments
05 авг 2026, 18:49
05 авг 2026, 18:49
f9fa9be
Код
Авторство
О чём код?
// SPDX-License-Identifier: GPL-2.0-or-later /* * kmod-static-nodes - manage modules.devname * * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org> * Copyright (C) 2011-2013 ProFUSION embedded systems * Copyright (C) 2013 Tom Gundersen <teg@jklm.no> */ #include <errno.h> #include <getopt.h> #include <limits.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/utsname.h> #include <shared/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 *const 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, NULL, 'o' }, { "format", required_argument, NULL, 'f' }, { "help", no_argument, NULL, '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_FAILURE; return EXIT_SUCCESS; } 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, _maybe_unused_ char modname[], char devname[], char type, unsigned int maj, unsigned int min) { const char *dir; int ret; dir = strrchr(devname, '/'); if (dir) { ret = fprintf(out, "d /dev/%.*s 0755 - - -\n", (int)(dir - devname), devname); if (ret < 0) return EXIT_FAILURE; } ret = fprintf(out, "%c! /dev/%s 0600 - - - %u:%u\n", type, devname, maj, min); if (ret < 0) return EXIT_FAILURE; return EXIT_SUCCESS; } 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_FAILURE; return EXIT_SUCCESS; } 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 choose format to use: see \"Formats\"\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], buf[PATH_MAX]; const char *output = NULL; FILE *in = NULL, *out = NULL; const struct static_nodes_format *format = &static_nodes_format_human; int r, ret = EXIT_SUCCESS; int c, valid; opterr = 0; while ((c = getopt_long(argc, argv, cmdopts_s, cmdopts, NULL)) != -1) { switch (c) { case 'o': output = optarg; break; case 'f': valid = 0; for (size_t 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 '?': fprintf(stderr, "unrecognised option \'%s\'\n\n", argv[optind - 1]); help(); 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; } r = snprintf(modules, sizeof(modules), MODULE_DIRECTORY "/%s/modules.devname", kernel.release); if (r >= (int)sizeof(modules)) { fprintf(stderr, "Error: could not open " MODULE_DIRECTORY "/%s/modules.devname - path too long\n", kernel.release); ret = EXIT_FAILURE; goto finish; } in = fopen(modules, "re"); if (in == NULL) { if (errno == ENOENT) { fprintf(stderr, "Warning: " MODULE_DIRECTORY "/%s/modules.devname not found - ignoring\n", kernel.release); ret = EXIT_SUCCESS; } else { fprintf(stderr, "Error: could not open " MODULE_DIRECTORY "/%s/modules.devname - %m\n", kernel.release); ret = EXIT_FAILURE; } goto finish; } if (output == NULL) { out = stdout; } else { r = mkdir_parents(output, 0755); if (r < 0) { fprintf(stderr, "Error: could not create parent directory for %s - %s.\n", output, strerror(-r)); ret = EXIT_FAILURE; goto finish; } out = fopen(output, "we"); if (out == NULL) { fprintf(stderr, "Error: could not create %s - %m\n", output); 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 = "output the static-node information installed with the currently running kernel", };