home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / modutils / depmod / conf_file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-06  |  16.4 KB  |  819 lines

  1. /* Copyright 1997 Free Software Foundation, Inc.
  2.    Contributed by Marcin Dalecki <dalecki@sub994.sub.uni-goettingen.de>
  3.  
  4.    This file is part of the Linux modutils.
  5.  
  6.    This program is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by the
  8.    Free Software Foundation; either version 2 of the License, or (at your
  9.    option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.    General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software Foundation,
  18.    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  19.  
  20. #ident "$Id: conf_file.c,v 1.1.1.1 1998/01/06 20:51:07 ewt Exp $"
  21.  
  22. #include <stddef.h>
  23. #include <stdio.h>
  24. #include <assert.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28. #include <ctype.h>
  29. #include <sys/stat.h>
  30. #include <sys/types.h>
  31. #include <sys/utsname.h>
  32. #include <signal.h>
  33. #include <limits.h>
  34. #include <dirent.h>
  35. #include <fnmatch.h>
  36.  
  37. #include "conf_file.h"
  38. #include "util.h"
  39. #include "misc.h"
  40.  
  41. /*
  42.  * List of different paths for different sets
  43.  * used like this: "/lib/module/SET/TYPE/bar.o
  44.  */
  45.  
  46. struct mod_type
  47.   {
  48.     struct mod_type *next;
  49.     char *type;
  50.   };
  51.  
  52. static struct mod_set
  53.   {
  54.     struct mod_set *next;
  55.     struct mod_type *types;
  56.     char *set;
  57.   }
  58.  *mod_set = NULL;
  59.  
  60. char *default_types[] =
  61. {
  62.   "fs",
  63.   "misc",
  64.   "net",
  65.   "scsi",
  66.   "block",
  67.   "cdrom",
  68.   "ipv4",
  69.   "ipv6",
  70.   NULL                /* marks the end of the list! */
  71. };
  72.  
  73. char *default_sets[] =
  74. {
  75.   "/lib/modules",
  76.   "/lib/modules/default",
  77.   NULL
  78. };
  79.  
  80. /*
  81.  * Operations concearned with the search paths.
  82.  */
  83.  
  84. static void
  85. add_set (char *set)
  86. {
  87.   struct mod_set *new_set;
  88.  
  89.   new_set = (struct mod_set *) xmalloc (sizeof (struct mod_set));
  90.   new_set->next = mod_set;
  91.   new_set->types = NULL;
  92.   new_set->set = xstrdup (set);
  93.   mod_set = new_set;
  94. }
  95.  
  96. static void
  97. add_type (struct mod_set *set, char *type)
  98. {
  99.   struct mod_type *new_type;
  100.  
  101.   new_type = (struct mod_type *) xmalloc (sizeof (struct mod_type));
  102.   new_type->next = set->types;
  103.   new_type->type = xstrdup (type);
  104.   set->types = new_type;
  105. }
  106.  
  107. static void
  108. add_option (char *module, char *args, int may_unload)
  109. {
  110.   struct mod_option *new_opt;
  111.   new_opt = (struct mod_option *) xmalloc (sizeof (struct mod_option));
  112.   new_opt->next = mod_options;
  113.   new_opt->module = xstrdup (module);
  114.   new_opt->may_unload = may_unload;
  115.   mod_options = new_opt;
  116.  
  117.   if (args)
  118.       new_opt->args = xstrdup (args);
  119.   else
  120.       new_opt->args = NULL;
  121. }
  122.  
  123. static struct action
  124. {
  125.   struct action *next;
  126.   enum command when;
  127.   char *module;
  128.   char *cmd;
  129. }
  130.  *mod_action = NULL;
  131.  
  132. char *depfile = NULL;
  133. char *insmod_opts = NULL;
  134. struct mod_option *mod_options = NULL;
  135.  
  136. static struct mod_alias
  137.   {
  138.     struct mod_alias *next;
  139.     char *name;
  140.     char *alias;
  141.   }
  142. alias_list[] =
  143. {
  144. #include "alias.h"
  145.   {
  146.     NULL, NULL, NULL
  147.   }
  148. };
  149.  
  150. static struct mod_alias *mod_alias = NULL;
  151.  
  152. static void
  153. add_alias (char *module, char *alias)
  154. {
  155.   struct mod_alias *tmp;
  156.  
  157.   tmp = (struct mod_alias *) xmalloc (sizeof (struct mod_alias));
  158.   tmp->next = mod_alias;
  159.   tmp->name = xstrdup (module);
  160.   tmp->alias = xstrdup (alias);
  161.   mod_alias = tmp;
  162. }
  163.  
  164. static void
  165. add_action (enum command when, char *module, char *action)
  166. {
  167.   struct action *tmp;
  168.  
  169.   tmp = (struct action *) xmalloc (sizeof (struct action));
  170.   tmp->next = mod_action;
  171.   tmp->when = when;
  172.   tmp->module = xstrdup (module);
  173.   tmp->cmd = xstrdup (action);
  174.   mod_action = tmp;
  175. }
  176.  
  177. static void
  178. release_all_sets (void)
  179. {
  180.   struct mod_set *set;
  181.   struct mod_set *tmp;
  182.  
  183.   set = mod_set;
  184.   while (set)
  185.     {
  186.       struct mod_type *type;
  187.       struct mod_type *ttmp;
  188.       tmp = set;
  189.       free (set->set);
  190.  
  191.       type = set->types;
  192.       while (type)
  193.     {
  194.       ttmp = type;
  195.       free (type->type);
  196.       type = type->next;
  197.       free (ttmp);
  198.     }
  199.       set = set->next;
  200.       free (tmp);
  201.     }
  202.   mod_set = NULL;
  203. }
  204.  
  205. /*
  206.  * Read the modules configuration file.
  207.  *
  208.  * Error messages are generated.
  209.  */
  210. static int
  211. error_missing_argument (int line)
  212. {
  213.   lprintf ("conf:%d: missing argument\n", line);
  214.   return 1;
  215. }
  216.  
  217. static int
  218. expect_action (int line, int assign,
  219.            enum command com,
  220.            char *cp, char **tmp)
  221. {
  222.   if (assign)
  223.     {
  224.       lprintf ("conf:%d: %s used in assignment\n", line, *tmp);
  225.       return 1;
  226.     }
  227.   if (!cp)
  228.     return error_missing_argument (line);
  229.   *tmp = cp + 1;
  230.   cp = strchr (*tmp, ' ');
  231.   if (!cp)
  232.     return error_missing_argument (line);
  233.   *cp = '\0';
  234.  
  235.   add_action (com, *tmp, cp + 1);
  236.  
  237.   return 0;
  238. }
  239.  
  240. int
  241. read_config_file (char *kernel_ver)
  242. {
  243.   struct utsname uts_info;
  244.   int drop_default_paths = 1;
  245.   char *depfile_tmp;
  246.   char **list;
  247.   struct mod_set *set;
  248.   char *def_set;
  249.   char *config;
  250.   char *tmp = NULL;
  251.   char *end;
  252.   int line = 0;            /* current line of the configuration file */
  253.   char linebuf [8192];
  254.  
  255.   /*
  256.    * Initialize the list of predefined aliases.
  257.    */
  258.   mod_alias = alias_list;
  259.   while (mod_alias[1].name && mod_alias[1].alias)
  260.     {
  261.       mod_alias->next = mod_alias + 1;
  262.       ++mod_alias;
  263.     }
  264.   mod_alias = alias_list;
  265.  
  266.   /*
  267.    * Create the full name of the output file.
  268.    */
  269.   if (kernel_ver)
  270.     {
  271.       depfile_tmp = (char *) xmalloc (strlen ("/lib/modules//modules.dep") +
  272.                       strlen (kernel_ver) + 1);
  273.       strcpy (depfile_tmp, "/lib/modules/");
  274.       strcat (depfile_tmp, kernel_ver);
  275.       strcat (depfile_tmp, "/modules.dep");
  276.     }
  277.   else
  278.     depfile_tmp = xstrdup ("");
  279.  
  280.   depfile = depfile_tmp;
  281.  
  282.   /*
  283.    * Create the primary path for modules:
  284.    */
  285.  
  286.   list = default_sets;
  287.   while (*list)
  288.     {
  289.       add_set (*list);
  290.       ++list;
  291.     }
  292.  
  293.   if (kernel_ver)
  294.     tmp = kernel_ver;
  295.   else
  296.     {
  297.       uname (&uts_info);
  298.       tmp = uts_info.release;
  299.     }
  300.   def_set = (char *) xmalloc (strlen ("/lib/modules/") + strlen (tmp) + 1);
  301.   strcpy (def_set, "/lib/modules/");
  302.   strcat (def_set, tmp);
  303.   add_set (def_set);
  304.  
  305.   free (def_set);
  306.  
  307.   /*
  308.    * Add the default types to the just created global list.
  309.    */
  310.   for (set = mod_set; set; set = set->next)
  311.     {
  312.       char **type;
  313.  
  314.       for (type = default_types; *type; ++type)
  315.     add_type (set, *type);
  316.     }
  317.  
  318.   /*
  319.    * Now read the configuration file.
  320.    */
  321.  
  322.   config = NULL;
  323.   if (!access ("/etc/modules.conf", R_OK))
  324.     config = read_and_preprocess_file ("/etc/modules.conf");
  325.   if (!config)
  326.     config = read_and_preprocess_file ("/etc/conf.modules");
  327.  
  328.   /*
  329.    * Parse the preprocessed file.
  330.    */
  331.   for (tmp = config; (end = get_concat_line (tmp, &line)); tmp = end)
  332.     {
  333.       char *cp;
  334.       int assign = 0;
  335.  
  336.       if (!*tmp)        /* ignore blank lines */
  337.     continue;
  338.  
  339.       tmp = resolve_string (tmp, linebuf, sizeof (linebuf));
  340.  
  341.       cp = strpbrk (tmp, " =");
  342.       if (cp)
  343.     {
  344.       if (*cp == '=')
  345.         assign = 1;
  346.       else
  347.         {
  348.  
  349.           if (cp[1] == '=')
  350.         {
  351.           assign = 1;
  352.           *cp = '\0';
  353.           ++cp;
  354.         }
  355.           else
  356.         assign = 0;
  357.         }
  358.       *cp = '\0';
  359.     }
  360.  
  361.       /*
  362.        * Now interpret the configuration lines
  363.        */
  364.       if (!strcmp (tmp, "keep"))
  365.     {
  366.       if (cp)
  367.         {
  368.           lprintf ("conf:%d: \"keep\" used with argument\n", line);
  369.           return 1;
  370.         }
  371.       drop_default_paths = 0;
  372.     }
  373.       else if (!strcmp (tmp, "insmod_opt"))
  374.     {
  375.       if (!assign)
  376.         {
  377.           lprintf ("conf:%d: \"insmod_opt\" not within assignment\n", line);
  378.           return 1;
  379.         }
  380.       if (!cp)
  381.         return error_missing_argument (line);
  382.       tmp = cp + 1;
  383.       insmod_opts = xstrdup (tmp);
  384.     }
  385.       else if (!strcmp (tmp, "depfile"))
  386.     {
  387.       if (!assign)
  388.         {
  389.           lprintf ("conf:%d: depfile not within assignment\n", line);
  390.           return 1;
  391.         }
  392.       if (!cp)
  393.         return error_missing_argument (line);
  394.       tmp = cp + 1;
  395.       free (depfile_tmp);
  396.       depfile_tmp = xstrdup (tmp);
  397.     }
  398.       else if (!strcmp (tmp, "options"))
  399.     {
  400.       if (assign)
  401.         {
  402.           lprintf ("conf:%d: options used in assignment\n", line);
  403.           return 1;
  404.         }
  405.       if (!cp)
  406.         return error_missing_argument (line);
  407.       tmp = cp + 1;
  408.       cp = strchr (tmp, ' ');
  409.       if (!cp)
  410.         {
  411.           lprintf ("conf:%d: missing module argument\n", line);
  412.           return 1;
  413.         }
  414.       *cp = '\0';
  415.  
  416.       if (!strcmp(tmp, "-k")) 
  417.         {
  418.           tmp = cp + 1;
  419.           cp = strchr (tmp, ' ');
  420.     
  421.           if (cp)
  422.         {
  423.           *cp = '\0';
  424.           add_option (tmp, cp + 1, 0);
  425.         }
  426.           else
  427.         {
  428.           add_option (tmp, NULL, 0);
  429.         }
  430.         }
  431.       else
  432.         {
  433.           add_option (tmp, cp + 1, 1);
  434.         }
  435.     }
  436.       else if (!strcmp (tmp, "alias"))
  437.     {
  438.       if (assign)
  439.         {
  440.           lprintf ("conf:%d: alias used in assignment\n", line);
  441.           return 1;
  442.         }
  443.       if (!cp)
  444.         return error_missing_argument (line);
  445.       tmp = cp + 1;
  446.       cp = strchr (tmp, ' ');
  447.       if (!cp)
  448.         return error_missing_argument (line);
  449.       *cp = '\0';
  450.  
  451.       if (strchr (cp, ' '))
  452.         {
  453.           lprintf ("conf:%d: ambigious alias requested\n", line);
  454.           return 1;
  455.         }
  456.       add_alias (tmp, cp + 1);
  457.     }
  458.       else if (!strcmp (tmp, "pre-install"))
  459.     {
  460.       if (expect_action (line, assign, PRE_INSTALL, cp, &tmp))
  461.         return 1;
  462.     }
  463.       else if (!strcmp (tmp, "install"))
  464.     {
  465.       if (expect_action (line, assign, INSTALL, cp, &tmp))
  466.         return 1;
  467.     }
  468.       else if (!strcmp (tmp, "post-install"))
  469.     {
  470.       if (expect_action (line, assign, POST_INSTALL, cp, &tmp))
  471.         return 1;
  472.     }
  473.       else if (!strcmp (tmp, "pre-remove"))
  474.     {
  475.       if (expect_action (line, assign, PRE_REMOVE, cp, &tmp))
  476.         return 1;
  477.     }
  478.       else if (!strcmp (tmp, "remove"))
  479.     {
  480.       if (expect_action (line, assign, REMOVE, cp, &tmp))
  481.         return 1;
  482.     }
  483.       else if (!strcmp (tmp, "post-remove"))
  484.     {
  485.       if (expect_action (line, assign, POST_REMOVE, cp, &tmp))
  486.         return 1;
  487.     }
  488.       else if (strstr (tmp, "path") == tmp)
  489.     {
  490.       if (!assign)
  491.         {
  492.           lprintf ("conf:%d: path not within assignment\n", line);
  493.           return 1;
  494.         }
  495.       if (!cp)
  496.         return error_missing_argument (line);
  497.       if (strchr (tmp, '['))
  498.         {
  499.           char *type;
  500.  
  501.           if (tmp != strstr (tmp, "path["))
  502.         {
  503.           lprintf ("conf:%d: syntax error \"%s\"\n", line, tmp);
  504.           return 1;
  505.         }
  506.           type = strchr (tmp, '[') + 1;
  507.           if (!(tmp = strchr (tmp, ']')))
  508.         {
  509.           lprintf ("conf:%d: missing \"]\"\n", line);
  510.           return 1;
  511.         }
  512.           *tmp = '\0';
  513.           if (tmp == type)
  514.         {
  515.           lprintf ("conf:%d: empty cathegory in path[...]\n", line);
  516.           return 1;
  517.         }
  518.           if (drop_default_paths)
  519.           {
  520.         /* We only do it once. */
  521.         drop_default_paths = 0;
  522.         release_all_sets ();
  523.           }
  524.           add_set (cp + 1);
  525.           add_type (mod_set, type);
  526.         }
  527.       else
  528.         {
  529.           char **type;
  530.  
  531.           if (strcmp (tmp, "path"))
  532.         {
  533.           lprintf ("conf:%d: unknown keyword \"%s\"\n", line, tmp);
  534.           return 1;
  535.         }
  536.           if (drop_default_paths)
  537.           {
  538.         /* We only do it once. */
  539.         drop_default_paths = 0;
  540.         release_all_sets ();
  541.           }
  542.           add_set (cp + 1);
  543.           /*
  544.            * And now add all default types to this set.
  545.            */
  546.           for (type = default_types; *type; ++type)
  547.         add_type (mod_set, *type);
  548.         }
  549.     }
  550.       else
  551.     {
  552.       lprintf ("conf:%d: unknown keyword \"%s\"\n", line, tmp);
  553.       return 1;
  554.     }
  555.     }
  556.   free (config);
  557.  
  558.   /*
  559.    * If the dependancy file wasn't specified by the configuration file and
  560.    * we where not forced to use one special, then give a default:
  561.    */
  562.   if (!*depfile_tmp)
  563.     {
  564.       if (kernel_ver)
  565.     tmp = kernel_ver;
  566.       else
  567.     {
  568.       uname (&uts_info);
  569.       tmp = uts_info.release;
  570.     }
  571.       free (depfile_tmp);
  572.       depfile_tmp = (char *) xmalloc (strlen ("/lib/modules//modules.dep") +
  573.                       strlen (tmp) + 1);
  574.       strcpy (depfile_tmp, "/lib/modules/");
  575.       strcat (depfile_tmp, tmp);
  576.       strcat (depfile_tmp, "/modules.dep");
  577.     }
  578.   depfile = depfile_tmp;
  579.  
  580.   return 0;
  581. }
  582.  
  583. /*
  584.  * Find all modules matching the globbing pattern "match" in directoryies of
  585.  * type "type". "many" specifies if we are looking for all possible matches
  586.  * or only the first one.
  587.  */
  588. struct mod_path *
  589. find_matching_mods (const char *match, const char *type, int many)
  590. {
  591.   struct mod_set *set;
  592.   struct mod_path *it = NULL;
  593.  
  594.   /*
  595.    * Go through all classes looking for the type.
  596.    */
  597.   for (set = mod_set; set; set = set->next)
  598.     {
  599.       struct mod_type *t;
  600.       for (t = set->types; t; t = t->next)
  601.     if (!type || !strcmp (type, t->type))
  602.       {
  603.         struct stat statb;
  604.         DIR *dp;
  605.         struct dirent *ep;
  606.         char *dir = (char *) xmalloc (strlen (set->set)
  607.                       + strlen (t->type) + 2);
  608.         strcpy (dir, set->set);
  609.         strcat (dir, "/");
  610.         strcat (dir, t->type);
  611.  
  612.         /*
  613.          * OK. Now we know where to search. Go through the contents of this
  614.          * directory and search for matches.
  615.          */
  616.  
  617.         dp = opendir (dir);
  618.         if (dp)
  619.           while ((ep = readdir (dp)))
  620.         {
  621.           /*
  622.            * Look if it's a regular file!
  623.            */
  624.           char *file = (char *) xmalloc (strlen (dir)
  625.                          + strlen (ep->d_name) + 2);
  626.           strcpy (file, dir);
  627.           strcat (file, "/");
  628.           strcat (file, ep->d_name);
  629.  
  630.           /*
  631.            * Check if it's a regular file and we have the permissions
  632.            * to access it.
  633.            */
  634.           if (stat (file, &statb) == -1
  635.               || (statb.st_mode & S_IFMT) != S_IFREG
  636.               || access (file, R_OK))
  637.             {
  638.               free (file);
  639.               continue;
  640.             }
  641.  
  642.           /*
  643.            * And now check if it is matching our search pattern
  644.            */
  645.  
  646.           if (!fnmatch (match, ep->d_name, FNM_PERIOD))
  647.             {
  648.               struct mod_path *tmp =
  649.               (struct mod_path *) xmalloc (sizeof (struct mod_path));
  650.               tmp->next = it;
  651.               tmp->path = file;
  652.               it = tmp;
  653.  
  654.               if (!many)    /* search only for the first match */
  655.             {
  656.               free (dir);
  657.               return it;
  658.             }
  659.             }
  660.           else
  661.             free (file);
  662.         }
  663.         free (dir);
  664.       }
  665.     }
  666.  
  667.   return it;
  668. }
  669.  
  670. /*
  671.  * Print out the currently active configuration.
  672.  */
  673. void
  674. print_active_config (void)
  675. {
  676.   struct mod_set *set;
  677.   struct mod_option *opt;
  678.   struct mod_alias *alias;
  679.   struct action *action;
  680.  
  681.   printf ("# This file was generated by: modprobe -c (" MODUTILS_VERSION ")\n");
  682.  
  683.   /*
  684.    * Go through all classes looking for the type.
  685.    */
  686.  
  687.   for (set = mod_set; set; set = set->next)
  688.     {
  689.       struct mod_type *t;
  690.       if ((t = set->types))
  691.     while (t)
  692.       {
  693.         printf ("path[%s]=%s\n", t->type, set->set);
  694.         t = t->next;
  695.       }
  696.       else
  697.     printf ("path=%s\n", set->set);
  698.     }
  699.   puts ("# Aliases");
  700.   for (alias = mod_alias; alias; alias = alias->next)
  701.     printf ("alias %s %s\n", alias->name, alias->alias);
  702.   puts ("# Options");
  703.   for (opt = mod_options; opt; opt = opt->next)
  704.     printf ("options %s %s\n", opt->module, opt->args);
  705.  
  706.   if (mod_action)
  707.     {
  708.       puts ("# Commands");
  709.       for (action = mod_action; action; action = action->next)
  710.     {
  711.       switch (action->when)
  712.         {
  713.         case PRE_INSTALL:
  714.           printf ("pre-install ");
  715.           break;
  716.         case INSTALL:
  717.           printf ("install ");
  718.           break;
  719.         case POST_INSTALL:
  720.           printf ("post-install ");
  721.           break;
  722.         case PRE_REMOVE:
  723.           printf ("pre-remove ");
  724.           break;
  725.         case REMOVE:
  726.           printf ("remove ");
  727.           break;
  728.         case POST_REMOVE:
  729.           printf ("post-remove ");
  730.           break;
  731.         }
  732.       printf ("%s %s\n", action->module, action->cmd);
  733.     }
  734.     }
  735. }
  736.  
  737. /*
  738.  * Look for a command associated with this action.
  739.  */
  740. char *
  741. find_assoc_cmd (enum command when, char *mod)
  742. {
  743.   char *modname = strip_o (mod);
  744.   struct action *action;
  745.  
  746.   for (action = mod_action; action; action = action->next)
  747.     if ((action->when == when) && !strcmp (action->module, modname))
  748.       {
  749.     free (modname);
  750.     return action->cmd;
  751.       }
  752.  
  753.   free (modname);
  754.   return NULL;
  755. }
  756.  
  757. /*
  758.  * Check if a module name is indeed an alias for another module.
  759.  * Return the real module or this one (mod) if it is not an alias
  760.  */
  761. static char *
  762. translate_alias (char *mod)
  763. {
  764.   struct mod_alias *alias;
  765.   char *modname = strip_o (mod);
  766.  
  767.   for (alias = mod_alias; alias; alias = alias->next)
  768.     if (!strcmp (alias->name, modname))
  769.       {
  770.     free (modname);
  771.     return alias->alias;
  772.       }
  773.  
  774.   free (modname);
  775.   return mod;
  776. }
  777.  
  778.  
  779. /*
  780.  *  Locate all modules matching the "match".
  781.  */
  782. struct mod_path *
  783. locate_mod_obj (char *match, char *type)
  784. {
  785.   struct mod_path *it = NULL;
  786.   char *match_o;
  787.  
  788.   if (strchr (match, '/') != NULL)
  789.     {
  790.       /*
  791.        * Absolute path. Don't search any further!
  792.        */
  793.  
  794.       it = (struct mod_path *) xmalloc (sizeof (struct mod_path));
  795.       it->next = NULL;
  796.       it->path = xstrdup (match);
  797.       return it;
  798.     }
  799.  
  800.   match = translate_alias (match);
  801.   if (!match || !(*match))
  802.     return NULL;
  803.   if (!strcmp (match, "off"))
  804.     return (void *) (-1);
  805.  
  806.   match_o = (char *) xmalloc (strlen (match) + 3);
  807.   strcpy (match_o, match);
  808.   strcat (match_o, ".o");
  809.  
  810.   it = find_matching_mods (match_o, type, 0);
  811.   free (match_o);
  812.  
  813.   if (!it)
  814.     if (!(it = find_matching_mods (match, type, 0)))
  815.       return NULL;
  816.  
  817.   return it;
  818. }
  819.