hyperv: Add API to read raw value of Hyper-V timer.
[dragonfly.git] / sys / boot / common / module.c
blob449e64dedea53ec5a0efba4f220cd17a49941e69
1 /*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
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.
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.
26 * $FreeBSD: src/sys/boot/common/module.c,v 1.25 2003/08/25 23:30:41 obrien Exp $
30 * file/module function dispatcher, support, etc.
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 #ifndef EFI
40 #include "libi386/libi386.h"
41 #endif
43 #include "bootstrap.h"
45 #define MDIR_REMOVED 0x0001
46 #define MDIR_NOHINTS 0x0002
48 struct moduledir {
49 char *d_path; /* path of modules directory */
50 u_char *d_hints; /* content of linker.hints file */
51 int d_hintsz; /* size of hints data */
52 int d_flags;
53 STAILQ_ENTRY(moduledir) d_link;
56 static int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
57 static int file_loadraw(char *type, char *name);
58 static int file_load_dependencies(struct preloaded_file *base_mod);
59 static char * file_search(const char *name, char **extlist);
60 static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
61 static int file_havepath(const char *name);
62 static char *mod_searchmodule(char *name, struct mod_depend *verinfo);
63 static void file_insert_tail(struct preloaded_file *mp);
64 struct file_metadata* metadata_next(struct file_metadata *base_mp, int type);
65 static void moduledir_readhints(struct moduledir *mdp);
66 static void moduledir_rebuild(void);
68 /* load address should be tweaked by first module loaded (kernel) */
69 static vm_offset_t loadaddr = 0;
71 static const char *default_searchpath ="modules;KERNEL";
72 static const char *local_module_path = "../modules.local";
74 static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list);
76 struct preloaded_file *preloaded_files = NULL;
78 static char *kld_ext_list[] = {
79 ".ko",
80 "",
81 NULL
84 COMMAND_SET(slow, "slow", "slow print", command_slow);
86 static int slomode;
88 static int
89 command_slow(int argc, char *argv[])
91 slomode = 1;
92 return CMD_OK;
95 void
96 slowprint(char c)
98 int i;
100 if (slomode) {
101 printf("SP-%c\n", c);
102 for (i = 0; i < 10; ++i)
103 delay(100000);
108 * load an object, either a disk file or code module.
110 * To load a file, the syntax is:
112 * load -t <type> <path>
114 * code modules are loaded as:
116 * load <path> <options>
118 COMMAND_SET(load, "load", "load a kernel or module", command_load);
120 static int
121 command_load(int argc, char *argv[])
123 char *typestr;
124 int dofile, dokld, ch, error;
126 dokld = dofile = 0;
127 optind = 1;
128 optreset = 1;
129 typestr = NULL;
130 if (argc == 1) {
131 command_errmsg = "no filename specified";
132 return(CMD_ERROR);
134 while ((ch = getopt(argc, argv, "kt:")) != -1) {
135 switch(ch) {
136 case 'k':
137 dokld = 1;
138 break;
139 case 't':
140 typestr = optarg;
141 dofile = 1;
142 break;
143 case '?':
144 default:
145 /* getopt has already reported an error */
146 return(CMD_OK);
149 argv += (optind - 1);
150 argc -= (optind - 1);
153 * Request to load a raw file?
155 if (dofile) {
156 if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) {
157 command_errmsg = "invalid load type";
158 return(CMD_ERROR);
160 return(file_loadraw(typestr, argv[1]));
163 * Do we have explicit KLD load ?
165 if (dokld || file_havepath(argv[1])) {
166 error = mod_loadkld(argv[1], argc - 2, argv + 2);
167 if (error == EEXIST) {
168 snprintf(command_errbuf, sizeof(command_errbuf),
169 "warning: KLD '%s' already loaded", argv[1]);
171 return (error == 0 ? CMD_OK : CMD_ERROR);
174 * Looks like a request for a module.
176 error = mod_load(argv[1], NULL, argc - 2, argv + 2);
177 if (error == EEXIST) {
178 snprintf(command_errbuf, sizeof(command_errbuf),
179 "warning: module '%s' already loaded", argv[1]);
181 return (error == 0 ? CMD_OK : CMD_ERROR);
184 COMMAND_SET(unload, "unload", "unload all modules", command_unload);
186 static int
187 command_unload(int argc, char *argv[])
189 struct preloaded_file *fp;
191 while (preloaded_files != NULL) {
192 fp = preloaded_files;
193 preloaded_files = preloaded_files->f_next;
194 file_discard(fp);
196 loadaddr = 0;
197 unsetenv("kernelname");
198 return(CMD_OK);
201 COMMAND_SET(crc, "crc", "calculate crc for file", command_crc);
203 uint32_t iscsi_crc32(const void *buf, size_t size);
204 uint32_t iscsi_crc32_ext(const void *buf, size_t size, uint32_t ocrc);
206 static int
207 command_crc(int argc, char *argv[])
209 char *name;
210 char *cp;
211 int i;
212 int fd, got, tot;
213 int error;
214 uint32_t crc;
215 char *buf;
217 if (argc == 1) {
218 command_errmsg = "no filename specified";
219 return(CMD_ERROR);
221 buf = malloc(8192);
223 error = 0;
224 printf("size\tcrc\t name\n");
225 for (i = 1; i < argc; ++i) {
226 /* locate the file on the load path */
227 cp = file_search(argv[i], NULL);
228 if (cp == NULL) {
229 snprintf(command_errbuf, sizeof(command_errbuf),
230 "can't find '%s'", argv[i]);
231 error = CMD_ERROR;
232 break;
234 name = cp;
236 if ((fd = rel_open(name, NULL, O_RDONLY)) < 0) {
237 snprintf(command_errbuf, sizeof(command_errbuf),
238 "can't open '%s': %s", name, strerror(errno));
239 free(name);
240 error = CMD_ERROR;
241 break;
243 tot = 0;
244 crc = 0;
245 for (;;) {
246 got = read(fd, buf, 8192);
247 if (got == 0)
248 break;
249 if (got < 0) {
250 printf("error reading '%s': %s\n",
251 name, strerror(errno));
252 break;
254 if (got == 0)
255 crc = iscsi_crc32(buf, got);
256 else
257 crc = iscsi_crc32_ext(buf, got, crc);
258 tot += got;
260 printf("%7d %08x %s\n", tot, crc, name);
261 free(name);
262 close(fd);
264 free (buf);
265 if (error == 0)
266 error = CMD_OK;
267 return error;
270 COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
272 static int
273 command_lsmod(int argc, char *argv[])
275 struct preloaded_file *fp;
276 struct kernel_module *mp;
277 struct file_metadata *md;
278 char lbuf[80];
279 int ch, verbose;
281 verbose = 0;
282 optind = 1;
283 optreset = 1;
284 while ((ch = getopt(argc, argv, "v")) != -1) {
285 switch(ch) {
286 case 'v':
287 verbose = 1;
288 break;
289 case '?':
290 default:
291 /* getopt has already reported an error */
292 return(CMD_OK);
296 pager_open();
297 for (fp = preloaded_files; fp; fp = fp->f_next) {
298 sprintf(lbuf, " %p: %s (%s, 0x%lx)\n",
299 (void *) fp->f_addr, fp->f_name, fp->f_type, (long) fp->f_size);
300 pager_output(lbuf);
301 if (fp->f_args != NULL) {
302 pager_output(" args: ");
303 pager_output(fp->f_args);
304 pager_output("\n");
306 if (fp->f_modules) {
307 pager_output(" modules: ");
308 for (mp = fp->f_modules; mp; mp = mp->m_next) {
309 sprintf(lbuf, "%s.%d ", mp->m_name, mp->m_version);
310 pager_output(lbuf);
312 pager_output("\n");
314 if (verbose) {
315 /* XXX could add some formatting smarts here to display some better */
316 for (md = fp->f_metadata; md != NULL; md = md->md_next) {
317 sprintf(lbuf, " 0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
318 pager_output(lbuf);
322 pager_close();
323 return(CMD_OK);
327 * File level interface, functions file_*
330 file_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
332 struct preloaded_file *fp;
333 int error;
334 int i;
336 error = EFTYPE;
337 for (i = 0, fp = NULL; file_formats[i] && fp == NULL; i++) {
338 error = (file_formats[i]->l_load)(filename, loadaddr, &fp);
339 if (error == 0) {
340 fp->f_loader = i; /* remember the loader */
341 *result = fp;
342 break;
344 if (error == EFTYPE)
345 continue; /* Unknown to this handler? */
346 if (error) {
347 snprintf(command_errbuf, sizeof(command_errbuf),
348 "can't load file '%s': %s", filename, strerror(error));
349 break;
352 return (error);
355 static int
356 file_load_dependencies(struct preloaded_file *base_file)
358 struct file_metadata *md;
359 struct preloaded_file *fp;
360 struct mod_depend *verinfo;
361 struct kernel_module *mp;
362 char *dmodname;
363 int error;
365 md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
366 if (md == NULL)
367 return (0);
368 error = 0;
369 do {
370 verinfo = (struct mod_depend*)md->md_data;
371 dmodname = (char *)(verinfo + 1);
372 if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
373 printf("loading required module '%s'\n", dmodname);
374 error = mod_load(dmodname, verinfo, 0, NULL);
375 if (error)
376 break;
378 * If module loaded via kld name which isn't listed
379 * in the linker.hints file, we should check if it have
380 * required version.
382 mp = file_findmodule(NULL, dmodname, verinfo);
383 if (mp == NULL) {
384 snprintf(command_errbuf, sizeof(command_errbuf),
385 "module '%s' exists but with wrong version", dmodname);
386 error = ENOENT;
387 break;
390 md = metadata_next(md, MODINFOMD_DEPLIST);
391 } while (md);
392 if (!error)
393 return (0);
394 /* Load failed; discard everything */
395 while (base_file != NULL) {
396 fp = base_file;
397 base_file = base_file->f_next;
398 file_discard(fp);
400 return (error);
404 * We've been asked to load (name) as (type), so just suck it in,
405 * no arguments or anything.
408 file_loadraw(char *type, char *name)
410 struct preloaded_file *fp;
411 char *cp;
412 int fd, got;
413 vm_offset_t laddr;
415 /* We can't load first */
416 if ((file_findfile(NULL, NULL)) == NULL) {
417 command_errmsg = "can't load file before kernel";
418 return(CMD_ERROR);
421 /* locate the file on the load path */
422 cp = file_search(name, NULL);
423 if (cp == NULL) {
424 snprintf(command_errbuf, sizeof(command_errbuf),
425 "can't find '%s'", name);
426 return(CMD_ERROR);
428 name = cp;
430 if ((fd = rel_open(name, NULL, O_RDONLY)) < 0) {
431 snprintf(command_errbuf, sizeof(command_errbuf),
432 "can't open '%s': %s", name, strerror(errno));
433 free(name);
434 return(CMD_ERROR);
437 laddr = loadaddr;
438 for (;;) {
439 /* read in 4k chunks; size is not really important */
440 #ifndef EFI
441 if (laddr + 4096 > heapbase) {
442 snprintf(command_errbuf, sizeof(command_errbuf),
443 "error reading '%s': out of load memory", name);
444 free(name);
445 close(fd);
446 return(CMD_ERROR);
448 #endif
449 got = archsw.arch_readin(fd, laddr, 4096);
450 if (got == 0) /* end of file */
451 break;
452 if (got < 0) { /* error */
453 snprintf(command_errbuf, sizeof(command_errbuf),
454 "error reading '%s': %s", name, strerror(errno));
455 free(name);
456 close(fd);
457 return(CMD_ERROR);
459 laddr += got;
462 /* Looks OK so far; create & populate control structure */
463 fp = file_alloc();
464 fp->f_name = name;
465 fp->f_type = strdup(type);
466 fp->f_args = NULL;
467 fp->f_metadata = NULL;
468 fp->f_loader = -1;
469 fp->f_addr = loadaddr;
470 fp->f_size = laddr - loadaddr;
472 /* recognise space consumption */
473 loadaddr = laddr;
475 /* Add to the list of loaded files */
476 file_insert_tail(fp);
477 close(fd);
478 return(CMD_OK);
482 * Load the module (name), pass it (argc),(argv), add container file
483 * to the list of loaded files.
484 * If module is already loaded just assign new argc/argv.
487 mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
489 struct kernel_module *mp;
490 int err;
491 char *filename;
493 if (file_havepath(modname)) {
494 printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
495 return (mod_loadkld(modname, argc, argv));
497 /* see if module is already loaded */
498 mp = file_findmodule(NULL, modname, verinfo);
499 if (mp) {
500 #ifdef moduleargs
501 if (mp->m_args)
502 free(mp->m_args);
503 mp->m_args = unargv(argc, argv);
504 #endif
505 snprintf(command_errbuf, sizeof(command_errbuf),
506 "warning: module '%s' already loaded", mp->m_name);
507 return (0);
509 /* locate file with the module on the search path */
510 filename = mod_searchmodule(modname, verinfo);
511 if (filename == NULL) {
512 snprintf(command_errbuf, sizeof(command_errbuf),
513 "can't find '%s'", modname);
514 return (ENOENT);
516 err = mod_loadkld(filename, argc, argv);
517 return (err);
521 * Load specified KLD. If path is omitted, then try to locate it via
522 * search path.
525 mod_loadkld(const char *kldname, int argc, char *argv[])
527 struct preloaded_file *fp, *last_file;
528 int err;
529 char *filename;
532 * Get fully qualified KLD name
534 filename = file_search(kldname, kld_ext_list);
535 if (filename == NULL) {
536 snprintf(command_errbuf, sizeof(command_errbuf),
537 "can't find '%s'", kldname);
538 return (ENOENT);
541 * Check if KLD already loaded
543 fp = file_findfile(filename, NULL);
544 if (fp) {
545 snprintf(command_errbuf, sizeof(command_errbuf),
546 "warning: KLD '%s' already loaded", filename);
547 free(filename);
548 return (0);
550 for (last_file = preloaded_files;
551 last_file != NULL && last_file->f_next != NULL;
552 last_file = last_file->f_next)
555 do {
556 err = file_load(filename, loadaddr, &fp);
557 if (err)
558 break;
559 fp->f_args = unargv(argc, argv);
560 loadaddr = fp->f_addr + fp->f_size;
561 file_insert_tail(fp); /* Add to the list of loaded files */
562 if (file_load_dependencies(fp) != 0) {
563 err = ENOENT;
564 last_file->f_next = NULL;
565 loadaddr = last_file->f_addr + last_file->f_size;
566 fp = NULL;
567 break;
569 } while(0);
570 if (err == EFTYPE)
571 snprintf(command_errbuf, sizeof(command_errbuf),
572 "don't know how to load module '%s'", filename);
573 if (err && fp)
574 file_discard(fp);
575 free(filename);
576 return (err);
580 * Find a file matching (name) and (type).
581 * NULL may be passed as a wildcard to either.
583 struct preloaded_file *
584 file_findfile(char *name, char *type)
586 struct preloaded_file *fp;
588 for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
589 if (((name == NULL) || !strcmp(name, fp->f_name)) &&
590 ((type == NULL) || !strcmp(type, fp->f_type)))
591 break;
593 return (fp);
597 * Find a module matching (name) inside of given file.
598 * NULL may be passed as a wildcard.
600 struct kernel_module *
601 file_findmodule(struct preloaded_file *fp, char *modname,
602 struct mod_depend *verinfo)
604 struct kernel_module *mp, *best;
605 int bestver, mver;
607 if (fp == NULL) {
608 for (fp = preloaded_files; fp; fp = fp->f_next) {
609 mp = file_findmodule(fp, modname, verinfo);
610 if (mp)
611 return (mp);
613 return (NULL);
615 best = NULL;
616 bestver = 0;
617 for (mp = fp->f_modules; mp; mp = mp->m_next) {
618 if (strcmp(modname, mp->m_name) == 0) {
619 if (verinfo == NULL)
620 return (mp);
621 mver = mp->m_version;
622 if (mver == verinfo->md_ver_preferred)
623 return (mp);
624 if (mver >= verinfo->md_ver_minimum &&
625 mver <= verinfo->md_ver_maximum &&
626 mver > bestver) {
627 best = mp;
628 bestver = mver;
632 return (best);
635 * Make a copy of (size) bytes of data from (p), and associate them as
636 * metadata of (type) to the module (mp).
638 void
639 file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
641 struct file_metadata *md;
643 md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
644 md->md_size = size;
645 md->md_type = type;
646 bcopy(p, md->md_data, size);
647 md->md_next = fp->f_metadata;
648 fp->f_metadata = md;
652 * Find a metadata object of (type) associated with the file (fp)
654 struct file_metadata *
655 file_findmetadata(struct preloaded_file *fp, int type)
657 struct file_metadata *md;
659 for (md = fp->f_metadata; md != NULL; md = md->md_next)
660 if (md->md_type == type)
661 break;
662 return(md);
665 struct file_metadata *
666 metadata_next(struct file_metadata *md, int type)
668 if (md == NULL)
669 return (NULL);
670 while((md = md->md_next) != NULL)
671 if (md->md_type == type)
672 break;
673 return (md);
676 static char *emptyextlist[] = { "", NULL };
679 * Check if the given file is in place and return full path to it.
681 static char *
682 file_lookup(const char *path, const char *name, int namelen, char **extlist)
684 struct stat st;
685 char *result, *cp, **cpp;
686 size_t pathlen, extlen;
688 pathlen = strlen(path);
689 extlen = 0;
690 if (extlist == NULL)
691 extlist = emptyextlist;
692 for (cpp = extlist; *cpp; cpp++)
693 extlen = MAX(extlen, strlen(*cpp));
694 result = malloc(pathlen + namelen + extlen + 2 + 7 + 1);
695 if (result == NULL)
696 return (NULL);
697 bcopy(path, result, pathlen);
698 if (pathlen > 0 && result[pathlen - 1] != '/')
699 result[pathlen++] = '/';
700 cp = result + pathlen;
701 bcopy(name, cp, namelen);
702 cp += namelen;
703 for (cpp = extlist; *cpp; cpp++) {
704 strcpy(cp, *cpp);
705 if (rel_stat(result, &st) == 0) {
706 if (S_ISREG(st.st_mode)) {
707 return result;
708 } else if (S_ISDIR(st.st_mode)) {
709 strcat(result, "/kernel");
710 if (rel_stat(result, &st) == 0 && S_ISREG(st.st_mode)) {
711 return result;
716 free(result);
717 return NULL;
721 * Check if file name have any qualifiers
723 static int
724 file_havepath(const char *name)
726 const char *cp;
728 archsw.arch_getdev(NULL, name, &cp);
729 return (cp != name || strchr(name, '/') != NULL);
733 * Attempt to find the file (name) on the module searchpath.
734 * If (name) is qualified in any way, we simply check it and
735 * return it or NULL. If it is not qualified, then we attempt
736 * to construct a path using entries in the environment variable
737 * module_path.
739 * The path we return a pointer to need never be freed, as we manage
740 * it internally.
742 static char *
743 file_search(const char *name, char **extlist)
745 struct moduledir *mdp;
746 struct stat sb;
747 char *result;
748 int namelen;
750 /* Don't look for nothing */
751 if (name == NULL)
752 return(NULL);
754 if (*name == 0)
755 return(strdup(name));
758 * Qualified name. If it is a directory tag on
759 * a "/kernel" to it.
761 if (file_havepath(name)) {
762 /* Qualified, so just see if it exists */
763 if (rel_stat(name, &sb) == 0) {
764 if (S_ISDIR(sb.st_mode)) {
765 result = malloc(strlen(name) + 7 + 1);
766 sprintf(result, "%s/kernel", name);
767 return(result);
768 } else {
769 return(strdup(name));
772 return(NULL);
774 moduledir_rebuild();
775 result = NULL;
776 namelen = strlen(name);
777 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
778 result = file_lookup(mdp->d_path, name, namelen, extlist);
779 if (result)
780 break;
782 return(result);
785 #define INT_ALIGN(base, ptr) \
786 ptr = (base) + roundup2((ptr) - (base), sizeof(int))
788 static char *
789 mod_search_hints(struct moduledir *mdp, const char *modname,
790 struct mod_depend *verinfo)
792 u_char *cp, *recptr, *bufend, *best;
793 char *result;
794 int *intp, bestver, blen, clen, found, ival, modnamelen, reclen;
796 moduledir_readhints(mdp);
797 modnamelen = strlen(modname);
798 found = 0;
799 result = NULL;
800 bestver = 0;
801 if (mdp->d_hints == NULL)
802 goto bad;
803 recptr = mdp->d_hints;
804 bufend = recptr + mdp->d_hintsz;
805 clen = blen = 0;
806 best = cp = NULL;
807 while (recptr < bufend && !found) {
808 intp = (int*)recptr;
809 reclen = *intp++;
810 ival = *intp++;
811 cp = (char*)intp;
812 switch (ival) {
813 case MDT_VERSION:
814 clen = *cp++;
815 if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
816 break;
817 cp += clen;
818 INT_ALIGN(mdp->d_hints, cp);
819 ival = *(int*)cp;
820 cp += sizeof(int);
821 clen = *cp++;
822 if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
823 found = 1;
824 break;
826 if (ival >= verinfo->md_ver_minimum &&
827 ival <= verinfo->md_ver_maximum &&
828 ival > bestver) {
829 bestver = ival;
830 best = cp;
831 blen = clen;
833 break;
834 default:
835 break;
837 recptr += reclen + sizeof(int);
840 * Finally check if KLD is in the place
842 if (found)
843 result = file_lookup(mdp->d_path, cp, clen, NULL);
844 else if (best)
845 result = file_lookup(mdp->d_path, best, blen, NULL);
846 bad:
848 * If nothing found or hints is absent - fallback to the old way
849 * by using "kldname[.ko]" as module name.
851 if (!found && !bestver && result == NULL)
852 result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
853 return result;
857 * Attempt to locate the file containing the module (name)
859 static char *
860 mod_searchmodule(char *name, struct mod_depend *verinfo)
862 struct moduledir *mdp;
863 char *result;
865 moduledir_rebuild();
867 * Now we ready to lookup module in the given directories
869 result = NULL;
870 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
871 result = mod_search_hints(mdp, name, verinfo);
872 if (result)
873 break;
876 return(result);
880 file_addmodule(struct preloaded_file *fp, char *modname, int version,
881 struct kernel_module **newmp)
883 struct kernel_module *mp;
884 struct mod_depend mdepend;
886 bzero(&mdepend, sizeof(mdepend));
887 mdepend.md_ver_preferred = version;
888 mp = file_findmodule(fp, modname, &mdepend);
889 if (mp)
890 return (EEXIST);
891 mp = malloc(sizeof(struct kernel_module));
892 if (mp == NULL)
893 return (ENOMEM);
894 bzero(mp, sizeof(struct kernel_module));
895 mp->m_name = strdup(modname);
896 mp->m_version = version;
897 mp->m_fp = fp;
898 mp->m_next = fp->f_modules;
899 fp->f_modules = mp;
900 if (newmp)
901 *newmp = mp;
902 return (0);
906 * Throw a file away
908 void
909 file_discard(struct preloaded_file *fp)
911 struct file_metadata *md, *md1;
912 struct kernel_module *mp, *mp1;
913 if (fp == NULL)
914 return;
915 md = fp->f_metadata;
916 while (md) {
917 md1 = md;
918 md = md->md_next;
919 free(md1);
921 mp = fp->f_modules;
922 while (mp) {
923 if (mp->m_name)
924 free(mp->m_name);
925 mp1 = mp;
926 mp = mp->m_next;
927 free(mp1);
929 if (fp->f_name != NULL)
930 free(fp->f_name);
931 if (fp->f_type != NULL)
932 free(fp->f_type);
933 if (fp->f_args != NULL)
934 free(fp->f_args);
935 free(fp);
939 * Allocate a new file; must be used instead of malloc()
940 * to ensure safe initialisation.
942 struct preloaded_file *
943 file_alloc(void)
945 struct preloaded_file *fp;
947 if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
948 bzero(fp, sizeof(struct preloaded_file));
950 return (fp);
954 * Add a module to the chain
956 static void
957 file_insert_tail(struct preloaded_file *fp)
959 struct preloaded_file *cm;
961 /* Append to list of loaded file */
962 fp->f_next = NULL;
963 if (preloaded_files == NULL) {
964 preloaded_files = fp;
965 } else {
966 for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
968 cm->f_next = fp;
972 static char *
973 moduledir_fullpath(struct moduledir *mdp, const char *fname)
975 char *cp;
977 cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
978 if (cp == NULL)
979 return NULL;
980 strcpy(cp, mdp->d_path);
981 strcat(cp, "/");
982 strcat(cp, fname);
983 return (cp);
987 * Read linker.hints file into memory performing some sanity checks.
989 static void
990 moduledir_readhints(struct moduledir *mdp)
992 struct stat st;
993 char *path;
994 int fd, size, version;
996 if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
997 return;
998 path = moduledir_fullpath(mdp, "linker.hints");
999 if (rel_stat(path, &st) != 0 ||
1000 st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
1001 st.st_size > 100 * 1024 || (fd = rel_open(path, NULL, O_RDONLY)) < 0) {
1002 free(path);
1003 mdp->d_flags |= MDIR_NOHINTS;
1004 return;
1006 free(path);
1007 size = read(fd, &version, sizeof(version));
1008 if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
1009 goto bad;
1010 size = st.st_size - size;
1011 mdp->d_hints = malloc(size);
1012 if (mdp->d_hints == NULL)
1013 goto bad;
1014 if (read(fd, mdp->d_hints, size) != size)
1015 goto bad;
1016 mdp->d_hintsz = size;
1017 close(fd);
1018 return;
1019 bad:
1020 close(fd);
1021 if (mdp->d_hints) {
1022 free(mdp->d_hints);
1023 mdp->d_hints = NULL;
1025 mdp->d_flags |= MDIR_NOHINTS;
1029 * Extract directories from the ';' separated list, remove duplicates.
1031 static void
1032 moduledir_rebuild(void)
1034 struct moduledir *mdp, *mtmp;
1035 const char *path, *cp, *ep, *modlocal;
1036 size_t cplen;
1038 path = getenv("module_path");
1039 if (path == NULL)
1040 path = default_searchpath;
1042 * Rebuild list of module directories if it changed
1044 STAILQ_FOREACH(mdp, &moduledir_list, d_link)
1045 mdp->d_flags |= MDIR_REMOVED;
1047 for (ep = path; *ep != 0; ep++) {
1048 cp = ep;
1049 for (; *ep != 0 && *ep != ';'; ep++)
1052 * Ignore trailing slashes
1054 for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
1056 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1057 if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
1058 continue;
1059 mdp->d_flags &= ~MDIR_REMOVED;
1060 break;
1062 if (mdp == NULL) {
1063 mdp = malloc(sizeof(*mdp) + cplen + 1);
1064 if (mdp == NULL)
1065 return;
1066 mdp->d_path = (char*)(mdp + 1);
1067 bcopy(cp, mdp->d_path, cplen);
1068 mdp->d_path[cplen] = 0;
1069 mdp->d_hints = NULL;
1070 mdp->d_flags = 0;
1071 STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1073 if (*ep == 0)
1074 break;
1077 * Include modules.local if requested
1079 modlocal = getenv("local_modules");
1080 if (modlocal != NULL && strcmp(modlocal, "YES") == 0) {
1081 cp = local_module_path;
1082 cplen = strlen(local_module_path);
1083 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1084 if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
1085 continue;
1086 mdp->d_flags &= ~MDIR_REMOVED;
1087 break;
1089 if (mdp == NULL) {
1090 mdp = malloc(sizeof(*mdp) + cplen + 1);
1091 if (mdp == NULL)
1092 return;
1093 mdp->d_path = (char*)(mdp + 1);
1094 bcopy(local_module_path, mdp->d_path, cplen);
1095 mdp->d_path[cplen] = 0;
1096 mdp->d_hints = NULL;
1097 mdp->d_flags = 0;
1098 STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1102 * Delete unused directories if any
1104 mdp = STAILQ_FIRST(&moduledir_list);
1105 while (mdp) {
1106 if ((mdp->d_flags & MDIR_REMOVED) == 0) {
1107 mdp = STAILQ_NEXT(mdp, d_link);
1108 } else {
1109 if (mdp->d_hints)
1110 free(mdp->d_hints);
1111 mtmp = mdp;
1112 mdp = STAILQ_NEXT(mdp, d_link);
1113 STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
1114 free(mtmp);