xref: /dragonfly/stand/boot/common/module.c (revision 34f6038d)
1479ab7f0SSascha Wildner /*-
2479ab7f0SSascha Wildner  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3479ab7f0SSascha Wildner  * All rights reserved.
4479ab7f0SSascha Wildner  *
5479ab7f0SSascha Wildner  * Redistribution and use in source and binary forms, with or without
6479ab7f0SSascha Wildner  * modification, are permitted provided that the following conditions
7479ab7f0SSascha Wildner  * are met:
8479ab7f0SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10479ab7f0SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12479ab7f0SSascha Wildner  *    documentation and/or other materials provided with the distribution.
13479ab7f0SSascha Wildner  *
14479ab7f0SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15479ab7f0SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16479ab7f0SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17479ab7f0SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18479ab7f0SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19479ab7f0SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20479ab7f0SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21479ab7f0SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22479ab7f0SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23479ab7f0SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24479ab7f0SSascha Wildner  * SUCH DAMAGE.
25479ab7f0SSascha Wildner  *
26479ab7f0SSascha Wildner  * $FreeBSD: src/sys/boot/common/module.c,v 1.25 2003/08/25 23:30:41 obrien Exp $
27479ab7f0SSascha Wildner  */
28479ab7f0SSascha Wildner 
29479ab7f0SSascha Wildner /*
30479ab7f0SSascha Wildner  * file/module function dispatcher, support, etc.
31479ab7f0SSascha Wildner  */
32479ab7f0SSascha Wildner 
33479ab7f0SSascha Wildner #include <stand.h>
34479ab7f0SSascha Wildner #include <string.h>
35479ab7f0SSascha Wildner #include <sys/param.h>
36479ab7f0SSascha Wildner #include <sys/linker.h>
37479ab7f0SSascha Wildner #include <sys/module.h>
38479ab7f0SSascha Wildner #include <sys/queue.h>
39479ab7f0SSascha Wildner #ifndef EFI
40479ab7f0SSascha Wildner #include "libi386/libi386.h"
41479ab7f0SSascha Wildner #endif
42479ab7f0SSascha Wildner 
43479ab7f0SSascha Wildner #include "bootstrap.h"
44479ab7f0SSascha Wildner 
45479ab7f0SSascha Wildner #define	MDIR_REMOVED	0x0001
46479ab7f0SSascha Wildner #define	MDIR_NOHINTS	0x0002
47479ab7f0SSascha Wildner 
48479ab7f0SSascha Wildner struct moduledir {
49479ab7f0SSascha Wildner 	char	*d_path;	/* path of modules directory */
50479ab7f0SSascha Wildner 	u_char	*d_hints;	/* content of linker.hints file */
51479ab7f0SSascha Wildner 	int	d_hintsz;	/* size of hints data */
52479ab7f0SSascha Wildner 	int	d_flags;
53479ab7f0SSascha Wildner 	STAILQ_ENTRY(moduledir) d_link;
54479ab7f0SSascha Wildner };
55479ab7f0SSascha Wildner 
56479ab7f0SSascha Wildner static int			file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
57479ab7f0SSascha Wildner static int			file_loadraw(char *type, char *name);
58479ab7f0SSascha Wildner static int			file_load_dependencies(struct preloaded_file *base_mod);
59479ab7f0SSascha Wildner static char *			file_search(const char *name, char **extlist);
60479ab7f0SSascha Wildner static struct kernel_module *	file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
61479ab7f0SSascha Wildner static int			file_havepath(const char *name);
62479ab7f0SSascha Wildner static char			*mod_searchmodule(char *name, struct mod_depend *verinfo);
63479ab7f0SSascha Wildner static void			file_insert_tail(struct preloaded_file *mp);
64d5ee8190SAaron LI static struct file_metadata*	metadata_next(struct file_metadata *base_mp, int type);
65479ab7f0SSascha Wildner static void			moduledir_readhints(struct moduledir *mdp);
66479ab7f0SSascha Wildner static void			moduledir_rebuild(void);
67479ab7f0SSascha Wildner 
68479ab7f0SSascha Wildner /* load address should be tweaked by first module loaded (kernel) */
69479ab7f0SSascha Wildner static vm_offset_t	loadaddr = 0;
70479ab7f0SSascha Wildner 
71479ab7f0SSascha Wildner static const char	*default_searchpath = "modules;KERNEL";
72479ab7f0SSascha Wildner static const char	*local_module_path = "../modules.local";
73479ab7f0SSascha Wildner 
74479ab7f0SSascha Wildner static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list);
75479ab7f0SSascha Wildner 
76479ab7f0SSascha Wildner struct preloaded_file *preloaded_files = NULL;
77479ab7f0SSascha Wildner 
78479ab7f0SSascha Wildner static char *kld_ext_list[] = {
79479ab7f0SSascha Wildner     ".ko",
80479ab7f0SSascha Wildner     "",
81479ab7f0SSascha Wildner     NULL
82479ab7f0SSascha Wildner };
83479ab7f0SSascha Wildner 
84479ab7f0SSascha Wildner /*
85479ab7f0SSascha Wildner  * load an object, either a disk file or code module.
86479ab7f0SSascha Wildner  *
87479ab7f0SSascha Wildner  * To load a file, the syntax is:
88479ab7f0SSascha Wildner  *
89479ab7f0SSascha Wildner  * load -t <type> <path>
90479ab7f0SSascha Wildner  *
91479ab7f0SSascha Wildner  * code modules are loaded as:
92479ab7f0SSascha Wildner  *
93479ab7f0SSascha Wildner  * load <path> <options>
94479ab7f0SSascha Wildner  */
95479ab7f0SSascha Wildner COMMAND_SET(load, "load", "load a kernel or module", command_load);
96479ab7f0SSascha Wildner 
97479ab7f0SSascha Wildner static int
command_load(int argc,char * argv[])98479ab7f0SSascha Wildner command_load(int argc, char *argv[])
99479ab7f0SSascha Wildner {
100479ab7f0SSascha Wildner     char	*typestr;
101479ab7f0SSascha Wildner     int		dofile, dokld, ch, error;
102479ab7f0SSascha Wildner 
103479ab7f0SSascha Wildner     dokld = dofile = 0;
104479ab7f0SSascha Wildner     optind = 1;
105479ab7f0SSascha Wildner     optreset = 1;
106479ab7f0SSascha Wildner     typestr = NULL;
107479ab7f0SSascha Wildner     if (argc == 1) {
108479ab7f0SSascha Wildner 	command_errmsg = "no filename specified";
109479ab7f0SSascha Wildner 	return(CMD_ERROR);
110479ab7f0SSascha Wildner     }
111479ab7f0SSascha Wildner     while ((ch = getopt(argc, argv, "kt:")) != -1) {
112479ab7f0SSascha Wildner 	switch(ch) {
113479ab7f0SSascha Wildner 	case 'k':
114479ab7f0SSascha Wildner 	    dokld = 1;
115479ab7f0SSascha Wildner 	    break;
116479ab7f0SSascha Wildner 	case 't':
117479ab7f0SSascha Wildner 	    typestr = optarg;
118479ab7f0SSascha Wildner 	    dofile = 1;
119479ab7f0SSascha Wildner 	    break;
120479ab7f0SSascha Wildner 	case '?':
121479ab7f0SSascha Wildner 	default:
122479ab7f0SSascha Wildner 	    /* getopt has already reported an error */
123479ab7f0SSascha Wildner 	    return(CMD_OK);
124479ab7f0SSascha Wildner 	}
125479ab7f0SSascha Wildner     }
126479ab7f0SSascha Wildner     argv += (optind - 1);
127479ab7f0SSascha Wildner     argc -= (optind - 1);
128479ab7f0SSascha Wildner 
129479ab7f0SSascha Wildner     /*
130479ab7f0SSascha Wildner      * Request to load a raw file?
131479ab7f0SSascha Wildner      */
132479ab7f0SSascha Wildner     if (dofile) {
133479ab7f0SSascha Wildner 	if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) {
134479ab7f0SSascha Wildner 	    command_errmsg = "invalid load type";
135479ab7f0SSascha Wildner 	    return(CMD_ERROR);
136479ab7f0SSascha Wildner 	}
137479ab7f0SSascha Wildner 	return(file_loadraw(typestr, argv[1]));
138479ab7f0SSascha Wildner     }
139479ab7f0SSascha Wildner     /*
140479ab7f0SSascha Wildner      * Do we have explicit KLD load ?
141479ab7f0SSascha Wildner      */
142479ab7f0SSascha Wildner     if (dokld || file_havepath(argv[1])) {
143479ab7f0SSascha Wildner 	error = mod_loadkld(argv[1], argc - 2, argv + 2);
144479ab7f0SSascha Wildner 	if (error == EEXIST) {
145479ab7f0SSascha Wildner 	    snprintf(command_errbuf, sizeof(command_errbuf),
146479ab7f0SSascha Wildner 		"warning: KLD '%s' already loaded", argv[1]);
147479ab7f0SSascha Wildner 	}
148479ab7f0SSascha Wildner 	return (error == 0 ? CMD_OK : CMD_ERROR);
149479ab7f0SSascha Wildner     }
150479ab7f0SSascha Wildner     /*
151479ab7f0SSascha Wildner      * Looks like a request for a module.
152479ab7f0SSascha Wildner      */
153479ab7f0SSascha Wildner     error = mod_load(argv[1], NULL, argc - 2, argv + 2);
154479ab7f0SSascha Wildner     if (error == EEXIST) {
155479ab7f0SSascha Wildner 	snprintf(command_errbuf, sizeof(command_errbuf),
156479ab7f0SSascha Wildner 	    "warning: module '%s' already loaded", argv[1]);
157479ab7f0SSascha Wildner     }
158479ab7f0SSascha Wildner     return (error == 0 ? CMD_OK : CMD_ERROR);
159479ab7f0SSascha Wildner }
160479ab7f0SSascha Wildner 
161479ab7f0SSascha Wildner COMMAND_SET(unload, "unload", "unload all modules", command_unload);
162479ab7f0SSascha Wildner 
163479ab7f0SSascha Wildner static int
command_unload(int argc,char * argv[])164479ab7f0SSascha Wildner command_unload(int argc, char *argv[])
165479ab7f0SSascha Wildner {
166479ab7f0SSascha Wildner     struct preloaded_file	*fp;
167479ab7f0SSascha Wildner 
168479ab7f0SSascha Wildner     while (preloaded_files != NULL) {
169479ab7f0SSascha Wildner 	fp = preloaded_files;
170479ab7f0SSascha Wildner 	preloaded_files = preloaded_files->f_next;
171479ab7f0SSascha Wildner 	file_discard(fp);
172479ab7f0SSascha Wildner     }
173479ab7f0SSascha Wildner     loadaddr = 0;
174479ab7f0SSascha Wildner     unsetenv("kernelname");
175479ab7f0SSascha Wildner     return(CMD_OK);
176479ab7f0SSascha Wildner }
177479ab7f0SSascha Wildner 
178479ab7f0SSascha Wildner COMMAND_SET(crc, "crc", "calculate crc for file", command_crc);
179479ab7f0SSascha Wildner 
180479ab7f0SSascha Wildner uint32_t iscsi_crc32(const void *buf, size_t size);
181479ab7f0SSascha Wildner uint32_t iscsi_crc32_ext(const void *buf, size_t size, uint32_t ocrc);
182479ab7f0SSascha Wildner 
183479ab7f0SSascha Wildner static int
command_crc(int argc,char * argv[])184479ab7f0SSascha Wildner command_crc(int argc, char *argv[])
185479ab7f0SSascha Wildner {
186479ab7f0SSascha Wildner     char	*name;
187479ab7f0SSascha Wildner     char	*cp;
188479ab7f0SSascha Wildner     int		i;
189479ab7f0SSascha Wildner     int		fd, got, tot;
190479ab7f0SSascha Wildner     int		error;
191479ab7f0SSascha Wildner     uint32_t	crc;
192479ab7f0SSascha Wildner     char	*buf;
193479ab7f0SSascha Wildner 
194479ab7f0SSascha Wildner     if (argc == 1) {
195479ab7f0SSascha Wildner 	command_errmsg = "no filename specified";
196479ab7f0SSascha Wildner 	return(CMD_ERROR);
197479ab7f0SSascha Wildner     }
198479ab7f0SSascha Wildner     buf = malloc(8192);
199479ab7f0SSascha Wildner 
200479ab7f0SSascha Wildner     error = 0;
201479ab7f0SSascha Wildner     printf("size\tcrc\t name\n");
202479ab7f0SSascha Wildner     for (i = 1; i < argc; ++i) {
203479ab7f0SSascha Wildner 	/* locate the file on the load path */
204479ab7f0SSascha Wildner 	cp = file_search(argv[i], NULL);
205479ab7f0SSascha Wildner 	if (cp == NULL) {
206479ab7f0SSascha Wildner 	    snprintf(command_errbuf, sizeof(command_errbuf),
207479ab7f0SSascha Wildner 		"can't find '%s'", argv[i]);
208479ab7f0SSascha Wildner 	    error = CMD_ERROR;
209479ab7f0SSascha Wildner 	    break;
210479ab7f0SSascha Wildner 	}
211479ab7f0SSascha Wildner 	name = cp;
212479ab7f0SSascha Wildner 
213479ab7f0SSascha Wildner 	if ((fd = rel_open(name, NULL, O_RDONLY)) < 0) {
214479ab7f0SSascha Wildner 	    snprintf(command_errbuf, sizeof(command_errbuf),
215479ab7f0SSascha Wildner 		"can't open '%s': %s", name, strerror(errno));
216479ab7f0SSascha Wildner 	    free(name);
217479ab7f0SSascha Wildner 	    error = CMD_ERROR;
218479ab7f0SSascha Wildner 	    break;
219479ab7f0SSascha Wildner 	}
220479ab7f0SSascha Wildner 	tot = 0;
221479ab7f0SSascha Wildner 	crc = 0;
222479ab7f0SSascha Wildner 	for (;;) {
223479ab7f0SSascha Wildner 	    got = read(fd, buf, 8192);
224479ab7f0SSascha Wildner 	    if (got == 0)
225479ab7f0SSascha Wildner 		break;
226479ab7f0SSascha Wildner 	    if (got < 0) {
227479ab7f0SSascha Wildner 		printf("error reading '%s': %s\n",
228479ab7f0SSascha Wildner 		    name, strerror(errno));
229479ab7f0SSascha Wildner 		break;
230479ab7f0SSascha Wildner 	    }
231479ab7f0SSascha Wildner 	    if (crc == 0)
232479ab7f0SSascha Wildner 		crc = iscsi_crc32(buf, got);
233479ab7f0SSascha Wildner 	    else
234479ab7f0SSascha Wildner 		crc = iscsi_crc32_ext(buf, got, crc);
235479ab7f0SSascha Wildner 	    tot += got;
236479ab7f0SSascha Wildner 	}
237479ab7f0SSascha Wildner 	printf("%7d %08x %s\n", tot, crc, name);
238479ab7f0SSascha Wildner 	free(name);
239479ab7f0SSascha Wildner 	close(fd);
240479ab7f0SSascha Wildner     }
241479ab7f0SSascha Wildner     free (buf);
242479ab7f0SSascha Wildner     if (error == 0)
243479ab7f0SSascha Wildner 	error = CMD_OK;
244479ab7f0SSascha Wildner     return error;
245479ab7f0SSascha Wildner }
246479ab7f0SSascha Wildner 
247479ab7f0SSascha Wildner COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
248479ab7f0SSascha Wildner 
249479ab7f0SSascha Wildner static int
command_lsmod(int argc,char * argv[])250479ab7f0SSascha Wildner command_lsmod(int argc, char *argv[])
251479ab7f0SSascha Wildner {
252479ab7f0SSascha Wildner     struct preloaded_file	*fp;
253479ab7f0SSascha Wildner     struct kernel_module	*mp;
254479ab7f0SSascha Wildner     struct file_metadata	*md;
255479ab7f0SSascha Wildner     char			lbuf[80];
256479ab7f0SSascha Wildner     int				ch, verbose;
257479ab7f0SSascha Wildner 
258479ab7f0SSascha Wildner     verbose = 0;
259479ab7f0SSascha Wildner     optind = 1;
260479ab7f0SSascha Wildner     optreset = 1;
261479ab7f0SSascha Wildner     while ((ch = getopt(argc, argv, "v")) != -1) {
262479ab7f0SSascha Wildner 	switch(ch) {
263479ab7f0SSascha Wildner 	case 'v':
264479ab7f0SSascha Wildner 	    verbose = 1;
265479ab7f0SSascha Wildner 	    break;
266479ab7f0SSascha Wildner 	case '?':
267479ab7f0SSascha Wildner 	default:
268479ab7f0SSascha Wildner 	    /* getopt has already reported an error */
269479ab7f0SSascha Wildner 	    return(CMD_OK);
270479ab7f0SSascha Wildner 	}
271479ab7f0SSascha Wildner     }
272479ab7f0SSascha Wildner 
273479ab7f0SSascha Wildner     pager_open();
274479ab7f0SSascha Wildner     for (fp = preloaded_files; fp; fp = fp->f_next) {
275479ab7f0SSascha Wildner 	sprintf(lbuf, " %p: %s (%s, 0x%lx)\n",
276479ab7f0SSascha Wildner 		(void *) fp->f_addr, fp->f_name, fp->f_type, (long) fp->f_size);
277479ab7f0SSascha Wildner 	pager_output(lbuf);
278479ab7f0SSascha Wildner 	if (fp->f_args != NULL) {
279479ab7f0SSascha Wildner 	    pager_output("    args: ");
280479ab7f0SSascha Wildner 	    pager_output(fp->f_args);
281479ab7f0SSascha Wildner 	    pager_output("\n");
282479ab7f0SSascha Wildner 	}
283479ab7f0SSascha Wildner 	if (fp->f_modules) {
284479ab7f0SSascha Wildner 	    pager_output("  modules: ");
285479ab7f0SSascha Wildner 	    for (mp = fp->f_modules; mp; mp = mp->m_next) {
286479ab7f0SSascha Wildner 		sprintf(lbuf, "%s.%d ", mp->m_name, mp->m_version);
287479ab7f0SSascha Wildner 		pager_output(lbuf);
288479ab7f0SSascha Wildner 	    }
289479ab7f0SSascha Wildner 	    pager_output("\n");
290479ab7f0SSascha Wildner 	}
291479ab7f0SSascha Wildner 	if (verbose) {
292479ab7f0SSascha Wildner 	    /* XXX could add some formatting smarts here to display some better */
293479ab7f0SSascha Wildner 	    for (md = fp->f_metadata; md != NULL; md = md->md_next) {
294479ab7f0SSascha Wildner 		sprintf(lbuf, "      0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
295479ab7f0SSascha Wildner 		pager_output(lbuf);
296479ab7f0SSascha Wildner 	    }
297479ab7f0SSascha Wildner 	}
298479ab7f0SSascha Wildner     }
299479ab7f0SSascha Wildner     pager_close();
300479ab7f0SSascha Wildner     return(CMD_OK);
301479ab7f0SSascha Wildner }
302479ab7f0SSascha Wildner 
303479ab7f0SSascha Wildner /*
304479ab7f0SSascha Wildner  * File level interface, functions file_*
305479ab7f0SSascha Wildner  */
306d5ee8190SAaron LI static int
file_load(char * filename,vm_offset_t dest,struct preloaded_file ** result)307479ab7f0SSascha Wildner file_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
308479ab7f0SSascha Wildner {
309479ab7f0SSascha Wildner     struct preloaded_file *fp;
310479ab7f0SSascha Wildner     int error;
311479ab7f0SSascha Wildner     int i;
312479ab7f0SSascha Wildner 
313479ab7f0SSascha Wildner     error = EFTYPE;
314479ab7f0SSascha Wildner     for (i = 0, fp = NULL; file_formats[i] && fp == NULL; i++) {
315138a936fSAaron LI 	error = (file_formats[i]->l_load)(filename, dest, &fp);
316479ab7f0SSascha Wildner 	if (error == 0) {
317479ab7f0SSascha Wildner 	    fp->f_loader = i;		/* remember the loader */
318479ab7f0SSascha Wildner 	    *result = fp;
319479ab7f0SSascha Wildner 	    break;
320479ab7f0SSascha Wildner 	}
321479ab7f0SSascha Wildner 	if (error == EFTYPE)
322479ab7f0SSascha Wildner 	    continue;		/* Unknown to this handler? */
323479ab7f0SSascha Wildner 	if (error) {
324479ab7f0SSascha Wildner 	    snprintf(command_errbuf, sizeof(command_errbuf),
325479ab7f0SSascha Wildner 		"can't load file '%s': %s", filename, strerror(error));
326479ab7f0SSascha Wildner 	    break;
327479ab7f0SSascha Wildner 	}
328479ab7f0SSascha Wildner     }
329479ab7f0SSascha Wildner     return (error);
330479ab7f0SSascha Wildner }
331479ab7f0SSascha Wildner 
332479ab7f0SSascha Wildner static int
file_load_dependencies(struct preloaded_file * base_file)333479ab7f0SSascha Wildner file_load_dependencies(struct preloaded_file *base_file)
334479ab7f0SSascha Wildner {
335479ab7f0SSascha Wildner     struct file_metadata *md;
336479ab7f0SSascha Wildner     struct preloaded_file *fp;
337479ab7f0SSascha Wildner     struct mod_depend *verinfo;
338479ab7f0SSascha Wildner     struct kernel_module *mp;
339479ab7f0SSascha Wildner     char *dmodname;
340479ab7f0SSascha Wildner     int error;
341479ab7f0SSascha Wildner 
342479ab7f0SSascha Wildner     md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
343479ab7f0SSascha Wildner     if (md == NULL)
344479ab7f0SSascha Wildner 	return (0);
345d5ee8190SAaron LI 
346479ab7f0SSascha Wildner     error = 0;
347479ab7f0SSascha Wildner     do {
348479ab7f0SSascha Wildner 	verinfo = (struct mod_depend*)md->md_data;
349479ab7f0SSascha Wildner 	dmodname = (char *)(verinfo + 1);
350479ab7f0SSascha Wildner 	if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
351479ab7f0SSascha Wildner 	    printf("loading required module '%s'\n", dmodname);
352479ab7f0SSascha Wildner 	    error = mod_load(dmodname, verinfo, 0, NULL);
353479ab7f0SSascha Wildner 	    if (error)
354479ab7f0SSascha Wildner 		break;
355479ab7f0SSascha Wildner 	    /*
356479ab7f0SSascha Wildner 	     * If module loaded via kld name which isn't listed
357479ab7f0SSascha Wildner 	     * in the linker.hints file, we should check if it have
358479ab7f0SSascha Wildner 	     * required version.
359479ab7f0SSascha Wildner 	     */
360479ab7f0SSascha Wildner 	    mp = file_findmodule(NULL, dmodname, verinfo);
361479ab7f0SSascha Wildner 	    if (mp == NULL) {
362479ab7f0SSascha Wildner 		snprintf(command_errbuf, sizeof(command_errbuf),
363479ab7f0SSascha Wildner 		    "module '%s' exists but with wrong version", dmodname);
364479ab7f0SSascha Wildner 		error = ENOENT;
365479ab7f0SSascha Wildner 		break;
366479ab7f0SSascha Wildner 	    }
367479ab7f0SSascha Wildner 	}
368479ab7f0SSascha Wildner 	md = metadata_next(md, MODINFOMD_DEPLIST);
369479ab7f0SSascha Wildner     } while (md);
370479ab7f0SSascha Wildner     if (!error)
371479ab7f0SSascha Wildner 	return (0);
372d5ee8190SAaron LI 
373479ab7f0SSascha Wildner     /* Load failed; discard everything */
374479ab7f0SSascha Wildner     while (base_file != NULL) {
375479ab7f0SSascha Wildner 	fp = base_file;
376479ab7f0SSascha Wildner 	base_file = base_file->f_next;
377479ab7f0SSascha Wildner 	file_discard(fp);
378479ab7f0SSascha Wildner     }
379479ab7f0SSascha Wildner     return (error);
380479ab7f0SSascha Wildner }
381479ab7f0SSascha Wildner 
382479ab7f0SSascha Wildner /*
383479ab7f0SSascha Wildner  * We've been asked to load (name) as (type), so just suck it in,
384479ab7f0SSascha Wildner  * no arguments or anything.
385479ab7f0SSascha Wildner  */
386d5ee8190SAaron LI static int
file_loadraw(char * type,char * name)387479ab7f0SSascha Wildner file_loadraw(char *type, char *name)
388479ab7f0SSascha Wildner {
389479ab7f0SSascha Wildner     struct preloaded_file	*fp;
390479ab7f0SSascha Wildner     char			*cp;
391479ab7f0SSascha Wildner     int				fd, got;
392479ab7f0SSascha Wildner     vm_offset_t			laddr;
393479ab7f0SSascha Wildner 
394479ab7f0SSascha Wildner     /* We can't load first */
395d5ee8190SAaron LI     if (file_findfile(NULL, NULL) == NULL) {
396479ab7f0SSascha Wildner 	command_errmsg = "can't load file before kernel";
397479ab7f0SSascha Wildner 	return(CMD_ERROR);
398479ab7f0SSascha Wildner     }
399479ab7f0SSascha Wildner 
400479ab7f0SSascha Wildner     /* locate the file on the load path */
401479ab7f0SSascha Wildner     cp = file_search(name, NULL);
402479ab7f0SSascha Wildner     if (cp == NULL) {
403479ab7f0SSascha Wildner 	snprintf(command_errbuf, sizeof(command_errbuf),
404479ab7f0SSascha Wildner 	    "can't find '%s'", name);
405479ab7f0SSascha Wildner 	return(CMD_ERROR);
406479ab7f0SSascha Wildner     }
407479ab7f0SSascha Wildner     name = cp;
408479ab7f0SSascha Wildner 
409479ab7f0SSascha Wildner     if ((fd = rel_open(name, NULL, O_RDONLY)) < 0) {
410479ab7f0SSascha Wildner 	snprintf(command_errbuf, sizeof(command_errbuf),
411479ab7f0SSascha Wildner 	    "can't open '%s': %s", name, strerror(errno));
412479ab7f0SSascha Wildner 	free(name);
413479ab7f0SSascha Wildner 	return(CMD_ERROR);
414479ab7f0SSascha Wildner     }
415479ab7f0SSascha Wildner 
416479ab7f0SSascha Wildner     laddr = loadaddr;
417479ab7f0SSascha Wildner     for (;;) {
418479ab7f0SSascha Wildner 	/* read in 4k chunks; size is not really important */
419479ab7f0SSascha Wildner #ifndef EFI
420479ab7f0SSascha Wildner 	if (laddr + 4096 > heapbase) {
421479ab7f0SSascha Wildner 	    snprintf(command_errbuf, sizeof(command_errbuf),
422479ab7f0SSascha Wildner 		"error reading '%s': out of load memory", name);
423479ab7f0SSascha Wildner 	    free(name);
424479ab7f0SSascha Wildner 	    close(fd);
425479ab7f0SSascha Wildner 	    return(CMD_ERROR);
426479ab7f0SSascha Wildner 	}
427479ab7f0SSascha Wildner #endif
428479ab7f0SSascha Wildner 	got = archsw.arch_readin(fd, laddr, 4096);
429479ab7f0SSascha Wildner 	if (got == 0)				/* end of file */
430479ab7f0SSascha Wildner 	    break;
431479ab7f0SSascha Wildner 	if (got < 0) {				/* error */
432479ab7f0SSascha Wildner 	    snprintf(command_errbuf, sizeof(command_errbuf),
433479ab7f0SSascha Wildner 		"error reading '%s': %s", name, strerror(errno));
434479ab7f0SSascha Wildner 	    free(name);
435479ab7f0SSascha Wildner 	    close(fd);
436479ab7f0SSascha Wildner 	    return(CMD_ERROR);
437479ab7f0SSascha Wildner 	}
438479ab7f0SSascha Wildner 	laddr += got;
439479ab7f0SSascha Wildner     }
440479ab7f0SSascha Wildner 
441479ab7f0SSascha Wildner     /* Looks OK so far; create & populate control structure */
442479ab7f0SSascha Wildner     fp = file_alloc();
443*34f6038dSAaron LI     fp->f_name = rel_rootpath(name);
444479ab7f0SSascha Wildner     fp->f_type = strdup(type);
445479ab7f0SSascha Wildner     fp->f_args = NULL;
446479ab7f0SSascha Wildner     fp->f_metadata = NULL;
447479ab7f0SSascha Wildner     fp->f_loader = -1;
448479ab7f0SSascha Wildner     fp->f_addr = loadaddr;
449479ab7f0SSascha Wildner     fp->f_size = laddr - loadaddr;
450479ab7f0SSascha Wildner 
451479ab7f0SSascha Wildner     /* recognise space consumption */
452479ab7f0SSascha Wildner     loadaddr = laddr;
453479ab7f0SSascha Wildner 
454479ab7f0SSascha Wildner     /* Add to the list of loaded files */
455479ab7f0SSascha Wildner     file_insert_tail(fp);
456479ab7f0SSascha Wildner     close(fd);
457479ab7f0SSascha Wildner     return(CMD_OK);
458479ab7f0SSascha Wildner }
459479ab7f0SSascha Wildner 
460479ab7f0SSascha Wildner /*
461479ab7f0SSascha Wildner  * Load the module (name), pass it (argc),(argv), add container file
462479ab7f0SSascha Wildner  * to the list of loaded files.
463479ab7f0SSascha Wildner  * If module is already loaded just assign new argc/argv.
464479ab7f0SSascha Wildner  */
465479ab7f0SSascha Wildner int
mod_load(char * modname,struct mod_depend * verinfo,int argc,char * argv[])466479ab7f0SSascha Wildner mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
467479ab7f0SSascha Wildner {
468479ab7f0SSascha Wildner     struct kernel_module	*mp;
469479ab7f0SSascha Wildner     int				err;
470479ab7f0SSascha Wildner     char			*filename;
471479ab7f0SSascha Wildner 
472479ab7f0SSascha Wildner     if (file_havepath(modname)) {
473479ab7f0SSascha Wildner 	printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
474479ab7f0SSascha Wildner 	return (mod_loadkld(modname, argc, argv));
475479ab7f0SSascha Wildner     }
476479ab7f0SSascha Wildner     /* see if module is already loaded */
477479ab7f0SSascha Wildner     mp = file_findmodule(NULL, modname, verinfo);
478479ab7f0SSascha Wildner     if (mp) {
479479ab7f0SSascha Wildner #ifdef moduleargs
480479ab7f0SSascha Wildner 	if (mp->m_args)
481479ab7f0SSascha Wildner 	    free(mp->m_args);
482479ab7f0SSascha Wildner 	mp->m_args = unargv(argc, argv);
483479ab7f0SSascha Wildner #endif
484479ab7f0SSascha Wildner 	snprintf(command_errbuf, sizeof(command_errbuf),
485479ab7f0SSascha Wildner 	    "warning: module '%s' already loaded", mp->m_name);
486479ab7f0SSascha Wildner 	return (0);
487479ab7f0SSascha Wildner     }
488479ab7f0SSascha Wildner     /* locate file with the module on the search path */
489479ab7f0SSascha Wildner     filename = mod_searchmodule(modname, verinfo);
490479ab7f0SSascha Wildner     if (filename == NULL) {
491479ab7f0SSascha Wildner 	snprintf(command_errbuf, sizeof(command_errbuf),
492479ab7f0SSascha Wildner 	    "can't find '%s'", modname);
493479ab7f0SSascha Wildner 	return (ENOENT);
494479ab7f0SSascha Wildner     }
495479ab7f0SSascha Wildner     err = mod_loadkld(filename, argc, argv);
496479ab7f0SSascha Wildner     return (err);
497479ab7f0SSascha Wildner }
498479ab7f0SSascha Wildner 
499479ab7f0SSascha Wildner /*
500479ab7f0SSascha Wildner  * Load specified KLD. If path is omitted, then try to locate it via
501479ab7f0SSascha Wildner  * search path.
502479ab7f0SSascha Wildner  */
503479ab7f0SSascha Wildner int
mod_loadkld(const char * kldname,int argc,char * argv[])504479ab7f0SSascha Wildner mod_loadkld(const char *kldname, int argc, char *argv[])
505479ab7f0SSascha Wildner {
506479ab7f0SSascha Wildner     struct preloaded_file	*fp, *last_file;
507479ab7f0SSascha Wildner     int				err;
508479ab7f0SSascha Wildner     char			*filename;
509479ab7f0SSascha Wildner 
510479ab7f0SSascha Wildner     /*
511479ab7f0SSascha Wildner      * Get fully qualified KLD name
512479ab7f0SSascha Wildner      */
513479ab7f0SSascha Wildner     filename = file_search(kldname, kld_ext_list);
514479ab7f0SSascha Wildner     if (filename == NULL) {
515479ab7f0SSascha Wildner 	snprintf(command_errbuf, sizeof(command_errbuf),
516479ab7f0SSascha Wildner 	    "can't find '%s'", kldname);
517479ab7f0SSascha Wildner 	return (ENOENT);
518479ab7f0SSascha Wildner     }
519479ab7f0SSascha Wildner     /*
520479ab7f0SSascha Wildner      * Check if KLD already loaded
521479ab7f0SSascha Wildner      */
522479ab7f0SSascha Wildner     fp = file_findfile(filename, NULL);
523479ab7f0SSascha Wildner     if (fp) {
524479ab7f0SSascha Wildner 	snprintf(command_errbuf, sizeof(command_errbuf),
525479ab7f0SSascha Wildner 	    "warning: KLD '%s' already loaded", filename);
526479ab7f0SSascha Wildner 	free(filename);
527479ab7f0SSascha Wildner 	return (0);
528479ab7f0SSascha Wildner     }
529479ab7f0SSascha Wildner     for (last_file = preloaded_files;
530479ab7f0SSascha Wildner 	 last_file != NULL && last_file->f_next != NULL;
531479ab7f0SSascha Wildner 	 last_file = last_file->f_next)
532479ab7f0SSascha Wildner 	;
533479ab7f0SSascha Wildner 
534479ab7f0SSascha Wildner     do {
535479ab7f0SSascha Wildner 	err = file_load(filename, loadaddr, &fp);
536479ab7f0SSascha Wildner 	if (err)
537479ab7f0SSascha Wildner 	    break;
538479ab7f0SSascha Wildner 	fp->f_args = unargv(argc, argv);
539479ab7f0SSascha Wildner 	loadaddr = fp->f_addr + fp->f_size;
540479ab7f0SSascha Wildner 	file_insert_tail(fp);		/* Add to the list of loaded files */
541479ab7f0SSascha Wildner 	if (file_load_dependencies(fp) != 0) {
542479ab7f0SSascha Wildner 	    err = ENOENT;
543479ab7f0SSascha Wildner 	    last_file->f_next = NULL;
544479ab7f0SSascha Wildner 	    loadaddr = last_file->f_addr + last_file->f_size;
545479ab7f0SSascha Wildner 	    fp = NULL;
546479ab7f0SSascha Wildner 	    break;
547479ab7f0SSascha Wildner 	}
548479ab7f0SSascha Wildner     } while(0);
549479ab7f0SSascha Wildner     if (err == EFTYPE)
550479ab7f0SSascha Wildner 	snprintf(command_errbuf, sizeof(command_errbuf),
551479ab7f0SSascha Wildner 	    "don't know how to load module '%s'", filename);
552479ab7f0SSascha Wildner     if (err && fp)
553479ab7f0SSascha Wildner 	file_discard(fp);
554479ab7f0SSascha Wildner     free(filename);
555479ab7f0SSascha Wildner     return (err);
556479ab7f0SSascha Wildner }
557479ab7f0SSascha Wildner 
558479ab7f0SSascha Wildner /*
559479ab7f0SSascha Wildner  * Find a file matching (name) and (type).
560479ab7f0SSascha Wildner  * NULL may be passed as a wildcard to either.
561479ab7f0SSascha Wildner  */
562479ab7f0SSascha Wildner struct preloaded_file *
file_findfile(char * name,char * type)563479ab7f0SSascha Wildner file_findfile(char *name, char *type)
564479ab7f0SSascha Wildner {
565479ab7f0SSascha Wildner     struct preloaded_file *fp;
566*34f6038dSAaron LI     char *rootpath;
567*34f6038dSAaron LI 
568*34f6038dSAaron LI     rootpath = NULL;
569*34f6038dSAaron LI     if (name != NULL)
570*34f6038dSAaron LI 	rootpath = rel_rootpath(name);
571479ab7f0SSascha Wildner 
572479ab7f0SSascha Wildner     for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
573*34f6038dSAaron LI 	if (((rootpath == NULL) || !strcmp(rootpath, fp->f_name)) &&
574479ab7f0SSascha Wildner 	    ((type == NULL) || !strcmp(type, fp->f_type)))
575479ab7f0SSascha Wildner 	    break;
576479ab7f0SSascha Wildner     }
577*34f6038dSAaron LI 
578*34f6038dSAaron LI     if (rootpath != NULL)
579*34f6038dSAaron LI 	free(rootpath);
580479ab7f0SSascha Wildner     return (fp);
581479ab7f0SSascha Wildner }
582479ab7f0SSascha Wildner 
583479ab7f0SSascha Wildner /*
584479ab7f0SSascha Wildner  * Find a module matching (name) inside of given file.
585479ab7f0SSascha Wildner  * NULL may be passed as a wildcard.
586479ab7f0SSascha Wildner  */
587d5ee8190SAaron LI static struct kernel_module *
file_findmodule(struct preloaded_file * fp,char * modname,struct mod_depend * verinfo)588479ab7f0SSascha Wildner file_findmodule(struct preloaded_file *fp, char *modname,
589479ab7f0SSascha Wildner 	struct mod_depend *verinfo)
590479ab7f0SSascha Wildner {
591479ab7f0SSascha Wildner     struct kernel_module *mp, *best;
592479ab7f0SSascha Wildner     int bestver, mver;
593479ab7f0SSascha Wildner 
594479ab7f0SSascha Wildner     if (fp == NULL) {
595479ab7f0SSascha Wildner 	for (fp = preloaded_files; fp; fp = fp->f_next) {
596479ab7f0SSascha Wildner 	    mp = file_findmodule(fp, modname, verinfo);
597479ab7f0SSascha Wildner 	    if (mp)
598479ab7f0SSascha Wildner 		return (mp);
599479ab7f0SSascha Wildner 	}
600479ab7f0SSascha Wildner 	return (NULL);
601479ab7f0SSascha Wildner     }
602d5ee8190SAaron LI 
603479ab7f0SSascha Wildner     best = NULL;
604479ab7f0SSascha Wildner     bestver = 0;
605479ab7f0SSascha Wildner     for (mp = fp->f_modules; mp; mp = mp->m_next) {
606479ab7f0SSascha Wildner         if (strcmp(modname, mp->m_name) == 0) {
607479ab7f0SSascha Wildner 	    if (verinfo == NULL)
608479ab7f0SSascha Wildner 		return (mp);
609479ab7f0SSascha Wildner 	    mver = mp->m_version;
610479ab7f0SSascha Wildner 	    if (mver == verinfo->md_ver_preferred)
611479ab7f0SSascha Wildner 		return (mp);
612479ab7f0SSascha Wildner 	    if (mver >= verinfo->md_ver_minimum &&
613479ab7f0SSascha Wildner 		mver <= verinfo->md_ver_maximum &&
614479ab7f0SSascha Wildner 		mver > bestver) {
615479ab7f0SSascha Wildner 		best = mp;
616479ab7f0SSascha Wildner 		bestver = mver;
617479ab7f0SSascha Wildner 	    }
618479ab7f0SSascha Wildner 	}
619479ab7f0SSascha Wildner     }
620479ab7f0SSascha Wildner     return (best);
621479ab7f0SSascha Wildner }
622479ab7f0SSascha Wildner /*
623479ab7f0SSascha Wildner  * Make a copy of (size) bytes of data from (p), and associate them as
624479ab7f0SSascha Wildner  * metadata of (type) to the module (mp).
625479ab7f0SSascha Wildner  */
626479ab7f0SSascha Wildner void
file_addmetadata(struct preloaded_file * fp,int type,size_t size,void * p)627479ab7f0SSascha Wildner file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
628479ab7f0SSascha Wildner {
629479ab7f0SSascha Wildner     struct file_metadata	*md;
630479ab7f0SSascha Wildner 
631479ab7f0SSascha Wildner     md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
632479ab7f0SSascha Wildner     md->md_size = size;
633479ab7f0SSascha Wildner     md->md_type = type;
634479ab7f0SSascha Wildner     bcopy(p, md->md_data, size);
635479ab7f0SSascha Wildner     md->md_next = fp->f_metadata;
636479ab7f0SSascha Wildner     fp->f_metadata = md;
637479ab7f0SSascha Wildner }
638479ab7f0SSascha Wildner 
639479ab7f0SSascha Wildner /*
640479ab7f0SSascha Wildner  * Find a metadata object of (type) associated with the file (fp)
641479ab7f0SSascha Wildner  */
642479ab7f0SSascha Wildner struct file_metadata *
file_findmetadata(struct preloaded_file * fp,int type)643479ab7f0SSascha Wildner file_findmetadata(struct preloaded_file *fp, int type)
644479ab7f0SSascha Wildner {
645479ab7f0SSascha Wildner     struct file_metadata *md;
646479ab7f0SSascha Wildner 
647479ab7f0SSascha Wildner     for (md = fp->f_metadata; md != NULL; md = md->md_next)
648479ab7f0SSascha Wildner 	if (md->md_type == type)
649479ab7f0SSascha Wildner 	    break;
650479ab7f0SSascha Wildner     return(md);
651479ab7f0SSascha Wildner }
652479ab7f0SSascha Wildner 
653d5ee8190SAaron LI static struct file_metadata *
metadata_next(struct file_metadata * md,int type)654479ab7f0SSascha Wildner metadata_next(struct file_metadata *md, int type)
655479ab7f0SSascha Wildner {
656479ab7f0SSascha Wildner     if (md == NULL)
657479ab7f0SSascha Wildner 	return (NULL);
658479ab7f0SSascha Wildner     while((md = md->md_next) != NULL)
659479ab7f0SSascha Wildner 	if (md->md_type == type)
660479ab7f0SSascha Wildner 	    break;
661479ab7f0SSascha Wildner     return (md);
662479ab7f0SSascha Wildner }
663479ab7f0SSascha Wildner 
664479ab7f0SSascha Wildner static char *emptyextlist[] = { "", NULL };
665479ab7f0SSascha Wildner 
666479ab7f0SSascha Wildner /*
667479ab7f0SSascha Wildner  * Check if the given file is in place and return full path to it.
668479ab7f0SSascha Wildner  */
669479ab7f0SSascha Wildner static char *
file_lookup(const char * path,const char * name,int namelen,char ** extlist)670479ab7f0SSascha Wildner file_lookup(const char *path, const char *name, int namelen, char **extlist)
671479ab7f0SSascha Wildner {
672479ab7f0SSascha Wildner     struct stat	st;
673479ab7f0SSascha Wildner     char	*result, *cp, **cpp;
674479ab7f0SSascha Wildner     size_t	pathlen, extlen;
675479ab7f0SSascha Wildner 
676479ab7f0SSascha Wildner     pathlen = strlen(path);
677479ab7f0SSascha Wildner     extlen = 0;
678479ab7f0SSascha Wildner     if (extlist == NULL)
679479ab7f0SSascha Wildner 	extlist = emptyextlist;
680479ab7f0SSascha Wildner     for (cpp = extlist; *cpp; cpp++)
681479ab7f0SSascha Wildner 	extlen = MAX(extlen, strlen(*cpp));
682479ab7f0SSascha Wildner     result = malloc(pathlen + namelen + extlen + 2 + 7 + 1);
683479ab7f0SSascha Wildner     if (result == NULL)
684479ab7f0SSascha Wildner 	return (NULL);
685479ab7f0SSascha Wildner     bcopy(path, result, pathlen);
686479ab7f0SSascha Wildner     if (pathlen > 0 && result[pathlen - 1] != '/')
687479ab7f0SSascha Wildner 	result[pathlen++] = '/';
688479ab7f0SSascha Wildner     cp = result + pathlen;
689479ab7f0SSascha Wildner     bcopy(name, cp, namelen);
690479ab7f0SSascha Wildner     cp += namelen;
691479ab7f0SSascha Wildner     for (cpp = extlist; *cpp; cpp++) {
692479ab7f0SSascha Wildner 	strcpy(cp, *cpp);
693479ab7f0SSascha Wildner 	if (rel_stat(result, &st) == 0) {
694479ab7f0SSascha Wildner 	    if (S_ISREG(st.st_mode)) {
695479ab7f0SSascha Wildner 		return result;
696479ab7f0SSascha Wildner 	    } else if (S_ISDIR(st.st_mode)) {
697479ab7f0SSascha Wildner 		strcat(result, "/kernel");
698479ab7f0SSascha Wildner 		if (rel_stat(result, &st) == 0 && S_ISREG(st.st_mode)) {
699479ab7f0SSascha Wildner 		    return result;
700479ab7f0SSascha Wildner 		}
701479ab7f0SSascha Wildner 	    }
702479ab7f0SSascha Wildner 	}
703479ab7f0SSascha Wildner     }
704479ab7f0SSascha Wildner     free(result);
705479ab7f0SSascha Wildner     return NULL;
706479ab7f0SSascha Wildner }
707479ab7f0SSascha Wildner 
708479ab7f0SSascha Wildner /*
709479ab7f0SSascha Wildner  * Check if file name have any qualifiers
710479ab7f0SSascha Wildner  */
711479ab7f0SSascha Wildner static int
file_havepath(const char * name)712479ab7f0SSascha Wildner file_havepath(const char *name)
713479ab7f0SSascha Wildner {
714479ab7f0SSascha Wildner     const char		*cp;
715479ab7f0SSascha Wildner 
716479ab7f0SSascha Wildner     archsw.arch_getdev(NULL, name, &cp);
717479ab7f0SSascha Wildner     return (cp != name || strchr(name, '/') != NULL);
718479ab7f0SSascha Wildner }
719479ab7f0SSascha Wildner 
720479ab7f0SSascha Wildner /*
721479ab7f0SSascha Wildner  * Attempt to find the file (name) on the module searchpath.
722479ab7f0SSascha Wildner  * If (name) is qualified in any way, we simply check it and
723479ab7f0SSascha Wildner  * return it or NULL.  If it is not qualified, then we attempt
724479ab7f0SSascha Wildner  * to construct a path using entries in the environment variable
725479ab7f0SSascha Wildner  * module_path.
726479ab7f0SSascha Wildner  *
727479ab7f0SSascha Wildner  * The path we return a pointer to need never be freed, as we manage
728479ab7f0SSascha Wildner  * it internally.
729479ab7f0SSascha Wildner  */
730479ab7f0SSascha Wildner static char *
file_search(const char * name,char ** extlist)731479ab7f0SSascha Wildner file_search(const char *name, char **extlist)
732479ab7f0SSascha Wildner {
733479ab7f0SSascha Wildner     struct moduledir	*mdp;
734479ab7f0SSascha Wildner     struct stat		sb;
735479ab7f0SSascha Wildner     char		*result;
736479ab7f0SSascha Wildner     int			namelen;
737479ab7f0SSascha Wildner 
738479ab7f0SSascha Wildner     /* Don't look for nothing */
739d5ee8190SAaron LI     if (name == NULL || *name == 0)
740479ab7f0SSascha Wildner 	return(NULL);
741479ab7f0SSascha Wildner 
742479ab7f0SSascha Wildner     /*
743479ab7f0SSascha Wildner      * Qualified name.  If it is a directory tag on
744479ab7f0SSascha Wildner      * a "/kernel" to it.
745479ab7f0SSascha Wildner      */
746479ab7f0SSascha Wildner     if (file_havepath(name)) {
747479ab7f0SSascha Wildner 	/* Qualified, so just see if it exists */
748479ab7f0SSascha Wildner 	if (rel_stat(name, &sb) == 0) {
749479ab7f0SSascha Wildner 	    if (S_ISDIR(sb.st_mode)) {
750479ab7f0SSascha Wildner 		result = malloc(strlen(name) + 7 + 1);
751479ab7f0SSascha Wildner 		sprintf(result, "%s/kernel", name);
752479ab7f0SSascha Wildner 		return(result);
753479ab7f0SSascha Wildner 	    } else {
754479ab7f0SSascha Wildner 		return(strdup(name));
755479ab7f0SSascha Wildner 	    }
756479ab7f0SSascha Wildner 	}
757479ab7f0SSascha Wildner 	return(NULL);
758479ab7f0SSascha Wildner     }
759d5ee8190SAaron LI 
760479ab7f0SSascha Wildner     moduledir_rebuild();
761479ab7f0SSascha Wildner     result = NULL;
762479ab7f0SSascha Wildner     namelen = strlen(name);
763479ab7f0SSascha Wildner     STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
764479ab7f0SSascha Wildner 	result = file_lookup(mdp->d_path, name, namelen, extlist);
765479ab7f0SSascha Wildner 	if (result)
766479ab7f0SSascha Wildner 	    break;
767479ab7f0SSascha Wildner     }
768479ab7f0SSascha Wildner     return(result);
769479ab7f0SSascha Wildner }
770479ab7f0SSascha Wildner 
771479ab7f0SSascha Wildner #define	INT_ALIGN(base, ptr) \
772479ab7f0SSascha Wildner 	ptr = (base) + roundup2((ptr) - (base), sizeof(int))
773479ab7f0SSascha Wildner 
774479ab7f0SSascha Wildner static char *
mod_search_hints(struct moduledir * mdp,const char * modname,struct mod_depend * verinfo)775479ab7f0SSascha Wildner mod_search_hints(struct moduledir *mdp, const char *modname,
776479ab7f0SSascha Wildner 	struct mod_depend *verinfo)
777479ab7f0SSascha Wildner {
778479ab7f0SSascha Wildner     u_char	*cp, *recptr, *bufend, *best;
779479ab7f0SSascha Wildner     char	*result;
780479ab7f0SSascha Wildner     int		*intp, bestver, blen, clen, found, ival, modnamelen, reclen;
781479ab7f0SSascha Wildner 
782479ab7f0SSascha Wildner     moduledir_readhints(mdp);
783479ab7f0SSascha Wildner     modnamelen = strlen(modname);
784479ab7f0SSascha Wildner     found = 0;
785479ab7f0SSascha Wildner     result = NULL;
786479ab7f0SSascha Wildner     bestver = 0;
787479ab7f0SSascha Wildner     if (mdp->d_hints == NULL)
788479ab7f0SSascha Wildner 	goto bad;
789479ab7f0SSascha Wildner     recptr = mdp->d_hints;
790479ab7f0SSascha Wildner     bufend = recptr + mdp->d_hintsz;
791479ab7f0SSascha Wildner     clen = blen = 0;
792479ab7f0SSascha Wildner     best = cp = NULL;
793479ab7f0SSascha Wildner     while (recptr < bufend && !found) {
794479ab7f0SSascha Wildner 	intp = (int*)recptr;
795479ab7f0SSascha Wildner 	reclen = *intp++;
796479ab7f0SSascha Wildner 	ival = *intp++;
797479ab7f0SSascha Wildner 	cp = (char*)intp;
798479ab7f0SSascha Wildner 	switch (ival) {
799479ab7f0SSascha Wildner 	case MDT_VERSION:
800479ab7f0SSascha Wildner 	    clen = *cp++;
801479ab7f0SSascha Wildner 	    if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
802479ab7f0SSascha Wildner 		break;
803479ab7f0SSascha Wildner 	    cp += clen;
804479ab7f0SSascha Wildner 	    INT_ALIGN(mdp->d_hints, cp);
805479ab7f0SSascha Wildner 	    ival = *(int*)cp;
806479ab7f0SSascha Wildner 	    cp += sizeof(int);
807479ab7f0SSascha Wildner 	    clen = *cp++;
808479ab7f0SSascha Wildner 	    if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
809479ab7f0SSascha Wildner 		found = 1;
810479ab7f0SSascha Wildner 		break;
811479ab7f0SSascha Wildner 	    }
812479ab7f0SSascha Wildner 	    if (ival >= verinfo->md_ver_minimum &&
813479ab7f0SSascha Wildner 		ival <= verinfo->md_ver_maximum &&
814479ab7f0SSascha Wildner 		ival > bestver) {
815479ab7f0SSascha Wildner 		bestver = ival;
816479ab7f0SSascha Wildner 		best = cp;
817479ab7f0SSascha Wildner 		blen = clen;
818479ab7f0SSascha Wildner 	    }
819479ab7f0SSascha Wildner 	    break;
820479ab7f0SSascha Wildner 	default:
821479ab7f0SSascha Wildner 	    break;
822479ab7f0SSascha Wildner 	}
823479ab7f0SSascha Wildner 	recptr += reclen + sizeof(int);
824479ab7f0SSascha Wildner     }
825479ab7f0SSascha Wildner     /*
826479ab7f0SSascha Wildner      * Finally check if KLD is in the place
827479ab7f0SSascha Wildner      */
828479ab7f0SSascha Wildner     if (found)
829479ab7f0SSascha Wildner 	result = file_lookup(mdp->d_path, cp, clen, NULL);
830479ab7f0SSascha Wildner     else if (best)
831479ab7f0SSascha Wildner 	result = file_lookup(mdp->d_path, best, blen, NULL);
832479ab7f0SSascha Wildner bad:
833479ab7f0SSascha Wildner     /*
834479ab7f0SSascha Wildner      * If nothing found or hints is absent - fallback to the old way
835479ab7f0SSascha Wildner      * by using "kldname[.ko]" as module name.
836479ab7f0SSascha Wildner      */
837479ab7f0SSascha Wildner     if (!found && !bestver && result == NULL)
838479ab7f0SSascha Wildner 	result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
839479ab7f0SSascha Wildner     return result;
840479ab7f0SSascha Wildner }
841479ab7f0SSascha Wildner 
842479ab7f0SSascha Wildner /*
843479ab7f0SSascha Wildner  * Attempt to locate the file containing the module (name)
844479ab7f0SSascha Wildner  */
845479ab7f0SSascha Wildner static char *
mod_searchmodule(char * name,struct mod_depend * verinfo)846479ab7f0SSascha Wildner mod_searchmodule(char *name, struct mod_depend *verinfo)
847479ab7f0SSascha Wildner {
848479ab7f0SSascha Wildner     struct	moduledir *mdp;
849479ab7f0SSascha Wildner     char	*result;
850479ab7f0SSascha Wildner 
851479ab7f0SSascha Wildner     moduledir_rebuild();
852479ab7f0SSascha Wildner     /*
853479ab7f0SSascha Wildner      * Now we ready to lookup module in the given directories
854479ab7f0SSascha Wildner      */
855479ab7f0SSascha Wildner     result = NULL;
856479ab7f0SSascha Wildner     STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
857479ab7f0SSascha Wildner 	result = mod_search_hints(mdp, name, verinfo);
858479ab7f0SSascha Wildner 	if (result)
859479ab7f0SSascha Wildner 	    break;
860479ab7f0SSascha Wildner     }
861479ab7f0SSascha Wildner 
862479ab7f0SSascha Wildner     return(result);
863479ab7f0SSascha Wildner }
864479ab7f0SSascha Wildner 
865479ab7f0SSascha Wildner int
file_addmodule(struct preloaded_file * fp,char * modname,int version,struct kernel_module ** newmp)866479ab7f0SSascha Wildner file_addmodule(struct preloaded_file *fp, char *modname, int version,
867479ab7f0SSascha Wildner 	struct kernel_module **newmp)
868479ab7f0SSascha Wildner {
869479ab7f0SSascha Wildner     struct kernel_module *mp;
870479ab7f0SSascha Wildner     struct mod_depend mdepend;
871479ab7f0SSascha Wildner 
872479ab7f0SSascha Wildner     bzero(&mdepend, sizeof(mdepend));
873479ab7f0SSascha Wildner     mdepend.md_ver_preferred = version;
874479ab7f0SSascha Wildner     mp = file_findmodule(fp, modname, &mdepend);
875479ab7f0SSascha Wildner     if (mp)
876479ab7f0SSascha Wildner 	return (EEXIST);
877479ab7f0SSascha Wildner     mp = malloc(sizeof(struct kernel_module));
878479ab7f0SSascha Wildner     if (mp == NULL)
879479ab7f0SSascha Wildner 	return (ENOMEM);
880479ab7f0SSascha Wildner     bzero(mp, sizeof(struct kernel_module));
881479ab7f0SSascha Wildner     mp->m_name = strdup(modname);
882479ab7f0SSascha Wildner     mp->m_version = version;
883479ab7f0SSascha Wildner     mp->m_fp = fp;
884479ab7f0SSascha Wildner     mp->m_next = fp->f_modules;
885479ab7f0SSascha Wildner     fp->f_modules = mp;
886479ab7f0SSascha Wildner     if (newmp)
887479ab7f0SSascha Wildner 	*newmp = mp;
888479ab7f0SSascha Wildner     return (0);
889479ab7f0SSascha Wildner }
890479ab7f0SSascha Wildner 
891479ab7f0SSascha Wildner /*
892479ab7f0SSascha Wildner  * Throw a file away
893479ab7f0SSascha Wildner  */
894479ab7f0SSascha Wildner void
file_discard(struct preloaded_file * fp)895479ab7f0SSascha Wildner file_discard(struct preloaded_file *fp)
896479ab7f0SSascha Wildner {
897479ab7f0SSascha Wildner     struct file_metadata	*md, *md1;
898479ab7f0SSascha Wildner     struct kernel_module	*mp, *mp1;
899d5ee8190SAaron LI 
900479ab7f0SSascha Wildner     if (fp == NULL)
901479ab7f0SSascha Wildner 	return;
902d5ee8190SAaron LI 
903479ab7f0SSascha Wildner     md = fp->f_metadata;
904479ab7f0SSascha Wildner     while (md) {
905479ab7f0SSascha Wildner 	md1 = md;
906479ab7f0SSascha Wildner 	md = md->md_next;
907479ab7f0SSascha Wildner 	free(md1);
908479ab7f0SSascha Wildner     }
909d5ee8190SAaron LI 
910479ab7f0SSascha Wildner     mp = fp->f_modules;
911479ab7f0SSascha Wildner     while (mp) {
912479ab7f0SSascha Wildner 	if (mp->m_name)
913479ab7f0SSascha Wildner 	    free(mp->m_name);
914d5ee8190SAaron LI #ifdef moduleargs
915d5ee8190SAaron LI 	if (mp->m_args)
916d5ee8190SAaron LI 	    free(mp->m_args);
917d5ee8190SAaron LI #endif
918479ab7f0SSascha Wildner 	mp1 = mp;
919479ab7f0SSascha Wildner 	mp = mp->m_next;
920479ab7f0SSascha Wildner 	free(mp1);
921479ab7f0SSascha Wildner     }
922d5ee8190SAaron LI 
923479ab7f0SSascha Wildner     if (fp->f_name != NULL)
924479ab7f0SSascha Wildner 	free(fp->f_name);
925479ab7f0SSascha Wildner     if (fp->f_type != NULL)
926479ab7f0SSascha Wildner 	free(fp->f_type);
927479ab7f0SSascha Wildner     if (fp->f_args != NULL)
928479ab7f0SSascha Wildner 	free(fp->f_args);
929479ab7f0SSascha Wildner     free(fp);
930479ab7f0SSascha Wildner }
931479ab7f0SSascha Wildner 
932479ab7f0SSascha Wildner /*
933479ab7f0SSascha Wildner  * Allocate a new file; must be used instead of malloc()
934479ab7f0SSascha Wildner  * to ensure safe initialisation.
935479ab7f0SSascha Wildner  */
936479ab7f0SSascha Wildner struct preloaded_file *
file_alloc(void)937479ab7f0SSascha Wildner file_alloc(void)
938479ab7f0SSascha Wildner {
939479ab7f0SSascha Wildner     struct preloaded_file	*fp;
940479ab7f0SSascha Wildner 
941479ab7f0SSascha Wildner     if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
942479ab7f0SSascha Wildner 	bzero(fp, sizeof(struct preloaded_file));
943479ab7f0SSascha Wildner     }
944479ab7f0SSascha Wildner     return (fp);
945479ab7f0SSascha Wildner }
946479ab7f0SSascha Wildner 
947479ab7f0SSascha Wildner /*
948479ab7f0SSascha Wildner  * Add a module to the chain
949479ab7f0SSascha Wildner  */
950479ab7f0SSascha Wildner static void
file_insert_tail(struct preloaded_file * fp)951479ab7f0SSascha Wildner file_insert_tail(struct preloaded_file *fp)
952479ab7f0SSascha Wildner {
953479ab7f0SSascha Wildner     struct preloaded_file	*cm;
954479ab7f0SSascha Wildner 
955479ab7f0SSascha Wildner     /* Append to list of loaded file */
956479ab7f0SSascha Wildner     fp->f_next = NULL;
957479ab7f0SSascha Wildner     if (preloaded_files == NULL) {
958479ab7f0SSascha Wildner 	preloaded_files = fp;
959479ab7f0SSascha Wildner     } else {
960479ab7f0SSascha Wildner 	for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
961479ab7f0SSascha Wildner 	    ;
962479ab7f0SSascha Wildner 	cm->f_next = fp;
963479ab7f0SSascha Wildner     }
964479ab7f0SSascha Wildner }
965479ab7f0SSascha Wildner 
966479ab7f0SSascha Wildner static char *
moduledir_fullpath(struct moduledir * mdp,const char * fname)967479ab7f0SSascha Wildner moduledir_fullpath(struct moduledir *mdp, const char *fname)
968479ab7f0SSascha Wildner {
969479ab7f0SSascha Wildner     char *cp;
970479ab7f0SSascha Wildner 
971479ab7f0SSascha Wildner     cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
972479ab7f0SSascha Wildner     if (cp == NULL)
973479ab7f0SSascha Wildner 	return NULL;
974479ab7f0SSascha Wildner     strcpy(cp, mdp->d_path);
975479ab7f0SSascha Wildner     strcat(cp, "/");
976479ab7f0SSascha Wildner     strcat(cp, fname);
977479ab7f0SSascha Wildner     return (cp);
978479ab7f0SSascha Wildner }
979479ab7f0SSascha Wildner 
980479ab7f0SSascha Wildner /*
981479ab7f0SSascha Wildner  * Read linker.hints file into memory performing some sanity checks.
982479ab7f0SSascha Wildner  */
983479ab7f0SSascha Wildner static void
moduledir_readhints(struct moduledir * mdp)984479ab7f0SSascha Wildner moduledir_readhints(struct moduledir *mdp)
985479ab7f0SSascha Wildner {
986479ab7f0SSascha Wildner     struct stat	st;
987479ab7f0SSascha Wildner     char	*path;
988479ab7f0SSascha Wildner     int		fd, size, version;
989479ab7f0SSascha Wildner 
990479ab7f0SSascha Wildner     if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
991479ab7f0SSascha Wildner 	return;
992479ab7f0SSascha Wildner     path = moduledir_fullpath(mdp, "linker.hints");
993479ab7f0SSascha Wildner     if (rel_stat(path, &st) != 0 ||
994479ab7f0SSascha Wildner 	st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
995479ab7f0SSascha Wildner 	st.st_size > 100 * 1024 || (fd = rel_open(path, NULL, O_RDONLY)) < 0) {
996479ab7f0SSascha Wildner 	free(path);
997479ab7f0SSascha Wildner 	mdp->d_flags |= MDIR_NOHINTS;
998479ab7f0SSascha Wildner 	return;
999479ab7f0SSascha Wildner     }
1000479ab7f0SSascha Wildner     free(path);
1001479ab7f0SSascha Wildner     size = read(fd, &version, sizeof(version));
1002479ab7f0SSascha Wildner     if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
1003479ab7f0SSascha Wildner 	goto bad;
1004479ab7f0SSascha Wildner     size = st.st_size - size;
1005479ab7f0SSascha Wildner     mdp->d_hints = malloc(size);
1006479ab7f0SSascha Wildner     if (mdp->d_hints == NULL)
1007479ab7f0SSascha Wildner 	goto bad;
1008479ab7f0SSascha Wildner     if (read(fd, mdp->d_hints, size) != size)
1009479ab7f0SSascha Wildner 	goto bad;
1010479ab7f0SSascha Wildner     mdp->d_hintsz = size;
1011479ab7f0SSascha Wildner     close(fd);
1012479ab7f0SSascha Wildner     return;
1013d5ee8190SAaron LI 
1014479ab7f0SSascha Wildner bad:
1015479ab7f0SSascha Wildner     close(fd);
1016479ab7f0SSascha Wildner     if (mdp->d_hints) {
1017479ab7f0SSascha Wildner 	free(mdp->d_hints);
1018479ab7f0SSascha Wildner 	mdp->d_hints = NULL;
1019479ab7f0SSascha Wildner     }
1020479ab7f0SSascha Wildner     mdp->d_flags |= MDIR_NOHINTS;
1021479ab7f0SSascha Wildner }
1022479ab7f0SSascha Wildner 
1023479ab7f0SSascha Wildner /*
1024479ab7f0SSascha Wildner  * Extract directories from the ';' separated list, remove duplicates.
1025479ab7f0SSascha Wildner  */
1026479ab7f0SSascha Wildner static void
moduledir_rebuild(void)1027479ab7f0SSascha Wildner moduledir_rebuild(void)
1028479ab7f0SSascha Wildner {
1029479ab7f0SSascha Wildner     struct	moduledir *mdp, *mtmp;
1030479ab7f0SSascha Wildner     const char	*path, *cp, *ep, *modlocal;
1031479ab7f0SSascha Wildner     size_t	cplen;
1032479ab7f0SSascha Wildner 
1033479ab7f0SSascha Wildner     path = getenv("module_path");
1034479ab7f0SSascha Wildner     if (path == NULL)
1035479ab7f0SSascha Wildner 	path = default_searchpath;
1036479ab7f0SSascha Wildner     /*
1037479ab7f0SSascha Wildner      * Rebuild list of module directories if it changed
1038479ab7f0SSascha Wildner      */
1039479ab7f0SSascha Wildner     STAILQ_FOREACH(mdp, &moduledir_list, d_link)
1040479ab7f0SSascha Wildner 	mdp->d_flags |= MDIR_REMOVED;
1041479ab7f0SSascha Wildner 
1042479ab7f0SSascha Wildner     for (ep = path; *ep != 0;  ep++) {
1043479ab7f0SSascha Wildner 	cp = ep;
1044479ab7f0SSascha Wildner 	for (; *ep != 0 && *ep != ';'; ep++)
1045479ab7f0SSascha Wildner 	    ;
1046479ab7f0SSascha Wildner 	/*
1047479ab7f0SSascha Wildner 	 * Ignore trailing slashes
1048479ab7f0SSascha Wildner 	 */
1049479ab7f0SSascha Wildner 	for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
1050479ab7f0SSascha Wildner 	    ;
1051479ab7f0SSascha Wildner 	STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1052479ab7f0SSascha Wildner 	    if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
1053479ab7f0SSascha Wildner 		continue;
1054479ab7f0SSascha Wildner 	    mdp->d_flags &= ~MDIR_REMOVED;
1055479ab7f0SSascha Wildner 	    break;
1056479ab7f0SSascha Wildner 	}
1057479ab7f0SSascha Wildner 	if (mdp == NULL) {
1058479ab7f0SSascha Wildner 	    mdp = malloc(sizeof(*mdp) + cplen + 1);
1059479ab7f0SSascha Wildner 	    if (mdp == NULL)
1060479ab7f0SSascha Wildner 		return;
1061479ab7f0SSascha Wildner 	    mdp->d_path = (char*)(mdp + 1);
1062479ab7f0SSascha Wildner 	    bcopy(cp, mdp->d_path, cplen);
1063479ab7f0SSascha Wildner 	    mdp->d_path[cplen] = 0;
1064479ab7f0SSascha Wildner 	    mdp->d_hints = NULL;
1065479ab7f0SSascha Wildner 	    mdp->d_flags = 0;
1066479ab7f0SSascha Wildner 	    STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1067479ab7f0SSascha Wildner 	}
1068479ab7f0SSascha Wildner 	if (*ep == 0)
1069479ab7f0SSascha Wildner 	    break;
1070479ab7f0SSascha Wildner     }
1071479ab7f0SSascha Wildner     /*
1072479ab7f0SSascha Wildner      * Include modules.local if requested
1073479ab7f0SSascha Wildner      */
1074479ab7f0SSascha Wildner     modlocal = getenv("local_modules");
1075479ab7f0SSascha Wildner     if (modlocal != NULL && strcmp(modlocal, "YES") == 0) {
1076479ab7f0SSascha Wildner 	cp = local_module_path;
1077479ab7f0SSascha Wildner 	cplen = strlen(local_module_path);
1078479ab7f0SSascha Wildner 	STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1079479ab7f0SSascha Wildner 	    if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
1080479ab7f0SSascha Wildner 		continue;
1081479ab7f0SSascha Wildner 	    mdp->d_flags &= ~MDIR_REMOVED;
1082479ab7f0SSascha Wildner 	    break;
1083479ab7f0SSascha Wildner 	}
1084479ab7f0SSascha Wildner 	if (mdp == NULL) {
1085479ab7f0SSascha Wildner 	    mdp = malloc(sizeof(*mdp) + cplen + 1);
1086479ab7f0SSascha Wildner 	    if (mdp == NULL)
1087479ab7f0SSascha Wildner 		return;
1088479ab7f0SSascha Wildner 	    mdp->d_path = (char*)(mdp + 1);
1089479ab7f0SSascha Wildner 	    bcopy(local_module_path, mdp->d_path, cplen);
1090479ab7f0SSascha Wildner 	    mdp->d_path[cplen] = 0;
1091479ab7f0SSascha Wildner 	    mdp->d_hints = NULL;
1092479ab7f0SSascha Wildner 	    mdp->d_flags = 0;
1093479ab7f0SSascha Wildner 	    STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1094479ab7f0SSascha Wildner 	}
1095479ab7f0SSascha Wildner     }
1096479ab7f0SSascha Wildner     /*
1097479ab7f0SSascha Wildner      * Delete unused directories if any
1098479ab7f0SSascha Wildner      */
1099479ab7f0SSascha Wildner     mdp = STAILQ_FIRST(&moduledir_list);
1100479ab7f0SSascha Wildner     while (mdp) {
1101479ab7f0SSascha Wildner 	if ((mdp->d_flags & MDIR_REMOVED) == 0) {
1102479ab7f0SSascha Wildner 	    mdp = STAILQ_NEXT(mdp, d_link);
1103479ab7f0SSascha Wildner 	} else {
1104479ab7f0SSascha Wildner 	    if (mdp->d_hints)
1105479ab7f0SSascha Wildner 		free(mdp->d_hints);
1106479ab7f0SSascha Wildner 	    mtmp = mdp;
1107479ab7f0SSascha Wildner 	    mdp = STAILQ_NEXT(mdp, d_link);
1108479ab7f0SSascha Wildner 	    STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
1109479ab7f0SSascha Wildner 	    free(mtmp);
1110479ab7f0SSascha Wildner 	}
1111479ab7f0SSascha Wildner     }
1112479ab7f0SSascha Wildner }
1113