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

回到INSMOD_MAIN

 

1691              check_module_parameters(f, &persist_parms);

1692      

1693              if (optind < argc) {

1694                     if (!process_module_arguments(f, argc - optind, argv + optind, 1))

1695                            goto out;

1696              }

1697              arch_create_got(f); /* DEPMOD */

1698                          hide_special_symbols(f);

 

当在命令行里运行程序时,我们可以在程序名后跟上参数。在insmod里也可以这样。不过要实现这个功能,模块需要做点工作。为了使自己能接受命令行参数,模块必须使用MODULE_PARM来处理这些变量。例如linux ipv6部分代码里的:

 

124  /* Default to forward because I got too much mail already. */

125  static int forward = NF_ACCEPT;

126  MODULE_PARM(forward, "i");

Insmod——MODULE_PARM

MODULE_PARMlinux-2.4.0/include/linux/module.h中。

 

209  /* Used to verify parameters given to the module.  The TYPE arg should

210     be a string in the following format:

211       [min[-max]]{b,h,i,l,s}

212     The MIN and MAX specifiers delimit the length of the array.  If MAX

213     is omitted, it defaults to MIN; if both are omitted, the default is 1.

214     The final character is a type specifier:

215         b     byte

216         h     short

217         i      int

218         l      long

219         s      string

220  */

221

222  #define MODULE_PARM(var,type)                  /

223  const char __module_parm_##var[]             /

224  __attribute__((section(".modinfo"))) =        /

225  "parm_" __MODULE_STRING(var) "=" type

226

227  #define MODULE_PARM_DESC(var,desc)        /

228  const char __module_parm_desc_##var[]            /

229  __attribute__((section(".modinfo"))) =        /

230          "parm_desc_" __MODULE_STRING(var) "=" desc

 

151  /* Indirect stringification.  */

152

153  #define __MODULE_STRING_1(x)    #x

154  #define __MODULE_STRING(x) __MODULE_STRING_1(x)

 

MODULE_PARMMODULE_PARM_DESC处理的变量,会将一条类似“parm_var=type”,“parm_desc_var=desc”的信息加入.modinfo段里。以上面的例子,假定模块名为ipv6,在insmod命令里,可以使用insmid ipv6 forward=1。这样的命令,在这个命令里,模块中的变量forward将被设为1

好了,现在来看看check_module_parameters这个函数,它和INSMOD_MAIN在同一个文件里。

Insmod——check_module_parameters函数

1335       /* Check that all module parameters have reasonable definitions */

1336       static void check_module_parameters(struct obj_file *f, int *persist_flag)

1337       {

1338              struct obj_section *sec;

1339              char *ptr, *value, *n, *endptr;

1340              int namelen, err = 0;

1341

1342              sec = obj_find_section(f, ".modinfo");

1343              if (sec == NULL) {

1344                     /* module does not support typed parameters */

1345                     return;

1346              }

1347

1348              ptr = sec->contents;

1349              endptr = ptr + sec->header.sh_size;

1350              while (ptr < endptr && !err) {

1351                     value = strchr(ptr, '=');

1352                     n = strchr(ptr, '/0');

1353                     if (value) {

1354                            namelen = value - ptr;

1355                            if (namelen >= 5 && strncmp(ptr, "parm_", 5) == 0

1356                                && !(namelen > 10 && strncmp(ptr, "parm_desc_", 10) == 0)) {

1357                                   char *pname = xmalloc(namelen + 1);

1358                                   strncpy(pname, ptr + 5, namelen - 5);

1359                                   pname[namelen - 5] = '/0';

1360                                   err = check_module_parameter(f, pname, value+1, persist_flag);

1361                                   free(pname);

1362                            }

1363                     } else {

1364                            if (n - ptr >= 5 && strncmp(ptr, "parm_", 5) == 0) {

1365                                   error("parameter %s found with no value", ptr);

1366                                   err = 1;

1367                            }

1368                     }

1369                     ptr = n + 1;

1370              }

1371

1372              if (err)

1373                     *persist_flag = 0;

1374              return;

1375      }

 

函数的主体是check_module_parameter,这个函数也在同一文件里。

Insmod——check_module_parameter函数

1266       /* Check that a module parameter has a reasonable definition */

1267       static int check_module_parameter(struct obj_file *f, char *key, char *value, int *persist_flag)

1269       {

1270              struct obj_symbol *sym;

1271              int min, max;

1272              char *p = value;

1273

1274              sym = obj_find_symbol(f, key);

1275              if (sym == NULL) {

1276                     /* FIXME: For 2.2 kernel compatibility, only issue warnings for

1277                     *        most error conditions.  Make these all errors in 2.5.

1278                     */

1279                     lprintf("Warning: %s symbol for parameter %s not found", error_file, key);

1280                     return(1);

1281              }

1282

1283              if (isdigit(*p)) {

1284                     min = strtoul(p, &p, 10);

1285                     if (*p == '-')1286

1286                            max = strtoul(p + 1, &p, 10);

1287                     else

1288                            max = min;

1289              } else

1290                     min = max = 1;

1291

1292              if (max < min) {

1293                     lprintf("Warning: %s parameter %s has max < min!", error_file, key);

1294                     return(1);

1295              }

1296

1297              switch (*p) {

1298              case 'c':

1299                     if (!isdigit(p[1])) {

1300                            lprintf("%s parameter %s has no size after 'c'!", error_file, key);

1301                            return(1);

1302                     }

1303                     while (isdigit(p[1]))

1304                            ++p;       /* swallow c array size */

1305                     break;

1306              case 'b':    /* drop through */

1307              case 'h':    /* drop through */

1308              case 'i':    /* drop through */

1309              case 'l':    /* drop through */

1310              case 's':

1311                     break;

1312              case '/0':

1313                     lprintf("%s parameter %s has no format character!", error_file, key);

1314                     return(1);

1315              default:

1316                     lprintf("%s parameter %s has unknown format character '%c'", error_file, key, *p);

1317                     return(1);

1318              }

1319              switch (*++p) {

1320              case 'p':

1321                     if (*(p-1) == 's') {

1322                            error("parameter %s is invalid persistent string", key);

1323                            return(1);

1324                     }

1325                     *persist_flag = 1;

1326                     break;

1327              case '/0':

1328                     break;

1329              default:

1330                     lprintf("%s parameter %s has unknown format modifier '%c'", error_file, key, *p);

1331                     return(1);

1332              }

1333              return(0);

1334      }

 

函数首先确定符号存在。根据前面注释的解释,在声明类型之前,可以min-max这样的形式声明该参数可以接受的值的个数。所以,1282~1289行解析可能存在的参数值个数声明,如果没有参数值个数取值范围,就默认为11296行处理变量的类型。这里与2.4.0内核有点不符,modutils-2.4.0还可以处理cp{c, i, l, h, s}这样的类型,如果变量前有p,就表明这些参数来自文件,而且模块退出时,参数值需要回写。

做完这个检查后,如果命令行里带入了参数(optind<argc),处理这些参数。函数process_module_arguments也在这个文件中。

Insmod——process_module_arguments函数

733  static int process_module_arguments(struct obj_file *f, int argc, char **argv, int required)

734  {

735         for (; argc > 0; ++argv, --argc) {

736                struct obj_symbol *sym;

737                int c;

738                int min, max;

739                int n;

740                char *contents;

741                char *input;

742                char *fmt;

743                char *key;

744                char *loc;

745

746                if ((input = strchr(*argv, '=')) == NULL)

747                       continue;

748

749                n = input - *argv;

750                input += 1; /* skip '=' */

751

752                key = alloca(n + 6);

753

754                if (m_has_modinfo) {

755                       memcpy(key, "parm_", 5);

756                       memcpy(key + 5, *argv, n);

757                       key[n + 5] = '/0';

758                       if ((fmt = get_modinfo_value(f, key)) == NULL) {

758                              if (required) {

760                                     error("invalid parameter %s", key);

761                                     return 0;

762                              }

763                              else {

764                                     if (flag_verbose)

765                                            lprintf("ignoring %s", *argv);

766                                     continue; /* silently ignore optional parameters */

767                              }

768                       }

769                       key += 5;

770

771                       if (isdigit(*fmt)) {

772                              min = strtoul(fmt, &fmt, 10);

773                              if (*fmt == '-')

774                                     max = strtoul(fmt + 1, &fmt, 10);

775                              else

776                                     max = min;

777                       } else

778                              min = max = 1;

779                } else { /* not m_has_modinfo */

780                       memcpy(key, *argv, n);

781                       key[n] = '/0';

782 

783                       if (isdigit(*input))

784                              fmt = "i";

785                       else

786                              fmt = "s";

787                       min = max = 0;

788                }

789

790                sym = obj_find_symbol(f, key);

791

792                /*

793                * Also check that the parameter was not

794                * resolved from the kernel.

795                */

796                if (sym == NULL || sym->secidx > SHN_HIRESERVE) {

797                       error("symbol for parameter %s not found", key);

798                       return 0;

799                }

800

801                contents = f->sections[sym->secidx]->contents;

802                loc = contents + sym->value;

803                n = 1;

804

805                while (*input) {

806                       char *str;

807

808                       switch (*fmt) {

809                       case 's':

810                       case 'c':

811                              /*

812                              * Do C quoting if we begin with a ",

813                              * else slurp the lot.

814                              */

815                              if (*input == '"') {

816                                     char *r;

817

818                                     str = alloca(strlen(input));

819                                     for (r = str, input++; *input != '"'; ++input, ++r) {

820                                            if (*input == '/0') {

821                                                   error("improperly terminated string argument for %s", key);

822                                                   return 0;

823                                            }

824                                            /* else */

825                                            if (*input != '//') {

826                                                   *r = *input;

827                                                   continue;

828                                            }

829                                            /* else  handle / */

830                                            switch (*++input) {

831                                            case 'a': *r = '/a'; break;

832                                            case 'b': *r = '/b'; break;

833                                            case 'e': *r = '/033'; break;

834                                            case 'f': *r = '/f'; break;

835                                            case 'n': *r = '/n'; break;

836                                            case 'r': *r = '/r'; break;

837                                            case 't': *r = '/t'; break;

838

839                                            case '0':

840                                            case '1':

841                                            case '2':

842                                            case '3':

843                                            case '4':

844                                            case '5':

845                                            case '6':

846                                            case '7':

847                                                   c = *input - '0';

849                                                   if ('0' <= input[1] && input[1] <= '7') {

850                                                          c = (c * 8) + *++input - '0';

851                                                          if ('0' <= input[1] && input[1] <= '7')

852                                                                 c = (c * 8) + *++input - '0';

853                                                   }

854                                                   *r = c;

855                                                   break;

856

857                                            default: *r = *input; break;

858                                            }

859                                     }

860                                     *r = '/0';

861                                     ++input;

862                              } else {

863                                     /*

864                                     * The string is not quoted.

865                                     * We will break it using the comma

866                                     * (like for ints).

867                                     * If the user wants to include commas

868                                     * in a string, he just has to quote it

869                                     */

870                                     char *r;

871 

872                                     /* Search the next comma */

873                                     if ((r = strchr(input, ',')) != NULL) {

874                                            /*

875                                            * Found a comma

876                                            * Recopy the current field

877                                            */

878                                            str = alloca(r - input + 1);

879                                            memcpy(str, input, r - input);

880                                            str[r - input] = '/0';

881                                            /* Keep next fields */

882                                            input = r;

883                                     } else {

884                                            /* last string */

885                                            str = input;

886                                            input = "";

887                                     }

888                              }

889

890                              if (*fmt == 's') {

891                                     /* Normal string */

892                                     obj_string_patch(f, sym->secidx, loc - contents, str);

893                                     loc += tgt_sizeof_char_p;

894                              } else {

895                                     /* Array of chars (in fact, matrix !) */

896                                     long charssize;       /* size of each member */

897

898                                     /* Get the size of each member */

899                                     /* Probably we should do that outside the loop ? */

900                                     if (!isdigit(*(fmt + 1))) {

901                                            error("parameter type 'c' for %s must be followed by"

902                                            " the maximum size", key);

903                                            return 0;

904                                     }

905                                     charssize = strtoul(fmt + 1, (char **) NULL, 10);

906

907                                     /* Check length */

908                                     if (strlen(str) >= charssize-1) {

909                                            error("string too long for %s (max %ld)",

910                                                  key, charssize - 1);

911                                            return 0;

912                                     }

913                                     /* Copy to location */

914                                     strcpy((char *) loc, str); /* safe, see check above */

915                                     loc += charssize;

916                              }

917                              /*

918                              * End of 's' and 'c'

919                              */

920                              break;

921

922                       case 'b':

923                              *loc++ = strtoul(input, &input, 0);

924                              break;

925

926                       case 'h':

927                              *(short *) loc = strtoul(input, &input, 0);

928                              loc += tgt_sizeof_short;

929                              break;

930

931                       case 'i':

932                              *(int *) loc = strtoul(input, &input, 0);

933                              loc += tgt_sizeof_int;

934                              break;

935 

936                       case 'l':

937                              *(long *) loc = strtoul(input, &input, 0);

938                              loc += tgt_sizeof_long;

939                              break;

940 

941                       default:

942                              error("unknown parameter type '%c' for %s",

943                                    *fmt, key);

944                              return 0;

945                       }

946                       /*

947                       * end of switch (*fmt)

948                       */

949

950                       while (*input && isspace(*input))

951                              ++input;

952                       if (*input == '/0')

953                              break; /* while (*input) */

954                       /* else */

955 

956                       if (*input == ',') {

957                              if (max && (++n > max)) {

958                                     error("too many values for %s (max %d)", key, max);

959                                     return 0;

960                              }

961                              ++input;

962                              /* continue with while (*input) */

963                       } else {

964                              error("invalid argument syntax for %s: '%c'",

965                                    key, *input);

966                              return 0;

967                       }

968                } /* end of while (*input) */

969

970                if (min && (n < min)) {

971                       error("too few values for %s (min %d)", key, min);

972                       return 0;

973                }

974         } /* end of for (;argc > 0;) */

975

976         return 1;

977          }

 

因为使用命令行参数时,一定是param=value这样的形式。所以,746~752行就是分开=2边的字符串。如果模块文件包含.modinfo这个段,那么就通过get_modinfo_value函数在.modinfo段里查找参数的格式。这个函数在同一文件里,而且很简单。

Insmod——get_modinfo_value函数

401  static char * get_modinfo_value(struct obj_file *f, const char *key)

402  {

403         struct obj_section *sec;

404         char *p, *v, *n, *ep;

405         size_t klen = strlen(key);

406

407         sec = obj_find_section(f, ".modinfo");

408         if (sec == NULL)

409                return NULL;

410

411         p = sec->contents;

412         ep = p + sec->header.sh_size;

413         while (p < ep) {

414                v = strchr(p, '=');

415                n = strchr(p, '/0');

416                if (v) {

417                       if (v - p == klen && strncmp(p, key, klen) == 0)

418                              return v + 1;

419                } else {

420                       if (n - p == klen && strcmp(p, key) == 0)

421                              return n;

422                }

423                p = n + 1;

424         }

425

426         return NULL;

427          }

 

在这里调用process_module_parameters时,参数required1。因此,如果在.modinfo段里找不到这个参数的格式,就要出错返回。如果没有.modinfo段,那么只能简单地根据参数设置值是数字还是字符来确定格式。790行在文件的符号集中查找与=左边字符串相同的符号。796行确定该符号存在,而且不是内核提供的(回忆一下,来自内核的符号保存在SHN_HIRESERVE+1的段,其他模块的符号保存在SHN_HIRESERVE+2以上的模块。由此,可以知道,命令行参数设定的只能是模块自己的符号。

805行开始根据数据声明的格式处理数据。对于字符型数据,如果字符串没有用””包含,则“,”就是分割符。而且在””里的字符串可以使用转义字符。每个字符串通过obj_string_patch保存到obj_file里。如果是数值型数据,则直接写到符号对应的值里。另外,还要测试传给参数的值的个数是否符合声明。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值