1 /* Insert a module into a running kernel.
2 Copyright 1996, 1997 Linux International.
3
4 New implementation contributed by Richard Henderson <rth@tamu.edu>
5 Based on original work by Bjorn Ekwall <bj0rn@blox.se>
6 Restructured (and partly rewritten) by:
7 Björn Ekwall <bj0rn@blox.se> February 1999
8
9 This file is part of the Linux modutils.
10
11 This program is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
15
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software Foundation,
23 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 */
25
26 /*
27 Fixes:
28
29 Adjust module size for mod_use_count in old_init_module:
30 B. James Phillippe <bryan@terran.org>
31
32 Merged modprobe + many fixes: Björn Ekwall <bj0rn@blox.se> February 1999
33 SMP "friendliness" (and -P): Bill Zumach <zumach+@transarc.com>
34
35 Ksymoops support: Keith Owens <kaos@ocs.com.au> August 1999.
36
37 Add -r flag: Keith Owens <kaos@ocs.com.au> October 1999.
38
39 More flexible recognition of the way the utility was called.
40 Suggested by Stepan Kasal, implemented in a different way by Keith
41 Owens <kaos@ocs.com.au> December 1999.
42
43 Rationalize common code for 32/64 bit architectures.
44 Keith Owens <kaos@ocs.com.au> December 1999.
45 Add arch64().
46 Keith Owens <kaos@ocs.com.au> December 1999.
47 */
48
49 #ident "$Id: insmod.c 1.12 Wed, 15 Mar 2000 23:50:08 +1100 keith $"
50
51 #include <sys/types.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <string.h>
55 #include <alloca.h>
56 #include <limits.h>
57 #include <ctype.h>
58 #include <errno.h>
59 #include <stddef.h>
60 #include <getopt.h>
61 #include <sys/stat.h>
62 #include <sys/file.h>
63
64 #include "module.h"
65 #include "obj.h"
66 #include "util.h"
67 #include "version.h"
68
69 #include "modstat.h"
70 #include "config.h"
71
72 #define STRVERSIONLEN 32
73
74 /*======================================================================*/
75
76 static int flag_force_load = 0;
77 static int flag_silent_poll = 0;
78 static int flag_verbose = 0;
79 static int flag_export = 1;
80 static int flag_load_map = 0;
81 static int flag_ksymoops = 1;
82
83 static int n_ext_modules_used;
84 static int m_has_modinfo;
85
86 extern int insmod_main(int argc, char **argv);
87 extern int insmod_main_32(int argc, char **argv);
88 extern int insmod_main_64(int argc, char **argv);
89 extern int modprobe_main(int argc, char **argv);
90 extern int rmmod_main(int argc, char **argv);
91 extern int ksyms_main(int argc, char **argv);
92 extern int lsmod_main(int argc, char **argv);
93
94 /*======================================================================*/
95
96 /* Get the kernel version in the canonical integer form. */
97
98 static int get_kernel_version(char str[STRVERSIONLEN])
99 {
100 char *p, *q;
101 int a, b, c;
102
103 strncpy(str, uts_info.release, STRVERSIONLEN);
104 p = uts_info.release;
105
106 a = strtoul(p, &p, 10);
107 if (*p != '.')
108 return -1;
109 b = strtoul(p + 1, &p, 10);
110 if (*p != '.')
111 return -1;
112 c = strtoul(p + 1, &q, 10);
113 if (p + 1 == q)
114 return -1;
115
116 return a << 16 | b << 8 | c;
117 }
118
119 /* String comparison for non-co-versioned kernel and module.
120 * prefix should be the same as used by genksyms for this kernel.
121 */
122 static char *ncv_prefix = NULL; /* Overridden by --prefix option */
123 static int ncv_plen = 0;
124
125 /* Only set prefix once. If set by the user, use it. If not set by the
126 * user, look for a well known kernel symbol and derive the prefix from
127 * there. Otherwise set the prefix depending on whether uts_info
128 * includes SMP or not for backwards compatibility.
129 */
130 static void set_ncv_prefix(char *prefix)
131 {
132 static char derived_prefix[256];
133 static const char well_known_symbol[] = "get_module_symbol_R";
134 struct module_symbol *s;
135 int i, l, pl;
136 const char *name;
137 char *p;
138
139 if (ncv_prefix)
140 return;
141
142 if (prefix)
143 ncv_prefix = prefix;
144 else {
145 /* Extract the prefix (if any) from the well known symbol */
146 for (i = 0, s = ksyms; i < nksyms; ++i, ++s) {
147 name = (char *) s->name;
148 if (strncmp(name, well_known_symbol, sizeof(well_known_symbol)-1) == 0) {
149 l = strlen(name);
150 pl = l - sizeof(well_known_symbol) - 7;
151 if (pl < 0 || pl > sizeof(derived_prefix)-1)
152 continue; /* Prefix is wrong length */
153 /* Must end with 8 hex digits */
154 (void) strtoul(name+l-8, &p, 16);
155 if (*p == 0) {
156 strncpy(derived_prefix, name+sizeof(well_known_symbol)-1, pl);
157 *(derived_prefix+pl) = '\0';
158 ncv_prefix = derived_prefix;
159 break;
160 }
161 }
162 }
163 }
164 if (!ncv_prefix) {
165 p = strchr(uts_info.version, ' ');
166 if (p && *(++p) && !strncmp(p, "SMP ", 4))
167 ncv_prefix = "smp_";
168 else
169 ncv_prefix = "";
170 }
171 ncv_plen = strlen(ncv_prefix);
172 if (flag_verbose)
173 printf("Symbol version prefix '%s'\n", ncv_prefix);
174 }
175
176 static int ncv_strcmp(const char *a, const char *b)
177 {
178 size_t alen = strlen(a), blen = strlen(b);
179
180 if (blen == alen + 10 + ncv_plen &&
181 b[alen] == '_' &&
182 b[alen + 1] == 'R' &&
183 !(ncv_plen && strncmp(b + alen + 2, ncv_prefix, ncv_plen))) {
184 return strncmp(a, b, alen);
185 } else if (alen == blen + 10 + ncv_plen &&
186 a[blen] == '_' && a[blen + 1] == 'R' &&
187 !(ncv_plen && strncmp(a + blen + 2, ncv_prefix, ncv_plen))) {
188 return strncmp(a, b, blen);
189 } else
190 return strcmp(a, b);
191 }
192
193 /*
194 * String hashing for non-co-versioned kernel and module.
195 * Here we are simply forced to drop the crc from the hash.
196 */
197 static unsigned long ncv_symbol_hash(const char *str)
198 {
199 size_t len = strlen(str);
200
201 if (len > 10 + ncv_plen &&
202 str[len - 10 - ncv_plen] == '_' &&
203 str[len - 9 - ncv_plen] == 'R' &&
204 !(
205 ncv_plen &&
206 strncmp(str + len - (8 + ncv_plen), ncv_prefix, ncv_plen)
207 ))
208 len -= 10 + ncv_plen;
209 return obj_elf_hash_n(str, len);
210 }
211
212 /*
213 * Conditionally add the symbols from the given symbol set
214 * to the new module.
215 */
216 static int add_symbols_from(struct obj_file *f, int idx,
217 struct module_symbol *syms, size_t nsyms)
218 {
219 struct module_symbol *s;
220 size_t i;
221 int used = 0;
222
223 for (i = 0, s = syms; i < nsyms; ++i, ++s) {
224 /*
225 * Only add symbols that are already marked external.
226 * If we override locals we may cause problems for
227 * argument initialization.
228 * We will also create a false dependency on the module.
229 */
230 struct obj_symbol *sym;
231
232 sym = obj_find_symbol(f, (char *) s->name);
233 if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) {
234 sym = obj_add_symbol(f, (char *) s->name, -1,
235 ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
236 idx, s->value, 0);
237 /*
238 * Did our symbol just get installed?
239 * If so, mark the module as "used".
240 */
241 if (sym->secidx == idx)
242 used = 1;
243 }
244 }
245
246 return used;
247 }
248
249 static void add_kernel_symbols(struct obj_file *f)
250 {
251 struct module_stat *m;
252 size_t i, nused = 0;
253
254 /* Add module symbols first. */
255 for (i = 0, m = module_stat; i < n_module_stat; ++i, ++m)
256 if (m->nsyms &&
257 add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms))
258 m->status = 1 /* used */, ++nused;
259 n_ext_modules_used = nused;
260
261 /* And finally the symbols from the kernel proper. */
262 if (nksyms)
263 add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
264 }
265
266 static void hide_special_symbols(struct obj_file *f)
267 {
268 struct obj_symbol *sym;
269 const char *const *p;
270 static const char *const specials[] =
271 {
272 "cleanup_module",
273 "init_module",
274 "kernel_version",
275 NULL
276 };
277
278 for (p = specials; *p; ++p)
279 if ((sym = obj_find_symbol(f, *p)) != NULL)
280 sym->info = ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info));
281 }
282
283 static void print_load_map(struct obj_file *f)
284 {
285 struct obj_symbol *sym;
286 struct obj_symbol **all, **p;
287 struct obj_section *sec;
288 int load_map_cmp(const void *a, const void *b) {
289 struct obj_symbol **as = (struct obj_symbol **) a;
290 struct obj_symbol **bs = (struct obj_symbol **) b;
291 unsigned long aa = obj_symbol_final_value(f, *as);
292 unsigned long ba = obj_symbol_final_value(f, *bs);
293 return aa < ba ? -1 : aa > ba ? 1 : 0;
294 }
295 int i, nsyms, *loaded;
296
297 /* Report on the section layout. */
298
299 lprintf("Sections: Size %-*s Align",
300 (int) (2 * sizeof(void *)), "Address");
301
302 for (sec = f->load_order; sec; sec = sec->load_next) {
303 int a;
304 unsigned long tmp;
305
306 for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a)
307 tmp >>= 1;
308 if (a == -1)
309 a = 0;
310
311 lprintf("%-16s%08lx %0*lx 2**%d",
312 sec->name,
313 (long)sec->header.sh_size,
314 (int) (2 * sizeof(void *)),
315 (long)sec->header.sh_addr,
316 a);
317 }
318
319 /* Quick reference which section indicies are loaded. */
320
321 loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
322 while (--i >= 0)
323 loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
324
325 /* Collect the symbols we'll be listing. */
326
327 for (nsyms = i = 0; i < HASH_BUCKETS; ++i)
328 for (sym = f->symtab[i]; sym; sym = sym->next)
329 if (sym->secidx <= SHN_HIRESERVE
330 && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
331 ++nsyms;
332
333 all = alloca(nsyms * sizeof(struct obj_symbol *));
334
335 for (i = 0, p = all; i < HASH_BUCKETS; ++i)
336 for (sym = f->symtab[i]; sym; sym = sym->next)
337 if (sym->secidx <= SHN_HIRESERVE
338 && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
339 *p++ = sym;
340
341 /* Sort them by final value. */
342 qsort(all, nsyms, sizeof(struct obj_file *), load_map_cmp);
343
344 /* And list them. */
345 lprintf("\nSymbols:");
346 for (p = all; p < all + nsyms; ++p) {
347 char type = '?';
348 unsigned long value;
349
350 sym = *p;
351 if (sym->secidx == SHN_ABS) {
352 type = 'A';
353 value = sym->value;
354 } else if (sym->secidx == SHN_UNDEF) {
355 type = 'U';
356 value = 0;
357 } else {
358 struct obj_section *sec = f->sections[sym->secidx];
359
360 if (sec->header.sh_type == SHT_NOBITS)
361 type = 'B';
362 else if (sec->header.sh_flags & SHF_ALLOC) {
363 if (sec->header.sh_flags & SHF_EXECINSTR)
364 type = 'T';
365 else if (sec->header.sh_flags & SHF_WRITE)
366 type = 'D';
367 else
368 type = 'R';
369 }
370 value = sym->value + sec->header.sh_addr;
371 }
372
373 if (ELFW(ST_BIND) (sym->info) == STB_LOCAL)
374 type = tolower(type);
375
376 lprintf("%0*lx %c %s", (int) (2 * sizeof(void *)), value,
377 type, sym->name);
378 }
379 }
380
381 /************************************************************************/
382 /* begin compat */
383
384 static char * get_modinfo_value(struct obj_file *f, const char *key)
385 {
386 struct obj_section *sec;
387 char *p, *v, *n, *ep;
388 size_t klen = strlen(key);
389
390 sec = obj_find_section(f, ".modinfo");
391 if (sec == NULL)
392 return NULL;
393
394 p = sec->contents;
395 ep = p + sec->header.sh_size;
396 while (p < ep) {
397 v = strchr(p, '=');
398 n = strchr(p, '\0');
399 if (v) {
400 if (v - p == klen && strncmp(p, key, klen) == 0)
401 return v + 1;
402 } else {
403 if (n - p == klen && strcmp(p, key) == 0)
404 return n;
405 }
406 p = n + 1;
407 }
408
409 return NULL;
410 }
411
412 static int create_this_module(struct obj_file *f, const char *m_name)
413 {
414 struct obj_section *sec;
415
416 sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
417 sizeof(struct module));
418 memset(sec->contents, 0, sizeof(struct module));
419
420 obj_add_symbol(f, "__this_module", -1, ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT),
421 sec->idx, 0, sizeof(struct module));
422
423 obj_string_patch(f, sec->idx, offsetof(struct module, name), m_name);
424
425 return 1;
426 }
427
428 #ifdef COMPAT_2_0
429 static int old_create_mod_use_count(struct obj_file *f)
430 {
431 struct obj_section *sec;
432 struct obj_symbol *got;
433
434 sec = obj_create_alloced_section_first(f, ".moduse",
435 sizeof(long), sizeof(long));
436
437 obj_add_symbol(f, "mod_use_count_",
438 -1, ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT),
439 sec->idx, 0, sizeof(long));
440
441 /*
442 * patb: if there is a _GLOBAL_OFFSET_TABLE_,
443 * add .got section for PIC type modules;
444 * we have to do this here, because obj_* calls are not made until
445 * after obj_check_undefined
446 * is there a better place for this exception?
447 */
448 got = obj_find_symbol(f, "_GLOBAL_OFFSET_TABLE_");
449 if (got)
450 {
451 sec = obj_create_alloced_section(f, ".got",
452 sizeof(long), sizeof(long));
453 got->secidx = sec->idx; /* mark the symbol as defined */
454 }
455 return 1;
456 }
457 #endif
458
459 /* add an entry to the __ksymtab section, creating it if necessary */
460 static void add_ksymtab(struct obj_file *f, struct obj_symbol *sym)
461 {
462 struct obj_section *sec;
463 ElfW(Addr) ofs;
464
465 /* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section.
466 * If __ksymtab is defined but not marked alloc, x out the first character
467 * (no obj_delete routine) and create a new __ksymtab with the correct
468 * characteristics.
469 */
470 sec = obj_find_section(f, "__ksymtab");
471 if (sec && !(sec->header.sh_flags & SHF_ALLOC)) {
472 *((char *)(sec->name)) = 'x'; /* override const */
473 sec = NULL;
474 }
475 if (!sec)
476 sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0);
477 if (!sec)
478 return;
479 sec->header.sh_flags |= SHF_ALLOC;
480
481 ofs = sec->header.sh_size;
482 obj_symbol_patch(f, sec->idx, ofs, sym);
483 obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name);
484 obj_extend_section(sec, 2 * tgt_sizeof_char_p);
485 }
486
487 static int create_module_ksymtab(struct obj_file *f)
488 {
489 struct obj_section *sec;
490 int i;
491
492 /* We must always add the module references. */
493
494 if (n_ext_modules_used) {
495 struct module_ref *dep;
496 struct obj_symbol *tm;
497
498 sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
499 (sizeof(struct module_ref)
500 * n_ext_modules_used));
501 if (!sec)
502 return 0;
503
504 tm = obj_find_symbol(f, "__this_module");
505 dep = (struct module_ref *) sec->contents;
506 for (i = 0; i < n_module_stat; ++i)
507 if (module_stat[i].status /* used */) {
508 dep->dep = module_stat[i].addr;
509 obj_symbol_patch(f, sec->idx, (char *) &dep->ref - sec->contents, tm);
510 dep->next_ref = 0;
511 ++dep;
512 }
513 }
514 if (flag_export && !obj_find_section(f, "__ksymtab")) {
515 int *loaded;
516
517 /* We don't want to export symbols residing in sections that
518 aren't loaded. There are a number of these created so that
519 we make sure certain module options don't appear twice. */
520
521 loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
522 while (--i >= 0)
523 loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
524
525 for (i = 0; i < HASH_BUCKETS; ++i) {
526 struct obj_symbol *sym;
527 for (sym = f->symtab[i]; sym; sym = sym->next) {
528 if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
529 && sym->secidx <= SHN_HIRESERVE
530 && (sym->secidx >= SHN_LORESERVE
531 || loaded[sym->secidx])) {
532 add_ksymtab(f, sym);
533 }
534 }
535 }
536 }
537 return 1;
538 }
539
540 /* Get the module's kernel version in the canonical integer form. */
541 static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
542 {
543 int a, b, c;
544 char *p, *q;
545
546 if ((p = get_modinfo_value(f, "kernel_version")) == NULL) {
547 struct obj_symbol *sym;
548
549 m_has_modinfo = 0;
550 if ((sym = obj_find_symbol(f, "kernel_version")) == NULL)
551 sym = obj_find_symbol(f, "__module_kernel_version");
552 if (sym == NULL)
553 return -1;
554 p = f->sections[sym->secidx]->contents + sym->value;
555 } else
556 m_has_modinfo = 1;
557
558 strncpy(str, p, STRVERSIONLEN);
559
560 a = strtoul(p, &p, 10);
561 if (*p != '.')
562 return -1;
563 b = strtoul(p + 1, &p, 10);
564 if (*p != '.')
565 return -1;
566 c = strtoul(p + 1, &q, 10);
567 if (p + 1 == q)
568 return -1;
569
570 return a << 16 | b << 8 | c;
571 }
572
573 /* Return the kernel symbol checksum version, or zero if not used. */
574 static int is_kernel_checksummed(void)
575 {
576 struct module_symbol *s;
577 size_t i;
578
579 /*
580 * Using_Versions might not be the first symbol,
581 * but it should be in there.
582 */
583 for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
584 if (strcmp((char *) s->name, "Using_Versions") == 0)
585 return s->value;
586
587 return 0;
588 }
589
590 static int is_module_checksummed(struct obj_file *f)
591 {
592 if (m_has_modinfo) {
593 const char *p = get_modinfo_value(f, "using_checksums");
594 if (p)
595 return atoi(p);
596 else
597 return 0;
598 } else
599 return obj_find_symbol(f, "Using_Versions") != NULL;
600 }
601
602 /* add module source, timestamp, kernel version and a symbol for the start of some sections.
603 * this info is used by ksymoops to do better debugging.
604 */
605 static void add_ksymoops_symbols(struct obj_file *f, const char *filename, const char *m_name)
606 {
607 struct obj_section *sec;
608 struct obj_symbol *sym;
609 char *name;
610 char str[STRVERSIONLEN];
611 const char symprefix[] = "__insmod_";
612 int i, l, lm_name, lfilename, use_ksymtab, version;
613 struct stat statbuf;
614
615 static const char *section_names[] = {
616 ".text",
617 ".rodata",
618 ".data",
619 ".bss"
620 };
621
622 lm_name = strlen(m_name);
623 lfilename = strlen(filename);
624
625 /* add to ksymtab if it already exists or there is no ksymtab and other symbols
626 * are not to be exported. otherwise leave ksymtab alone for now, the
627 * "export all symbols" compatibility code will export these symbols later.
628 */
629
630 use_ksymtab = obj_find_section(f, "__ksymtab") || !flag_export;
631
632 if ((sec = obj_find_section(f, ".this"))) {
633 /* tag the module header with the object name, last modified
634 * timestamp and module version. worst case for module version
635 * is 0xffffff, decimal 16777215. putting all three fields in
636 * one symbol is less readable but saves kernel space.
637 */
638 l = sizeof(symprefix)+ /* "__insmod_" */
639 lm_name+ /* module name */
640 2+ /* "_O" */
641 lfilename+ /* object filename */
642 2+ /* "_M" */
643 2*sizeof(statbuf.st_mtime)+ /* mtime in hex */
644 2+ /* "_V" */
645 8+ /* version in dec */
646 1; /* nul */
647 name = xmalloc(l);
648 if (stat(filename, &statbuf) != 0)
649 statbuf.st_mtime = 0;
650 version = get_module_version(f, str); /* -1 if not found */
651 snprintf(name, l, "%s%s_O%s_M%0*lX_V%d",
652 symprefix, m_name, filename,
653 2*sizeof(statbuf.st_mtime), statbuf.st_mtime,
654 version);
655 sym = obj_add_symbol(f, name, -1,
656 ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
657 sec->idx, sec->header.sh_addr, 0);
658 if (use_ksymtab)
659 add_ksymtab(f, sym);
660 }
661
662 /* tag the desired sections if size is non-zero */
663
664 for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); ++i) {
665 if ((sec = obj_find_section(f, section_names[i])) &&
666 sec->header.sh_size) {
667 l = sizeof(symprefix)+ /* "__insmod_" */
668 lm_name+ /* module name */
669 2+ /* "_S" */
670 strlen(sec->name)+ /* section name */
671 2+ /* "_L" */
672 8+ /* length in dec */
673 1; /* nul */
674 name = xmalloc(l);
675 snprintf(name, l, "%s%s_S%s_L%ld",
676 symprefix, m_name, sec->name,
677 (long)sec->header.sh_size);
678 sym = obj_add_symbol(f, name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
679 sec->idx, sec->header.sh_addr, 0);
680 if (use_ksymtab)
681 add_ksymtab(f, sym);
682 }
683 }
684 }
685
686 static int process_module_arguments(struct obj_file *f, int argc, char **argv)
687 {
688 for (; argc > 0; ++argv, --argc) {
689 struct obj_symbol *sym;
690 int c;
691 int min, max;
692 int n;
693 char *contents;
694 char *input;
695 char *fmt;
696 char *key;
697 char *loc;
698
699 if ((input = strchr(*argv, '=')) == NULL)
700 continue;
701
702 n = input - *argv;
703 input += 1; /* skip '=' */
704
705 key = alloca(n + 6);
706
707 if (m_has_modinfo) {
708 memcpy(key, "parm_", 5);
709 memcpy(key + 5, *argv, n);
710 key[n + 5] = '\0';
711 if ((fmt = get_modinfo_value(f, key)) == NULL) {
712 error("invalid parameter %s", key);
713 return 0;
714 }
715 key += 5;
716
717 if (isdigit(*fmt)) {
718 min = strtoul(fmt, &fmt, 10);
719 if (*fmt == '-')
720 max = strtoul(fmt + 1, &fmt, 10);
721 else
722 max = min;
723 } else
724 min = max = 1;
725 } else { /* not m_has_modinfo */
726 memcpy(key, *argv, n);
727 key[n] = '\0';
728
729 if (isdigit(*input))
730 fmt = "i";
731 else
732 fmt = "s";
733 min = max = 0;
734 }
735
736 sym = obj_find_symbol(f, key);
737
738 /*
739 * Also check that the parameter was not
740 * resolved from the kernel.
741 */
742 if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
743 error("symbol for parameter %s not found", key);
744 return 0;
745 }
746
747 contents = f->sections[sym->secidx]->contents;
748 loc = contents + sym->value;
749 n = 1;
750
751 while (*input) {
752 char *str;
753
754 switch (*fmt) {
755 case 's':
756 case 'c':
757 /*
758 * Do C quoting if we begin with a ",
759 * else slurp the lot.
760 */
761 if (*input == '"') {
762 char *r;
763
764 str = alloca(strlen(input));
765 for (r = str, input++; *input != '"'; ++input, ++r) {
766 if (*input == '\0') {
767 error("improperly terminated string argument for %s", key);
768 return 0;
769 }
770 /* else */
771 if (*input != '\\') {
772 *r = *input;
773 continue;
774 }
775 /* else handle \ */
776 switch (*++input) {
777 case 'a': *r = '\a'; break;
778 case 'b': *r = '\b'; break;
779 case 'e': *r = '\033'; break;
780 case 'f': *r = '\f'; break;
781 case 'n': *r = '\n'; break;
782 case 'r': *r = '\r'; break;
783 case 't': *r = '\t'; break;
784
785 case '':
786 case '1':
787 case '2':
788 case '3':
789 case '4':
790 case '5':
791 case '6':
792 case '7':
793 c = *input - '';
794 if ('' <= input[1] && input[1] <= '7') {
795 c = (c * 8) + *++input - '';
796 if ('' <= input[1] && input[1] <= '7')
797 c = (c * 8) + *++input - '';
798 }
799 *r = c;
800 break;
801
802 default: *r = *input; break;
803 }
804 }
805 *r = '\0';
806 ++input;
807 } else {
808 /*
809 * The string is not quoted.
810 * We will break it using the comma
811 * (like for ints).
812 * If the user wants to include commas
813 * in a string, he just has to quote it
814 */
815 char *r;
816
817 /* Search the next comma */
818 if ((r = strchr(input, ',')) != NULL) {
819 /*
820 * Found a comma
821 * Recopy the current field
822 */
823 str = alloca(r - input + 1);
824 memcpy(str, input, r - input);
825 str[r - input] = '\0';
826 /* Keep next fields */
827 input = r;
828 } else {
829 /* last string */
830 str = input;
831 input = "";
832 }
833 }
834
835 if (*fmt == 's') {
836 /* Normal string */
837 obj_string_patch(f, sym->secidx, loc - contents, str);
838 loc += tgt_sizeof_char_p;
839 } else {
840 /* Array of chars (in fact, matrix !) */
841 long charssize; /* size of each member */
842
843 /* Get the size of each member */
844 /* Probably we should do that outside the loop ? */
845 if (!isdigit(*(fmt + 1))) {
846 error("parameter type 'c' for %s must be followed by"
847 " the maximum size", key);
848 return 0;
849 }
850 charssize = strtoul(fmt + 1, (char **) NULL, 10);
851
852 /* Check length */
853 if (strlen(str) >= charssize) {
854 error("string too long for %s (max %ld)",
855 key, charssize - 1);
856 return 0;
857 }
858 /* Copy to location */
859 strcpy((char *) loc, str);
860 loc += charssize;
861 }
862 /*
863 * End of 's' and 'c'
864 */
865 break;
866
867 case 'b':
868 *loc++ = strtoul(input, &input, 0);
869 break;
870
871 case 'h':
872 *(short *) loc = strtoul(input, &input, 0);
873 loc += tgt_sizeof_short;
874 break;
875
876 case 'i':
877 *(int *) loc = strtoul(input, &input, 0);
878 loc += tgt_sizeof_int;
879 break;
880
881 case 'l':
882 *(long *) loc = strtoul(input, &input, 0);
883 loc += tgt_sizeof_long;
884 break;
885
886 default:
887 error("unknown parameter type '%c' for %s",
888 *fmt, key);
889 return 0;
890 }
891 /*
892 * end of switch (*fmt)
893 */
894
895 while (*input && isspace(*input))
896 ++input;
897 if (*input == '\0')
898 break; /* while (*input) */
899 /* else */
900
901 if (*input == ',') {
902 if (max && (++n > max)) {
903 error("too many values for %s (max %d)", key, max);
904 return 0;
905 }
906 ++input;
907 /* continue with while (*input) */
908 } else {
909 error("invalid argument syntax for %s: '%c'",
910 key, *input);
911 return 0;
912 }
913 } /* end of while (*input) */
914
915 if (min && (n < min)) {
916 error("too few values for %s (min %d)", key, min);
917 return 0;
918 }
919 } /* end of for (;argc > 0;) */
920
921 return 1;
922 }
923
924 static int init_module(const char *m_name, struct obj_file *f, unsigned long m_size)
925 {
926 struct module *module;
927 struct obj_section *sec;
928 void *image;
929 int ret;
930 tgt_long m_addr;
931
932 sec = obj_find_section(f, ".this");
933 module = (struct module *) sec->contents;
934 m_addr = sec->header.sh_addr;
935
936 module->size_of_struct = sizeof(*module);
937 module->size = m_size;
938 module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
939
940 sec = obj_find_section(f, "__ksymtab");
941 if (sec && sec->header.sh_size) {
942 module->syms = sec->header.sh_addr;
943 module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
944 }
945 if (n_ext_modules_used) {
946 sec = obj_find_section(f, ".kmodtab");
947 module->deps = sec->header.sh_addr;
948 module->ndeps = n_ext_modules_used;
949 }
950 module->init = obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
951 module->cleanup = obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
952
953 sec = obj_find_section(f, "__ex_table");
954 if (sec) {
955 module->ex_table_start = sec->header.sh_addr;
956 module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
957 }
958 sec = obj_find_section(f, ".text.init");
959 if (sec) {
960 module->runsize = sec->header.sh_addr - m_addr;
961 }
962 sec = obj_find_section(f, ".data.init");
963 if (sec) {
964 if (!module->runsize ||
965 module->runsize > sec->header.sh_addr - m_addr)
966 module->runsize = sec->header.sh_addr - m_addr;
967 }
968 if (!arch_init_module(f, module))
969 return 0;
970
971 /*
972 * Whew! All of the initialization is complete.
973 * Collect the final module image and give it to the kernel.
974 */
975 image = xmalloc(m_size);
976 obj_create_image(f, image);
977
978 ret = sys_init_module(m_name, (struct module *) image);
979 if (ret) {
980 error("init_module: %m");
981 if (ret == -EBUSY)
982 lprintf("Hint: this error can be caused by incorrect module parameters, "
983 "including invalid IO and IRQ parameters\n");
984 }
985
986 free(image);
987
988 return ret == 0;
989 }
990
991 #ifdef COMPAT_2_0
992 static int old_init_module(const char *m_name, struct obj_file *f, unsigned long m_size)
993 {
994 char *image;
995 struct old_mod_routines routines;
996 struct old_symbol_table *symtab;
997 int ret;
998 int nsyms = 0, strsize = 0, total;
999
1000 /* Create the symbol table */
1001 /* Size things first... */
1002 if (flag_export) {
1003 int i;
1004 for (i = 0; i < HASH_BUCKETS; ++i) {
1005 struct obj_symbol *sym;
1006
1007 for (sym = f->symtab[i]; sym; sym = sym->next)
1008 if (ELFW(ST_BIND) (sym->info) != STB_LOCAL &&
1009 sym->secidx <= SHN_HIRESERVE) {
1010 sym->ksymidx = nsyms++;
1011 strsize += strlen(sym->name) + 1;
1012 }
1013 }
1014 }
1015 total = (sizeof(struct old_symbol_table) +
1016 nsyms * sizeof(struct old_module_symbol) +
1017 n_ext_modules_used * sizeof(struct old_module_ref) +
1018 strsize);
1019 symtab = xmalloc(total);
1020 symtab->size = total;
1021 symtab->n_symbols = nsyms;
1022 symtab->n_refs = n_ext_modules_used;
1023
1024 if (flag_export && nsyms) {
1025 struct old_module_symbol *ksym;
1026 char *str;
1027 int i;
1028
1029 ksym = symtab->symbol;
1030 str = ((char *) ksym +
1031 nsyms * sizeof(struct old_module_symbol) +
1032 n_ext_modules_used * sizeof(struct old_module_ref));
1033
1034 for (i = 0; i < HASH_BUCKETS; ++i) {
1035 struct obj_symbol *sym;
1036 for (sym = f->symtab[i]; sym; sym = sym->next)
1037 if (sym->ksymidx >= 0) {
1038 ksym->addr = obj_symbol_final_value(f, sym);
1039 ksym->name = (unsigned long) str - (unsigned long) symtab;
1040
1041 str = stpcpy(str, sym->name) + 1;
1042 ksym++;
1043 }
1044 }
1045 }
1046
1047 if (n_ext_modules_used) {
1048 struct old_module_ref *ref;
1049 int i;
1050
1051 ref = (struct old_module_ref *)
1052 ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol));
1053
1054 for (i = 0; i < n_module_stat; ++i) {
1055 if (module_stat[i].status /* used */) {
1056 ref++->module = module_stat[i].modstruct;
1057 }
1058 }
1059 }
1060
1061 /* Fill in routines. */
1062
1063 routines.init = obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
1064 routines.cleanup = obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
1065
1066 /*
1067 * Whew! All of the initialization is complete.
1068 * Collect the final module image and give it to the kernel.
1069 */
1070 image = xmalloc(m_size);
1071 obj_create_image(f, image);
1072
1073 /*
1074 * image holds the complete relocated module,
1075 * accounting correctly for mod_use_count.
1076 * However the old module kernel support assume that it
1077 * is receiving something which does not contain mod_use_count.
1078 */
1079 ret = old_sys_init_module(m_name, image + sizeof(long),
1080 (m_size - sizeof(long)) |
1081 (flag_autoclean ? OLD_MOD_AUTOCLEAN : 0),
1082 &routines,
1083 symtab);
1084 if (ret)
1085 error("init_module: %m");
1086
1087 free(image);
1088 free(symtab);
1089
1090 return ret == 0;
1091 }
1092 #endif
1093 /* end compat */
1094 /************************************************************************/
1095
1096
1097 /* For common 3264 code, only compile the usage message once, in the 64 bit version */
1098 #if defined(COMMON_3264) && defined(ONLY_32)
1099 extern void insmod_usage(void); /* Use the copy in the 64 bit version */
1100 #else /* Common 64 bit version or any non common code - compile usage routine */
1101 void insmod_usage(void)
1102 {
1103 fputs("Usage:\n"
1104 "insmod [-fkmopsvVxXyY] [-o name] [-P prefix] module [[sym=value]...]\n"
1105
1106 "\n"
1107 " module Filename of a loadable kernel module (*.o)\n"
1108 " -f, --force Force loading under wrong kernel version\n"
1109 " -k, --autoclean Make module autoclean-able\n"
1110 " -m, --map Generate load map (so crashes can be traced)\n"
1111 " -n, --noload Don't load, just show\n"
1112 " -o NAME, --name=NAME Set internal module name to NAME\n"
1113 " -p, --poll Poll mode; check if the module matches the kernel\n"
1114 " -s, --syslog Report errors via syslog\n"
1115 " -v, --verbose Verbose output\n"
1116 " -L, --lock Prevent simultaneous loads of the same module\n"
1117 " -V, --version Show version\n"
1118 " -x Do not export externs\n"
1119 " -X Do export externs (default)\n"
1120 " -y Do not add ksymoops symbols\n"
1121 " -Y Do add ksymoops symbols (default)\n"
1122 " -r Allow root to load modules not owned by root\n"
1123 " -P PREFIX\n"
1124 " --prefix=PREFIX Prefix for kernel or module symbols\n"
1125 ,stderr);
1126 exit(1);
1127 }
1128 #endif /* defined(COMMON_3264) && defined(ONLY_32) */
1129
1130 #if defined(COMMON_3264) && defined(ONLY_32)
1131 #define INSMOD_MAIN insmod_main_32 /* 32 bit version */
1132 #elif defined(COMMON_3264) && defined(ONLY_64)
1133 #define INSMOD_MAIN insmod_main_64 /* 64 bit version */
1134 #else
1135 #define INSMOD_MAIN insmod_main /* Not common code */
1136 #endif
1137
1138 int INSMOD_MAIN(int argc, char **argv)
1139 {
1140 int k_version;
1141 int k_crcs;
1142 char k_strversion[STRVERSIONLEN];
1143 struct option long_opts[] = {
1144 {"force", 0, 0, 'f'},
1145 {"autoclean", 0, 0, 'k'},
1146 {"map", 0, 0, 'm'},
1147 {"noload", 0, 0, 'n'},
1148 {"name", 1, 0, 'o'},
1149 {"poll", 0, 0, 'p'},
1150 {"syslog", 0, 0, 's'},
1151 {"verbose", 0, 0, 'v'},
1152 {"version", 0, 0, 'V'},
1153 {"lock", 0, 0, 'L'},
1154 {"prefix", 1, 0, 'P'},
1155 {"noexport", 0, 0, 'x'},
1156 {"export", 0, 0, 'X'},
1157 {"quiet", 0, 0, 'q'},
1158 {"noksymoops", 0, 0, 'y'},
1159 {"ksymoops", 0, 0, 'Y'},
1160 {"root", 0, 0, 'r'},
1161 {0, 0, 0, 0}
1162 };
1163 char *m_name = NULL;
1164 int m_version;
1165 ElfW(Addr) m_addr;
1166 unsigned long m_size;
1167 int m_crcs;
1168 char m_strversion[STRVERSIONLEN];
1169 char *filename;
1170 FILE *fp;
1171 struct obj_file *f;
1172 int o;
1173 int noload = 0;
1174 int dolock = 1; /*Note: was: 0; */
1175 int quiet = 0;
1176 int exit_status = 1;
1177 int i;
1178
1179 error_file = "insmod";
1180
1181 /* To handle repeated calls from combined modprobe */
1182 errors = optind = 0;
1183
1184 /* Process the command line. */
1185 while ((o = getopt_long(argc, argv, "fkmno:pqsvVxXLP:yYr",
1186 &long_opts[0], NULL)) != EOF)
1187 switch (o) {
1188 case 'f': /* force loading */
1189 flag_force_load = 1;
1190 break;
1191 case 'k': /* module loaded by kerneld, auto-cleanable */
1192 flag_autoclean = 1;
1193 break;
1194 case 'L': /* protect against recursion. */
1195 dolock = 1;
1196 break;
1197 case 'm': /* generate load map */
1198 flag_load_map = 1;
1199 break;
1200 case 'n': /* don't load, just check */
1201 noload = 1;
1202 break;
1203 case 'o': /* name the output module */
1204 m_name = optarg;
1205 break;
1206 case 'p': /* silent poll mode */
1207 flag_silent_poll = 1;
1208 break;
1209 case 'q': /* Don't print unresolved symbols */
1210 quiet = 1;
1211 break;
1212 case 's': /* start syslog */
1213 setsyslog("insmod");
1214 break;
1215 case 'v': /* verbose output */
1216 flag_verbose = 1;
1217 break;
1218 case 'V':
1219 fputs("insmod version " MODUTILS_VERSION "\n", stderr);
1220 break;
1221 case 'x': /* do not export externs */
1222 flag_export = 0;
1223 break;
1224 case 'X': /* do export externs */
1225 flag_export = 1;
1226 break;
1227 case 'y': /* do not define ksymoops symbols */
1228 flag_ksymoops = 0;
1229 break;
1230 case 'Y': /* do define ksymoops symbols */
1231 flag_ksymoops = 1;
1232 break;
1233 case 'r': /* allow root to load non-root modules */
1234 root_check_off = 1;
1235 break;
1236 case 'P': /* use prefix on crc */
1237 set_ncv_prefix(optarg);
1238 break;
1239 default:
1240 insmod_usage();
1241 break;
1242 }
1243
1244 if (optind >= argc) {
1245 insmod_usage();
1246 }
1247 filename = argv[optind++];
1248
1249 if (config_read(0, NULL, NULL, NULL) < 0) {
1250 error("Failed handle configuration");
1251 }
1252
1253 if (m_name == NULL) {
1254 size_t len;
1255 char *p;
1256
1257 if ((p = strrchr(filename, '/')) != NULL)
1258 p++;
1259 else
1260 p = filename;
1261 len = strlen(p);
1262 if (len > 2 && p[len - 2] == '.' && p[len - 1] == 'o')
1263 len -= 2;
1264 else if (len > 4 && p[len - 4] == '.' && p[len - 3] == 'm'
1265 && p[len - 2] == 'o' && p[len - 1] == 'd')
1266 len -= 4;
1267
1268 m_name = xmalloc(len + 1);
1269 memcpy(m_name, p, len);
1270 m_name[len] = '\0';
1271 }
1272
1273 /* Locate the file to be loaded. */
1274 if (!strchr(filename, '/') && !strchr(filename, '.')) {
1275 char *tmp = search_module_path(filename);
1276 if (tmp == NULL) {
1277 error("%s: no module by that name found", filename);
1278 return 1;
1279 }
1280 filename = tmp;
1281 printf("Using %s\n", filename);
1282 } else if (flag_verbose)
1283 printf("Using %s\n", filename);
1284
1285 /* And open it. */
1286 if ((fp = fopen(filename, "r")) == NULL) {
1287 error_file = filename;
1288 error("%s: %m", filename);
1289 return 1;
1290 }
1291 /* Try to prevent multiple simultaneous loads. */
1292 if (dolock)
1293 flock(fileno(fp), LOCK_EX);
1294
1295 if (!get_kernel_info(K_SYMBOLS))
1296 goto out;
1297
1298 /*
1299 * Set the genksyms prefix if this is a versioned kernel
1300 * and it's not already set.
1301 */
1302 set_ncv_prefix(NULL);
1303
1304 for (i = 0; i < n_module_stat; ++i) {
1305 if (strcmp(module_stat[i].name, m_name) == 0) {
1306 error("a module named %s already exists", m_name);
1307 goto out;
1308 }
1309 }
1310
1311 error_file = filename;
1312 if ((f = obj_load(fp)) == NULL)
1313 goto out;
1314
1315 /* Version correspondence? */
1316 k_version = get_kernel_version(k_strversion);
1317 m_version = get_module_version(f, m_strversion);
1318 if (m_version == -1) {
1319 error("couldn't find the kernel version the module was compiled for");
1320 goto out;
1321 }
1322
1323 k_crcs = is_kernel_checksummed();
1324 m_crcs = is_module_checksummed(f);
1325 if ((m_crcs == 0 || k_crcs == 0) &&
1326 strncmp(k_strversion, m_strversion, STRVERSIONLEN) != 0) {
1327 if (flag_force_load) {
1328 lprintf("Warning: kernel-module version mismatch\n"
1329 "\t%s was compiled for kernel version %s\n"
1330 "\twhile this kernel is version %s\n",
1331 filename, m_strversion, k_strversion);
1332 } else {
1333 if (!quiet)
1334 error("kernel-module version mismatch\n"
1335 "\t%s was compiled for kernel version %s\n"
1336 "\twhile this kernel is version %s.",
1337 filename, m_strversion, k_strversion);
1338 goto out;
1339 }
1340 }
1341 if (m_crcs != k_crcs)
1342 obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
1343
1344 /* Let the module know about the kernel symbols. */
1345 add_kernel_symbols(f);
1346
1347 /* Allocate common symbols, symbol tables, and string tables. */
1348 #ifdef COMPAT_2_0
1349 if (k_new_syscalls
1350 ? !create_this_module(f, m_name)
1351 : !old_create_mod_use_count(f))
1352 goto out;
1353 #else
1354 if (!create_this_module(f, m_name))
1355 goto out;
1356 #endif
1357
1358 if (!obj_check_undefineds(f, quiet))
1359 goto out;
1360 obj_allocate_commons(f);
1361
1362 if (optind < argc) {
1363 if (!process_module_arguments(f, argc - optind, argv + optind))
1364 goto out;
1365 }
1366 arch_create_got(f);
1367 hide_special_symbols(f);
1368 if (flag_ksymoops)
1369 add_ksymoops_symbols(f, filename, m_name);
1370
1371 if (k_new_syscalls)
1372 create_module_ksymtab(f);
1373
1374 if (errors)
1375 goto out;
1376
1377 /* If we were just checking, we made it. */
1378 if (flag_silent_poll) {
1379 exit_status = 0;
1380 goto out;
1381 }
1382 /* Module has now finished growing; find its size and install it. */
1383 m_size = obj_load_size(f);
1384
1385 if (noload) {
1386 /* Don't bother actually touching the kernel. */
1387 m_addr = 0x12340000;
1388 } else {
1389 errno = 0;
1390 m_addr = create_module(m_name, m_size);
1391 switch (errno) {
1392 case 0:
1393 break;
1394 case EEXIST:
1395 if (dolock) {
1396 /*
1397 * Assume that we were just invoked
1398 * simultaneous with another insmod
1399 * and return success.
1400 */
1401 exit_status = 0;
1402 goto out;
1403 }
1404 error("a module named %s already exists", m_name);
1405 goto out;
1406 case ENOMEM:
1407 error("can't allocate kernel memory for module; needed %lu bytes",
1408 m_size);
1409 goto out;
1410 default:
1411 error("create_module: %m");
1412 goto out;
1413 }
1414 }
1415
1416 if (!obj_relocate(f, m_addr)) {
1417 if (!noload)
1418 delete_module(m_name);
1419 goto out;
1420 }
1421 if (!noload) {
1422 #ifdef COMPAT_2_0
1423 if (k_new_syscalls)
1424 init_module(m_name, f, m_size);
1425 else
1426 old_init_module(m_name, f, m_size);
1427 #else
1428 init_module(m_name, f, m_size);
1429 #endif
1430 }
1431 if (errors) {
1432 if (!noload)
1433 delete_module(m_name);
1434 goto out;
1435 }
1436 if (flag_load_map)
1437 print_load_map(f);
1438 exit_status = 0;
1439
1440 out:
1441 if (dolock)
1442 flock(fileno(fp), LOCK_UN);
1443 fclose(fp);
1444 if (!noload)
1445 snap_shot(NULL, 0);
1446
1447 return exit_status;
1448 }
1449
1450 /* For common 3264 code, add an overall insmod_main, in the 64 bit version. */
1451 #if defined(COMMON_3264) && defined(ONLY_64)
1452 int insmod_main(int argc, char **argv)
1453 {
1454 if (arch64())
1455 return insmod_main_64(argc, argv);
1456 else
1457 return insmod_main_32(argc, argv);
1458 }
1459 #endif /* defined(COMMON_3264) && defined(ONLY_64) */
1460
1461
1462 /* For common 3264 code, only compile main in the 64 bit version. */
1463 #if defined(COMMON_3264) && defined(ONLY_32)
1464 /* Use the main in the 64 bit version */
1465 #else
1466 /* This mainline looks at the name it was invoked under, checks that the name
1467 * contains exactly one of the possible combined targets and invokes the
1468 * corresponding handler for that function.
1469 */
1470 int main(int argc, char **argv)
1471 {
1472 /* List of possible program names and the corresponding mainline routines */
1473 static struct { char *name; int (*handler)(int, char **); } mains[] =
1474 {
1475 { "insmod", &insmod_main },
1476 #ifdef COMBINE_modprobe
1477 { "modprobe", &modprobe_main },
1478 #endif
1479 #ifdef COMBINE_rmmod
1480 { "rmmod", &rmmod_main },
1481 #endif
1482 #ifdef COMBINE_ksyms
1483 { "ksyms", &ksyms_main },
1484 #endif
1485 #ifdef COMBINE_lsmod
1486 { "lsmod", &lsmod_main },
1487 #endif
1488 };
1489 #define MAINS_NO (sizeof(mains)/sizeof(mains[0]))
1490 static int mains_match;
1491 static int mains_which;
1492
1493 char *p = strrchr(argv[0], '/');
1494 char error_id1[2048] = "The "; /* Way oversized */
1495 char error_id2[2048] = ""; /* Way oversized */
1496 int i;
1497
1498 p = p ? p + 1 : argv[0];
1499
1500 for (i = 0; i < MAINS_NO; ++i) {
1501 if (i) {
1502 strcat(error_id1, "/");
1503 if (i == MAINS_NO-1)
1504 strcat(error_id2, " or ");
1505 else
1506 strcat(error_id2, ", ");
1507 }
1508 strcat(error_id1, mains[i].name);
1509 strcat(error_id2, mains[i].name);
1510 if (strstr(p, mains[i].name)) {
1511 ++mains_match;
1512 mains_which = i;
1513 }
1514 }
1515
1516 /* Finish the error identifiers */
1517 if (MAINS_NO != 1)
1518 strcat(error_id1, " combined");
1519 strcat(error_id1, " binary");
1520
1521 if (mains_match == 0 && MAINS_NO == 1)
1522 ++mains_match; /* Not combined, any name will do */
1523 if (mains_match == 0) {
1524 error("%s does not have a recognisable name, the name must contain one of %s.",
1525 error_id1, error_id2);
1526 return(1);
1527 }
1528 else if (mains_match > 1) {
1529 error("%s has an ambiguous name, it must contain %s%s.",
1530 error_id1, MAINS_NO == 1 ? "" : "exactly one of ", error_id2);
1531 return(1);
1532 }
1533 else
1534 return((mains[mains_which].handler)(argc, argv));
1535 }
1536 #endif /* defined(COMMON_3264) && defined(ONLY_32) */
1537
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.