kern_linker.c revision 32153
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 *
2632153Sbde *	$Id: kern_linker.c,v 1.5 1997/12/12 04:00:59 dyson Exp $
2725537Sdfr */
2825537Sdfr
2925537Sdfr#include <sys/param.h>
3025537Sdfr#include <sys/kernel.h>
3125537Sdfr#include <sys/systm.h>
3225537Sdfr#include <sys/malloc.h>
3325537Sdfr#include <sys/sysproto.h>
3425537Sdfr#include <sys/sysent.h>
3525537Sdfr#include <sys/proc.h>
3625537Sdfr#include <sys/lock.h>
3725537Sdfr#include <machine/cpu.h>
3825537Sdfr#include <sys/module.h>
3925537Sdfr#include <sys/linker.h>
4031675Sdyson#include <sys/unistd.h>
4125537Sdfr
4232153SbdeMALLOC_DEFINE(M_LINKER, "kld", "kernel linker");
4331324Sbdelinker_file_t linker_current_file;
4431324Sbde
4525537Sdfrstatic struct lock lock;	/* lock for the file list */
4625537Sdfrstatic linker_class_list_t classes;
4725537Sdfrstatic linker_file_list_t files;
4825537Sdfrstatic int next_file_id = 1;
4925537Sdfr
5025537Sdfrstatic void
5125537Sdfrlinker_init(void* arg)
5225537Sdfr{
5325537Sdfr    lockinit(&lock, PVM, "klink", 0, 0);
5425537Sdfr    TAILQ_INIT(&classes);
5525537Sdfr    TAILQ_INIT(&files);
5625537Sdfr}
5725537Sdfr
5825537SdfrSYSINIT(linker, SI_SUB_KMEM, SI_ORDER_SECOND, linker_init, 0);
5925537Sdfr
6025537Sdfrint
6125537Sdfrlinker_add_class(const char* desc, void* priv,
6225537Sdfr		 struct linker_class_ops* ops)
6325537Sdfr{
6425537Sdfr    linker_class_t lc;
6525537Sdfr
6625537Sdfr    lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT);
6725537Sdfr    if (!lc)
6825537Sdfr	return ENOMEM;
6925537Sdfr
7025537Sdfr    lc->desc = desc;
7125537Sdfr    lc->priv = priv;
7225537Sdfr    lc->ops = ops;
7325537Sdfr    TAILQ_INSERT_HEAD(&classes, lc, link);
7425537Sdfr
7525537Sdfr    return 0;
7625537Sdfr}
7725537Sdfr
7825537Sdfrstatic void
7925537Sdfrlinker_file_sysinit(linker_file_t lf)
8025537Sdfr{
8125537Sdfr    struct linker_set* sysinits;
8225537Sdfr    struct sysinit** sipp;
8325537Sdfr    struct sysinit** xipp;
8425537Sdfr    struct sysinit* save;
8525537Sdfr
8625537Sdfr    linker_current_file = lf;
8725537Sdfr
8825537Sdfr    KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
8925537Sdfr		   lf->filename));
9025537Sdfr
9125537Sdfr    sysinits = (struct linker_set*)
9225537Sdfr	linker_file_lookup_symbol(lf, "sysinit_set", 0);
9325537Sdfr    if (!sysinits)
9425537Sdfr	return;
9525537Sdfr
9625537Sdfr    /*
9725537Sdfr     * Perform a bubble sort of the system initialization objects by
9825537Sdfr     * their subsystem (primary key) and order (secondary key).
9925537Sdfr     *
10025537Sdfr     * Since some things care about execution order, this is the
10125537Sdfr     * operation which ensures continued function.
10225537Sdfr     */
10325537Sdfr    for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
10425537Sdfr	for( xipp = sipp + 1; *xipp; xipp++) {
10525537Sdfr	    if( (*sipp)->subsystem < (*xipp)->subsystem ||
10625537Sdfr		( (*sipp)->subsystem == (*xipp)->subsystem &&
10725537Sdfr		  (*sipp)->order < (*xipp)->order))
10825537Sdfr		continue;	/* skip*/
10925537Sdfr	    save = *sipp;
11025537Sdfr	    *sipp = *xipp;
11125537Sdfr	    *xipp = save;
11225537Sdfr	}
11325537Sdfr    }
11425537Sdfr
11525537Sdfr
11625537Sdfr    /*
11725537Sdfr     * Traverse the (now) ordered list of system initialization tasks.
11825537Sdfr     * Perform each task, and continue on to the next task.
11925537Sdfr     *
12025537Sdfr     * The last item on the list is expected to be the scheduler,
12125537Sdfr     * which will not return.
12225537Sdfr     */
12325537Sdfr    for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
12425537Sdfr	if( (*sipp)->subsystem == SI_SUB_DUMMY)
12525537Sdfr	    continue;	/* skip dummy task(s)*/
12625537Sdfr
12725537Sdfr	switch( (*sipp)->type) {
12825537Sdfr	case SI_TYPE_DEFAULT:
12925537Sdfr	    /* no special processing*/
13025537Sdfr	    (*((*sipp)->func))( (*sipp)->udata);
13125537Sdfr	    break;
13225537Sdfr
13325537Sdfr	case SI_TYPE_KTHREAD:
13431675Sdyson#if !defined(SMP)
13525537Sdfr	    /* kernel thread*/
13631675Sdyson	    if (fork1(&proc0, RFFDG|RFPROC|RFMEM))
13731675Sdyson		panic("fork kernel thread");
13831675Sdyson	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
13931675Sdyson		(*sipp)->func, (*sipp)->udata);
14031675Sdyson	    break;
14131675Sdyson#endif
14231675Sdyson
14331675Sdyson	case SI_TYPE_KPROCESS:
14431675Sdyson	    /* kernel thread*/
14531675Sdyson	    if (fork1(&proc0, RFFDG|RFPROC))
14625537Sdfr		panic("fork kernel process");
14730994Sphk	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
14830994Sphk		(*sipp)->func, (*sipp)->udata);
14925537Sdfr	    break;
15025537Sdfr
15125537Sdfr	default:
15225537Sdfr	    panic( "linker_file_sysinit: unrecognized init type");
15325537Sdfr	}
15425537Sdfr    }
15525537Sdfr}
15625537Sdfr
15725537Sdfrint
15825537Sdfrlinker_load_file(const char* filename, linker_file_t* result)
15925537Sdfr{
16025537Sdfr    linker_class_t lc;
16125537Sdfr    linker_file_t lf;
16225537Sdfr    int error = 0;
16325537Sdfr
16425537Sdfr    lf = linker_find_file_by_name(filename);
16525537Sdfr    if (lf) {
16625537Sdfr	KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
16725537Sdfr	*result = lf;
16825537Sdfr	lf->refs++;
16925537Sdfr	goto out;
17025537Sdfr    }
17125537Sdfr
17225537Sdfr    lf = NULL;
17325537Sdfr    for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
17425537Sdfr	KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
17525537Sdfr		       filename, lc->desc));
17625537Sdfr	if (error = lc->ops->load_file(filename, &lf))
17725537Sdfr	    goto out;
17825537Sdfr	if (lf) {
17925537Sdfr	    linker_file_sysinit(lf);
18025537Sdfr
18125537Sdfr	    *result = lf;
18225537Sdfr	    goto out;
18325537Sdfr	}
18425537Sdfr    }
18525537Sdfr
18625537Sdfr    error = ENOEXEC;		/* format not recognised */
18725537Sdfr
18825537Sdfrout:
18925537Sdfr    return error;
19025537Sdfr}
19125537Sdfr
19225537Sdfrlinker_file_t
19325537Sdfrlinker_find_file_by_name(const char* filename)
19425537Sdfr{
19525537Sdfr    linker_file_t lf = 0;
19625537Sdfr
19725537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
19825537Sdfr    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
19925537Sdfr	if (!strcmp(lf->filename, filename))
20025537Sdfr	    break;
20125537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
20225537Sdfr
20325537Sdfr    return lf;
20425537Sdfr}
20525537Sdfr
20625537Sdfrlinker_file_t
20725537Sdfrlinker_find_file_by_id(int fileid)
20825537Sdfr{
20925537Sdfr    linker_file_t lf = 0;
21025537Sdfr
21125537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
21225537Sdfr    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
21325537Sdfr	if (lf->id == fileid)
21425537Sdfr	    break;
21525537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
21625537Sdfr
21725537Sdfr    return lf;
21825537Sdfr}
21925537Sdfr
22025537Sdfrlinker_file_t
22125537Sdfrlinker_make_file(const char* filename, void* priv, struct linker_file_ops* ops)
22225537Sdfr{
22325537Sdfr    linker_file_t lf = 0;
22425537Sdfr    int namelen;
22525537Sdfr
22625537Sdfr    KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
22725537Sdfr    lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
22825537Sdfr    namelen = strlen(filename) + 1;
22925537Sdfr    lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK);
23025537Sdfr    if (!lf)
23125537Sdfr	goto out;
23225537Sdfr
23325537Sdfr    lf->refs = 1;
23425537Sdfr    lf->userrefs = 0;
23525537Sdfr    lf->filename = (char*) (lf + 1);
23625537Sdfr    strcpy(lf->filename, filename);
23725537Sdfr    lf->id = next_file_id++;
23825537Sdfr    lf->ndeps = 0;
23925537Sdfr    lf->deps = NULL;
24025537Sdfr    STAILQ_INIT(&lf->common);
24125537Sdfr    TAILQ_INIT(&lf->modules);
24225537Sdfr
24325537Sdfr    lf->priv = priv;
24425537Sdfr    lf->ops = ops;
24525537Sdfr    TAILQ_INSERT_TAIL(&files, lf, link);
24625537Sdfr
24725537Sdfrout:
24825537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
24925537Sdfr    return lf;
25025537Sdfr}
25125537Sdfr
25225537Sdfrint
25325537Sdfrlinker_file_unload(linker_file_t file)
25425537Sdfr{
25525537Sdfr    module_t mod, next;
25625537Sdfr    struct common_symbol* cp;
25725537Sdfr    int error = 0;
25825537Sdfr    int i;
25925537Sdfr
26025537Sdfr    KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", lf->refs));
26125537Sdfr    lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
26225537Sdfr    if (file->refs == 1) {
26325537Sdfr	KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
26425537Sdfr	/*
26525537Sdfr	 * Inform any modules associated with this file.
26625537Sdfr	 */
26725537Sdfr	for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
26825537Sdfr	    next = module_getfnext(mod);
26925537Sdfr
27025537Sdfr	    /*
27125537Sdfr	     * Give the module a chance to veto the unload.
27225537Sdfr	     */
27325537Sdfr	    if (error = module_unload(mod)) {
27425537Sdfr		KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
27525537Sdfr			       mod));
27625537Sdfr		lockmgr(&lock, LK_RELEASE, 0, curproc);
27725537Sdfr		goto out;
27825537Sdfr	    }
27925537Sdfr
28025537Sdfr	    module_release(mod);
28125537Sdfr	}
28225537Sdfr    }
28325537Sdfr
28425537Sdfr    file->refs--;
28525537Sdfr    if (file->refs > 0) {
28625537Sdfr	lockmgr(&lock, LK_RELEASE, 0, curproc);
28725537Sdfr	goto out;
28825537Sdfr    }
28925537Sdfr
29025537Sdfr    TAILQ_REMOVE(&files, file, link);
29125537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
29225537Sdfr
29325537Sdfr    for (i = 0; i < file->ndeps; i++)
29425537Sdfr	linker_file_unload(file->deps[i]);
29525537Sdfr    free(file->deps, M_LINKER);
29625537Sdfr
29725537Sdfr    for (cp = STAILQ_FIRST(&file->common); cp;
29825537Sdfr	 cp = STAILQ_FIRST(&file->common)) {
29925537Sdfr	STAILQ_REMOVE(&file->common, cp, common_symbol, link);
30025537Sdfr	free(cp, M_LINKER);
30125537Sdfr    }
30225537Sdfr
30325537Sdfr    file->ops->unload(file);
30425537Sdfr    free(file, M_LINKER);
30525537Sdfr
30625537Sdfrout:
30725537Sdfr    return error;
30825537Sdfr}
30925537Sdfr
31025537Sdfrint
31125537Sdfrlinker_file_add_dependancy(linker_file_t file, linker_file_t dep)
31225537Sdfr{
31325537Sdfr    linker_file_t* newdeps;
31425537Sdfr
31525537Sdfr    newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
31625537Sdfr		     M_LINKER, M_WAITOK);
31725537Sdfr    if (newdeps == NULL)
31825537Sdfr	return ENOMEM;
31925537Sdfr
32025537Sdfr    if (file->deps) {
32125537Sdfr	bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
32225537Sdfr	free(file->deps, M_LINKER);
32325537Sdfr    }
32425537Sdfr    file->deps = newdeps;
32525537Sdfr    file->deps[file->ndeps] = dep;
32625537Sdfr    file->ndeps++;
32725537Sdfr
32825537Sdfr    return 0;
32925537Sdfr}
33025537Sdfr
33125537Sdfrcaddr_t
33225537Sdfrlinker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
33325537Sdfr{
33425537Sdfr    caddr_t address;
33525537Sdfr    size_t size;
33625537Sdfr    size_t common_size = 0;
33725537Sdfr    int i;
33825537Sdfr
33925537Sdfr    KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d",
34025537Sdfr		  file, name, deps));
34125537Sdfr
34225537Sdfr    if (file->ops->lookup_symbol(file, name, &address, &size) == 0)
34325537Sdfr	if (address == 0)
34425537Sdfr	    /*
34525537Sdfr	     * For commons, first look them up in the dependancies and
34625537Sdfr	     * only allocate space if not found there.
34725537Sdfr	     */
34825537Sdfr	    common_size = size;
34925537Sdfr	else
35025537Sdfr	    return address;
35125537Sdfr
35225537Sdfr    if (deps)
35325537Sdfr	for (i = 0; i < file->ndeps; i++) {
35425537Sdfr	    address = linker_file_lookup_symbol(file->deps[i], name, 0);
35525537Sdfr	    if (address)
35625537Sdfr		return address;
35725537Sdfr	}
35825537Sdfr
35925537Sdfr    if (common_size > 0) {
36025537Sdfr	/*
36125537Sdfr	 * This is a common symbol which was not found in the
36225537Sdfr	 * dependancies.  We maintain a simple common symbol table in
36325537Sdfr	 * the file object.
36425537Sdfr	 */
36525537Sdfr	struct common_symbol* cp;
36625537Sdfr
36725537Sdfr	for (cp = STAILQ_FIRST(&file->common); cp;
36825537Sdfr	     cp = STAILQ_NEXT(cp, link))
36925537Sdfr	    if (!strcmp(cp->name, name))
37025537Sdfr		return cp->address;
37125537Sdfr
37225537Sdfr	/*
37325537Sdfr	 * Round the symbol size up to align.
37425537Sdfr	 */
37525537Sdfr	common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
37625537Sdfr	cp = malloc(sizeof(struct common_symbol)
37725537Sdfr		    + common_size
37825537Sdfr		    + strlen(name) + 1,
37925537Sdfr		    M_LINKER, M_WAITOK);
38025537Sdfr	if (!cp)
38125537Sdfr	    return 0;
38225537Sdfr
38325537Sdfr	cp->address = (caddr_t) (cp + 1);
38425537Sdfr	cp->name = cp->address + common_size;
38525537Sdfr	strcpy(cp->name, name);
38625537Sdfr	bzero(cp->address, common_size);
38725537Sdfr	STAILQ_INSERT_TAIL(&file->common, cp, link);
38825537Sdfr
38925537Sdfr	return cp->address;
39025537Sdfr    }
39125537Sdfr
39225537Sdfr    return 0;
39325537Sdfr}
39425537Sdfr
39525537Sdfr/*
39625537Sdfr * Syscalls.
39725537Sdfr */
39825537Sdfr
39925537Sdfrint
40030994Sphkkldload(struct proc* p, struct kldload_args* uap)
40125537Sdfr{
40225537Sdfr    char* filename = NULL;
40325537Sdfr    linker_file_t lf;
40425537Sdfr    int error = 0;
40525537Sdfr
40630994Sphk    p->p_retval[0] = -1;
40725537Sdfr
40825537Sdfr    if (securelevel > 0)
40925537Sdfr	return EPERM;
41025537Sdfr
41125537Sdfr    if (error = suser(p->p_ucred, &p->p_acflag))
41225537Sdfr	return error;
41325537Sdfr
41425537Sdfr    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
41525537Sdfr    if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
41625537Sdfr	goto out;
41725537Sdfr
41825537Sdfr    if (error = linker_load_file(uap->file, &lf))
41925537Sdfr	goto out;
42025537Sdfr
42125537Sdfr    lf->userrefs++;
42230994Sphk    p->p_retval[0] = lf->id;
42325537Sdfr
42425537Sdfrout:
42525537Sdfr    if (filename)
42625537Sdfr	free(filename, M_TEMP);
42725537Sdfr    return error;
42825537Sdfr}
42925537Sdfr
43025537Sdfrint
43130994Sphkkldunload(struct proc* p, struct kldunload_args* uap)
43225537Sdfr{
43325537Sdfr    linker_file_t lf;
43425537Sdfr    int error = 0;
43525537Sdfr
43625537Sdfr    if (securelevel > 0)
43725537Sdfr	return EPERM;
43825537Sdfr
43925537Sdfr    if (error = suser(p->p_ucred, &p->p_acflag))
44025537Sdfr	return error;
44125537Sdfr
44225537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
44325537Sdfr    if (lf) {
44425537Sdfr	KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
44525537Sdfr	if (lf->userrefs == 0) {
44625537Sdfr	    printf("linkerunload: attempt to unload file which was not loaded by user\n");
44725537Sdfr	    error = EBUSY;
44825537Sdfr	    goto out;
44925537Sdfr	}
45025537Sdfr	lf->userrefs--;
45125537Sdfr	error = linker_file_unload(lf);
45225537Sdfr    } else
45325537Sdfr	error = ENOENT;
45425537Sdfr
45525537Sdfrout:
45625537Sdfr    return error;
45725537Sdfr}
45825537Sdfr
45925537Sdfrint
46030994Sphkkldfind(struct proc* p, struct kldfind_args* uap)
46125537Sdfr{
46225537Sdfr    char* filename = NULL;
46325537Sdfr    linker_file_t lf;
46425537Sdfr    int error = 0;
46525537Sdfr
46630994Sphk    p->p_retval[0] = -1;
46725537Sdfr
46825537Sdfr    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
46925537Sdfr    if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
47025537Sdfr	goto out;
47125537Sdfr
47225537Sdfr    lf = linker_find_file_by_name(filename);
47325537Sdfr    if (lf)
47430994Sphk	p->p_retval[0] = lf->id;
47525537Sdfr    else
47625537Sdfr	error = ENOENT;
47725537Sdfr
47825537Sdfrout:
47925537Sdfr    if (filename)
48025537Sdfr	free(filename, M_TEMP);
48125537Sdfr    return error;
48225537Sdfr}
48325537Sdfr
48425537Sdfrint
48530994Sphkkldnext(struct proc* p, struct kldnext_args* uap)
48625537Sdfr{
48725537Sdfr    linker_file_t lf;
48825537Sdfr    int error = 0;
48925537Sdfr
49025537Sdfr    if (SCARG(uap, fileid) == 0) {
49125537Sdfr	if (TAILQ_FIRST(&files))
49230994Sphk	    p->p_retval[0] = TAILQ_FIRST(&files)->id;
49325537Sdfr	else
49430994Sphk	    p->p_retval[0] = 0;
49525537Sdfr	return 0;
49625537Sdfr    }
49725537Sdfr
49825537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
49925537Sdfr    if (lf) {
50025537Sdfr	if (TAILQ_NEXT(lf, link))
50130994Sphk	    p->p_retval[0] = TAILQ_NEXT(lf, link)->id;
50225537Sdfr	else
50330994Sphk	    p->p_retval[0] = 0;
50425537Sdfr    } else
50525537Sdfr	error = ENOENT;
50625537Sdfr
50725537Sdfr    return error;
50825537Sdfr}
50925537Sdfr
51025537Sdfrint
51130994Sphkkldstat(struct proc* p, struct kldstat_args* uap)
51225537Sdfr{
51325537Sdfr    linker_file_t lf;
51425537Sdfr    int error = 0;
51525537Sdfr    int version;
51625537Sdfr    struct kld_file_stat* stat;
51725537Sdfr    int namelen;
51825537Sdfr
51925537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
52025537Sdfr    if (!lf) {
52125537Sdfr	error = ENOENT;
52225537Sdfr	goto out;
52325537Sdfr    }
52425537Sdfr
52525537Sdfr    stat = SCARG(uap, stat);
52625537Sdfr
52725537Sdfr    /*
52825537Sdfr     * Check the version of the user's structure.
52925537Sdfr     */
53025537Sdfr    if (error = copyin(&stat->version, &version, sizeof(version)))
53125537Sdfr	goto out;
53225537Sdfr    if (version != sizeof(struct kld_file_stat)) {
53325537Sdfr	error = EINVAL;
53425537Sdfr	goto out;
53525537Sdfr    }
53625537Sdfr
53725537Sdfr    namelen = strlen(lf->filename) + 1;
53825537Sdfr    if (namelen > MAXPATHLEN)
53925537Sdfr	namelen = MAXPATHLEN;
54025537Sdfr    if (error = copyout(lf->filename, &stat->name[0], namelen))
54125537Sdfr	goto out;
54225537Sdfr    if (error = copyout(&lf->refs, &stat->refs, sizeof(int)))
54325537Sdfr	goto out;
54425537Sdfr    if (error = copyout(&lf->id, &stat->id, sizeof(int)))
54525537Sdfr	goto out;
54625537Sdfr    if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t)))
54725537Sdfr	goto out;
54825537Sdfr    if (error = copyout(&lf->size, &stat->size, sizeof(size_t)))
54925537Sdfr	goto out;
55025537Sdfr
55130994Sphk    p->p_retval[0] = 0;
55225537Sdfr
55325537Sdfrout:
55425537Sdfr    return error;
55525537Sdfr}
55625537Sdfr
55725537Sdfrint
55830994Sphkkldfirstmod(struct proc* p, struct kldfirstmod_args* uap)
55925537Sdfr{
56025537Sdfr    linker_file_t lf;
56125537Sdfr    int error = 0;
56225537Sdfr
56325537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
56425537Sdfr    if (lf) {
56525537Sdfr	if (TAILQ_FIRST(&lf->modules))
56630994Sphk	    p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules));
56725537Sdfr	else
56830994Sphk	    p->p_retval[0] = 0;
56925537Sdfr    } else
57025537Sdfr	error = ENOENT;
57125537Sdfr
57225537Sdfr    return error;
57325537Sdfr}
574