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