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