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