module.c revision 53993
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 53993 1999-12-01 18:30:26Z dcs $
2738465Smsmith */
2838465Smsmith
2938465Smsmith/*
3038465Smsmith * 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
4038764Smsmithstatic struct loaded_module	*mod_loadmodule(char *name, int argc, char *argv[]);
4138764Smsmithstatic char			*mod_searchdep(struct loaded_module *mp);
4239178Smsmithstatic char			*mod_searchfile(char *name);
4338764Smsmithstatic char			*mod_searchmodule(char *name);
4438764Smsmithstatic void			mod_append(struct loaded_module *mp);
4538764Smsmith
4639178Smsmith/* load address should be tweaked by first module loaded (kernel) */
4738465Smsmithstatic vm_offset_t	loadaddr = 0;
4838465Smsmith
4940141Speterstatic char		*default_searchpath ="/;/boot;/modules";
5039178Smsmith
5138465Smsmithstruct loaded_module *loaded_modules = NULL;
5238465Smsmith
5338764Smsmith/*
5438764Smsmith * load an object, either a disk file or code module.
5538764Smsmith *
5638764Smsmith * To load a file, the syntax is:
5738764Smsmith *
5838764Smsmith * load -t <type> <path>
5938764Smsmith *
6038764Smsmith * code modules are loaded as:
6138764Smsmith *
6238764Smsmith * load <path> <options>
6338764Smsmith */
6438764Smsmith
6538465SmsmithCOMMAND_SET(load, "load", "load a kernel or module", command_load);
6638465Smsmith
6738465Smsmithstatic int
6838465Smsmithcommand_load(int argc, char *argv[])
6938465Smsmith{
7038764Smsmith    char	*typestr;
7138764Smsmith    int		dofile, ch;
7238764Smsmith
7338764Smsmith    dofile = 0;
7438764Smsmith    optind = 1;
7542512Smsmith    optreset = 1;
7638764Smsmith    typestr = NULL;
7753993Sdcs    if (argc == 1) {
7853993Sdcs	command_errmsg = "no filename specified";
7953993Sdcs	return(CMD_ERROR);
8053993Sdcs    }
8138764Smsmith    while ((ch = getopt(argc, argv, "t:")) != -1) {
8238764Smsmith	switch(ch) {
8338764Smsmith	case 't':
8438764Smsmith	    typestr = optarg;
8538764Smsmith	    dofile = 1;
8638764Smsmith	    break;
8738764Smsmith	case '?':
8838764Smsmith	default:
8938764Smsmith	    /* getopt has already reported an error */
9038764Smsmith	    return(CMD_OK);
9138764Smsmith	}
9238764Smsmith    }
9338764Smsmith    argv += (optind - 1);
9438764Smsmith    argc -= (optind - 1);
9538764Smsmith
9638764Smsmith    /*
9738764Smsmith     * Request to load a raw file?
9838764Smsmith     */
9938764Smsmith    if (dofile) {
10038764Smsmith	if ((typestr == NULL) || (*typestr == 0)) {
10138764Smsmith	    command_errmsg = "invalid load type";
10238764Smsmith	    return(CMD_ERROR);
10338764Smsmith	}
10438764Smsmith	return(mod_loadobj(typestr, argv[1]));
10538764Smsmith    }
10638764Smsmith
10738764Smsmith    /*
10838764Smsmith     * Looks like a request for a module.
10938764Smsmith     */
11038465Smsmith    return(mod_load(argv[1], argc - 2, argv + 2));
11138465Smsmith}
11238465Smsmith
11338712SmsmithCOMMAND_SET(unload, "unload", "unload all modules", command_unload);
11438712Smsmith
11538712Smsmithstatic int
11638712Smsmithcommand_unload(int argc, char *argv[])
11738712Smsmith{
11838712Smsmith    struct loaded_module	*mp;
11938712Smsmith
12038712Smsmith    while (loaded_modules != NULL) {
12138712Smsmith	mp = loaded_modules;
12238712Smsmith	loaded_modules = loaded_modules->m_next;
12338764Smsmith	mod_discard(mp);
12438712Smsmith    }
12538712Smsmith    loadaddr = 0;
12638712Smsmith    return(CMD_OK);
12738712Smsmith}
12838712Smsmith
12938465SmsmithCOMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
13038465Smsmith
13138465Smsmithstatic int
13238465Smsmithcommand_lsmod(int argc, char *argv[])
13338465Smsmith{
13438465Smsmith    struct loaded_module	*am;
13538764Smsmith    struct module_metadata	*md;
13638465Smsmith    char			lbuf[80];
13738764Smsmith    int				ch, verbose;
13838764Smsmith
13938764Smsmith    verbose = 0;
14038764Smsmith    optind = 1;
14142512Smsmith    optreset = 1;
14238764Smsmith    while ((ch = getopt(argc, argv, "v")) != -1) {
14338764Smsmith	switch(ch) {
14438764Smsmith	case 'v':
14538764Smsmith	    verbose = 1;
14638764Smsmith	    break;
14738764Smsmith	case '?':
14838764Smsmith	default:
14938764Smsmith	    /* getopt has already reported an error */
15038764Smsmith	    return(CMD_OK);
15138764Smsmith	}
15238764Smsmith    }
15338764Smsmith
15438465Smsmith    pager_open();
15538465Smsmith    for (am = loaded_modules; (am != NULL); am = am->m_next) {
15639673Sdfr	sprintf(lbuf, " %p: %s (%s, 0x%lx)\n",
15739673Sdfr		(void *) am->m_addr, am->m_name, am->m_type, (long) am->m_size);
15838465Smsmith	pager_output(lbuf);
15938465Smsmith	if (am->m_args != NULL) {
16038465Smsmith	    pager_output("    args: ");
16138465Smsmith	    pager_output(am->m_args);
16238465Smsmith	    pager_output("\n");
16338465Smsmith	}
16438764Smsmith	if (verbose)
16538764Smsmith	    /* XXX could add some formatting smarts here to display some better */
16638764Smsmith	    for (md = am->m_metadata; md != NULL; md = md->md_next) {
16739673Sdfr		sprintf(lbuf, "      0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
16838764Smsmith		pager_output(lbuf);
16938764Smsmith	    }
17038465Smsmith    }
17138465Smsmith    pager_close();
17238465Smsmith    return(CMD_OK);
17338465Smsmith}
17438465Smsmith
17538764Smsmith/*
17638764Smsmith * We've been asked to load (name) and give it (argc),(argv).
17738764Smsmith * Start by trying to load it, and then attempt to load all of its
17838764Smsmith * dependancies.  If we fail at any point, throw them all away and
17938764Smsmith * fail the entire load.
18038764Smsmith *
18138764Smsmith * XXX if a depended-on module requires arguments, it must be loaded
18238764Smsmith *     explicitly first.
18338764Smsmith */
18438465Smsmithint
18538465Smsmithmod_load(char *name, int argc, char *argv[])
18638465Smsmith{
18738764Smsmith    struct loaded_module	*last_mod, *base_mod, *mp;
18838764Smsmith    char			*dep_name;
18938764Smsmith
19038764Smsmith    /* remember previous last module on chain */
19138764Smsmith    for (last_mod = loaded_modules;
19238764Smsmith	 (last_mod != NULL) && (last_mod->m_next != NULL);
19338764Smsmith	 last_mod = last_mod->m_next)
19438764Smsmith	;
19538465Smsmith
19638764Smsmith    /*
19738764Smsmith     * Load the first module; note that it's the only one that gets
19838764Smsmith     * arguments explicitly.
19938764Smsmith     */
20038764Smsmith    if ((base_mod = mod_loadmodule(name, argc, argv)) == NULL)
20138764Smsmith	return(CMD_ERROR);
20238465Smsmith
20338764Smsmith    /*
20438764Smsmith     * Look for dependancies.
20538764Smsmith     */
20638764Smsmith    while ((dep_name = mod_searchdep(base_mod)) != NULL) {
20738764Smsmith	printf("loading required module '%s'\n", dep_name);
20838764Smsmith	if ((mp = mod_loadmodule(dep_name, 0, NULL)) == NULL) {
20938764Smsmith	    /* Load failed; discard everything */
21038764Smsmith	    while (base_mod != NULL) {
21138764Smsmith		mp = base_mod;
21238764Smsmith		base_mod = base_mod->m_next;
21338764Smsmith		mod_discard(mp);
21438764Smsmith	    }
21538764Smsmith	    last_mod->m_next = NULL;
21638764Smsmith	    loadaddr = last_mod->m_addr + last_mod->m_size;
21738764Smsmith	    /* error message already set by mod_loadmodule */
21838764Smsmith	    return(CMD_ERROR);
21938764Smsmith	}
22038764Smsmith    }
22138764Smsmith    return(CMD_OK);
22238764Smsmith}
22338764Smsmith
22438764Smsmith/*
22538764Smsmith * We've been asked to load (name) as (type), so just suck it in,
22638764Smsmith * no arguments or anything.
22738764Smsmith */
22838764Smsmithint
22938764Smsmithmod_loadobj(char *type, char *name)
23038764Smsmith{
23138764Smsmith    struct loaded_module	*mp;
23238764Smsmith    char			*cp;
23338764Smsmith    int				fd, got;
23438764Smsmith    vm_offset_t			laddr;
23538764Smsmith
23638764Smsmith    /* We can't load first */
23738764Smsmith    if ((mod_findmodule(NULL, NULL)) == NULL) {
23838764Smsmith	command_errmsg = "can't load file before kernel";
23938764Smsmith	return(CMD_ERROR);
24038764Smsmith    }
24138764Smsmith
24239178Smsmith    /* locate the file on the load path */
24339178Smsmith    cp = mod_searchfile(name);
24439178Smsmith    if (cp == NULL) {
24539178Smsmith	sprintf(command_errbuf, "can't find '%s'", name);
24639178Smsmith	return(CMD_ERROR);
24739178Smsmith    }
24839178Smsmith    name = cp;
24938764Smsmith
25038764Smsmith    if ((fd = open(name, O_RDONLY)) < 0) {
25138764Smsmith	sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno));
25244570Sdcs	free(name);
25338764Smsmith	return(CMD_ERROR);
25438764Smsmith    }
25538764Smsmith
25638764Smsmith    laddr = loadaddr;
25738764Smsmith    for (;;) {
25838764Smsmith	/* read in 4k chunks; size is not really important */
25938764Smsmith	got = archsw.arch_readin(fd, laddr, 4096);
26038764Smsmith	if (got == 0)				/* end of file */
26138764Smsmith	    break;
26238764Smsmith	if (got < 0) {				/* error */
26338764Smsmith	    sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno));
26444210Sdcs	    free(name);
26538764Smsmith	    return(CMD_ERROR);
26638764Smsmith	}
26738764Smsmith	laddr += got;
26838764Smsmith    }
26938764Smsmith
27038764Smsmith    /* Looks OK so far; create & populate control structure */
27138764Smsmith    mp = malloc(sizeof(struct loaded_module));
27244210Sdcs    mp->m_name = name;
27338764Smsmith    mp->m_type = strdup(type);
27438764Smsmith    mp->m_args = NULL;
27538764Smsmith    mp->m_metadata = NULL;
27638764Smsmith    mp->m_loader = -1;
27738764Smsmith    mp->m_addr = loadaddr;
27838764Smsmith    mp->m_size = laddr - loadaddr;
27938764Smsmith
28038764Smsmith    /* recognise space consumption */
28138764Smsmith    loadaddr = laddr;
28238764Smsmith
28338764Smsmith    /* Add to the list of loaded modules */
28438764Smsmith    mod_append(mp);
28538764Smsmith    return(CMD_OK);
28638764Smsmith}
28738764Smsmith
28838764Smsmith/*
28938764Smsmith * Load the module (name), pass it (argc),(argv).
29038764Smsmith * Don't do any dependancy checking.
29138764Smsmith */
29238764Smsmithstatic struct loaded_module *
29338764Smsmithmod_loadmodule(char *name, int argc, char *argv[])
29438764Smsmith{
29538764Smsmith    struct loaded_module	*mp;
29638764Smsmith    int				i, err;
29738764Smsmith    char			*cp;
29838764Smsmith
29939178Smsmith    /* locate the module on the search path */
30039178Smsmith    cp = mod_searchmodule(name);
30139178Smsmith    if (cp == NULL) {
30239178Smsmith	sprintf(command_errbuf, "can't find '%s'", name);
30339178Smsmith	return(NULL);
30439178Smsmith    }
30539178Smsmith    name = cp;
30639178Smsmith
30738764Smsmith    err = 0;
30838764Smsmith    for (i = 0, mp = NULL; (module_formats[i] != NULL) && (mp == NULL); i++) {
30938764Smsmith	if ((err = (module_formats[i]->l_load)(name, loadaddr, &mp)) != 0) {
31038764Smsmith
31138465Smsmith	    /* Unknown to this handler? */
31238465Smsmith	    if (err == EFTYPE)
31338465Smsmith		continue;
31438465Smsmith
31538465Smsmith	    /* Fatal error */
31638465Smsmith	    sprintf(command_errbuf, "can't load module '%s': %s", name, strerror(err));
31744570Sdcs	    free(name);
31838764Smsmith	    return(NULL);
31938712Smsmith	} else {
32038764Smsmith
32138764Smsmith	    /* Load was OK, set args */
32238764Smsmith	    mp->m_args = unargv(argc, argv);
32338764Smsmith
32438764Smsmith	    /* where can we put the next one? */
32538764Smsmith	    loadaddr = mp->m_addr + mp->m_size;
32638764Smsmith
32738712Smsmith	    /* remember the loader */
32838764Smsmith	    mp->m_loader = i;
32938764Smsmith
33038764Smsmith	    /* Add to the list of loaded modules */
33138764Smsmith	    mod_append(mp);
33238764Smsmith
33338764Smsmith	    break;
33438465Smsmith	}
33538465Smsmith    }
33638764Smsmith    if (err == EFTYPE)
33738764Smsmith	sprintf(command_errbuf, "don't know how to load module '%s'", name);
33844570Sdcs    free(name);
33938764Smsmith    return(mp);
34038764Smsmith}
34138764Smsmith
34238764Smsmith/*
34338764Smsmith * Search the modules from (mp) onwards, and return the name of the
34438764Smsmith * first unresolved dependancy, or NULL if none were found.
34538764Smsmith */
34638764Smsmithstatic char *
34738764Smsmithmod_searchdep(struct loaded_module *mp)
34838764Smsmith{
34940141Speter    char				*deps;
35040141Speter    size_t				deplen;
35138764Smsmith    struct module_metadata		*md;
35238764Smsmith    struct loaded_module		*dmp;
35338764Smsmith    int					dindex;
35438764Smsmith
35538764Smsmith    for (; mp != NULL; mp = mp->m_next) {
35638764Smsmith
35738764Smsmith	/*
35838764Smsmith	 * Get KLD module data
35938764Smsmith	 */
36038764Smsmith	deps = NULL;
36140141Speter	deplen = 0;
36240141Speter	if ((md = mod_findmetadata(mp, MODINFOMD_DEPLIST)) != NULL) {
36340141Speter	    deps = (char *)md->md_data;
36440141Speter	    deplen = md->md_size;
36540141Speter	}
36638465Smsmith
36740141Speter	if (deps != NULL && deplen > 0) {
36838764Smsmith
36938764Smsmith	    /* Iterate over dependancies */
37040141Speter	    dindex = 0;
37140141Speter	    while (dindex < deplen) {
37238764Smsmith		/*
37338764Smsmith		 * Look for a module matching the dependancy; if we don't have it,
37438764Smsmith		 * we need it.
37538764Smsmith		 */
37640141Speter		if ((dmp = mod_findmodule(&deps[dindex], NULL)) == NULL)
37740141Speter		    return(&deps[dindex]);
37840141Speter		dindex += strlen(&deps[dindex]) + 1;
37938764Smsmith	    }
38038764Smsmith	}
38138465Smsmith    }
38238764Smsmith    return(NULL);
38338465Smsmith}
38438465Smsmith
38538764Smsmith/*
38638764Smsmith * Find a module matching (name) and (type).
38738764Smsmith * NULL may be passed as a wildcard to either.
38838764Smsmith */
38938465Smsmithstruct loaded_module *
39038465Smsmithmod_findmodule(char *name, char *type)
39138465Smsmith{
39238465Smsmith    struct loaded_module	*mp;
39338465Smsmith
39438465Smsmith    for (mp = loaded_modules; mp != NULL; mp = mp->m_next) {
39538465Smsmith	if (((name == NULL) || !strcmp(name, mp->m_name)) &&
39638465Smsmith	    ((type == NULL) || !strcmp(type, mp->m_type)))
39738465Smsmith	    break;
39838465Smsmith    }
39938465Smsmith    return(mp);
40038465Smsmith}
40138712Smsmith
40238764Smsmith/*
40338764Smsmith * Make a copy of (size) bytes of data from (p), and associate them as
40438764Smsmith * metadata of (type) to the module (mp).
40538764Smsmith */
40638712Smsmithvoid
40738712Smsmithmod_addmetadata(struct loaded_module *mp, int type, size_t size, void *p)
40838712Smsmith{
40938712Smsmith    struct module_metadata	*md;
41038712Smsmith
41138712Smsmith    md = malloc(sizeof(struct module_metadata) + size);
41238712Smsmith    md->md_size = size;
41338712Smsmith    md->md_type = type;
41438712Smsmith    bcopy(p, md->md_data, size);
41538712Smsmith    md->md_next = mp->m_metadata;
41638712Smsmith    mp->m_metadata = md;
41738712Smsmith}
41838712Smsmith
41938764Smsmith/*
42038764Smsmith * Find a metadata object of (type) associated with the module
42138764Smsmith * (mp)
42238764Smsmith */
42338712Smsmithstruct module_metadata *
42438712Smsmithmod_findmetadata(struct loaded_module *mp, int type)
42538712Smsmith{
42638712Smsmith    struct module_metadata	*md;
42738712Smsmith
42838712Smsmith    for (md = mp->m_metadata; md != NULL; md = md->md_next)
42938712Smsmith	if (md->md_type == type)
43038712Smsmith	    break;
43138712Smsmith    return(md);
43238712Smsmith}
43338764Smsmith
43438764Smsmith/*
43539178Smsmith * Attempt to find the file (name) on the module searchpath.
43638764Smsmith * If (name) is qualified in any way, we simply check it and
43738764Smsmith * return it or NULL.  If it is not qualified, then we attempt
43838764Smsmith * to construct a path using entries in the environment variable
43938764Smsmith * module_path.
44038764Smsmith *
44138764Smsmith * The path we return a pointer to need never be freed, as we manage
44238764Smsmith * it internally.
44338764Smsmith */
44438764Smsmithstatic char *
44539178Smsmithmod_searchfile(char *name)
44638764Smsmith{
44744570Sdcs    char		*result;
44839673Sdfr    char		*path, *sp;
44939673Sdfr    const char		*cp;
45038764Smsmith    struct stat		sb;
45138764Smsmith
45238764Smsmith    /* Don't look for nothing */
45344210Sdcs    if (name == NULL)
45438764Smsmith	return(name);
45538764Smsmith
45644210Sdcs    if (*name == 0)
45744210Sdcs	return(strdup(name));
45844210Sdcs
45938764Smsmith    /*
46038764Smsmith     * See if there's a device on the front, or a directory name.
46138764Smsmith     */
46238764Smsmith    archsw.arch_getdev(NULL, name, &cp);
46338764Smsmith    if ((cp != name) || (strchr(name, '/') != NULL)) {
46438764Smsmith	/* Qualified, so just see if it exists */
46538764Smsmith	if (stat(name, &sb) == 0)
46644210Sdcs	    return(strdup(name));
46738764Smsmith	return(NULL);
46838764Smsmith    }
46938764Smsmith
47038764Smsmith    /*
47138764Smsmith     * Get the module path
47238764Smsmith     */
47338764Smsmith    if ((cp = getenv("module_path")) == NULL)
47439178Smsmith	cp = default_searchpath;
47538764Smsmith    sp = path = strdup(cp);
47638764Smsmith
47738764Smsmith    /*
47838764Smsmith     * Traverse the path, splitting off ';'-delimited components.
47938764Smsmith     */
48044570Sdcs    result = NULL;
48138764Smsmith    while((cp = strsep(&path, ";")) != NULL) {
48239178Smsmith	result = malloc(strlen(cp) + strlen(name) + 5);
48339178Smsmith	strcpy(result, cp);
48439178Smsmith	if (cp[strlen(cp) - 1] != '/')
48539178Smsmith	    strcat(result, "/");
48639178Smsmith	strcat(result, name);
48739178Smsmith/*	printf("search '%s'\n", result); */
48839178Smsmith	if ((stat(result, &sb) == 0) &&
48939178Smsmith	    S_ISREG(sb.st_mode))
49038764Smsmith	    break;
49138764Smsmith	free(result);
49238764Smsmith	result = NULL;
49338764Smsmith    }
49438764Smsmith    free(sp);
49538764Smsmith    return(result);
49638764Smsmith}
49738764Smsmith
49838764Smsmith/*
49939178Smsmith * Attempt to locate the file containing the module (name)
50039178Smsmith */
50139178Smsmithstatic char *
50239178Smsmithmod_searchmodule(char *name)
50339178Smsmith{
50439178Smsmith    char	*tn, *result;
50539178Smsmith
50639178Smsmith    /* Look for (name).ko */
50739673Sdfr    tn = malloc(strlen(name) + 3 + 1);
50839178Smsmith    strcpy(tn, name);
50939178Smsmith    strcat(tn, ".ko");
51039178Smsmith    result = mod_searchfile(tn);
51139178Smsmith    free(tn);
51239178Smsmith    /* Look for just (name) (useful for finding kernels) */
51339178Smsmith    if (result == NULL)
51439178Smsmith	result = mod_searchfile(name);
51539178Smsmith
51639178Smsmith    return(result);
51739178Smsmith}
51839178Smsmith
51939178Smsmith
52039178Smsmith/*
52138764Smsmith * Throw a module away
52238764Smsmith */
52338764Smsmithvoid
52438764Smsmithmod_discard(struct loaded_module *mp)
52538764Smsmith{
52638764Smsmith    struct module_metadata	*md;
52738764Smsmith
52839178Smsmith    if (mp != NULL) {
52939178Smsmith	while (mp->m_metadata != NULL) {
53039178Smsmith	    md = mp->m_metadata;
53139178Smsmith	    mp->m_metadata = mp->m_metadata->md_next;
53239178Smsmith	    free(md);
53339178Smsmith	}
53439178Smsmith	if (mp->m_name != NULL)
53539178Smsmith	    free(mp->m_name);
53639178Smsmith	if (mp->m_type != NULL)
53739178Smsmith	    free(mp->m_type);
53839178Smsmith	if (mp->m_args != NULL)
53939178Smsmith	    free(mp->m_args);
54039178Smsmith	free(mp);
54139178Smsmith    }
54238764Smsmith}
54338764Smsmith
54438764Smsmith/*
54539178Smsmith * Allocate a new module; must be used instead of malloc()
54639178Smsmith * to ensure safe initialisation.
54739178Smsmith */
54839178Smsmithstruct loaded_module *
54939178Smsmithmod_allocmodule(void)
55039178Smsmith{
55139178Smsmith    struct loaded_module	*mp;
55239178Smsmith
55339178Smsmith    if ((mp = malloc(sizeof(struct loaded_module))) != NULL) {
55439178Smsmith	bzero(mp, sizeof(struct loaded_module));
55539178Smsmith    }
55639178Smsmith    return(mp);
55739178Smsmith}
55839178Smsmith
55939178Smsmith
56039178Smsmith/*
56138764Smsmith * Add a module to the chain
56238764Smsmith */
56338764Smsmithstatic void
56438764Smsmithmod_append(struct loaded_module *mp)
56538764Smsmith{
56638764Smsmith    struct loaded_module	*cm;
56738764Smsmith
56838764Smsmith    /* Append to list of loaded modules */
56938764Smsmith    mp->m_next = NULL;
57038764Smsmith    if (loaded_modules == NULL) {
57138764Smsmith	loaded_modules = mp;
57238764Smsmith    } else {
57338764Smsmith	for (cm = loaded_modules; cm->m_next != NULL; cm = cm->m_next)
57438764Smsmith	    ;
57538764Smsmith	cm->m_next = mp;
57638764Smsmith    }
57738764Smsmith}
578