kern_linker.c revision 118094
125537Sdfr/*-
259603Sdfr * Copyright (c) 1997-2000 Doug Rabson
325537Sdfr * All rights reserved.
425537Sdfr *
525537Sdfr * Redistribution and use in source and binary forms, with or without
625537Sdfr * modification, are permitted provided that the following conditions
725537Sdfr * are met:
825537Sdfr * 1. Redistributions of source code must retain the above copyright
925537Sdfr *    notice, this list of conditions and the following disclaimer.
1025537Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1125537Sdfr *    notice, this list of conditions and the following disclaimer in the
1225537Sdfr *    documentation and/or other materials provided with the distribution.
1325537Sdfr *
1425537Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1525537Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1625537Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1725537Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1825537Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1925537Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2025537Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2125537Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2225537Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2325537Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2425537Sdfr * SUCH DAMAGE.
2525537Sdfr */
2625537Sdfr
27116182Sobrien#include <sys/cdefs.h>
28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_linker.c 118094 2003-07-27 17:04:56Z phk $");
29116182Sobrien
3040159Speter#include "opt_ddb.h"
31107089Srwatson#include "opt_mac.h"
3240159Speter
3325537Sdfr#include <sys/param.h>
3425537Sdfr#include <sys/kernel.h>
3525537Sdfr#include <sys/systm.h>
3625537Sdfr#include <sys/malloc.h>
3725537Sdfr#include <sys/sysproto.h>
3825537Sdfr#include <sys/sysent.h>
3925537Sdfr#include <sys/proc.h>
4025537Sdfr#include <sys/lock.h>
4182749Sdillon#include <sys/mutex.h>
4292547Sarr#include <sys/sx.h>
43107089Srwatson#include <sys/mac.h>
4425537Sdfr#include <sys/module.h>
4525537Sdfr#include <sys/linker.h>
4640159Speter#include <sys/fcntl.h>
4740159Speter#include <sys/libkern.h>
4840159Speter#include <sys/namei.h>
4940159Speter#include <sys/vnode.h>
5040159Speter#include <sys/sysctl.h>
5125537Sdfr
5259603Sdfr#include "linker_if.h"
5359603Sdfr
5440961Speter#ifdef KLD_DEBUG
5540961Speterint kld_debug = 0;
5640961Speter#endif
5740961Speter
5891040Sarr/*
5991040Sarr * static char *linker_search_path(const char *name, struct mod_depend
6091040Sarr * *verinfo);
6191040Sarr */
6291040Sarrstatic const char 	*linker_basename(const char *path);
6359751Speter
6478161Speter/* Metadata from the static kernel */
6578161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata);
6678161Speter
6759751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker");
6859751Speter
6940906Speterlinker_file_t linker_kernel_file;
7031324Sbde
7198452Sarrstatic struct mtx kld_mtx;	/* kernel linker mutex */
7298452Sarr
7325537Sdfrstatic linker_class_list_t classes;
7450068Sgrogstatic linker_file_list_t linker_files;
7525537Sdfrstatic int next_file_id = 1;
7698452Sarrstatic int linker_no_more_classes = 0;
7725537Sdfr
7886553Sarr#define	LINKER_GET_NEXT_FILE_ID(a) do {					\
7991040Sarr	linker_file_t lftmp;						\
8086553Sarr									\
8186553Sarrretry:									\
8298452Sarr	mtx_lock(&kld_mtx);						\
8391040Sarr	TAILQ_FOREACH(lftmp, &linker_files, link) {			\
8491040Sarr		if (next_file_id == lftmp->id) {			\
8591040Sarr			next_file_id++;					\
8698452Sarr			mtx_unlock(&kld_mtx);				\
8791040Sarr			goto retry;					\
8891040Sarr		}							\
8991040Sarr	}								\
9091040Sarr	(a) = next_file_id;						\
9198452Sarr	mtx_unlock(&kld_mtx);	/* Hold for safe read of id variable */	\
9286553Sarr} while(0)
9386553Sarr
9486553Sarr
9559751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */
9660938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t;
9759751Speterstruct modlist {
9891040Sarr	TAILQ_ENTRY(modlist) link;	/* chain together all modules */
9991040Sarr	linker_file_t   container;
10091040Sarr	const char 	*name;
10191040Sarr	int             version;
10259751Speter};
10391040Sarrtypedef struct modlist *modlist_t;
10491040Sarrstatic modlisthead_t found_modules;
10559751Speter
10694321Sbrianstatic modlist_t	modlist_lookup2(const char *name,
10794321Sbrian			    struct mod_depend *verinfo);
10894321Sbrian
10959603Sdfrstatic char *
11059603Sdfrlinker_strdup(const char *str)
11159603Sdfr{
11291040Sarr	char *result;
11359603Sdfr
114111119Simp	if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
11591040Sarr		strcpy(result, str);
11691040Sarr	return (result);
11759603Sdfr}
11859603Sdfr
11925537Sdfrstatic void
12091040Sarrlinker_init(void *arg)
12125537Sdfr{
12291040Sarr
12398452Sarr	mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF);
12491040Sarr	TAILQ_INIT(&classes);
12591040Sarr	TAILQ_INIT(&linker_files);
12625537Sdfr}
12725537Sdfr
12891040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0)
12925537Sdfr
13098452Sarrstatic void
13198452Sarrlinker_stop_class_add(void *arg)
13298452Sarr{
13398452Sarr
13498452Sarr	linker_no_more_classes = 1;
13598452Sarr}
13698452Sarr
13798452SarrSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL)
13898452Sarr
13925537Sdfrint
14059603Sdfrlinker_add_class(linker_class_t lc)
14125537Sdfr{
14291040Sarr
14398452Sarr	/*
14498452Sarr	 * We disallow any class registration passt SI_ORDER_ANY
14598452Sarr	 * of SI_SUB_KLD.
14698452Sarr	 */
14798452Sarr	if (linker_no_more_classes == 1)
14898452Sarr		return (EPERM);
14991040Sarr	kobj_class_compile((kobj_class_t) lc);
15091040Sarr	TAILQ_INSERT_TAIL(&classes, lc, link);
15191040Sarr	return (0);
15225537Sdfr}
15325537Sdfr
15425537Sdfrstatic void
15525537Sdfrlinker_file_sysinit(linker_file_t lf)
15625537Sdfr{
15791040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
15825537Sdfr
15991040Sarr	KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
16091040Sarr	    lf->filename));
16125537Sdfr
16291040Sarr	if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0)
16391040Sarr		return;
16491040Sarr	/*
16591040Sarr	 * Perform a bubble sort of the system initialization objects by
16691040Sarr	 * their subsystem (primary key) and order (secondary key).
16791040Sarr	 *
16891040Sarr	 * Since some things care about execution order, this is the operation
16991040Sarr	 * which ensures continued function.
17091040Sarr	 */
17191040Sarr	for (sipp = start; sipp < stop; sipp++) {
17291040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
17391040Sarr			if ((*sipp)->subsystem < (*xipp)->subsystem ||
17491040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
17591040Sarr			    (*sipp)->order <= (*xipp)->order))
17691040Sarr				continue;	/* skip */
17791040Sarr			save = *sipp;
17891040Sarr			*sipp = *xipp;
17991040Sarr			*xipp = save;
18091040Sarr		}
18125537Sdfr	}
18225537Sdfr
18391040Sarr	/*
18491040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
18591040Sarr	 * Perform each task, and continue on to the next task.
18691040Sarr	 */
18791040Sarr	for (sipp = start; sipp < stop; sipp++) {
18891040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
18991040Sarr			continue;	/* skip dummy task(s) */
19025537Sdfr
19191040Sarr		/* Call function */
19291040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
19391040Sarr	}
19425537Sdfr}
19525537Sdfr
19641055Speterstatic void
19741055Speterlinker_file_sysuninit(linker_file_t lf)
19841055Speter{
19991040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
20041055Speter
20191040Sarr	KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
20291040Sarr	    lf->filename));
20341055Speter
20491068Sarr	if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop,
20591040Sarr	    NULL) != 0)
20691040Sarr		return;
20741055Speter
20891040Sarr	/*
20991040Sarr	 * Perform a reverse bubble sort of the system initialization objects
21091040Sarr	 * by their subsystem (primary key) and order (secondary key).
21191040Sarr	 *
21291040Sarr	 * Since some things care about execution order, this is the operation
21391040Sarr	 * which ensures continued function.
21491040Sarr	 */
21591040Sarr	for (sipp = start; sipp < stop; sipp++) {
21691040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
21791040Sarr			if ((*sipp)->subsystem > (*xipp)->subsystem ||
21891040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
21991040Sarr			    (*sipp)->order >= (*xipp)->order))
22091040Sarr				continue;	/* skip */
22191040Sarr			save = *sipp;
22291040Sarr			*sipp = *xipp;
22391040Sarr			*xipp = save;
22491040Sarr		}
22541055Speter	}
22641055Speter
22791040Sarr	/*
22891040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
22991040Sarr	 * Perform each task, and continue on to the next task.
23091040Sarr	 */
23191040Sarr	for (sipp = start; sipp < stop; sipp++) {
23291040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
23391040Sarr			continue;	/* skip dummy task(s) */
23441055Speter
23591040Sarr		/* Call function */
23691040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
23791040Sarr	}
23841055Speter}
23941055Speter
24044078Sdfrstatic void
24144078Sdfrlinker_file_register_sysctls(linker_file_t lf)
24244078Sdfr{
24391040Sarr	struct sysctl_oid **start, **stop, **oidp;
24444078Sdfr
24591040Sarr	KLD_DPF(FILE,
24691040Sarr	    ("linker_file_register_sysctls: registering SYSCTLs for %s\n",
24791040Sarr	    lf->filename));
24844078Sdfr
24991040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
25091040Sarr		return;
25144078Sdfr
25291040Sarr	for (oidp = start; oidp < stop; oidp++)
25391040Sarr		sysctl_register_oid(*oidp);
25444078Sdfr}
25544078Sdfr
25644078Sdfrstatic void
25744078Sdfrlinker_file_unregister_sysctls(linker_file_t lf)
25844078Sdfr{
25991040Sarr	struct sysctl_oid **start, **stop, **oidp;
26044078Sdfr
26191040Sarr	KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs"
26291040Sarr	    " for %s\n", lf->filename));
26344078Sdfr
26491040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
26591040Sarr		return;
26644078Sdfr
26791040Sarr	for (oidp = start; oidp < stop; oidp++)
26891040Sarr		sysctl_unregister_oid(*oidp);
26944078Sdfr}
27044078Sdfr
27159751Speterstatic int
27259751Speterlinker_file_register_modules(linker_file_t lf)
27359751Speter{
27491040Sarr	struct mod_metadata **start, **stop, **mdp;
27591040Sarr	const moduledata_t *moddata;
27691040Sarr	int error;
27759751Speter
27891040Sarr	KLD_DPF(FILE, ("linker_file_register_modules: registering modules"
27991040Sarr	    " in %s\n", lf->filename));
28059751Speter
28191068Sarr	if (linker_file_lookup_set(lf, "modmetadata_set", &start,
28291040Sarr	    &stop, 0) != 0) {
28391040Sarr		/*
28491040Sarr		 * This fallback should be unnecessary, but if we get booted
28591040Sarr		 * from boot2 instead of loader and we are missing our
28691040Sarr		 * metadata then we have to try the best we can.
28791040Sarr		 */
28891040Sarr		if (lf == linker_kernel_file) {
28991040Sarr			start = SET_BEGIN(modmetadata_set);
29091040Sarr			stop = SET_LIMIT(modmetadata_set);
29191040Sarr		} else
29291040Sarr			return (0);
29378161Speter	}
29491040Sarr	for (mdp = start; mdp < stop; mdp++) {
29591040Sarr		if ((*mdp)->md_type != MDT_MODULE)
29691040Sarr			continue;
29791040Sarr		moddata = (*mdp)->md_data;
29891040Sarr		KLD_DPF(FILE, ("Registering module %s in %s\n",
29991040Sarr		    moddata->name, lf->filename));
30091040Sarr		error = module_register(moddata, lf);
30191040Sarr		if (error)
30291068Sarr			printf("Module %s failed to register: %d\n",
30391040Sarr			    moddata->name, error);
30459751Speter	}
30591040Sarr	return (0);
30659751Speter}
30759751Speter
30859751Speterstatic void
30959751Speterlinker_init_kernel_modules(void)
31059751Speter{
31191040Sarr
31291040Sarr	linker_file_register_modules(linker_kernel_file);
31359751Speter}
31459751Speter
31591040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0)
31659751Speter
317101241Smuxstatic int
31891040Sarrlinker_load_file(const char *filename, linker_file_t *result)
31925537Sdfr{
32091040Sarr	linker_class_t lc;
32191040Sarr	linker_file_t lf;
32291040Sarr	int foundfile, error = 0;
32325537Sdfr
32491040Sarr	/* Refuse to load modules if securelevel raised */
32591040Sarr	if (securelevel > 0)
32691040Sarr		return (EPERM);
32762261Sarchie
32891040Sarr	lf = linker_find_file_by_name(filename);
32991040Sarr	if (lf) {
33091040Sarr		KLD_DPF(FILE, ("linker_load_file: file %s is already loaded,"
33191040Sarr		    " incrementing refs\n", filename));
33291040Sarr		*result = lf;
33391040Sarr		lf->refs++;
33491040Sarr		goto out;
33591040Sarr	}
33691040Sarr	lf = NULL;
33791040Sarr	foundfile = 0;
33898452Sarr
33998452Sarr	/*
34098452Sarr	 * We do not need to protect (lock) classes here because there is
34198452Sarr	 * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY)
34298452Sarr	 * and there is no class deregistration mechanism at this time.
34398452Sarr	 */
34491040Sarr	TAILQ_FOREACH(lc, &classes, link) {
34591040Sarr		KLD_DPF(FILE, ("linker_load_file: trying to load %s\n",
34691040Sarr		    filename));
34791040Sarr		error = LINKER_LOAD_FILE(lc, filename, &lf);
34891040Sarr		/*
34991040Sarr		 * If we got something other than ENOENT, then it exists but
35091040Sarr		 * we cannot load it for some other reason.
35191040Sarr		 */
35291040Sarr		if (error != ENOENT)
35391040Sarr			foundfile = 1;
35491040Sarr		if (lf) {
35591040Sarr			linker_file_register_modules(lf);
35691040Sarr			linker_file_register_sysctls(lf);
35791040Sarr			linker_file_sysinit(lf);
35891040Sarr			lf->flags |= LINKER_FILE_LINKED;
35991040Sarr			*result = lf;
36091040Sarr			error = 0;
36191040Sarr			goto out;
36291040Sarr		}
36391040Sarr	}
36442755Speter	/*
36591040Sarr	 * Less than ideal, but tells the user whether it failed to load or
36691040Sarr	 * the module was not found.
36742755Speter	 */
368105337Ssam	if (foundfile) {
369105337Ssam		/*
370105337Ssam		 * Format not recognized or otherwise unloadable.
371105337Ssam		 * When loading a module that is statically built into
372105337Ssam		 * the kernel EEXIST percolates back up as the return
373105337Ssam		 * value.  Preserve this so that apps like sysinstall
374105337Ssam		 * can recognize this special case and not post bogus
375105337Ssam		 * dialog boxes.
376105337Ssam		 */
377105337Ssam		if (error != EEXIST)
378105337Ssam			error = ENOEXEC;
379105337Ssam	} else
38091068Sarr		error = ENOENT;		/* Nothing found */
38125537Sdfrout:
38291040Sarr	return (error);
38325537Sdfr}
38425537Sdfr
38578413Sbrianint
38694321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo,
38794321Sbrian    linker_file_t *result)
38878413Sbrian{
38994321Sbrian	modlist_t mod;
39094321Sbrian
39194321Sbrian	if ((mod = modlist_lookup2(modname, verinfo)) != NULL) {
39294321Sbrian		*result = mod->container;
39394321Sbrian		(*result)->refs++;
39494321Sbrian		return (0);
39594321Sbrian	}
39694321Sbrian
39794321Sbrian	return (linker_load_module(NULL, modname, NULL, verinfo, result));
39878413Sbrian}
39978413Sbrian
40025537Sdfrlinker_file_t
40191040Sarrlinker_find_file_by_name(const char *filename)
40225537Sdfr{
40391040Sarr	linker_file_t lf = 0;
40491040Sarr	char *koname;
40525537Sdfr
406111119Simp	koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
40791040Sarr	if (koname == NULL)
40891040Sarr		goto out;
40991040Sarr	sprintf(koname, "%s.ko", filename);
41040861Speter
41198452Sarr	mtx_lock(&kld_mtx);
41291040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
41392032Sdwmalone		if (strcmp(lf->filename, koname) == 0)
41491040Sarr			break;
41592032Sdwmalone		if (strcmp(lf->filename, filename) == 0)
41691040Sarr			break;
41791040Sarr	}
41898452Sarr	mtx_unlock(&kld_mtx);
41940861Speterout:
42091040Sarr	if (koname)
42191040Sarr		free(koname, M_LINKER);
42291040Sarr	return (lf);
42325537Sdfr}
42425537Sdfr
42525537Sdfrlinker_file_t
42625537Sdfrlinker_find_file_by_id(int fileid)
42725537Sdfr{
42891040Sarr	linker_file_t lf = 0;
42998452Sarr
43098452Sarr	mtx_lock(&kld_mtx);
43191040Sarr	TAILQ_FOREACH(lf, &linker_files, link)
43291040Sarr		if (lf->id == fileid)
43391040Sarr			break;
43498452Sarr	mtx_unlock(&kld_mtx);
43591040Sarr	return (lf);
43625537Sdfr}
43725537Sdfr
43825537Sdfrlinker_file_t
43991040Sarrlinker_make_file(const char *pathname, linker_class_t lc)
44025537Sdfr{
44191040Sarr	linker_file_t lf;
44291040Sarr	const char *filename;
44325537Sdfr
44491040Sarr	lf = NULL;
44591040Sarr	filename = linker_basename(pathname);
44640159Speter
44791040Sarr	KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
448111119Simp	lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK);
44991040Sarr	if (lf == NULL)
45091040Sarr		goto out;
45191040Sarr	lf->refs = 1;
45291040Sarr	lf->userrefs = 0;
45391040Sarr	lf->flags = 0;
45491040Sarr	lf->filename = linker_strdup(filename);
45591040Sarr	LINKER_GET_NEXT_FILE_ID(lf->id);
45691040Sarr	lf->ndeps = 0;
45791040Sarr	lf->deps = NULL;
45891040Sarr	STAILQ_INIT(&lf->common);
45991040Sarr	TAILQ_INIT(&lf->modules);
46098452Sarr	mtx_lock(&kld_mtx);
46191040Sarr	TAILQ_INSERT_TAIL(&linker_files, lf, link);
46298452Sarr	mtx_unlock(&kld_mtx);
46325537Sdfrout:
46491040Sarr	return (lf);
46525537Sdfr}
46625537Sdfr
46725537Sdfrint
46825537Sdfrlinker_file_unload(linker_file_t file)
46925537Sdfr{
47091040Sarr	module_t mod, next;
47191040Sarr	modlist_t ml, nextml;
47291040Sarr	struct common_symbol *cp;
47391040Sarr	int error, i;
47425537Sdfr
47591040Sarr	error = 0;
47662261Sarchie
47791040Sarr	/* Refuse to unload modules if securelevel raised. */
47891040Sarr	if (securelevel > 0)
47991040Sarr		return (EPERM);
480107089Srwatson#ifdef MAC
481107089Srwatson	error = mac_check_kld_unload(curthread->td_ucred);
482107089Srwatson	if (error)
483107089Srwatson		return (error);
484107089Srwatson#endif
48525537Sdfr
48691040Sarr	KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
48791040Sarr	if (file->refs == 1) {
48891040Sarr		KLD_DPF(FILE, ("linker_file_unload: file is unloading,"
48991040Sarr		    " informing modules\n"));
49091040Sarr
49191040Sarr		/*
49291040Sarr		 * Inform any modules associated with this file.
49391040Sarr		 */
49492547Sarr		MOD_XLOCK;
49591040Sarr		for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
49691040Sarr			next = module_getfnext(mod);
49792547Sarr			MOD_XUNLOCK;
49891040Sarr
49991040Sarr			/*
50091040Sarr			 * Give the module a chance to veto the unload.
50191040Sarr			 */
50291040Sarr			if ((error = module_unload(mod)) != 0) {
503109605Sjake				KLD_DPF(FILE, ("linker_file_unload: module %p"
50491040Sarr				    " vetoes unload\n", mod));
50591040Sarr				goto out;
50692547Sarr			} else
50792547Sarr				MOD_XLOCK;
50891040Sarr			module_release(mod);
50991040Sarr		}
51092547Sarr		MOD_XUNLOCK;
51191040Sarr	}
51291040Sarr	file->refs--;
51391040Sarr	if (file->refs > 0) {
51425537Sdfr		goto out;
51591040Sarr	}
51691040Sarr	for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) {
51791040Sarr		nextml = TAILQ_NEXT(ml, link);
51891040Sarr		if (ml->container == file)
51991040Sarr			TAILQ_REMOVE(&found_modules, ml, link);
52091040Sarr	}
52125537Sdfr
52291040Sarr	/*
52391040Sarr	 * Don't try to run SYSUNINITs if we are unloaded due to a
52491040Sarr	 * link error.
52591040Sarr	 */
52691040Sarr	if (file->flags & LINKER_FILE_LINKED) {
52791040Sarr		linker_file_sysuninit(file);
52891040Sarr		linker_file_unregister_sysctls(file);
52925537Sdfr	}
53098452Sarr	mtx_lock(&kld_mtx);
53191040Sarr	TAILQ_REMOVE(&linker_files, file, link);
53298452Sarr	mtx_unlock(&kld_mtx);
53325537Sdfr
53491040Sarr	if (file->deps) {
53591040Sarr		for (i = 0; i < file->ndeps; i++)
53691040Sarr			linker_file_unload(file->deps[i]);
53791040Sarr		free(file->deps, M_LINKER);
53891040Sarr		file->deps = NULL;
53959751Speter	}
54091040Sarr	for (cp = STAILQ_FIRST(&file->common); cp;
54191068Sarr	    cp = STAILQ_FIRST(&file->common)) {
54291040Sarr		STAILQ_REMOVE(&file->common, cp, common_symbol, link);
54391040Sarr		free(cp, M_LINKER);
54491040Sarr	}
54559751Speter
54691040Sarr	LINKER_UNLOAD(file);
54791040Sarr	if (file->filename) {
54891040Sarr		free(file->filename, M_LINKER);
54991040Sarr		file->filename = NULL;
55091040Sarr	}
55191040Sarr	kobj_delete((kobj_t) file, M_LINKER);
55225537Sdfrout:
55391040Sarr	return (error);
55425537Sdfr}
55525537Sdfr
55625537Sdfrint
55786469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep)
55825537Sdfr{
55991040Sarr	linker_file_t *newdeps;
56025537Sdfr
56191040Sarr	newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *),
562111119Simp	    M_LINKER, M_WAITOK | M_ZERO);
56391040Sarr	if (newdeps == NULL)
56491040Sarr		return (ENOMEM);
56525537Sdfr
56691040Sarr	if (file->deps) {
56791040Sarr		bcopy(file->deps, newdeps,
56891040Sarr		    file->ndeps * sizeof(linker_file_t *));
56991040Sarr		free(file->deps, M_LINKER);
57091040Sarr	}
57191040Sarr	file->deps = newdeps;
57291040Sarr	file->deps[file->ndeps] = dep;
57391040Sarr	file->ndeps++;
57491040Sarr	return (0);
57525537Sdfr}
57625537Sdfr
57778161Speter/*
57891040Sarr * Locate a linker set and its contents.  This is a helper function to avoid
57991040Sarr * linker_if.h exposure elsewhere.  Note: firstp and lastp are really void ***
58078161Speter */
58178161Speterint
58278161Speterlinker_file_lookup_set(linker_file_t file, const char *name,
58391040Sarr    void *firstp, void *lastp, int *countp)
58478161Speter{
58578161Speter
58691040Sarr	return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp));
58778161Speter}
58878161Speter
58925537Sdfrcaddr_t
59091040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
59125537Sdfr{
59291040Sarr	c_linker_sym_t sym;
59391040Sarr	linker_symval_t symval;
59491040Sarr	caddr_t address;
59591040Sarr	size_t common_size = 0;
59692032Sdwmalone	int i;
59725537Sdfr
598109605Sjake	KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n",
59991040Sarr	    file, name, deps));
60025537Sdfr
60191040Sarr	if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) {
60291040Sarr		LINKER_SYMBOL_VALUES(file, sym, &symval);
60391040Sarr		if (symval.value == 0)
60491040Sarr			/*
60591040Sarr			 * For commons, first look them up in the
60691040Sarr			 * dependencies and only allocate space if not found
60791040Sarr			 * there.
60891040Sarr			 */
60991040Sarr			common_size = symval.size;
61091040Sarr		else {
61191040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol"
612109605Sjake			    ".value=%p\n", symval.value));
61391040Sarr			return (symval.value);
61491040Sarr		}
61540159Speter	}
61691040Sarr	if (deps) {
61791040Sarr		for (i = 0; i < file->ndeps; i++) {
61891040Sarr			address = linker_file_lookup_symbol(file->deps[i],
61991040Sarr			    name, 0);
62091040Sarr			if (address) {
62191040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
622109605Sjake				    " deps value=%p\n", address));
62391040Sarr				return (address);
62491040Sarr			}
62591040Sarr		}
62625537Sdfr	}
62791040Sarr	if (common_size > 0) {
62891040Sarr		/*
62991040Sarr		 * This is a common symbol which was not found in the
63091040Sarr		 * dependencies.  We maintain a simple common symbol table in
63191040Sarr		 * the file object.
63291040Sarr		 */
63391040Sarr		struct common_symbol *cp;
63442849Speter
63591040Sarr		STAILQ_FOREACH(cp, &file->common, link) {
63692032Sdwmalone			if (strcmp(cp->name, name) == 0) {
63791040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
638109605Sjake				    " old common value=%p\n", cp->address));
63991040Sarr				return (cp->address);
64091040Sarr			}
64191040Sarr		}
64291040Sarr		/*
64391040Sarr		 * Round the symbol size up to align.
64491040Sarr		 */
64591040Sarr		common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
64691040Sarr		cp = malloc(sizeof(struct common_symbol)
64791040Sarr		    + common_size + strlen(name) + 1, M_LINKER,
648111119Simp		    M_WAITOK | M_ZERO);
64991040Sarr		if (cp == NULL) {
65091040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
65191040Sarr			return (0);
65291040Sarr		}
65391040Sarr		cp->address = (caddr_t)(cp + 1);
65491040Sarr		cp->name = cp->address + common_size;
65591040Sarr		strcpy(cp->name, name);
65691040Sarr		bzero(cp->address, common_size);
65791040Sarr		STAILQ_INSERT_TAIL(&file->common, cp, link);
65825537Sdfr
65991040Sarr		KLD_DPF(SYM, ("linker_file_lookup_symbol: new common"
660109605Sjake		    " value=%p\n", cp->address));
66191040Sarr		return (cp->address);
66240159Speter	}
66391040Sarr	KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
66491040Sarr	return (0);
66525537Sdfr}
66625537Sdfr
66740159Speter#ifdef DDB
66825537Sdfr/*
66991040Sarr * DDB Helpers.  DDB has to look across multiple files with their own symbol
67091040Sarr * tables and string tables.
67191040Sarr *
67291040Sarr * Note that we do not obey list locking protocols here.  We really don't need
67391040Sarr * DDB to hang because somebody's got the lock held.  We'll take the chance
67491040Sarr * that the files list is inconsistant instead.
67540159Speter */
67640159Speter
67740159Speterint
67843309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
67940159Speter{
68091040Sarr	linker_file_t lf;
68140159Speter
68291040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
68391040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0)
68491040Sarr			return (0);
68591040Sarr	}
68691040Sarr	return (ENOENT);
68740159Speter}
68840159Speter
68940159Speterint
69043309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
69140159Speter{
69291040Sarr	linker_file_t lf;
69391040Sarr	c_linker_sym_t best, es;
69491040Sarr	u_long diff, bestdiff, off;
69540159Speter
69691040Sarr	best = 0;
69791040Sarr	off = (uintptr_t)value;
69891040Sarr	bestdiff = off;
69991040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
70091040Sarr		if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0)
70191040Sarr			continue;
70291040Sarr		if (es != 0 && diff < bestdiff) {
70391040Sarr			best = es;
70491040Sarr			bestdiff = diff;
70591040Sarr		}
70691040Sarr		if (bestdiff == 0)
70791040Sarr			break;
70840159Speter	}
70991040Sarr	if (best) {
71091040Sarr		*sym = best;
71191040Sarr		*diffp = bestdiff;
71291040Sarr		return (0);
71391040Sarr	} else {
71491040Sarr		*sym = 0;
71591040Sarr		*diffp = off;
71691040Sarr		return (ENOENT);
71791040Sarr	}
71840159Speter}
71940159Speter
72040159Speterint
72143309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
72240159Speter{
72391040Sarr	linker_file_t lf;
72440159Speter
72591040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
72691040Sarr		if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0)
72791040Sarr			return (0);
72891040Sarr	}
72991040Sarr	return (ENOENT);
73040159Speter}
73140159Speter#endif
73240159Speter
73340159Speter/*
73425537Sdfr * Syscalls.
73525537Sdfr */
73682749Sdillon/*
73782749Sdillon * MPSAFE
73882749Sdillon */
73925537Sdfrint
74091040Sarrkldload(struct thread *td, struct kldload_args *uap)
74125537Sdfr{
74291040Sarr	char *kldname, *modname;
74391040Sarr	char *pathname = NULL;
74491040Sarr	linker_file_t lf;
74591040Sarr	int error = 0;
74625537Sdfr
74791040Sarr	td->td_retval[0] = -1;
74825537Sdfr
74991040Sarr	mtx_lock(&Giant);
75082749Sdillon
75193159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
75293159Sarr		goto out;
75393159Sarr
75493593Sjhb	if ((error = suser(td)) != 0)
75591040Sarr		goto out;
75625537Sdfr
757111119Simp	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
758107855Salfred	if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0)
75991040Sarr		goto out;
76025537Sdfr
76191040Sarr	/*
76291040Sarr	 * If path do not contain qualified name or any dot in it
76391040Sarr	 * (kldname.ko, or kldname.ver.ko) treat it as interface
76491040Sarr	 * name.
76591040Sarr	 */
76691040Sarr	if (index(pathname, '/') || index(pathname, '.')) {
76791040Sarr		kldname = pathname;
76891040Sarr		modname = NULL;
76991040Sarr	} else {
77091040Sarr		kldname = NULL;
77191040Sarr		modname = pathname;
77291040Sarr	}
77391040Sarr	error = linker_load_module(kldname, modname, NULL, NULL, &lf);
77491040Sarr	if (error)
77591040Sarr		goto out;
77642316Smsmith
77791040Sarr	lf->userrefs++;
77891040Sarr	td->td_retval[0] = lf->id;
77925537Sdfrout:
78091040Sarr	if (pathname)
78191040Sarr		free(pathname, M_TEMP);
78291040Sarr	mtx_unlock(&Giant);
78391040Sarr	return (error);
78425537Sdfr}
78525537Sdfr
78682749Sdillon/*
78782749Sdillon * MPSAFE
78882749Sdillon */
78925537Sdfrint
79091040Sarrkldunload(struct thread *td, struct kldunload_args *uap)
79125537Sdfr{
79291040Sarr	linker_file_t lf;
79391040Sarr	int error = 0;
79425537Sdfr
79591040Sarr	mtx_lock(&Giant);
79682749Sdillon
79793159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
79893159Sarr		goto out;
79993159Sarr
80093593Sjhb	if ((error = suser(td)) != 0)
80191040Sarr		goto out;
80225537Sdfr
803107849Salfred	lf = linker_find_file_by_id(uap->fileid);
80491040Sarr	if (lf) {
80591040Sarr		KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
80691040Sarr		if (lf->userrefs == 0) {
80791040Sarr			printf("kldunload: attempt to unload file that was"
80891040Sarr			    " loaded by the kernel\n");
80991040Sarr			error = EBUSY;
81091040Sarr			goto out;
81191040Sarr		}
81291068Sarr		lf->userrefs--;
81391040Sarr		error = linker_file_unload(lf);
81491040Sarr		if (error)
81591040Sarr			lf->userrefs++;
81691040Sarr	} else
81791040Sarr		error = ENOENT;
81825537Sdfrout:
81991068Sarr	mtx_unlock(&Giant);
82091068Sarr	return (error);
82125537Sdfr}
82225537Sdfr
82382749Sdillon/*
82482749Sdillon * MPSAFE
82582749Sdillon */
82625537Sdfrint
82791040Sarrkldfind(struct thread *td, struct kldfind_args *uap)
82825537Sdfr{
82991040Sarr	char *pathname;
83091040Sarr	const char *filename;
83191040Sarr	linker_file_t lf;
83291040Sarr	int error = 0;
83325537Sdfr
834107089Srwatson#ifdef MAC
835107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
836107089Srwatson	if (error)
837107089Srwatson		return (error);
838107089Srwatson#endif
839107089Srwatson
84091040Sarr	mtx_lock(&Giant);
84191040Sarr	td->td_retval[0] = -1;
84282749Sdillon
843111119Simp	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
844107855Salfred	if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0)
84591040Sarr		goto out;
84625537Sdfr
84791040Sarr	filename = linker_basename(pathname);
84891040Sarr	lf = linker_find_file_by_name(filename);
84991040Sarr	if (lf)
85091040Sarr		td->td_retval[0] = lf->id;
85191040Sarr	else
85291040Sarr		error = ENOENT;
85325537Sdfrout:
85491040Sarr	if (pathname)
85591040Sarr		free(pathname, M_TEMP);
85691040Sarr	mtx_unlock(&Giant);
85791040Sarr	return (error);
85825537Sdfr}
85925537Sdfr
86082749Sdillon/*
86182749Sdillon * MPSAFE
86282749Sdillon */
86325537Sdfrint
86491040Sarrkldnext(struct thread *td, struct kldnext_args *uap)
86525537Sdfr{
86691040Sarr	linker_file_t lf;
86791040Sarr	int error = 0;
86825537Sdfr
869107089Srwatson#ifdef MAC
870107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
871107089Srwatson	if (error)
872107089Srwatson		return (error);
873107089Srwatson#endif
874107089Srwatson
87591040Sarr	mtx_lock(&Giant);
87682749Sdillon
877107849Salfred	if (uap->fileid == 0) {
87898452Sarr		mtx_lock(&kld_mtx);
87991040Sarr		if (TAILQ_FIRST(&linker_files))
88091040Sarr			td->td_retval[0] = TAILQ_FIRST(&linker_files)->id;
88191040Sarr		else
88291040Sarr			td->td_retval[0] = 0;
88398452Sarr		mtx_unlock(&kld_mtx);
88491040Sarr		goto out;
88591040Sarr	}
886107849Salfred	lf = linker_find_file_by_id(uap->fileid);
88791040Sarr	if (lf) {
88891040Sarr		if (TAILQ_NEXT(lf, link))
88991040Sarr			td->td_retval[0] = TAILQ_NEXT(lf, link)->id;
89091040Sarr		else
89191040Sarr			td->td_retval[0] = 0;
89291040Sarr	} else
89391040Sarr		error = ENOENT;
89482749Sdillonout:
89591040Sarr	mtx_unlock(&Giant);
89691040Sarr	return (error);
89725537Sdfr}
89825537Sdfr
89982749Sdillon/*
90082749Sdillon * MPSAFE
90182749Sdillon */
90225537Sdfrint
90391040Sarrkldstat(struct thread *td, struct kldstat_args *uap)
90425537Sdfr{
90591040Sarr	linker_file_t lf;
90691040Sarr	int error = 0;
90791040Sarr	int namelen, version;
90891040Sarr	struct kld_file_stat *stat;
90925537Sdfr
910107089Srwatson#ifdef MAC
911107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
912107089Srwatson	if (error)
913107089Srwatson		return (error);
914107089Srwatson#endif
915107089Srwatson
91691040Sarr	mtx_lock(&Giant);
91782749Sdillon
918107849Salfred	lf = linker_find_file_by_id(uap->fileid);
91991040Sarr	if (lf == NULL) {
92091040Sarr		error = ENOENT;
92191040Sarr		goto out;
92291040Sarr	}
923107849Salfred	stat = uap->stat;
92425537Sdfr
92591040Sarr	/*
92691040Sarr	 * Check the version of the user's structure.
92791040Sarr	 */
92891040Sarr	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
92991040Sarr		goto out;
93091040Sarr	if (version != sizeof(struct kld_file_stat)) {
93191040Sarr		error = EINVAL;
93291040Sarr		goto out;
93391040Sarr	}
93491040Sarr	namelen = strlen(lf->filename) + 1;
93591040Sarr	if (namelen > MAXPATHLEN)
93691040Sarr		namelen = MAXPATHLEN;
93791040Sarr	if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
93891040Sarr		goto out;
93991040Sarr	if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
94091040Sarr		goto out;
94191040Sarr	if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
94291040Sarr		goto out;
94391040Sarr	if ((error = copyout(&lf->address, &stat->address,
94491040Sarr	    sizeof(caddr_t))) != 0)
94591040Sarr		goto out;
94691040Sarr	if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
94791040Sarr		goto out;
94825537Sdfr
94991040Sarr	td->td_retval[0] = 0;
95025537Sdfrout:
95191040Sarr	mtx_unlock(&Giant);
95291040Sarr	return (error);
95325537Sdfr}
95425537Sdfr
95582749Sdillon/*
95682749Sdillon * MPSAFE
95782749Sdillon */
95825537Sdfrint
95991040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap)
96025537Sdfr{
96191040Sarr	linker_file_t lf;
96291040Sarr	module_t mp;
96391040Sarr	int error = 0;
96425537Sdfr
965107089Srwatson#ifdef MAC
966107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
967107089Srwatson	if (error)
968107089Srwatson		return (error);
969107089Srwatson#endif
970107089Srwatson
97191040Sarr	mtx_lock(&Giant);
972107849Salfred	lf = linker_find_file_by_id(uap->fileid);
97391040Sarr	if (lf) {
97492547Sarr		MOD_SLOCK;
97591040Sarr		mp = TAILQ_FIRST(&lf->modules);
97691040Sarr		if (mp != NULL)
97791040Sarr			td->td_retval[0] = module_getid(mp);
97891040Sarr		else
97991040Sarr			td->td_retval[0] = 0;
98092547Sarr		MOD_SUNLOCK;
98191040Sarr	} else
98291040Sarr		error = ENOENT;
98391040Sarr	mtx_unlock(&Giant);
98491040Sarr	return (error);
98525537Sdfr}
98640159Speter
98782749Sdillon/*
98882749Sdillon * MPSAFE
98982749Sdillon */
99041090Speterint
99183366Sjuliankldsym(struct thread *td, struct kldsym_args *uap)
99241090Speter{
99391040Sarr	char *symstr = NULL;
99491040Sarr	c_linker_sym_t sym;
99591040Sarr	linker_symval_t symval;
99691040Sarr	linker_file_t lf;
99791040Sarr	struct kld_sym_lookup lookup;
99891040Sarr	int error = 0;
99941090Speter
1000107089Srwatson#ifdef MAC
1001107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
1002107089Srwatson	if (error)
1003107089Srwatson		return (error);
1004107089Srwatson#endif
1005107089Srwatson
100691040Sarr	mtx_lock(&Giant);
100782749Sdillon
1008107849Salfred	if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0)
100991040Sarr		goto out;
101091068Sarr	if (lookup.version != sizeof(lookup) ||
1011107849Salfred	    uap->cmd != KLDSYM_LOOKUP) {
101291040Sarr		error = EINVAL;
101391040Sarr		goto out;
101491040Sarr	}
1015111119Simp	symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
101691040Sarr	if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
101791040Sarr		goto out;
1018107849Salfred	if (uap->fileid != 0) {
1019107849Salfred		lf = linker_find_file_by_id(uap->fileid);
102091040Sarr		if (lf == NULL) {
102191040Sarr			error = ENOENT;
102291040Sarr			goto out;
102391040Sarr		}
102491040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
102591040Sarr		    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
102691040Sarr			lookup.symvalue = (uintptr_t) symval.value;
102791040Sarr			lookup.symsize = symval.size;
1028107855Salfred			error = copyout(&lookup, uap->data, sizeof(lookup));
102991040Sarr		} else
103091040Sarr			error = ENOENT;
103191040Sarr	} else {
103298452Sarr		mtx_lock(&kld_mtx);
103391040Sarr		TAILQ_FOREACH(lf, &linker_files, link) {
103491040Sarr			if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
103591040Sarr			    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
103691040Sarr				lookup.symvalue = (uintptr_t)symval.value;
103791040Sarr				lookup.symsize = symval.size;
1038107849Salfred				error = copyout(&lookup, uap->data,
103991040Sarr				    sizeof(lookup));
104091068Sarr				break;
104191040Sarr			}
104291040Sarr		}
104398452Sarr		mtx_unlock(&kld_mtx);
104491040Sarr		if (lf == NULL)
104591040Sarr			error = ENOENT;
104641090Speter	}
104741090Speterout:
104891040Sarr	if (symstr)
104991040Sarr		free(symstr, M_TEMP);
105091040Sarr	mtx_unlock(&Giant);
105191040Sarr	return (error);
105241090Speter}
105341090Speter
105440159Speter/*
105540159Speter * Preloaded module support
105640159Speter */
105740159Speter
105859751Speterstatic modlist_t
105974642Sbpmodlist_lookup(const char *name, int ver)
106059751Speter{
106191040Sarr	modlist_t mod;
106259751Speter
106391040Sarr	TAILQ_FOREACH(mod, &found_modules, link) {
106492032Sdwmalone		if (strcmp(mod->name, name) == 0 &&
106592032Sdwmalone		    (ver == 0 || mod->version == ver))
106691040Sarr			return (mod);
106791040Sarr	}
106891040Sarr	return (NULL);
106959751Speter}
107059751Speter
107174642Sbpstatic modlist_t
107283321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo)
107383321Speter{
107491040Sarr	modlist_t mod, bestmod;
107592032Sdwmalone	int ver;
107683321Speter
107791040Sarr	if (verinfo == NULL)
107891040Sarr		return (modlist_lookup(name, 0));
107991040Sarr	bestmod = NULL;
108091040Sarr	for (mod = TAILQ_FIRST(&found_modules); mod;
108191040Sarr	    mod = TAILQ_NEXT(mod, link)) {
108292032Sdwmalone		if (strcmp(mod->name, name) != 0)
108391040Sarr			continue;
108491040Sarr		ver = mod->version;
108591040Sarr		if (ver == verinfo->md_ver_preferred)
108691040Sarr			return (mod);
108791040Sarr		if (ver >= verinfo->md_ver_minimum &&
108891068Sarr		    ver <= verinfo->md_ver_maximum &&
108991068Sarr		    ver > bestmod->version)
109091040Sarr			bestmod = mod;
109191040Sarr	}
109291040Sarr	return (bestmod);
109383321Speter}
109483321Speter
109583321Speterstatic modlist_t
109678501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container)
109774642Sbp{
109891040Sarr	modlist_t mod;
109974642Sbp
110092705Sarr	mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO);
110191040Sarr	if (mod == NULL)
110291040Sarr		panic("no memory for module list");
110391040Sarr	mod->container = container;
110491040Sarr	mod->name = modname;
110591040Sarr	mod->version = version;
110691040Sarr	TAILQ_INSERT_TAIL(&found_modules, mod, link);
110791040Sarr	return (mod);
110874642Sbp}
110974642Sbp
111040159Speterstatic void
111178161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start,
111291040Sarr    struct mod_metadata **stop, int preload)
111374642Sbp{
111491040Sarr	struct mod_metadata *mp, **mdp;
111591040Sarr	const char *modname;
111691040Sarr	int ver;
111774642Sbp
111891040Sarr	for (mdp = start; mdp < stop; mdp++) {
1119109605Sjake		mp = *mdp;
112091040Sarr		if (mp->md_type != MDT_VERSION)
112191040Sarr			continue;
1122109605Sjake		modname = mp->md_cval;
1123109605Sjake		ver = ((struct mod_version *)mp->md_data)->mv_version;
112491040Sarr		if (modlist_lookup(modname, ver) != NULL) {
112591040Sarr			printf("module %s already present!\n", modname);
112691040Sarr			/* XXX what can we do? this is a build error. :-( */
112791040Sarr			continue;
112891040Sarr		}
112991040Sarr		modlist_newmodule(modname, ver, lf);
113074642Sbp	}
113174642Sbp}
113274642Sbp
113374642Sbpstatic void
113491040Sarrlinker_preload(void *arg)
113540159Speter{
113691040Sarr	caddr_t modptr;
113791040Sarr	const char *modname, *nmodname;
113891040Sarr	char *modtype;
113991040Sarr	linker_file_t lf;
114091040Sarr	linker_class_t lc;
114192032Sdwmalone	int error;
114291040Sarr	linker_file_list_t loaded_files;
114391040Sarr	linker_file_list_t depended_files;
114491040Sarr	struct mod_metadata *mp, *nmp;
114591040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
114691040Sarr	struct mod_depend *verinfo;
114791040Sarr	int nver;
114891040Sarr	int resolves;
114991040Sarr	modlist_t mod;
115091040Sarr	struct sysinit **si_start, **si_stop;
115140159Speter
115291040Sarr	TAILQ_INIT(&loaded_files);
115391040Sarr	TAILQ_INIT(&depended_files);
115491040Sarr	TAILQ_INIT(&found_modules);
115591040Sarr	error = 0;
115659751Speter
115791040Sarr	modptr = NULL;
115891040Sarr	while ((modptr = preload_search_next_name(modptr)) != NULL) {
115991040Sarr		modname = (char *)preload_search_info(modptr, MODINFO_NAME);
116091040Sarr		modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
116191040Sarr		if (modname == NULL) {
116291040Sarr			printf("Preloaded module at %p does not have a"
116391040Sarr			    " name!\n", modptr);
116491040Sarr			continue;
116591040Sarr		}
116691040Sarr		if (modtype == NULL) {
116791040Sarr			printf("Preloaded module at %p does not have a type!\n",
116891040Sarr			    modptr);
116991040Sarr			continue;
117091040Sarr		}
117191040Sarr		printf("Preloaded %s \"%s\" at %p.\n", modtype, modname,
117291040Sarr		    modptr);
117340159Speter		lf = NULL;
117491040Sarr		TAILQ_FOREACH(lc, &classes, link) {
117591040Sarr			error = LINKER_LINK_PRELOAD(lc, modname, &lf);
117691040Sarr			if (error) {
117791040Sarr				lf = NULL;
117891040Sarr				break;
117991040Sarr			}
118091040Sarr		}
118191040Sarr		if (lf)
118291040Sarr			TAILQ_INSERT_TAIL(&loaded_files, lf, loaded);
118340159Speter	}
118440159Speter
118591040Sarr	/*
118691040Sarr	 * First get a list of stuff in the kernel.
118791040Sarr	 */
118891040Sarr	if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start,
118991040Sarr	    &stop, NULL) == 0)
119091040Sarr		linker_addmodules(linker_kernel_file, start, stop, 1);
119159751Speter
119259751Speter	/*
119391040Sarr	 * this is a once-off kinky bubble sort resolve relocation dependency
119491040Sarr	 * requirements
119559751Speter	 */
119691040Sarrrestart:
119791040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
119891040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
119991040Sarr		    &stop, NULL);
120091040Sarr		/*
120191040Sarr		 * First, look to see if we would successfully link with this
120291040Sarr		 * stuff.
120391040Sarr		 */
120491040Sarr		resolves = 1;	/* unless we know otherwise */
120591040Sarr		if (!error) {
120691040Sarr			for (mdp = start; mdp < stop; mdp++) {
1207109605Sjake				mp = *mdp;
120891040Sarr				if (mp->md_type != MDT_DEPEND)
120991040Sarr					continue;
1210109605Sjake				modname = mp->md_cval;
1211109605Sjake				verinfo = mp->md_data;
121291040Sarr				for (nmdp = start; nmdp < stop; nmdp++) {
1213109605Sjake					nmp = *nmdp;
121491040Sarr					if (nmp->md_type != MDT_VERSION)
121591040Sarr						continue;
1216109605Sjake					nmodname = nmp->md_cval;
121792032Sdwmalone					if (strcmp(modname, nmodname) == 0)
121891040Sarr						break;
121991040Sarr				}
122091040Sarr				if (nmdp < stop)   /* it's a self reference */
122191040Sarr					continue;
122291040Sarr
122391040Sarr				/*
122491040Sarr				 * ok, the module isn't here yet, we
122591040Sarr				 * are not finished
122691040Sarr				 */
122791068Sarr				if (modlist_lookup2(modname, verinfo) == NULL)
122891040Sarr					resolves = 0;
122991040Sarr			}
123064143Speter		}
123191040Sarr		/*
123291040Sarr		 * OK, if we found our modules, we can link.  So, "provide"
123391040Sarr		 * the modules inside and add it to the end of the link order
123491040Sarr		 * list.
123591040Sarr		 */
123691040Sarr		if (resolves) {
123791040Sarr			if (!error) {
123891040Sarr				for (mdp = start; mdp < stop; mdp++) {
1239109605Sjake					mp = *mdp;
124091040Sarr					if (mp->md_type != MDT_VERSION)
124191040Sarr						continue;
1242109605Sjake					modname = mp->md_cval;
1243109605Sjake					nver = ((struct mod_version *)
1244109605Sjake					    mp->md_data)->mv_version;
124591040Sarr					if (modlist_lookup(modname,
124691040Sarr					    nver) != NULL) {
124791040Sarr						printf("module %s already"
124891040Sarr						    " present!\n", modname);
124991040Sarr						linker_file_unload(lf);
125091040Sarr						TAILQ_REMOVE(&loaded_files,
125191040Sarr						    lf, loaded);
125291040Sarr						/* we changed tailq next ptr */
125391068Sarr						goto restart;
125491040Sarr					}
125591040Sarr					modlist_newmodule(modname, nver, lf);
125691040Sarr				}
125791040Sarr			}
125891040Sarr			TAILQ_REMOVE(&loaded_files, lf, loaded);
125991040Sarr			TAILQ_INSERT_TAIL(&depended_files, lf, loaded);
126091040Sarr			/*
126191040Sarr			 * Since we provided modules, we need to restart the
126291040Sarr			 * sort so that the previous files that depend on us
126391040Sarr			 * have a chance. Also, we've busted the tailq next
126491040Sarr			 * pointer with the REMOVE.
126591040Sarr			 */
126691040Sarr			goto restart;
126759751Speter		}
126859751Speter	}
126991040Sarr
127059751Speter	/*
127191040Sarr	 * At this point, we check to see what could not be resolved..
127259751Speter	 */
127391040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
127491040Sarr		printf("KLD file %s is missing dependencies\n", lf->filename);
127591040Sarr		linker_file_unload(lf);
127691040Sarr		TAILQ_REMOVE(&loaded_files, lf, loaded);
127740159Speter	}
127859751Speter
127978161Speter	/*
128091040Sarr	 * We made it. Finish off the linking in the order we determined.
128178161Speter	 */
128291040Sarr	TAILQ_FOREACH(lf, &depended_files, loaded) {
128391040Sarr		if (linker_kernel_file) {
128491040Sarr			linker_kernel_file->refs++;
128591040Sarr			error = linker_file_add_dependency(lf,
128691040Sarr			    linker_kernel_file);
128791040Sarr			if (error)
128891040Sarr				panic("cannot add dependency");
128991040Sarr		}
129091040Sarr		lf->userrefs++;	/* so we can (try to) kldunload it */
129191040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
129291040Sarr		    &stop, NULL);
129391040Sarr		if (!error) {
129491040Sarr			for (mdp = start; mdp < stop; mdp++) {
1295109605Sjake				mp = *mdp;
129691040Sarr				if (mp->md_type != MDT_DEPEND)
129791040Sarr					continue;
1298109605Sjake				modname = mp->md_cval;
1299109605Sjake				verinfo = mp->md_data;
130091040Sarr				mod = modlist_lookup2(modname, verinfo);
130191040Sarr				mod->container->refs++;
130291040Sarr				error = linker_file_add_dependency(lf,
130391040Sarr				    mod->container);
130491040Sarr				if (error)
130591040Sarr					panic("cannot add dependency");
130691040Sarr			}
130791040Sarr		}
130891040Sarr		/*
130991040Sarr		 * Now do relocation etc using the symbol search paths
131091040Sarr		 * established by the dependencies
131191040Sarr		 */
131291040Sarr		error = LINKER_LINK_PRELOAD_FINISH(lf);
131391040Sarr		if (error) {
131491040Sarr			printf("KLD file %s - could not finalize loading\n",
131591040Sarr			    lf->filename);
131691040Sarr			linker_file_unload(lf);
131791040Sarr			continue;
131891040Sarr		}
131991040Sarr		linker_file_register_modules(lf);
132091040Sarr		if (linker_file_lookup_set(lf, "sysinit_set", &si_start,
132191040Sarr		    &si_stop, NULL) == 0)
132291040Sarr			sysinit_add(si_start, si_stop);
132391040Sarr		linker_file_register_sysctls(lf);
132491040Sarr		lf->flags |= LINKER_FILE_LINKED;
132559751Speter	}
132691040Sarr	/* woohoo! we made it! */
132740159Speter}
132840159Speter
132991040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0)
133040159Speter
133140159Speter/*
133240159Speter * Search for a not-loaded module by name.
133391040Sarr *
133440159Speter * Modules may be found in the following locations:
133591040Sarr *
133691040Sarr * - preloaded (result is just the module name) - on disk (result is full path
133791040Sarr * to module)
133891040Sarr *
133991040Sarr * If the module name is qualified in any way (contains path, etc.) the we
134091040Sarr * simply return a copy of it.
134191040Sarr *
134240159Speter * The search path can be manipulated via sysctl.  Note that we use the ';'
134340159Speter * character as a separator to be consistent with the bootloader.
134440159Speter */
134540159Speter
134683321Speterstatic char linker_hintfile[] = "linker.hints";
1347111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules";
134840159Speter
134940159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
135091040Sarr    sizeof(linker_path), "module load search path");
135140159Speter
135277843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path));
135370417Speter
135459751Speterstatic char *linker_ext_list[] = {
135583321Speter	"",
135659751Speter	".ko",
135759751Speter	NULL
135859751Speter};
135959751Speter
136083321Speter/*
136191040Sarr * Check if file actually exists either with or without extension listed in
136291040Sarr * the linker_ext_list. (probably should be generic for the rest of the
136391040Sarr * kernel)
136483321Speter */
136559751Speterstatic char *
136691040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name,
136791040Sarr    int namelen, struct vattr *vap)
136840159Speter{
136991040Sarr	struct nameidata nd;
137091040Sarr	struct thread *td = curthread;	/* XXX */
137191040Sarr	char *result, **cpp, *sep;
137291040Sarr	int error, len, extlen, reclen, flags;
137391040Sarr	enum vtype type;
137440159Speter
137591040Sarr	extlen = 0;
137691040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
137791040Sarr		len = strlen(*cpp);
137891040Sarr		if (len > extlen)
137991040Sarr			extlen = len;
138091040Sarr	}
138191040Sarr	extlen++;		/* trailing '\0' */
138291040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
138383321Speter
138491040Sarr	reclen = pathlen + strlen(sep) + namelen + extlen + 1;
1385111119Simp	result = malloc(reclen, M_LINKER, M_WAITOK);
138691040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
138791040Sarr		snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep,
138891040Sarr		    namelen, name, *cpp);
138991040Sarr		/*
139091040Sarr		 * Attempt to open the file, and return the path if
139191040Sarr		 * we succeed and it's a regular file.
139291040Sarr		 */
139391040Sarr		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td);
139491040Sarr		flags = FREAD;
1395118094Sphk		error = vn_open(&nd, &flags, 0, -1);
139691040Sarr		if (error == 0) {
139791040Sarr			NDFREE(&nd, NDF_ONLY_PNBUF);
139891040Sarr			type = nd.ni_vp->v_type;
139991040Sarr			if (vap)
140091406Sjhb				VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td);
140191040Sarr			VOP_UNLOCK(nd.ni_vp, 0, td);
140291406Sjhb			vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
140391040Sarr			if (type == VREG)
140491040Sarr				return (result);
140591040Sarr		}
140683321Speter	}
140791040Sarr	free(result, M_LINKER);
140891040Sarr	return (NULL);
140983321Speter}
141083321Speter
141191040Sarr#define	INT_ALIGN(base, ptr)	ptr =					\
141283321Speter	(base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
141383321Speter
141483321Speter/*
141591040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If
141691040Sarr * version specification is available, then try to find the best KLD.
141783321Speter * Otherwise just find the latest one.
141883321Speter */
141983321Speterstatic char *
142091040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname,
142191040Sarr    int modnamelen, struct mod_depend *verinfo)
142283321Speter{
142391040Sarr	struct thread *td = curthread;	/* XXX */
142491406Sjhb	struct ucred *cred = td ? td->td_ucred : NULL;
142591040Sarr	struct nameidata nd;
142691040Sarr	struct vattr vattr, mattr;
142791040Sarr	u_char *hints = NULL;
142891040Sarr	u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep;
142991040Sarr	int error, ival, bestver, *intp, reclen, found, flags, clen, blen;
143083321Speter
143191040Sarr	result = NULL;
143291040Sarr	bestver = found = 0;
143383321Speter
143491040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
143591040Sarr	reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen +
143691040Sarr	    strlen(sep) + 1;
1437111119Simp	pathbuf = malloc(reclen, M_LINKER, M_WAITOK);
143891040Sarr	snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep,
143991040Sarr	    linker_hintfile);
144083321Speter
144191040Sarr	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td);
144291040Sarr	flags = FREAD;
1443118094Sphk	error = vn_open(&nd, &flags, 0, -1);
144491040Sarr	if (error)
144591040Sarr		goto bad;
144691040Sarr	NDFREE(&nd, NDF_ONLY_PNBUF);
144791040Sarr	if (nd.ni_vp->v_type != VREG)
144891040Sarr		goto bad;
144991040Sarr	best = cp = NULL;
145091040Sarr	error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td);
145191040Sarr	if (error)
145291040Sarr		goto bad;
145391040Sarr	/*
145491040Sarr	 * XXX: we need to limit this number to some reasonable value
145591040Sarr	 */
145691040Sarr	if (vattr.va_size > 100 * 1024) {
145791040Sarr		printf("hints file too large %ld\n", (long)vattr.va_size);
145891040Sarr		goto bad;
145991040Sarr	}
1460111119Simp	hints = malloc(vattr.va_size, M_TEMP, M_WAITOK);
146191040Sarr	if (hints == NULL)
146291040Sarr		goto bad;
146391068Sarr	error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0,
1464101941Srwatson	    UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td);
146591040Sarr	if (error)
146691040Sarr		goto bad;
146799553Sjeff	VOP_UNLOCK(nd.ni_vp, 0, td);
146891040Sarr	vn_close(nd.ni_vp, FREAD, cred, td);
146991040Sarr	nd.ni_vp = NULL;
147091040Sarr	if (reclen != 0) {
147191040Sarr		printf("can't read %d\n", reclen);
147291040Sarr		goto bad;
147391040Sarr	}
147491040Sarr	intp = (int *)hints;
147583321Speter	ival = *intp++;
147691040Sarr	if (ival != LINKER_HINTS_VERSION) {
147791040Sarr		printf("hints file version mismatch %d\n", ival);
147891040Sarr		goto bad;
147983321Speter	}
148091040Sarr	bufend = hints + vattr.va_size;
148191040Sarr	recptr = (u_char *)intp;
148291040Sarr	clen = blen = 0;
148391040Sarr	while (recptr < bufend && !found) {
148491040Sarr		intp = (int *)recptr;
148591040Sarr		reclen = *intp++;
148691040Sarr		ival = *intp++;
148791040Sarr		cp = (char *)intp;
148891040Sarr		switch (ival) {
148991040Sarr		case MDT_VERSION:
149091040Sarr			clen = *cp++;
149191040Sarr			if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
149291040Sarr				break;
149391040Sarr			cp += clen;
149491040Sarr			INT_ALIGN(hints, cp);
149591040Sarr			ival = *(int *)cp;
149691040Sarr			cp += sizeof(int);
149791040Sarr			clen = *cp++;
149891040Sarr			if (verinfo == NULL ||
149991040Sarr			    ival == verinfo->md_ver_preferred) {
150091040Sarr				found = 1;
150191040Sarr				break;
150291040Sarr			}
150391040Sarr			if (ival >= verinfo->md_ver_minimum &&
150491040Sarr			    ival <= verinfo->md_ver_maximum &&
150591040Sarr			    ival > bestver) {
150691040Sarr				bestver = ival;
150791040Sarr				best = cp;
150891040Sarr				blen = clen;
150991040Sarr			}
151091040Sarr			break;
151191040Sarr		default:
151291040Sarr			break;
151391040Sarr		}
151491040Sarr		recptr += reclen + sizeof(int);
151591040Sarr	}
151683321Speter	/*
151791040Sarr	 * Finally check if KLD is in the place
151883321Speter	 */
151991040Sarr	if (found)
152091040Sarr		result = linker_lookup_file(path, pathlen, cp, clen, &mattr);
152191040Sarr	else if (best)
152291040Sarr		result = linker_lookup_file(path, pathlen, best, blen, &mattr);
152391040Sarr
152491040Sarr	/*
152591040Sarr	 * KLD is newer than hints file. What we should do now?
152691040Sarr	 */
152791040Sarr	if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >))
152891040Sarr		printf("warning: KLD '%s' is newer than the linker.hints"
152991040Sarr		    " file\n", result);
153083321Speterbad:
1531105167Sphk	free(pathbuf, M_LINKER);
153291040Sarr	if (hints)
153391040Sarr		free(hints, M_TEMP);
153499553Sjeff	if (nd.ni_vp != NULL) {
153599553Sjeff		VOP_UNLOCK(nd.ni_vp, 0, td);
153691040Sarr		vn_close(nd.ni_vp, FREAD, cred, td);
153799553Sjeff	}
153891040Sarr	/*
153991040Sarr	 * If nothing found or hints is absent - fallback to the old
154091040Sarr	 * way by using "kldname[.ko]" as module name.
154191040Sarr	 */
154291040Sarr	if (!found && !bestver && result == NULL)
154391040Sarr		result = linker_lookup_file(path, pathlen, modname,
154491040Sarr		    modnamelen, NULL);
154591040Sarr	return (result);
154683321Speter}
154783321Speter
154883321Speter/*
154983321Speter * Lookup KLD which contains requested module in the all directories.
155083321Speter */
155183321Speterstatic char *
155283321Speterlinker_search_module(const char *modname, int modnamelen,
155391040Sarr    struct mod_depend *verinfo)
155483321Speter{
155591040Sarr	char *cp, *ep, *result;
155683321Speter
155791040Sarr	/*
155891040Sarr	 * traverse the linker path
155991040Sarr	 */
156091040Sarr	for (cp = linker_path; *cp; cp = ep + 1) {
156191040Sarr		/* find the end of this component */
156291040Sarr		for (ep = cp; (*ep != 0) && (*ep != ';'); ep++);
156391068Sarr		result = linker_hints_lookup(cp, ep - cp, modname,
156491068Sarr		    modnamelen, verinfo);
156591040Sarr		if (result != NULL)
156691040Sarr			return (result);
156791040Sarr		if (*ep == 0)
156891040Sarr			break;
156991040Sarr	}
157091040Sarr	return (NULL);
157183321Speter}
157283321Speter
157383321Speter/*
157483321Speter * Search for module in all directories listed in the linker_path.
157583321Speter */
157683321Speterstatic char *
157783321Speterlinker_search_kld(const char *name)
157883321Speter{
157991040Sarr	char *cp, *ep, *result, **cpp;
158091040Sarr	int extlen, len;
158183321Speter
158291040Sarr	/* qualified at all? */
158391040Sarr	if (index(name, '/'))
158491040Sarr		return (linker_strdup(name));
158540159Speter
158691040Sarr	extlen = 0;
158791040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
158891040Sarr		len = strlen(*cpp);
158991040Sarr		if (len > extlen)
159091040Sarr			extlen = len;
159191040Sarr	}
159291040Sarr	extlen++;		/* trailing '\0' */
159359751Speter
159491040Sarr	/* traverse the linker path */
159591040Sarr	len = strlen(name);
159691040Sarr	for (ep = linker_path; *ep; ep++) {
159791040Sarr		cp = ep;
159891040Sarr		/* find the end of this component */
159991040Sarr		for (; *ep != 0 && *ep != ';'; ep++);
160091040Sarr		result = linker_lookup_file(cp, ep - cp, name, len, NULL);
160191040Sarr		if (result != NULL)
160291040Sarr			return (result);
160391040Sarr	}
160491040Sarr	return (NULL);
160540159Speter}
160659751Speter
160759751Speterstatic const char *
160891040Sarrlinker_basename(const char *path)
160959751Speter{
161091040Sarr	const char *filename;
161159751Speter
161291040Sarr	filename = rindex(path, '/');
161391040Sarr	if (filename == NULL)
161491040Sarr		return path;
161591040Sarr	if (filename[1])
161691040Sarr		filename++;
161791040Sarr	return (filename);
161859751Speter}
161959751Speter
162059751Speter/*
162191040Sarr * Find a file which contains given module and load it, if "parent" is not
162291040Sarr * NULL, register a reference to it.
162359751Speter */
1624101241Smuxint
162583321Speterlinker_load_module(const char *kldname, const char *modname,
162691040Sarr    struct linker_file *parent, struct mod_depend *verinfo,
162791040Sarr    struct linker_file **lfpp)
162859751Speter{
162991040Sarr	linker_file_t lfdep;
163091040Sarr	const char *filename;
163191040Sarr	char *pathname;
163291040Sarr	int error;
163359751Speter
163491040Sarr	if (modname == NULL) {
163591040Sarr		/*
163691040Sarr 		 * We have to load KLD
163791040Sarr 		 */
163891068Sarr		KASSERT(verinfo == NULL, ("linker_load_module: verinfo"
163991068Sarr		    " is not NULL"));
164091040Sarr		pathname = linker_search_kld(kldname);
164191040Sarr	} else {
164291040Sarr		if (modlist_lookup2(modname, verinfo) != NULL)
164391040Sarr			return (EEXIST);
164494322Sbrian		if (kldname != NULL)
164594322Sbrian			pathname = linker_strdup(kldname);
164695488Sbrian		else if (rootvnode == NULL)
164794322Sbrian			pathname = NULL;
164894322Sbrian		else
164991040Sarr			/*
165091040Sarr			 * Need to find a KLD with required module
165191040Sarr			 */
165291040Sarr			pathname = linker_search_module(modname,
165391040Sarr			    strlen(modname), verinfo);
165491040Sarr	}
165591040Sarr	if (pathname == NULL)
165691040Sarr		return (ENOENT);
165791040Sarr
165883321Speter	/*
165991040Sarr	 * Can't load more than one file with the same basename XXX:
166091040Sarr	 * Actually it should be possible to have multiple KLDs with
166191040Sarr	 * the same basename but different path because they can
166291040Sarr	 * provide different versions of the same modules.
166383321Speter	 */
166491040Sarr	filename = linker_basename(pathname);
166591040Sarr	if (linker_find_file_by_name(filename)) {
166691040Sarr		error = EEXIST;
166791040Sarr		goto out;
166883321Speter	}
166991040Sarr	do {
167091040Sarr		error = linker_load_file(pathname, &lfdep);
167191040Sarr		if (error)
167291040Sarr			break;
167391040Sarr		if (modname && verinfo &&
167491040Sarr		    modlist_lookup2(modname, verinfo) == NULL) {
167591040Sarr			linker_file_unload(lfdep);
167691040Sarr			error = ENOENT;
167791040Sarr			break;
167891040Sarr		}
167991040Sarr		if (parent) {
168091040Sarr			error = linker_file_add_dependency(parent, lfdep);
168191040Sarr			if (error)
168291040Sarr				break;
168391040Sarr		}
168491040Sarr		if (lfpp)
168591040Sarr			*lfpp = lfdep;
168691040Sarr	} while (0);
168759751Speterout:
168891040Sarr	if (pathname)
168991040Sarr		free(pathname, M_LINKER);
169091040Sarr	return (error);
169159751Speter}
169259751Speter
169359751Speter/*
169491040Sarr * This routine is responsible for finding dependencies of userland initiated
169591040Sarr * kldload(2)'s of files.
169659751Speter */
169759751Speterint
169886469Siedowselinker_load_dependencies(linker_file_t lf)
169959751Speter{
170091040Sarr	linker_file_t lfdep;
170191040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
170291040Sarr	struct mod_metadata *mp, *nmp;
170391040Sarr	struct mod_depend *verinfo;
170491040Sarr	modlist_t mod;
170591040Sarr	const char *modname, *nmodname;
170692032Sdwmalone	int ver, error = 0, count;
170759751Speter
170891040Sarr	/*
170991040Sarr	 * All files are dependant on /kernel.
171091040Sarr	 */
171191040Sarr	if (linker_kernel_file) {
171291040Sarr		linker_kernel_file->refs++;
171391040Sarr		error = linker_file_add_dependency(lf, linker_kernel_file);
171491040Sarr		if (error)
171591040Sarr			return (error);
171659751Speter	}
171791040Sarr	if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop,
171891040Sarr	    &count) != 0)
171991040Sarr		return (0);
172091040Sarr	for (mdp = start; mdp < stop; mdp++) {
1721109605Sjake		mp = *mdp;
172291040Sarr		if (mp->md_type != MDT_VERSION)
172391040Sarr			continue;
1724109605Sjake		modname = mp->md_cval;
1725109605Sjake		ver = ((struct mod_version *)mp->md_data)->mv_version;
172691040Sarr		mod = modlist_lookup(modname, ver);
172791040Sarr		if (mod != NULL) {
172891040Sarr			printf("interface %s.%d already present in the KLD"
172991040Sarr			    " '%s'!\n", modname, ver,
173091040Sarr			    mod->container->filename);
173191040Sarr			return (EEXIST);
173291040Sarr		}
173391040Sarr	}
173474642Sbp
173591040Sarr	for (mdp = start; mdp < stop; mdp++) {
1736109605Sjake		mp = *mdp;
173791040Sarr		if (mp->md_type != MDT_DEPEND)
173891040Sarr			continue;
1739109605Sjake		modname = mp->md_cval;
1740109605Sjake		verinfo = mp->md_data;
174191040Sarr		nmodname = NULL;
174291040Sarr		for (nmdp = start; nmdp < stop; nmdp++) {
1743109605Sjake			nmp = *nmdp;
174491040Sarr			if (nmp->md_type != MDT_VERSION)
174591040Sarr				continue;
1746109605Sjake			nmodname = nmp->md_cval;
174792032Sdwmalone			if (strcmp(modname, nmodname) == 0)
174891040Sarr				break;
174991040Sarr		}
175091040Sarr		if (nmdp < stop)/* early exit, it's a self reference */
175191040Sarr			continue;
175291040Sarr		mod = modlist_lookup2(modname, verinfo);
175391040Sarr		if (mod) {	/* woohoo, it's loaded already */
175491040Sarr			lfdep = mod->container;
175591040Sarr			lfdep->refs++;
175691040Sarr			error = linker_file_add_dependency(lf, lfdep);
175791040Sarr			if (error)
175891040Sarr				break;
175991040Sarr			continue;
176091040Sarr		}
176191040Sarr		error = linker_load_module(NULL, modname, lf, verinfo, NULL);
176291040Sarr		if (error) {
176391040Sarr			printf("KLD %s: depends on %s - not available\n",
176491040Sarr			    lf->filename, modname);
176591040Sarr			break;
176691040Sarr		}
176759751Speter	}
176859751Speter
176991040Sarr	if (error)
177091040Sarr		return (error);
177191040Sarr	linker_addmodules(lf, start, stop, 0);
177291040Sarr	return (error);
177359751Speter}
177485736Sgreen
177585736Sgreenstatic int
177685736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque)
177785736Sgreen{
177885736Sgreen	struct sysctl_req *req;
177985736Sgreen
178085736Sgreen	req = opaque;
178185736Sgreen	return (SYSCTL_OUT(req, name, strlen(name) + 1));
178285736Sgreen}
178385736Sgreen
178485736Sgreen/*
178585736Sgreen * Export a nul-separated, double-nul-terminated list of all function names
178685736Sgreen * in the kernel.
178785736Sgreen */
178885736Sgreenstatic int
178985736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS)
179085736Sgreen{
179185736Sgreen	linker_file_t lf;
179285736Sgreen	int error;
179385736Sgreen
1794107089Srwatson#ifdef MAC
1795107089Srwatson	error = mac_check_kld_stat(req->td->td_ucred);
1796107089Srwatson	if (error)
1797107089Srwatson		return (error);
1798107089Srwatson#endif
1799100488Struckman	sysctl_wire_old_buffer(req, 0);
180098452Sarr	mtx_lock(&kld_mtx);
180185736Sgreen	TAILQ_FOREACH(lf, &linker_files, link) {
180285736Sgreen		error = LINKER_EACH_FUNCTION_NAME(lf,
180385736Sgreen		    sysctl_kern_function_list_iterate, req);
180498452Sarr		if (error) {
180598452Sarr			mtx_unlock(&kld_mtx);
180685736Sgreen			return (error);
180798452Sarr		}
180885736Sgreen	}
180998452Sarr	mtx_unlock(&kld_mtx);
181085736Sgreen	return (SYSCTL_OUT(req, "", 1));
181185736Sgreen}
181285736Sgreen
181385736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD,
181491040Sarr    NULL, 0, sysctl_kern_function_list, "", "kernel function list");
1815