1/* modinfo.c - Display module info 2 * 3 * Copyright 2012 Andre Renaud <andre@bluewatersys.com> 4 * 5 * TODO: cleanup 6 7USE_MODINFO(NEWTOY(modinfo, "<1b:k:F:0", TOYFLAG_SBIN)) 8 9config MODINFO 10 bool "modinfo" 11 default y 12 help 13 usage: modinfo [-0] [-b basedir] [-k kernel] [-F field] [module|file...] 14 15 Display module fields for modules specified by name or .ko path. 16 17 -F Only show the given field 18 -0 Separate fields with NUL rather than newline 19 -b Use <basedir> as root for /lib/modules/ 20 -k Look in given directory under /lib/modules/ 21*/ 22 23#define FOR_modinfo 24#include "toys.h" 25 26GLOBALS( 27 char *F, *k, *b; 28 29 long mod; 30 int count; 31) 32 33static void output_field(char *field, char *value) 34{ 35 if (!TT.F) xprintf("%s:%*c", field, 15-(int)strlen(field), ' '); 36 else if (strcmp(TT.F, field)) return; 37 xprintf("%s", value); 38 xputc(FLAG(0) ? 0 : '\n'); 39} 40 41static void modinfo_file(char *full_name) 42{ 43 int fd, len, i; 44 char *buf = 0, *pos, *modinfo_tags[] = { 45 "alias", "license", "description", "author", "firmware", 46 "vermagic", "srcversion", "intree", "depends", "parm", 47 "parmtype", 48 }; 49 50 if (-1 != (fd = open(full_name, O_RDONLY))) { 51 len = fdlength(fd); 52 buf = xmmap(0, len, PROT_READ, MAP_SHARED, fd, 0); 53 close(fd); 54 } 55 56 if (!buf) { 57 perror_msg_raw(full_name); 58 return; 59 } 60 61 TT.count++; 62 output_field("filename", full_name); 63 64 for (pos = buf; pos < buf+len; pos++) { 65 if (*pos) continue; 66 67 for (i=0; i<ARRAY_LEN(modinfo_tags); i++) { 68 char *str = modinfo_tags[i]; 69 int len = strlen(str); 70 71 if (!strncmp(pos+1, str, len) && pos[len+1] == '=') 72 output_field(str, pos+len+2); 73 } 74 } 75 76 munmap(buf, len); 77} 78 79static int check_module(struct dirtree *new) 80{ 81 if (!dirtree_notdotdot(new)) return 0; 82 83 if (S_ISREG(new->st.st_mode)) { 84 char *s; 85 86 for (s = toys.optargs[TT.mod]; *s; s++) { 87 int len = 0; 88 89 // The kernel treats - and _ the same, so we should too. 90 for (len = 0; s[len]; len++) { 91 if (s[len] == '-' && new->name[len] == '_') continue; 92 if (s[len] == '_' && new->name[len] == '-') continue; 93 if (s[len] != new->name[len]) break; 94 } 95 if (s[len] || strcmp(new->name+len, ".ko")) break; 96 97 modinfo_file(s = dirtree_path(new, 0)); 98 free(s); 99 100 return DIRTREE_ABORT; 101 } 102 } 103 104 return DIRTREE_RECURSE; 105} 106 107void modinfo_main(void) 108{ 109 struct utsname uts; 110 111 // Android (as shipped by Google) currently only has modules on /vendor. 112 // Android does not support multiple sets of modules for different kernels. 113 if (CFG_TOYBOX_ON_ANDROID) { 114 if (!TT.b) TT.b = "/vendor"; 115 if (!TT.k) TT.k = ""; 116 } else { 117 uname(&uts); 118 if (!TT.b) TT.b = ""; 119 if (!TT.k) TT.k = uts.release; 120 } 121 122 for (TT.mod = 0; TT.mod<toys.optc; TT.mod++) { 123 char *s = strstr(toys.optargs[TT.mod], ".ko"); 124 125 if (s && !s[3]) modinfo_file(toys.optargs[TT.mod]); 126 else { 127 char *path = xmprintf("%s/lib/modules/%s", TT.b, TT.k); 128 129 TT.count = 0; 130 dirtree_read(path, check_module); 131 if (!TT.count) error_msg("%s: not found", toys.optargs[TT.mod]); 132 free(path); 133 } 134 } 135} 136