kern_linker.c revision 46112
125537Sdfr/*-
225537Sdfr * Copyright (c) 1997 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 *
2646112Sphk *	$Id: kern_linker.c,v 1.29 1999/04/06 03:02:11 peter Exp $
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>
3925537Sdfr#include <machine/cpu.h>
4040159Speter#include <machine/bootinfo.h>
4125537Sdfr#include <sys/module.h>
4225537Sdfr#include <sys/linker.h>
4331675Sdyson#include <sys/unistd.h>
4440159Speter#include <sys/fcntl.h>
4540159Speter#include <sys/libkern.h>
4640159Speter#include <sys/namei.h>
4740159Speter#include <sys/vnode.h>
4840159Speter#include <sys/sysctl.h>
4925537Sdfr
5040961Speter#ifdef KLD_DEBUG
5140961Speterint kld_debug = 0;
5240961Speter#endif
5340961Speter
5432153SbdeMALLOC_DEFINE(M_LINKER, "kld", "kernel linker");
5531324Sbdelinker_file_t linker_current_file;
5640906Speterlinker_file_t linker_kernel_file;
5731324Sbde
5825537Sdfrstatic struct lock lock;	/* lock for the file list */
5925537Sdfrstatic linker_class_list_t classes;
6025537Sdfrstatic linker_file_list_t files;
6125537Sdfrstatic int next_file_id = 1;
6225537Sdfr
6325537Sdfrstatic void
6425537Sdfrlinker_init(void* arg)
6525537Sdfr{
6625537Sdfr    lockinit(&lock, PVM, "klink", 0, 0);
6725537Sdfr    TAILQ_INIT(&classes);
6825537Sdfr    TAILQ_INIT(&files);
6925537Sdfr}
7025537Sdfr
7140159SpeterSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0);
7225537Sdfr
7325537Sdfrint
7425537Sdfrlinker_add_class(const char* desc, void* priv,
7525537Sdfr		 struct linker_class_ops* ops)
7625537Sdfr{
7725537Sdfr    linker_class_t lc;
7825537Sdfr
7925537Sdfr    lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT);
8025537Sdfr    if (!lc)
8125537Sdfr	return ENOMEM;
8240395Speter    bzero(lc, sizeof(*lc));
8325537Sdfr
8425537Sdfr    lc->desc = desc;
8525537Sdfr    lc->priv = priv;
8625537Sdfr    lc->ops = ops;
8725537Sdfr    TAILQ_INSERT_HEAD(&classes, lc, link);
8825537Sdfr
8925537Sdfr    return 0;
9025537Sdfr}
9125537Sdfr
9225537Sdfrstatic void
9325537Sdfrlinker_file_sysinit(linker_file_t lf)
9425537Sdfr{
9525537Sdfr    struct linker_set* sysinits;
9625537Sdfr    struct sysinit** sipp;
9725537Sdfr    struct sysinit** xipp;
9825537Sdfr    struct sysinit* save;
9940159Speter    moduledata_t *moddata;
10025537Sdfr
10125537Sdfr    KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
10225537Sdfr		   lf->filename));
10325537Sdfr
10425537Sdfr    sysinits = (struct linker_set*)
10525537Sdfr	linker_file_lookup_symbol(lf, "sysinit_set", 0);
10640159Speter
10740159Speter    KLD_DPF(FILE, ("linker_file_sysinit: SYSINITs %p\n", sysinits));
10825537Sdfr    if (!sysinits)
10925537Sdfr	return;
11025537Sdfr
11140159Speter    /* HACK ALERT! */
11240159Speter    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
11340159Speter	if ((*sipp)->func == module_register_init) {
11440159Speter	    moddata = (*sipp)->udata;
11540159Speter	    moddata->_file = lf;
11640159Speter	}
11740159Speter    }
11840159Speter
11925537Sdfr    /*
12025537Sdfr     * Perform a bubble sort of the system initialization objects by
12125537Sdfr     * their subsystem (primary key) and order (secondary key).
12225537Sdfr     *
12325537Sdfr     * Since some things care about execution order, this is the
12425537Sdfr     * operation which ensures continued function.
12525537Sdfr     */
12641055Speter    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
12741055Speter	for (xipp = sipp + 1; *xipp; xipp++) {
12841055Speter	    if ((*sipp)->subsystem <= (*xipp)->subsystem ||
12941055Speter		 ((*sipp)->subsystem == (*xipp)->subsystem &&
13041055Speter		  (*sipp)->order <= (*xipp)->order))
13125537Sdfr		continue;	/* skip*/
13225537Sdfr	    save = *sipp;
13325537Sdfr	    *sipp = *xipp;
13425537Sdfr	    *xipp = save;
13525537Sdfr	}
13625537Sdfr    }
13725537Sdfr
13825537Sdfr
13925537Sdfr    /*
14025537Sdfr     * Traverse the (now) ordered list of system initialization tasks.
14125537Sdfr     * Perform each task, and continue on to the next task.
14225537Sdfr     */
14341055Speter    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
14441055Speter	if ((*sipp)->subsystem == SI_SUB_DUMMY)
14525537Sdfr	    continue;	/* skip dummy task(s)*/
14625537Sdfr
14741055Speter	switch ((*sipp)->type) {
14825537Sdfr	case SI_TYPE_DEFAULT:
14925537Sdfr	    /* no special processing*/
15041055Speter	    (*((*sipp)->func))((*sipp)->udata);
15125537Sdfr	    break;
15225537Sdfr
15325537Sdfr	case SI_TYPE_KTHREAD:
15431675Sdyson#if !defined(SMP)
15525537Sdfr	    /* kernel thread*/
15631675Sdyson	    if (fork1(&proc0, RFFDG|RFPROC|RFMEM))
15731675Sdyson		panic("fork kernel thread");
15831675Sdyson	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
15931675Sdyson		(*sipp)->func, (*sipp)->udata);
16031675Sdyson	    break;
16131675Sdyson#endif
16231675Sdyson
16331675Sdyson	case SI_TYPE_KPROCESS:
16431675Sdyson	    /* kernel thread*/
16531675Sdyson	    if (fork1(&proc0, RFFDG|RFPROC))
16625537Sdfr		panic("fork kernel process");
16730994Sphk	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
16830994Sphk		(*sipp)->func, (*sipp)->udata);
16925537Sdfr	    break;
17025537Sdfr
17125537Sdfr	default:
17241055Speter	    panic ("linker_file_sysinit: unrecognized init type");
17325537Sdfr	}
17425537Sdfr    }
17525537Sdfr}
17625537Sdfr
17741055Speterstatic void
17841055Speterlinker_file_sysuninit(linker_file_t lf)
17941055Speter{
18041055Speter    struct linker_set* sysuninits;
18141055Speter    struct sysinit** sipp;
18241055Speter    struct sysinit** xipp;
18341055Speter    struct sysinit* save;
18441055Speter
18541055Speter    KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
18641055Speter		   lf->filename));
18741055Speter
18841055Speter    sysuninits = (struct linker_set*)
18941055Speter	linker_file_lookup_symbol(lf, "sysuninit_set", 0);
19041055Speter
19141055Speter    KLD_DPF(FILE, ("linker_file_sysuninit: SYSUNINITs %p\n", sysuninits));
19241055Speter    if (!sysuninits)
19341055Speter	return;
19441055Speter
19541055Speter    /*
19641055Speter     * Perform a reverse bubble sort of the system initialization objects
19741055Speter     * by their subsystem (primary key) and order (secondary key).
19841055Speter     *
19941055Speter     * Since some things care about execution order, this is the
20041055Speter     * operation which ensures continued function.
20141055Speter     */
20241055Speter    for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) {
20341055Speter	for (xipp = sipp + 1; *xipp; xipp++) {
20441055Speter	    if ((*sipp)->subsystem >= (*xipp)->subsystem ||
20541055Speter		 ((*sipp)->subsystem == (*xipp)->subsystem &&
20641055Speter		  (*sipp)->order >= (*xipp)->order))
20741055Speter		continue;	/* skip*/
20841055Speter	    save = *sipp;
20941055Speter	    *sipp = *xipp;
21041055Speter	    *xipp = save;
21141055Speter	}
21241055Speter    }
21341055Speter
21441055Speter
21541055Speter    /*
21641055Speter     * Traverse the (now) ordered list of system initialization tasks.
21741055Speter     * Perform each task, and continue on to the next task.
21841055Speter     */
21941055Speter    for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) {
22041055Speter	if ((*sipp)->subsystem == SI_SUB_DUMMY)
22141055Speter	    continue;	/* skip dummy task(s)*/
22241055Speter
22341055Speter	switch ((*sipp)->type) {
22441055Speter	case SI_TYPE_DEFAULT:
22541055Speter	    /* no special processing*/
22641055Speter	    (*((*sipp)->func))((*sipp)->udata);
22741055Speter	    break;
22841055Speter
22941055Speter	default:
23041055Speter	    panic("linker_file_sysuninit: unrecognized uninit type");
23141055Speter	}
23241055Speter    }
23341055Speter}
23441055Speter
23544078Sdfrstatic void
23644078Sdfrlinker_file_register_sysctls(linker_file_t lf)
23744078Sdfr{
23844078Sdfr    struct linker_set* sysctls;
23944078Sdfr
24044078Sdfr    KLD_DPF(FILE, ("linker_file_register_sysctls: registering SYSCTLs for %s\n",
24144078Sdfr		   lf->filename));
24244078Sdfr
24344078Sdfr    sysctls = (struct linker_set*)
24444078Sdfr	linker_file_lookup_symbol(lf, "sysctl_set", 0);
24544078Sdfr
24644078Sdfr    KLD_DPF(FILE, ("linker_file_register_sysctls: SYSCTLs %p\n", sysctls));
24744078Sdfr    if (!sysctls)
24844078Sdfr	return;
24944078Sdfr
25044078Sdfr    sysctl_register_set(sysctls);
25144078Sdfr}
25244078Sdfr
25344078Sdfrstatic void
25444078Sdfrlinker_file_unregister_sysctls(linker_file_t lf)
25544078Sdfr{
25644078Sdfr    struct linker_set* sysctls;
25744078Sdfr
25844078Sdfr    KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs for %s\n",
25944078Sdfr		   lf->filename));
26044078Sdfr
26144078Sdfr    sysctls = (struct linker_set*)
26244078Sdfr	linker_file_lookup_symbol(lf, "sysctl_set", 0);
26344078Sdfr
26444078Sdfr    KLD_DPF(FILE, ("linker_file_unregister_sysctls: SYSCTLs %p\n", sysctls));
26544078Sdfr    if (!sysctls)
26644078Sdfr	return;
26744078Sdfr
26844078Sdfr    sysctl_unregister_set(sysctls);
26944078Sdfr}
27044078Sdfr
27125537Sdfrint
27225537Sdfrlinker_load_file(const char* filename, linker_file_t* result)
27325537Sdfr{
27425537Sdfr    linker_class_t lc;
27525537Sdfr    linker_file_t lf;
27642755Speter    int foundfile, error = 0;
27740861Speter    char *koname = NULL;
27825537Sdfr
27925537Sdfr    lf = linker_find_file_by_name(filename);
28025537Sdfr    if (lf) {
28125537Sdfr	KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
28225537Sdfr	*result = lf;
28325537Sdfr	lf->refs++;
28425537Sdfr	goto out;
28525537Sdfr    }
28625537Sdfr
28740861Speter    koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
28840861Speter    if (koname == NULL) {
28940861Speter	error = ENOMEM;
29040861Speter	goto out;
29140861Speter    }
29240861Speter    sprintf(koname, "%s.ko", filename);
29325537Sdfr    lf = NULL;
29442755Speter    foundfile = 0;
29525537Sdfr    for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
29625537Sdfr	KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
29725537Sdfr		       filename, lc->desc));
29842755Speter
29942755Speter	error = lc->ops->load_file(koname, &lf);	/* First with .ko */
30042755Speter	if (lf == NULL && error == ENOENT)
30142755Speter	    error = lc->ops->load_file(filename, &lf);	/* Then try without */
30242755Speter	/*
30342755Speter	 * If we got something other than ENOENT, then it exists but we cannot
30442755Speter	 * load it for some other reason.
30542755Speter	 */
30642755Speter	if (error != ENOENT)
30742755Speter	    foundfile = 1;
30825537Sdfr	if (lf) {
30944549Sdfr	    linker_file_register_sysctls(lf);
31025537Sdfr	    linker_file_sysinit(lf);
31125537Sdfr
31225537Sdfr	    *result = lf;
31340861Speter	    error = 0;
31425537Sdfr	    goto out;
31525537Sdfr	}
31625537Sdfr    }
31742755Speter    /*
31842755Speter     * Less than ideal, but tells the user whether it failed to load or
31942755Speter     * the module was not found.
32042755Speter     */
32142755Speter    if (foundfile)
32242755Speter	error = ENOEXEC;	/* Format not recognised (or unloadable) */
32342755Speter    else
32442755Speter	error = ENOENT;		/* Nothing found */
32525537Sdfr
32625537Sdfrout:
32740861Speter    if (koname)
32840861Speter	free(koname, M_LINKER);
32925537Sdfr    return error;
33025537Sdfr}
33125537Sdfr
33225537Sdfrlinker_file_t
33325537Sdfrlinker_find_file_by_name(const char* filename)
33425537Sdfr{
33525537Sdfr    linker_file_t lf = 0;
33640861Speter    char *koname;
33725537Sdfr
33840861Speter    koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
33940861Speter    if (koname == NULL)
34040861Speter	goto out;
34140861Speter    sprintf(koname, "%s.ko", filename);
34240861Speter
34325537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
34440861Speter    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
34540861Speter	if (!strcmp(lf->filename, koname))
34640861Speter	    break;
34725537Sdfr	if (!strcmp(lf->filename, filename))
34825537Sdfr	    break;
34940861Speter    }
35025537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
35125537Sdfr
35240861Speterout:
35340861Speter    if (koname)
35440861Speter	free(koname, M_LINKER);
35525537Sdfr    return lf;
35625537Sdfr}
35725537Sdfr
35825537Sdfrlinker_file_t
35925537Sdfrlinker_find_file_by_id(int fileid)
36025537Sdfr{
36125537Sdfr    linker_file_t lf = 0;
36225537Sdfr
36325537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
36425537Sdfr    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
36525537Sdfr	if (lf->id == fileid)
36625537Sdfr	    break;
36725537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
36825537Sdfr
36925537Sdfr    return lf;
37025537Sdfr}
37125537Sdfr
37225537Sdfrlinker_file_t
37340159Speterlinker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops)
37425537Sdfr{
37525537Sdfr    linker_file_t lf = 0;
37625537Sdfr    int namelen;
37740159Speter    const char *filename;
37825537Sdfr
37940159Speter    filename = rindex(pathname, '/');
38040159Speter    if (filename && filename[1])
38140159Speter	filename++;
38240159Speter    else
38340159Speter	filename = pathname;
38440159Speter
38525537Sdfr    KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
38645356Speter    lockmgr(&lock, LK_EXCLUSIVE, 0, curproc);
38725537Sdfr    namelen = strlen(filename) + 1;
38825537Sdfr    lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK);
38925537Sdfr    if (!lf)
39025537Sdfr	goto out;
39140395Speter    bzero(lf, sizeof(*lf));
39225537Sdfr
39325537Sdfr    lf->refs = 1;
39425537Sdfr    lf->userrefs = 0;
39543185Sdfr    lf->flags = 0;
39625537Sdfr    lf->filename = (char*) (lf + 1);
39725537Sdfr    strcpy(lf->filename, filename);
39825537Sdfr    lf->id = next_file_id++;
39925537Sdfr    lf->ndeps = 0;
40025537Sdfr    lf->deps = NULL;
40125537Sdfr    STAILQ_INIT(&lf->common);
40225537Sdfr    TAILQ_INIT(&lf->modules);
40325537Sdfr
40425537Sdfr    lf->priv = priv;
40525537Sdfr    lf->ops = ops;
40625537Sdfr    TAILQ_INSERT_TAIL(&files, lf, link);
40725537Sdfr
40825537Sdfrout:
40925537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
41025537Sdfr    return lf;
41125537Sdfr}
41225537Sdfr
41325537Sdfrint
41425537Sdfrlinker_file_unload(linker_file_t file)
41525537Sdfr{
41625537Sdfr    module_t mod, next;
41725537Sdfr    struct common_symbol* cp;
41825537Sdfr    int error = 0;
41925537Sdfr    int i;
42025537Sdfr
42140159Speter    KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
42245356Speter    lockmgr(&lock, LK_EXCLUSIVE, 0, curproc);
42325537Sdfr    if (file->refs == 1) {
42425537Sdfr	KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
42525537Sdfr	/*
42625537Sdfr	 * Inform any modules associated with this file.
42725537Sdfr	 */
42825537Sdfr	for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
42925537Sdfr	    next = module_getfnext(mod);
43025537Sdfr
43125537Sdfr	    /*
43225537Sdfr	     * Give the module a chance to veto the unload.
43325537Sdfr	     */
43443301Sdillon	    if ((error = module_unload(mod)) != 0) {
43525537Sdfr		KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
43625537Sdfr			       mod));
43725537Sdfr		lockmgr(&lock, LK_RELEASE, 0, curproc);
43825537Sdfr		goto out;
43925537Sdfr	    }
44025537Sdfr
44125537Sdfr	    module_release(mod);
44225537Sdfr	}
44325537Sdfr    }
44425537Sdfr
44525537Sdfr    file->refs--;
44625537Sdfr    if (file->refs > 0) {
44725537Sdfr	lockmgr(&lock, LK_RELEASE, 0, curproc);
44825537Sdfr	goto out;
44925537Sdfr    }
45025537Sdfr
45143185Sdfr    /* Don't try to run SYSUNINITs if we are unloaded due to a link error */
45244078Sdfr    if (file->flags & LINKER_FILE_LINKED) {
45343185Sdfr	linker_file_sysuninit(file);
45444078Sdfr	linker_file_unregister_sysctls(file);
45544078Sdfr    }
45641055Speter
45725537Sdfr    TAILQ_REMOVE(&files, file, link);
45825537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
45940159Speter
46025537Sdfr    for (i = 0; i < file->ndeps; i++)
46125537Sdfr	linker_file_unload(file->deps[i]);
46225537Sdfr    free(file->deps, M_LINKER);
46325537Sdfr
46425537Sdfr    for (cp = STAILQ_FIRST(&file->common); cp;
46525537Sdfr	 cp = STAILQ_FIRST(&file->common)) {
46625537Sdfr	STAILQ_REMOVE(&file->common, cp, common_symbol, link);
46725537Sdfr	free(cp, M_LINKER);
46825537Sdfr    }
46925537Sdfr
47025537Sdfr    file->ops->unload(file);
47125537Sdfr    free(file, M_LINKER);
47225537Sdfr
47325537Sdfrout:
47425537Sdfr    return error;
47525537Sdfr}
47625537Sdfr
47725537Sdfrint
47825537Sdfrlinker_file_add_dependancy(linker_file_t file, linker_file_t dep)
47925537Sdfr{
48025537Sdfr    linker_file_t* newdeps;
48125537Sdfr
48225537Sdfr    newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
48325537Sdfr		     M_LINKER, M_WAITOK);
48425537Sdfr    if (newdeps == NULL)
48525537Sdfr	return ENOMEM;
48640395Speter    bzero(newdeps, (file->ndeps + 1) * sizeof(linker_file_t*));
48725537Sdfr
48825537Sdfr    if (file->deps) {
48925537Sdfr	bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
49025537Sdfr	free(file->deps, M_LINKER);
49125537Sdfr    }
49225537Sdfr    file->deps = newdeps;
49325537Sdfr    file->deps[file->ndeps] = dep;
49425537Sdfr    file->ndeps++;
49525537Sdfr
49625537Sdfr    return 0;
49725537Sdfr}
49825537Sdfr
49925537Sdfrcaddr_t
50025537Sdfrlinker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
50125537Sdfr{
50243309Sdillon    c_linker_sym_t sym;
50338275Sdfr    linker_symval_t symval;
50442849Speter    linker_file_t lf;
50525537Sdfr    caddr_t address;
50625537Sdfr    size_t common_size = 0;
50725537Sdfr    int i;
50825537Sdfr
50940159Speter    KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
51025537Sdfr		  file, name, deps));
51125537Sdfr
51238275Sdfr    if (file->ops->lookup_symbol(file, name, &sym) == 0) {
51338275Sdfr	file->ops->symbol_values(file, sym, &symval);
51438275Sdfr	if (symval.value == 0)
51525537Sdfr	    /*
51625537Sdfr	     * For commons, first look them up in the dependancies and
51725537Sdfr	     * only allocate space if not found there.
51825537Sdfr	     */
51938275Sdfr	    common_size = symval.size;
52040159Speter	else {
52140159Speter	    KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol.value=%x\n", symval.value));
52238275Sdfr	    return symval.value;
52340159Speter	}
52438275Sdfr    }
52525537Sdfr
52642849Speter    if (deps) {
52725537Sdfr	for (i = 0; i < file->ndeps; i++) {
52825537Sdfr	    address = linker_file_lookup_symbol(file->deps[i], name, 0);
52940159Speter	    if (address) {
53040159Speter		KLD_DPF(SYM, ("linker_file_lookup_symbol: deps value=%x\n", address));
53125537Sdfr		return address;
53240159Speter	    }
53325537Sdfr	}
53425537Sdfr
53542849Speter	/* If we have not found it in the dependencies, search globally */
53642849Speter	for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
53742849Speter	    /* But skip the current file if it's on the list */
53842849Speter	    if (lf == file)
53942849Speter		continue;
54042849Speter	    /* And skip the files we searched above */
54142849Speter	    for (i = 0; i < file->ndeps; i++)
54242849Speter		if (lf == file->deps[i])
54342849Speter		    break;
54442849Speter	    if (i < file->ndeps)
54542849Speter		continue;
54642849Speter	    address = linker_file_lookup_symbol(lf, name, 0);
54742849Speter	    if (address) {
54842849Speter		KLD_DPF(SYM, ("linker_file_lookup_symbol: global value=%x\n", address));
54942849Speter		return address;
55042849Speter	    }
55142849Speter	}
55242849Speter    }
55342849Speter
55425537Sdfr    if (common_size > 0) {
55525537Sdfr	/*
55625537Sdfr	 * This is a common symbol which was not found in the
55725537Sdfr	 * dependancies.  We maintain a simple common symbol table in
55825537Sdfr	 * the file object.
55925537Sdfr	 */
56025537Sdfr	struct common_symbol* cp;
56125537Sdfr
56225537Sdfr	for (cp = STAILQ_FIRST(&file->common); cp;
56325537Sdfr	     cp = STAILQ_NEXT(cp, link))
56440159Speter	    if (!strcmp(cp->name, name)) {
56540159Speter		KLD_DPF(SYM, ("linker_file_lookup_symbol: old common value=%x\n", cp->address));
56625537Sdfr		return cp->address;
56740159Speter	    }
56825537Sdfr
56925537Sdfr	/*
57025537Sdfr	 * Round the symbol size up to align.
57125537Sdfr	 */
57225537Sdfr	common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
57325537Sdfr	cp = malloc(sizeof(struct common_symbol)
57425537Sdfr		    + common_size
57525537Sdfr		    + strlen(name) + 1,
57625537Sdfr		    M_LINKER, M_WAITOK);
57740159Speter	if (!cp) {
57840159Speter	    KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
57925537Sdfr	    return 0;
58040159Speter	}
58140395Speter	bzero(cp, sizeof(struct common_symbol) + common_size + strlen(name)+ 1);
58225537Sdfr
58325537Sdfr	cp->address = (caddr_t) (cp + 1);
58425537Sdfr	cp->name = cp->address + common_size;
58525537Sdfr	strcpy(cp->name, name);
58625537Sdfr	bzero(cp->address, common_size);
58725537Sdfr	STAILQ_INSERT_TAIL(&file->common, cp, link);
58825537Sdfr
58940159Speter	KLD_DPF(SYM, ("linker_file_lookup_symbol: new common value=%x\n", cp->address));
59025537Sdfr	return cp->address;
59125537Sdfr    }
59225537Sdfr
59340159Speter    KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
59425537Sdfr    return 0;
59525537Sdfr}
59625537Sdfr
59740159Speter#ifdef DDB
59825537Sdfr/*
59940159Speter * DDB Helpers.  DDB has to look across multiple files with their own
60040159Speter * symbol tables and string tables.
60140159Speter *
60240159Speter * Note that we do not obey list locking protocols here.  We really don't
60340159Speter * need DDB to hang because somebody's got the lock held.  We'll take the
60440159Speter * chance that the files list is inconsistant instead.
60540159Speter */
60640159Speter
60740159Speterint
60843309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
60940159Speter{
61040159Speter    linker_file_t lf;
61140159Speter
61240159Speter    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
61340159Speter	if (lf->ops->lookup_symbol(lf, symstr, sym) == 0)
61440159Speter	    return 0;
61540159Speter    }
61640159Speter    return ENOENT;
61740159Speter}
61840159Speter
61940159Speterint
62043309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
62140159Speter{
62240159Speter    linker_file_t lf;
62340159Speter    u_long off = (u_long)value;
62440159Speter    u_long diff, bestdiff;
62543309Sdillon    c_linker_sym_t best;
62643309Sdillon    c_linker_sym_t es;
62740159Speter
62840159Speter    best = 0;
62940159Speter    bestdiff = off;
63040159Speter    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
63140159Speter	if (lf->ops->search_symbol(lf, value, &es, &diff) != 0)
63240159Speter	    continue;
63340159Speter	if (es != 0 && diff < bestdiff) {
63440159Speter	    best = es;
63540159Speter	    bestdiff = diff;
63640159Speter	}
63740159Speter	if (bestdiff == 0)
63840159Speter	    break;
63940159Speter    }
64040159Speter    if (best) {
64140159Speter	*sym = best;
64240159Speter	*diffp = bestdiff;
64340159Speter	return 0;
64440159Speter    } else {
64540159Speter	*sym = 0;
64640159Speter	*diffp = off;
64740159Speter	return ENOENT;
64840159Speter    }
64940159Speter}
65040159Speter
65140159Speterint
65243309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
65340159Speter{
65440159Speter    linker_file_t lf;
65540159Speter
65640159Speter    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
65740159Speter	if (lf->ops->symbol_values(lf, sym, symval) == 0)
65840159Speter	    return 0;
65940159Speter    }
66040159Speter    return ENOENT;
66140159Speter}
66240159Speter
66340159Speter#endif
66440159Speter
66540159Speter/*
66625537Sdfr * Syscalls.
66725537Sdfr */
66825537Sdfr
66925537Sdfrint
67030994Sphkkldload(struct proc* p, struct kldload_args* uap)
67125537Sdfr{
67242316Smsmith    char* filename = NULL, *modulename;
67325537Sdfr    linker_file_t lf;
67425537Sdfr    int error = 0;
67525537Sdfr
67630994Sphk    p->p_retval[0] = -1;
67725537Sdfr
67825537Sdfr    if (securelevel > 0)
67925537Sdfr	return EPERM;
68025537Sdfr
68146112Sphk    if ((error = suser(p)) != 0)
68225537Sdfr	return error;
68325537Sdfr
68425537Sdfr    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
68543301Sdillon    if ((error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) != 0)
68625537Sdfr	goto out;
68725537Sdfr
68842316Smsmith    /* Can't load more than one module with the same name */
68942316Smsmith    modulename = rindex(filename, '/');
69042316Smsmith    if (modulename == NULL)
69142316Smsmith	modulename = filename;
69244173Sdfr    else
69344173Sdfr	modulename++;
69442316Smsmith    if (linker_find_file_by_name(modulename)) {
69542316Smsmith	error = EEXIST;
69642316Smsmith	goto out;
69742316Smsmith    }
69842316Smsmith
69943301Sdillon    if ((error = linker_load_file(filename, &lf)) != 0)
70025537Sdfr	goto out;
70125537Sdfr
70225537Sdfr    lf->userrefs++;
70330994Sphk    p->p_retval[0] = lf->id;
70440159Speter
70525537Sdfrout:
70625537Sdfr    if (filename)
70725537Sdfr	free(filename, M_TEMP);
70825537Sdfr    return error;
70925537Sdfr}
71025537Sdfr
71125537Sdfrint
71230994Sphkkldunload(struct proc* p, struct kldunload_args* uap)
71325537Sdfr{
71425537Sdfr    linker_file_t lf;
71525537Sdfr    int error = 0;
71625537Sdfr
71725537Sdfr    if (securelevel > 0)
71825537Sdfr	return EPERM;
71925537Sdfr
72046112Sphk    if ((error = suser(p)) != 0)
72125537Sdfr	return error;
72225537Sdfr
72325537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
72425537Sdfr    if (lf) {
72525537Sdfr	KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
72625537Sdfr	if (lf->userrefs == 0) {
72743084Speter	    printf("linkerunload: attempt to unload file that was loaded by the kernel\n");
72825537Sdfr	    error = EBUSY;
72925537Sdfr	    goto out;
73025537Sdfr	}
73143084Speter	lf->userrefs--;
73242837Speter	error = linker_file_unload(lf);
73342837Speter	if (error)
73443084Speter	    lf->userrefs++;
73525537Sdfr    } else
73625537Sdfr	error = ENOENT;
73725537Sdfr
73825537Sdfrout:
73925537Sdfr    return error;
74025537Sdfr}
74125537Sdfr
74225537Sdfrint
74330994Sphkkldfind(struct proc* p, struct kldfind_args* uap)
74425537Sdfr{
74542316Smsmith    char* filename = NULL, *modulename;
74625537Sdfr    linker_file_t lf;
74725537Sdfr    int error = 0;
74825537Sdfr
74930994Sphk    p->p_retval[0] = -1;
75025537Sdfr
75125537Sdfr    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
75243301Sdillon    if ((error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) != 0)
75325537Sdfr	goto out;
75425537Sdfr
75542316Smsmith    modulename = rindex(filename, '/');
75642316Smsmith    if (modulename == NULL)
75742316Smsmith	modulename = filename;
75842316Smsmith
75942316Smsmith    lf = linker_find_file_by_name(modulename);
76025537Sdfr    if (lf)
76130994Sphk	p->p_retval[0] = lf->id;
76225537Sdfr    else
76325537Sdfr	error = ENOENT;
76440159Speter
76525537Sdfrout:
76625537Sdfr    if (filename)
76725537Sdfr	free(filename, M_TEMP);
76825537Sdfr    return error;
76925537Sdfr}
77025537Sdfr
77125537Sdfrint
77230994Sphkkldnext(struct proc* p, struct kldnext_args* uap)
77325537Sdfr{
77425537Sdfr    linker_file_t lf;
77525537Sdfr    int error = 0;
77625537Sdfr
77725537Sdfr    if (SCARG(uap, fileid) == 0) {
77825537Sdfr	if (TAILQ_FIRST(&files))
77930994Sphk	    p->p_retval[0] = TAILQ_FIRST(&files)->id;
78025537Sdfr	else
78130994Sphk	    p->p_retval[0] = 0;
78225537Sdfr	return 0;
78325537Sdfr    }
78440159Speter
78525537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
78625537Sdfr    if (lf) {
78725537Sdfr	if (TAILQ_NEXT(lf, link))
78830994Sphk	    p->p_retval[0] = TAILQ_NEXT(lf, link)->id;
78925537Sdfr	else
79030994Sphk	    p->p_retval[0] = 0;
79125537Sdfr    } else
79225537Sdfr	error = ENOENT;
79325537Sdfr
79425537Sdfr    return error;
79525537Sdfr}
79625537Sdfr
79725537Sdfrint
79830994Sphkkldstat(struct proc* p, struct kldstat_args* uap)
79925537Sdfr{
80025537Sdfr    linker_file_t lf;
80125537Sdfr    int error = 0;
80225537Sdfr    int version;
80325537Sdfr    struct kld_file_stat* stat;
80425537Sdfr    int namelen;
80525537Sdfr
80625537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
80725537Sdfr    if (!lf) {
80825537Sdfr	error = ENOENT;
80925537Sdfr	goto out;
81025537Sdfr    }
81125537Sdfr
81225537Sdfr    stat = SCARG(uap, stat);
81325537Sdfr
81425537Sdfr    /*
81525537Sdfr     * Check the version of the user's structure.
81625537Sdfr     */
81743301Sdillon    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
81825537Sdfr	goto out;
81925537Sdfr    if (version != sizeof(struct kld_file_stat)) {
82025537Sdfr	error = EINVAL;
82125537Sdfr	goto out;
82225537Sdfr    }
82325537Sdfr
82425537Sdfr    namelen = strlen(lf->filename) + 1;
82525537Sdfr    if (namelen > MAXPATHLEN)
82625537Sdfr	namelen = MAXPATHLEN;
82743301Sdillon    if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
82825537Sdfr	goto out;
82943301Sdillon    if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
83025537Sdfr	goto out;
83143301Sdillon    if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
83225537Sdfr	goto out;
83343301Sdillon    if ((error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) != 0)
83425537Sdfr	goto out;
83543301Sdillon    if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
83625537Sdfr	goto out;
83725537Sdfr
83830994Sphk    p->p_retval[0] = 0;
83925537Sdfr
84025537Sdfrout:
84125537Sdfr    return error;
84225537Sdfr}
84325537Sdfr
84425537Sdfrint
84530994Sphkkldfirstmod(struct proc* p, struct kldfirstmod_args* uap)
84625537Sdfr{
84725537Sdfr    linker_file_t lf;
84825537Sdfr    int error = 0;
84925537Sdfr
85025537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
85125537Sdfr    if (lf) {
85225537Sdfr	if (TAILQ_FIRST(&lf->modules))
85330994Sphk	    p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules));
85425537Sdfr	else
85530994Sphk	    p->p_retval[0] = 0;
85625537Sdfr    } else
85725537Sdfr	error = ENOENT;
85825537Sdfr
85925537Sdfr    return error;
86025537Sdfr}
86140159Speter
86241090Speterint
86341090Speterkldsym(struct proc *p, struct kldsym_args *uap)
86441090Speter{
86541090Speter    char *symstr = NULL;
86643309Sdillon    c_linker_sym_t sym;
86741090Speter    linker_symval_t symval;
86841090Speter    linker_file_t lf;
86941090Speter    struct kld_sym_lookup lookup;
87041090Speter    int error = 0;
87141090Speter
87243301Sdillon    if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0)
87341090Speter	goto out;
87441090Speter    if (lookup.version != sizeof(lookup) || SCARG(uap, cmd) != KLDSYM_LOOKUP) {
87541090Speter	error = EINVAL;
87641090Speter	goto out;
87741090Speter    }
87841090Speter
87941090Speter    symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
88043301Sdillon    if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
88141090Speter	goto out;
88241090Speter
88341090Speter    if (SCARG(uap, fileid) != 0) {
88441090Speter	lf = linker_find_file_by_id(SCARG(uap, fileid));
88541090Speter	if (lf == NULL) {
88641090Speter	    error = ENOENT;
88741090Speter	    goto out;
88841090Speter	}
88941090Speter	if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 &&
89041090Speter	    lf->ops->symbol_values(lf, sym, &symval) == 0) {
89141090Speter	    lookup.symvalue = (u_long)symval.value;
89241090Speter	    lookup.symsize = symval.size;
89341090Speter	    error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
89441090Speter	} else
89541090Speter	    error = ENOENT;
89641090Speter    } else {
89741090Speter	for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
89841090Speter	    if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 &&
89941090Speter		lf->ops->symbol_values(lf, sym, &symval) == 0) {
90041090Speter		lookup.symvalue = (u_long)symval.value;
90141090Speter		lookup.symsize = symval.size;
90241090Speter		error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
90341090Speter		break;
90441090Speter	    }
90541090Speter	}
90641090Speter	if (!lf)
90741090Speter	    error = ENOENT;
90841090Speter    }
90941090Speterout:
91041090Speter    if (symstr)
91141090Speter	free(symstr, M_TEMP);
91241090Speter    return error;
91341090Speter}
91441090Speter
91540159Speter/*
91640159Speter * Preloaded module support
91740159Speter */
91840159Speter
91940159Speterstatic void
92040159Speterlinker_preload(void* arg)
92140159Speter{
92240159Speter    caddr_t		modptr;
92340159Speter    char		*modname;
92440162Speter    char		*modtype;
92540159Speter    linker_file_t	lf;
92640159Speter    linker_class_t	lc;
92740159Speter    int			error;
92840159Speter    struct linker_set	*sysinits;
92940159Speter    struct sysinit	**sipp;
93040159Speter    moduledata_t	*moddata;
93140159Speter
93240159Speter    modptr = NULL;
93340159Speter    while ((modptr = preload_search_next_name(modptr)) != NULL) {
93440159Speter	modname = (char *)preload_search_info(modptr, MODINFO_NAME);
93540162Speter	modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
93640159Speter	if (modname == NULL) {
93740625Smsmith	    printf("Preloaded module at %p does not have a name!\n", modptr);
93840159Speter	    continue;
93940159Speter	}
94040162Speter	if (modtype == NULL) {
94140625Smsmith	    printf("Preloaded module at %p does not have a type!\n", modptr);
94240162Speter	    continue;
94340162Speter	}
94440625Smsmith	printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, modptr);
94540159Speter	lf = linker_find_file_by_name(modname);
94640159Speter	if (lf) {
94740159Speter	    lf->userrefs++;
94840159Speter	    continue;
94940159Speter	}
95040159Speter	lf = NULL;
95140159Speter	for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
95240159Speter	    error = lc->ops->load_file(modname, &lf);
95340159Speter	    if (error) {
95440159Speter		lf = NULL;
95540159Speter		break;
95640159Speter	    }
95740159Speter	}
95840159Speter	if (lf) {
95940159Speter	    lf->userrefs++;
96040159Speter
96140159Speter	    sysinits = (struct linker_set*)
96240159Speter		linker_file_lookup_symbol(lf, "sysinit_set", 0);
96340159Speter	    if (sysinits) {
96440159Speter		/* HACK ALERT!
96540159Speter		 * This is to set the sysinit moduledata so that the module
96640159Speter		 * can attach itself to the correct containing file.
96740159Speter		 * The sysinit could be run at *any* time.
96840159Speter		 */
96940159Speter		for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
97040159Speter		    if ((*sipp)->func == module_register_init) {
97140159Speter			moddata = (*sipp)->udata;
97240159Speter			moddata->_file = lf;
97340159Speter		    }
97440159Speter		}
97540159Speter		sysinit_add((struct sysinit **)sysinits->ls_items);
97640159Speter	    }
97744078Sdfr	    linker_file_register_sysctls(lf);
97840159Speter	}
97940159Speter    }
98040159Speter}
98140159Speter
98240159SpeterSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0);
98340159Speter
98440159Speter/*
98540159Speter * Search for a not-loaded module by name.
98640159Speter *
98740159Speter * Modules may be found in the following locations:
98840159Speter *
98940159Speter * - preloaded (result is just the module name)
99040159Speter * - on disk (result is full path to module)
99140159Speter *
99240159Speter * If the module name is qualified in any way (contains path, etc.)
99340159Speter * the we simply return a copy of it.
99440159Speter *
99540159Speter * The search path can be manipulated via sysctl.  Note that we use the ';'
99640159Speter * character as a separator to be consistent with the bootloader.
99740159Speter */
99840159Speter
99940159Speterstatic char linker_path[MAXPATHLEN + 1] = "/;/boot/;/modules/";
100040159Speter
100140159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
100240159Speter	      sizeof(linker_path), "module load search path");
100340159Speter
100440159Speterstatic char *
100540159Speterlinker_strdup(const char *str)
100640159Speter{
100740159Speter    char	*result;
100840159Speter
100940159Speter    if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
101040159Speter	strcpy(result, str);
101140159Speter    return(result);
101240159Speter}
101340159Speter
101440159Speterchar *
101540159Speterlinker_search_path(const char *name)
101640159Speter{
101740159Speter    struct nameidata	nd;
101840159Speter    struct proc		*p = curproc;	/* XXX */
101940159Speter    char		*cp, *ep, *result;
102040159Speter    int			error;
102140159Speter    enum vtype		type;
102240159Speter
102340159Speter    /* qualified at all? */
102440159Speter    if (index(name, '/'))
102540159Speter	return(linker_strdup(name));
102640159Speter
102740159Speter    /* traverse the linker path */
102840159Speter    cp = linker_path;
102940159Speter    for (;;) {
103040159Speter
103140159Speter	/* find the end of this component */
103240159Speter	for (ep = cp; (*ep != 0) && (*ep != ';'); ep++)
103340159Speter	    ;
103440159Speter	result = malloc((strlen(name) + (ep - cp) + 1), M_LINKER, M_WAITOK);
103540159Speter	if (result == NULL)	/* actually ENOMEM */
103640159Speter	    return(NULL);
103740159Speter
103840159Speter	strncpy(result, cp, ep - cp);
103940159Speter	strcpy(result + (ep - cp), name);
104040159Speter
104140159Speter	/*
104240159Speter	 * Attempt to open the file, and return the path if we succeed and it's
104340159Speter	 * a regular file.
104440159Speter	 */
104540159Speter	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p);
104640159Speter	error = vn_open(&nd, FREAD, 0);
104740159Speter	if (error == 0) {
104840159Speter	    type = nd.ni_vp->v_type;
104940159Speter	    VOP_UNLOCK(nd.ni_vp, 0, p);
105040159Speter	    vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
105140159Speter	    if (type == VREG)
105240159Speter		return(result);
105340159Speter	}
105440159Speter	free(result, M_LINKER);
105540159Speter
105640159Speter	if (*ep == 0)
105740159Speter	    break;
105840159Speter	cp = ep + 1;
105940159Speter    }
106040159Speter    return(NULL);
106140159Speter}
1062