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

./modutils-2.4.0/depmod/目录下有一个配置文件的样式,Example.module.conf

 

1     # This is an example of additional definitions you can put in /etc/modules.conf

2     # Note that modprobe has some default aliases built in ("modprobe -c").

3     # The built-in aliases will be overridden by any definitions in this file.

4

5     keep # keep the default set of paths and _add_ the following path(s)

6     path[net]=/lib/modules/`uname -r`/some_special_directory

7

8     alias scsi_hostadapter aha1542

9     alias eth0 3c509

10    alias eth1 de620

11    options de620 irq=7 bnc=1

12    # override:

13    alias char-major-14 sound

14

15    # Conditional decoding via: if, else, elseif, endif

16    #

17    # Avoid having "path" definitions in conditional parts,

18    # unless you are _sure_ that the modules.dep file generated

19    # by depmod is always correct whenever modprobe executes.

20    #

21    # version dependence:

22    if `kernelversion` > 2.0

23           alias char-major-14 sb

24    endif

25

26    # Include another config file: include FILE

27    # in this case some additional aliases

28    if -f /etc/devfs.aliases

29           include /etc/devfs.aliases

30    endif

31

32    # Additional dependencies, "pull in"

33    above sb adlib_card

34

35                 # Set parameters (also in the environment): define PARAM VALUE

 

下面以这个文档为例子,分析配置文件的解析过程。

 

895  /*

896  * endif

897  */

898  if (!assgn && strcmp(parm, "endif") == 0) {

899         if (level > 0)

900                --level;

901         else {

902                error("unmatched endif in line %d", lineno);

903                return -1;

904         }

905         continue;

906  }

 

907  /*

908  * else

909  */

910  if (!assgn && strcmp(parm, "else") == 0) {

911         if (level <= 0) {

912                error("else without if in line %d", lineno);

913                return -1;

914         }

915         state[level] = !state[level];

916         continue;

917  }

918

919  /*

920  * elseif

921  */

922  if (!assgn && strcmp(parm, "elseif") == 0) {

923         if (level <= 0) {

924                error("elseif without if in line %d", lineno);

925                return -1;

926         }

927         if (state[level] != 0) {

928                /*

929                * We have already found a TRUE

930                * if statement in this "chain".

931                * That's what "2" means.

932                */

933                state[level] = 2;

934                continue;

935         }

936         /* else: No TRUE if has been found, cheat */

937         /*

938         * The "if" handling increments level,

939         * but this is the _same_ level as before.

940         * So, compensate for it.

941         */

942         --level;

943         parm = "if";

944         /* Fallthru to "if" */

945  }

946

947  /*

948  * if

949  */

950  if (strcmp(parm, "if") == 0) {

951         char *cmp;

952         int not = 0;

953         int numeric = 0;

954

955         if (level >= MAX_LEVEL) {

956                error("Too many nested if's in line %d/n", lineno);

957                return -1;

958         }

959         state[++level] = 0; /* default false */

960

961         if (*arg == '!') {

962                not = 1;

963                arg = next_word(arg);

964         }

965

966         if (strncmp(arg, "-k", 2) == 0) {

967                state[level] = flag_autoclean;

968                continue;

969         }

970

971         if (strncmp(arg, "-f", 2) == 0) {

972                char *file = next_word(arg);

973                meta_expand(file, &g, NULL, version, ME_ALL);

974                if (access(g.pathc ? g.pathv[0] : file, R_OK) == 0)

975                       state[level] = !not;

976                else

977                       state[level] = not;

978                continue;

979         }

980

981         if (strncmp(arg, "-n", 2) == 0) {

982                numeric = 1;

983                arg = next_word(arg);

984         }

985

986

987         cmp = next_word(arg);

988         if (*cmp) {

989                GLOB_LIST g2;

990                long n1 = 0;

991                long n2 = 0;

992                char *w1 = "";

993                char *w2 = "";

994

995                arg2 = next_word(cmp);

996

997                meta_expand(arg, &g, NULL, version, ME_ALL);

998                if (g.pathc && g.pathv[0])

999                       w1 = g.pathv[0];

1000

1001                     meta_expand(arg2, &g2, NULL, version, ME_ALL);

1002                     if (g2.pathc && g2.pathv[0])

1003                            w2 = g2.pathv[0];

1004

1005                     if (numeric) {

1006                            n1 = strtol(w1, NULL, 0);

1007                            n2 = strtol(w2, NULL, 0);

1008                     }

1009

1010                     if (strcmp(cmp, "==") == 0 ||

1011                         strcmp(cmp, "=") == 0) {

1012                            if (numeric)

1013                                state[level] = (n1 == n2);

1014                            else

1015                                state[level] = strcmp(w1, w2) == 0;

1016                     } else if (strcmp(cmp, "!=") == 0) {

1017                            if (numeric)

1018                                state[level] = (n1 != n2);

1019                            else

1020                                state[level] = strcmp(w1, w2) != 0;

1021                     } else if (strcmp(cmp, ">=") == 0) {

1022                            if (numeric)

1023                                state[level] = (n1 >= n2);

1024                            else

1025                                state[level] = strcmp(w1, w2) >= 0;

1026                     } else if (strcmp(cmp, "<=") == 0) {

1027                            if (numeric)

1028                                state[level] = (n1 <= n2);

1029                            else

1030                                state[level] = strcmp(w1, w2) <= 0;

1031                     } else if (strcmp(cmp, ">") == 0) {

1032                            if (numeric)

1033                                state[level] = (n1 > n2);

1034                            else

1035                                state[level] = strcmp(w1, w2) > 0;

1036                     } else if (strcmp(cmp, "<") == 0) {

1037                            if (numeric)

1038                                state[level] = (n1 < n2);

1039                            else

1040                                state[level] = strcmp(w1, w2) < 0;

1041                     }

1042              } else { /* Check defined value, if any */

1043                     /* undef or defined as

1044                     *    "" or "0" or "false" => false

1045                     *  defined => true

1046                     */

1047                     if (!meta_expand(arg, &g, NULL, version, ME_ALL) &&

1048                         g.pathc > 0 &&

1049                         strcmp(g.pathv[0], "0") != 0 &&

1050                         strcmp(g.pathv[0], "false") != 0 &&

1051                         strlen(g.pathv[0]) != 0)

1052                            state[level] = 1; /* true */

1053              }

1054              if (not)

1055                     state[level] = !state[level];

1056

1057              continue;

1058       }

1059

1060       /*

1061       * Should we bother?

1062       */

1063       if (state[level] != 1)

1064              continue;

1065

1066       /*

1067       * define

1068       */

1069       if (!assgn && strcmp(parm, "define") == 0) {

1070              char env[PATH_MAX];

1071

1072              arg2 = next_word(arg);

1073              meta_expand(arg2, &g, NULL, version, ME_ALL);

1074              snprintf(env, sizeof(env), "%s=%s", arg, (g.pathc ? g.pathv[0] : ""));

1075              putenv(env);

1076              one_err = 0;

1077       }

1078

1079       /*

1080       * include

1081       */

1082       if (!assgn && strcmp(parm, "include") == 0) {

1083              meta_expand(arg, &g, NULL, version, ME_ALL);

1084

1085              if (!do_read(all, version, base_dir, g.pathc ? g.pathv[0] : arg, depth+1))

1086                     one_err = 0;

1087              else

1088                     error("include %s failed/n", arg);

1089       }

1090

1091       /*

1092       * above

1093       */

1094       else if (all && !assgn && strcmp(parm, "above") == 0) {

1095              decode_list(&n_abovelist, &abovelist, arg, adding, version, 0);

1096              one_err = 0;

1097       }

1098

1099       /*

1100       * below

1101       */

1102       else if (all && !assgn && strcmp(parm, "below") == 0) {

1103              decode_list(&n_belowlist, &belowlist, arg, adding, version, 0);

1104              one_err = 0;

1105       }

1106

1107       /*

1108       * prune

1109       */

1110       else if (all && !assgn && strcmp(parm, "prune") == 0) {

1111              decode_list(&n_prunelist, &prunelist, arg, adding, version, 0);

1112              one_err = 0;

1113       }

1114

1115       /*

1116       * probe

1117       */

1118       else if (all && !assgn && strcmp(parm, "probe") == 0) {

1119              decode_list(&n_probe_list, &probe_list, arg, adding, version, 0);

1120              one_err = 0;

1121       }

1122

1123       /*

1124       * probeall

1125       */

1126       else if (all && !assgn && strcmp(parm, "probeall") == 0) {

1127              decode_list(&n_probeall_list, &probeall_list, arg, adding, version, 0);

1128              one_err = 0;

1129       }

1130

1131       /*

1132       * options

1133       */

1134       else if (all && !assgn && strcmp(parm, "options") == 0) {

1135              decode_list(&n_opt_list, &opt_list, arg, adding, version, 1);

1136              one_err = 0;

1137       }

1138

1139       /*

1140       * alias

1141       */

1142       else if (all && !assgn && strcmp(parm, "alias") == 0) {

1143              /*

1144              * Replace any previous (default) definitions

1145              * for the same module

1146              */

1147              decode_list(&n_aliases, &aliases, arg, 0, version, 0);

1148              one_err = 0;

1149       }

1150

1151       /*

1152       * Specification: /etc/modules.conf

1153       * The format of the commands in /etc/modules.conf are:

1154       *

1155       *    pre-install module command

1156       *    install module command

1157       *    post-install module command

1158       *    pre-remove module command

1159       *    remove module command

1160       *    post-remove module command

1161       *

1162       * The different words are separated by tabs or spaces.

1163       */

1164       /*

1165       * pre-install

1166       */

1167       else if (all && !assgn && (strcmp(parm, "pre-install") == 0)) {

1168              decode_exec(arg, EXEC_PRE_INSTALL);

1169              one_err = 0;

1170       }

1171

1172       /*

1173       * install

1174       */

1175       else if (all && !assgn && (strcmp(parm, "install") == 0)) {

1176              decode_exec(arg, EXEC_INSTALL);

1177              one_err = 0;

1178       }

1179

1180       /*

1181       * post-install

1182       */

1183       else if (all && !assgn && (strcmp(parm, "post-install") == 0)) {

1184              decode_exec(arg, EXEC_POST_INSTALL);

1185              one_err = 0;

1186       }

1187

1188       /*

1189       * pre-remove

1190       */

1191       else if (all && !assgn && (strcmp(parm, "pre-remove") == 0)) {

1192              decode_exec(arg, EXEC_PRE_REMOVE);

1193              one_err = 0;

1194       }

1195

1196       /*

1197       * remove

1198       */

1199       else if (all && !assgn && (strcmp(parm, "remove") == 0)) {

1200              decode_exec(arg, EXEC_REMOVE);

1201              one_err = 0;

1202       }

1203

1204       /*

1205       * post-remove

1206       */

1207       else if (all && !assgn && (strcmp(parm, "post-remove") == 0)) {

1208              decode_exec(arg, EXEC_POST_REMOVE);

1209              one_err = 0;

1210       }

1211

1212       /*

1213       * insmod_opt=

1214       */

1215       else if (assgn && (strcmp(parm, "insmod_opt") == 0)) {

1216              insmod_opt = xstrdup(arg);

1217              one_err = 0;

1218       }

1219

1220       /*

1221       * keep

1222       */

1223       else if (!assgn && (strcmp(parm, "keep") == 0)) {

1224              drop_default_paths = 0;

1225              one_err = 0;

1226       }

1227

1228       /*

1229       * path...=

1230       */

1231       else if (assgn && strncmp(parm, "path", 4) == 0) {

1232              /*

1233              * Specification: config file / path parameter

1234              * The path parameter specifies a directory to

1235              * search for modules.

1236              * This parameter may be repeated multiple times.

1237              *

1238              * Note that the actual path may be defined using

1239              * wildcards and other shell meta-chars, such as "*?`".

1240              * For example:

1241              *      path[misc]=/lib/modules/1.1.5?/misc

1242              *

1243              * Optionally the path keyword carries a tag.

1244              * This tells us a little more about the purpose of

1245              * this directory and allows some automated operations.

1246              * A path is marked with a tag by adding the tag,

1247              * enclosed in square brackets, to the path keyword:

1248              * #

1249              * path[boot]=/lib/modules/boot

1250              * #

1251              * This case identifies the path a of directory

1252              * holding modules loadable a boot time.

1253              */

1254

1255              if (drop_default_paths) {

1256                     int n;

1257

1258                     /*

1259                     * Specification: config file / path / default

1260                     *

1261                     * Whenever there is a path[] specification

1262                     * in the config file, all the default

1263                     * path are reset.

1264                     *

1265                     * If one instead wants to _add_ to the default

1266                     * set of paths, one has to have the option

1267                     *    keep

1268                     * before the first path[]-specification line

1269                     * in the configuration file.

1270                     */

1271                     drop_default_paths = 0;

1272                     for (n = 0; n < nmodpath; n++) {

1273                            free(modpath[n].path);

1274                            free(modpath[n].type);

1275                     }

1276                     nmodpath = 0;

1277              }

1278

1279              /*

1280              * Get (the optional) tag

1281              * If the tag is missing, the word "misc"

1282              * is assumed.

1283              */

1284              type = "misc";

1285

1286              if (parm[4] == '['] {

1287                     char *pt_type = parm + 5;

1288                            while (*pt_type != '/0' && *pt_type != ')')

1289                            pt_type++;

1290

1291                     if (*pt_type == ')' && pt_type[1] == '/0') {

1292                            *pt_type = '/0';

1293                            type = parm + 5;

1294                     } /* else CHECKME */

1295              }

1296

1297              /*

1298              * Handle the actual path description

1299              */

1300              if (meta_expand(arg, &g, base_dir, version, ME_ALL))

1301                     return -1;

1302              for (glb = g.pathv; glb && *glb; ++glb) {

1303                     modpath[nmodpath].type = xstrdup(type);

1304                     modpath[nmodpath].path = *glb;

1305                     if (++nmodpath >= maxpath) {

1306                            maxpath += 100;

1307                            modpath = (struct PATH_TYPE *)xrealloc(modpath,

1308                                   maxpath * sizeof(struct PATH_TYPE));

1309                     }

1310              }

1311              one_err = 0;

1312       }

1313

1314       /*

1315       * persistdir

1316       */

1317       else if (assgn && strcmp(parm, "persistdir") == 0) {

1318              meta_expand(arg, &g, NULL, version, ME_ALL);

1319              persistdir = xstrdup(g.pathc ? g.pathv[0] : arg);

1320              one_err = 0;

1321       }

1322

1323       /* Names for generated files in config file */

1324       for (i = 0; one_err && i < gen_file_count; ++i)

1325              one_err = gen_file_conf(gen_file+i, assgn, parm, arg);

1326

1327       /*

1328       * any errors so far?

1329       */

1330       if (all == 0)

1331              one_err = 0;

1332       else if (one_err) {

1333              error("Invalid line %d in %s/n/t%s",

1334                          lineno, conf_file, buf);

1335              ret = -1;

1336       }

1337}

 

首先看Example.module.conf的第5行。经过866~893行的处理,parm=”keep”arg=0。然后进入1223行的else if块,将drop_default_pathsone_error置为0。至此,对第5行的处理结束。

读取第6行,经过866~893行后,parm=”path[net]”arg=”/lib/modules/`uname -r`/ some_special_directoryassign=1。注意,在path[net]=之间不能有空格,否则通不过884行的if语句。然后进入1231行的else if块。首先注意1232~1253行的注释,注释中提到path可以使用[…]这样的标识,以方便自动处理程序,在这里tagnet。另外,在路径中可以使用Shell里的元符号,真是功能强大啊。在1259~1269行的注释中说明,如果在所有的path命令前声明keep,默认的path配置都将保留,否则将覆盖,这里声明了keep。因此跳过了1255~1277行。

1286~1296行提取path的标识。

1301行,meta_expand函数对arg指向的路径进行元符号转换处理,函数的第2个参数g,是一个GLOB_LIST结构,该结构定义于./modutils-2.4.0/include/util.h

Insmod——GLOB_LIST结构

65    /*

66    * Generic globlist <bj0rn@blox.se>

67    */

68    typedef struct {

69           int pathc;       /* Count of paths matched so far  */

70           char **pathv;    /* List of matched pathnames.  */

71             } GLOB_LIST;

 

函数meta_expand的定义在./modutils-2.4.0/util/meta_expand.c中。

Insmod——meta_expand函数

152  /*

153  * Expand the string (including meta-character) to a list of matches

154  *

155  * Return 0 if OK else -1

156  */

157  int meta_expand(char *pt, GLOB_LIST *g, char *base_dir, char *version, int type)

158  {

159         FILE *fin;

160         int len = 0;

161         char *line = NULL;

162         char *p, *p1;

163         char tmpline[PATH_MAX + 1];

164         char wrk[sizeof(tmpline)];

165         char tmpcmd[2*sizeof(tmpline)+20];    /* room for /bin/echo "text" */

166

167         g->pathc = 0;

168         g->pathv = NULL;

169

170         /*

171         * Take care of version dependent expansions

172         * Needed for forced version handling

173         */

174         if ((p = strchr(pt, '`')) != NULL && (type & ME_BUILTIN_COMMAND)) {

175                do {

176                       char *s;

177

178                       for (s = p + 1; isspace(*s); ++s)

179                              ;

180

181                       if (strncmp(s, "uname -r", 8) == 0) {

182                              while (*s && (*s != '`'))

183                                     ++s;

184                              if (*s == '`') {

185                                     *p = '/0';

186                                     snprintf(wrk, sizeof(wrk), "%s%s%s",

187                                                 pt,

188                                                 version,

189                                                 s + 1);

190                                     *p = '`';

191                              }

192                              strcpy(tmpline, wrk);     /* safe, same size */

193                              pt = tmpline;

194                       } else if (strncmp(s, "kernelversion", 13) == 0) {

195                              while (*s && (*s != '`'))

196                                     ++s;

197                              if (*s == '`') {

198                                     int n;

199                                     char *k;

200

201                                     *p = '/0';

202                                     for (n = 0, k = version; *k; ++k) {

203                                     if (*k == '.' && ++n == 2)

204                                                   break;

205                                     }

206                                     snprintf(wrk, sizeof(wrk), "%s%.*s%s",

207                                                 pt,

208                                                 /* typecast for Alpha */

209                                                 (int)(k - version),

210                                                 version,

211                                                 s + 1);

212                                     *p = '`';

213                                     strcpy(tmpline, wrk);     /* safe, same size */

214                                     pt = tmpline;

215                              }

216                       } else

217                              break;

218                } while ((p = strchr(pt, '`')) != NULL);

219         }

220

221         /*

222         * Any remaining meta-chars?

223         */

224         if (strpbrk(pt, SHELL_META) == NULL) {

225                /*

226                * No meta-chars.

227                * Split into words, delimited by whitespace.

228                */

229                snprintf(wrk, sizeof(wrk), "%s%s", (base_dir ? base_dir : ""), pt);

230                strcpy(tmpline, wrk);     /* safe, same size */

231                if ((p = strtok(tmpline, " /t/n")) != NULL) {

232                       while (p) {

233                              g->pathv = (char **)xrealloc(g->pathv,

234                                        (g->pathc + 2) * sizeof(char *));

235                              g->pathv[g->pathc++] = xstrdup(p);

236                              p = strtok(NULL, " /t/n");

237                       }

238                }

239                if (g->pathc)

240                       g->pathv[g->pathc] = NULL;

241                return 0;

242         }

243         /* else */

244         /*

245         * Handle remaining meta-chars

246         */

247

248         /*

249         * Just plain quotes?

250         */

251         if (strpbrk(pt, "&();|<>$`!{}[]~=+:?*") == NULL &&

252             (p = strpbrk(pt, "/"'//"))) {

253                split_line(g, pt, 1);

254                return 0;

255         }

256

257         if (strpbrk(pt, "&();|<>$`/"'//!{}~+:[]~?*") == NULL) {

258                /* Only "=" remaining, should be module options */

259                split_line(g, pt, 0);

260                return 0;

261         }

262

263         /*

264         * If there are meta-characters and

265         * if they are only shell glob meta-characters: do globbing

266         */

267  #if HAVE_WORDEXP

268         if (strpbrk(pt, "&();|<>`/"'//!{}~=+:") == NULL &&

269             strpbrk(pt, "$[]~?*"))

270  #else

271         if (strpbrk(pt, "&();|<>$`/"'//!{}~=+:") == NULL &&

272             strpbrk(pt, "[]~?*"))

273  #endif

274                if ((type & ME_GLOB) && glob_it(pt, g) == 0)

275                       return 0;

276

277         if (strpbrk(pt, "&();|<>$`/"'//!{}~+:[]~?*") == NULL) {

278                /* Only "=" remaining, should be module options */

279                split_line(g, pt, 0);

280                return 0;

281         }

282

283         /*

284         * Last resort: Use "echo".

285         * DANGER: Applying shell expansion to user supplied input is a

286         *         major security risk.  Modutils code should only do meta

287         *         expansion via shell commands for trusted data.  Basically

288         *         this means only for data in the config file.   Even that

289         *         assumes that the user cannot run modprobe as root with

290         *         their own config file.  Programs (including the kernel)

291         *         that invoke modprobe as root with user supplied input must

292         *         pass exactly one user supplied parameter and must set

293         *         safe mode.

294                */

295         if (!(type & ME_SHELL_COMMAND))

296                return 0;

297         snprintf(wrk, sizeof(wrk), "%s%s", (base_dir ? base_dir : ""), pt);

298         strcpy(tmpline, wrk);     /* safe, same size */

299         snprintf(tmpcmd, sizeof(tmpcmd), "/bin/echo /"");

300         for (p = tmpline, p1 = tmpcmd + strlen(tmpcmd); *p; ++p, ++p1) {

301                if (*p == '"' || *p == '//')

302                       *p1++ = '//';

303                *p1 = *p;

304         }

305         *p1++ = '"';

306         *p1++ = '/0';

307         if (p1 - tmpcmd > sizeof(tmpcmd)) {

308                error("tmpcmd overflow, should never happen");

309                exit(1);

310         }

311         if ((fin = popen(tmpcmd, "r")) == NULL) {

312                error("Can't execute: %s", tmpcmd);

313                return -1;

314         }

315         /* else */

316

317         /*

318         * Collect the result

319         */

320         while (fgets(tmpcmd, PATH_MAX, fin) != NULL) {

321                int l = strlen(tmpcmd);

322

323                line = (char *)xrealloc(line, len + l + 1);

324                line[len] = '/0';

325                strcat(line + len, tmpcmd);    /* safe, realloc */

326                len += l;

327         }

328         pclose(fin);

329

330         if (line) {

331                /* shell used to strip one set of quotes.  Paranoia code in

332                * 2.3.20 stops that strip so we do it ourselves.

333                */

334                split_line(g, line, 1);

335                free(line);

336         }

337

338         return 0;

339          }

 

1301行中调用meta_expandtypeME_ALL,该宏定义在./modutils-2.4.0/include/util.h中。

Insmod——ME_ALL

76    #define ME_ALL (ME_GLOB|ME_SHELL_COMMAND|ME_BUILTIN_COMMAND)

 

至此,进入174行的if块中。178行的for循环提取”`”包含的内容,这里是uname –r。在182~193行中,uname –r被替换为version信息。195~215行则对kernelversion进行替换,替换部分为versionx.xx,也就是主次版本号。224行以下,对Shell元符号进行处理。这里我们将进入224行的if块。在这里加上base_dir,也就是path的起始目录路径,在insmod中,base_dirnull231~237处理分行的情况——将他们拷贝到一处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值