man: fix typo
[platform/upstream/kmod.git] / tools / static-nodes.c
1 /*
2  * kmod-static-nodes - manage modules.devname
3  *
4  * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org>
5  * Copyright (C) 2011-2013  ProFUSION embedded systems
6  * Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <errno.h>
23 #include <getopt.h>
24 #include <limits.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/utsname.h>
33
34 #include <shared/util.h>
35
36 #include "kmod.h"
37
38 struct static_nodes_format {
39         const char *name;
40         int (*write)(FILE *, char[], char[], char, unsigned int, unsigned int);
41         const char *description;
42 };
43
44 static const struct static_nodes_format static_nodes_format_human;
45 static const struct static_nodes_format static_nodes_format_tmpfiles;
46 static const struct static_nodes_format static_nodes_format_devname;
47
48 static const struct static_nodes_format *static_nodes_formats[] = {
49         &static_nodes_format_human,
50         &static_nodes_format_tmpfiles,
51         &static_nodes_format_devname,
52 };
53
54 static const char cmdopts_s[] = "o:f:h";
55 static const struct option cmdopts[] = {
56         { "output", required_argument, 0, 'o'},
57         { "format", required_argument, 0, 'f'},
58         { "help", no_argument, 0, 'h'},
59         { },
60 };
61
62 static int write_human(FILE *out, char modname[], char devname[], char type, unsigned int maj, unsigned int min)
63 {
64         int ret;
65
66         ret = fprintf(out,
67                         "Module: %s\n"
68                         "\tDevice node: /dev/%s\n"
69                         "\t\tType: %s device\n"
70                         "\t\tMajor: %u\n"
71                         "\t\tMinor: %u\n",
72                         modname, devname,
73                         (type == 'c') ? "character" : "block", maj, min);
74         if (ret >= 0)
75                 return EXIT_SUCCESS;
76         else
77                 return EXIT_FAILURE;
78 }
79
80 static const struct static_nodes_format static_nodes_format_human = {
81         .name = "human",
82         .write = write_human,
83         .description = "(default) a human readable format. Do not parse.",
84 };
85
86 static int write_tmpfiles(FILE *out, char modname[], char devname[], char type, unsigned int maj, unsigned int min)
87 {
88         const char *dir;
89         int ret;
90
91         dir = strrchr(devname, '/');
92         if (dir) {
93                 ret = fprintf(out, "d /dev/%.*s 0755 - - -\n",
94                               (int)(dir - devname), devname);
95                 if (ret < 0)
96                         return EXIT_FAILURE;
97         }
98
99         ret = fprintf(out, "%c! /dev/%s 0600 - - - %u:%u\n",
100                       type, devname, maj, min);
101         if (ret < 0)
102                 return EXIT_FAILURE;
103
104         return EXIT_SUCCESS;
105 }
106
107 static const struct static_nodes_format static_nodes_format_tmpfiles = {
108         .name = "tmpfiles",
109         .write = write_tmpfiles,
110         .description = "the tmpfiles.d(5) format used by systemd-tmpfiles.",
111 };
112
113 static int write_devname(FILE *out, char modname[], char devname[], char type, unsigned int maj, unsigned int min)
114 {
115         int ret;
116
117         ret = fprintf(out, "%s %s %c%u:%u\n", modname, devname, type, maj, min);
118         if (ret >= 0)
119                 return EXIT_SUCCESS;
120         else
121                 return EXIT_FAILURE;
122 }
123
124 static const struct static_nodes_format static_nodes_format_devname = {
125         .name = "devname",
126         .write = write_devname,
127         .description = "the modules.devname format.",
128 };
129
130 static void help(void)
131 {
132         size_t i;
133
134         printf("Usage:\n"
135                "\t%s static-nodes [options]\n"
136                "\n"
137                "kmod static-nodes outputs the static-node information of the currently running kernel.\n"
138                "\n"
139                "Options:\n"
140                "\t-f, --format=FORMAT  choose format to use: see \"Formats\"\n"
141                "\t-o, --output=FILE    write output to file\n"
142                "\t-h, --help           show this help\n"
143                "\n"
144                "Formats:\n",
145          program_invocation_short_name);
146
147         for (i = 0; i < ARRAY_SIZE(static_nodes_formats); i++) {
148                 if (static_nodes_formats[i]->description != NULL) {
149                         printf("\t%-12s %s\n", static_nodes_formats[i]->name,
150                                static_nodes_formats[i]->description);
151                 }
152         }
153 }
154
155 static int do_static_nodes(int argc, char *argv[])
156 {
157         struct utsname kernel;
158         char modules[PATH_MAX], buf[4096];
159         const char *output = "/dev/stdout";
160         FILE *in = NULL, *out = NULL;
161         const struct static_nodes_format *format = &static_nodes_format_human;
162         int r, ret = EXIT_SUCCESS;
163
164         for (;;) {
165                 int c, idx = 0, valid;
166                 size_t i;
167
168                 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
169                 if (c == -1) {
170                         break;
171                 }
172                 switch (c) {
173                 case 'o':
174                         output = optarg;
175                         break;
176                 case 'f':
177                         valid = 0;
178
179                         for (i = 0; i < ARRAY_SIZE(static_nodes_formats); i++) {
180                                 if (streq(static_nodes_formats[i]->name, optarg)) {
181                                         format = static_nodes_formats[i];
182                                         valid = 1;
183                                 }
184                         }
185
186                         if (!valid) {
187                                 fprintf(stderr, "Unknown format: '%s'.\n",
188                                         optarg);
189                                 help();
190                                 ret = EXIT_FAILURE;
191                                 goto finish;
192                         }
193                         break;
194                 case 'h':
195                         help();
196                         goto finish;
197                 case '?':
198                         ret = EXIT_FAILURE;
199                         goto finish;
200                 default:
201                         fprintf(stderr, "Unexpected commandline option '%c'.\n",
202                                 c);
203                         help();
204                         ret = EXIT_FAILURE;
205                         goto finish;
206                 }
207         }
208
209         if (uname(&kernel) < 0) {
210                 fputs("Error: uname failed!\n", stderr);
211                 ret = EXIT_FAILURE;
212                 goto finish;
213         }
214
215         snprintf(modules, sizeof(modules), "/lib/modules/%s/modules.devname", kernel.release);
216         in = fopen(modules, "re");
217         if (in == NULL) {
218                 if (errno == ENOENT) {
219                         fprintf(stderr, "Warning: /lib/modules/%s/modules.devname not found - ignoring\n",
220                                 kernel.release);
221                         ret = EXIT_SUCCESS;
222                 } else {
223                         fprintf(stderr, "Error: could not open /lib/modules/%s/modules.devname - %m\n",
224                                 kernel.release);
225                         ret = EXIT_FAILURE;
226                 }
227                 goto finish;
228         }
229
230         r = mkdir_parents(output, 0755);
231         if (r < 0) {
232                 fprintf(stderr, "Error: could not create parent directory for %s - %m.\n", output);
233                 ret = EXIT_FAILURE;
234                 goto finish;
235         }
236
237         out = fopen(output, "we");
238         if (out == NULL) {
239                 fprintf(stderr, "Error: could not create %s - %m\n", output);
240                 ret = EXIT_FAILURE;
241                 goto finish;
242         }
243
244         while (fgets(buf, sizeof(buf), in) != NULL) {
245                 char modname[PATH_MAX];
246                 char devname[PATH_MAX];
247                 char type;
248                 unsigned int maj, min;
249                 int matches;
250
251                 if (buf[0] == '#')
252                         continue;
253
254                 matches = sscanf(buf, "%s %s %c%u:%u", modname, devname,
255                                  &type, &maj, &min);
256                 if (matches != 5 || (type != 'c' && type != 'b')) {
257                         fprintf(stderr, "Error: invalid devname entry: %s", buf);
258                         ret = EXIT_FAILURE;
259                         continue;
260                 }
261
262                 format->write(out, modname, devname, type, maj, min);
263         }
264
265 finish:
266         if (in)
267                 fclose(in);
268         if (out)
269                 fclose(out);
270         return ret;
271 }
272
273 const struct kmod_cmd kmod_cmd_static_nodes = {
274         .name = "static-nodes",
275         .cmd = do_static_nodes,
276         .help = "outputs the static-node information installed with the currently running kernel",
277 };