kern_linker.c revision 83358
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 *
2650477Speter * $FreeBSD: head/sys/kern/kern_linker.c 83358 2001-09-12 00:50:23Z peter $
2725537Sdfr */
2825537Sdfr
2940159Speter#include "opt_ddb.h"
3040159Speter
3125537Sdfr#include <sys/param.h>
3225537Sdfr#include <sys/kernel.h>
3325537Sdfr#include <sys/systm.h>
3425537Sdfr#include <sys/malloc.h>
3525537Sdfr#include <sys/sysproto.h>
3625537Sdfr#include <sys/sysent.h>
3725537Sdfr#include <sys/proc.h>
3825537Sdfr#include <sys/lock.h>
3982749Sdillon#include <sys/mutex.h>
4025537Sdfr#include <sys/module.h>
4125537Sdfr#include <sys/linker.h>
4240159Speter#include <sys/fcntl.h>
4340159Speter#include <sys/libkern.h>
4440159Speter#include <sys/namei.h>
4540159Speter#include <sys/vnode.h>
4640159Speter#include <sys/sysctl.h>
4725537Sdfr
4854655Seivind
4959603Sdfr#include "linker_if.h"
5059603Sdfr
5140961Speter#ifdef KLD_DEBUG
5240961Speterint kld_debug = 0;
5340961Speter#endif
5440961Speter
5583321Speter/*static char *linker_search_path(const char *name, struct mod_depend *verinfo);*/
5659751Speterstatic const char *linker_basename(const char* path);
5783321Speterstatic int linker_load_module(const char *kldname, const char *modname,
5883321Speter	struct linker_file *parent, struct mod_depend *verinfo,
5983321Speter	struct linker_file **lfpp);
6059751Speter
6178161Speter/* Metadata from the static kernel */
6278161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata);
6378161Speter
6459751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker");
6559751Speter
6640906Speterlinker_file_t linker_kernel_file;
6731324Sbde
6825537Sdfrstatic struct lock lock;	/* lock for the file list */
6925537Sdfrstatic linker_class_list_t classes;
7050068Sgrogstatic linker_file_list_t linker_files;
7125537Sdfrstatic int next_file_id = 1;
7225537Sdfr
7359751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */
7460938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t;
7559751Speterstruct modlist {
7660938Sjake    TAILQ_ENTRY(modlist) link;		/* chain together all modules */
7759751Speter    linker_file_t	container;
7859751Speter    const char		*name;
7974642Sbp    int			version;
8059751Speter};
8159751Spetertypedef struct modlist	*modlist_t;
8259751Speterstatic modlisthead_t	found_modules;
8359751Speter
8459603Sdfrstatic char *
8559603Sdfrlinker_strdup(const char *str)
8659603Sdfr{
8759603Sdfr    char	*result;
8859603Sdfr
8959603Sdfr    if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
9059603Sdfr	strcpy(result, str);
9159603Sdfr    return(result);
9259603Sdfr}
9359603Sdfr
9425537Sdfrstatic void
9525537Sdfrlinker_init(void* arg)
9625537Sdfr{
9725537Sdfr    lockinit(&lock, PVM, "klink", 0, 0);
9825537Sdfr    TAILQ_INIT(&classes);
9950068Sgrog    TAILQ_INIT(&linker_files);
10025537Sdfr}
10125537Sdfr
10240159SpeterSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0);
10325537Sdfr
10425537Sdfrint
10559603Sdfrlinker_add_class(linker_class_t lc)
10625537Sdfr{
10759603Sdfr    kobj_class_compile((kobj_class_t) lc);
10859751Speter    TAILQ_INSERT_TAIL(&classes, lc, link);
10925537Sdfr    return 0;
11025537Sdfr}
11125537Sdfr
11225537Sdfrstatic void
11325537Sdfrlinker_file_sysinit(linker_file_t lf)
11425537Sdfr{
11578161Speter    struct sysinit** start, ** stop;
11625537Sdfr    struct sysinit** sipp;
11725537Sdfr    struct sysinit** xipp;
11825537Sdfr    struct sysinit* save;
11925537Sdfr
12025537Sdfr    KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
12125537Sdfr		   lf->filename));
12225537Sdfr
12378161Speter    if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0)
12425537Sdfr	return;
12525537Sdfr    /*
12625537Sdfr     * Perform a bubble sort of the system initialization objects by
12725537Sdfr     * their subsystem (primary key) and order (secondary key).
12825537Sdfr     *
12925537Sdfr     * Since some things care about execution order, this is the
13025537Sdfr     * operation which ensures continued function.
13125537Sdfr     */
13278161Speter    for (sipp = start; sipp < stop; sipp++) {
13378161Speter	for (xipp = sipp + 1; xipp < stop; xipp++) {
13462860Sbp	    if ((*sipp)->subsystem < (*xipp)->subsystem ||
13541055Speter		 ((*sipp)->subsystem == (*xipp)->subsystem &&
13641055Speter		  (*sipp)->order <= (*xipp)->order))
13725537Sdfr		continue;	/* skip*/
13825537Sdfr	    save = *sipp;
13925537Sdfr	    *sipp = *xipp;
14025537Sdfr	    *xipp = save;
14125537Sdfr	}
14225537Sdfr    }
14325537Sdfr
14425537Sdfr
14525537Sdfr    /*
14625537Sdfr     * Traverse the (now) ordered list of system initialization tasks.
14725537Sdfr     * Perform each task, and continue on to the next task.
14825537Sdfr     */
14978161Speter    for (sipp = start; sipp < stop; sipp++) {
15041055Speter	if ((*sipp)->subsystem == SI_SUB_DUMMY)
15125537Sdfr	    continue;	/* skip dummy task(s)*/
15225537Sdfr
15348391Speter	/* Call function */
15448391Speter	(*((*sipp)->func))((*sipp)->udata);
15525537Sdfr    }
15625537Sdfr}
15725537Sdfr
15841055Speterstatic void
15941055Speterlinker_file_sysuninit(linker_file_t lf)
16041055Speter{
16178161Speter    struct sysinit** start, ** stop;
16241055Speter    struct sysinit** sipp;
16341055Speter    struct sysinit** xipp;
16441055Speter    struct sysinit* save;
16541055Speter
16641055Speter    KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
16741055Speter		   lf->filename));
16841055Speter
16978161Speter    if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, NULL) != 0)
17041055Speter	return;
17141055Speter
17241055Speter    /*
17341055Speter     * Perform a reverse bubble sort of the system initialization objects
17441055Speter     * by their subsystem (primary key) and order (secondary key).
17541055Speter     *
17641055Speter     * Since some things care about execution order, this is the
17741055Speter     * operation which ensures continued function.
17841055Speter     */
17978161Speter    for (sipp = start; sipp < stop; sipp++) {
18078161Speter	for (xipp = sipp + 1; xipp < stop; xipp++) {
18162860Sbp	    if ((*sipp)->subsystem > (*xipp)->subsystem ||
18241055Speter		 ((*sipp)->subsystem == (*xipp)->subsystem &&
18341055Speter		  (*sipp)->order >= (*xipp)->order))
18441055Speter		continue;	/* skip*/
18541055Speter	    save = *sipp;
18641055Speter	    *sipp = *xipp;
18741055Speter	    *xipp = save;
18841055Speter	}
18941055Speter    }
19041055Speter
19141055Speter    /*
19241055Speter     * Traverse the (now) ordered list of system initialization tasks.
19341055Speter     * Perform each task, and continue on to the next task.
19441055Speter     */
19578161Speter    for (sipp = start; sipp < stop; sipp++) {
19641055Speter	if ((*sipp)->subsystem == SI_SUB_DUMMY)
19741055Speter	    continue;	/* skip dummy task(s)*/
19841055Speter
19948391Speter	/* Call function */
20048391Speter	(*((*sipp)->func))((*sipp)->udata);
20141055Speter    }
20241055Speter}
20341055Speter
20444078Sdfrstatic void
20544078Sdfrlinker_file_register_sysctls(linker_file_t lf)
20644078Sdfr{
20778161Speter    struct sysctl_oid **start, **stop, **oidp;
20844078Sdfr
20944078Sdfr    KLD_DPF(FILE, ("linker_file_register_sysctls: registering SYSCTLs for %s\n",
21044078Sdfr		   lf->filename));
21144078Sdfr
21278161Speter    if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
21344078Sdfr	return;
21444078Sdfr
21578161Speter    for (oidp = start; oidp < stop; oidp++)
21678161Speter	sysctl_register_oid(*oidp);
21744078Sdfr}
21844078Sdfr
21944078Sdfrstatic void
22044078Sdfrlinker_file_unregister_sysctls(linker_file_t lf)
22144078Sdfr{
22278161Speter    struct sysctl_oid **start, **stop, **oidp;
22344078Sdfr
22444078Sdfr    KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs for %s\n",
22544078Sdfr		   lf->filename));
22644078Sdfr
22778161Speter    if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
22844078Sdfr	return;
22944078Sdfr
23078161Speter    for (oidp = start; oidp < stop; oidp++)
23178161Speter	sysctl_unregister_oid(*oidp);
23244078Sdfr}
23344078Sdfr
23459751Speterstatic int
23559751Speterlinker_file_register_modules(linker_file_t lf)
23659751Speter{
23774639Sbp    int error;
23878161Speter    struct mod_metadata **start, **stop;
23978161Speter    struct mod_metadata **mdp;
24059751Speter    const moduledata_t *moddata;
24159751Speter
24259751Speter    KLD_DPF(FILE, ("linker_file_register_modules: registering modules in %s\n",
24359751Speter		   lf->filename));
24459751Speter
24578161Speter    if (linker_file_lookup_set(lf, "modmetadata_set", &start, &stop, 0) != 0) {
24678161Speter	/*
24778161Speter	 * This fallback should be unnecessary, but if we get booted from
24878161Speter	 * boot2 instead of loader and we are missing our metadata then
24978161Speter	 * we have to try the best we can.
25078161Speter	 */
25178161Speter	if (lf == linker_kernel_file) {
25278161Speter	    start = SET_BEGIN(modmetadata_set);
25378161Speter	    stop = SET_LIMIT(modmetadata_set);
25478161Speter	} else {
25578161Speter	    return 0;
25678161Speter	}
25778161Speter    }
25878161Speter    for (mdp = start; mdp < stop; mdp++) {
25978161Speter	if ((*mdp)->md_type != MDT_MODULE)
26074639Sbp	    continue;
26178161Speter	moddata = (*mdp)->md_data;
26274639Sbp	KLD_DPF(FILE, ("Registering module %s in %s\n",
26374639Sbp             moddata->name, lf->filename));
26474639Sbp	if (module_lookupbyname(moddata->name) != NULL) {
26574639Sbp	    printf("Warning: module %s already exists\n", moddata->name);
26674639Sbp	    continue;	/* or return a error ? */
26759751Speter	}
26874639Sbp	error = module_register(moddata, lf);
26974639Sbp	if (error)
27074639Sbp	    printf("Module %s failed to register: %d\n", moddata->name, error);
27159751Speter    }
27274639Sbp    return 0;
27359751Speter}
27459751Speter
27559751Speterstatic void
27659751Speterlinker_init_kernel_modules(void)
27759751Speter{
27859751Speter    linker_file_register_modules(linker_kernel_file);
27959751Speter}
28059751Speter
28159751SpeterSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0);
28259751Speter
28325537Sdfrint
28425537Sdfrlinker_load_file(const char* filename, linker_file_t* result)
28525537Sdfr{
28625537Sdfr    linker_class_t lc;
28725537Sdfr    linker_file_t lf;
28842755Speter    int foundfile, error = 0;
28925537Sdfr
29062261Sarchie    /* Refuse to load modules if securelevel raised */
29162261Sarchie    if (securelevel > 0)
29262261Sarchie	return EPERM;
29362261Sarchie
29425537Sdfr    lf = linker_find_file_by_name(filename);
29525537Sdfr    if (lf) {
29625537Sdfr	KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
29725537Sdfr	*result = lf;
29825537Sdfr	lf->refs++;
29925537Sdfr	goto out;
30025537Sdfr    }
30125537Sdfr
30225537Sdfr    lf = NULL;
30342755Speter    foundfile = 0;
30471999Sphk    TAILQ_FOREACH(lc, &classes, link) {
30580701Sjake	KLD_DPF(FILE, ("linker_load_file: trying to load %s\n",
30680701Sjake		       filename));
30759751Speter	error = LINKER_LOAD_FILE(lc, filename, &lf);
30842755Speter	/*
30942755Speter	 * If we got something other than ENOENT, then it exists but we cannot
31042755Speter	 * load it for some other reason.
31142755Speter	 */
31242755Speter	if (error != ENOENT)
31342755Speter	    foundfile = 1;
31425537Sdfr	if (lf) {
31559751Speter	    linker_file_register_modules(lf);
31644549Sdfr	    linker_file_register_sysctls(lf);
31725537Sdfr	    linker_file_sysinit(lf);
31859751Speter	    lf->flags |= LINKER_FILE_LINKED;
31925537Sdfr
32025537Sdfr	    *result = lf;
32140861Speter	    error = 0;
32225537Sdfr	    goto out;
32325537Sdfr	}
32425537Sdfr    }
32542755Speter    /*
32642755Speter     * Less than ideal, but tells the user whether it failed to load or
32742755Speter     * the module was not found.
32842755Speter     */
32942755Speter    if (foundfile)
33042755Speter	error = ENOEXEC;	/* Format not recognised (or unloadable) */
33142755Speter    else
33242755Speter	error = ENOENT;		/* Nothing found */
33325537Sdfr
33425537Sdfrout:
33525537Sdfr    return error;
33625537Sdfr}
33725537Sdfr
33883321Speter/* XXX: function parameters are incomplete */
33978413Sbrianint
34078413Sbrianlinker_reference_module(const char *modname, linker_file_t *result)
34178413Sbrian{
34278413Sbrian
34383321Speter    return linker_load_module(NULL, modname, NULL, NULL, result);
34478413Sbrian}
34578413Sbrian
34625537Sdfrlinker_file_t
34725537Sdfrlinker_find_file_by_name(const char* filename)
34825537Sdfr{
34925537Sdfr    linker_file_t lf = 0;
35040861Speter    char *koname;
35125537Sdfr
35240861Speter    koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
35340861Speter    if (koname == NULL)
35440861Speter	goto out;
35540861Speter    sprintf(koname, "%s.ko", filename);
35640861Speter
35725537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
35871999Sphk    TAILQ_FOREACH(lf, &linker_files, link) {
35940861Speter	if (!strcmp(lf->filename, koname))
36040861Speter	    break;
36125537Sdfr	if (!strcmp(lf->filename, filename))
36225537Sdfr	    break;
36340861Speter    }
36425537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
36525537Sdfr
36640861Speterout:
36740861Speter    if (koname)
36840861Speter	free(koname, M_LINKER);
36925537Sdfr    return lf;
37025537Sdfr}
37125537Sdfr
37225537Sdfrlinker_file_t
37325537Sdfrlinker_find_file_by_id(int fileid)
37425537Sdfr{
37525537Sdfr    linker_file_t lf = 0;
37625537Sdfr
37725537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
37871999Sphk    TAILQ_FOREACH(lf, &linker_files, link)
37925537Sdfr	if (lf->id == fileid)
38025537Sdfr	    break;
38125537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
38225537Sdfr
38325537Sdfr    return lf;
38425537Sdfr}
38525537Sdfr
38625537Sdfrlinker_file_t
38759603Sdfrlinker_make_file(const char* pathname, linker_class_t lc)
38825537Sdfr{
38925537Sdfr    linker_file_t lf = 0;
39040159Speter    const char *filename;
39125537Sdfr
39259751Speter    filename = linker_basename(pathname);
39340159Speter
39425537Sdfr    KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
39545356Speter    lockmgr(&lock, LK_EXCLUSIVE, 0, curproc);
39659603Sdfr    lf = (linker_file_t) kobj_create((kobj_class_t) lc, M_LINKER, M_WAITOK);
39725537Sdfr    if (!lf)
39825537Sdfr	goto out;
39925537Sdfr
40025537Sdfr    lf->refs = 1;
40125537Sdfr    lf->userrefs = 0;
40243185Sdfr    lf->flags = 0;
40359603Sdfr    lf->filename = linker_strdup(filename);
40425537Sdfr    lf->id = next_file_id++;
40525537Sdfr    lf->ndeps = 0;
40625537Sdfr    lf->deps = NULL;
40725537Sdfr    STAILQ_INIT(&lf->common);
40825537Sdfr    TAILQ_INIT(&lf->modules);
40925537Sdfr
41050068Sgrog    TAILQ_INSERT_TAIL(&linker_files, lf, link);
41125537Sdfr
41225537Sdfrout:
41325537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
41425537Sdfr    return lf;
41525537Sdfr}
41625537Sdfr
41725537Sdfrint
41825537Sdfrlinker_file_unload(linker_file_t file)
41925537Sdfr{
42025537Sdfr    module_t mod, next;
42159751Speter    modlist_t ml, nextml;
42225537Sdfr    struct common_symbol* cp;
42325537Sdfr    int error = 0;
42425537Sdfr    int i;
42525537Sdfr
42662261Sarchie    /* Refuse to unload modules if securelevel raised */
42762261Sarchie    if (securelevel > 0)
42862261Sarchie	return EPERM;
42962261Sarchie
43040159Speter    KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
43145356Speter    lockmgr(&lock, LK_EXCLUSIVE, 0, curproc);
43225537Sdfr    if (file->refs == 1) {
43325537Sdfr	KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
43425537Sdfr	/*
43525537Sdfr	 * Inform any modules associated with this file.
43625537Sdfr	 */
43725537Sdfr	for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
43825537Sdfr	    next = module_getfnext(mod);
43925537Sdfr
44025537Sdfr	    /*
44125537Sdfr	     * Give the module a chance to veto the unload.
44225537Sdfr	     */
44343301Sdillon	    if ((error = module_unload(mod)) != 0) {
44425537Sdfr		KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
44525537Sdfr			       mod));
44625537Sdfr		lockmgr(&lock, LK_RELEASE, 0, curproc);
44725537Sdfr		goto out;
44825537Sdfr	    }
44925537Sdfr
45025537Sdfr	    module_release(mod);
45125537Sdfr	}
45225537Sdfr    }
45325537Sdfr
45425537Sdfr    file->refs--;
45525537Sdfr    if (file->refs > 0) {
45625537Sdfr	lockmgr(&lock, LK_RELEASE, 0, curproc);
45725537Sdfr	goto out;
45825537Sdfr    }
45925537Sdfr
46059751Speter    for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) {
46159751Speter	nextml = TAILQ_NEXT(ml, link);
46259751Speter	if (ml->container == file) {
46359751Speter	    TAILQ_REMOVE(&found_modules, ml, link);
46459751Speter	}
46559751Speter    }
46659751Speter
46743185Sdfr    /* Don't try to run SYSUNINITs if we are unloaded due to a link error */
46844078Sdfr    if (file->flags & LINKER_FILE_LINKED) {
46943185Sdfr	linker_file_sysuninit(file);
47044078Sdfr	linker_file_unregister_sysctls(file);
47144078Sdfr    }
47241055Speter
47350068Sgrog    TAILQ_REMOVE(&linker_files, file, link);
47425537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
47540159Speter
47659751Speter    if (file->deps) {
47759751Speter	for (i = 0; i < file->ndeps; i++)
47859751Speter	    linker_file_unload(file->deps[i]);
47959751Speter	free(file->deps, M_LINKER);
48059751Speter	file->deps = NULL;
48159751Speter    }
48225537Sdfr
48325537Sdfr    for (cp = STAILQ_FIRST(&file->common); cp;
48425537Sdfr	 cp = STAILQ_FIRST(&file->common)) {
48560938Sjake	STAILQ_REMOVE(&file->common, cp, common_symbol, link);
48625537Sdfr	free(cp, M_LINKER);
48725537Sdfr    }
48825537Sdfr
48959603Sdfr    LINKER_UNLOAD(file);
49059751Speter    if (file->filename) {
49159751Speter	free(file->filename, M_LINKER);
49259751Speter	file->filename = NULL;
49359751Speter    }
49459603Sdfr    kobj_delete((kobj_t) file, M_LINKER);
49525537Sdfr
49625537Sdfrout:
49725537Sdfr    return error;
49825537Sdfr}
49925537Sdfr
50025537Sdfrint
50125537Sdfrlinker_file_add_dependancy(linker_file_t file, linker_file_t dep)
50225537Sdfr{
50325537Sdfr    linker_file_t* newdeps;
50425537Sdfr
50525537Sdfr    newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
50669781Sdwmalone		     M_LINKER, M_WAITOK | M_ZERO);
50725537Sdfr    if (newdeps == NULL)
50825537Sdfr	return ENOMEM;
50925537Sdfr
51025537Sdfr    if (file->deps) {
51125537Sdfr	bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
51225537Sdfr	free(file->deps, M_LINKER);
51325537Sdfr    }
51425537Sdfr    file->deps = newdeps;
51525537Sdfr    file->deps[file->ndeps] = dep;
51625537Sdfr    file->ndeps++;
51725537Sdfr
51825537Sdfr    return 0;
51925537Sdfr}
52025537Sdfr
52178161Speter/*
52278161Speter * Locate a linker set and its contents.
52378161Speter * This is a helper function to avoid linker_if.h exposure elsewhere.
52478161Speter * Note: firstp and lastp are really void ***
52578161Speter */
52678161Speterint
52778161Speterlinker_file_lookup_set(linker_file_t file, const char *name,
52878161Speter		       void *firstp, void *lastp, int *countp)
52978161Speter{
53078161Speter
53178161Speter    return LINKER_LOOKUP_SET(file, name, firstp, lastp, countp);
53278161Speter}
53378161Speter
53425537Sdfrcaddr_t
53525537Sdfrlinker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
53625537Sdfr{
53743309Sdillon    c_linker_sym_t sym;
53838275Sdfr    linker_symval_t symval;
53925537Sdfr    caddr_t address;
54025537Sdfr    size_t common_size = 0;
54125537Sdfr    int i;
54225537Sdfr
54340159Speter    KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
54425537Sdfr		  file, name, deps));
54525537Sdfr
54659603Sdfr    if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) {
54759603Sdfr	LINKER_SYMBOL_VALUES(file, sym, &symval);
54838275Sdfr	if (symval.value == 0)
54925537Sdfr	    /*
55025537Sdfr	     * For commons, first look them up in the dependancies and
55125537Sdfr	     * only allocate space if not found there.
55225537Sdfr	     */
55338275Sdfr	    common_size = symval.size;
55440159Speter	else {
55540159Speter	    KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol.value=%x\n", symval.value));
55638275Sdfr	    return symval.value;
55740159Speter	}
55838275Sdfr    }
55925537Sdfr
56042849Speter    if (deps) {
56125537Sdfr	for (i = 0; i < file->ndeps; i++) {
56225537Sdfr	    address = linker_file_lookup_symbol(file->deps[i], name, 0);
56340159Speter	    if (address) {
56440159Speter		KLD_DPF(SYM, ("linker_file_lookup_symbol: deps value=%x\n", address));
56525537Sdfr		return address;
56640159Speter	    }
56725537Sdfr	}
56842849Speter    }
56942849Speter
57025537Sdfr    if (common_size > 0) {
57125537Sdfr	/*
57225537Sdfr	 * This is a common symbol which was not found in the
57325537Sdfr	 * dependancies.  We maintain a simple common symbol table in
57425537Sdfr	 * the file object.
57525537Sdfr	 */
57625537Sdfr	struct common_symbol* cp;
57725537Sdfr
57872012Sphk	STAILQ_FOREACH(cp, &file->common, link)
57940159Speter	    if (!strcmp(cp->name, name)) {
58040159Speter		KLD_DPF(SYM, ("linker_file_lookup_symbol: old common value=%x\n", cp->address));
58125537Sdfr		return cp->address;
58240159Speter	    }
58325537Sdfr
58425537Sdfr	/*
58525537Sdfr	 * Round the symbol size up to align.
58625537Sdfr	 */
58725537Sdfr	common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
58825537Sdfr	cp = malloc(sizeof(struct common_symbol)
58925537Sdfr		    + common_size
59025537Sdfr		    + strlen(name) + 1,
59169781Sdwmalone		    M_LINKER, M_WAITOK | M_ZERO);
59240159Speter	if (!cp) {
59340159Speter	    KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
59425537Sdfr	    return 0;
59540159Speter	}
59625537Sdfr
59725537Sdfr	cp->address = (caddr_t) (cp + 1);
59825537Sdfr	cp->name = cp->address + common_size;
59925537Sdfr	strcpy(cp->name, name);
60025537Sdfr	bzero(cp->address, common_size);
60125537Sdfr	STAILQ_INSERT_TAIL(&file->common, cp, link);
60225537Sdfr
60340159Speter	KLD_DPF(SYM, ("linker_file_lookup_symbol: new common value=%x\n", cp->address));
60425537Sdfr	return cp->address;
60525537Sdfr    }
60625537Sdfr
60740159Speter    KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
60825537Sdfr    return 0;
60925537Sdfr}
61025537Sdfr
61140159Speter#ifdef DDB
61225537Sdfr/*
61340159Speter * DDB Helpers.  DDB has to look across multiple files with their own
61440159Speter * symbol tables and string tables.
61540159Speter *
61640159Speter * Note that we do not obey list locking protocols here.  We really don't
61740159Speter * need DDB to hang because somebody's got the lock held.  We'll take the
61840159Speter * chance that the files list is inconsistant instead.
61940159Speter */
62040159Speter
62140159Speterint
62243309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
62340159Speter{
62440159Speter    linker_file_t lf;
62540159Speter
62671999Sphk    TAILQ_FOREACH(lf, &linker_files, link) {
62759603Sdfr	if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0)
62840159Speter	    return 0;
62940159Speter    }
63040159Speter    return ENOENT;
63140159Speter}
63240159Speter
63340159Speterint
63443309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
63540159Speter{
63640159Speter    linker_file_t lf;
63750272Sbde    u_long off = (uintptr_t)value;
63840159Speter    u_long diff, bestdiff;
63943309Sdillon    c_linker_sym_t best;
64043309Sdillon    c_linker_sym_t es;
64140159Speter
64240159Speter    best = 0;
64340159Speter    bestdiff = off;
64471999Sphk    TAILQ_FOREACH(lf, &linker_files, link) {
64559603Sdfr	if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0)
64640159Speter	    continue;
64740159Speter	if (es != 0 && diff < bestdiff) {
64840159Speter	    best = es;
64940159Speter	    bestdiff = diff;
65040159Speter	}
65140159Speter	if (bestdiff == 0)
65240159Speter	    break;
65340159Speter    }
65440159Speter    if (best) {
65540159Speter	*sym = best;
65640159Speter	*diffp = bestdiff;
65740159Speter	return 0;
65840159Speter    } else {
65940159Speter	*sym = 0;
66040159Speter	*diffp = off;
66140159Speter	return ENOENT;
66240159Speter    }
66340159Speter}
66440159Speter
66540159Speterint
66643309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
66740159Speter{
66840159Speter    linker_file_t lf;
66940159Speter
67071999Sphk    TAILQ_FOREACH(lf, &linker_files, link) {
67159603Sdfr	if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0)
67240159Speter	    return 0;
67340159Speter    }
67440159Speter    return ENOENT;
67540159Speter}
67640159Speter
67740159Speter#endif
67840159Speter
67940159Speter/*
68025537Sdfr * Syscalls.
68125537Sdfr */
68282749Sdillon/*
68382749Sdillon * MPSAFE
68482749Sdillon */
68525537Sdfrint
68630994Sphkkldload(struct proc* p, struct kldload_args* uap)
68725537Sdfr{
68883321Speter    char *kldname, *modname;
68982749Sdillon    char *pathname = NULL;
69025537Sdfr    linker_file_t lf;
69125537Sdfr    int error = 0;
69225537Sdfr
69330994Sphk    p->p_retval[0] = -1;
69425537Sdfr
69562261Sarchie    if (securelevel > 0)	/* redundant, but that's OK */
69625537Sdfr	return EPERM;
69725537Sdfr
69882749Sdillon    mtx_lock(&Giant);
69982749Sdillon
70046112Sphk    if ((error = suser(p)) != 0)
70182749Sdillon	goto out;
70225537Sdfr
70359751Speter    pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
70459751Speter    if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0)
70525537Sdfr	goto out;
70625537Sdfr
70783321Speter    /*
70883321Speter     * If path do not contain qualified name or any dot in it (kldname.ko, or
70983321Speter     * kldname.ver.ko) treat it as interface name.
71083321Speter     */
71183321Speter    if (index(pathname, '/') || index(pathname, '.')) {
71283321Speter	kldname = pathname;
71383321Speter	modname = NULL;
71483321Speter    } else {
71583321Speter	kldname = NULL;
71683321Speter	modname = pathname;
71759751Speter    }
71883321Speter    error = linker_load_module(kldname, modname, NULL, NULL, &lf);
71983321Speter    if (error)
72042316Smsmith	goto out;
72142316Smsmith
72225537Sdfr    lf->userrefs++;
72330994Sphk    p->p_retval[0] = lf->id;
72440159Speter
72525537Sdfrout:
72659751Speter    if (pathname)
72759751Speter	free(pathname, M_TEMP);
72882749Sdillon    mtx_unlock(&Giant);
72982749Sdillon    return (error);
73025537Sdfr}
73125537Sdfr
73282749Sdillon/*
73382749Sdillon * MPSAFE
73482749Sdillon */
73525537Sdfrint
73630994Sphkkldunload(struct proc* p, struct kldunload_args* uap)
73725537Sdfr{
73825537Sdfr    linker_file_t lf;
73925537Sdfr    int error = 0;
74025537Sdfr
74162261Sarchie    if (securelevel > 0)	/* redundant, but that's OK */
74225537Sdfr	return EPERM;
74325537Sdfr
74482749Sdillon    mtx_lock(&Giant);
74582749Sdillon
74646112Sphk    if ((error = suser(p)) != 0)
74782749Sdillon	goto out;
74825537Sdfr
74925537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
75025537Sdfr    if (lf) {
75125537Sdfr	KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
75225537Sdfr	if (lf->userrefs == 0) {
75359751Speter	    printf("kldunload: attempt to unload file that was loaded by the kernel\n");
75425537Sdfr	    error = EBUSY;
75525537Sdfr	    goto out;
75625537Sdfr	}
75743084Speter	lf->userrefs--;
75842837Speter	error = linker_file_unload(lf);
75942837Speter	if (error)
76043084Speter	    lf->userrefs++;
76182749Sdillon    } else {
76225537Sdfr	error = ENOENT;
76382749Sdillon    }
76425537Sdfrout:
76582749Sdillon    mtx_unlock(&Giant);
76682749Sdillon    return (error);
76725537Sdfr}
76825537Sdfr
76982749Sdillon/*
77082749Sdillon * MPSAFE
77182749Sdillon */
77225537Sdfrint
77330994Sphkkldfind(struct proc* p, struct kldfind_args* uap)
77425537Sdfr{
77559751Speter    char* pathname;
77659751Speter    const char *filename;
77725537Sdfr    linker_file_t lf;
77825537Sdfr    int error = 0;
77925537Sdfr
78082749Sdillon    mtx_lock(&Giant);
78182749Sdillon
78230994Sphk    p->p_retval[0] = -1;
78325537Sdfr
78459751Speter    pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
78559751Speter    if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0)
78625537Sdfr	goto out;
78725537Sdfr
78859751Speter    filename = linker_basename(pathname);
78942316Smsmith
79059751Speter    lf = linker_find_file_by_name(filename);
79125537Sdfr    if (lf)
79230994Sphk	p->p_retval[0] = lf->id;
79325537Sdfr    else
79425537Sdfr	error = ENOENT;
79540159Speter
79625537Sdfrout:
79759751Speter    if (pathname)
79859751Speter	free(pathname, M_TEMP);
79982749Sdillon    mtx_unlock(&Giant);
80082749Sdillon    return (error);
80125537Sdfr}
80225537Sdfr
80382749Sdillon/*
80482749Sdillon * MPSAFE
80582749Sdillon */
80625537Sdfrint
80730994Sphkkldnext(struct proc* p, struct kldnext_args* uap)
80825537Sdfr{
80925537Sdfr    linker_file_t lf;
81025537Sdfr    int error = 0;
81125537Sdfr
81282749Sdillon    mtx_lock(&Giant);
81382749Sdillon
81425537Sdfr    if (SCARG(uap, fileid) == 0) {
81550068Sgrog	if (TAILQ_FIRST(&linker_files))
81650068Sgrog	    p->p_retval[0] = TAILQ_FIRST(&linker_files)->id;
81725537Sdfr	else
81830994Sphk	    p->p_retval[0] = 0;
81982749Sdillon	goto out;
82025537Sdfr    }
82140159Speter
82225537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
82325537Sdfr    if (lf) {
82425537Sdfr	if (TAILQ_NEXT(lf, link))
82530994Sphk	    p->p_retval[0] = TAILQ_NEXT(lf, link)->id;
82625537Sdfr	else
82730994Sphk	    p->p_retval[0] = 0;
82882749Sdillon    } else {
82925537Sdfr	error = ENOENT;
83082749Sdillon    }
83182749Sdillonout:
83282749Sdillon    mtx_unlock(&Giant);
83382749Sdillon    return (error);
83425537Sdfr}
83525537Sdfr
83682749Sdillon/*
83782749Sdillon * MPSAFE
83882749Sdillon */
83925537Sdfrint
84030994Sphkkldstat(struct proc* p, struct kldstat_args* uap)
84125537Sdfr{
84225537Sdfr    linker_file_t lf;
84325537Sdfr    int error = 0;
84425537Sdfr    int version;
84525537Sdfr    struct kld_file_stat* stat;
84625537Sdfr    int namelen;
84725537Sdfr
84882749Sdillon    mtx_lock(&Giant);
84982749Sdillon
85025537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
85125537Sdfr    if (!lf) {
85225537Sdfr	error = ENOENT;
85325537Sdfr	goto out;
85425537Sdfr    }
85525537Sdfr
85625537Sdfr    stat = SCARG(uap, stat);
85725537Sdfr
85825537Sdfr    /*
85925537Sdfr     * Check the version of the user's structure.
86025537Sdfr     */
86143301Sdillon    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
86225537Sdfr	goto out;
86325537Sdfr    if (version != sizeof(struct kld_file_stat)) {
86425537Sdfr	error = EINVAL;
86525537Sdfr	goto out;
86625537Sdfr    }
86725537Sdfr
86825537Sdfr    namelen = strlen(lf->filename) + 1;
86925537Sdfr    if (namelen > MAXPATHLEN)
87025537Sdfr	namelen = MAXPATHLEN;
87143301Sdillon    if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
87225537Sdfr	goto out;
87343301Sdillon    if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
87425537Sdfr	goto out;
87543301Sdillon    if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
87625537Sdfr	goto out;
87743301Sdillon    if ((error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) != 0)
87825537Sdfr	goto out;
87943301Sdillon    if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
88025537Sdfr	goto out;
88125537Sdfr
88230994Sphk    p->p_retval[0] = 0;
88325537Sdfr
88425537Sdfrout:
88582749Sdillon    mtx_unlock(&Giant);
88682749Sdillon    return (error);
88725537Sdfr}
88825537Sdfr
88982749Sdillon/*
89082749Sdillon * MPSAFE
89182749Sdillon */
89225537Sdfrint
89330994Sphkkldfirstmod(struct proc* p, struct kldfirstmod_args* uap)
89425537Sdfr{
89525537Sdfr    linker_file_t lf;
89625537Sdfr    int error = 0;
89725537Sdfr
89882749Sdillon    mtx_lock(&Giant);
89925537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
90025537Sdfr    if (lf) {
90125537Sdfr	if (TAILQ_FIRST(&lf->modules))
90230994Sphk	    p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules));
90325537Sdfr	else
90430994Sphk	    p->p_retval[0] = 0;
90582749Sdillon    } else {
90625537Sdfr	error = ENOENT;
90782749Sdillon    }
90882749Sdillon    mtx_unlock(&Giant);
90982749Sdillon    return (error);
91025537Sdfr}
91140159Speter
91282749Sdillon/*
91382749Sdillon * MPSAFE
91482749Sdillon */
91541090Speterint
91641090Speterkldsym(struct proc *p, struct kldsym_args *uap)
91741090Speter{
91841090Speter    char *symstr = NULL;
91943309Sdillon    c_linker_sym_t sym;
92041090Speter    linker_symval_t symval;
92141090Speter    linker_file_t lf;
92241090Speter    struct kld_sym_lookup lookup;
92341090Speter    int error = 0;
92441090Speter
92582749Sdillon    mtx_lock(&Giant);
92682749Sdillon
92743301Sdillon    if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0)
92841090Speter	goto out;
92941090Speter    if (lookup.version != sizeof(lookup) || SCARG(uap, cmd) != KLDSYM_LOOKUP) {
93041090Speter	error = EINVAL;
93141090Speter	goto out;
93241090Speter    }
93341090Speter
93441090Speter    symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
93543301Sdillon    if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
93641090Speter	goto out;
93741090Speter
93841090Speter    if (SCARG(uap, fileid) != 0) {
93941090Speter	lf = linker_find_file_by_id(SCARG(uap, fileid));
94041090Speter	if (lf == NULL) {
94141090Speter	    error = ENOENT;
94241090Speter	    goto out;
94341090Speter	}
94459603Sdfr	if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
94559603Sdfr	    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
94650272Sbde	    lookup.symvalue = (uintptr_t)symval.value;
94741090Speter	    lookup.symsize = symval.size;
94841090Speter	    error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
94941090Speter	} else
95041090Speter	    error = ENOENT;
95141090Speter    } else {
95271999Sphk	TAILQ_FOREACH(lf, &linker_files, link) {
95359603Sdfr	    if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
95459603Sdfr		LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
95550272Sbde		lookup.symvalue = (uintptr_t)symval.value;
95641090Speter		lookup.symsize = symval.size;
95741090Speter		error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
95841090Speter		break;
95941090Speter	    }
96041090Speter	}
96141090Speter	if (!lf)
96241090Speter	    error = ENOENT;
96341090Speter    }
96441090Speterout:
96541090Speter    if (symstr)
96641090Speter	free(symstr, M_TEMP);
96782749Sdillon    mtx_unlock(&Giant);
96882749Sdillon    return (error);
96941090Speter}
97041090Speter
97140159Speter/*
97240159Speter * Preloaded module support
97340159Speter */
97440159Speter
97559751Speterstatic modlist_t
97674642Sbpmodlist_lookup(const char *name, int ver)
97759751Speter{
97859751Speter    modlist_t mod;
97959751Speter
98071999Sphk    TAILQ_FOREACH(mod, &found_modules, link) {
98174642Sbp	if (strcmp(mod->name, name) == 0 && (ver == 0 || mod->version == ver))
98259751Speter	    return mod;
98359751Speter    }
98459751Speter    return NULL;
98559751Speter}
98659751Speter
98774642Sbpstatic modlist_t
98883321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo)
98983321Speter{
99083321Speter    modlist_t mod, bestmod;
99183321Speter    int ver;
99283321Speter
99383321Speter    if (verinfo == NULL)
99483321Speter	return modlist_lookup(name, 0);
99583321Speter    bestmod = NULL;
99683321Speter    for (mod = TAILQ_FIRST(&found_modules); mod; mod = TAILQ_NEXT(mod, link)) {
99783321Speter	if (strcmp(mod->name, name) != 0)
99883321Speter	    continue;
99983321Speter	ver = mod->version;
100083321Speter	if (ver == verinfo->md_ver_preferred)
100183321Speter	    return mod;
100283321Speter	if (ver >= verinfo->md_ver_minimum &&
100383321Speter	    ver <= verinfo->md_ver_maximum &&
100483321Speter	    ver > bestmod->version)
100583321Speter	    bestmod = mod;
100683321Speter    }
100783321Speter    return bestmod;
100883321Speter}
100983321Speter
101083321Speterstatic modlist_t
101178501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container)
101274642Sbp{
101374642Sbp    modlist_t mod;
101474642Sbp
101574642Sbp    mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT);
101674642Sbp    if (mod == NULL)
101774642Sbp	panic("no memory for module list");
101874642Sbp    bzero(mod, sizeof(*mod));
101974642Sbp    mod->container = container;
102074642Sbp    mod->name = modname;
102174642Sbp    mod->version = version;
102274642Sbp    TAILQ_INSERT_TAIL(&found_modules, mod, link);
102374642Sbp    return mod;
102474642Sbp}
102574642Sbp
102659751Speter/*
102759751Speter * This routine is cheap and nasty but will work for data pointers.
102859751Speter */
102959751Speterstatic void *
103078501Sdeslinker_reloc_ptr(linker_file_t lf, const void *offset)
103159751Speter{
103259751Speter	return lf->address + (uintptr_t)offset;
103359751Speter}
103459751Speter
103574642Sbp/*
103674642Sbp * Dereference MDT_VERSION metadata into module name and version
103774642Sbp */
103840159Speterstatic void
103974642Sbplinker_mdt_version(linker_file_t lf, struct mod_metadata *mp,
104078501Sdes	const char **modname, int *version)
104174642Sbp{
104274642Sbp    struct mod_version *mvp;
104374642Sbp
104474642Sbp    if (modname)
104574642Sbp	*modname = linker_reloc_ptr(lf, mp->md_cval);
104674642Sbp    if (version) {
104774642Sbp	mvp = linker_reloc_ptr(lf, mp->md_data);
104874642Sbp	*version = mvp->mv_version;
104974642Sbp    }
105074642Sbp}
105174642Sbp
105274642Sbp/*
105374642Sbp * Dereference MDT_DEPEND metadata into module name and mod_depend structure
105474642Sbp */
105574642Sbpstatic void
105674642Sbplinker_mdt_depend(linker_file_t lf, struct mod_metadata *mp,
105778501Sdes	const char **modname, struct mod_depend **verinfo)
105874642Sbp{
105974642Sbp
106074642Sbp    if (modname)
106174642Sbp	*modname = linker_reloc_ptr(lf, mp->md_cval);
106274642Sbp    if (verinfo)
106374642Sbp	*verinfo = linker_reloc_ptr(lf, mp->md_data);
106474642Sbp}
106574642Sbp
106674642Sbpstatic void
106778161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start,
106878161Speter	struct mod_metadata **stop, int preload)
106974642Sbp{
107078161Speter    struct mod_metadata	*mp, **mdp;
107178501Sdes    const char *modname;
107278161Speter    int ver;
107374642Sbp
107478161Speter    for (mdp = start; mdp < stop; mdp++) {
107574642Sbp	if (preload)
107678161Speter	    mp = *mdp;
107774642Sbp	else
107878161Speter	    mp = linker_reloc_ptr(lf, *mdp);
107974642Sbp	if (mp->md_type != MDT_VERSION)
108074642Sbp	    continue;
108174642Sbp	if (preload) {
108274642Sbp	    modname = mp->md_cval;
108374642Sbp	    ver = ((struct mod_version*)mp->md_data)->mv_version;
108474642Sbp	} else
108574642Sbp	    linker_mdt_version(lf, mp, &modname, &ver);
108674642Sbp	if (modlist_lookup(modname, ver) != NULL) {
108774642Sbp	    printf("module %s already present!\n", modname);
108874642Sbp	    /* XXX what can we do? this is a build error. :-( */
108974642Sbp	    continue;
109074642Sbp	}
109174642Sbp	modlist_newmodule(modname, ver, lf);
109274642Sbp    }
109374642Sbp}
109474642Sbp
109574642Sbpstatic void
109640159Speterlinker_preload(void* arg)
109740159Speter{
109840159Speter    caddr_t		modptr;
109978501Sdes    const char		*modname, *nmodname;
110040162Speter    char		*modtype;
110140159Speter    linker_file_t	lf;
110240159Speter    linker_class_t	lc;
110374639Sbp    int			error;
110459751Speter    linker_file_list_t	loaded_files;
110559751Speter    linker_file_list_t	depended_files;
110664143Speter    struct mod_metadata	*mp, *nmp;
110778161Speter    struct mod_metadata **start, **stop, **mdp, **nmdp;
110874642Sbp    struct mod_depend	*verinfo;
110978161Speter    int			nver;
111059751Speter    int			resolves;
111159751Speter    modlist_t		mod;
111278161Speter    struct sysinit	**si_start, **si_stop;
111340159Speter
111459751Speter    TAILQ_INIT(&loaded_files);
111559751Speter    TAILQ_INIT(&depended_files);
111659751Speter    TAILQ_INIT(&found_modules);
111759751Speter    error = 0;
111859751Speter
111940159Speter    modptr = NULL;
112040159Speter    while ((modptr = preload_search_next_name(modptr)) != NULL) {
112140159Speter	modname = (char *)preload_search_info(modptr, MODINFO_NAME);
112240162Speter	modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
112340159Speter	if (modname == NULL) {
112440625Smsmith	    printf("Preloaded module at %p does not have a name!\n", modptr);
112540159Speter	    continue;
112640159Speter	}
112740162Speter	if (modtype == NULL) {
112840625Smsmith	    printf("Preloaded module at %p does not have a type!\n", modptr);
112940162Speter	    continue;
113040162Speter	}
113140625Smsmith	printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, modptr);
113240159Speter	lf = NULL;
113371999Sphk	TAILQ_FOREACH(lc, &classes, link) {
113459751Speter	    error = LINKER_LINK_PRELOAD(lc, modname, &lf);
113540159Speter	    if (error) {
113640159Speter		lf = NULL;
113740159Speter		break;
113840159Speter	    }
113940159Speter	}
114059751Speter	if (lf)
114159751Speter	    TAILQ_INSERT_TAIL(&loaded_files, lf, loaded);
114259751Speter    }
114340159Speter
114459751Speter    /*
114559751Speter     * First get a list of stuff in the kernel.
114659751Speter     */
114778161Speter    if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, &stop,
114878161Speter			       NULL) == 0)
114978161Speter	linker_addmodules(linker_kernel_file, start, stop, 1);
115059751Speter
115159751Speter    /*
115259751Speter     * this is a once-off kinky bubble sort
115359751Speter     * resolve relocation dependency requirements
115459751Speter     */
115559751Speterrestart:
115671999Sphk    TAILQ_FOREACH(lf, &loaded_files, loaded) {
115778161Speter	error = linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL);
115859751Speter	/*
115959751Speter	 * First, look to see if we would successfully link with this stuff.
116059751Speter	 */
116159751Speter	resolves = 1;	/* unless we know otherwise */
116278161Speter	if (!error) {
116378161Speter	    for (mdp = start; mdp < stop; mdp++) {
116478161Speter		mp = linker_reloc_ptr(lf, *mdp);
116559751Speter		if (mp->md_type != MDT_DEPEND)
116659751Speter		    continue;
116774642Sbp		linker_mdt_depend(lf, mp, &modname, &verinfo);
116878161Speter		for (nmdp = start; nmdp < stop; nmdp++) {
116978161Speter		    nmp = linker_reloc_ptr(lf, *nmdp);
117064143Speter		    if (nmp->md_type != MDT_VERSION)
117164143Speter			continue;
117274642Sbp		    linker_mdt_version(lf, nmp, &nmodname, NULL);
117364143Speter		    nmodname = linker_reloc_ptr(lf, nmp->md_cval);
117464143Speter		    if (strcmp(modname, nmodname) == 0)
117564143Speter			break;
117664143Speter		}
117778161Speter		if (nmdp < stop)		/* it's a self reference */
117864143Speter		    continue;
117983321Speter		if (modlist_lookup2(modname, verinfo) == NULL) {
118059751Speter		    /* ok, the module isn't here yet, we are not finished */
118159751Speter		    resolves = 0;
118259751Speter		}
118359751Speter	    }
118459751Speter	}
118559751Speter	/*
118659751Speter	 * OK, if we found our modules, we can link.  So, "provide" the
118759751Speter	 * modules inside and add it to the end of the link order list.
118859751Speter	 */
118959751Speter	if (resolves) {
119078161Speter	    if (!error) {
119178161Speter		for (mdp = start; mdp < stop; mdp++) {
119278161Speter		    mp = linker_reloc_ptr(lf, *mdp);
119359751Speter		    if (mp->md_type != MDT_VERSION)
119459751Speter			continue;
119574642Sbp		    linker_mdt_version(lf, mp, &modname, &nver);
119674642Sbp		    if (modlist_lookup(modname, nver) != NULL) {
119759751Speter			printf("module %s already present!\n", modname);
119859751Speter			linker_file_unload(lf);
119959751Speter			TAILQ_REMOVE(&loaded_files, lf, loaded);
120059751Speter			goto restart;	/* we changed the tailq next ptr */
120140159Speter		    }
120274642Sbp		    modlist_newmodule(modname, nver, lf);
120340159Speter		}
120440159Speter	    }
120559751Speter	    TAILQ_REMOVE(&loaded_files, lf, loaded);
120659751Speter	    TAILQ_INSERT_TAIL(&depended_files, lf, loaded);
120759751Speter	    /*
120859751Speter	     * Since we provided modules, we need to restart the sort so
120959751Speter	     * that the previous files that depend on us have a chance.
121059751Speter	     * Also, we've busted the tailq next pointer with the REMOVE.
121159751Speter	     */
121259751Speter	    goto restart;
121340159Speter	}
121440159Speter    }
121559751Speter
121659751Speter    /*
121759751Speter     * At this point, we check to see what could not be resolved..
121859751Speter     */
121971999Sphk    TAILQ_FOREACH(lf, &loaded_files, loaded) {
122059751Speter	printf("KLD file %s is missing dependencies\n", lf->filename);
122159751Speter	linker_file_unload(lf);
122259751Speter	TAILQ_REMOVE(&loaded_files, lf, loaded);
122359751Speter    }
122459751Speter
122559751Speter    /*
122659751Speter     * We made it. Finish off the linking in the order we determined.
122759751Speter     */
122871999Sphk    TAILQ_FOREACH(lf, &depended_files, loaded) {
122959751Speter	if (linker_kernel_file) {
123059751Speter	    linker_kernel_file->refs++;
123159751Speter	    error = linker_file_add_dependancy(lf, linker_kernel_file);
123259751Speter	    if (error)
123359751Speter		panic("cannot add dependency");
123459751Speter	}
123559751Speter	lf->userrefs++;		/* so we can (try to) kldunload it */
123678161Speter	error = linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL);
123778161Speter	if (!error) {
123878161Speter	    for (mdp = start; mdp < stop; mdp++) {
123978161Speter		mp = linker_reloc_ptr(lf, *mdp);
124059751Speter		if (mp->md_type != MDT_DEPEND)
124159751Speter		    continue;
124274642Sbp		linker_mdt_depend(lf, mp, &modname, &verinfo);
124383321Speter		mod = modlist_lookup2(modname, verinfo);
124459751Speter		mod->container->refs++;
124559751Speter		error = linker_file_add_dependancy(lf, mod->container);
124659751Speter		if (error)
124759751Speter		    panic("cannot add dependency");
124859751Speter	    }
124959751Speter	}
125059751Speter
125178161Speter	/*
125278161Speter	 * Now do relocation etc using the symbol search paths established by
125378161Speter	 * the dependencies
125478161Speter	 */
125559751Speter	error = LINKER_LINK_PRELOAD_FINISH(lf);
125659751Speter	if (error) {
125759751Speter	    printf("KLD file %s - could not finalize loading\n", lf->filename);
125859751Speter	    linker_file_unload(lf);
125959751Speter	    continue;
126059751Speter	}
126159751Speter
126274639Sbp	linker_file_register_modules(lf);
126378161Speter	if (linker_file_lookup_set(lf, "sysinit_set", &si_start, &si_stop, NULL) == 0)
126478161Speter	    sysinit_add(si_start, si_stop);
126559751Speter	linker_file_register_sysctls(lf);
126659751Speter	lf->flags |= LINKER_FILE_LINKED;
126759751Speter    }
126859751Speter    /* woohoo! we made it! */
126940159Speter}
127040159Speter
127140159SpeterSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0);
127240159Speter
127340159Speter/*
127440159Speter * Search for a not-loaded module by name.
127540159Speter *
127640159Speter * Modules may be found in the following locations:
127740159Speter *
127840159Speter * - preloaded (result is just the module name)
127940159Speter * - on disk (result is full path to module)
128040159Speter *
128140159Speter * If the module name is qualified in any way (contains path, etc.)
128240159Speter * the we simply return a copy of it.
128340159Speter *
128440159Speter * The search path can be manipulated via sysctl.  Note that we use the ';'
128540159Speter * character as a separator to be consistent with the bootloader.
128640159Speter */
128740159Speter
128883321Speterstatic char linker_hintfile[] = "linker.hints";
128983358Speterstatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules;/modules";
129040159Speter
129140159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
129240159Speter	      sizeof(linker_path), "module load search path");
129340159Speter
129477843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path));
129570417Speter
129659751Speterstatic char *linker_ext_list[] = {
129783321Speter	"",
129859751Speter	".ko",
129959751Speter	NULL
130059751Speter};
130159751Speter
130283321Speter/*
130383321Speter * Check if file actually exists either with or without extension listed
130483321Speter * in the linker_ext_list.
130583321Speter * (probably should be generic for the rest of the kernel)
130683321Speter */
130759751Speterstatic char *
130883321Speterlinker_lookup_file(const char *path, int pathlen,
130983321Speter	const char *name, int namelen, struct vattr *vap)
131040159Speter{
131140159Speter    struct nameidata	nd;
131240159Speter    struct proc		*p = curproc;	/* XXX */
131383358Speter    char		*result, **cpp, *sep;
131483358Speter    int			error, len, extlen, reclen, flags;
131540159Speter    enum vtype		type;
131640159Speter
131783321Speter    extlen = 0;
131883321Speter    for (cpp = linker_ext_list; *cpp; cpp++) {
131983321Speter	len = strlen(*cpp);
132083321Speter	if (len > extlen)
132183321Speter	    extlen = len;
132283321Speter    }
132383321Speter    extlen++;	/* trailing '\0' */
132483358Speter    sep = (path[pathlen - 1] != '/') ? "/" : "";
132583321Speter
132683358Speter    reclen = pathlen + strlen(sep) + namelen + extlen + 1;
132783358Speter    result = malloc(reclen, M_LINKER, M_WAITOK);
132883321Speter    for (cpp = linker_ext_list; *cpp; cpp++) {
132983358Speter	snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep,
133083358Speter	    namelen, name, *cpp);
133183321Speter	/*
133283321Speter	 * Attempt to open the file, and return the path if we succeed
133383321Speter	 * and it's a regular file.
133483321Speter	 */
133583321Speter	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p);
133683321Speter	flags = FREAD;
133783321Speter	error = vn_open(&nd, &flags, 0);
133883321Speter	if (error == 0) {
133983321Speter	    NDFREE(&nd, NDF_ONLY_PNBUF);
134083321Speter	    type = nd.ni_vp->v_type;
134183321Speter	    if (vap)
134283321Speter		VOP_GETATTR(nd.ni_vp, vap, p->p_ucred, p);
134383321Speter	    VOP_UNLOCK(nd.ni_vp, 0, p);
134483321Speter	    vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
134583321Speter	    if (type == VREG)
134683321Speter	        return(result);
134783321Speter	}
134883321Speter    }
134983321Speter    free(result, M_LINKER);
135083321Speter    return(NULL);
135183321Speter}
135283321Speter
135383321Speter#define	INT_ALIGN(base, ptr)	ptr = \
135483321Speter	(base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
135583321Speter
135683321Speter/*
135783321Speter * Lookup KLD which contains requested module in the "linker.hints" file.
135883321Speter * If version specification is available, then try to find the best KLD.
135983321Speter * Otherwise just find the latest one.
136083321Speter */
136183321Speterstatic char *
136283321Speterlinker_hints_lookup(const char *path, int pathlen,
136383321Speter	const char *modname, int modnamelen,
136483321Speter	struct mod_depend *verinfo)
136583321Speter{
136683321Speter    struct proc *p = curproc;
136783321Speter    struct ucred *cred = p ? p->p_ucred : NULL;
136883321Speter    struct nameidata nd;
136983321Speter    struct vattr vattr, mattr;
137083321Speter    u_char *hints = NULL;
137183358Speter    u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep;
137283321Speter    int error, ival, bestver, *intp, reclen, found, flags, clen, blen;
137383321Speter
137483321Speter    result = NULL;
137583321Speter    bestver = found = 0;
137683321Speter
137783358Speter    sep = (path[pathlen - 1] != '/') ? "/" : "";
137883358Speter    reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen +
137983358Speter        strlen(sep) + 1;
138083321Speter    pathbuf = malloc(reclen, M_LINKER, M_WAITOK);
138183358Speter    snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, linker_hintfile);
138283321Speter
138383321Speter    NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, p);
138483321Speter    flags = FREAD;
138583321Speter    error = vn_open(&nd, &flags, 0);
138683321Speter    if (error)
138783321Speter	goto bad;
138883321Speter    NDFREE(&nd, NDF_ONLY_PNBUF);
138983321Speter    VOP_UNLOCK(nd.ni_vp, 0, p);
139083321Speter    if (nd.ni_vp->v_type != VREG)
139183321Speter	goto bad;
139283321Speter    best = cp = NULL;
139383321Speter    error = VOP_GETATTR(nd.ni_vp, &vattr, cred, p);
139483321Speter    if (error)
139583321Speter	goto bad;
139683321Speter    /*
139783321Speter     * XXX: we need to limit this number to some reasonable value
139883321Speter     */
139983321Speter    if (vattr.va_size > 100 * 1024) {
140083321Speter	printf("hints file too large %ld\n", (long)vattr.va_size);
140183321Speter	goto bad;
140283321Speter    }
140383321Speter    hints = malloc(vattr.va_size, M_TEMP, M_WAITOK);
140483321Speter    if (hints == NULL)
140583321Speter	goto bad;
140683321Speter    error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0,
140783321Speter		    UIO_SYSSPACE, IO_NODELOCKED, cred, &reclen, p);
140883321Speter    if (error)
140983321Speter	goto bad;
141083321Speter    vn_close(nd.ni_vp, FREAD, cred, p);
141183321Speter    nd.ni_vp = NULL;
141283321Speter    if (reclen != 0) {
141383321Speter	printf("can't read %d\n", reclen);
141483321Speter	goto bad;
141583321Speter    }
141683321Speter    intp = (int*)hints;
141783321Speter    ival = *intp++;
141883321Speter    if (ival != LINKER_HINTS_VERSION) {
141983321Speter	printf("hints file version mismatch %d\n", ival);
142083321Speter	goto bad;
142183321Speter    }
142283321Speter    bufend = hints + vattr.va_size;
142383321Speter    recptr = (u_char*)intp;
142483321Speter    clen = blen = 0;
142583321Speter    while (recptr < bufend && !found) {
142683321Speter	intp = (int*)recptr;
142783321Speter	reclen = *intp++;
142883321Speter	ival = *intp++;
142983321Speter	cp = (char*)intp;
143083321Speter	switch (ival) {
143183321Speter	case MDT_VERSION:
143283321Speter	    clen = *cp++;
143383321Speter	    if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
143483321Speter		break;
143583321Speter	    cp += clen;
143683321Speter	    INT_ALIGN(hints, cp);
143783321Speter	    ival = *(int*)cp;
143883321Speter	    cp += sizeof(int);
143983321Speter	    clen = *cp++;
144083321Speter	    if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
144183321Speter		found = 1;
144283321Speter		break;
144383321Speter	    }
144483321Speter	    if (ival >= verinfo->md_ver_minimum &&
144583321Speter		ival <= verinfo->md_ver_maximum &&
144683321Speter		ival > bestver) {
144783321Speter		bestver = ival;
144883321Speter		best = cp;
144983321Speter		blen = clen;
145083321Speter	    }
145183321Speter	    break;
145283321Speter	default:
145383321Speter	    break;
145483321Speter	}
145583321Speter	recptr += reclen + sizeof(int);
145683321Speter    }
145783321Speter    /*
145883321Speter     * Finally check if KLD is in the place
145983321Speter     */
146083321Speter    if (found)
146183321Speter	result = linker_lookup_file(path, pathlen, cp, clen, &mattr);
146283321Speter    else if (best)
146383321Speter	result = linker_lookup_file(path, pathlen, best, blen, &mattr);
146483321Speter    if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) {
146583321Speter	/*
146683321Speter	 * KLD is newer than hints file. What we should do now ?
146783321Speter	 */
146883358Speter	 printf("warning: KLD '%s' is newer than the linker.hints file\n",
146983358Speter	     result);
147083321Speter    }
147183321Speterbad:
147283321Speter    if (hints)
147383321Speter	free(hints, M_TEMP);
147483321Speter    if (nd.ni_vp != NULL)
147583321Speter	vn_close(nd.ni_vp, FREAD, cred, p);
147683321Speter    /*
147783321Speter     * If nothing found or hints is absent - fallback to the old way
147883321Speter     * by using "kldname[.ko]" as module name.
147983321Speter     */
148083321Speter    if (!found && !bestver && result == NULL)
148183321Speter	result = linker_lookup_file(path, pathlen, modname, modnamelen, NULL);
148283321Speter    return result;
148383321Speter}
148483321Speter
148583321Speter/*
148683321Speter * Lookup KLD which contains requested module in the all directories.
148783321Speter */
148883321Speterstatic char *
148983321Speterlinker_search_module(const char *modname, int modnamelen,
149083321Speter	struct mod_depend *verinfo)
149183321Speter{
149283321Speter    char *cp, *ep, *result;
149383321Speter
149483321Speter    /*
149583321Speter     * traverse the linker path
149683321Speter     */
149783321Speter    for (cp = linker_path; *cp; cp = ep + 1) {
149883321Speter
149983321Speter	/* find the end of this component */
150083321Speter	for (ep = cp; (*ep != 0) && (*ep != ';'); ep++)
150183321Speter	    ;
150283321Speter	result = linker_hints_lookup(cp, ep - cp, modname, modnamelen, verinfo);
150383321Speter	if (result != NULL)
150483321Speter	    return(result);
150583321Speter	if (*ep == 0)
150683321Speter	    break;
150783321Speter    }
150883321Speter    return (NULL);
150983321Speter}
151083321Speter
151183321Speter/*
151283321Speter * Search for module in all directories listed in the linker_path.
151383321Speter */
151483321Speterstatic char *
151583321Speterlinker_search_kld(const char *name)
151683321Speter{
151783321Speter    char		*cp, *ep, *result, **cpp;
151883321Speter    int			extlen, len;
151983321Speter
152040159Speter    /* qualified at all? */
152154411Speter    if (index(name, '/'))
152240159Speter	return(linker_strdup(name));
152340159Speter
152459751Speter    extlen = 0;
152559751Speter    for (cpp = linker_ext_list; *cpp; cpp++) {
152659751Speter	len = strlen(*cpp);
152759751Speter	if (len > extlen)
152859751Speter	    extlen = len;
152959751Speter    }
153059751Speter    extlen++;	/* trailing '\0' */
153159751Speter
153240159Speter    /* traverse the linker path */
153359751Speter    len = strlen(name);
153483321Speter    for (ep = linker_path; *ep; ep++) {
153583321Speter	cp = ep;
153640159Speter	/* find the end of this component */
153783321Speter	for (; *ep != 0 && *ep != ';'; ep++)
153840159Speter	    ;
153983321Speter	result = linker_lookup_file(cp, ep - cp, name, len, NULL);
154083321Speter	if (result != NULL)
154183321Speter	    return(result);
154240159Speter    }
154340159Speter    return(NULL);
154440159Speter}
154559751Speter
154659751Speterstatic const char *
154759751Speterlinker_basename(const char* path)
154859751Speter{
154959751Speter    const char *filename;
155059751Speter
155159751Speter    filename = rindex(path, '/');
155259751Speter    if (filename == NULL)
155359751Speter	return path;
155459751Speter    if (filename[1])
155559751Speter	filename++;
155659751Speter    return filename;
155759751Speter}
155859751Speter
155959751Speter/*
156059751Speter * Find a file which contains given module and load it,
156159751Speter * if "parent" is not NULL, register a reference to it.
156259751Speter */
156359751Speterstatic int
156483321Speterlinker_load_module(const char *kldname, const char *modname,
156583321Speter	struct linker_file *parent, struct mod_depend *verinfo,
156683321Speter	struct linker_file **lfpp)
156759751Speter{
156859751Speter    linker_file_t lfdep;
156959751Speter    const char *filename;
157059751Speter    char *pathname;
157159751Speter    int error;
157259751Speter
157383321Speter    if (modname == NULL) {
157483321Speter	/*
157583321Speter	 * We have to load KLD
157683321Speter	 */
157783321Speter	KASSERT(verinfo == NULL, ("linker_load_module: verinfo is not NULL"));
157883321Speter	pathname = linker_search_kld(kldname);
157983321Speter    } else {
158083321Speter	if (modlist_lookup2(modname, verinfo) != NULL)
158183321Speter	    return (EEXIST);
158283321Speter	if (kldname == NULL) {
158383321Speter	    /*
158483321Speter	     * Need to find a KLD with required module
158583321Speter	     */
158683321Speter	    pathname = linker_search_module(modname, strlen(modname), verinfo);
158783321Speter	} else
158883321Speter	    pathname = linker_strdup(kldname);
158983321Speter    }
159083321Speter    if (pathname == NULL)
159183321Speter	return (ENOENT);
159283321Speter
159359751Speter    /*
159483321Speter     * Can't load more than one file with the same basename
159583321Speter     * XXX: Actually it should be possible to have multiple KLDs
159683321Speter     * with the same basename but different path because they can provide
159783321Speter     * different versions of the same modules.
159859751Speter     */
159959751Speter    filename = linker_basename(pathname);
160059751Speter    if (linker_find_file_by_name(filename)) {
160159751Speter	error = EEXIST;
160259751Speter	goto out;
160359751Speter    }
160459751Speter
160559751Speter    do {
160659751Speter	error = linker_load_file(pathname, &lfdep);
160759751Speter	if (error)
160859751Speter	    break;
160983321Speter	if (modname && verinfo && modlist_lookup2(modname, verinfo) == NULL) {
161083321Speter	    linker_file_unload(lfdep);
161183321Speter	    error = ENOENT;
161283321Speter	    break;
161383321Speter	}
161459751Speter	if (parent) {
161559751Speter	    error = linker_file_add_dependancy(parent, lfdep);
161659751Speter	    if (error)
161759751Speter		break;
161859751Speter	}
161983321Speter	if (lfpp)
162083321Speter	    *lfpp = lfdep;
162159751Speter    } while(0);
162259751Speterout:
162359751Speter    if (pathname)
162459751Speter	free(pathname, M_LINKER);
162559751Speter    return error;
162659751Speter}
162759751Speter
162859751Speter/*
162959751Speter * This routine is responsible for finding dependencies of userland
163059751Speter * initiated kldload(2)'s of files.
163159751Speter */
163259751Speterint
163359751Speterlinker_load_dependancies(linker_file_t lf)
163459751Speter{
163559751Speter    linker_file_t lfdep;
163678161Speter    struct mod_metadata **start, **stop, **mdp, **nmdp;
163759751Speter    struct mod_metadata *mp, *nmp;
163883321Speter    struct mod_depend *verinfo;
163959751Speter    modlist_t mod;
164078501Sdes    const char *modname, *nmodname;
164178161Speter    int ver, error = 0, count;
164259751Speter
164359751Speter    /*
164459751Speter     * All files are dependant on /kernel.
164559751Speter     */
164659751Speter    if (linker_kernel_file) {
164759751Speter	linker_kernel_file->refs++;
164859751Speter	error = linker_file_add_dependancy(lf, linker_kernel_file);
164959751Speter	if (error)
165059751Speter	    return error;
165159751Speter    }
165259751Speter
165378161Speter    if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, &count) != 0)
165474641Sbp	return 0;
165578161Speter    for (mdp = start; mdp < stop; mdp++) {
165678161Speter	mp = linker_reloc_ptr(lf, *mdp);
165774641Sbp	if (mp->md_type != MDT_VERSION)
165874641Sbp	    continue;
165974642Sbp	linker_mdt_version(lf, mp, &modname, &ver);
166074642Sbp	mod = modlist_lookup(modname, ver);
166174642Sbp	if (mod != NULL) {
166274642Sbp	    printf("interface %s.%d already present in the KLD '%s'!\n",
166374642Sbp		modname, ver, mod->container->filename);
166474641Sbp	    return EEXIST;
166559751Speter	}
166659751Speter    }
166774642Sbp
166878161Speter    for (mdp = start; mdp < stop; mdp++) {
166978161Speter	mp = linker_reloc_ptr(lf, *mdp);
167074641Sbp	if (mp->md_type != MDT_DEPEND)
167174641Sbp	    continue;
167283321Speter	linker_mdt_depend(lf, mp, &modname, &verinfo);
167374641Sbp	nmodname = NULL;
167478161Speter	for (nmdp = start; nmdp < stop; nmdp++) {
167578161Speter	    nmp = linker_reloc_ptr(lf, *nmdp);
167674641Sbp	    if (nmp->md_type != MDT_VERSION)
167759751Speter		continue;
167874641Sbp	    nmodname = linker_reloc_ptr(lf, nmp->md_cval);
167974641Sbp	    if (strcmp(modname, nmodname) == 0)
168059751Speter		break;
168159751Speter	}
168278161Speter	if (nmdp < stop)	/* early exit, it's a self reference */
168374641Sbp	    continue;
168483321Speter	mod = modlist_lookup2(modname, verinfo);
168574641Sbp	if (mod) {		/* woohoo, it's loaded already */
168674641Sbp	    lfdep = mod->container;
168774641Sbp	    lfdep->refs++;
168874641Sbp	    error = linker_file_add_dependancy(lf, lfdep);
168974641Sbp	    if (error)
169074641Sbp		break;
169174641Sbp	    continue;
169274641Sbp	}
169383321Speter	error = linker_load_module(NULL, modname, lf, verinfo, NULL);
169474641Sbp	if (error) {
169574641Sbp	    printf("KLD %s: depends on %s - not available\n",
169674641Sbp		lf->filename, modname);
169774641Sbp	    break;
169874641Sbp	}
169974641Sbp    }
170059751Speter
170174641Sbp    if (error)
170274641Sbp	return error;
170378161Speter    linker_addmodules(lf, start, stop, 0);
170459751Speter    return error;
170559751Speter}
1706