module.c revision 294417
1246149Ssjg/*-
2246149Ssjg * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3246149Ssjg * All rights reserved.
4246149Ssjg *
5246149Ssjg * Redistribution and use in source and binary forms, with or without
6246149Ssjg * modification, are permitted provided that the following conditions
7321964Ssjg * are met:
8246149Ssjg * 1. Redistributions of source code must retain the above copyright
9246149Ssjg *    notice, this list of conditions and the following disclaimer.
10246149Ssjg * 2. Redistributions in binary form must reproduce the above copyright
11246149Ssjg *    notice, this list of conditions and the following disclaimer in the
12246149Ssjg *    documentation and/or other materials provided with the distribution.
13246149Ssjg *
14246149Ssjg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15246149Ssjg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16246149Ssjg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17246149Ssjg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18246149Ssjg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19246149Ssjg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20246149Ssjg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21246149Ssjg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22246149Ssjg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23246149Ssjg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24246149Ssjg * SUCH DAMAGE.
25246149Ssjg */
26246149Ssjg
27246149Ssjg#include <sys/cdefs.h>
28246149Ssjg__FBSDID("$FreeBSD: stable/10/sys/boot/common/module.c 294417 2016-01-20 13:23:02Z royger $");
29246149Ssjg
30246149Ssjg/*
31246149Ssjg * file/module function dispatcher, support, etc.
32246149Ssjg */
33246149Ssjg
34246149Ssjg#include <stand.h>
35246149Ssjg#include <string.h>
36246149Ssjg#include <sys/param.h>
37246149Ssjg#include <sys/linker.h>
38246149Ssjg#include <sys/module.h>
39246149Ssjg#include <sys/queue.h>
40246149Ssjg
41246149Ssjg#include "bootstrap.h"
42246149Ssjg
43246149Ssjg#define	MDIR_REMOVED	0x0001
44246149Ssjg#define	MDIR_NOHINTS	0x0002
45246149Ssjg
46246149Ssjgstruct moduledir {
47246149Ssjg	char	*d_path;	/* path of modules directory */
48246149Ssjg	u_char	*d_hints;	/* content of linker.hints file */
49246149Ssjg	int	d_hintsz;	/* size of hints data */
50246149Ssjg	int	d_flags;
51246149Ssjg	STAILQ_ENTRY(moduledir) d_link;
52246149Ssjg};
53246149Ssjg
54246149Ssjgstatic int			file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
55246149Ssjgstatic int			file_load_dependencies(struct preloaded_file *base_mod);
56246149Ssjgstatic char *			file_search(const char *name, char **extlist);
57246149Ssjgstatic struct kernel_module *	file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
58246149Ssjgstatic int			file_havepath(const char *name);
59246149Ssjgstatic char			*mod_searchmodule(char *name, struct mod_depend *verinfo);
60246149Ssjgstatic void			file_insert_tail(struct preloaded_file *mp);
61246149Ssjgstruct file_metadata*		metadata_next(struct file_metadata *base_mp, int type);
62246149Ssjgstatic void			moduledir_readhints(struct moduledir *mdp);
63246149Ssjgstatic void			moduledir_rebuild(void);
64246149Ssjg
65246149Ssjg/* load address should be tweaked by first module loaded (kernel) */
66246149Ssjgstatic vm_offset_t	loadaddr = 0;
67246149Ssjg
68246149Ssjg#if defined(LOADER_FDT_SUPPORT)
69246149Ssjgstatic const char	*default_searchpath =
70246149Ssjg    "/boot/kernel;/boot/modules;/boot/dtb";
71246149Ssjg#else
72246149Ssjgstatic const char	*default_searchpath ="/boot/kernel;/boot/modules";
73246149Ssjg#endif
74246149Ssjg
75246149Ssjgstatic STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list);
76246149Ssjg
77246149Ssjgstruct preloaded_file *preloaded_files = NULL;
78246149Ssjg
79246149Ssjgstatic char *kld_ext_list[] = {
80246149Ssjg    ".ko",
81246149Ssjg    "",
82246149Ssjg    ".debug",
83246149Ssjg    NULL
84246149Ssjg};
85246149Ssjg
86246149Ssjg
87246149Ssjg/*
88246149Ssjg * load an object, either a disk file or code module.
89246149Ssjg *
90246149Ssjg * To load a file, the syntax is:
91246149Ssjg *
92246149Ssjg * load -t <type> <path>
93246149Ssjg *
94246149Ssjg * code modules are loaded as:
95246149Ssjg *
96246149Ssjg * load <path> <options>
97246149Ssjg */
98246149Ssjg
99246149SsjgCOMMAND_SET(load, "load", "load a kernel or module", command_load);
100246149Ssjg
101246149Ssjgstatic int
102246149Ssjgcommand_load(int argc, char *argv[])
103246149Ssjg{
104246149Ssjg    char	*typestr;
105246149Ssjg    int		dofile, dokld, ch, error;
106246149Ssjg
107246149Ssjg    dokld = dofile = 0;
108246149Ssjg    optind = 1;
109246149Ssjg    optreset = 1;
110246149Ssjg    typestr = NULL;
111246149Ssjg    if (argc == 1) {
112246149Ssjg	command_errmsg = "no filename specified";
113246149Ssjg	return(CMD_ERROR);
114246149Ssjg    }
115321964Ssjg    while ((ch = getopt(argc, argv, "kt:")) != -1) {
116246149Ssjg	switch(ch) {
117321964Ssjg	case 'k':
118246149Ssjg	    dokld = 1;
119321964Ssjg	    break;
120246149Ssjg	case 't':
121246149Ssjg	    typestr = optarg;
122246149Ssjg	    dofile = 1;
123246149Ssjg	    break;
124246149Ssjg	case '?':
125246149Ssjg	default:
126246149Ssjg	    /* getopt has already reported an error */
127246149Ssjg	    return(CMD_OK);
128246149Ssjg	}
129246149Ssjg    }
130246149Ssjg    argv += (optind - 1);
131246149Ssjg    argc -= (optind - 1);
132246149Ssjg
133246149Ssjg    /*
134246149Ssjg     * Request to load a raw file?
135246149Ssjg     */
136246149Ssjg    if (dofile) {
137246149Ssjg	if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) {
138246149Ssjg	    command_errmsg = "invalid load type";
139246149Ssjg	    return(CMD_ERROR);
140246149Ssjg	}
141246149Ssjg	return (file_loadraw(argv[1], typestr, 1) ? CMD_OK : CMD_ERROR);
142246149Ssjg    }
143246149Ssjg    /*
144246149Ssjg     * Do we have explicit KLD load ?
145246149Ssjg     */
146246149Ssjg    if (dokld || file_havepath(argv[1])) {
147246149Ssjg	error = mod_loadkld(argv[1], argc - 2, argv + 2);
148246149Ssjg	if (error == EEXIST)
149246149Ssjg	    sprintf(command_errbuf, "warning: KLD '%s' already loaded", argv[1]);
150246149Ssjg	return (error == 0 ? CMD_OK : CMD_ERROR);
151246149Ssjg    }
152246149Ssjg    /*
153246149Ssjg     * Looks like a request for a module.
154246149Ssjg     */
155246149Ssjg    error = mod_load(argv[1], NULL, argc - 2, argv + 2);
156246149Ssjg    if (error == EEXIST)
157246149Ssjg	sprintf(command_errbuf, "warning: module '%s' already loaded", argv[1]);
158246149Ssjg    return (error == 0 ? CMD_OK : CMD_ERROR);
159246149Ssjg}
160246149Ssjg
161246149SsjgCOMMAND_SET(load_geli, "load_geli", "load a geli key", command_load_geli);
162246149Ssjg
163246149Ssjgstatic int
164246149Ssjgcommand_load_geli(int argc, char *argv[])
165246149Ssjg{
166246149Ssjg    char	typestr[80];
167246149Ssjg    char	*cp;
168246149Ssjg    int		ch, num;
169246149Ssjg
170246149Ssjg    if (argc < 3) {
171246149Ssjg	    command_errmsg = "usage is [-n key#] <prov> <file>";
172246149Ssjg	    return(CMD_ERROR);
173246149Ssjg    }
174246149Ssjg
175246149Ssjg    num = 0;
176246149Ssjg    optind = 1;
177246149Ssjg    optreset = 1;
178246149Ssjg    while ((ch = getopt(argc, argv, "n:")) != -1) {
179246149Ssjg	switch(ch) {
180246149Ssjg	case 'n':
181246149Ssjg	    num = strtol(optarg, &cp, 0);
182246149Ssjg	    if (cp == optarg) {
183246149Ssjg		    sprintf(command_errbuf, "bad key index '%s'", optarg);
184246149Ssjg		    return(CMD_ERROR);
185246149Ssjg	    }
186246149Ssjg	    break;
187246149Ssjg	case '?':
188246149Ssjg	default:
189246149Ssjg	    /* getopt has already reported an error */
190246149Ssjg	    return(CMD_OK);
191246149Ssjg	}
192246149Ssjg    }
193246149Ssjg    argv += (optind - 1);
194246149Ssjg    argc -= (optind - 1);
195246149Ssjg    sprintf(typestr, "%s:geli_keyfile%d", argv[1], num);
196246149Ssjg    return (file_loadraw(argv[2], typestr, 1) ? CMD_OK : CMD_ERROR);
197246149Ssjg}
198246149Ssjg
199246149SsjgCOMMAND_SET(unload, "unload", "unload all modules", command_unload);
200246149Ssjg
201246149Ssjgstatic int
202246149Ssjgcommand_unload(int argc, char *argv[])
203246149Ssjg{
204246149Ssjg    struct preloaded_file	*fp;
205246149Ssjg
206246149Ssjg    while (preloaded_files != NULL) {
207246149Ssjg	fp = preloaded_files;
208246149Ssjg	preloaded_files = preloaded_files->f_next;
209246149Ssjg	file_discard(fp);
210    }
211    loadaddr = 0;
212    unsetenv("kernelname");
213    return(CMD_OK);
214}
215
216COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
217
218static int
219command_lsmod(int argc, char *argv[])
220{
221    struct preloaded_file	*fp;
222    struct kernel_module	*mp;
223    struct file_metadata	*md;
224    char			lbuf[80];
225    int				ch, verbose;
226
227    verbose = 0;
228    optind = 1;
229    optreset = 1;
230    while ((ch = getopt(argc, argv, "v")) != -1) {
231	switch(ch) {
232	case 'v':
233	    verbose = 1;
234	    break;
235	case '?':
236	default:
237	    /* getopt has already reported an error */
238	    return(CMD_OK);
239	}
240    }
241
242    pager_open();
243    for (fp = preloaded_files; fp; fp = fp->f_next) {
244	sprintf(lbuf, " %p: %s (%s, 0x%lx)\n",
245		(void *) fp->f_addr, fp->f_name, fp->f_type, (long) fp->f_size);
246	pager_output(lbuf);
247	if (fp->f_args != NULL) {
248	    pager_output("    args: ");
249	    pager_output(fp->f_args);
250	    pager_output("\n");
251	}
252	if (fp->f_modules) {
253	    pager_output("  modules: ");
254	    for (mp = fp->f_modules; mp; mp = mp->m_next) {
255		sprintf(lbuf, "%s.%d ", mp->m_name, mp->m_version);
256		pager_output(lbuf);
257	    }
258	    pager_output("\n");
259	}
260	if (verbose) {
261	    /* XXX could add some formatting smarts here to display some better */
262	    for (md = fp->f_metadata; md != NULL; md = md->md_next) {
263		sprintf(lbuf, "      0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
264		pager_output(lbuf);
265	    }
266	}
267    }
268    pager_close();
269    return(CMD_OK);
270}
271
272/*
273 * File level interface, functions file_*
274 */
275int
276file_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
277{
278    static int last_file_format = 0;
279    struct preloaded_file *fp;
280    int error;
281    int i;
282
283    if (archsw.arch_loadaddr != NULL)
284	dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest);
285
286    error = EFTYPE;
287    for (i = last_file_format, fp = NULL;
288	file_formats[i] && fp == NULL; i++) {
289	error = (file_formats[i]->l_load)(filename, dest, &fp);
290	if (error == 0) {
291	    fp->f_loader = last_file_format = i; /* remember the loader */
292	    *result = fp;
293	    break;
294	} else if (last_file_format == i && i != 0) {
295	    /* Restart from the beginning */
296	    i = -1;
297	    last_file_format = 0;
298	    fp = NULL;
299	    continue;
300	}
301	if (error == EFTYPE)
302	    continue;		/* Unknown to this handler? */
303	if (error) {
304	    sprintf(command_errbuf, "can't load file '%s': %s",
305		filename, strerror(error));
306	    break;
307	}
308    }
309    return (error);
310}
311
312static int
313file_load_dependencies(struct preloaded_file *base_file)
314{
315    struct file_metadata *md;
316    struct preloaded_file *fp;
317    struct mod_depend *verinfo;
318    struct kernel_module *mp;
319    char *dmodname;
320    int error;
321
322    md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
323    if (md == NULL)
324	return (0);
325    error = 0;
326    do {
327	verinfo = (struct mod_depend*)md->md_data;
328	dmodname = (char *)(verinfo + 1);
329	if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
330	    printf("loading required module '%s'\n", dmodname);
331	    error = mod_load(dmodname, verinfo, 0, NULL);
332	    if (error)
333		break;
334	    /*
335	     * If module loaded via kld name which isn't listed
336	     * in the linker.hints file, we should check if it have
337	     * required version.
338	     */
339	    mp = file_findmodule(NULL, dmodname, verinfo);
340	    if (mp == NULL) {
341		sprintf(command_errbuf, "module '%s' exists but with wrong version",
342		    dmodname);
343		error = ENOENT;
344		break;
345	    }
346	}
347	md = metadata_next(md, MODINFOMD_DEPLIST);
348    } while (md);
349    if (!error)
350	return (0);
351    /* Load failed; discard everything */
352    while (base_file != NULL) {
353        fp = base_file;
354        base_file = base_file->f_next;
355        file_discard(fp);
356    }
357    return (error);
358}
359
360/*
361 * We've been asked to load (name) as (type), so just suck it in,
362 * no arguments or anything.
363 */
364struct preloaded_file *
365file_loadraw(char *name, char *type, int insert)
366{
367    struct preloaded_file	*fp;
368    char			*cp;
369    int				fd, got;
370    vm_offset_t			laddr;
371
372    /* We can't load first */
373    if ((file_findfile(NULL, NULL)) == NULL) {
374	command_errmsg = "can't load file before kernel";
375	return(NULL);
376    }
377
378    /* locate the file on the load path */
379    cp = file_search(name, NULL);
380    if (cp == NULL) {
381	sprintf(command_errbuf, "can't find '%s'", name);
382	return(NULL);
383    }
384    name = cp;
385
386    if ((fd = open(name, O_RDONLY)) < 0) {
387	sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno));
388	free(name);
389	return(NULL);
390    }
391
392    if (archsw.arch_loadaddr != NULL)
393	loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
394
395    laddr = loadaddr;
396    for (;;) {
397	/* read in 4k chunks; size is not really important */
398	got = archsw.arch_readin(fd, laddr, 4096);
399	if (got == 0)				/* end of file */
400	    break;
401	if (got < 0) {				/* error */
402	    sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno));
403	    free(name);
404	    close(fd);
405	    return(NULL);
406	}
407	laddr += got;
408    }
409
410    /* Looks OK so far; create & populate control structure */
411    fp = file_alloc();
412    fp->f_name = strdup(name);
413    fp->f_type = strdup(type);
414    fp->f_args = NULL;
415    fp->f_metadata = NULL;
416    fp->f_loader = -1;
417    fp->f_addr = loadaddr;
418    fp->f_size = laddr - loadaddr;
419
420    /* recognise space consumption */
421    loadaddr = laddr;
422
423    /* Add to the list of loaded files */
424    if (insert != 0)
425    	file_insert_tail(fp);
426    close(fd);
427    return(fp);
428}
429
430/*
431 * Load the module (name), pass it (argc),(argv), add container file
432 * to the list of loaded files.
433 * If module is already loaded just assign new argc/argv.
434 */
435int
436mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
437{
438    struct kernel_module	*mp;
439    int				err;
440    char			*filename;
441
442    if (file_havepath(modname)) {
443	printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
444	return (mod_loadkld(modname, argc, argv));
445    }
446    /* see if module is already loaded */
447    mp = file_findmodule(NULL, modname, verinfo);
448    if (mp) {
449#ifdef moduleargs
450	if (mp->m_args)
451	    free(mp->m_args);
452	mp->m_args = unargv(argc, argv);
453#endif
454	sprintf(command_errbuf, "warning: module '%s' already loaded", mp->m_name);
455	return (0);
456    }
457    /* locate file with the module on the search path */
458    filename = mod_searchmodule(modname, verinfo);
459    if (filename == NULL) {
460	sprintf(command_errbuf, "can't find '%s'", modname);
461	return (ENOENT);
462    }
463    err = mod_loadkld(filename, argc, argv);
464    return (err);
465}
466
467/*
468 * Load specified KLD. If path is omitted, then try to locate it via
469 * search path.
470 */
471int
472mod_loadkld(const char *kldname, int argc, char *argv[])
473{
474    struct preloaded_file	*fp, *last_file;
475    int				err;
476    char			*filename;
477
478    /*
479     * Get fully qualified KLD name
480     */
481    filename = file_search(kldname, kld_ext_list);
482    if (filename == NULL) {
483	sprintf(command_errbuf, "can't find '%s'", kldname);
484	return (ENOENT);
485    }
486    /*
487     * Check if KLD already loaded
488     */
489    fp = file_findfile(filename, NULL);
490    if (fp) {
491	sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename);
492	free(filename);
493	return (0);
494    }
495    for (last_file = preloaded_files;
496	 last_file != NULL && last_file->f_next != NULL;
497	 last_file = last_file->f_next)
498	;
499
500    do {
501	err = file_load(filename, loadaddr, &fp);
502	if (err)
503	    break;
504	fp->f_args = unargv(argc, argv);
505	loadaddr = fp->f_addr + fp->f_size;
506	file_insert_tail(fp);		/* Add to the list of loaded files */
507	if (file_load_dependencies(fp) != 0) {
508	    err = ENOENT;
509	    last_file->f_next = NULL;
510	    loadaddr = last_file->f_addr + last_file->f_size;
511	    fp = NULL;
512	    break;
513	}
514    } while(0);
515    if (err == EFTYPE)
516	sprintf(command_errbuf, "don't know how to load module '%s'", filename);
517    if (err && fp)
518	file_discard(fp);
519    free(filename);
520    return (err);
521}
522
523/*
524 * Find a file matching (name) and (type).
525 * NULL may be passed as a wildcard to either.
526 */
527struct preloaded_file *
528file_findfile(const char *name, const char *type)
529{
530    struct preloaded_file *fp;
531
532    for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
533	if (((name == NULL) || !strcmp(name, fp->f_name)) &&
534	    ((type == NULL) || !strcmp(type, fp->f_type)))
535	    break;
536    }
537    return (fp);
538}
539
540/*
541 * Find a module matching (name) inside of given file.
542 * NULL may be passed as a wildcard.
543 */
544struct kernel_module *
545file_findmodule(struct preloaded_file *fp, char *modname,
546	struct mod_depend *verinfo)
547{
548    struct kernel_module *mp, *best;
549    int bestver, mver;
550
551    if (fp == NULL) {
552	for (fp = preloaded_files; fp; fp = fp->f_next) {
553	    mp = file_findmodule(fp, modname, verinfo);
554    	    if (mp)
555		return (mp);
556	}
557	return (NULL);
558    }
559    best = NULL;
560    bestver = 0;
561    for (mp = fp->f_modules; mp; mp = mp->m_next) {
562        if (strcmp(modname, mp->m_name) == 0) {
563	    if (verinfo == NULL)
564		return (mp);
565	    mver = mp->m_version;
566	    if (mver == verinfo->md_ver_preferred)
567		return (mp);
568	    if (mver >= verinfo->md_ver_minimum &&
569		mver <= verinfo->md_ver_maximum &&
570		mver > bestver) {
571		best = mp;
572		bestver = mver;
573	    }
574	}
575    }
576    return (best);
577}
578/*
579 * Make a copy of (size) bytes of data from (p), and associate them as
580 * metadata of (type) to the module (mp).
581 */
582void
583file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
584{
585    struct file_metadata	*md;
586
587    md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
588    md->md_size = size;
589    md->md_type = type;
590    bcopy(p, md->md_data, size);
591    md->md_next = fp->f_metadata;
592    fp->f_metadata = md;
593}
594
595/*
596 * Find a metadata object of (type) associated with the file (fp)
597 */
598struct file_metadata *
599file_findmetadata(struct preloaded_file *fp, int type)
600{
601    struct file_metadata *md;
602
603    for (md = fp->f_metadata; md != NULL; md = md->md_next)
604	if (md->md_type == type)
605	    break;
606    return(md);
607}
608
609struct file_metadata *
610metadata_next(struct file_metadata *md, int type)
611{
612    if (md == NULL)
613	return (NULL);
614    while((md = md->md_next) != NULL)
615	if (md->md_type == type)
616	    break;
617    return (md);
618}
619
620static char *emptyextlist[] = { "", NULL };
621
622/*
623 * Check if the given file is in place and return full path to it.
624 */
625static char *
626file_lookup(const char *path, const char *name, int namelen, char **extlist)
627{
628    struct stat	st;
629    char	*result, *cp, **cpp;
630    int		pathlen, extlen, len;
631
632    pathlen = strlen(path);
633    extlen = 0;
634    if (extlist == NULL)
635	extlist = emptyextlist;
636    for (cpp = extlist; *cpp; cpp++) {
637	len = strlen(*cpp);
638	if (len > extlen)
639	    extlen = len;
640    }
641    result = malloc(pathlen + namelen + extlen + 2);
642    if (result == NULL)
643	return (NULL);
644    bcopy(path, result, pathlen);
645    if (pathlen > 0 && result[pathlen - 1] != '/')
646	result[pathlen++] = '/';
647    cp = result + pathlen;
648    bcopy(name, cp, namelen);
649    cp += namelen;
650    for (cpp = extlist; *cpp; cpp++) {
651	strcpy(cp, *cpp);
652	if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
653	    return result;
654    }
655    free(result);
656    return NULL;
657}
658
659/*
660 * Check if file name have any qualifiers
661 */
662static int
663file_havepath(const char *name)
664{
665    const char		*cp;
666
667    archsw.arch_getdev(NULL, name, &cp);
668    return (cp != name || strchr(name, '/') != NULL);
669}
670
671/*
672 * Attempt to find the file (name) on the module searchpath.
673 * If (name) is qualified in any way, we simply check it and
674 * return it or NULL.  If it is not qualified, then we attempt
675 * to construct a path using entries in the environment variable
676 * module_path.
677 *
678 * The path we return a pointer to need never be freed, as we manage
679 * it internally.
680 */
681static char *
682file_search(const char *name, char **extlist)
683{
684    struct moduledir	*mdp;
685    struct stat		sb;
686    char		*result;
687    int			namelen;
688
689    /* Don't look for nothing */
690    if (name == NULL)
691	return(NULL);
692
693    if (*name == 0)
694	return(strdup(name));
695
696    if (file_havepath(name)) {
697	/* Qualified, so just see if it exists */
698	if (stat(name, &sb) == 0)
699	    return(strdup(name));
700	return(NULL);
701    }
702    moduledir_rebuild();
703    result = NULL;
704    namelen = strlen(name);
705    STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
706	result = file_lookup(mdp->d_path, name, namelen, extlist);
707	if (result)
708	    break;
709    }
710    return(result);
711}
712
713#define	INT_ALIGN(base, ptr)	ptr = \
714	(base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
715
716static char *
717mod_search_hints(struct moduledir *mdp, const char *modname,
718	struct mod_depend *verinfo)
719{
720    u_char	*cp, *recptr, *bufend, *best;
721    char	*result;
722    int		*intp, bestver, blen, clen, found, ival, modnamelen, reclen;
723
724    moduledir_readhints(mdp);
725    modnamelen = strlen(modname);
726    found = 0;
727    result = NULL;
728    bestver = 0;
729    if (mdp->d_hints == NULL)
730	goto bad;
731    recptr = mdp->d_hints;
732    bufend = recptr + mdp->d_hintsz;
733    clen = blen = 0;
734    best = cp = NULL;
735    while (recptr < bufend && !found) {
736	intp = (int*)recptr;
737	reclen = *intp++;
738	ival = *intp++;
739	cp = (char*)intp;
740	switch (ival) {
741	case MDT_VERSION:
742	    clen = *cp++;
743	    if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
744		break;
745	    cp += clen;
746	    INT_ALIGN(mdp->d_hints, cp);
747	    ival = *(int*)cp;
748	    cp += sizeof(int);
749	    clen = *cp++;
750	    if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
751		found = 1;
752		break;
753	    }
754	    if (ival >= verinfo->md_ver_minimum &&
755		ival <= verinfo->md_ver_maximum &&
756		ival > bestver) {
757		bestver = ival;
758		best = cp;
759		blen = clen;
760	    }
761	    break;
762	default:
763	    break;
764	}
765	recptr += reclen + sizeof(int);
766    }
767    /*
768     * Finally check if KLD is in the place
769     */
770    if (found)
771	result = file_lookup(mdp->d_path, cp, clen, NULL);
772    else if (best)
773	result = file_lookup(mdp->d_path, best, blen, NULL);
774bad:
775    /*
776     * If nothing found or hints is absent - fallback to the old way
777     * by using "kldname[.ko]" as module name.
778     */
779    if (!found && !bestver && result == NULL)
780	result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
781    return result;
782}
783
784/*
785 * Attempt to locate the file containing the module (name)
786 */
787static char *
788mod_searchmodule(char *name, struct mod_depend *verinfo)
789{
790    struct	moduledir *mdp;
791    char	*result;
792
793    moduledir_rebuild();
794    /*
795     * Now we ready to lookup module in the given directories
796     */
797    result = NULL;
798    STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
799	result = mod_search_hints(mdp, name, verinfo);
800	if (result)
801	    break;
802    }
803
804    return(result);
805}
806
807int
808file_addmodule(struct preloaded_file *fp, char *modname, int version,
809	struct kernel_module **newmp)
810{
811    struct kernel_module *mp;
812    struct mod_depend mdepend;
813
814    bzero(&mdepend, sizeof(mdepend));
815    mdepend.md_ver_preferred = version;
816    mp = file_findmodule(fp, modname, &mdepend);
817    if (mp)
818	return (EEXIST);
819    mp = malloc(sizeof(struct kernel_module));
820    if (mp == NULL)
821	return (ENOMEM);
822    bzero(mp, sizeof(struct kernel_module));
823    mp->m_name = strdup(modname);
824    mp->m_version = version;
825    mp->m_fp = fp;
826    mp->m_next = fp->f_modules;
827    fp->f_modules = mp;
828    if (newmp)
829	*newmp = mp;
830    return (0);
831}
832
833/*
834 * Throw a file away
835 */
836void
837file_discard(struct preloaded_file *fp)
838{
839    struct file_metadata	*md, *md1;
840    struct kernel_module	*mp, *mp1;
841    if (fp == NULL)
842	return;
843    md = fp->f_metadata;
844    while (md) {
845	md1 = md;
846	md = md->md_next;
847	free(md1);
848    }
849    mp = fp->f_modules;
850    while (mp) {
851	if (mp->m_name)
852	    free(mp->m_name);
853	mp1 = mp;
854	mp = mp->m_next;
855	free(mp1);
856    }
857    if (fp->f_name != NULL)
858	free(fp->f_name);
859    if (fp->f_type != NULL)
860        free(fp->f_type);
861    if (fp->f_args != NULL)
862        free(fp->f_args);
863    free(fp);
864}
865
866/*
867 * Allocate a new file; must be used instead of malloc()
868 * to ensure safe initialisation.
869 */
870struct preloaded_file *
871file_alloc(void)
872{
873    struct preloaded_file	*fp;
874
875    if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
876	bzero(fp, sizeof(struct preloaded_file));
877    }
878    return (fp);
879}
880
881/*
882 * Add a module to the chain
883 */
884static void
885file_insert_tail(struct preloaded_file *fp)
886{
887    struct preloaded_file	*cm;
888
889    /* Append to list of loaded file */
890    fp->f_next = NULL;
891    if (preloaded_files == NULL) {
892	preloaded_files = fp;
893    } else {
894	for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
895	    ;
896	cm->f_next = fp;
897    }
898}
899
900static char *
901moduledir_fullpath(struct moduledir *mdp, const char *fname)
902{
903    char *cp;
904
905    cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
906    if (cp == NULL)
907	return NULL;
908    strcpy(cp, mdp->d_path);
909    strcat(cp, "/");
910    strcat(cp, fname);
911    return (cp);
912}
913
914/*
915 * Read linker.hints file into memory performing some sanity checks.
916 */
917static void
918moduledir_readhints(struct moduledir *mdp)
919{
920    struct stat	st;
921    char	*path;
922    int		fd, size, version;
923
924    if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
925	return;
926    path = moduledir_fullpath(mdp, "linker.hints");
927    if (stat(path, &st) != 0 ||
928	st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
929	st.st_size > 100 * 1024 || (fd = open(path, O_RDONLY)) < 0) {
930	free(path);
931	mdp->d_flags |= MDIR_NOHINTS;
932	return;
933    }
934    free(path);
935    size = read(fd, &version, sizeof(version));
936    if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
937	goto bad;
938    size = st.st_size - size;
939    mdp->d_hints = malloc(size);
940    if (mdp->d_hints == NULL)
941	goto bad;
942    if (read(fd, mdp->d_hints, size) != size)
943	goto bad;
944    mdp->d_hintsz = size;
945    close(fd);
946    return;
947bad:
948    close(fd);
949    if (mdp->d_hints) {
950	free(mdp->d_hints);
951	mdp->d_hints = NULL;
952    }
953    mdp->d_flags |= MDIR_NOHINTS;
954    return;
955}
956
957/*
958 * Extract directories from the ';' separated list, remove duplicates.
959 */
960static void
961moduledir_rebuild(void)
962{
963    struct	moduledir *mdp, *mtmp;
964    const char	*path, *cp, *ep;
965    int		cplen;
966
967    path = getenv("module_path");
968    if (path == NULL)
969	path = default_searchpath;
970    /*
971     * Rebuild list of module directories if it changed
972     */
973    STAILQ_FOREACH(mdp, &moduledir_list, d_link)
974	mdp->d_flags |= MDIR_REMOVED;
975
976    for (ep = path; *ep != 0;  ep++) {
977	cp = ep;
978	for (; *ep != 0 && *ep != ';'; ep++)
979	    ;
980	/*
981	 * Ignore trailing slashes
982	 */
983	for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
984	    ;
985	STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
986	    if (strlen(mdp->d_path) != cplen ||	bcmp(cp, mdp->d_path, cplen) != 0)
987		continue;
988	    mdp->d_flags &= ~MDIR_REMOVED;
989	    break;
990	}
991	if (mdp == NULL) {
992	    mdp = malloc(sizeof(*mdp) + cplen + 1);
993	    if (mdp == NULL)
994		return;
995	    mdp->d_path = (char*)(mdp + 1);
996	    bcopy(cp, mdp->d_path, cplen);
997	    mdp->d_path[cplen] = 0;
998	    mdp->d_hints = NULL;
999	    mdp->d_flags = 0;
1000	    STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1001	}
1002	if (*ep == 0)
1003	    break;
1004    }
1005    /*
1006     * Delete unused directories if any
1007     */
1008    mdp = STAILQ_FIRST(&moduledir_list);
1009    while (mdp) {
1010	if ((mdp->d_flags & MDIR_REMOVED) == 0) {
1011	    mdp = STAILQ_NEXT(mdp, d_link);
1012	} else {
1013	    if (mdp->d_hints)
1014		free(mdp->d_hints);
1015	    mtmp = mdp;
1016	    mdp = STAILQ_NEXT(mdp, d_link);
1017	    STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
1018	    free(mtmp);
1019	}
1020    }
1021    return;
1022}
1023