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