| /* modinfo.c - Display module info |
| * |
| * Copyright 2012 Andre Renaud <andre@bluewatersys.com> |
| * |
| * TODO: cleanup |
| |
| USE_MODINFO(NEWTOY(modinfo, "<1b:k:F:0", TOYFLAG_SBIN)) |
| |
| config MODINFO |
| bool "modinfo" |
| default y |
| help |
| usage: modinfo [-0] [-b basedir] [-k kernel] [-F field] [module|file...] |
| |
| Display module fields for modules specified by name or .ko path. |
| |
| -F Only show the given field |
| -0 Separate fields with NUL rather than newline |
| -b Use <basedir> as root for /lib/modules/ |
| -k Look in given directory under /lib/modules/ |
| */ |
| |
| #define FOR_modinfo |
| #include "toys.h" |
| |
| GLOBALS( |
| char *F, *k, *b; |
| |
| long mod; |
| int count; |
| ) |
| |
| static void output_field(char *field, char *value) |
| { |
| if (!TT.F) xprintf("%s:%*c", field, 15-(int)strlen(field), ' '); |
| else if (strcmp(TT.F, field)) return; |
| xprintf("%s", value); |
| xputc(FLAG(0) ? 0 : '\n'); |
| } |
| |
| static void modinfo_file(char *full_name) |
| { |
| int fd, len, i; |
| char *buf = 0, *pos, *modinfo_tags[] = { |
| "alias", "license", "description", "author", "firmware", |
| "vermagic", "srcversion", "intree", "depends", "parm", |
| "parmtype", |
| }; |
| |
| if (-1 != (fd = open(full_name, O_RDONLY))) { |
| len = fdlength(fd); |
| buf = xmmap(0, len, PROT_READ, MAP_SHARED, fd, 0); |
| close(fd); |
| } |
| |
| if (!buf) { |
| perror_msg_raw(full_name); |
| return; |
| } |
| |
| TT.count++; |
| output_field("filename", full_name); |
| |
| for (pos = buf; pos < buf+len; pos++) { |
| if (*pos) continue; |
| |
| for (i=0; i<ARRAY_LEN(modinfo_tags); i++) { |
| char *str = modinfo_tags[i]; |
| int len = strlen(str); |
| |
| if (!strncmp(pos+1, str, len) && pos[len+1] == '=') |
| output_field(str, pos+len+2); |
| } |
| } |
| |
| munmap(buf, len); |
| } |
| |
| static int check_module(struct dirtree *new) |
| { |
| if (!dirtree_notdotdot(new)) return 0; |
| |
| if (S_ISREG(new->st.st_mode)) { |
| char *s; |
| |
| for (s = toys.optargs[TT.mod]; *s; s++) { |
| int len = 0; |
| |
| // The kernel treats - and _ the same, so we should too. |
| for (len = 0; s[len]; len++) { |
| if (s[len] == '-' && new->name[len] == '_') continue; |
| if (s[len] == '_' && new->name[len] == '-') continue; |
| if (s[len] != new->name[len]) break; |
| } |
| if (s[len] || strcmp(new->name+len, ".ko")) break; |
| |
| modinfo_file(s = dirtree_path(new, 0)); |
| free(s); |
| |
| return DIRTREE_ABORT; |
| } |
| } |
| |
| return DIRTREE_RECURSE; |
| } |
| |
| void modinfo_main(void) |
| { |
| struct utsname uts; |
| |
| // Android (as shipped by Google) currently only has modules on /vendor. |
| // Android does not support multiple sets of modules for different kernels. |
| if (CFG_TOYBOX_ON_ANDROID) { |
| if (!TT.b) TT.b = "/vendor"; |
| if (!TT.k) TT.k = ""; |
| } else { |
| uname(&uts); |
| if (!TT.b) TT.b = ""; |
| if (!TT.k) TT.k = uts.release; |
| } |
| |
| for (TT.mod = 0; TT.mod<toys.optc; TT.mod++) { |
| char *s = strstr(toys.optargs[TT.mod], ".ko"); |
| |
| if (s && !s[3]) modinfo_file(toys.optargs[TT.mod]); |
| else { |
| char *path = xmprintf("%s/lib/modules/%s", TT.b, TT.k); |
| |
| TT.count = 0; |
| dirtree_read(path, check_module); |
| if (!TT.count) error_msg("%s: not found", toys.optargs[TT.mod]); |
| free(path); |
| } |
| } |
| } |