module.c revision 65613
138465Smsmith/*-
238465Smsmith * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
338465Smsmith * All rights reserved.
438465Smsmith *
538465Smsmith * Redistribution and use in source and binary forms, with or without
638465Smsmith * modification, are permitted provided that the following conditions
738465Smsmith * are met:
838465Smsmith * 1. Redistributions of source code must retain the above copyright
938465Smsmith *    notice, this list of conditions and the following disclaimer.
1038465Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1138465Smsmith *    notice, this list of conditions and the following disclaimer in the
1238465Smsmith *    documentation and/or other materials provided with the distribution.
1338465Smsmith *
1438465Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538465Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638465Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738465Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838465Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938465Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038465Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138465Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238465Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338465Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438465Smsmith * SUCH DAMAGE.
2538465Smsmith *
2650477Speter * $FreeBSD: head/sys/boot/common/module.c 65613 2000-09-08 16:47:05Z dcs $
2738465Smsmith */
2838465Smsmith
2938465Smsmith/*
3059854Sbp * file/module function dispatcher, support, etc.
3138465Smsmith */
3238465Smsmith
3338465Smsmith#include <stand.h>
3438465Smsmith#include <string.h>
3540141Speter#include <sys/param.h>
3640141Speter#include <sys/linker.h>
3738465Smsmith
3838465Smsmith#include "bootstrap.h"
3938465Smsmith
4059854Sbpstatic int			file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
4159854Sbpstatic int			file_loadraw(char *type, char *name);
4259854Sbpstatic int			file_load_dependancies(struct preloaded_file *base_mod);
4359854Sbpstatic char *			file_search(char *name);
4459854Sbpstruct kernel_module *		file_findmodule(struct preloaded_file *fp, char *modname);
4538764Smsmithstatic char			*mod_searchmodule(char *name);
4659854Sbpstatic void			file_insert_tail(struct preloaded_file *mp);
4759854Sbpstruct file_metadata*		metadata_next(struct file_metadata *base_mp, int type);
4838764Smsmith
4939178Smsmith/* load address should be tweaked by first module loaded (kernel) */
5038465Smsmithstatic vm_offset_t	loadaddr = 0;
5138465Smsmith
5265501Sobrienstatic const char	*default_searchpath ="/boot/modules;/modules;/boot/kernel";
5339178Smsmith
5459854Sbpstruct preloaded_file *preloaded_files = NULL;
5538465Smsmith
5638764Smsmith/*
5738764Smsmith * load an object, either a disk file or code module.
5838764Smsmith *
5938764Smsmith * To load a file, the syntax is:
6038764Smsmith *
6138764Smsmith * load -t <type> <path>
6238764Smsmith *
6338764Smsmith * code modules are loaded as:
6438764Smsmith *
6538764Smsmith * load <path> <options>
6638764Smsmith */
6738764Smsmith
6838465SmsmithCOMMAND_SET(load, "load", "load a kernel or module", command_load);
6938465Smsmith
7038465Smsmithstatic int
7138465Smsmithcommand_load(int argc, char *argv[])
7238465Smsmith{
7338764Smsmith    char	*typestr;
7457468Sbp    int		dofile, ch, error;
7538764Smsmith
7638764Smsmith    dofile = 0;
7738764Smsmith    optind = 1;
7842512Smsmith    optreset = 1;
7938764Smsmith    typestr = NULL;
8053993Sdcs    if (argc == 1) {
8153993Sdcs	command_errmsg = "no filename specified";
8253993Sdcs	return(CMD_ERROR);
8353993Sdcs    }
8438764Smsmith    while ((ch = getopt(argc, argv, "t:")) != -1) {
8538764Smsmith	switch(ch) {
8638764Smsmith	case 't':
8738764Smsmith	    typestr = optarg;
8838764Smsmith	    dofile = 1;
8938764Smsmith	    break;
9038764Smsmith	case '?':
9138764Smsmith	default:
9238764Smsmith	    /* getopt has already reported an error */
9338764Smsmith	    return(CMD_OK);
9438764Smsmith	}
9538764Smsmith    }
9638764Smsmith    argv += (optind - 1);
9738764Smsmith    argc -= (optind - 1);
9838764Smsmith
9938764Smsmith    /*
10038764Smsmith     * Request to load a raw file?
10138764Smsmith     */
10238764Smsmith    if (dofile) {
10338764Smsmith	if ((typestr == NULL) || (*typestr == 0)) {
10438764Smsmith	    command_errmsg = "invalid load type";
10538764Smsmith	    return(CMD_ERROR);
10638764Smsmith	}
10759854Sbp	return(file_loadraw(typestr, argv[1]));
10838764Smsmith    }
10938764Smsmith
11038764Smsmith    /*
11138764Smsmith     * Looks like a request for a module.
11238764Smsmith     */
11357468Sbp    error = mod_load(argv[1], argc - 2, argv + 2);
11457468Sbp    if (error == EEXIST)
11557468Sbp	sprintf(command_errbuf, "warning: module '%s' already loaded", argv[1]);
11657468Sbp    return (error == 0 ? CMD_OK : CMD_ERROR);
11738465Smsmith}
11838465Smsmith
11938712SmsmithCOMMAND_SET(unload, "unload", "unload all modules", command_unload);
12038712Smsmith
12138712Smsmithstatic int
12238712Smsmithcommand_unload(int argc, char *argv[])
12338712Smsmith{
12459854Sbp    struct preloaded_file	*fp;
12538712Smsmith
12659854Sbp    while (preloaded_files != NULL) {
12759854Sbp	fp = preloaded_files;
12859854Sbp	preloaded_files = preloaded_files->f_next;
12959854Sbp	file_discard(fp);
13038712Smsmith    }
13138712Smsmith    loadaddr = 0;
13265613Sdcs    unsetenv("kernelname");
13338712Smsmith    return(CMD_OK);
13438712Smsmith}
13538712Smsmith
13638465SmsmithCOMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
13738465Smsmith
13838465Smsmithstatic int
13938465Smsmithcommand_lsmod(int argc, char *argv[])
14038465Smsmith{
14159854Sbp    struct preloaded_file	*fp;
14259854Sbp    struct kernel_module	*mp;
14359854Sbp    struct file_metadata	*md;
14438465Smsmith    char			lbuf[80];
14538764Smsmith    int				ch, verbose;
14638764Smsmith
14738764Smsmith    verbose = 0;
14838764Smsmith    optind = 1;
14942512Smsmith    optreset = 1;
15038764Smsmith    while ((ch = getopt(argc, argv, "v")) != -1) {
15138764Smsmith	switch(ch) {
15238764Smsmith	case 'v':
15338764Smsmith	    verbose = 1;
15438764Smsmith	    break;
15538764Smsmith	case '?':
15638764Smsmith	default:
15738764Smsmith	    /* getopt has already reported an error */
15838764Smsmith	    return(CMD_OK);
15938764Smsmith	}
16038764Smsmith    }
16138764Smsmith
16238465Smsmith    pager_open();
16359854Sbp    for (fp = preloaded_files; fp; fp = fp->f_next) {
16439673Sdfr	sprintf(lbuf, " %p: %s (%s, 0x%lx)\n",
16559854Sbp		(void *) fp->f_addr, fp->f_name, fp->f_type, (long) fp->f_size);
16638465Smsmith	pager_output(lbuf);
16759854Sbp	if (fp->f_args != NULL) {
16838465Smsmith	    pager_output("    args: ");
16959854Sbp	    pager_output(fp->f_args);
17038465Smsmith	    pager_output("\n");
17138465Smsmith	}
17259854Sbp	if (fp->f_modules) {
17359854Sbp	    pager_output("  modules: ");
17459854Sbp	    for (mp = fp->f_modules; mp; mp = mp->m_next) {
17559854Sbp		sprintf(lbuf, "%s ", mp->m_name);
17659854Sbp		pager_output(lbuf);
17759854Sbp	    }
17859854Sbp	    pager_output("\n");
17959854Sbp	}
18059854Sbp	if (verbose) {
18138764Smsmith	    /* XXX could add some formatting smarts here to display some better */
18259854Sbp	    for (md = fp->f_metadata; md != NULL; md = md->md_next) {
18339673Sdfr		sprintf(lbuf, "      0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
18438764Smsmith		pager_output(lbuf);
18538764Smsmith	    }
18659854Sbp	}
18738465Smsmith    }
18838465Smsmith    pager_close();
18938465Smsmith    return(CMD_OK);
19038465Smsmith}
19138465Smsmith
19238764Smsmith/*
19359854Sbp * File level interface, functions file_*
19438764Smsmith */
19538465Smsmithint
19659854Sbpfile_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
19738465Smsmith{
19859854Sbp    struct preloaded_file *fp;
19959854Sbp    int error;
20059854Sbp    int i;
20138764Smsmith
20259854Sbp    error = EFTYPE;
20359854Sbp    for (i = 0, fp = NULL; file_formats[i] && fp == NULL; i++) {
20459854Sbp	error = (file_formats[i]->l_load)(filename, loadaddr, &fp);
20559854Sbp	if (error == 0) {
20659854Sbp	    fp->f_loader = i;		/* remember the loader */
20759854Sbp	    *result = fp;
20859854Sbp	    break;
20959854Sbp	}
21059854Sbp	if (error == EFTYPE)
21159854Sbp	    continue;		/* Unknown to this handler? */
21259854Sbp	if (error) {
21359854Sbp	    sprintf(command_errbuf, "can't load file '%s': %s",
21459854Sbp		filename, strerror(error));
21559854Sbp	    break;
21659854Sbp	}
21759854Sbp    }
21859854Sbp    return (error);
21959854Sbp}
22038465Smsmith
22159854Sbpstatic int
22259854Sbpfile_load_dependancies(struct preloaded_file *base_file) {
22359854Sbp    struct file_metadata *md;
22459854Sbp    struct preloaded_file *fp;
22559854Sbp    char *dmodname;
22659854Sbp    int error;
22759854Sbp
22859854Sbp    md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
22959854Sbp    if (md == NULL)
23059854Sbp	return (0);
23159854Sbp    error = 0;
23259854Sbp    do {
23359854Sbp	dmodname = (char *)md->md_data;
23459854Sbp	if (file_findmodule(NULL, dmodname) == NULL) {
23559854Sbp	    printf("loading required module '%s'\n", dmodname);
23659854Sbp	    error = mod_load(dmodname, 0, NULL);
23759854Sbp	    if (error)
23859854Sbp		break;
23959854Sbp	}
24059854Sbp	md = metadata_next(md, MODINFOMD_DEPLIST);
24159854Sbp    } while (md);
24257468Sbp    if (!error)
24357468Sbp	return (0);
24457468Sbp    /* Load failed; discard everything */
24559854Sbp    while (base_file != NULL) {
24659854Sbp        fp = base_file;
24759854Sbp        base_file = base_file->f_next;
24859854Sbp        file_discard(fp);
24938764Smsmith    }
25057468Sbp    return (error);
25138764Smsmith}
25238764Smsmith/*
25338764Smsmith * We've been asked to load (name) as (type), so just suck it in,
25438764Smsmith * no arguments or anything.
25538764Smsmith */
25638764Smsmithint
25759854Sbpfile_loadraw(char *type, char *name)
25838764Smsmith{
25959854Sbp    struct preloaded_file	*fp;
26038764Smsmith    char			*cp;
26138764Smsmith    int				fd, got;
26238764Smsmith    vm_offset_t			laddr;
26338764Smsmith
26438764Smsmith    /* We can't load first */
26559854Sbp    if ((file_findfile(NULL, NULL)) == NULL) {
26638764Smsmith	command_errmsg = "can't load file before kernel";
26738764Smsmith	return(CMD_ERROR);
26838764Smsmith    }
26938764Smsmith
27039178Smsmith    /* locate the file on the load path */
27159854Sbp    cp = file_search(name);
27239178Smsmith    if (cp == NULL) {
27339178Smsmith	sprintf(command_errbuf, "can't find '%s'", name);
27439178Smsmith	return(CMD_ERROR);
27539178Smsmith    }
27639178Smsmith    name = cp;
27738764Smsmith
27838764Smsmith    if ((fd = open(name, O_RDONLY)) < 0) {
27938764Smsmith	sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno));
28044570Sdcs	free(name);
28138764Smsmith	return(CMD_ERROR);
28238764Smsmith    }
28338764Smsmith
28438764Smsmith    laddr = loadaddr;
28538764Smsmith    for (;;) {
28638764Smsmith	/* read in 4k chunks; size is not really important */
28738764Smsmith	got = archsw.arch_readin(fd, laddr, 4096);
28838764Smsmith	if (got == 0)				/* end of file */
28938764Smsmith	    break;
29038764Smsmith	if (got < 0) {				/* error */
29138764Smsmith	    sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno));
29244210Sdcs	    free(name);
29357269Smsmith	    close(fd);
29438764Smsmith	    return(CMD_ERROR);
29538764Smsmith	}
29638764Smsmith	laddr += got;
29738764Smsmith    }
29838764Smsmith
29938764Smsmith    /* Looks OK so far; create & populate control structure */
30059854Sbp    fp = file_alloc();
30159854Sbp    fp->f_name = name;
30259854Sbp    fp->f_type = strdup(type);
30359854Sbp    fp->f_args = NULL;
30459854Sbp    fp->f_metadata = NULL;
30559854Sbp    fp->f_loader = -1;
30659854Sbp    fp->f_addr = loadaddr;
30759854Sbp    fp->f_size = laddr - loadaddr;
30838764Smsmith
30938764Smsmith    /* recognise space consumption */
31038764Smsmith    loadaddr = laddr;
31138764Smsmith
31259854Sbp    /* Add to the list of loaded files */
31359854Sbp    file_insert_tail(fp);
31457269Smsmith    close(fd);
31538764Smsmith    return(CMD_OK);
31638764Smsmith}
31738764Smsmith
31838764Smsmith/*
31959854Sbp * Load the module (name), pass it (argc),(argv), add container file
32059854Sbp * to the list of loaded files.
32159854Sbp * If module is already loaded just assign new argc/argv.
32238764Smsmith */
32359854Sbpint
32459854Sbpmod_load(char *modname, int argc, char *argv[])
32538764Smsmith{
32659854Sbp    struct preloaded_file	*fp, *last_file;
32759854Sbp    struct kernel_module	*mp;
32859854Sbp    int				err;
32959854Sbp    char			*filename;
33038764Smsmith
33157468Sbp    /* see if module is already loaded */
33259854Sbp    mp = file_findmodule(NULL, modname);
33357468Sbp    if (mp) {
33459854Sbp#ifdef moduleargs
33559854Sbp	if (mp->m_args)
33659854Sbp	    free(mp->m_args);
33759854Sbp	mp->m_args = unargv(argc, argv);
33859854Sbp#endif
33959854Sbp	sprintf(command_errbuf, "warning: module '%s' already loaded", mp->m_name);
34059854Sbp	return (0);
34157468Sbp    }
34259854Sbp    /* locate file with the module on the search path */
34359854Sbp    filename = mod_searchmodule(modname);
34459854Sbp    if (filename == NULL) {
34559854Sbp	sprintf(command_errbuf, "can't find '%s'", modname);
34659854Sbp	return (ENOENT);
34759854Sbp    }
34859854Sbp    for (last_file = preloaded_files;
34959854Sbp	 last_file != NULL && last_file->f_next != NULL;
35059854Sbp	 last_file = last_file->f_next)
35159854Sbp	;
35257468Sbp
35359854Sbp    fp = NULL;
35459854Sbp    do {
35559854Sbp	err = file_load(filename, loadaddr, &fp);
35659854Sbp	if (err)
35738764Smsmith	    break;
35859854Sbp#ifdef moduleargs
35959854Sbp	mp = file_findmodule(fp, modname);
36059854Sbp	if (mp == NULL) {
36159854Sbp	    sprintf(command_errbuf, "module '%s' not found in the file '%s': %s",
36259854Sbp		modname, filename, strerror(err));
36359854Sbp	    err = ENOENT;
36459854Sbp	    break;
36538465Smsmith	}
36659854Sbp	mp->m_args = unargv(argc, argv);
36759854Sbp#else
36859854Sbp	fp->f_args = unargv(argc, argv);
36959854Sbp#endif
37059854Sbp	loadaddr = fp->f_addr + fp->f_size;
37159854Sbp	file_insert_tail(fp);		/* Add to the list of loaded files */
37259854Sbp	if (file_load_dependancies(fp) != 0) {
37359854Sbp	    err = ENOENT;
37459854Sbp	    last_file->f_next = NULL;
37559854Sbp	    loadaddr = last_file->f_addr + last_file->f_size;
37659854Sbp	    fp = NULL;
37759854Sbp	    break;
37859854Sbp	}
37959854Sbp    } while(0);
38038764Smsmith    if (err == EFTYPE)
38159854Sbp	sprintf(command_errbuf, "don't know how to load module '%s'", filename);
38259854Sbp    if (err && fp)
38359854Sbp	file_discard(fp);
38459854Sbp    free(filename);
38557468Sbp    return (err);
38638764Smsmith}
38738764Smsmith
38859854Sbp/*
38959854Sbp * Find a file matching (name) and (type).
39059854Sbp * NULL may be passed as a wildcard to either.
39159854Sbp */
39259854Sbpstruct preloaded_file *
39359854Sbpfile_findfile(char *name, char *type)
39438764Smsmith{
39559854Sbp    struct preloaded_file *fp;
39638764Smsmith
39759854Sbp    for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
39859854Sbp	if (((name == NULL) || !strcmp(name, fp->f_name)) &&
39959854Sbp	    ((type == NULL) || !strcmp(type, fp->f_type)))
40059854Sbp	    break;
40159854Sbp    }
40259854Sbp    return (fp);
40338465Smsmith}
40438465Smsmith
40538764Smsmith/*
40659854Sbp * Find a module matching (name) inside of given file.
40759854Sbp * NULL may be passed as a wildcard.
40838764Smsmith */
40959854Sbpstruct kernel_module *
41059854Sbpfile_findmodule(struct preloaded_file *fp, char *modname)
41138465Smsmith{
41259854Sbp    struct kernel_module *mp;
41359854Sbp
41459854Sbp    if (fp == NULL) {
41559854Sbp	for (fp = preloaded_files; fp; fp = fp->f_next) {
41659854Sbp	    for (mp = fp->f_modules; mp; mp = mp->m_next) {
41759854Sbp    		if (strcmp(modname, mp->m_name) == 0)
41859854Sbp		    return (mp);
41959854Sbp	    }
42059854Sbp	}
42159854Sbp	return (NULL);
42238465Smsmith    }
42359854Sbp    for (mp = fp->f_modules; mp; mp = mp->m_next) {
42459854Sbp        if (strcmp(modname, mp->m_name) == 0)
42559854Sbp	    return (mp);
42659854Sbp    }
42759854Sbp    return (NULL);
42838465Smsmith}
42938764Smsmith/*
43038764Smsmith * Make a copy of (size) bytes of data from (p), and associate them as
43138764Smsmith * metadata of (type) to the module (mp).
43238764Smsmith */
43338712Smsmithvoid
43459854Sbpfile_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
43538712Smsmith{
43659854Sbp    struct file_metadata	*md;
43738712Smsmith
43864187Sjhb    md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
43938712Smsmith    md->md_size = size;
44038712Smsmith    md->md_type = type;
44138712Smsmith    bcopy(p, md->md_data, size);
44259854Sbp    md->md_next = fp->f_metadata;
44359854Sbp    fp->f_metadata = md;
44438712Smsmith}
44538712Smsmith
44638764Smsmith/*
44759854Sbp * Find a metadata object of (type) associated with the file (fp)
44838764Smsmith */
44959854Sbpstruct file_metadata *
45059854Sbpfile_findmetadata(struct preloaded_file *fp, int type)
45138712Smsmith{
45259854Sbp    struct file_metadata *md;
45338712Smsmith
45459854Sbp    for (md = fp->f_metadata; md != NULL; md = md->md_next)
45538712Smsmith	if (md->md_type == type)
45638712Smsmith	    break;
45738712Smsmith    return(md);
45838712Smsmith}
45938764Smsmith
46059854Sbpstruct file_metadata *
46159854Sbpmetadata_next(struct file_metadata *md, int type)
46257468Sbp{
46357468Sbp    if (md == NULL)
46457468Sbp	return (NULL);
46557468Sbp    while((md = md->md_next) != NULL)
46657468Sbp	if (md->md_type == type)
46757468Sbp	    break;
46857468Sbp    return (md);
46957468Sbp}
47057468Sbp
47138764Smsmith/*
47239178Smsmith * Attempt to find the file (name) on the module searchpath.
47338764Smsmith * If (name) is qualified in any way, we simply check it and
47438764Smsmith * return it or NULL.  If it is not qualified, then we attempt
47538764Smsmith * to construct a path using entries in the environment variable
47638764Smsmith * module_path.
47738764Smsmith *
47838764Smsmith * The path we return a pointer to need never be freed, as we manage
47938764Smsmith * it internally.
48038764Smsmith */
48138764Smsmithstatic char *
48259854Sbpfile_search(char *name)
48338764Smsmith{
48444570Sdcs    char		*result;
48539673Sdfr    char		*path, *sp;
48639673Sdfr    const char		*cp;
48738764Smsmith    struct stat		sb;
48838764Smsmith
48938764Smsmith    /* Don't look for nothing */
49044210Sdcs    if (name == NULL)
49138764Smsmith	return(name);
49238764Smsmith
49344210Sdcs    if (*name == 0)
49444210Sdcs	return(strdup(name));
49544210Sdcs
49638764Smsmith    /*
49738764Smsmith     * See if there's a device on the front, or a directory name.
49838764Smsmith     */
49938764Smsmith    archsw.arch_getdev(NULL, name, &cp);
50038764Smsmith    if ((cp != name) || (strchr(name, '/') != NULL)) {
50138764Smsmith	/* Qualified, so just see if it exists */
50238764Smsmith	if (stat(name, &sb) == 0)
50344210Sdcs	    return(strdup(name));
50438764Smsmith	return(NULL);
50538764Smsmith    }
50638764Smsmith
50738764Smsmith    /*
50838764Smsmith     * Get the module path
50938764Smsmith     */
51038764Smsmith    if ((cp = getenv("module_path")) == NULL)
51139178Smsmith	cp = default_searchpath;
51238764Smsmith    sp = path = strdup(cp);
51338764Smsmith
51438764Smsmith    /*
51538764Smsmith     * Traverse the path, splitting off ';'-delimited components.
51638764Smsmith     */
51744570Sdcs    result = NULL;
51838764Smsmith    while((cp = strsep(&path, ";")) != NULL) {
51939178Smsmith	result = malloc(strlen(cp) + strlen(name) + 5);
52039178Smsmith	strcpy(result, cp);
52139178Smsmith	if (cp[strlen(cp) - 1] != '/')
52239178Smsmith	    strcat(result, "/");
52339178Smsmith	strcat(result, name);
52439178Smsmith	if ((stat(result, &sb) == 0) &&
52539178Smsmith	    S_ISREG(sb.st_mode))
52638764Smsmith	    break;
52738764Smsmith	free(result);
52838764Smsmith	result = NULL;
52938764Smsmith    }
53038764Smsmith    free(sp);
53138764Smsmith    return(result);
53238764Smsmith}
53338764Smsmith
53438764Smsmith/*
53539178Smsmith * Attempt to locate the file containing the module (name)
53639178Smsmith */
53739178Smsmithstatic char *
53839178Smsmithmod_searchmodule(char *name)
53939178Smsmith{
54039178Smsmith    char	*tn, *result;
54139178Smsmith
54239178Smsmith    /* Look for (name).ko */
54339673Sdfr    tn = malloc(strlen(name) + 3 + 1);
54439178Smsmith    strcpy(tn, name);
54539178Smsmith    strcat(tn, ".ko");
54659854Sbp    result = file_search(tn);
54739178Smsmith    free(tn);
54839178Smsmith    /* Look for just (name) (useful for finding kernels) */
54939178Smsmith    if (result == NULL)
55059854Sbp	result = file_search(name);
55139178Smsmith
55239178Smsmith    return(result);
55339178Smsmith}
55439178Smsmith
55559854Sbpint
55659854Sbpfile_addmodule(struct preloaded_file *fp, char *modname,
55759854Sbp	struct kernel_module **newmp)
55859854Sbp{
55959854Sbp    struct kernel_module *mp;
56039178Smsmith
56159854Sbp    mp = file_findmodule(fp, modname);
56259854Sbp    if (mp)
56359854Sbp	return (EEXIST);
56459854Sbp    mp = malloc(sizeof(struct kernel_module));
56559854Sbp    if (mp == NULL)
56659854Sbp	return (ENOMEM);
56759854Sbp    bzero(mp, sizeof(struct kernel_module));
56859854Sbp    mp->m_name = strdup(modname);
56959854Sbp    mp->m_fp = fp;
57059854Sbp    mp->m_next = fp->f_modules;
57159854Sbp    fp->f_modules = mp;
57259854Sbp    if (newmp)
57359854Sbp	*newmp = mp;
57459854Sbp    return (0);
57559854Sbp}
57659854Sbp
57739178Smsmith/*
57859854Sbp * Throw a file away
57938764Smsmith */
58038764Smsmithvoid
58159854Sbpfile_discard(struct preloaded_file *fp)
58238764Smsmith{
58359854Sbp    struct file_metadata	*md, *md1;
58459854Sbp    struct kernel_module	*mp, *mp1;
58559854Sbp    if (fp == NULL)
58659854Sbp	return;
58759854Sbp    md = fp->f_metadata;
58859854Sbp    while (md) {
58959854Sbp	md1 = md;
59059854Sbp	md = md->md_next;
59159854Sbp	free(md1);
59259854Sbp    }
59359854Sbp    mp = fp->f_modules;
59459854Sbp    while (mp) {
59559854Sbp	if (mp->m_name)
59639178Smsmith	    free(mp->m_name);
59759854Sbp	mp1 = mp;
59859854Sbp	mp = mp->m_next;
59959854Sbp	free(mp1);
60059854Sbp    }
60159854Sbp    if (fp->f_name != NULL)
60259854Sbp	free(fp->f_name);
60359854Sbp    if (fp->f_type != NULL)
60459854Sbp        free(fp->f_type);
60559854Sbp    if (fp->f_args != NULL)
60659854Sbp        free(fp->f_args);
60759854Sbp    free(fp);
60838764Smsmith}
60938764Smsmith
61038764Smsmith/*
61159854Sbp * Allocate a new file; must be used instead of malloc()
61239178Smsmith * to ensure safe initialisation.
61339178Smsmith */
61459854Sbpstruct preloaded_file *
61559854Sbpfile_alloc(void)
61639178Smsmith{
61759854Sbp    struct preloaded_file	*fp;
61839178Smsmith
61959854Sbp    if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
62059854Sbp	bzero(fp, sizeof(struct preloaded_file));
62139178Smsmith    }
62259854Sbp    return (fp);
62339178Smsmith}
62439178Smsmith
62539178Smsmith/*
62638764Smsmith * Add a module to the chain
62738764Smsmith */
62838764Smsmithstatic void
62959854Sbpfile_insert_tail(struct preloaded_file *fp)
63038764Smsmith{
63159854Sbp    struct preloaded_file	*cm;
63238764Smsmith
63359854Sbp    /* Append to list of loaded file */
63459854Sbp    fp->f_next = NULL;
63559854Sbp    if (preloaded_files == NULL) {
63659854Sbp	preloaded_files = fp;
63738764Smsmith    } else {
63859854Sbp	for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
63938764Smsmith	    ;
64059854Sbp	cm->f_next = fp;
64138764Smsmith    }
64238764Smsmith}
64359854Sbp
644