insmod的入口在insmod.c,在./modultils-2.4.0/insmod/下。
1944 /* For common 3264 code, only compile main in the 64 bit version. */
1945 #if defined(COMMON_3264) && defined(ONLY_32)
1946 /* Use the main in the 64 bit version */
1947 #else
1948 /* This mainline looks at the name it was invoked under, checks that the name
1949 * contains exactly one of the possible combined targets and invokes the
1950 * corresponding handler for that function.
1951 */
1952 int main(int argc, char **argv)
1953 {
1954 /* List of possible program names and the corresponding mainline routines */
1955 static struct { char *name; int (*handler)(int, char **); } mains[] =
1956 {
1957 { "insmod", &insmod_main },
1958 #ifdef COMBINE_modprobe
1959 { "modprobe", &modprobe_main },
1960 #endif
1961 #ifdef COMBINE_rmmod
1962 { "rmmod", &rmmod_main },
1963 #endif
1964 #ifdef COMBINE_ksyms
1965 { "ksyms", &ksyms_main },
1966 #endif
1967 #ifdef COMBINE_lsmod
1968 { "lsmod", &lsmod_main },
1969 #endif
1970 #ifdef COMBINE_kallsyms
1971 { "kallsyms", &kallsyms_main },
1972 #endif
1973 };
1974 #define MAINS_NO (sizeof(mains)/sizeof(mains[0]))
1975 static int mains_match;
1976 static int mains_which;
1977
1978 char *p = strrchr(argv[0], '/');
1979 char error_id1[2048] = "The "; /* Way oversized */
1980 char error_id2[2048] = ""; /* Way oversized */
1981 int i;
1982
1983 p = p ? p + 1 : argv[0];
1984
1985 for (i = 0; i < MAINS_NO; ++i) {
1986 if (i) {
1987 xstrcat(error_id1, "/", sizeof(error_id1));
1988 if (i == MAINS_NO-1)
1989 xstrcat(error_id2, " or ", sizeof(error_id2));
1990 else
1991 xstrcat(error_id2, ", ", sizeof(error_id2));
1992 }
1993 xstrcat(error_id1, mains[i].name, sizeof(error_id1));
1994 xstrcat(error_id2, mains[i].name, sizeof(error_id2));
1995 if (strstr(p, mains[i].name)) {
1996 ++mains_match;
1997 mains_which = i;
1998 }
1999 }
2000
2001 /* Finish the error identifiers */
2002 if (MAINS_NO != 1)
2003 xstrcat(error_id1, " combined", sizeof(error_id1));
2004 xstrcat(error_id1, " binary", sizeof(error_id1));
2005
2006 if (mains_match == 0 && MAINS_NO == 1)
2007 ++mains_match; /* Not combined, any name will do */
2008 if (mains_match == 0) {
2009 error("%s does not have a recognisable name, "
2010 "the name must contain one of %s.",
2011 error_id1, error_id2);
2012 return(1);
2013 }
2014 else if (mains_match > 1) {
2015 error("%s has an ambiguous name, it must contain %s%s.",
2016 error_id1, MAINS_NO == 1 ? "" : "exactly one of ", error_id2);
2017 return(1);
2018 }
2019 else
2020 return((mains[mains_which].handler)(argc, argv));
2021 }
2022 #endif /* defined(COMMON_3264) && defined(ONLY_32) */
当输入insmod –x…命令时,将调用insmod_main,这是个宏定义。
1416 #if defined(COMMON_3264) && defined(ONLY_32)
1417 #define INSMOD_MAIN insmod_main_32 /* 32 bit version */
1418 #elif defined(COMMON_3264) && defined(ONLY_64)
1419 #define INSMOD_MAIN insmod_main_64 /* 64 bit version */
1420 #else
1421 #define INSMOD_MAIN insmod_main /* Not common code */
1422 #endif
不管是怎么样的体系,最后都会进入INSMOD_MAIN函数。这个函数在insmod.c中。
Insmod——INSMOD_MAIN函数
1424 int INSMOD_MAIN(int argc, char **argv)
1425 {
1426 int k_version;
1427 int k_crcs;
1428 char k_strversion[STRVERSIONLEN];
1429 struct option long_opts[] = {
1430 {"force", 0, 0, 'f'},
1431 {"help", 0, 0, 'h'},
1432 {"autoclean", 0, 0, 'k'},
1433 {"lock", 0, 0, 'L'},
1434 {"map", 0, 0, 'm'},
1435 {"noload", 0, 0, 'n'},
1436 {"probe", 0, 0, 'p'},
1437 {"poll", 0, 0, 'p'}, /* poll is deprecated, remove in 2.5 */
1438 {"quiet", 0, 0, 'q'},
1439 {"root", 0, 0, 'r'},
1440 {"syslog", 0, 0, 's'},
1441 {"kallsyms", 0, 0, 'S'},
1442 {"verbose", 0, 0, 'v'},
1443 {"version", 0, 0, 'V'},
1444 {"noexport", 0, 0, 'x'},
1445 {"export", 0, 0, 'X'},
1446 {"noksymoops", 0, 0, 'y'},
1447 {"ksymoops", 0, 0, 'Y'},
1448
1449 {"persist", 1, 0, 'e'},
1450 {"name", 1, 0, 'o'},
1451 {"blob", 1, 0, 'O'},
1452 {"prefix", 1, 0, 'P'},
1453 {0, 0, 0, 0}
1454 };
1455 char *m_name = NULL;
1456 char *blob_name = NULL; /* Save object as binary blob */
1457 int m_version;
1458 ElfW(Addr) m_addr;
1459 unsigned long m_size;
1460 int m_crcs;
1461 char m_strversion[STRVERSIONLEN];
1462 char *filename;
1463 char *persist_name = NULL; /* filename to hold any persistent data */
1464 int fp;
1465 struct obj_file *f;
1466 struct obj_section *kallsyms = NULL, *archdata = NULL;
1467 int o;
1468 int noload = 0;
1469 int dolock = 1; /*Note: was: 0; */
1470 int quiet = 0;
1471 int exit_status = 1;
1472 int force_kallsyms = 0;
1473 int persist_parms = 0; /* does module have persistent parms? */
1474 int i;
1475
1476 error_file = "insmod";
1477
1478 /* To handle repeated calls from combined modprobe */
1479 errors = optind = 0;
1480
1481 /* Process the command line. */
1482 while ((o = getopt_long(argc, argv, "fhkLmnpqrsSvVxXyYe:o:O:P:R:",
1483 &long_opts[0], NULL)) != EOF)
1484 switch (o) {
1485 case 'f': /* force loading */
1486 flag_force_load = 1;
1487 break;
1488 case 'h': /* Print the usage message. */
1489 insmod_usage();
1490 break;
1491 case 'k': /* module loaded by kerneld, auto-cleanable */
1492 flag_autoclean = 1;
1493 break;
1494 case 'L': /* protect against recursion. */
1495 dolock = 1;
1496 break;
1497 case 'm': /* generate load map */
1498 flag_load_map = 1;
1499 break;
1500 case 'n': /* don't load, just check */
1501 noload = 1;
1502 break;
1503 case 'p': /* silent probe mode */
1504 flag_silent_probe = 1;
1505 break;
1506 case 'q': /* Don't print unresolved symbols */
1507 quiet = 1;
1508 break;
1509 case 'r': /* allow root to load non-root modules */
1510 root_check_off = !root_check_off;
1511 break;
1512 case 's': /* start syslog */
1513 setsyslog("insmod");
1514 break;
1515 case 'S': /* Force kallsyms */
1516 force_kallsyms = 1;
1517 break;
1518 case 'v': /* verbose output */
1519 flag_verbose = 1;
1520 break;
1521 case 'V':
1522 fputs("insmod version " MODUTILS_VERSION "/n", stderr);
1523 break;
1524 case 'x': /* do not export externs */
1525 flag_export = 0;
1526 break;
1527 case 'X': /* do export externs */
1528 flag_export = 1;
1529 break;
1530 case 'y': /* do not define ksymoops symbols */
1531 flag_ksymoops = 0;
1532 break;
1533 case 'Y': /* do define ksymoops symbols */
1534 flag_ksymoops = 1;
1535 break;
1536
1537 case 'e': /* persistent data filename */
1538 free(persist_name);
1539 persist_name = xstrdup(optarg);
1540 break;
1541 case 'o': /* name the output module */
1542 m_name = optarg;
1543 break;
1544 case 'O': /* save the output module object */
1545 blob_name = optarg;
1546 break;
1547 case 'P': /* use prefix on crc */
1548 set_ncv_prefix(optarg);
1549 break;
1550
1551 default:
1552 insmod_usage();
1553 break;
1554 }
1555
1556 if (optind >= argc) {
1557 insmod_usage();
1558 }
1559 filename = argv[optind++];
1560
以上的代码,声明变量,处理命令行参数。各参数的含义,注释中已有说明,其用途在下面代码中可明了。需要说明的是1548行的set_ncv_prefix(optarg),该函数也在insmod.c中。其用途是让用户设置版本识别前缀。
为了使内核与所使用模块兼容,不至发生错误,linux里使用前、后缀(?)标识不同版本的内核与模块,在加载时内核就可以通过前后缀识别是否是正确版本的模块。
1561 if (config_read(0, NULL, "", NULL) < 0) {
1562 error("Failed handle configuration");
1563 }
modutils工具具有令人恐怖的配置性能,简直与一个小型语言相仿。不过在insmod里,配置文件很多配置项都不起作用,唯一用到就是prune,它在查找模块路径名时被用作过滤项。函数config_read正是解读modutils配置文档的关键。该函数在./modultis-2.4.0/util/config_read.c中。
Insmod——config_read函数
1359 int config_read(int all, char *force_ver, char *base_dir, char *conf_file)
1360 {
1361 int r;
1362 if (modpath != NULL)
1363 return 0; /* already initialized */
1364
1365 if (uname(&uts_info) < 0) {
1367 error("Failed to find kernel name information");
1368 return -1;
1369 }
1370
1371 r = do_read(all, force_ver, base_dir, conf_file, 0);
1372
1373 if (quick && !r && !need_update (force_ver, base_dir))
1374 exit (0);
1375
1376 return r;
1377 }
函数do_read也在同一文件中。
Insmod——do_read函数
475 /*
476 * Read the configuration file.
477 * If parameter "all" == 0 then ignore everything except path info
478 * Return -1 if any error.
479 * Error messages generated.
480 */
481 static int do_read(int all, char *force_ver, char *base_dir, char *conf_file, int depth)
482 {
483 #define MAX_LEVEL 20
484 FILE *fin;
485 GLOB_LIST g;
486 int i;
487 int assgn;
488 int drop_default_paths = 1;
489 int lineno = 0;
490 int ret = 0;
491 int state[MAX_LEVEL + 1]; /* nested "if" */
492 int level = 0;
493 char buf[3000];
494 char tmpline[100];
495 char **pathp;
496 char *envpath;
497 char *version;
498 char *type;
499 char **glb;
500 char old_name[] = "/etc/conf.modules";
501 int conf_file_specified = 0;
502
503 /*
504 * The configuration file is optional.
505 * No error is printed if it is missing.
506 * If it is missing the following content is assumed.
507 *
508 * path[boot]=/lib/modules/boot
509 *
510 * path[toplevel]=/lib/modules/`uname -r`
511 *
512 * path[toplevel]=/lib/modules/`kernelversion`
513 * (where kernelversion gives the major kernel version: "2.0", "2.2"...)
514 *
515 * path[toplevel]=/lib/modules/default
516 *
517 * path[kernel]=/lib/modules/kernel
518 * path[fs]=/lib/modules/fs
519 * path[net]=/lib/modules/net
520 * path[scsi]=/lib/modules/scsi
521 * path[block]=/lib/modules/block
522 * path[cdrom]=/lib/modules/cdrom
523 * path[ipv4]=/lib/modules/ipv4
524 * path[ipv6]=/lib/modules/ipv6
525 * path[sound]=/lib/modules/sound
526 * path[fc4]=/lib/modules/fc4
527 * path[video]=/lib/modules/video
528 * path[misc]=/lib/modules/misc
529 * path[pcmcia]=/lib/modules/pcmcia
530 * path[atm]=/lib/modules/atm
531 * path[usb]=/lib/modules/usb
532 * path[ide]=/lib/modules/ide
533 * path[ieee1394]=/lib/modules/ieee1394
534 * path[mtd]=/lib/modules/mtd
535 *
536 * The idea is that modprobe will look first if the
537 * modules are compiled for the current release of the kernel.
538 * If not found, it will look for modules that fit for the
539 * general kernelversion (2.0, 2.2 and so on).
540 * If still not found, it will look into the default release.
541 * And if still not found, it will look in the other directories.
542 *
543 * The strategy should be like this:
544 * When you install a new linux kernel, the modules should go
545 * into a directory related to the release (version) of the kernel.
546 * Then you can do a symlink "default" to this directory.
547 *
548 * Each time you compile a new kernel, the make modules_install
549 * will create a new directory, but it won't change thee default.
550 *
551 * When you get a module unrelated to the kernel distribution
552 * you can place it in one of the last three directory types.
553 *
554 * This is the default strategy. Of course you can overide
555 * this in /etc/modules.conf.
556 *
557 * 2.3.15 added a new file tree walk algorithm which made it possible to
558 * point at a top level directory and get the same behaviour as earlier
559 * versions of modutils. 2.3.16 takes this one stage further, it
560 * removes all the individual directory names from most of the scans,
561 * only pointing at the top level directory. The only exception is the
562 * last ditch scan, scanning all of /lib/modules would be a bad idea(TM)
563 * so the last ditch scan still runs individual directory names under
564 * /lib/modules.
565 *
567 * Additional syntax:
568 *
569 * [add] above module module1 ...
570 * Specify additional modules to pull in on top of a module
571 *
572 * [add] below module module1 ...
573 * Specify additional modules needed to be able to load a module
574 *
575 * [add] prune filename ...
576 *
577 * [add] probe name module1 ...
578 * When "name" is requested, modprobe tries to install each
579 * module in the list until it succeeds.
580 *
581 * [add] probeall name module1 ...
582 * When "name" is requested, modprobe tries to install all
583 * modules in the list.
584 * If any module is installed, the command has succeeded.
585 *
586 * [add] options module option_list
587 *
588 * For all of the above, the optional "add" prefix is used to
589 * add to a list instead of replacing the contents.
590 *
591 * include FILE_TO_INCLUDE
592 * This does what you expect. No limitation on include levels.
593 *
594 * persistdir=persist_directory
595 * Name the directory to save persistent data from modules.
596 *
597 * In the following WORD is a sequence if non-white characters.
598 * If ' " or ` is found in the string, all characters up to the
599 * matching ' " or ` will also be included, even whitespace.
600 * Every WORD will then be expanded w.r.t. meta-characters.
601 * If the expanded result gives more than one word, then only
602 * the first word of the result will be used.
603 *
604 *
605 * define CODE WORD
606 * Do a putenv("CODE=WORD")
607 *
608 * EXPRESSION below can be:
609 * WORD compare_op WORD
610 * where compare_op is one of == != < <= >= >
611 * The string values of the WORDs are compared
612 * or
613 * -n WORD compare_op WORD
614 * where compare_op is one of == != < <= >= >
615 * The numeric values of the WORDs are compared
616 * or
617 * WORD
618 * if the expansion of WORD fails, or if the
619 * expansion is "0" (zero), "false" or "" (empty)
620 * then the expansion has the value FALSE.
621 * Otherwise the expansion has the value TRUE
622 * or
623 * -f FILENAME
624 * Test if the file FILENAME exists
625 * or
626 * -k
627 * Test if "autoclean" (i.e. called from the kernel)
628 * or
629 * ! EXPRESSION
630 * A negated expression is also an expression
631 *
632 * if EXPRESSION
633 * any config line
634 * ...
635 * elseif EXPRESSION
636 * any config line
637 * ...
638 * else
639 * any config line
640 * ...
641 * endif
642 *
643 * The else and elseif keywords are optional.
644 * "if"-statements nest up to 20 levels.
645 */
请仔细阅读上面的注释,modutils的配置文档功能很强大,是吧?!如果不是很明白,不要紧,往下看就明白了。
646 state[0] = 1;
647
648 if (force_ver)
649 version = force_ver;
650 else
651 version = uts_info.release;
652
653 config_version = xstrdup(version);
这里force_ver为null,uts_info已经在config_read中设置好了,见config_read,1365行。以上,获取合适的version信息,并保存在config_version中。
655 /* Only read the default entries on the first file */
656 if (depth == 0) {
657 maxpath = 100;
658 modpath = (struct PATH_TYPE*)xmalloc(maxpath*sizeof(struct PATH_TYPE));
659 nmodpath = 0;
660
661 maxexecs = 10;
662 execs = (struct EXEC_TYPE*)xmalloc(maxexecs*sizeof(struct EXEC_TYPE));
663 nexecs = 0;
664
665 /*
666 * Build predef options
667 */
668 if (all && optlist[0])
669 n_opt_list = build_list(optlist, &opt_list, version, 1);
670
671 /*
672 * Build predef above
673 */
674 if (all && above[0])
675 n_abovelist = build_list(above, &abovelist, version, 0);
676
677 /*
678 * Build predef below
679 */
680 if (all && below[0])
681 n_belowlist = build_list(below, &belowlist, version, 0);
682
683 /*
684 * Build predef prune list
685 */
686 if (prune[0])
687 n_prunelist = build_list(prune, &prunelist, version, 0);
688
689 /*
690 * Build predef aliases
691 */
692 if (all && aliaslist[0])
693 n_aliases = build_list(aliaslist, &aliases, version, 0);
参数oplist,above,below,prune,aliaslist都在./modutils/util/alias.h中,为一些预定义规则。在insmod里除了aliaslist,其他都是“空的”。
函数build_list也在同一文件。用于建立上述预定义规则的链表。
Insmod——build_list函数
380 static int build_list(char **in, OPT_LIST **out, char *version, int opts)
381 {
382 GLOB_LIST *pg;
383 int i;
384
385 for (i = 0; in[i]; ++i) {
386 char *p = xstrdup(in[i]);
387 char *pt = next_word(p);
388 char *pn = p;
389
390 *out = (OPT_LIST *)xrealloc(*out, (i + 2) * sizeof(OPT_LIST));
391 (*out)[i].autoclean = 1;
392 if (opts && !strcmp (p, "-k")) {
393 pn = pt;
394 pt = next_word(pn);
395 (*out)[i].autoclean = 0;
396 }
397 pg = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST));
398 meta_expand(pt, pg, NULL, version, ME_ALL);
399 (*out)[i].name = xstrdup(pn);
400 (*out)[i].opts = pg;
401 free(p);
402 }
403 memset(&(*out)[i], 0, sizeof(OPT_LIST));
404
405 return i;
406 }
这段代码相当简单,输入的参数按name value|-k name value这样的样式给出,经过解析保存在out表里。如果指定-k,就可以将一个模块的autoclean置为0。这个标志将被设置入module里,使module可以自动卸载。另外,在预定义参数中可以使用shell中的元字符(meta character),如:$,*,并按Shell里的含义来解释。SHELL_META定义了这些元字符,在./modutils-2.4.0/include/util.h。
Insmod——SHELL_META宏
31 #define SHELL_META "&();|<>$`/"'//!{}[]~=+:?*" /* Sum of bj0rn and Debian */
OPT_LIST的定义在./modutils-2.4.0/include/config.h中:
Insmod——OPT_LIST结构
51 typedef struct {
52 char *name;
53 GLOB_LIST *opts;
54 int autoclean;
55 } OPT_LIST;
接下来,设置模块的查找目录。
696 /* Order and priority is now: (MODPATH + modules.conf) || (predefs + modules.conf) */
697 if ((envpath = getenv("MODPATH")) != NULL && !safemode) {
698 size_t len;
699 char *p;
700 char *path;
701
702 /* Make a copy so's we can mung it with strtok. */
703 len = strlen(envpath) + 1;
704 p = alloca(len);
705 memcpy(p, envpath, len);
706 path = alloca(PATH_MAX);
707
708 for (p = strtok(p, ":"); p != NULL; p = strtok(NULL, ":")) {
709 len = snprintf(path, PATH_MAX, p, version);
710 modpath[nmodpath].path = xstrdup(path);
711 if ((type = strrchr(path, '/')) != NULL)
712 type += 1;
713 else
714 type = "misc";
715 modpath[nmodpath].type = xstrdup(type);
716 if (++nmodpath >= maxpath) {
717 maxpath += 100;
718 modpath = (struct PATH_TYPE *)xrealloc(modpath,
719 maxpath * sizeof(struct PATH_TYPE));
720 }
721
722 }
723 } else {
724 /*
725 * Build the default "path[type]" configuration
726 */
727 int n;
728 char *k;
729
730 /* The first entry in the path list */
731 modpath[nmodpath].type = xstrdup("boot");
732 snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/boot", base_dir);
733 modpath[nmodpath].path = xstrdup(tmpline);
734 ++nmodpath;
735 /* The second entry in the path list, `uname -r` */
736 modpath[nmodpath].type = xstrdup("toplevel");
737 snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%s", base_dir, version);
738 modpath[nmodpath].path = xstrdup(tmpline);
739 ++nmodpath;
740
741 /* The third entry in the path list, `kernelversion` */
742 modpath[nmodpath].type = xstrdup("toplevel");
743 for (n = 0, k = version; *k; ++k) {
744 if (*k == '.' && ++n == 2)
745 break;
746 }
747 snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%.*s", base_dir,
748 (/* typecast for Alpha */ int)(k - version), version);
749 modpath[nmodpath].path = xstrdup(tmpline);
750 ++nmodpath;
751
752 /* The rest of the entries in the path list */
753 for (pathp = tbpath; *pathp; ++pathp) {
754 char **type;
755
756 for (type = tbtype; *type; ++type) {
757 char path[PATH_MAX];
758
759 snprintf(path, sizeof(path), "%s%s/%s", base_dir, *pathp, *type);
760 if (meta_expand(path, &g, NULL, version, ME_ALL))
761 return -1;
762
763 for (glb = g.pathv; glb && *glb; ++glb) {
764 modpath[nmodpath].type = xstrdup(*type);
765 modpath[nmodpath].path = *glb;
766 if (++nmodpath >= maxpath) {
767 maxpath += 100;
768 modpath = (struct PATH_TYPE *)xrealloc(modpath,
769 maxpath * sizeof(struct PATH_TYPE));
770 }
771 }
772 }
773 }
774 }
注意safemode在config.c中定位为全局变量,insmod不对它赋任何值,因此在这里其值为0。所以,如果modpath这个环境变量被设置,将使用这个值构造module的各个路径,否则就使用默认路径,具体可以看函数开头的注释。从代码中可以看到在环境变量中的路径通过“:”分割,对于不以“/”开头的路径,程序一概归入“misc”类路径。如果使用默认路径,insmod将传入null给base_dir。因此,构成如函数头部所注明的默认路径。
776 /* Environment overrides for testing only, undocumented */
777 for (i = 0; i < gen_file_count; ++i)
778 gen_file_env(gen_file+i);
779
780 } /* End of depth == 0 */
这里使用了gen_file数组,这个数组的定义在同一个文件里。
Insmod——gen_file数组
112 /* The initialization order must match the gen_file_enum order in config.h */
113 struct gen_files gen_file[] = {
114 {"generic_string", NULL, 0},
115 {"pcimap", NULL, 0},
116 {"isapnpmap", NULL, 0},
117 {"usbmap", NULL, 0},
118 {"parportmap", NULL, 0},
119 {"dep", NULL, 0},
120 };
gen_files结构定义在./modutils-2.4.0/include/config.h中,
Insmod——gen_files结构
79 /* Information about generated files */
80 struct gen_files {
81 char *base; /* xxx in /lib/modules/`uname -r`/modules.xxx */
82 char *name; /* name actually used */
83 time_t mtime;
84 };
函数gen_file_env也在./modutils-2.4.0/util/config.c。
Insmod——gen_file_env函数
408 /* Environment variables can override defaults, testing only */
409 static void gen_file_env(struct gen_files *gf)
410 {
411 if (!safemode) {
412 char *e = xmalloc(strlen(gf->base)+5), *p1 = gf->base, *p2 = e;
413 while ((*p2++ = toupper(*p1++))) ;
414 strcpy(p2-1, "PATH"); /* safe, xmalloc */
415 if ((p2 = getenv(e)) != NULL) {
416 free(gf->name);
417 gf->name = xstrdup(p2);
418 }
419 free(e);
420 }
421 }
这个函数的作用显而易见,将gen_files的base字符串转换为大写,并在结尾加上“PATH”,如果存在同名的环境变量,则将其值赋予gen_files的name。从字面上,这些gen_files应该是些公用文档和位图。
782 if (conf_file ||
783 ((conf_file = getenv("MODULECONFIG")) != NULL && *conf_file && !safemode)) {
784 if (!(fin = fopen(conf_file, "r"))) {
785 error("Can't open %s", conf_file);
786 return -1;
787 }
788 conf_file_specified = 1;
789 } else {
790 if (!(fin = fopen((conf_file = ETC_MODULES_CONF), "r"))) {
791 /* Fall back to non-standard name */
792 if ((fin = fopen((conf_file = old_name), "r"))) {
793 fprintf(stderr,
794 "Warning: modutils is reading from %s because/n"
795 " %s does not exist. The use of %s is/n"
796 " deprecated, please rename %s to %s/n"
797 " as soon as possible. Command/n"
798 " mv %s %s/n",
799 old_name, ETC_MODULES_CONF,
800 old_name, old_name, ETC_MODULES_CONF,
801 old_name, ETC_MODULES_CONF);
802 }
803 /* So what... use the default configuration */
804 }
805 }
如果在调用config_read时,传入了一个conf_file指针,或者设置了MODULECONFIG环境变量,那么在这里将打开、读入conf_file指定的文件(就是所谓的配置文件)。否则打开、读入ETC_MODULES_CONF所指定文件。ETC_MODULES_CONF在./modutils-2.4.0/include/config.h中定义为:
Insmod——ETC_MODULES_CONF宏
31 #define ETC_MODULES_CONF "/etc/modules.conf"
如果"/etc/modules.conf"打不开,则尝试old_name指定的文件。old_name在前面500行的地方被定义为"/etc/conf.modules"。估计这是以前linux使用的配置文档路径。
807 if (fin) {
808 struct stat statbuf1, statbuf2;
809 if (fstat(fileno(fin), &statbuf1) == 0)
810 config_mtime = statbuf1.st_mtime;
811 config_file = xstrdup(conf_file); /* Save name actually used */
812 if (!conf_file_specified &&
813 stat(ETC_MODULES_CONF, &statbuf1) == 0 &&
814 stat(old_name, &statbuf2) == 0) {
815 /* Both /etc files exist */
816 if (statbuf1.st_dev == statbuf2.st_dev &&
817 statbuf1.st_ino == statbuf2.st_ino) {
818 if (lstat(ETC_MODULES_CONF, &statbuf1) == 0 &&
819 S_ISLNK(statbuf1.st_mode))
820 fprintf(stderr,
821 "Warning: You do not need a link from %s to/n"
822 " %s. The use of %s is deprecated,/n"
823 " please remove %s and rename %s/n"
824 " to %s as soon as possible. Commands./n"
825 " rm %s/n"
826 " mv %s %s/n",
827 ETC_MODULES_CONF, old_name,
828 old_name, ETC_MODULES_CONF, old_name, ETC_MODULES_CONF,
829 ETC_MODULES_CONF,
830 old_name, ETC_MODULES_CONF);
831 else {
832 #ifndef NO_WARN_ON_OLD_LINK
833 fprintf(stderr,
834 "Warning: You do not need a link from %s to/n"
835 " %s. The use of %s is deprecated,/n"
836 " please remove %s as soon as possible. Command/n"
837 " rm %s/n",
838 old_name, ETC_MODULES_CONF,
839 old_name, old_name,
840 old_name);
841 #endif
842 }
843 }
844 else
845 fprintf(stderr,
846 "Warning: modutils is reading from %s and/n"
847 " ignoring %s. The use of %s is deprecated,/n"
848 " please remove %s as soon as possible. Command/n"
849 " rm %s/n",
850 ETC_MODULES_CONF, old_name,
851 old_name, old_name,
852 old_name);
853 }
854 }
接下来测试"/etc/modules.conf"和"/etc/conf.modules"是否同时存在,或者其中是另一个的符号链接,是的话给出警告。
856 /*
857 * Finally, decode the file
858 */
859 while (fin && fgets_strip(buf, sizeof(buf) - 1, fin, &lineno) != NULL) {
860 char *arg2;
861 char *parm = buf;
862 char *arg;
863 int one_err = 0;
864 int adding;
865
866 while (isspace(*parm))
867 parm++;
868
869 if (strncmp(parm, "add", 3) == 0) {
870 adding = 1;
871 parm += 3;
872 while (isspace(*parm))
873 parm++;
874 } else
875 adding = 0;
876
877 arg = parm;
878
879 if (*parm == '/0')
880 continue;
881
882 one_err = 1;
883
884 while (*arg > ' ' && *arg != '=')
885 arg++;
886
887 if (*arg == '=')
888 assgn = 1;
889 else
890 assgn = 0;
891 *arg++ = '/0';
892 while (isspace(*arg))
893 arg++;
函数fgets_strip在同一文件里,作用是提取文件每一行。
Insmod——fgets_strip函数
215 /*
216 * Read a line of a configuration file and process continuation lines.
217 * Return buf, or NULL if EOF.
218 * Blank at the end of line are always stripped.
219 * Everything on a line following comchar is a comment.
220 *
221 * Continuation character is /
222 * Comment character is #
223 */
224 char *fgets_strip(char *buf, int sizebuf, FILE * fin, int *lineno)
225 {
226 int nocomment = 1; /* No comments found ? */
227 int contline = 0;
228 char *start = buf;
229 char *ret = NULL;
230 char comchar = '#';
231 char contchar = '//';
232
233 *buf = '/0';
234
235 while (fgets(buf, sizebuf, fin) != NULL) {
236 char *end = strip_end(buf);
237 char *pt = strchr(buf, comchar);
238
239 if (pt != NULL) {
240 nocomment = 0;
241 *pt = '/0';
242 end = strip_end(buf);
243 }
244
245 if (lineno != NULL)
246 (*lineno)++;
247 ret = start;
248 if (contline) {
249 char *pt = buf;
250
251 while (isspace(*pt))
252 pt++;
253 if (pt > buf + 1) {
254 strcpy(buf + 1, pt); /* safe, backward copy */
255 buf[0] = ' ';
256 end -= (int) (pt - buf) - 1;
257 } else if (pt == buf + 1) {
258 buf[0] = ' ';
259 }
260 }
261 if (end > buf && *(end - 1) == contchar) {
262 if (end == buf + 1 || *(end - 2) != contchar) {
263 /* Continuation */
264 contline = 1;
265 end--;
266 *end = '/0';
267 buf = end;
268 } else {
269 *(end - 1) = '/0';
270 break;
271 }
272 } else {
273 break;
274 }
275 }
276
277 return ret;
278 }
236行的函数strip_end也在config.c中,作用是除去行末尾的空白字符。
Insmod——strip_end函数
202 /*
203 * Strip white char at the end of a string.
204 * Return the address of the last non white char + 1 (point on the '/0').
205 */
206 static char *strip_end(char *str)
207 {
208 int len = strlen(str);
209
210 for (str += len - 1; len > 0 && (isspace(*str)); --len, --str)
211 *str = '/0';
212 return str + 1;
213 }
237~243行用于去掉以#开头的注释。261行检测行最后一个有效字符是否为连句符‘/’,如果行不为空,见end>buf这个判断,而且最后字符不是连句符,则通过273行的break退出循环。否则进入262行的if语句,如果该行只有一个‘/’字符,或者‘/’前面没有紧接的‘/’字符,则认为连句。而‘//’将按转义处理。在连句情况下回到235行的while继续读取文件中的下一句。然后进入248行的if块。248~260行的处理很简单,将下一句的有效字符拷贝到上一行的末尾,拼成一行。
回到do_read函数。869~873行判断是否为添加属性(参见函数开头的注释)。行877~893分割出parm,并将arg定位到下一个参数起始。