Modultils工具源码分析之insmod篇 (2)

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_vernulluts_info已经在config_read中设置好了,见config_read1365行。以上,获取合适的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);

 

参数oplistabovebelowprunealiaslist都在./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              }

 

注意safemodeconfig.c中定位为全局变量,insmod不对它赋任何值,因此在这里其值为0。所以,如果modpath这个环境变量被设置,将使用这个值构造module的各个路径,否则就使用默认路径,具体可以看函数开头的注释。从代码中可以看到在环境变量中的路径通过“:”分割,对于不以“/”开头的路径,程序一概归入“misc”类路径。如果使用默认路径,insmod将传入nullbase_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_filesbase字符串转换为大写,并在结尾加上“PATH”,如果存在同名的环境变量,则将其值赋予gen_filesname。从字面上,这些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定位到下一个参数起始。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值