9230fec854573711d68e1444150d856f4b43f504
[oweals/busybox.git] / modutils / modprobe.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * really dumb modprobe implementation for busybox
4  * Copyright (C) 2001 Lineo, davidm@lineo.com
5  *
6  * dependency specific stuff completly rewritten and
7  * copyright (c) 2002 by Robert Griebl, griebl@gmx.de
8  *
9  */
10
11 #include <sys/utsname.h>
12 #include <stdio.h>
13 #include <getopt.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <syslog.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include "busybox.h"
20
21
22
23 struct dep_t {
24         char *  m_module;
25         
26         int     m_depcnt;
27         char ** m_deparr;
28         
29         struct dep_t * m_next;
30 };
31
32 struct mod_list_t {
33         char *  m_module;
34         
35         struct mod_list_t * m_prev;
36         struct mod_list_t * m_next;
37 };
38
39
40 static struct dep_t *depend;
41 static int autoclean, show_only, quiet, do_syslog, verbose;
42
43
44 static struct dep_t *build_dep ( void )
45 {
46         struct utsname un;
47         FILE *f;
48         struct dep_t *first = 0;
49         struct dep_t *current = 0;
50         char buffer [4096];
51         char *filename = buffer;
52         int continuation_line = 0;
53         
54         if ( uname ( &un ))
55                 return 0;
56                 
57         // check for buffer overflow in following code
58         if ( xstrlen ( un. release ) > ( sizeof( buffer ) - 64 ))
59                 return 0;
60                                 
61         strcpy ( filename, "/lib/modules/" );
62         strcat ( filename, un. release );
63         strcat ( filename, "/modules.dep" );
64
65         f = fopen ( filename, "r" );
66         if ( !f )
67                 return 0;
68         
69         while ( fgets ( buffer, sizeof( buffer), f )) {
70                 int l = xstrlen ( buffer );
71                 char *p = 0;
72                 
73                 if ( buffer [l-1] == '\n' ) {
74                         buffer [l-1] = 0;
75                         l--;
76                 }
77                 
78                 if ( l == 0 ) {
79                         continuation_line = 0;
80                         continue;
81                 }
82                 
83                 if ( !continuation_line ) {             
84                         char *col = strchr ( buffer, ':' );
85                 
86                         if ( col ) {
87                                 char *mods;
88                                 char *mod;
89                                 int ext = 0;
90                                 
91                                 *col = 0;
92                                 mods = strrchr ( buffer, '/' );
93                                 
94                                 if ( !mods )
95                                         mods = buffer;
96                                 else
97                                         mods++;
98                                         
99                                 if (( *(col-2) == '.' ) && ( *(col-1) == 'o' ))
100                                         ext = 2;
101                                 
102                                 mod = xstrndup ( mods, col - mods - ext );
103                                         
104                                 if ( !current ) {
105                                         first = current = (struct dep_t *) malloc ( sizeof ( struct dep_t ));
106                                 }
107                                 else {
108                                         current-> m_next = (struct dep_t *) malloc ( sizeof ( struct dep_t ));
109                                         current = current-> m_next;
110                                 }
111                                 current-> m_module = mod;
112                                 current-> m_depcnt = 0;
113                                 current-> m_deparr = 0;
114                                 current-> m_next   = 0;
115                                                 
116                                 //printf ( "%s:\n", mod );
117                                                 
118                                 p = col + 1;            
119                         }
120                         else
121                                 p = 0;
122                 }
123                 else
124                         p = buffer;
125                         
126                 if ( p && *p ) {
127                         char *end = &buffer [l-1];
128                         char *deps = strrchr ( end, '/' );
129                         char *dep;
130                         int ext = 0;
131                         
132                         while ( isblank ( *end ) || ( *end == '\\' ))
133                                 end--;
134                                 
135                         deps = strrchr ( p, '/' );
136                         
137                         if ( !deps || ( deps < p )) {
138                                 deps = p;
139                 
140                                 while ( isblank ( *deps ))
141                                         deps++;
142                         }
143                         else
144                                 deps++;
145                         
146                         if (( *(end-1) == '.' ) && ( *end == 'o' ))
147                                 ext = 2;
148                         
149                         dep = xstrndup ( deps, end - deps - ext + 1 );
150                         
151                         current-> m_depcnt++;
152                         current-> m_deparr = (char **) xrealloc ( current-> m_deparr, sizeof ( char *) * current-> m_depcnt );
153                         current-> m_deparr [current-> m_depcnt - 1] = dep;              
154                         
155                         //printf ( "    %d) %s\n", current-> m_depcnt, current-> m_deparr [current-> m_depcnt -1] );
156                 }
157         
158                 if ( buffer [l-1] == '\\' )
159                         continuation_line = 1;
160                 else
161                         continuation_line = 0;
162         }
163         fclose ( f );
164         
165         return first;
166 }
167
168
169 static int mod_process ( struct mod_list_t *list, int do_insert )
170 {
171         char lcmd [256];
172         int rc = 0;
173
174         if ( !list )
175                 return 1;
176
177         while ( list ) {
178                 if ( do_insert )
179                         snprintf ( lcmd, sizeof( lcmd ) - 1, "insmod %s %s %s %s 2>/dev/null", do_syslog ? "-s" : "", autoclean ? "-k" : "", quiet ? "-q" : "", list-> m_module );
180                 else
181                         snprintf ( lcmd, sizeof( lcmd ) - 1, "rmmod %s %s 2>/dev/null", do_syslog ? "-s" : "", list-> m_module );
182                 
183                 if ( verbose )
184                         printf ( "%s\n", lcmd );
185                 if ( !show_only )
186                         rc |= system ( lcmd );
187                         
188                 list = do_insert ? list-> m_prev : list-> m_next;
189         }
190         return rc;
191 }
192
193 static void check_dep ( char *mod, struct mod_list_t **head, struct mod_list_t **tail )
194 {
195         struct mod_list_t *find;
196         struct dep_t *dt;
197
198         int lm;
199
200         // remove .o extension
201         lm = xstrlen ( mod );
202         if (( mod [lm-2] == '.' ) && ( mod [lm-1] == 'o' ))
203                 mod [lm-2] = 0;
204
205         // search for duplicates
206         for ( find = *head; find; find = find-> m_next ) {
207                 if ( !strcmp ( mod, find-> m_module )) {
208                         // found -> dequeue it
209
210                         if ( find-> m_prev )
211                                 find-> m_prev-> m_next = find-> m_next;
212                         else
213                                 *head = find-> m_next;
214                                         
215                         if ( find-> m_next )
216                                 find-> m_next-> m_prev = find-> m_prev;
217                         else
218                                 *tail = find-> m_prev;
219                                         
220                         break; // there can be only one duplicate
221                 }                               
222         }
223
224         if ( !find ) { // did not find a duplicate
225                 find = (struct mod_list_t *) xmalloc ( sizeof(struct mod_list_t));              
226                 find-> m_module = mod;
227         }
228
229         // enqueue at tail      
230         if ( *tail )
231                 (*tail)-> m_next = find;
232         find-> m_prev   = *tail;
233         find-> m_next   = 0;
234         
235         if ( !*head )
236                 *head = find;
237         *tail = find;
238                 
239         // check dependencies
240         for ( dt = depend; dt; dt = dt-> m_next ) {
241                 if ( !strcmp ( dt-> m_module, mod )) {
242                         int i;
243                         
244                         for ( i = 0; i < dt-> m_depcnt; i++ )
245                                 check_dep ( dt-> m_deparr [i], head, tail );
246                 }
247         }               
248 }
249
250
251
252 static int mod_insert ( char *mod, int argc, char **argv )
253 {
254         struct mod_list_t *tail = 0;
255         struct mod_list_t *head = 0;    
256         int rc = 0;
257         
258         // get dep list for module mod
259         check_dep ( mod, &head, &tail );
260         
261         if ( head && tail ) {
262                 int i;
263                 int l = 0;
264         
265                 // append module args
266                 l = xstrlen ( mod );
267                 for ( i = 0; i < argc; i++ ) 
268                         l += ( xstrlen ( argv [i] ) + 1 );
269                 
270                 head-> m_module = xstrndup ( mod, l );
271                 
272                 for ( i = 0; i < argc; i++ ) {
273                         strcat ( head-> m_module, " " );
274                         strcat ( head-> m_module, argv [i] );
275                 }
276
277                 // process tail ---> head
278                 rc |= mod_process ( tail, 1 );
279         }
280         else
281                 rc = 1;
282         
283         return rc;
284 }
285
286 static void mod_remove ( char *mod )
287 {
288         static struct mod_list_t rm_a_dummy = { "-a", 0, 0 }; 
289         
290         struct mod_list_t *head = 0;
291         struct mod_list_t *tail = 0;
292         
293         if ( mod )
294                 check_dep ( mod, &head, &tail );
295         else  // autoclean
296                 head = tail = &rm_a_dummy;
297         
298         if ( head && tail )
299                 mod_process ( head, 0 );  // process head ---> tail
300 }
301
302
303
304 extern int modprobe_main(int argc, char** argv)
305 {
306         int     opt;
307         int remove_opt = 0;
308
309         autoclean = show_only = quiet = do_syslog = verbose = 0;
310
311         while ((opt = getopt(argc, argv, "acdklnqrst:vVC:")) != -1) {
312                 switch(opt) {
313                 case 'c': // no config used
314                 case 'l': // no pattern matching
315                         return EXIT_SUCCESS;
316                         break;
317                 case 'C': // no config used
318                 case 't': // no pattern matching
319                         error_msg_and_die("-t and -C not supported");
320
321                 case 'a': // ignore
322                 case 'd': // ignore
323                         break;
324                 case 'k':
325                         autoclean++;
326                         break;
327                 case 'n':
328                         show_only++;
329                         break;
330                 case 'q':
331                         quiet++;
332                         break;
333                 case 'r':
334                         remove_opt++;
335                         break;
336                 case 's':
337                         do_syslog++;
338                         break;
339                 case 'v':
340                         verbose++;
341                         break;
342                 case 'V':
343                 default:
344                         show_usage();
345                         break;
346                 }
347         }
348         
349         depend = build_dep ( ); 
350
351         if ( !depend ) 
352                 error_msg_and_die ( "could not parse modules.dep\n" );
353         
354         if (remove_opt) {
355                 do {
356                         mod_remove ( optind < argc ? argv [optind] : 0 );
357                 } while ( ++optind < argc );
358                 
359                 return EXIT_SUCCESS;
360         }
361
362         if (optind >= argc) 
363                 error_msg_and_die ( "No module or pattern provided\n" );
364         
365         return mod_insert ( argv [optind], argc - optind - 1, argv + optind + 1 ) ? \
366                EXIT_FAILURE : EXIT_SUCCESS;
367 }
368
369