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