]> git.ipfire.org Git - thirdparty/kmod.git/blame - tools/modinfo.c
testsuite: prefer the use of streq()
[thirdparty/kmod.git] / tools / modinfo.c
CommitLineData
0cc3ccfd
GSB
1/*
2 * kmod-modinfo - query kernel module information using libkmod.
3 *
e6b0e49b 4 * Copyright (C) 2011-2013 ProFUSION embedded systems
0cc3ccfd
GSB
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
c2e4286b
LDM
20#include <errno.h>
21#include <getopt.h>
22#include <limits.h>
23#include <stdbool.h>
0cc3ccfd
GSB
24#include <stdio.h>
25#include <stdlib.h>
0cc3ccfd 26#include <string.h>
0cc3ccfd 27#include <sys/stat.h>
c2e4286b
LDM
28#include <sys/utsname.h>
29
f4e8c162
LDM
30#include <shared/util.h>
31
f357866d 32#include <libkmod/libkmod.h>
0cc3ccfd 33
4a2e20df
LDM
34#include "kmod.h"
35
0cc3ccfd
GSB
36static char separator = '\n';
37static const char *field = NULL;
38
39struct param {
40 struct param *next;
41 const char *name;
42 const char *param;
43 const char *type;
44 int namelen;
45 int paramlen;
46 int typelen;
47};
48
49static struct param *add_param(const char *name, int namelen, const char *param, int paramlen, const char *type, int typelen, struct param **list)
50{
51 struct param *it;
52
53 for (it = *list; it != NULL; it = it->next) {
54 if (it->namelen == namelen &&
55 memcmp(it->name, name, namelen) == 0)
56 break;
57 }
58
59 if (it == NULL) {
60 it = malloc(sizeof(struct param));
61 if (it == NULL)
62 return NULL;
63 it->next = *list;
64 *list = it;
65 it->name = name;
66 it->namelen = namelen;
67 it->param = NULL;
68 it->type = NULL;
69 it->paramlen = 0;
70 it->typelen = 0;
71 }
72
73 if (param != NULL) {
74 it->param = param;
75 it->paramlen = paramlen;
76 }
77
78 if (type != NULL) {
79 it->type = type;
80 it->typelen = typelen;
81 }
82
83 return it;
84}
85
b014c490
GSB
86static int process_parm(const char *key, const char *value, struct param **params)
87{
88 const char *name, *param, *type;
89 int namelen, paramlen, typelen;
90 struct param *it;
91 const char *colon = strchr(value, ':');
92 if (colon == NULL) {
9382dbf7 93 ERR("Found invalid \"%s=%s\": missing ':'\n",
b014c490
GSB
94 key, value);
95 return 0;
96 }
97
98 name = value;
99 namelen = colon - value;
100 if (strcmp(key, "parm") == 0) {
101 param = colon + 1;
102 paramlen = strlen(param);
103 type = NULL;
104 typelen = 0;
105 } else {
106 param = NULL;
107 paramlen = 0;
108 type = colon + 1;
109 typelen = strlen(type);
110 }
111
112 it = add_param(name, namelen, param, paramlen, type, typelen, params);
113 if (it == NULL) {
9382dbf7 114 ERR("Out of memory!\n");
b014c490
GSB
115 return -ENOMEM;
116 }
117
118 return 0;
119}
120
121static int modinfo_params_do(const struct kmod_list *list)
122{
123 const struct kmod_list *l;
124 struct param *params = NULL;
125 int err = 0;
126
127 kmod_list_foreach(l, list) {
128 const char *key = kmod_module_info_get_key(l);
129 const char *value = kmod_module_info_get_value(l);
130 if (strcmp(key, "parm") != 0 &&
131 strcmp(key, "parmtype") != 0)
132 continue;
133
134 err = process_parm(key, value, &params);
135 if (err < 0)
136 goto end;
137 }
138
139 while (params != NULL) {
140 struct param *p = params;
141 params = p->next;
142
143 if (p->param == NULL)
144 printf("%.*s: (%.*s)%c",
145 p->namelen, p->name, p->typelen, p->type,
146 separator);
147 else if (p->type != NULL)
148 printf("%.*s:%.*s (%.*s)%c",
149 p->namelen, p->name,
150 p->paramlen, p->param,
151 p->typelen, p->type,
152 separator);
153 else
154 printf("%.*s:%.*s%c",
155 p->namelen, p->name,
156 p->paramlen, p->param,
157 separator);
158
159 free(p);
160 }
161
162end:
163 while (params != NULL) {
164 void *tmp = params;
165 params = params->next;
166 free(tmp);
167 }
168
169 return err;
170}
171
0cc3ccfd
GSB
172static int modinfo_do(struct kmod_module *mod)
173{
174 struct kmod_list *l, *list = NULL;
175 struct param *params = NULL;
176 int err;
177
178 if (field != NULL && strcmp(field, "filename") == 0) {
179 printf("%s%c", kmod_module_get_path(mod), separator);
180 return 0;
181 } else if (field == NULL) {
182 printf("%-16s%s%c", "filename:",
183 kmod_module_get_path(mod), separator);
184 }
185
186 err = kmod_module_get_info(mod, &list);
187 if (err < 0) {
9382dbf7 188 ERR("could not get modinfo from '%s': %s\n",
0cc3ccfd
GSB
189 kmod_module_get_name(mod), strerror(-err));
190 return err;
191 }
192
b014c490
GSB
193 if (field != NULL && strcmp(field, "parm") == 0) {
194 err = modinfo_params_do(list);
195 goto end;
196 }
197
0cc3ccfd
GSB
198 kmod_list_foreach(l, list) {
199 const char *key = kmod_module_info_get_key(l);
200 const char *value = kmod_module_info_get_value(l);
201 int keylen;
202
203 if (field != NULL) {
204 if (strcmp(field, key) != 0)
205 continue;
206 /* filtered output contains no key, just value */
207 printf("%s%c", value, separator);
208 continue;
209 }
210
211 if (strcmp(key, "parm") == 0 || strcmp(key, "parmtype") == 0) {
b014c490
GSB
212 err = process_parm(key, value, &params);
213 if (err < 0)
0cc3ccfd 214 goto end;
0cc3ccfd
GSB
215 continue;
216 }
217
218 if (separator == '\0') {
219 printf("%s=%s%c", key, value, separator);
220 continue;
221 }
222
223 keylen = strlen(key);
224 printf("%s:%-*s%s%c", key, 15 - keylen, "", value, separator);
225 }
226
227 if (field != NULL)
228 goto end;
229
230 while (params != NULL) {
231 struct param *p = params;
232 params = p->next;
233
234 if (p->param == NULL)
235 printf("%-16s%.*s:%.*s%c", "parm:",
236 p->namelen, p->name, p->typelen, p->type,
237 separator);
238 else if (p->type != NULL)
515ec796 239 printf("%-16s%.*s:%.*s (%.*s)%c", "parm:",
0cc3ccfd
GSB
240 p->namelen, p->name,
241 p->paramlen, p->param,
242 p->typelen, p->type,
243 separator);
244 else
515ec796 245 printf("%-16s%.*s:%.*s%c",
0cc3ccfd
GSB
246 "parm:",
247 p->namelen, p->name,
248 p->paramlen, p->param,
249 separator);
250
251 free(p);
252 }
253
254end:
255 while (params != NULL) {
256 void *tmp = params;
257 params = params->next;
258 free(tmp);
259 }
260 kmod_module_info_free_list(list);
261
262 return err;
263}
264
265static int modinfo_path_do(struct kmod_ctx *ctx, const char *path)
266{
267 struct kmod_module *mod;
268 int err = kmod_module_new_from_path(ctx, path, &mod);
269 if (err < 0) {
9382dbf7 270 ERR("Module file %s not found.\n", path);
0cc3ccfd
GSB
271 return err;
272 }
273 err = modinfo_do(mod);
274 kmod_module_unref(mod);
275 return err;
276}
277
278static int modinfo_alias_do(struct kmod_ctx *ctx, const char *alias)
279{
3e4c6af6 280 struct kmod_list *l, *filtered, *list = NULL;
0cc3ccfd
GSB
281 int err = kmod_module_new_from_lookup(ctx, alias, &list);
282 if (err < 0) {
9382dbf7 283 ERR("Module alias %s not found.\n", alias);
0cc3ccfd
GSB
284 return err;
285 }
5f85a133
DR
286
287 if (list == NULL) {
9382dbf7 288 ERR("Module %s not found.\n", alias);
5f85a133
DR
289 return -ENOENT;
290 }
291
3e4c6af6
DR
292 err = kmod_module_apply_filter(ctx, KMOD_FILTER_BUILTIN, list, &filtered);
293 kmod_module_unref_list(list);
294 if (err < 0) {
9382dbf7 295 ERR("Failed to filter list: %m\n");
3e4c6af6
DR
296 return err;
297 }
298
299 if (filtered == NULL) {
9382dbf7 300 ERR("Module %s not found.\n", alias);
3e4c6af6
DR
301 return -ENOENT;
302 }
303
304 kmod_list_foreach(l, filtered) {
0cc3ccfd
GSB
305 struct kmod_module *mod = kmod_module_get_module(l);
306 int r = modinfo_do(mod);
307 kmod_module_unref(mod);
308 if (r < 0)
309 err = r;
310 }
3e4c6af6 311 kmod_module_unref_list(filtered);
0cc3ccfd
GSB
312 return err;
313}
314
022e1f0e 315static const char cmdopts_s[] = "adlpn0F:k:b:Vh";
0cc3ccfd
GSB
316static const struct option cmdopts[] = {
317 {"author", no_argument, 0, 'a'},
318 {"description", no_argument, 0, 'd'},
319 {"license", no_argument, 0, 'l'},
320 {"parameters", no_argument, 0, 'p'},
321 {"filename", no_argument, 0, 'n'},
322 {"null", no_argument, 0, '0'},
323 {"field", required_argument, 0, 'F'},
324 {"set-version", required_argument, 0, 'k'},
325 {"basedir", required_argument, 0, 'b'},
326 {"version", no_argument, 0, 'V'},
327 {"help", no_argument, 0, 'h'},
328 {NULL, 0, 0, 0}
329};
330
4a2e20df 331static void help(void)
0cc3ccfd 332{
34e06bfb 333 printf("Usage:\n"
0cc3ccfd
GSB
334 "\t%s [options] filename [args]\n"
335 "Options:\n"
336 "\t-a, --author Print only 'author'\n"
337 "\t-d, --description Print only 'description'\n"
338 "\t-l, --license Print only 'license'\n"
339 "\t-p, --parameters Print only 'parm'\n"
340 "\t-n, --filename Print only 'filename'\n"
341 "\t-0, --null Use \\0 instead of \\n\n"
342 "\t-F, --field=FIELD Print only provided FIELD\n"
343 "\t-k, --set-version=VERSION Use VERSION instead of `uname -r`\n"
c5b37dba 344 "\t-b, --basedir=DIR Use DIR as filesystem root for /lib/modules\n"
0cc3ccfd
GSB
345 "\t-V, --version Show version\n"
346 "\t-h, --help Show this help\n",
7c04aeee 347 program_invocation_short_name);
0cc3ccfd
GSB
348}
349
a23f0c9c
DM
350static bool is_module_filename(const char *name)
351{
352 struct stat st;
a23f0c9c
DM
353
354 if (stat(name, &st) == 0 && S_ISREG(st.st_mode) &&
6f02b6fa 355 path_ends_with_kmod_ext(name, strlen(name)))
a23f0c9c 356 return true;
a23f0c9c
DM
357
358 return false;
359}
360
769becb5 361static int do_modinfo(int argc, char *argv[])
0cc3ccfd
GSB
362{
363 struct kmod_ctx *ctx;
364 char dirname_buf[PATH_MAX];
365 const char *dirname = NULL;
366 const char *kversion = NULL;
367 const char *root = NULL;
368 const char *null_config = NULL;
369 int i, err;
370
371 for (;;) {
372 int c, idx = 0;
373 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
374 if (c == -1)
375 break;
376 switch (c) {
377 case 'a':
378 field = "author";
379 break;
380 case 'd':
381 field = "description";
382 break;
383 case 'l':
384 field = "license";
385 break;
386 case 'p':
387 field = "parm";
388 break;
389 case 'n':
390 field = "filename";
391 break;
392 case '0':
393 separator = '\0';
394 break;
395 case 'F':
396 field = optarg;
397 break;
398 case 'k':
399 kversion = optarg;
400 break;
401 case 'b':
402 root = optarg;
403 break;
404 case 'h':
4a2e20df 405 help();
0cc3ccfd
GSB
406 return EXIT_SUCCESS;
407 case 'V':
408 puts(PACKAGE " version " VERSION);
409 return EXIT_SUCCESS;
410 case '?':
411 return EXIT_FAILURE;
412 default:
9382dbf7 413 ERR("unexpected getopt_long() value '%c'.\n", c);
0cc3ccfd
GSB
414 return EXIT_FAILURE;
415 }
416 }
417
418 if (optind >= argc) {
9382dbf7 419 ERR("missing module or filename.\n");
0cc3ccfd
GSB
420 return EXIT_FAILURE;
421 }
422
423 if (root != NULL || kversion != NULL) {
424 struct utsname u;
425 if (root == NULL)
426 root = "";
427 if (kversion == NULL) {
428 if (uname(&u) < 0) {
9382dbf7 429 ERR("uname() failed: %m\n");
0cc3ccfd
GSB
430 return EXIT_FAILURE;
431 }
432 kversion = u.release;
433 }
c5b37dba 434 snprintf(dirname_buf, sizeof(dirname_buf), "%s/lib/modules/%s",
0cc3ccfd
GSB
435 root, kversion);
436 dirname = dirname_buf;
437 }
438
439 ctx = kmod_new(dirname, &null_config);
440 if (!ctx) {
9382dbf7 441 ERR("kmod_new() failed!\n");
0cc3ccfd
GSB
442 return EXIT_FAILURE;
443 }
0cc3ccfd
GSB
444
445 err = 0;
446 for (i = optind; i < argc; i++) {
447 const char *name = argv[i];
0cc3ccfd
GSB
448 int r;
449
a23f0c9c 450 if (is_module_filename(name))
0cc3ccfd
GSB
451 r = modinfo_path_do(ctx, name);
452 else
453 r = modinfo_alias_do(ctx, name);
454
455 if (r < 0)
456 err = r;
457 }
458
459 kmod_unref(ctx);
460 return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
461}
769becb5 462
769becb5
LDM
463const struct kmod_cmd kmod_cmd_compat_modinfo = {
464 .name = "modinfo",
465 .cmd = do_modinfo,
466 .help = "compat modinfo command",
467};