home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / a / bin / modules-.2 / modules- / modules-1.2.8 / depmod / modprobe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-31  |  12.5 KB  |  575 lines

  1. #include <stdio.h>
  2. #include <stdarg.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <stdlib.h>
  6. #include <ctype.h>
  7. #include <sys/param.h>
  8. #include "link.h"
  9. #include "kernelsyms.h"
  10.  
  11. static char verbose_flag = 0;
  12. static int from_kerneld = 0;
  13.  
  14.  
  15. static void verbose (const char *ctl, ...)
  16. {
  17.     if (verbose_flag){
  18.         va_list list;
  19.         va_start (list,ctl);
  20.         vprintf (ctl,list);
  21.         va_end (list)
  22.         fflush (stdout);
  23.     }
  24. }
  25.  
  26. /*
  27.     Strip the extension of a file name
  28.     Return a pointer to a static buffer
  29. */
  30. const char *stripo(const char *fname)
  31. {
  32. #if 0
  33.     static char buf[300];
  34.     strcpy (buf,fname);
  35.     char *pt = buf + strlen(buf)-1;
  36.     while (pt > buf){
  37.         if (*pt == '.'){
  38.             *pt = '\0';
  39.             break;
  40.         }
  41.         pt--;
  42.     }
  43.     return buf;
  44. #else
  45.     const char *pt = fname;
  46.     while ((pt=strchr(fname,'/'))!=NULL) fname = pt+1;
  47.     if ((pt = strrchr(fname, '.'))
  48.         && ((strcmp(pt, ".o") == 0) || (strcmp(pt, ".mod") == 0))) {
  49.         char *leak = (char *)malloc(pt - fname + 1);
  50.         strncpy(leak, fname, pt - fname);
  51.         leak[pt - fname] = '\0';
  52.         fname = leak;
  53.     }
  54.     return fname;
  55. #endif
  56. }
  57.  
  58. /*
  59.     Return the options associated with a module.
  60.     Return NULL if there is none.
  61. */
  62. static char *any_options(const char *mod)
  63. {
  64.     const char *modname = stripo(mod);
  65.     int len = strlen(modname);
  66.  
  67.     for (int i = 0; optlist[i]; ++i) {
  68.         if (strncmp(optlist[i], modname, len) == 0
  69.             && isspace (optlist[i][len])) {
  70.             return str_skip(&(optlist[i][len]));
  71.         }
  72.     }
  73.     return NULL;
  74. }
  75.  
  76. class NODE{
  77. public:
  78.     NODE *next;
  79.     NODE *info;
  80.     char *str;
  81.     /*~PROTOBEG~ NODE */
  82. public:
  83.     NODE (const char *_str, NODE *_next);
  84.     NODE *lookup (const char *name);
  85.     ~NODE (void);
  86.     /*~PROTOEND~ NODE */
  87. };
  88.  
  89. PUBLIC NODE::NODE(const char *_str, NODE *_next)
  90. {
  91.     next = _next;
  92.     info = NULL;
  93.     str = strdup_err (_str);
  94. }
  95.  
  96. PUBLIC NODE::~NODE()
  97. {
  98.     delete info;
  99.     delete next;
  100.     free (str);
  101. }
  102.  
  103. PUBLIC NODE * NODE::lookup (const char *name)
  104. {
  105.     NODE *ret = NULL;
  106.     if (strcmp(name,str)==0){
  107.         ret = this;
  108.     }else if (next != NULL){
  109.         ret = next->lookup(name);
  110.     }
  111.     return ret;
  112. }
  113.  
  114. class DEPEND{
  115.     NODE *in_kernel;
  116.     NODE *dep_file;
  117.     /*~PROTOBEG~ DEPEND */
  118. public:
  119.     DEPEND (void);
  120.     int insmod (const char *mod,
  121.          NODE **newin_kernel,
  122.          char *options[]);
  123.     int read (const char *cfgfile);
  124.     int readcur (void);
  125.     int unload (const char *mod);
  126.     ~DEPEND (void);
  127.     /*~PROTOEND~ DEPEND */
  128. };
  129.  
  130. PUBLIC DEPEND::DEPEND()
  131. {
  132.     in_kernel = NULL;
  133.     dep_file = NULL;
  134. }
  135. PUBLIC DEPEND::~DEPEND()
  136. {
  137.     delete in_kernel;
  138.     delete dep_file;
  139. }
  140. /*
  141.     Read the liste of module already loaded in the kernel
  142. */
  143. PUBLIC int DEPEND::readcur ()
  144. {
  145. #if 0
  146.     int ret = -1;
  147.     FILE *fin = fopen ("/proc/modules","r");
  148.     delete in_kernel;
  149.     in_kernel = NULL;
  150.     if (fin != NULL){
  151.         char buf[300];
  152.         char mod[300];
  153.         while(fgets(buf,sizeof(buf)-1,fin)!=NULL
  154.             && sscanf(buf,"%s",mod)==1){
  155.             in_kernel = new NODE(stripo(mod),in_kernel);
  156.         }
  157.         fclose (fin);
  158.         ret = 0;
  159.     }
  160. #else
  161.     int ret = 0;
  162.     delete in_kernel;
  163.     in_kernel = NULL;
  164.     struct kernel_sym *ksym;
  165.     int so_far = 0;
  166.  
  167.     load_kernel_symbols();
  168.  
  169.     for (ksym = ksymtab; so_far < nksyms ; ++so_far, ksym++) {
  170.         if (ksym->name[0] == '#') {
  171.             if (ksym->name[1]) {
  172.                 in_kernel = new NODE(ksym->name + 1,in_kernel);
  173.             }
  174.             else
  175.                 break;
  176.         }
  177.     }
  178. #endif
  179.     return ret;
  180. }
  181. /*
  182.     Read the dependancy file.
  183.     The format is like a makefile.
  184. */
  185. PUBLIC int DEPEND::read (const char *cfgfile)
  186. {
  187.     int ret = -1;
  188.     FILE *fin = fopen (cfgfile,"r");
  189.     if (fin == NULL){
  190.         depmod_error ("Can't open dependancies file %s (%s)"
  191.             ,cfgfile,strerror(errno));
  192.     }else{
  193.         char buf[300];
  194.         ret = 0;
  195.         while(fgets(buf,sizeof(buf)-1,fin)!=NULL){
  196.             char line[300];
  197.             str_strip (buf,line);
  198.             if (line[0] != '\0'){
  199.                 char *pt = line;
  200.                 while (isspace(*pt)) pt++;
  201.                 char *modname = pt;
  202.                 while (*pt != ':' && *pt != '\0' && !isspace(*pt)) pt++;
  203.                 if (*pt != ':'){
  204.                     depmod_error ("Invalid dependancy\n\t%s",line);
  205.                     ret = -1;
  206.                 }else{
  207.                     *pt++ = '\0';
  208.                     dep_file = new NODE (modname,dep_file);
  209.                     // Parse the list of modules
  210.                     while (*pt != '\0'){
  211.                         while (isspace (*pt)) pt++;
  212.                         if (*pt > ' '){
  213.                             char *depname = pt;
  214.                             while (*pt > ' ') pt++;
  215.                             if (*pt != '\0') *pt++ = '\0';
  216.                             dep_file->info = new NODE (depname
  217.                                 ,dep_file->info);
  218.                         }
  219.                     }
  220.                 }
  221.             }
  222.         }
  223.         fclose (fin);
  224.         ret = 0;
  225.     }
  226.     return ret;
  227. }
  228. static int call_rmmod(const char *mod)
  229. {
  230.     char cmd[300];
  231.     mod = stripo(mod);
  232.     sprintf (cmd,"/sbin/rmmod %s %s",(depmod_syslog ? "-s" : ""),mod);
  233.     // This special sequence is there so error message generated
  234.     // by rmmod are indented.
  235.     verbose ("\r\t%s\n\t\t",cmd);
  236.     int ret = system(cmd);
  237.     return ret;
  238. }
  239. /*
  240.     Unload all submodule in reverse order they were loaded.
  241.     Return -1 if any error.
  242. */
  243. static int rmmod (NODE *nod)
  244. {
  245.     int ret = 0;
  246.     if (nod != NULL){
  247.         ret = rmmod (nod->next);
  248.         if (ret == 0){
  249.             ret = call_rmmod(nod->str);
  250.         }
  251.     }
  252.     return ret;
  253. }
  254. static NODE *lookup (NODE *nod, const char *str)
  255. {
  256.     NODE *ret = NULL;
  257.     if (nod != NULL){
  258.         ret = nod->lookup (str);
  259.     }
  260.     return ret;
  261. }
  262. /*
  263.     Try to load a module and the sub-module needed.
  264.     Return -1 if any error.
  265.  
  266.     If the module can't ne loaded, undo everything.
  267. */
  268. PUBLIC int DEPEND::insmod (
  269.     const char *mod,
  270.     NODE **newin_kernel,    // modules added by this session
  271.     char *options[])
  272. {
  273.     int ret = 0;
  274.     if (mod != NULL
  275.         && lookup (in_kernel,stripo(mod))==NULL
  276.         && lookup (*newin_kernel,mod)==NULL){
  277.         NODE *nod = lookup (dep_file,mod);
  278.         if (nod == NULL){
  279.             depmod_error ("No dependancy information for module %s",mod);
  280.             ret = -1;
  281.         }else{
  282.             NODE *dep = nod->info;
  283.             while (dep != NULL && ret == 0){
  284.                 ret = insmod (dep->str,newin_kernel,NULL);
  285.                 dep = dep->next;
  286.             }
  287.             if (ret == 0){
  288.                 char cmd[300];
  289.                 sprintf (cmd,"/sbin/insmod %s %s %s"
  290.                     ,from_kerneld ? "-k" : ""
  291.                     ,depmod_syslog ? "-s" : ""
  292.                     ,mod);
  293.                 char *op;
  294.                 if (options && options[0] &&
  295.                     strchr(options[0], '=')) {
  296.                     for (int nopt = 0; options[nopt]; ++nopt) {
  297.                         if (strchr(options[nopt], '=')){
  298.                             strcat(cmd, " ");
  299.                             strcat(cmd, options[nopt]);
  300.                         }
  301.                         else
  302.                             break;
  303.                     }
  304.                 }
  305.                 else if (op = any_options(mod)) {
  306.                     strcat(cmd, " ");
  307.                     strcat(cmd, op);
  308.                 }
  309.                 verbose ("\r\t%s\n\t\t",cmd);
  310.                 /* For now, seems like insmod is not reporting */
  311.                 /* success or failure correctly, so we read */
  312.                 /* /proc/modules each time */
  313.                 ret = system(cmd);
  314.                 //readcur();
  315.                 //ret = lookup (in_kernel,stripo(mod))==NULL ? -1 : 0;
  316.                 //verbose (" -> %s\n",ret==0 ? "OK" : "Error");
  317.                 if (ret != 0){
  318.                     // Must unload all the sub-module
  319.                     rmmod (nod->info);
  320.                 }else{
  321.                     *newin_kernel = new NODE (mod,*newin_kernel);
  322.                 }
  323.             }else{
  324.                 rmmod (nod->info);
  325.                 readcur();
  326.             }
  327.         }
  328.     }
  329.     return ret;
  330. }
  331. /*
  332.     Unload a module and whatever modules was requiered by this module.
  333.     We blindly remove everything in order, even if a module is needed
  334.     by another module. The idea is that this module will refuse to
  335.     unload.
  336.  
  337.     Return -1 if the first module cound not be unloaded.
  338. */
  339. PUBLIC int DEPEND::unload (
  340.     const char *mod)
  341. {
  342.     int ret = 0;
  343.     if (mod != NULL){
  344.         char *tbpath[1000];
  345.         int nbl = config_locate (mod,tbpath,NULL);
  346.         if (nbl == 0){
  347.             /* #Specification: modprobe -r / unknown module
  348.                 If there is no information about a module in
  349.                 the dependancy file, we simply call /sbin/rmmod
  350.                 on the module without further checking.
  351.             */
  352.             ret = call_rmmod(mod);
  353.         }else{
  354.             for (int m=0; m<nbl; m++){
  355.                 char *path = tbpath[m];
  356.                 if(lookup (in_kernel,stripo(path))!=NULL){
  357.                     NODE *nod = lookup (dep_file,path);
  358.                     if (nod == NULL){
  359.                         depmod_error (
  360.                             "No dependancy information for module %s"
  361.                             ,mod);
  362.                     }else{
  363.                         ret = call_rmmod (path);
  364.                         /* We don't care if we succeed */
  365.                         /* to unload sub-modules. */
  366.                         NODE *dep = nod->info;
  367.                         while (dep != NULL){
  368.                             unload (dep->str);
  369.                             dep = dep->next;
  370.                         }
  371.                     }
  372.                 }
  373.             }
  374.             tbstr_free (tbpath,nbl);
  375.         }
  376.     }
  377.     return ret;
  378. }
  379.  
  380.  
  381.  
  382. static int modprobe_fromlist (
  383.     DEPEND &dep,
  384.     char *list[],
  385.     int nb,
  386.     const char *type,
  387.     int loadall)
  388. {
  389.     int ret = -1;
  390.     for (int i=0; i<nb; i++){
  391.         NODE *newin_kernel = NULL;
  392.         char *tbpath[1000];
  393.         /* #Specification: modprobe / module option
  394.             We can pass option to module in the modprobe's command line.
  395.             It goes like this:
  396.             #
  397.             /sbin/modprobe module opt1=value opt2=value [ othermodule ...]
  398.             #
  399.             An option is a keyword followed by an equal sign and a value.
  400.             No space are allowed in the sequence, unless it is quoted.
  401.  
  402.             The option list end at the end of the list or at the
  403.             first non-option argument (a module).
  404.         */
  405.         if (strchr(list[i], '=') == NULL) {
  406.             int nbl = config_locate (list[i],tbpath,type);
  407.             if (nbl == 0){
  408.                 depmod_error ("Can't locate module %s",list[i]);
  409.             }else{
  410.                 for (int m=0; m<nbl; m++){
  411.                     if (dep.insmod (tbpath[m],&newin_kernel,&list[i+1])
  412.                         != -1){
  413.                         ret = 0;
  414.                         if (!loadall) break;
  415.                     }
  416.                 }
  417.                 tbstr_free (tbpath,nbl);
  418.             }
  419.         }
  420.         delete newin_kernel;
  421.         if (ret == 0 && !loadall) break;
  422.     }
  423.     return ret;
  424. }
  425. /*
  426.     Print all available module matching "pattern" and of a certain type.
  427.     type may be NULL.
  428. */
  429. static void modprobe_printlist (
  430.     const char *pattern,
  431.     const char *type)
  432. {
  433.     char *lst[1000];
  434.     int nb = config_lstmod (pattern,type,lst,1);
  435.     for (int i=0; i<nb; i++) printf ("%s\n",lst[i]);
  436.     tbstr_free (lst,nb);
  437. }
  438.  
  439. static void modprobe_nothing(const char *str)
  440. {
  441.     depmod_error (
  442.         "Nothing to %s ???\n"
  443.         "Specify at least a module or a wildcard like \\*",str);
  444. }
  445.  
  446. int modprobe_main (int argc, char *argv[])
  447. {
  448.     int ret = -1;
  449.     if (argc == 1){
  450.         fprintf (stderr,
  451.             "modprobe " DEPMOD_RELEASE "\n"
  452.             "Load/Unload modules with dependancies\n"
  453.             "\n"
  454.             "modprobe [-a] [ -t type ] module1 module2 ...\n"
  455.             "modprobe -c\n"
  456.             "\n"
  457.             "  modprobe will try to load one of module1 module2 and will\n"
  458.             "  automaticly load the modules needed by module1 or module2\n"
  459.             "  using the dependancy file (see " ETC_CONF_MODULES ").\n"
  460.             "  If type is specified, the modules will be search only\n"
  461.             "  in the corresponding directory (See path[type]=... in\n"
  462.             "  " ETC_CONF_MODULES "). Note that modprobe can expand\n"
  463.             "  wildcards, so\n"
  464.             "\n"
  465.             "      modprobe -t net \\* \n"
  466.             "  will load one of the ethernet driver.\n"
  467.             "\n"
  468.             "  Unless -a option is provided, modprobe will\n"
  469.             "  stop loading as soon as one module load sucessfully\n"
  470.             "\n"
  471.             "      modprobe -a -t boot \\*\n"
  472.             "  will load all module of type boot.\n"
  473.             "\n"
  474.             "modprobe -r module\n"
  475.             "  remove a module and all sub-modules it depends on\n"
  476.             "\n"
  477.             "modprobe -l [ -t type ] [ pattern ]\n"
  478.             "  will list all modules available. With option -t, it will\n"
  479.             "  shows only those of a certain type. A pattern may be used\n"
  480.             "  to limit the output.\n"
  481.             "\n"
  482.             "modprobe -c\n"
  483.             "  will display the current configuration\n"
  484.             "\n"
  485.             "It is calling /sbin/insmod and /sbin/rmmod to achieve its goal.\n"
  486.             );
  487.     }else if (config_read()!=-1){
  488.         DEPEND dep;
  489.         if (dep.read(config_getdepfile())!=-1
  490.             && dep.readcur()!=-1){
  491.             ret = 0;
  492.             int loadall = 0;    // Load only one module out of a list
  493.             char *type = NULL;    // Search in all path[]
  494.             int remove = 0;
  495.             int showconfig = 0;
  496.             int list = 0;
  497.             int noarg = 1;
  498.             while (1){
  499.                 char *arg = argv[noarg];
  500.                 if (arg == NULL || arg[0] != '-'){
  501.                     break;
  502.                 }else if (!isalpha(arg[1])){
  503.                     depmod_error ("Invalid option %s",arg);
  504.                     ret = -1;
  505.                 }else{
  506.                     char *opt = arg + 2;
  507.                     if (arg[1] == 't'){
  508.                         if (opt[0] != '\0'){
  509.                             type = opt;
  510.                         }else if (noarg < argc-1){
  511.                             type = argv[++noarg];
  512.                         }else{
  513.                             depmod_error ("Missing value for option -t");
  514.                             ret = -1;
  515.                         }
  516.                     }else if (arg[1] == 'a'){
  517.                         loadall = 1;
  518.                     }else if (arg[1] == 'c'){
  519.                         showconfig = 1;
  520.                     }else if (arg[1] == 'd'){
  521.                         debugmode = 1;
  522.                     }else if (arg[1] == 'l'){
  523.                         list = 1;
  524.                     }else if (arg[1] == 'r'){
  525.                         remove = 1;
  526.                     }else if (arg[1] == 'v'){
  527.                         verbose_flag = 1;
  528.                     }else if (arg[1] == 'k'){
  529.                         from_kerneld = 1;
  530.                     }else if (arg[1] == 's'){
  531.                         depmod_setsyslog ("modprobe");
  532.                     }else{
  533.                         depmod_error ("Invalid option %s",arg);
  534.                         ret = -1;
  535.                     }
  536.                 }
  537.                 noarg++;
  538.             }
  539.             if (ret != -1){
  540.                 int left = argc - noarg;
  541.                 char **lst = argv + noarg;
  542.                 if (showconfig){
  543.                     config_show();
  544.                 }else if (remove){
  545.                     if (left == 0){
  546.                         modprobe_nothing ("remove");
  547.                     }else{
  548.                         for (int i=0; i<left && ret == 0; i++){
  549.                             ret = dep.unload (lst[i]);
  550.                         }
  551.                     }
  552.                 }else if (list){
  553.                     if (left > 0){
  554.                         for (int i=0; i<left && ret == 0; i++){
  555.                             modprobe_printlist (lst[i],type);
  556.                         }
  557.                     }else{
  558.                         modprobe_printlist ("*",type);
  559.                     }
  560.                     ret = 0;
  561.                 }else{
  562.                     if (left == 0){
  563.                         modprobe_nothing ("load");
  564.                     }else{
  565.                         ret = modprobe_fromlist (dep,lst,left,type,loadall);
  566.                     }
  567.                 }
  568.             }
  569.         }
  570.     }
  571.     verbose ("\n");
  572.     return ret;
  573. }
  574.  
  575.