]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/common/module.c
Update llvm, clang and lldb to trunk r257626, and update build glue.
[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 (name) as (type), so just suck it in,
392  * no arguments or anything.
393  */
394 struct preloaded_file *
395 file_loadraw(char *name, char *type, int insert)
396 {
397     struct preloaded_file       *fp;
398     char                        *cp;
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     cp = file_search(name, NULL);
410     if (cp == NULL) {
411         sprintf(command_errbuf, "can't find '%s'", name);
412         return(NULL);
413     }
414     name = cp;
415
416     if ((fd = open(name, O_RDONLY)) < 0) {
417         sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno));
418         free(name);
419         return(NULL);
420     }
421
422     if (archsw.arch_loadaddr != NULL)
423         loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
424
425     printf("%s ", name);
426
427     laddr = loadaddr;
428     for (;;) {
429         /* read in 4k chunks; size is not really important */
430         got = archsw.arch_readin(fd, laddr, 4096);
431         if (got == 0)                           /* end of file */
432             break;
433         if (got < 0) {                          /* error */
434             sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno));
435             free(name);
436             close(fd);
437             return(NULL);
438         }
439         laddr += got;
440     }
441
442     printf("size=%#jx\n", (uintmax_t)(laddr - loadaddr));
443
444     /* Looks OK so far; create & populate control structure */
445     fp = file_alloc();
446     fp->f_name = strdup(name);
447     fp->f_type = strdup(type);
448     fp->f_args = NULL;
449     fp->f_metadata = NULL;
450     fp->f_loader = -1;
451     fp->f_addr = loadaddr;
452     fp->f_size = laddr - loadaddr;
453
454     /* recognise space consumption */
455     loadaddr = laddr;
456
457     /* Add to the list of loaded files */
458     if (insert != 0)
459         file_insert_tail(fp);
460     close(fd);
461     return(fp);
462 }
463
464 /*
465  * Load the module (name), pass it (argc),(argv), add container file
466  * to the list of loaded files.
467  * If module is already loaded just assign new argc/argv.
468  */
469 int
470 mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
471 {
472     struct kernel_module        *mp;
473     int                         err;
474     char                        *filename;
475
476     if (file_havepath(modname)) {
477         printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
478         return (mod_loadkld(modname, argc, argv));
479     }
480     /* see if module is already loaded */
481     mp = file_findmodule(NULL, modname, verinfo);
482     if (mp) {
483 #ifdef moduleargs
484         if (mp->m_args)
485             free(mp->m_args);
486         mp->m_args = unargv(argc, argv);
487 #endif
488         sprintf(command_errbuf, "warning: module '%s' already loaded", mp->m_name);
489         return (0);
490     }
491     /* locate file with the module on the search path */
492     filename = mod_searchmodule(modname, verinfo);
493     if (filename == NULL) {
494         sprintf(command_errbuf, "can't find '%s'", modname);
495         return (ENOENT);
496     }
497     err = mod_loadkld(filename, argc, argv);
498     return (err);
499 }
500
501 /*
502  * Load specified KLD. If path is omitted, then try to locate it via
503  * search path.
504  */
505 int
506 mod_loadkld(const char *kldname, int argc, char *argv[])
507 {
508     struct preloaded_file       *fp, *last_file;
509     int                         err;
510     char                        *filename;
511
512     /*
513      * Get fully qualified KLD name
514      */
515     filename = file_search(kldname, kld_ext_list);
516     if (filename == NULL) {
517         sprintf(command_errbuf, "can't find '%s'", kldname);
518         return (ENOENT);
519     }
520     /* 
521      * Check if KLD already loaded
522      */
523     fp = file_findfile(filename, NULL);
524     if (fp) {
525         sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename);
526         free(filename);
527         return (0);
528     }
529     for (last_file = preloaded_files; 
530          last_file != NULL && last_file->f_next != NULL;
531          last_file = last_file->f_next)
532         ;
533
534     do {
535         err = file_load(filename, loadaddr, &fp);
536         if (err)
537             break;
538         fp->f_args = unargv(argc, argv);
539         loadaddr = fp->f_addr + fp->f_size;
540         file_insert_tail(fp);           /* Add to the list of loaded files */
541         if (file_load_dependencies(fp) != 0) {
542             err = ENOENT;
543             last_file->f_next = NULL;
544             loadaddr = last_file->f_addr + last_file->f_size;
545             fp = NULL;
546             break;
547         }
548     } while(0);
549     if (err == EFTYPE)
550         sprintf(command_errbuf, "don't know how to load module '%s'", filename);
551     if (err && fp)
552         file_discard(fp);
553     free(filename);
554     return (err);
555 }
556
557 /*
558  * Find a file matching (name) and (type).
559  * NULL may be passed as a wildcard to either.
560  */
561 struct preloaded_file *
562 file_findfile(const char *name, const char *type)
563 {
564     struct preloaded_file *fp;
565
566     for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
567         if (((name == NULL) || !strcmp(name, fp->f_name)) &&
568             ((type == NULL) || !strcmp(type, fp->f_type)))
569             break;
570     }
571     return (fp);
572 }
573
574 /*
575  * Find a module matching (name) inside of given file.
576  * NULL may be passed as a wildcard.
577  */
578 struct kernel_module *
579 file_findmodule(struct preloaded_file *fp, char *modname,
580         struct mod_depend *verinfo)
581 {
582     struct kernel_module *mp, *best;
583     int bestver, mver;
584
585     if (fp == NULL) {
586         for (fp = preloaded_files; fp; fp = fp->f_next) {
587             mp = file_findmodule(fp, modname, verinfo);
588             if (mp)
589                 return (mp);
590         }
591         return (NULL);
592     }
593     best = NULL;
594     bestver = 0;
595     for (mp = fp->f_modules; mp; mp = mp->m_next) {
596         if (strcmp(modname, mp->m_name) == 0) {
597             if (verinfo == NULL)
598                 return (mp);
599             mver = mp->m_version;
600             if (mver == verinfo->md_ver_preferred)
601                 return (mp);
602             if (mver >= verinfo->md_ver_minimum && 
603                 mver <= verinfo->md_ver_maximum &&
604                 mver > bestver) {
605                 best = mp;
606                 bestver = mver;
607             }
608         }
609     }
610     return (best);
611 }
612 /*
613  * Make a copy of (size) bytes of data from (p), and associate them as
614  * metadata of (type) to the module (mp).
615  */
616 void
617 file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
618 {
619     struct file_metadata        *md;
620
621     md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
622     md->md_size = size;
623     md->md_type = type;
624     bcopy(p, md->md_data, size);
625     md->md_next = fp->f_metadata;
626     fp->f_metadata = md;
627 }
628
629 /*
630  * Find a metadata object of (type) associated with the file (fp)
631  */
632 struct file_metadata *
633 file_findmetadata(struct preloaded_file *fp, int type)
634 {
635     struct file_metadata *md;
636
637     for (md = fp->f_metadata; md != NULL; md = md->md_next)
638         if (md->md_type == type)
639             break;
640     return(md);
641 }
642
643 struct file_metadata *
644 metadata_next(struct file_metadata *md, int type)
645 {
646     if (md == NULL)
647         return (NULL);
648     while((md = md->md_next) != NULL)
649         if (md->md_type == type)
650             break;
651     return (md);
652 }
653
654 static char *emptyextlist[] = { "", NULL };
655
656 /*
657  * Check if the given file is in place and return full path to it.
658  */
659 static char *
660 file_lookup(const char *path, const char *name, int namelen, char **extlist)
661 {
662     struct stat st;
663     char        *result, *cp, **cpp;
664     int         pathlen, extlen, len;
665
666     pathlen = strlen(path);
667     extlen = 0;
668     if (extlist == NULL)
669         extlist = emptyextlist;
670     for (cpp = extlist; *cpp; cpp++) {
671         len = strlen(*cpp);
672         if (len > extlen)
673             extlen = len;
674     }
675     result = malloc(pathlen + namelen + extlen + 2);
676     if (result == NULL)
677         return (NULL);
678     bcopy(path, result, pathlen);
679     if (pathlen > 0 && result[pathlen - 1] != '/')
680         result[pathlen++] = '/';
681     cp = result + pathlen;
682     bcopy(name, cp, namelen);
683     cp += namelen;
684     for (cpp = extlist; *cpp; cpp++) {
685         strcpy(cp, *cpp);
686         if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
687             return result;
688     }
689     free(result);
690     return NULL;
691 }
692
693 /*
694  * Check if file name have any qualifiers
695  */
696 static int
697 file_havepath(const char *name)
698 {
699     const char          *cp;
700
701     archsw.arch_getdev(NULL, name, &cp);
702     return (cp != name || strchr(name, '/') != NULL);
703 }
704
705 /*
706  * Attempt to find the file (name) on the module searchpath.
707  * If (name) is qualified in any way, we simply check it and
708  * return it or NULL.  If it is not qualified, then we attempt
709  * to construct a path using entries in the environment variable
710  * module_path.
711  *
712  * The path we return a pointer to need never be freed, as we manage
713  * it internally.
714  */
715 static char *
716 file_search(const char *name, char **extlist)
717 {
718     struct moduledir    *mdp;
719     struct stat         sb;
720     char                *result;
721     int                 namelen;
722
723     /* Don't look for nothing */
724     if (name == NULL)
725         return(NULL);
726
727     if (*name == 0)
728         return(strdup(name));
729
730     if (file_havepath(name)) {
731         /* Qualified, so just see if it exists */
732         if (stat(name, &sb) == 0)
733             return(strdup(name));
734         return(NULL);
735     }
736     moduledir_rebuild();
737     result = NULL;
738     namelen = strlen(name);
739     STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
740         result = file_lookup(mdp->d_path, name, namelen, extlist);
741         if (result)
742             break;
743     }
744     return(result);
745 }
746
747 #define INT_ALIGN(base, ptr)    ptr = \
748         (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
749
750 static char *
751 mod_search_hints(struct moduledir *mdp, const char *modname,
752         struct mod_depend *verinfo)
753 {
754     u_char      *cp, *recptr, *bufend, *best;
755     char        *result;
756     int         *intp, bestver, blen, clen, found, ival, modnamelen, reclen;
757
758     moduledir_readhints(mdp);
759     modnamelen = strlen(modname);
760     found = 0;
761     result = NULL;
762     bestver = 0;
763     if (mdp->d_hints == NULL)
764         goto bad;
765     recptr = mdp->d_hints;
766     bufend = recptr + mdp->d_hintsz;
767     clen = blen = 0;
768     best = cp = NULL;
769     while (recptr < bufend && !found) {
770         intp = (int*)recptr;
771         reclen = *intp++;
772         ival = *intp++;
773         cp = (char*)intp;
774         switch (ival) {
775         case MDT_VERSION:
776             clen = *cp++;
777             if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
778                 break;
779             cp += clen;
780             INT_ALIGN(mdp->d_hints, cp);
781             ival = *(int*)cp;
782             cp += sizeof(int);
783             clen = *cp++;
784             if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
785                 found = 1;
786                 break;
787             }
788             if (ival >= verinfo->md_ver_minimum && 
789                 ival <= verinfo->md_ver_maximum &&
790                 ival > bestver) {
791                 bestver = ival;
792                 best = cp;
793                 blen = clen;
794             }
795             break;
796         default:
797             break;
798         }
799         recptr += reclen + sizeof(int);
800     }
801     /*
802      * Finally check if KLD is in the place
803      */
804     if (found)
805         result = file_lookup(mdp->d_path, cp, clen, NULL);
806     else if (best)
807         result = file_lookup(mdp->d_path, best, blen, NULL);
808 bad:
809     /*
810      * If nothing found or hints is absent - fallback to the old way
811      * by using "kldname[.ko]" as module name.
812      */
813     if (!found && !bestver && result == NULL)
814         result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
815     return result;
816 }
817
818 /*
819  * Attempt to locate the file containing the module (name)
820  */
821 static char *
822 mod_searchmodule(char *name, struct mod_depend *verinfo)
823 {
824     struct      moduledir *mdp;
825     char        *result;
826
827     moduledir_rebuild();
828     /*
829      * Now we ready to lookup module in the given directories
830      */
831     result = NULL;
832     STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
833         result = mod_search_hints(mdp, name, verinfo);
834         if (result)
835             break;
836     }
837
838     return(result);
839 }
840
841 int
842 file_addmodule(struct preloaded_file *fp, char *modname, int version,
843         struct kernel_module **newmp)
844 {
845     struct kernel_module *mp;
846     struct mod_depend mdepend;
847
848     bzero(&mdepend, sizeof(mdepend));
849     mdepend.md_ver_preferred = version;
850     mp = file_findmodule(fp, modname, &mdepend);
851     if (mp)
852         return (EEXIST);
853     mp = malloc(sizeof(struct kernel_module));
854     if (mp == NULL)
855         return (ENOMEM);
856     bzero(mp, sizeof(struct kernel_module));
857     mp->m_name = strdup(modname);
858     mp->m_version = version;
859     mp->m_fp = fp;
860     mp->m_next = fp->f_modules;
861     fp->f_modules = mp;
862     if (newmp)
863         *newmp = mp;
864     return (0);
865 }
866
867 /*
868  * Throw a file away
869  */
870 void
871 file_discard(struct preloaded_file *fp)
872 {
873     struct file_metadata        *md, *md1;
874     struct kernel_module        *mp, *mp1;
875     if (fp == NULL)
876         return;
877     md = fp->f_metadata;
878     while (md) {
879         md1 = md;
880         md = md->md_next;
881         free(md1);
882     }
883     mp = fp->f_modules;
884     while (mp) {
885         if (mp->m_name)
886             free(mp->m_name);
887         mp1 = mp;
888         mp = mp->m_next;
889         free(mp1);
890     }   
891     if (fp->f_name != NULL)
892         free(fp->f_name);
893     if (fp->f_type != NULL)
894         free(fp->f_type);
895     if (fp->f_args != NULL)
896         free(fp->f_args);
897     free(fp);
898 }
899
900 /*
901  * Allocate a new file; must be used instead of malloc()
902  * to ensure safe initialisation.
903  */
904 struct preloaded_file *
905 file_alloc(void)
906 {
907     struct preloaded_file       *fp;
908     
909     if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
910         bzero(fp, sizeof(struct preloaded_file));
911     }
912     return (fp);
913 }
914
915 /*
916  * Add a module to the chain
917  */
918 static void
919 file_insert_tail(struct preloaded_file *fp)
920 {
921     struct preloaded_file       *cm;
922     
923     /* Append to list of loaded file */
924     fp->f_next = NULL;
925     if (preloaded_files == NULL) {
926         preloaded_files = fp;
927     } else {
928         for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
929             ;
930         cm->f_next = fp;
931     }
932 }
933
934 static char *
935 moduledir_fullpath(struct moduledir *mdp, const char *fname)
936 {
937     char *cp;
938
939     cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
940     if (cp == NULL)
941         return NULL;
942     strcpy(cp, mdp->d_path);
943     strcat(cp, "/");
944     strcat(cp, fname);
945     return (cp);
946 }
947
948 /*
949  * Read linker.hints file into memory performing some sanity checks.
950  */
951 static void
952 moduledir_readhints(struct moduledir *mdp)
953 {
954     struct stat st;
955     char        *path;
956     int         fd, size, version;
957
958     if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
959         return;
960     path = moduledir_fullpath(mdp, "linker.hints");
961     if (stat(path, &st) != 0 ||
962         st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
963         st.st_size > LINKER_HINTS_MAX || (fd = open(path, O_RDONLY)) < 0) {
964         free(path);
965         mdp->d_flags |= MDIR_NOHINTS;
966         return;
967     }
968     free(path);
969     size = read(fd, &version, sizeof(version));
970     if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
971         goto bad;
972     size = st.st_size - size;
973     mdp->d_hints = malloc(size);
974     if (mdp->d_hints == NULL)
975         goto bad;
976     if (read(fd, mdp->d_hints, size) != size)
977         goto bad;
978     mdp->d_hintsz = size;
979     close(fd);
980     return;
981 bad:
982     close(fd);
983     if (mdp->d_hints) {
984         free(mdp->d_hints);
985         mdp->d_hints = NULL;
986     }
987     mdp->d_flags |= MDIR_NOHINTS;
988     return;
989 }
990
991 /*
992  * Extract directories from the ';' separated list, remove duplicates.
993  */
994 static void
995 moduledir_rebuild(void)
996 {
997     struct      moduledir *mdp, *mtmp;
998     const char  *path, *cp, *ep;
999     size_t      cplen;
1000
1001     path = getenv("module_path");
1002     if (path == NULL)
1003         path = default_searchpath;
1004     /*
1005      * Rebuild list of module directories if it changed
1006      */
1007     STAILQ_FOREACH(mdp, &moduledir_list, d_link)
1008         mdp->d_flags |= MDIR_REMOVED;
1009
1010     for (ep = path; *ep != 0;  ep++) {
1011         cp = ep;
1012         for (; *ep != 0 && *ep != ';'; ep++)
1013             ;
1014         /*
1015          * Ignore trailing slashes
1016          */
1017         for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
1018             ;
1019         STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1020             if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
1021                 continue;
1022             mdp->d_flags &= ~MDIR_REMOVED;
1023             break;
1024         }
1025         if (mdp == NULL) {
1026             mdp = malloc(sizeof(*mdp) + cplen + 1);
1027             if (mdp == NULL)
1028                 return;
1029             mdp->d_path = (char*)(mdp + 1);
1030             bcopy(cp, mdp->d_path, cplen);
1031             mdp->d_path[cplen] = 0;
1032             mdp->d_hints = NULL;
1033             mdp->d_flags = 0;
1034             STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1035         }
1036         if (*ep == 0)
1037             break;
1038     }
1039     /*
1040      * Delete unused directories if any
1041      */
1042     mdp = STAILQ_FIRST(&moduledir_list);
1043     while (mdp) {
1044         if ((mdp->d_flags & MDIR_REMOVED) == 0) {
1045             mdp = STAILQ_NEXT(mdp, d_link);
1046         } else {
1047             if (mdp->d_hints)
1048                 free(mdp->d_hints);
1049             mtmp = mdp;
1050             mdp = STAILQ_NEXT(mdp, d_link);
1051             STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
1052             free(mtmp);
1053         }
1054     }
1055     return;
1056 }