The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/boot/common/module.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 /*
   31  * file/module function dispatcher, support, etc.
   32  */
   33 
   34 #include <stand.h>
   35 #include <string.h>
   36 #include <sys/param.h>
   37 #include <sys/linker.h>
   38 #include <sys/module.h>
   39 #include <sys/queue.h>
   40 
   41 #include "bootstrap.h"
   42 
   43 #define MDIR_REMOVED    0x0001
   44 #define MDIR_NOHINTS    0x0002
   45 
   46 struct moduledir {
   47         char    *d_path;        /* path of modules directory */
   48         u_char  *d_hints;       /* content of linker.hints file */
   49         int     d_hintsz;       /* size of hints data */
   50         int     d_flags;
   51         STAILQ_ENTRY(moduledir) d_link;
   52 };
   53 
   54 static int                      file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
   55 static int                      file_loadraw(char *type, char *name);
   56 static int                      file_load_dependencies(struct preloaded_file *base_mod);
   57 static char *                   file_search(const char *name, char **extlist);
   58 static struct kernel_module *   file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
   59 static int                      file_havepath(const char *name);
   60 static char                     *mod_searchmodule(char *name, struct mod_depend *verinfo);
   61 static void                     file_insert_tail(struct preloaded_file *mp);
   62 struct file_metadata*           metadata_next(struct file_metadata *base_mp, int type);
   63 static void                     moduledir_readhints(struct moduledir *mdp);
   64 static void                     moduledir_rebuild(void);
   65 
   66 /* load address should be tweaked by first module loaded (kernel) */
   67 static vm_offset_t      loadaddr = 0;
   68 
   69 static const char       *default_searchpath ="/boot/kernel;/boot/modules";
   70 
   71 static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list);
   72 
   73 struct preloaded_file *preloaded_files = NULL;
   74 
   75 static char *kld_ext_list[] = {
   76     ".ko",
   77     "",
   78     ".debug",
   79     NULL
   80 };
   81 
   82 
   83 /*
   84  * load an object, either a disk file or code module.
   85  *
   86  * To load a file, the syntax is:
   87  *
   88  * load -t <type> <path>
   89  *
   90  * code modules are loaded as:
   91  *
   92  * load <path> <options>
   93  */
   94 
   95 COMMAND_SET(load, "load", "load a kernel or module", command_load);
   96 
   97 static int
   98 command_load(int argc, char *argv[])
   99 {
  100     char        *typestr;
  101     int         dofile, dokld, ch, error;
  102     
  103     dokld = dofile = 0;
  104     optind = 1;
  105     optreset = 1;
  106     typestr = NULL;
  107     if (argc == 1) {
  108         command_errmsg = "no filename specified";
  109         return(CMD_ERROR);
  110     }
  111     while ((ch = getopt(argc, argv, "kt:")) != -1) {
  112         switch(ch) {
  113         case 'k':
  114             dokld = 1;
  115             break;
  116         case 't':
  117             typestr = optarg;
  118             dofile = 1;
  119             break;
  120         case '?':
  121         default:
  122             /* getopt has already reported an error */
  123             return(CMD_OK);
  124         }
  125     }
  126     argv += (optind - 1);
  127     argc -= (optind - 1);
  128 
  129     /*
  130      * Request to load a raw file?
  131      */
  132     if (dofile) {
  133         if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) {
  134             command_errmsg = "invalid load type";
  135             return(CMD_ERROR);
  136         }
  137         return(file_loadraw(typestr, argv[1]));
  138     }
  139     /*
  140      * Do we have explicit KLD load ?
  141      */
  142     if (dokld || file_havepath(argv[1])) {
  143         error = mod_loadkld(argv[1], argc - 2, argv + 2);
  144         if (error == EEXIST)
  145             sprintf(command_errbuf, "warning: KLD '%s' already loaded", argv[1]);
  146         return (error == 0 ? CMD_OK : CMD_ERROR);
  147     }
  148     /*
  149      * Looks like a request for a module.
  150      */
  151     error = mod_load(argv[1], NULL, argc - 2, argv + 2);
  152     if (error == EEXIST)
  153         sprintf(command_errbuf, "warning: module '%s' already loaded", argv[1]);
  154     return (error == 0 ? CMD_OK : CMD_ERROR);
  155 }
  156 
  157 COMMAND_SET(unload, "unload", "unload all modules", command_unload);
  158 
  159 static int
  160 command_unload(int argc, char *argv[])
  161 {
  162     struct preloaded_file       *fp;
  163     
  164     while (preloaded_files != NULL) {
  165         fp = preloaded_files;
  166         preloaded_files = preloaded_files->f_next;
  167         file_discard(fp);
  168     }
  169     loadaddr = 0;
  170     unsetenv("kernelname");
  171     return(CMD_OK);
  172 }
  173 
  174 COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
  175 
  176 static int
  177 command_lsmod(int argc, char *argv[])
  178 {
  179     struct preloaded_file       *fp;
  180     struct kernel_module        *mp;
  181     struct file_metadata        *md;
  182     char                        lbuf[80];
  183     int                         ch, verbose;
  184 
  185     verbose = 0;
  186     optind = 1;
  187     optreset = 1;
  188     while ((ch = getopt(argc, argv, "v")) != -1) {
  189         switch(ch) {
  190         case 'v':
  191             verbose = 1;
  192             break;
  193         case '?':
  194         default:
  195             /* getopt has already reported an error */
  196             return(CMD_OK);
  197         }
  198     }
  199 
  200     pager_open();
  201     for (fp = preloaded_files; fp; fp = fp->f_next) {
  202         sprintf(lbuf, " %p: %s (%s, 0x%lx)\n", 
  203                 (void *) fp->f_addr, fp->f_name, fp->f_type, (long) fp->f_size);
  204         pager_output(lbuf);
  205         if (fp->f_args != NULL) {
  206             pager_output("    args: ");
  207             pager_output(fp->f_args);
  208             pager_output("\n");
  209         }
  210         if (fp->f_modules) {
  211             pager_output("  modules: ");
  212             for (mp = fp->f_modules; mp; mp = mp->m_next) {
  213                 sprintf(lbuf, "%s.%d ", mp->m_name, mp->m_version);
  214                 pager_output(lbuf);
  215             }
  216             pager_output("\n");
  217         }
  218         if (verbose) {
  219             /* XXX could add some formatting smarts here to display some better */
  220             for (md = fp->f_metadata; md != NULL; md = md->md_next) {
  221                 sprintf(lbuf, "      0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
  222                 pager_output(lbuf);
  223             }
  224         }
  225     }
  226     pager_close();
  227     return(CMD_OK);
  228 }
  229 
  230 /*
  231  * File level interface, functions file_*
  232  */
  233 int
  234 file_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
  235 {
  236     struct preloaded_file *fp;
  237     int error;
  238     int i;
  239 
  240     error = EFTYPE;
  241     for (i = 0, fp = NULL; file_formats[i] && fp == NULL; i++) {
  242         error = (file_formats[i]->l_load)(filename, loadaddr, &fp);
  243         if (error == 0) {
  244             fp->f_loader = i;           /* remember the loader */
  245             *result = fp;
  246             break;
  247         }
  248         if (error == EFTYPE)
  249             continue;           /* Unknown to this handler? */
  250         if (error) {
  251             sprintf(command_errbuf, "can't load file '%s': %s",
  252                 filename, strerror(error));
  253             break;
  254         }
  255     }
  256     return (error);
  257 }
  258 
  259 static int
  260 file_load_dependencies(struct preloaded_file *base_file) {
  261     struct file_metadata *md;
  262     struct preloaded_file *fp;
  263     struct mod_depend *verinfo;
  264     struct kernel_module *mp;
  265     char *dmodname;
  266     int error;
  267 
  268     md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
  269     if (md == NULL)
  270         return (0);
  271     error = 0;
  272     do {
  273         verinfo = (struct mod_depend*)md->md_data;
  274         dmodname = (char *)(verinfo + 1);
  275         if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
  276             printf("loading required module '%s'\n", dmodname);
  277             error = mod_load(dmodname, verinfo, 0, NULL);
  278             if (error)
  279                 break;
  280             /*
  281              * If module loaded via kld name which isn't listed
  282              * in the linker.hints file, we should check if it have
  283              * required version.
  284              */
  285             mp = file_findmodule(NULL, dmodname, verinfo);
  286             if (mp == NULL) {
  287                 sprintf(command_errbuf, "module '%s' exists but with wrong version",
  288                     dmodname);
  289                 error = ENOENT;
  290                 break;
  291             }
  292         }
  293         md = metadata_next(md, MODINFOMD_DEPLIST);
  294     } while (md);
  295     if (!error)
  296         return (0);
  297     /* Load failed; discard everything */
  298     while (base_file != NULL) {
  299         fp = base_file;
  300         base_file = base_file->f_next;
  301         file_discard(fp);
  302     }
  303     return (error);
  304 }
  305 /*
  306  * We've been asked to load (name) as (type), so just suck it in,
  307  * no arguments or anything.
  308  */
  309 int
  310 file_loadraw(char *type, char *name)
  311 {
  312     struct preloaded_file       *fp;
  313     char                        *cp;
  314     int                         fd, got;
  315     vm_offset_t                 laddr;
  316 
  317     /* We can't load first */
  318     if ((file_findfile(NULL, NULL)) == NULL) {
  319         command_errmsg = "can't load file before kernel";
  320         return(CMD_ERROR);
  321     }
  322 
  323     /* locate the file on the load path */
  324     cp = file_search(name, NULL);
  325     if (cp == NULL) {
  326         sprintf(command_errbuf, "can't find '%s'", name);
  327         return(CMD_ERROR);
  328     }
  329     name = cp;
  330     
  331     if ((fd = open(name, O_RDONLY)) < 0) {
  332         sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno));
  333         free(name);
  334         return(CMD_ERROR);
  335     }
  336 
  337     laddr = loadaddr;
  338     for (;;) {
  339         /* read in 4k chunks; size is not really important */
  340         got = archsw.arch_readin(fd, laddr, 4096);
  341         if (got == 0)                           /* end of file */
  342             break;
  343         if (got < 0) {                          /* error */
  344             sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno));
  345             free(name);
  346             close(fd);
  347             return(CMD_ERROR);
  348         }
  349         laddr += got;
  350     }
  351     
  352     /* Looks OK so far; create & populate control structure */
  353     fp = file_alloc();
  354     fp->f_name = name;
  355     fp->f_type = strdup(type);
  356     fp->f_args = NULL;
  357     fp->f_metadata = NULL;
  358     fp->f_loader = -1;
  359     fp->f_addr = loadaddr;
  360     fp->f_size = laddr - loadaddr;
  361 
  362     /* recognise space consumption */
  363     loadaddr = laddr;
  364 
  365     /* Add to the list of loaded files */
  366     file_insert_tail(fp);
  367     close(fd);
  368     return(CMD_OK);
  369 }
  370 
  371 /*
  372  * Load the module (name), pass it (argc),(argv), add container file
  373  * to the list of loaded files.
  374  * If module is already loaded just assign new argc/argv.
  375  */
  376 int
  377 mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
  378 {
  379     struct kernel_module        *mp;
  380     int                         err;
  381     char                        *filename;
  382 
  383     if (file_havepath(modname)) {
  384         printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
  385         return (mod_loadkld(modname, argc, argv));
  386     }
  387     /* see if module is already loaded */
  388     mp = file_findmodule(NULL, modname, verinfo);
  389     if (mp) {
  390 #ifdef moduleargs
  391         if (mp->m_args)
  392             free(mp->m_args);
  393         mp->m_args = unargv(argc, argv);
  394 #endif
  395         sprintf(command_errbuf, "warning: module '%s' already loaded", mp->m_name);
  396         return (0);
  397     }
  398     /* locate file with the module on the search path */
  399     filename = mod_searchmodule(modname, verinfo);
  400     if (filename == NULL) {
  401         sprintf(command_errbuf, "can't find '%s'", modname);
  402         return (ENOENT);
  403     }
  404     err = mod_loadkld(filename, argc, argv);
  405     return (err);
  406 }
  407 
  408 /*
  409  * Load specified KLD. If path is omitted, then try to locate it via
  410  * search path.
  411  */
  412 int
  413 mod_loadkld(const char *kldname, int argc, char *argv[])
  414 {
  415     struct preloaded_file       *fp, *last_file;
  416     int                         err;
  417     char                        *filename;
  418 
  419     /*
  420      * Get fully qualified KLD name
  421      */
  422     filename = file_search(kldname, kld_ext_list);
  423     if (filename == NULL) {
  424         sprintf(command_errbuf, "can't find '%s'", kldname);
  425         return (ENOENT);
  426     }
  427     /* 
  428      * Check if KLD already loaded
  429      */
  430     fp = file_findfile(filename, NULL);
  431     if (fp) {
  432         sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename);
  433         free(filename);
  434         return (0);
  435     }
  436     for (last_file = preloaded_files; 
  437          last_file != NULL && last_file->f_next != NULL;
  438          last_file = last_file->f_next)
  439         ;
  440 
  441     do {
  442         err = file_load(filename, loadaddr, &fp);
  443         if (err)
  444             break;
  445         fp->f_args = unargv(argc, argv);
  446         loadaddr = fp->f_addr + fp->f_size;
  447         file_insert_tail(fp);           /* Add to the list of loaded files */
  448         if (file_load_dependencies(fp) != 0) {
  449             err = ENOENT;
  450             last_file->f_next = NULL;
  451             loadaddr = last_file->f_addr + last_file->f_size;
  452             fp = NULL;
  453             break;
  454         }
  455     } while(0);
  456     if (err == EFTYPE)
  457         sprintf(command_errbuf, "don't know how to load module '%s'", filename);
  458     if (err && fp)
  459         file_discard(fp);
  460     free(filename);
  461     return (err);
  462 }
  463 
  464 /*
  465  * Find a file matching (name) and (type).
  466  * NULL may be passed as a wildcard to either.
  467  */
  468 struct preloaded_file *
  469 file_findfile(char *name, char *type)
  470 {
  471     struct preloaded_file *fp;
  472 
  473     for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
  474         if (((name == NULL) || !strcmp(name, fp->f_name)) &&
  475             ((type == NULL) || !strcmp(type, fp->f_type)))
  476             break;
  477     }
  478     return (fp);
  479 }
  480 
  481 /*
  482  * Find a module matching (name) inside of given file.
  483  * NULL may be passed as a wildcard.
  484  */
  485 struct kernel_module *
  486 file_findmodule(struct preloaded_file *fp, char *modname,
  487         struct mod_depend *verinfo)
  488 {
  489     struct kernel_module *mp, *best;
  490     int bestver, mver;
  491 
  492     if (fp == NULL) {
  493         for (fp = preloaded_files; fp; fp = fp->f_next) {
  494             mp = file_findmodule(fp, modname, verinfo);
  495             if (mp)
  496                 return (mp);
  497         }
  498         return (NULL);
  499     }
  500     best = NULL;
  501     bestver = 0;
  502     for (mp = fp->f_modules; mp; mp = mp->m_next) {
  503         if (strcmp(modname, mp->m_name) == 0) {
  504             if (verinfo == NULL)
  505                 return (mp);
  506             mver = mp->m_version;
  507             if (mver == verinfo->md_ver_preferred)
  508                 return (mp);
  509             if (mver >= verinfo->md_ver_minimum && 
  510                 mver <= verinfo->md_ver_maximum &&
  511                 mver > bestver) {
  512                 best = mp;
  513                 bestver = mver;
  514             }
  515         }
  516     }
  517     return (best);
  518 }
  519 /*
  520  * Make a copy of (size) bytes of data from (p), and associate them as
  521  * metadata of (type) to the module (mp).
  522  */
  523 void
  524 file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
  525 {
  526     struct file_metadata        *md;
  527 
  528     md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
  529     md->md_size = size;
  530     md->md_type = type;
  531     bcopy(p, md->md_data, size);
  532     md->md_next = fp->f_metadata;
  533     fp->f_metadata = md;
  534 }
  535 
  536 /*
  537  * Find a metadata object of (type) associated with the file (fp)
  538  */
  539 struct file_metadata *
  540 file_findmetadata(struct preloaded_file *fp, int type)
  541 {
  542     struct file_metadata *md;
  543 
  544     for (md = fp->f_metadata; md != NULL; md = md->md_next)
  545         if (md->md_type == type)
  546             break;
  547     return(md);
  548 }
  549 
  550 struct file_metadata *
  551 metadata_next(struct file_metadata *md, int type)
  552 {
  553     if (md == NULL)
  554         return (NULL);
  555     while((md = md->md_next) != NULL)
  556         if (md->md_type == type)
  557             break;
  558     return (md);
  559 }
  560 
  561 static char *emptyextlist[] = { "", NULL };
  562 
  563 /*
  564  * Check if the given file is in place and return full path to it.
  565  */
  566 static char *
  567 file_lookup(const char *path, const char *name, int namelen, char **extlist)
  568 {
  569     struct stat st;
  570     char        *result, *cp, **cpp;
  571     int         pathlen, extlen, len;
  572 
  573     pathlen = strlen(path);
  574     extlen = 0;
  575     if (extlist == NULL)
  576         extlist = emptyextlist;
  577     for (cpp = extlist; *cpp; cpp++) {
  578         len = strlen(*cpp);
  579         if (len > extlen)
  580             extlen = len;
  581     }
  582     result = malloc(pathlen + namelen + extlen + 2);
  583     if (result == NULL)
  584         return (NULL);
  585     bcopy(path, result, pathlen);
  586     if (pathlen > 0 && result[pathlen - 1] != '/')
  587         result[pathlen++] = '/';
  588     cp = result + pathlen;
  589     bcopy(name, cp, namelen);
  590     cp += namelen;
  591     for (cpp = extlist; *cpp; cpp++) {
  592         strcpy(cp, *cpp);
  593         if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
  594             return result;
  595     }
  596     free(result);
  597     return NULL;
  598 }
  599 
  600 /*
  601  * Check if file name have any qualifiers
  602  */
  603 static int
  604 file_havepath(const char *name)
  605 {
  606     const char          *cp;
  607 
  608     archsw.arch_getdev(NULL, name, &cp);
  609     return (cp != name || strchr(name, '/') != NULL);
  610 }
  611 
  612 /*
  613  * Attempt to find the file (name) on the module searchpath.
  614  * If (name) is qualified in any way, we simply check it and
  615  * return it or NULL.  If it is not qualified, then we attempt
  616  * to construct a path using entries in the environment variable
  617  * module_path.
  618  *
  619  * The path we return a pointer to need never be freed, as we manage
  620  * it internally.
  621  */
  622 static char *
  623 file_search(const char *name, char **extlist)
  624 {
  625     struct moduledir    *mdp;
  626     struct stat         sb;
  627     char                *result;
  628     int                 namelen;
  629 
  630     /* Don't look for nothing */
  631     if (name == NULL)
  632         return(NULL);
  633 
  634     if (*name == 0)
  635         return(strdup(name));
  636 
  637     if (file_havepath(name)) {
  638         /* Qualified, so just see if it exists */
  639         if (stat(name, &sb) == 0)
  640             return(strdup(name));
  641         return(NULL);
  642     }
  643     moduledir_rebuild();
  644     result = NULL;
  645     namelen = strlen(name);
  646     STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
  647         result = file_lookup(mdp->d_path, name, namelen, extlist);
  648         if (result)
  649             break;
  650     }
  651     return(result);
  652 }
  653 
  654 #define INT_ALIGN(base, ptr)    ptr = \
  655         (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
  656 
  657 static char *
  658 mod_search_hints(struct moduledir *mdp, const char *modname,
  659         struct mod_depend *verinfo)
  660 {
  661     u_char      *cp, *recptr, *bufend, *best;
  662     char        *result;
  663     int         *intp, bestver, blen, clen, found, ival, modnamelen, reclen;
  664 
  665     moduledir_readhints(mdp);
  666     modnamelen = strlen(modname);
  667     found = 0;
  668     result = NULL;
  669     bestver = 0;
  670     if (mdp->d_hints == NULL)
  671         goto bad;
  672     recptr = mdp->d_hints;
  673     bufend = recptr + mdp->d_hintsz;
  674     clen = blen = 0;
  675     best = cp = NULL;
  676     while (recptr < bufend && !found) {
  677         intp = (int*)recptr;
  678         reclen = *intp++;
  679         ival = *intp++;
  680         cp = (char*)intp;
  681         switch (ival) {
  682         case MDT_VERSION:
  683             clen = *cp++;
  684             if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
  685                 break;
  686             cp += clen;
  687             INT_ALIGN(mdp->d_hints, cp);
  688             ival = *(int*)cp;
  689             cp += sizeof(int);
  690             clen = *cp++;
  691             if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
  692                 found = 1;
  693                 break;
  694             }
  695             if (ival >= verinfo->md_ver_minimum && 
  696                 ival <= verinfo->md_ver_maximum &&
  697                 ival > bestver) {
  698                 bestver = ival;
  699                 best = cp;
  700                 blen = clen;
  701             }
  702             break;
  703         default:
  704             break;
  705         }
  706         recptr += reclen + sizeof(int);
  707     }
  708     /*
  709      * Finally check if KLD is in the place
  710      */
  711     if (found)
  712         result = file_lookup(mdp->d_path, cp, clen, NULL);
  713     else if (best)
  714         result = file_lookup(mdp->d_path, best, blen, NULL);
  715 bad:
  716     /*
  717      * If nothing found or hints is absent - fallback to the old way
  718      * by using "kldname[.ko]" as module name.
  719      */
  720     if (!found && !bestver && result == NULL)
  721         result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
  722     return result;
  723 }
  724 
  725 /*
  726  * Attempt to locate the file containing the module (name)
  727  */
  728 static char *
  729 mod_searchmodule(char *name, struct mod_depend *verinfo)
  730 {
  731     struct      moduledir *mdp;
  732     char        *result;
  733 
  734     moduledir_rebuild();
  735     /*
  736      * Now we ready to lookup module in the given directories
  737      */
  738     result = NULL;
  739     STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
  740         result = mod_search_hints(mdp, name, verinfo);
  741         if (result)
  742             break;
  743     }
  744 
  745     return(result);
  746 }
  747 
  748 int
  749 file_addmodule(struct preloaded_file *fp, char *modname, int version,
  750         struct kernel_module **newmp)
  751 {
  752     struct kernel_module *mp;
  753     struct mod_depend mdepend;
  754 
  755     bzero(&mdepend, sizeof(mdepend));
  756     mdepend.md_ver_preferred = version;
  757     mp = file_findmodule(fp, modname, &mdepend);
  758     if (mp)
  759         return (EEXIST);
  760     mp = malloc(sizeof(struct kernel_module));
  761     if (mp == NULL)
  762         return (ENOMEM);
  763     bzero(mp, sizeof(struct kernel_module));
  764     mp->m_name = strdup(modname);
  765     mp->m_version = version;
  766     mp->m_fp = fp;
  767     mp->m_next = fp->f_modules;
  768     fp->f_modules = mp;
  769     if (newmp)
  770         *newmp = mp;
  771     return (0);
  772 }
  773 
  774 /*
  775  * Throw a file away
  776  */
  777 void
  778 file_discard(struct preloaded_file *fp)
  779 {
  780     struct file_metadata        *md, *md1;
  781     struct kernel_module        *mp, *mp1;
  782     if (fp == NULL)
  783         return;
  784     md = fp->f_metadata;
  785     while (md) {
  786         md1 = md;
  787         md = md->md_next;
  788         free(md1);
  789     }
  790     mp = fp->f_modules;
  791     while (mp) {
  792         if (mp->m_name)
  793             free(mp->m_name);
  794         mp1 = mp;
  795         mp = mp->m_next;
  796         free(mp1);
  797     }   
  798     if (fp->f_name != NULL)
  799         free(fp->f_name);
  800     if (fp->f_type != NULL)
  801         free(fp->f_type);
  802     if (fp->f_args != NULL)
  803         free(fp->f_args);
  804     free(fp);
  805 }
  806 
  807 /*
  808  * Allocate a new file; must be used instead of malloc()
  809  * to ensure safe initialisation.
  810  */
  811 struct preloaded_file *
  812 file_alloc(void)
  813 {
  814     struct preloaded_file       *fp;
  815     
  816     if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
  817         bzero(fp, sizeof(struct preloaded_file));
  818     }
  819     return (fp);
  820 }
  821 
  822 /*
  823  * Add a module to the chain
  824  */
  825 static void
  826 file_insert_tail(struct preloaded_file *fp)
  827 {
  828     struct preloaded_file       *cm;
  829     
  830     /* Append to list of loaded file */
  831     fp->f_next = NULL;
  832     if (preloaded_files == NULL) {
  833         preloaded_files = fp;
  834     } else {
  835         for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
  836             ;
  837         cm->f_next = fp;
  838     }
  839 }
  840 
  841 static char *
  842 moduledir_fullpath(struct moduledir *mdp, const char *fname)
  843 {
  844     char *cp;
  845 
  846     cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
  847     if (cp == NULL)
  848         return NULL;
  849     strcpy(cp, mdp->d_path);
  850     strcat(cp, "/");
  851     strcat(cp, fname);
  852     return (cp);
  853 }
  854 
  855 /*
  856  * Read linker.hints file into memory performing some sanity checks.
  857  */
  858 static void
  859 moduledir_readhints(struct moduledir *mdp)
  860 {
  861     struct stat st;
  862     char        *path;
  863     int         fd, size, version;
  864 
  865     if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
  866         return;
  867     path = moduledir_fullpath(mdp, "linker.hints");
  868     if (stat(path, &st) != 0 ||
  869         st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
  870         st.st_size > 100 * 1024 || (fd = open(path, O_RDONLY)) < 0) {
  871         free(path);
  872         mdp->d_flags |= MDIR_NOHINTS;
  873         return;
  874     }
  875     free(path);
  876     size = read(fd, &version, sizeof(version));
  877     if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
  878         goto bad;
  879     size = st.st_size - size;
  880     mdp->d_hints = malloc(size);
  881     if (mdp->d_hints == NULL)
  882         goto bad;
  883     if (read(fd, mdp->d_hints, size) != size)
  884         goto bad;
  885     mdp->d_hintsz = size;
  886     close(fd);
  887     return;
  888 bad:
  889     close(fd);
  890     if (mdp->d_hints) {
  891         free(mdp->d_hints);
  892         mdp->d_hints = NULL;
  893     }
  894     mdp->d_flags |= MDIR_NOHINTS;
  895     return;
  896 }
  897 
  898 /*
  899  * Extract directories from the ';' separated list, remove duplicates.
  900  */
  901 static void
  902 moduledir_rebuild(void)
  903 {
  904     struct      moduledir *mdp, *mtmp;
  905     const char  *path, *cp, *ep;
  906     int         cplen;
  907 
  908     path = getenv("module_path");
  909     if (path == NULL)
  910         path = default_searchpath;
  911     /*
  912      * Rebuild list of module directories if it changed
  913      */
  914     STAILQ_FOREACH(mdp, &moduledir_list, d_link)
  915         mdp->d_flags |= MDIR_REMOVED;
  916 
  917     for (ep = path; *ep != 0;  ep++) {
  918         cp = ep;
  919         for (; *ep != 0 && *ep != ';'; ep++)
  920             ;
  921         /*
  922          * Ignore trailing slashes
  923          */
  924         for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
  925             ;
  926         STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
  927             if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
  928                 continue;
  929             mdp->d_flags &= ~MDIR_REMOVED;
  930             break;
  931         }
  932         if (mdp == NULL) {
  933             mdp = malloc(sizeof(*mdp) + cplen + 1);
  934             if (mdp == NULL)
  935                 return;
  936             mdp->d_path = (char*)(mdp + 1);
  937             bcopy(cp, mdp->d_path, cplen);
  938             mdp->d_path[cplen] = 0;
  939             mdp->d_hints = NULL;
  940             mdp->d_flags = 0;
  941             STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
  942         }
  943         if (*ep == 0)
  944             break;
  945     }
  946     /*
  947      * Delete unused directories if any
  948      */
  949     mdp = STAILQ_FIRST(&moduledir_list);
  950     while (mdp) {
  951         if ((mdp->d_flags & MDIR_REMOVED) == 0) {
  952             mdp = STAILQ_NEXT(mdp, d_link);
  953         } else {
  954             if (mdp->d_hints)
  955                 free(mdp->d_hints);
  956             mtmp = mdp;
  957             mdp = STAILQ_NEXT(mdp, d_link);
  958             STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
  959             free(mtmp);
  960         }
  961     }
  962     return;
  963 }

Cache object: 46cc3ebbfed547226e1a2acc87f26598


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.