]> git.ipfire.org Git - thirdparty/kmod.git/blob - tools/modinfo.c
Fix includes after change to build-sys
[thirdparty/kmod.git] / tools / modinfo.c
1 /*
2 * kmod-modinfo - query kernel module information using libkmod.
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
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 <errno.h>
21 #include <getopt.h>
22 #include <limits.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/utsname.h>
29
30 #include <shared/util.h>
31
32 #include <libkmod/libkmod.h>
33
34 #include "kmod.h"
35
36 static char separator = '\n';
37 static const char *field = NULL;
38
39 struct 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
49 static 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
86 static 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) {
93 ERR("Found invalid \"%s=%s\": missing ':'\n",
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) {
114 ERR("Out of memory!\n");
115 return -ENOMEM;
116 }
117
118 return 0;
119 }
120
121 static 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
162 end:
163 while (params != NULL) {
164 void *tmp = params;
165 params = params->next;
166 free(tmp);
167 }
168
169 return err;
170 }
171
172 static 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) {
188 ERR("could not get modinfo from '%s': %s\n",
189 kmod_module_get_name(mod), strerror(-err));
190 return err;
191 }
192
193 if (field != NULL && strcmp(field, "parm") == 0) {
194 err = modinfo_params_do(list);
195 goto end;
196 }
197
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) {
212 err = process_parm(key, value, &params);
213 if (err < 0)
214 goto end;
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)
239 printf("%-16s%.*s:%.*s (%.*s)%c", "parm:",
240 p->namelen, p->name,
241 p->paramlen, p->param,
242 p->typelen, p->type,
243 separator);
244 else
245 printf("%-16s%.*s:%.*s%c",
246 "parm:",
247 p->namelen, p->name,
248 p->paramlen, p->param,
249 separator);
250
251 free(p);
252 }
253
254 end:
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
265 static 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) {
270 ERR("Module file %s not found.\n", path);
271 return err;
272 }
273 err = modinfo_do(mod);
274 kmod_module_unref(mod);
275 return err;
276 }
277
278 static int modinfo_alias_do(struct kmod_ctx *ctx, const char *alias)
279 {
280 struct kmod_list *l, *filtered, *list = NULL;
281 int err = kmod_module_new_from_lookup(ctx, alias, &list);
282 if (err < 0) {
283 ERR("Module alias %s not found.\n", alias);
284 return err;
285 }
286
287 if (list == NULL) {
288 ERR("Module %s not found.\n", alias);
289 return -ENOENT;
290 }
291
292 err = kmod_module_apply_filter(ctx, KMOD_FILTER_BUILTIN, list, &filtered);
293 kmod_module_unref_list(list);
294 if (err < 0) {
295 ERR("Failed to filter list: %m\n");
296 return err;
297 }
298
299 if (filtered == NULL) {
300 ERR("Module %s not found.\n", alias);
301 return -ENOENT;
302 }
303
304 kmod_list_foreach(l, filtered) {
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 }
311 kmod_module_unref_list(filtered);
312 return err;
313 }
314
315 static const char cmdopts_s[] = "adlpn0F:k:b:Vh";
316 static 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
331 static void help(void)
332 {
333 printf("Usage:\n"
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"
344 "\t-b, --basedir=DIR Use DIR as filesystem root for /lib/modules\n"
345 "\t-V, --version Show version\n"
346 "\t-h, --help Show this help\n",
347 program_invocation_short_name);
348 }
349
350 static bool is_module_filename(const char *name)
351 {
352 struct stat st;
353
354 if (stat(name, &st) == 0 && S_ISREG(st.st_mode) &&
355 path_ends_with_kmod_ext(name, strlen(name)))
356 return true;
357
358 return false;
359 }
360
361 static int do_modinfo(int argc, char *argv[])
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':
405 help();
406 return EXIT_SUCCESS;
407 case 'V':
408 puts(PACKAGE " version " VERSION);
409 return EXIT_SUCCESS;
410 case '?':
411 return EXIT_FAILURE;
412 default:
413 ERR("unexpected getopt_long() value '%c'.\n", c);
414 return EXIT_FAILURE;
415 }
416 }
417
418 if (optind >= argc) {
419 ERR("missing module or filename.\n");
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) {
429 ERR("uname() failed: %m\n");
430 return EXIT_FAILURE;
431 }
432 kversion = u.release;
433 }
434 snprintf(dirname_buf, sizeof(dirname_buf), "%s/lib/modules/%s",
435 root, kversion);
436 dirname = dirname_buf;
437 }
438
439 ctx = kmod_new(dirname, &null_config);
440 if (!ctx) {
441 ERR("kmod_new() failed!\n");
442 return EXIT_FAILURE;
443 }
444
445 err = 0;
446 for (i = optind; i < argc; i++) {
447 const char *name = argv[i];
448 int r;
449
450 if (is_module_filename(name))
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 }
462
463 const struct kmod_cmd kmod_cmd_compat_modinfo = {
464 .name = "modinfo",
465 .cmd = do_modinfo,
466 .help = "compat modinfo command",
467 };