1*cf5a6c84SAndroid Build Coastguard Worker /* modprobe.c - modprobe utility.
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2012 Madhur Verma <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2013 Kyungwan Han <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker *
6*cf5a6c84SAndroid Build Coastguard Worker * No Standard.
7*cf5a6c84SAndroid Build Coastguard Worker
8*cf5a6c84SAndroid Build Coastguard Worker USE_MODPROBE(NEWTOY(modprobe, "alrqvsDbd*", TOYFLAG_SBIN))
9*cf5a6c84SAndroid Build Coastguard Worker
10*cf5a6c84SAndroid Build Coastguard Worker config MODPROBE
11*cf5a6c84SAndroid Build Coastguard Worker bool "modprobe"
12*cf5a6c84SAndroid Build Coastguard Worker default n
13*cf5a6c84SAndroid Build Coastguard Worker help
14*cf5a6c84SAndroid Build Coastguard Worker usage: modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]
15*cf5a6c84SAndroid Build Coastguard Worker
16*cf5a6c84SAndroid Build Coastguard Worker modprobe utility - inserts modules and dependencies.
17*cf5a6c84SAndroid Build Coastguard Worker
18*cf5a6c84SAndroid Build Coastguard Worker -a Load multiple MODULEs
19*cf5a6c84SAndroid Build Coastguard Worker -b Apply blacklist to module names too
20*cf5a6c84SAndroid Build Coastguard Worker -D Show dependencies
21*cf5a6c84SAndroid Build Coastguard Worker -d Load modules from DIR, option may be used multiple times
22*cf5a6c84SAndroid Build Coastguard Worker -l List (MODULE is a pattern)
23*cf5a6c84SAndroid Build Coastguard Worker -q Quiet
24*cf5a6c84SAndroid Build Coastguard Worker -r Remove MODULE (stacks) or do autoclean
25*cf5a6c84SAndroid Build Coastguard Worker -s Log to syslog
26*cf5a6c84SAndroid Build Coastguard Worker -v Verbose
27*cf5a6c84SAndroid Build Coastguard Worker */
28*cf5a6c84SAndroid Build Coastguard Worker #define FOR_modprobe
29*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
30*cf5a6c84SAndroid Build Coastguard Worker
31*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
32*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *dirs;
33*cf5a6c84SAndroid Build Coastguard Worker
34*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *probes, *dbase[256];
35*cf5a6c84SAndroid Build Coastguard Worker char *cmdopts;
36*cf5a6c84SAndroid Build Coastguard Worker int nudeps, symreq;
37*cf5a6c84SAndroid Build Coastguard Worker )
38*cf5a6c84SAndroid Build Coastguard Worker
39*cf5a6c84SAndroid Build Coastguard Worker #define MODNAME_LEN 256
40*cf5a6c84SAndroid Build Coastguard Worker
41*cf5a6c84SAndroid Build Coastguard Worker // Modules flag definations
42*cf5a6c84SAndroid Build Coastguard Worker #define MOD_ALOADED 0x0001
43*cf5a6c84SAndroid Build Coastguard Worker #define MOD_BLACKLIST 0x0002
44*cf5a6c84SAndroid Build Coastguard Worker #define MOD_FNDDEPMOD 0x0004
45*cf5a6c84SAndroid Build Coastguard Worker #define MOD_NDDEPS 0x0008
46*cf5a6c84SAndroid Build Coastguard Worker
47*cf5a6c84SAndroid Build Coastguard Worker // Current probing modules info
48*cf5a6c84SAndroid Build Coastguard Worker struct module_s {
49*cf5a6c84SAndroid Build Coastguard Worker uint32_t flags;
50*cf5a6c84SAndroid Build Coastguard Worker char *cmdname, *name, *depent, *opts;
51*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *rnames, *dep;
52*cf5a6c84SAndroid Build Coastguard Worker };
53*cf5a6c84SAndroid Build Coastguard Worker
54*cf5a6c84SAndroid Build Coastguard Worker // Converts path name FILE to module name.
path2mod(char * file,char * mod)55*cf5a6c84SAndroid Build Coastguard Worker static char *path2mod(char *file, char *mod)
56*cf5a6c84SAndroid Build Coastguard Worker {
57*cf5a6c84SAndroid Build Coastguard Worker int i;
58*cf5a6c84SAndroid Build Coastguard Worker char *from;
59*cf5a6c84SAndroid Build Coastguard Worker
60*cf5a6c84SAndroid Build Coastguard Worker if (!file) return NULL;
61*cf5a6c84SAndroid Build Coastguard Worker if (!mod) mod = xmalloc(MODNAME_LEN);
62*cf5a6c84SAndroid Build Coastguard Worker
63*cf5a6c84SAndroid Build Coastguard Worker from = getbasename(file);
64*cf5a6c84SAndroid Build Coastguard Worker
65*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i < (MODNAME_LEN-1) && from[i] && from[i] != '.'; i++)
66*cf5a6c84SAndroid Build Coastguard Worker mod[i] = (from[i] == '-') ? '_' : from[i];
67*cf5a6c84SAndroid Build Coastguard Worker mod[i] = '\0';
68*cf5a6c84SAndroid Build Coastguard Worker return mod;
69*cf5a6c84SAndroid Build Coastguard Worker }
70*cf5a6c84SAndroid Build Coastguard Worker
71*cf5a6c84SAndroid Build Coastguard Worker // Add options in opts from toadd.
add_opts(char * opts,char * toadd)72*cf5a6c84SAndroid Build Coastguard Worker static char *add_opts(char *opts, char *toadd)
73*cf5a6c84SAndroid Build Coastguard Worker {
74*cf5a6c84SAndroid Build Coastguard Worker if (toadd) {
75*cf5a6c84SAndroid Build Coastguard Worker int optlen = 0;
76*cf5a6c84SAndroid Build Coastguard Worker
77*cf5a6c84SAndroid Build Coastguard Worker if (opts) optlen = strlen(opts);
78*cf5a6c84SAndroid Build Coastguard Worker opts = xrealloc(opts, optlen + strlen(toadd) + 2);
79*cf5a6c84SAndroid Build Coastguard Worker sprintf(opts + optlen, " %s", toadd);
80*cf5a6c84SAndroid Build Coastguard Worker }
81*cf5a6c84SAndroid Build Coastguard Worker return opts;
82*cf5a6c84SAndroid Build Coastguard Worker }
83*cf5a6c84SAndroid Build Coastguard Worker
84*cf5a6c84SAndroid Build Coastguard Worker // Remove first element from the list and return it.
llist_popme(struct arg_list ** head)85*cf5a6c84SAndroid Build Coastguard Worker static void *llist_popme(struct arg_list **head)
86*cf5a6c84SAndroid Build Coastguard Worker {
87*cf5a6c84SAndroid Build Coastguard Worker char *data = NULL;
88*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *temp = *head;
89*cf5a6c84SAndroid Build Coastguard Worker
90*cf5a6c84SAndroid Build Coastguard Worker if (temp) {
91*cf5a6c84SAndroid Build Coastguard Worker data = temp->arg;
92*cf5a6c84SAndroid Build Coastguard Worker *head = temp->next;
93*cf5a6c84SAndroid Build Coastguard Worker free(temp);
94*cf5a6c84SAndroid Build Coastguard Worker }
95*cf5a6c84SAndroid Build Coastguard Worker return data;
96*cf5a6c84SAndroid Build Coastguard Worker }
97*cf5a6c84SAndroid Build Coastguard Worker
98*cf5a6c84SAndroid Build Coastguard Worker // Add new node at the beginning of the list.
llist_add(struct arg_list ** old,void * data)99*cf5a6c84SAndroid Build Coastguard Worker static void llist_add(struct arg_list **old, void *data)
100*cf5a6c84SAndroid Build Coastguard Worker {
101*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *new = xmalloc(sizeof(struct arg_list));
102*cf5a6c84SAndroid Build Coastguard Worker
103*cf5a6c84SAndroid Build Coastguard Worker new->arg = (char*)data;
104*cf5a6c84SAndroid Build Coastguard Worker new->next = *old;
105*cf5a6c84SAndroid Build Coastguard Worker *old = new;
106*cf5a6c84SAndroid Build Coastguard Worker }
107*cf5a6c84SAndroid Build Coastguard Worker
108*cf5a6c84SAndroid Build Coastguard Worker // Add new node at tail of list.
llist_add_tail(struct arg_list ** head,void * data)109*cf5a6c84SAndroid Build Coastguard Worker static void llist_add_tail(struct arg_list **head, void *data)
110*cf5a6c84SAndroid Build Coastguard Worker {
111*cf5a6c84SAndroid Build Coastguard Worker while (*head) head = &(*head)->next;
112*cf5a6c84SAndroid Build Coastguard Worker *head = xzalloc(sizeof(struct arg_list));
113*cf5a6c84SAndroid Build Coastguard Worker (*head)->arg = (char*)data;
114*cf5a6c84SAndroid Build Coastguard Worker }
115*cf5a6c84SAndroid Build Coastguard Worker
116*cf5a6c84SAndroid Build Coastguard Worker // Reverse list order.
llist_rev(struct arg_list * list)117*cf5a6c84SAndroid Build Coastguard Worker static struct arg_list *llist_rev(struct arg_list *list)
118*cf5a6c84SAndroid Build Coastguard Worker {
119*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *rev = NULL;
120*cf5a6c84SAndroid Build Coastguard Worker
121*cf5a6c84SAndroid Build Coastguard Worker while (list) {
122*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *next = list->next;
123*cf5a6c84SAndroid Build Coastguard Worker
124*cf5a6c84SAndroid Build Coastguard Worker list->next = rev;
125*cf5a6c84SAndroid Build Coastguard Worker rev = list;
126*cf5a6c84SAndroid Build Coastguard Worker list = next;
127*cf5a6c84SAndroid Build Coastguard Worker }
128*cf5a6c84SAndroid Build Coastguard Worker return rev;
129*cf5a6c84SAndroid Build Coastguard Worker }
130*cf5a6c84SAndroid Build Coastguard Worker
131*cf5a6c84SAndroid Build Coastguard Worker /*
132*cf5a6c84SAndroid Build Coastguard Worker * Returns struct module_s from the data base if found, NULL otherwise.
133*cf5a6c84SAndroid Build Coastguard Worker * if add - create module entry, add it to data base and return the same mod.
134*cf5a6c84SAndroid Build Coastguard Worker */
get_mod(char * mod,uint8_t add)135*cf5a6c84SAndroid Build Coastguard Worker static struct module_s *get_mod(char *mod, uint8_t add)
136*cf5a6c84SAndroid Build Coastguard Worker {
137*cf5a6c84SAndroid Build Coastguard Worker char name[MODNAME_LEN];
138*cf5a6c84SAndroid Build Coastguard Worker struct module_s *modentry;
139*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *temp;
140*cf5a6c84SAndroid Build Coastguard Worker unsigned i, hash = 0;
141*cf5a6c84SAndroid Build Coastguard Worker
142*cf5a6c84SAndroid Build Coastguard Worker path2mod(mod, name);
143*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; name[i]; i++) hash = ((hash*31) + hash) + name[i];
144*cf5a6c84SAndroid Build Coastguard Worker hash %= ARRAY_LEN(TT.dbase);
145*cf5a6c84SAndroid Build Coastguard Worker for (temp = TT.dbase[hash]; temp; temp = temp->next) {
146*cf5a6c84SAndroid Build Coastguard Worker modentry = (struct module_s *) temp->arg;
147*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(modentry->name, name)) return modentry;
148*cf5a6c84SAndroid Build Coastguard Worker }
149*cf5a6c84SAndroid Build Coastguard Worker if (!add) return NULL;
150*cf5a6c84SAndroid Build Coastguard Worker modentry = xzalloc(sizeof(*modentry));
151*cf5a6c84SAndroid Build Coastguard Worker modentry->name = xstrdup(name);
152*cf5a6c84SAndroid Build Coastguard Worker llist_add(&TT.dbase[hash], modentry);
153*cf5a6c84SAndroid Build Coastguard Worker return modentry;
154*cf5a6c84SAndroid Build Coastguard Worker }
155*cf5a6c84SAndroid Build Coastguard Worker
156*cf5a6c84SAndroid Build Coastguard Worker /*
157*cf5a6c84SAndroid Build Coastguard Worker * Read a line from file with \ continuation and skip commented lines.
158*cf5a6c84SAndroid Build Coastguard Worker * Return the line in allocated string (*li)
159*cf5a6c84SAndroid Build Coastguard Worker */
read_line(FILE * fl,char ** li)160*cf5a6c84SAndroid Build Coastguard Worker static int read_line(FILE *fl, char **li)
161*cf5a6c84SAndroid Build Coastguard Worker {
162*cf5a6c84SAndroid Build Coastguard Worker char *nxtline = NULL, *line;
163*cf5a6c84SAndroid Build Coastguard Worker ssize_t len, nxtlen;
164*cf5a6c84SAndroid Build Coastguard Worker size_t linelen, nxtlinelen;
165*cf5a6c84SAndroid Build Coastguard Worker
166*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
167*cf5a6c84SAndroid Build Coastguard Worker line = NULL;
168*cf5a6c84SAndroid Build Coastguard Worker linelen = nxtlinelen = 0;
169*cf5a6c84SAndroid Build Coastguard Worker len = getline(&line, &linelen, fl);
170*cf5a6c84SAndroid Build Coastguard Worker if (len <= 0) {
171*cf5a6c84SAndroid Build Coastguard Worker free(line);
172*cf5a6c84SAndroid Build Coastguard Worker return len;
173*cf5a6c84SAndroid Build Coastguard Worker }
174*cf5a6c84SAndroid Build Coastguard Worker // checking for commented lines.
175*cf5a6c84SAndroid Build Coastguard Worker if (line[0] != '#') break;
176*cf5a6c84SAndroid Build Coastguard Worker free(line);
177*cf5a6c84SAndroid Build Coastguard Worker }
178*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
179*cf5a6c84SAndroid Build Coastguard Worker if (line[len - 1] == '\n') len--;
180*cf5a6c84SAndroid Build Coastguard Worker if (!len) {
181*cf5a6c84SAndroid Build Coastguard Worker free(line);
182*cf5a6c84SAndroid Build Coastguard Worker return len;
183*cf5a6c84SAndroid Build Coastguard Worker } else if (line[len - 1] != '\\') break;
184*cf5a6c84SAndroid Build Coastguard Worker
185*cf5a6c84SAndroid Build Coastguard Worker len--;
186*cf5a6c84SAndroid Build Coastguard Worker nxtlen = getline(&nxtline, &nxtlinelen, fl);
187*cf5a6c84SAndroid Build Coastguard Worker if (nxtlen <= 0) break;
188*cf5a6c84SAndroid Build Coastguard Worker if (linelen < len + nxtlen + 1) {
189*cf5a6c84SAndroid Build Coastguard Worker linelen = len + nxtlen + 1;
190*cf5a6c84SAndroid Build Coastguard Worker line = xrealloc(line, linelen);
191*cf5a6c84SAndroid Build Coastguard Worker }
192*cf5a6c84SAndroid Build Coastguard Worker memcpy(&line[len], nxtline, nxtlen);
193*cf5a6c84SAndroid Build Coastguard Worker len += nxtlen;
194*cf5a6c84SAndroid Build Coastguard Worker }
195*cf5a6c84SAndroid Build Coastguard Worker line[len] = '\0';
196*cf5a6c84SAndroid Build Coastguard Worker *li = xstrdup(line);
197*cf5a6c84SAndroid Build Coastguard Worker free(line);
198*cf5a6c84SAndroid Build Coastguard Worker if (nxtline) free(nxtline);
199*cf5a6c84SAndroid Build Coastguard Worker return len;
200*cf5a6c84SAndroid Build Coastguard Worker }
201*cf5a6c84SAndroid Build Coastguard Worker
202*cf5a6c84SAndroid Build Coastguard Worker /*
203*cf5a6c84SAndroid Build Coastguard Worker * Action to be taken on all config files in default directories
204*cf5a6c84SAndroid Build Coastguard Worker * checks for aliases, options, install, remove and blacklist
205*cf5a6c84SAndroid Build Coastguard Worker */
config_action(struct dirtree * node)206*cf5a6c84SAndroid Build Coastguard Worker static int config_action(struct dirtree *node)
207*cf5a6c84SAndroid Build Coastguard Worker {
208*cf5a6c84SAndroid Build Coastguard Worker FILE *fc;
209*cf5a6c84SAndroid Build Coastguard Worker char *filename, *tokens[3], *line, *linecp;
210*cf5a6c84SAndroid Build Coastguard Worker struct module_s *modent;
211*cf5a6c84SAndroid Build Coastguard Worker int tcount = 0;
212*cf5a6c84SAndroid Build Coastguard Worker
213*cf5a6c84SAndroid Build Coastguard Worker if (!dirtree_notdotdot(node)) return 0;
214*cf5a6c84SAndroid Build Coastguard Worker if (S_ISDIR(node->st.st_mode)) return DIRTREE_RECURSE;
215*cf5a6c84SAndroid Build Coastguard Worker
216*cf5a6c84SAndroid Build Coastguard Worker if (!S_ISREG(node->st.st_mode)) return 0; // process only regular file
217*cf5a6c84SAndroid Build Coastguard Worker filename = dirtree_path(node, NULL);
218*cf5a6c84SAndroid Build Coastguard Worker if (!(fc = fopen(filename, "r"))) {
219*cf5a6c84SAndroid Build Coastguard Worker free(filename);
220*cf5a6c84SAndroid Build Coastguard Worker return 0;
221*cf5a6c84SAndroid Build Coastguard Worker }
222*cf5a6c84SAndroid Build Coastguard Worker for (line = linecp = NULL; read_line(fc, &line) >= 0;
223*cf5a6c84SAndroid Build Coastguard Worker free(line), free(linecp), line = linecp = NULL) {
224*cf5a6c84SAndroid Build Coastguard Worker char *tk = NULL;
225*cf5a6c84SAndroid Build Coastguard Worker
226*cf5a6c84SAndroid Build Coastguard Worker if (!strlen(line)) continue;
227*cf5a6c84SAndroid Build Coastguard Worker linecp = xstrdup(line);
228*cf5a6c84SAndroid Build Coastguard Worker for (tk = strtok(linecp, "# \t"), tcount = 0; tk;
229*cf5a6c84SAndroid Build Coastguard Worker tk = strtok(NULL, "# \t"), tcount++) {
230*cf5a6c84SAndroid Build Coastguard Worker tokens[tcount] = tk;
231*cf5a6c84SAndroid Build Coastguard Worker if (tcount == 2) {
232*cf5a6c84SAndroid Build Coastguard Worker tokens[2] = line + strlen(tokens[0]) + strlen(tokens[1]) + 2;
233*cf5a6c84SAndroid Build Coastguard Worker break;
234*cf5a6c84SAndroid Build Coastguard Worker }
235*cf5a6c84SAndroid Build Coastguard Worker }
236*cf5a6c84SAndroid Build Coastguard Worker // Every command requires at least one argument.
237*cf5a6c84SAndroid Build Coastguard Worker if (tcount < 2) continue;
238*cf5a6c84SAndroid Build Coastguard Worker // process the tokens[0] contains first word of config line.
239*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(tokens[0], "alias")) {
240*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *temp;
241*cf5a6c84SAndroid Build Coastguard Worker char alias[MODNAME_LEN], *realname;
242*cf5a6c84SAndroid Build Coastguard Worker
243*cf5a6c84SAndroid Build Coastguard Worker if (!tokens[2]) continue;
244*cf5a6c84SAndroid Build Coastguard Worker path2mod(tokens[1], alias);
245*cf5a6c84SAndroid Build Coastguard Worker for (temp = TT.probes; temp; temp = temp->next) {
246*cf5a6c84SAndroid Build Coastguard Worker modent = (struct module_s *) temp->arg;
247*cf5a6c84SAndroid Build Coastguard Worker if (fnmatch(alias, modent->name, 0)) continue;
248*cf5a6c84SAndroid Build Coastguard Worker realname = path2mod(tokens[2], NULL);
249*cf5a6c84SAndroid Build Coastguard Worker llist_add(&modent->rnames, realname);
250*cf5a6c84SAndroid Build Coastguard Worker if (modent->flags & MOD_NDDEPS) {
251*cf5a6c84SAndroid Build Coastguard Worker modent->flags &= ~MOD_NDDEPS;
252*cf5a6c84SAndroid Build Coastguard Worker TT.nudeps--;
253*cf5a6c84SAndroid Build Coastguard Worker }
254*cf5a6c84SAndroid Build Coastguard Worker modent = get_mod(realname, 1);
255*cf5a6c84SAndroid Build Coastguard Worker if (!(modent->flags & MOD_NDDEPS)) {
256*cf5a6c84SAndroid Build Coastguard Worker modent->flags |= MOD_NDDEPS;
257*cf5a6c84SAndroid Build Coastguard Worker TT.nudeps++;
258*cf5a6c84SAndroid Build Coastguard Worker }
259*cf5a6c84SAndroid Build Coastguard Worker }
260*cf5a6c84SAndroid Build Coastguard Worker } else if (!strcmp(tokens[0], "options")) {
261*cf5a6c84SAndroid Build Coastguard Worker if (!tokens[2]) continue;
262*cf5a6c84SAndroid Build Coastguard Worker modent = get_mod(tokens[1], 1);
263*cf5a6c84SAndroid Build Coastguard Worker modent->opts = add_opts(modent->opts, tokens[2]);
264*cf5a6c84SAndroid Build Coastguard Worker } else if (!strcmp(tokens[0], "include"))
265*cf5a6c84SAndroid Build Coastguard Worker dirtree_read(tokens[1], config_action);
266*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(tokens[0], "blacklist"))
267*cf5a6c84SAndroid Build Coastguard Worker get_mod(tokens[1], 1)->flags |= MOD_BLACKLIST;
268*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(tokens[0], "install")) continue;
269*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(tokens[0], "remove")) continue;
270*cf5a6c84SAndroid Build Coastguard Worker else if (!FLAG(q))
271*cf5a6c84SAndroid Build Coastguard Worker error_msg("Invalid option %s found in file %s", tokens[0], filename);
272*cf5a6c84SAndroid Build Coastguard Worker }
273*cf5a6c84SAndroid Build Coastguard Worker fclose(fc);
274*cf5a6c84SAndroid Build Coastguard Worker free(filename);
275*cf5a6c84SAndroid Build Coastguard Worker return 0;
276*cf5a6c84SAndroid Build Coastguard Worker }
277*cf5a6c84SAndroid Build Coastguard Worker
278*cf5a6c84SAndroid Build Coastguard Worker // Show matched modules else return -1 on failure.
depmode_read_entry(char * cmdname)279*cf5a6c84SAndroid Build Coastguard Worker static int depmode_read_entry(char *cmdname)
280*cf5a6c84SAndroid Build Coastguard Worker {
281*cf5a6c84SAndroid Build Coastguard Worker char *line, *name;
282*cf5a6c84SAndroid Build Coastguard Worker int ret = -1;
283*cf5a6c84SAndroid Build Coastguard Worker FILE *fe = xfopen("modules.dep", "r");
284*cf5a6c84SAndroid Build Coastguard Worker
285*cf5a6c84SAndroid Build Coastguard Worker while (read_line(fe, &line) >= 0) {
286*cf5a6c84SAndroid Build Coastguard Worker char *tmp = strchr(line, ':');
287*cf5a6c84SAndroid Build Coastguard Worker
288*cf5a6c84SAndroid Build Coastguard Worker if (tmp) {
289*cf5a6c84SAndroid Build Coastguard Worker *tmp = '\0';
290*cf5a6c84SAndroid Build Coastguard Worker name = basename(line);
291*cf5a6c84SAndroid Build Coastguard Worker tmp = strchr(name, '.');
292*cf5a6c84SAndroid Build Coastguard Worker if (tmp) *tmp = '\0';
293*cf5a6c84SAndroid Build Coastguard Worker if (!cmdname || !fnmatch(cmdname, name, 0)) {
294*cf5a6c84SAndroid Build Coastguard Worker if (tmp) *tmp = '.';
295*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) puts(line);
296*cf5a6c84SAndroid Build Coastguard Worker ret = 0;
297*cf5a6c84SAndroid Build Coastguard Worker }
298*cf5a6c84SAndroid Build Coastguard Worker }
299*cf5a6c84SAndroid Build Coastguard Worker free(line);
300*cf5a6c84SAndroid Build Coastguard Worker }
301*cf5a6c84SAndroid Build Coastguard Worker fclose(fe);
302*cf5a6c84SAndroid Build Coastguard Worker return ret;
303*cf5a6c84SAndroid Build Coastguard Worker }
304*cf5a6c84SAndroid Build Coastguard Worker
305*cf5a6c84SAndroid Build Coastguard Worker // Finds dependencies for modules from the modules.dep file.
find_dep(void)306*cf5a6c84SAndroid Build Coastguard Worker static void find_dep(void)
307*cf5a6c84SAndroid Build Coastguard Worker {
308*cf5a6c84SAndroid Build Coastguard Worker char *line = NULL;
309*cf5a6c84SAndroid Build Coastguard Worker struct module_s *mod;
310*cf5a6c84SAndroid Build Coastguard Worker FILE *fe = xfopen("modules.dep", "r");
311*cf5a6c84SAndroid Build Coastguard Worker
312*cf5a6c84SAndroid Build Coastguard Worker for (; read_line(fe, &line) >= 0; free(line)) {
313*cf5a6c84SAndroid Build Coastguard Worker char *tmp = strchr(line, ':');
314*cf5a6c84SAndroid Build Coastguard Worker
315*cf5a6c84SAndroid Build Coastguard Worker if (tmp) {
316*cf5a6c84SAndroid Build Coastguard Worker *tmp = '\0';
317*cf5a6c84SAndroid Build Coastguard Worker mod = get_mod(line, 0);
318*cf5a6c84SAndroid Build Coastguard Worker if (!mod) continue;
319*cf5a6c84SAndroid Build Coastguard Worker if ((mod->flags & MOD_ALOADED) && !(FLAG(r)|FLAG(D))) continue;
320*cf5a6c84SAndroid Build Coastguard Worker
321*cf5a6c84SAndroid Build Coastguard Worker mod->flags |= MOD_FNDDEPMOD;
322*cf5a6c84SAndroid Build Coastguard Worker if ((mod->flags & MOD_NDDEPS) && !mod->dep) {
323*cf5a6c84SAndroid Build Coastguard Worker TT.nudeps--;
324*cf5a6c84SAndroid Build Coastguard Worker llist_add(&mod->dep, xstrdup(line));
325*cf5a6c84SAndroid Build Coastguard Worker tmp++;
326*cf5a6c84SAndroid Build Coastguard Worker if (*tmp) {
327*cf5a6c84SAndroid Build Coastguard Worker char *tok;
328*cf5a6c84SAndroid Build Coastguard Worker
329*cf5a6c84SAndroid Build Coastguard Worker while ((tok = strsep(&tmp, " \t"))) {
330*cf5a6c84SAndroid Build Coastguard Worker if (!*tok) continue;
331*cf5a6c84SAndroid Build Coastguard Worker llist_add_tail(&mod->dep, xstrdup(tok));
332*cf5a6c84SAndroid Build Coastguard Worker }
333*cf5a6c84SAndroid Build Coastguard Worker }
334*cf5a6c84SAndroid Build Coastguard Worker }
335*cf5a6c84SAndroid Build Coastguard Worker }
336*cf5a6c84SAndroid Build Coastguard Worker }
337*cf5a6c84SAndroid Build Coastguard Worker fclose(fe);
338*cf5a6c84SAndroid Build Coastguard Worker }
339*cf5a6c84SAndroid Build Coastguard Worker
340*cf5a6c84SAndroid Build Coastguard Worker // Remove a module from the Linux Kernel. if !modules does auto remove.
rm_mod(char * modules)341*cf5a6c84SAndroid Build Coastguard Worker static int rm_mod(char *modules)
342*cf5a6c84SAndroid Build Coastguard Worker {
343*cf5a6c84SAndroid Build Coastguard Worker char *s;
344*cf5a6c84SAndroid Build Coastguard Worker
345*cf5a6c84SAndroid Build Coastguard Worker if (modules && (s = strend(modules, ".ko"))) *s = 0;
346*cf5a6c84SAndroid Build Coastguard Worker return syscall(__NR_delete_module, modules, O_NONBLOCK);
347*cf5a6c84SAndroid Build Coastguard Worker }
348*cf5a6c84SAndroid Build Coastguard Worker
349*cf5a6c84SAndroid Build Coastguard Worker // Insert module; simpler than insmod(1) because we already flattened the array
350*cf5a6c84SAndroid Build Coastguard Worker // of flags, and don't need to support loading from stdin.
ins_mod(char * modules,char * flags)351*cf5a6c84SAndroid Build Coastguard Worker static int ins_mod(char *modules, char *flags)
352*cf5a6c84SAndroid Build Coastguard Worker {
353*cf5a6c84SAndroid Build Coastguard Worker int fd = xopenro(modules), rc = syscall(__NR_finit_module, fd, flags, 0);
354*cf5a6c84SAndroid Build Coastguard Worker
355*cf5a6c84SAndroid Build Coastguard Worker xclose(fd);
356*cf5a6c84SAndroid Build Coastguard Worker return rc;
357*cf5a6c84SAndroid Build Coastguard Worker }
358*cf5a6c84SAndroid Build Coastguard Worker
359*cf5a6c84SAndroid Build Coastguard Worker // Add module in probes list, if not loaded.
add_mod(char * name)360*cf5a6c84SAndroid Build Coastguard Worker static void add_mod(char *name)
361*cf5a6c84SAndroid Build Coastguard Worker {
362*cf5a6c84SAndroid Build Coastguard Worker struct module_s *mod = get_mod(name, 1);
363*cf5a6c84SAndroid Build Coastguard Worker
364*cf5a6c84SAndroid Build Coastguard Worker if (!(FLAG(r)|FLAG(D)) && (mod->flags & MOD_ALOADED)) {
365*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) printf("%s already loaded\n", name);
366*cf5a6c84SAndroid Build Coastguard Worker return;
367*cf5a6c84SAndroid Build Coastguard Worker }
368*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) printf("queuing %s\n", name);
369*cf5a6c84SAndroid Build Coastguard Worker mod->cmdname = name;
370*cf5a6c84SAndroid Build Coastguard Worker mod->flags |= MOD_NDDEPS;
371*cf5a6c84SAndroid Build Coastguard Worker llist_add_tail(&TT.probes, mod);
372*cf5a6c84SAndroid Build Coastguard Worker TT.nudeps++;
373*cf5a6c84SAndroid Build Coastguard Worker if (!strncmp(mod->name, "symbol:", 7)) TT.symreq = 1;
374*cf5a6c84SAndroid Build Coastguard Worker }
375*cf5a6c84SAndroid Build Coastguard Worker
376*cf5a6c84SAndroid Build Coastguard Worker // Parse cmdline options suplied for module.
add_cmdopt(char ** argv)377*cf5a6c84SAndroid Build Coastguard Worker static char *add_cmdopt(char **argv)
378*cf5a6c84SAndroid Build Coastguard Worker {
379*cf5a6c84SAndroid Build Coastguard Worker char *opt = xzalloc(1);
380*cf5a6c84SAndroid Build Coastguard Worker int lopt = 0;
381*cf5a6c84SAndroid Build Coastguard Worker
382*cf5a6c84SAndroid Build Coastguard Worker while (*++argv) {
383*cf5a6c84SAndroid Build Coastguard Worker char *fmt, *var, *val;
384*cf5a6c84SAndroid Build Coastguard Worker
385*cf5a6c84SAndroid Build Coastguard Worker var = *argv;
386*cf5a6c84SAndroid Build Coastguard Worker opt = xrealloc(opt, lopt + 2 + strlen(var) + 2);
387*cf5a6c84SAndroid Build Coastguard Worker // check for key=val or key = val.
388*cf5a6c84SAndroid Build Coastguard Worker fmt = "%.*s%s ";
389*cf5a6c84SAndroid Build Coastguard Worker for (val = var; *val && *val != '='; val++);
390*cf5a6c84SAndroid Build Coastguard Worker if (*val && strchr(++val, ' ')) fmt = "%.*s\"%s\" ";
391*cf5a6c84SAndroid Build Coastguard Worker lopt += sprintf(opt + lopt, fmt, (int) (val - var), var, val);
392*cf5a6c84SAndroid Build Coastguard Worker }
393*cf5a6c84SAndroid Build Coastguard Worker return opt;
394*cf5a6c84SAndroid Build Coastguard Worker }
395*cf5a6c84SAndroid Build Coastguard Worker
396*cf5a6c84SAndroid Build Coastguard Worker // Probes a single module and loads all its dependencies.
go_probe(struct module_s * m)397*cf5a6c84SAndroid Build Coastguard Worker static void go_probe(struct module_s *m)
398*cf5a6c84SAndroid Build Coastguard Worker {
399*cf5a6c84SAndroid Build Coastguard Worker int rc = 0, first = 1;
400*cf5a6c84SAndroid Build Coastguard Worker
401*cf5a6c84SAndroid Build Coastguard Worker if (!(m->flags & MOD_FNDDEPMOD)) {
402*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(q)) error_msg("module %s not found in modules.dep", m->name);
403*cf5a6c84SAndroid Build Coastguard Worker return;
404*cf5a6c84SAndroid Build Coastguard Worker }
405*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) printf("go_prob'ing %s\n", m->name);
406*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(r)) m->dep = llist_rev(m->dep);
407*cf5a6c84SAndroid Build Coastguard Worker
408*cf5a6c84SAndroid Build Coastguard Worker while (m->dep) {
409*cf5a6c84SAndroid Build Coastguard Worker struct module_s *m2;
410*cf5a6c84SAndroid Build Coastguard Worker char *fn, *options;
411*cf5a6c84SAndroid Build Coastguard Worker
412*cf5a6c84SAndroid Build Coastguard Worker rc = 0;
413*cf5a6c84SAndroid Build Coastguard Worker fn = llist_popme(&m->dep);
414*cf5a6c84SAndroid Build Coastguard Worker m2 = get_mod(fn, 1);
415*cf5a6c84SAndroid Build Coastguard Worker // are we removing ?
416*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(r)) {
417*cf5a6c84SAndroid Build Coastguard Worker if (m2->flags & MOD_ALOADED) {
418*cf5a6c84SAndroid Build Coastguard Worker if (rm_mod(m2->name)) {
419*cf5a6c84SAndroid Build Coastguard Worker if (first) {
420*cf5a6c84SAndroid Build Coastguard Worker perror_msg("can't unload module %s", m2->name);
421*cf5a6c84SAndroid Build Coastguard Worker break;
422*cf5a6c84SAndroid Build Coastguard Worker }
423*cf5a6c84SAndroid Build Coastguard Worker } else m2->flags &= ~MOD_ALOADED;
424*cf5a6c84SAndroid Build Coastguard Worker }
425*cf5a6c84SAndroid Build Coastguard Worker first = 0;
426*cf5a6c84SAndroid Build Coastguard Worker continue;
427*cf5a6c84SAndroid Build Coastguard Worker }
428*cf5a6c84SAndroid Build Coastguard Worker // TODO how does free work here without leaking?
429*cf5a6c84SAndroid Build Coastguard Worker options = m2->opts;
430*cf5a6c84SAndroid Build Coastguard Worker m2->opts = NULL;
431*cf5a6c84SAndroid Build Coastguard Worker if (m == m2) options = add_opts(options, TT.cmdopts);
432*cf5a6c84SAndroid Build Coastguard Worker
433*cf5a6c84SAndroid Build Coastguard Worker // are we only checking dependencies ?
434*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(D)) {
435*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v))
436*cf5a6c84SAndroid Build Coastguard Worker printf(options ? "insmod %s %s\n" : "insmod %s\n", fn, options);
437*cf5a6c84SAndroid Build Coastguard Worker if (options) free(options);
438*cf5a6c84SAndroid Build Coastguard Worker continue;
439*cf5a6c84SAndroid Build Coastguard Worker }
440*cf5a6c84SAndroid Build Coastguard Worker if (m2->flags & MOD_ALOADED) {
441*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) printf("%s already loaded\n", fn);
442*cf5a6c84SAndroid Build Coastguard Worker if (options) free(options);
443*cf5a6c84SAndroid Build Coastguard Worker continue;
444*cf5a6c84SAndroid Build Coastguard Worker }
445*cf5a6c84SAndroid Build Coastguard Worker // none of above is true insert the module.
446*cf5a6c84SAndroid Build Coastguard Worker errno = 0;
447*cf5a6c84SAndroid Build Coastguard Worker rc = ins_mod(fn, options ? : "");
448*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v))
449*cf5a6c84SAndroid Build Coastguard Worker printf("loaded %s '%s': %s\n", fn, options, strerror(errno));
450*cf5a6c84SAndroid Build Coastguard Worker if (errno == EEXIST) rc = 0;
451*cf5a6c84SAndroid Build Coastguard Worker free(options);
452*cf5a6c84SAndroid Build Coastguard Worker if (rc) {
453*cf5a6c84SAndroid Build Coastguard Worker perror_msg("can't load module %s (%s)", m2->name, fn);
454*cf5a6c84SAndroid Build Coastguard Worker break;
455*cf5a6c84SAndroid Build Coastguard Worker }
456*cf5a6c84SAndroid Build Coastguard Worker m2->flags |= MOD_ALOADED;
457*cf5a6c84SAndroid Build Coastguard Worker }
458*cf5a6c84SAndroid Build Coastguard Worker }
459*cf5a6c84SAndroid Build Coastguard Worker
modprobe_main(void)460*cf5a6c84SAndroid Build Coastguard Worker void modprobe_main(void)
461*cf5a6c84SAndroid Build Coastguard Worker {
462*cf5a6c84SAndroid Build Coastguard Worker char **argv = toys.optargs, *procline = NULL;
463*cf5a6c84SAndroid Build Coastguard Worker FILE *fs;
464*cf5a6c84SAndroid Build Coastguard Worker struct module_s *module;
465*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *dirs;
466*cf5a6c84SAndroid Build Coastguard Worker
467*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc<1 && !FLAG(r) == !FLAG(l)) help_exit("bad syntax");
468*cf5a6c84SAndroid Build Coastguard Worker // Check for -r flag without arg if yes then do auto remove.
469*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(r) && !toys.optc) {
470*cf5a6c84SAndroid Build Coastguard Worker if (rm_mod(0)) perror_exit("rmmod");
471*cf5a6c84SAndroid Build Coastguard Worker return;
472*cf5a6c84SAndroid Build Coastguard Worker }
473*cf5a6c84SAndroid Build Coastguard Worker
474*cf5a6c84SAndroid Build Coastguard Worker if (!TT.dirs) {
475*cf5a6c84SAndroid Build Coastguard Worker struct utsname uts;
476*cf5a6c84SAndroid Build Coastguard Worker
477*cf5a6c84SAndroid Build Coastguard Worker uname(&uts);
478*cf5a6c84SAndroid Build Coastguard Worker TT.dirs = xzalloc(sizeof(struct arg_list));
479*cf5a6c84SAndroid Build Coastguard Worker TT.dirs->arg = xmprintf("/lib/modules/%s", uts.release);
480*cf5a6c84SAndroid Build Coastguard Worker }
481*cf5a6c84SAndroid Build Coastguard Worker
482*cf5a6c84SAndroid Build Coastguard Worker // modules.dep processing for dependency check.
483*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(l)) {
484*cf5a6c84SAndroid Build Coastguard Worker for (dirs = TT.dirs; dirs; dirs = dirs->next) {
485*cf5a6c84SAndroid Build Coastguard Worker xchdir(dirs->arg);
486*cf5a6c84SAndroid Build Coastguard Worker if (!depmode_read_entry(*toys.optargs)) return;
487*cf5a6c84SAndroid Build Coastguard Worker }
488*cf5a6c84SAndroid Build Coastguard Worker error_exit("no module found.");
489*cf5a6c84SAndroid Build Coastguard Worker }
490*cf5a6c84SAndroid Build Coastguard Worker
491*cf5a6c84SAndroid Build Coastguard Worker // Read /proc/modules to get loaded modules.
492*cf5a6c84SAndroid Build Coastguard Worker fs = fopen("/proc/modules", "r");
493*cf5a6c84SAndroid Build Coastguard Worker
494*cf5a6c84SAndroid Build Coastguard Worker while (fs && read_line(fs, &procline) > 0) {
495*cf5a6c84SAndroid Build Coastguard Worker *strchr(procline, ' ') = 0;
496*cf5a6c84SAndroid Build Coastguard Worker get_mod(procline, 1)->flags = MOD_ALOADED;
497*cf5a6c84SAndroid Build Coastguard Worker free(procline);
498*cf5a6c84SAndroid Build Coastguard Worker procline = NULL;
499*cf5a6c84SAndroid Build Coastguard Worker }
500*cf5a6c84SAndroid Build Coastguard Worker if (fs) fclose(fs);
501*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(a) || FLAG(r)) for (; *argv; argv++) add_mod(*argv);
502*cf5a6c84SAndroid Build Coastguard Worker else {
503*cf5a6c84SAndroid Build Coastguard Worker add_mod(*argv);
504*cf5a6c84SAndroid Build Coastguard Worker TT.cmdopts = add_cmdopt(argv);
505*cf5a6c84SAndroid Build Coastguard Worker }
506*cf5a6c84SAndroid Build Coastguard Worker if (!TT.probes) {
507*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) puts("All modules loaded");
508*cf5a6c84SAndroid Build Coastguard Worker return;
509*cf5a6c84SAndroid Build Coastguard Worker }
510*cf5a6c84SAndroid Build Coastguard Worker dirtree_flagread("/etc/modprobe.conf", DIRTREE_SHUTUP, config_action);
511*cf5a6c84SAndroid Build Coastguard Worker dirtree_flagread("/etc/modprobe.d", DIRTREE_SHUTUP, config_action);
512*cf5a6c84SAndroid Build Coastguard Worker
513*cf5a6c84SAndroid Build Coastguard Worker for (dirs = TT.dirs; dirs; dirs = dirs->next) {
514*cf5a6c84SAndroid Build Coastguard Worker xchdir(dirs->arg);
515*cf5a6c84SAndroid Build Coastguard Worker if (TT.symreq) dirtree_read("modules.symbols", config_action);
516*cf5a6c84SAndroid Build Coastguard Worker if (TT.nudeps) dirtree_read("modules.alias", config_action);
517*cf5a6c84SAndroid Build Coastguard Worker }
518*cf5a6c84SAndroid Build Coastguard Worker
519*cf5a6c84SAndroid Build Coastguard Worker for (dirs = TT.dirs; dirs; dirs = dirs->next) {
520*cf5a6c84SAndroid Build Coastguard Worker xchdir(dirs->arg);
521*cf5a6c84SAndroid Build Coastguard Worker find_dep();
522*cf5a6c84SAndroid Build Coastguard Worker }
523*cf5a6c84SAndroid Build Coastguard Worker
524*cf5a6c84SAndroid Build Coastguard Worker while ((module = llist_popme(&TT.probes))) {
525*cf5a6c84SAndroid Build Coastguard Worker if (!module->rnames) {
526*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) puts("probing by module name");
527*cf5a6c84SAndroid Build Coastguard Worker /* This is not an alias. Literal names are blacklisted
528*cf5a6c84SAndroid Build Coastguard Worker * only if '-b' is given.
529*cf5a6c84SAndroid Build Coastguard Worker */
530*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(b) || !(module->flags & MOD_BLACKLIST))
531*cf5a6c84SAndroid Build Coastguard Worker go_probe(module);
532*cf5a6c84SAndroid Build Coastguard Worker continue;
533*cf5a6c84SAndroid Build Coastguard Worker }
534*cf5a6c84SAndroid Build Coastguard Worker do { // Probe all real names for the alias.
535*cf5a6c84SAndroid Build Coastguard Worker char *real = ((struct arg_list *)llist_pop(&module->rnames))->arg;
536*cf5a6c84SAndroid Build Coastguard Worker struct module_s *m2 = get_mod(real, 0);
537*cf5a6c84SAndroid Build Coastguard Worker
538*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v))
539*cf5a6c84SAndroid Build Coastguard Worker printf("probing alias %s by realname %s\n", module->name, real);
540*cf5a6c84SAndroid Build Coastguard Worker if (!m2) continue;
541*cf5a6c84SAndroid Build Coastguard Worker if (!(m2->flags & MOD_BLACKLIST)
542*cf5a6c84SAndroid Build Coastguard Worker && (!(m2->flags & MOD_ALOADED) || FLAG(r) || FLAG(D)))
543*cf5a6c84SAndroid Build Coastguard Worker go_probe(m2);
544*cf5a6c84SAndroid Build Coastguard Worker free(real);
545*cf5a6c84SAndroid Build Coastguard Worker } while (module->rnames);
546*cf5a6c84SAndroid Build Coastguard Worker }
547*cf5a6c84SAndroid Build Coastguard Worker }
548