122028508SToomas Soome /*
222028508SToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
322028508SToomas Soome * All rights reserved.
422028508SToomas Soome *
522028508SToomas Soome * Redistribution and use in source and binary forms, with or without
622028508SToomas Soome * modification, are permitted provided that the following conditions
722028508SToomas Soome * are met:
822028508SToomas Soome * 1. Redistributions of source code must retain the above copyright
922028508SToomas Soome * notice, this list of conditions and the following disclaimer.
1022028508SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
1122028508SToomas Soome * notice, this list of conditions and the following disclaimer in the
1222028508SToomas Soome * documentation and/or other materials provided with the distribution.
1322028508SToomas Soome *
1422028508SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1522028508SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1622028508SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1722028508SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1822028508SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1922028508SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2022028508SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2122028508SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2222028508SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2322028508SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2422028508SToomas Soome * SUCH DAMAGE.
2522028508SToomas Soome */
2622028508SToomas Soome
2722028508SToomas Soome #include <sys/cdefs.h>
2822028508SToomas Soome
2922028508SToomas Soome /*
3022028508SToomas Soome * file/module function dispatcher, support, etc.
3122028508SToomas Soome */
3222028508SToomas Soome
3322028508SToomas Soome #include <stand.h>
3422028508SToomas Soome #include <string.h>
3522028508SToomas Soome #include <sys/param.h>
3622028508SToomas Soome #include <sys/linker.h>
3722028508SToomas Soome #include <sys/module.h>
3822028508SToomas Soome #include <sys/queue.h>
3922028508SToomas Soome #include <sys/stdint.h>
4022028508SToomas Soome #include <sys/tem_impl.h>
4122028508SToomas Soome #include <sys/font.h>
4222028508SToomas Soome #include <sys/sha1.h>
4322028508SToomas Soome #include <libcrypto.h>
4422028508SToomas Soome
4522028508SToomas Soome #include "bootstrap.h"
4622028508SToomas Soome
4722028508SToomas Soome #if defined(EFI)
4822028508SToomas Soome #define PTOV(pa) ((void *)pa)
4922028508SToomas Soome #else
5022028508SToomas Soome #include "../i386/btx/lib/btxv86.h"
5122028508SToomas Soome #endif
5222028508SToomas Soome
5322028508SToomas Soome #define MDIR_REMOVED 0x0001
5422028508SToomas Soome #define MDIR_NOHINTS 0x0002
5522028508SToomas Soome
5622028508SToomas Soome struct moduledir {
5722028508SToomas Soome char *d_path; /* path of modules directory */
5822028508SToomas Soome uchar_t *d_hints; /* content of linker.hints file */
5922028508SToomas Soome int d_hintsz; /* size of hints data */
6022028508SToomas Soome int d_flags;
6122028508SToomas Soome STAILQ_ENTRY(moduledir) d_link;
6222028508SToomas Soome };
6322028508SToomas Soome
6422028508SToomas Soome static int file_load(char *, vm_offset_t, struct preloaded_file **);
6522028508SToomas Soome static int file_load_dependencies(struct preloaded_file *);
6622028508SToomas Soome static char *file_search(const char *, const char **);
6722028508SToomas Soome static struct kernel_module *file_findmodule(struct preloaded_file *, char *,
6822028508SToomas Soome struct mod_depend *);
6922028508SToomas Soome static int file_havepath(const char *);
7022028508SToomas Soome static char *mod_searchmodule(char *, struct mod_depend *);
7122028508SToomas Soome static void file_insert_tail(struct preloaded_file *);
7222028508SToomas Soome static void file_remove(struct preloaded_file *);
7322028508SToomas Soome struct file_metadata *metadata_next(struct file_metadata *, int);
7422028508SToomas Soome static void moduledir_readhints(struct moduledir *);
7522028508SToomas Soome static void moduledir_rebuild(void);
7622028508SToomas Soome
7722028508SToomas Soome /* load address should be tweaked by first module loaded (kernel) */
7822028508SToomas Soome static vm_offset_t loadaddr = 0;
7922028508SToomas Soome
8022028508SToomas Soome #if defined(LOADER_FDT_SUPPORT)
8122028508SToomas Soome static const char *default_searchpath = "/boot/kernel;/boot/modules;/boot/dtb";
8222028508SToomas Soome #else
8322028508SToomas Soome static const char *default_searchpath = "/platform/i86pc";
8422028508SToomas Soome #endif
8522028508SToomas Soome
8622028508SToomas Soome static STAILQ_HEAD(, moduledir) moduledir_list =
8722028508SToomas Soome STAILQ_HEAD_INITIALIZER(moduledir_list);
8822028508SToomas Soome
8922028508SToomas Soome struct preloaded_file *preloaded_files = NULL;
9022028508SToomas Soome
9122028508SToomas Soome static const char *kld_ext_list[] = {
9222028508SToomas Soome ".ko",
9322028508SToomas Soome "",
9422028508SToomas Soome ".debug",
9522028508SToomas Soome NULL
9622028508SToomas Soome };
9722028508SToomas Soome
9822028508SToomas Soome
9922028508SToomas Soome /*
10022028508SToomas Soome * load an object, either a disk file or code module.
10122028508SToomas Soome *
10222028508SToomas Soome * To load a file, the syntax is:
10322028508SToomas Soome *
10422028508SToomas Soome * load -t <type> <path>
10522028508SToomas Soome *
10622028508SToomas Soome * code modules are loaded as:
10722028508SToomas Soome *
10822028508SToomas Soome * load <path> <options>
10922028508SToomas Soome */
11022028508SToomas Soome
11122028508SToomas Soome COMMAND_SET(load, "load", "load a kernel or module", command_load);
11222028508SToomas Soome
11322028508SToomas Soome static int
command_load(int argc,char * argv[])11422028508SToomas Soome command_load(int argc, char *argv[])
11522028508SToomas Soome {
11622028508SToomas Soome char *typestr;
11722028508SToomas Soome int dofile, dokld, ch, error;
11822028508SToomas Soome
11922028508SToomas Soome dokld = dofile = 0;
12022028508SToomas Soome optind = 1;
12122028508SToomas Soome optreset = 1;
12222028508SToomas Soome typestr = NULL;
12322028508SToomas Soome if (argc == 1) {
12422028508SToomas Soome command_errmsg = "no filename specified";
12522028508SToomas Soome return (CMD_CRIT);
12622028508SToomas Soome }
12722028508SToomas Soome while ((ch = getopt(argc, argv, "kt:")) != -1) {
12822028508SToomas Soome switch (ch) {
12922028508SToomas Soome case 'k':
13022028508SToomas Soome dokld = 1;
13122028508SToomas Soome break;
13222028508SToomas Soome case 't':
13322028508SToomas Soome typestr = optarg;
13422028508SToomas Soome dofile = 1;
13522028508SToomas Soome break;
13622028508SToomas Soome case '?':
13722028508SToomas Soome default:
13822028508SToomas Soome /* getopt has already reported an error */
13922028508SToomas Soome return (CMD_OK);
14022028508SToomas Soome }
14122028508SToomas Soome }
14222028508SToomas Soome argv += (optind - 1);
14322028508SToomas Soome argc -= (optind - 1);
14422028508SToomas Soome
14522028508SToomas Soome printf("Loading %s...\n", argv[1]);
14622028508SToomas Soome /*
14722028508SToomas Soome * Request to load a raw file?
14822028508SToomas Soome */
14922028508SToomas Soome if (dofile) {
15022028508SToomas Soome struct preloaded_file *fp;
15122028508SToomas Soome
15222028508SToomas Soome if ((typestr == NULL) || (*typestr == 0)) {
15322028508SToomas Soome command_errmsg = "invalid load type";
15422028508SToomas Soome return (CMD_CRIT);
15522028508SToomas Soome }
15622028508SToomas Soome
15722028508SToomas Soome if (file_findfile(argv[1], typestr) != NULL) {
158fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
15922028508SToomas Soome "warning: file '%s' already loaded", argv[1]);
16022028508SToomas Soome return (CMD_WARN);
16122028508SToomas Soome }
16222028508SToomas Soome
16322028508SToomas Soome fp = file_loadraw(argv[1], typestr, argc - 2, argv + 2, 1);
16422028508SToomas Soome if (fp != NULL)
16522028508SToomas Soome return (CMD_OK);
16622028508SToomas Soome
16722028508SToomas Soome /* Failing to load mfs_root is never going to end well! */
16822028508SToomas Soome if (strcmp("mfs_root", typestr) == 0)
16922028508SToomas Soome return (CMD_FATAL);
17022028508SToomas Soome
17122028508SToomas Soome return (CMD_ERROR);
17222028508SToomas Soome }
17322028508SToomas Soome /*
17422028508SToomas Soome * Do we have explicit KLD load ?
17522028508SToomas Soome */
17622028508SToomas Soome if (dokld || file_havepath(argv[1])) {
17722028508SToomas Soome error = mod_loadkld(argv[1], argc - 2, argv + 2);
17822028508SToomas Soome if (error == EEXIST) {
179fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
18022028508SToomas Soome "warning: KLD '%s' already loaded", argv[1]);
18122028508SToomas Soome return (CMD_WARN);
18222028508SToomas Soome }
18322028508SToomas Soome
18422028508SToomas Soome return (error == 0 ? CMD_OK : CMD_CRIT);
18522028508SToomas Soome }
18622028508SToomas Soome /*
18722028508SToomas Soome * Looks like a request for a module.
18822028508SToomas Soome */
18922028508SToomas Soome error = mod_load(argv[1], NULL, argc - 2, argv + 2);
19022028508SToomas Soome if (error == EEXIST) {
191fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
19222028508SToomas Soome "warning: module '%s' already loaded", argv[1]);
19322028508SToomas Soome return (CMD_WARN);
19422028508SToomas Soome }
19522028508SToomas Soome
19622028508SToomas Soome return (error == 0 ? CMD_OK : CMD_CRIT);
19722028508SToomas Soome }
19822028508SToomas Soome
19922028508SToomas Soome void
unload(void)20022028508SToomas Soome unload(void)
20122028508SToomas Soome {
20222028508SToomas Soome struct preloaded_file *fp;
20322028508SToomas Soome
20422028508SToomas Soome while (preloaded_files != NULL) {
20522028508SToomas Soome fp = preloaded_files;
20622028508SToomas Soome preloaded_files = preloaded_files->f_next;
20722028508SToomas Soome file_discard(fp);
20822028508SToomas Soome }
20922028508SToomas Soome loadaddr = 0;
210fc39bce2SToomas Soome (void) unsetenv("kernelname");
21122028508SToomas Soome }
21222028508SToomas Soome
21322028508SToomas Soome COMMAND_SET(unload, "unload", "unload all modules", command_unload);
21422028508SToomas Soome
21522028508SToomas Soome static int
command_unload(int argc __unused,char * argv[]__unused)21622028508SToomas Soome command_unload(int argc __unused, char *argv[] __unused)
21722028508SToomas Soome {
21822028508SToomas Soome unload();
21922028508SToomas Soome return (CMD_OK);
22022028508SToomas Soome }
22122028508SToomas Soome
22222028508SToomas Soome COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
22322028508SToomas Soome
22422028508SToomas Soome static int
command_lsmod(int argc,char * argv[])22522028508SToomas Soome command_lsmod(int argc, char *argv[])
22622028508SToomas Soome {
22722028508SToomas Soome struct preloaded_file *fp;
22822028508SToomas Soome struct kernel_module *mp;
22922028508SToomas Soome struct file_metadata *md;
23022028508SToomas Soome char lbuf[80];
23122028508SToomas Soome int ch, verbose, hash, ret = 0;
23222028508SToomas Soome
23322028508SToomas Soome verbose = 0;
23422028508SToomas Soome hash = 0;
23522028508SToomas Soome optind = 1;
23622028508SToomas Soome optreset = 1;
23722028508SToomas Soome while ((ch = getopt(argc, argv, "vs")) != -1) {
23822028508SToomas Soome switch (ch) {
23922028508SToomas Soome case 'v':
24022028508SToomas Soome verbose = 1;
24122028508SToomas Soome break;
24222028508SToomas Soome case 's':
24322028508SToomas Soome hash = 1;
24422028508SToomas Soome break;
24522028508SToomas Soome case '?':
24622028508SToomas Soome default:
24722028508SToomas Soome /* getopt has already reported an error */
24822028508SToomas Soome return (CMD_OK);
24922028508SToomas Soome }
25022028508SToomas Soome }
25122028508SToomas Soome
25222028508SToomas Soome pager_open();
25322028508SToomas Soome for (fp = preloaded_files; fp; fp = fp->f_next) {
254fc39bce2SToomas Soome (void) snprintf(lbuf, sizeof (lbuf), " %p: ",
255fc39bce2SToomas Soome (void *) fp->f_addr);
256fc39bce2SToomas Soome (void) pager_output(lbuf);
257fc39bce2SToomas Soome (void) pager_output(fp->f_name);
258fc39bce2SToomas Soome (void) snprintf(lbuf, sizeof (lbuf), " (%s, 0x%lx)\n",
259fc39bce2SToomas Soome fp->f_type, (long)fp->f_size);
26022028508SToomas Soome if (pager_output(lbuf))
26122028508SToomas Soome break;
26222028508SToomas Soome if (fp->f_args != NULL) {
263fc39bce2SToomas Soome (void) pager_output(" args: ");
264fc39bce2SToomas Soome (void) pager_output(fp->f_args);
26522028508SToomas Soome if (pager_output("\n"))
26622028508SToomas Soome break;
26722028508SToomas Soome if (strcmp(fp->f_type, "hash") == 0) {
268fc39bce2SToomas Soome size_t dsize;
269fc39bce2SToomas Soome
270fc39bce2SToomas Soome (void) pager_output(" contents: ");
271fc39bce2SToomas Soome dsize = fp->f_size + 1;
272fc39bce2SToomas Soome if (sizeof (lbuf) < dsize)
273fc39bce2SToomas Soome dsize = sizeof (lbuf);
274fc39bce2SToomas Soome (void) strlcpy(lbuf, ptov(fp->f_addr), dsize);
27522028508SToomas Soome if (pager_output(lbuf))
27622028508SToomas Soome break;
27722028508SToomas Soome }
27822028508SToomas Soome }
27922028508SToomas Soome
28022028508SToomas Soome if (hash == 1) {
28122028508SToomas Soome void *ptr = PTOV(fp->f_addr);
28222028508SToomas Soome
283fc39bce2SToomas Soome (void) pager_output(" hash: ");
28422028508SToomas Soome sha1(ptr, fp->f_size, (uint8_t *)lbuf);
28522028508SToomas Soome for (int i = 0; i < SHA1_DIGEST_LENGTH; i++)
28622028508SToomas Soome printf("%02x", (int)(lbuf[i] & 0xff));
28722028508SToomas Soome if (pager_output("\n"))
28822028508SToomas Soome break;
28922028508SToomas Soome }
29022028508SToomas Soome
29122028508SToomas Soome if (fp->f_modules) {
292fc39bce2SToomas Soome (void) pager_output(" modules: ");
29322028508SToomas Soome for (mp = fp->f_modules; mp; mp = mp->m_next) {
294fc39bce2SToomas Soome (void) snprintf(lbuf, sizeof (lbuf), "%s.%d ",
295fc39bce2SToomas Soome mp->m_name, mp->m_version);
296fc39bce2SToomas Soome (void) pager_output(lbuf);
29722028508SToomas Soome }
29822028508SToomas Soome if (pager_output("\n"))
29922028508SToomas Soome break;
30022028508SToomas Soome }
30122028508SToomas Soome if (verbose) {
30222028508SToomas Soome /*
30322028508SToomas Soome * XXX could add some formatting smarts here to
30422028508SToomas Soome * display some better
30522028508SToomas Soome */
30622028508SToomas Soome for (md = fp->f_metadata; md != NULL;
30722028508SToomas Soome md = md->md_next) {
308fc39bce2SToomas Soome (void) snprintf(lbuf, sizeof (lbuf),
309fc39bce2SToomas Soome " 0x%04x, 0x%lx\n",
31022028508SToomas Soome md->md_type, (long)md->md_size);
31122028508SToomas Soome if ((ret = pager_output(lbuf)))
31222028508SToomas Soome break;
31322028508SToomas Soome }
31422028508SToomas Soome }
31522028508SToomas Soome if (ret != 0)
31622028508SToomas Soome break;
31722028508SToomas Soome }
31822028508SToomas Soome pager_close();
31922028508SToomas Soome return (CMD_OK);
32022028508SToomas Soome }
32122028508SToomas Soome
32222028508SToomas Soome /*
32322028508SToomas Soome * File level interface, functions file_*
32422028508SToomas Soome */
32522028508SToomas Soome int
file_load(char * filename,vm_offset_t dest,struct preloaded_file ** result)32622028508SToomas Soome file_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
32722028508SToomas Soome {
32822028508SToomas Soome static int last_file_format = 0;
32922028508SToomas Soome struct preloaded_file *fp;
33022028508SToomas Soome int error;
33122028508SToomas Soome int i;
33222028508SToomas Soome
33322028508SToomas Soome if (preloaded_files == NULL)
33422028508SToomas Soome last_file_format = 0;
33522028508SToomas Soome
33622028508SToomas Soome if (archsw.arch_loadaddr != NULL)
33722028508SToomas Soome dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest);
33822028508SToomas Soome
33922028508SToomas Soome error = EFTYPE;
34022028508SToomas Soome for (i = last_file_format, fp = NULL;
34122028508SToomas Soome file_formats[i] && fp == NULL; i++) {
34222028508SToomas Soome error = (file_formats[i]->l_load)(filename, dest, &fp);
34322028508SToomas Soome if (error == 0) {
34422028508SToomas Soome /* remember the loader */
34522028508SToomas Soome fp->f_loader = last_file_format = i;
34622028508SToomas Soome *result = fp;
34722028508SToomas Soome break;
34822028508SToomas Soome } else if (last_file_format == i && i != 0) {
34922028508SToomas Soome /* Restart from the beginning */
35022028508SToomas Soome i = -1;
35122028508SToomas Soome last_file_format = 0;
35222028508SToomas Soome fp = NULL;
35322028508SToomas Soome continue;
35422028508SToomas Soome }
35522028508SToomas Soome if (error == EFTYPE)
35622028508SToomas Soome continue; /* Unknown to this handler? */
35722028508SToomas Soome if (error) {
358fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
35922028508SToomas Soome "can't load file '%s': %s", filename,
36022028508SToomas Soome strerror(error));
36122028508SToomas Soome break;
36222028508SToomas Soome }
36322028508SToomas Soome }
36422028508SToomas Soome return (error);
36522028508SToomas Soome }
36622028508SToomas Soome
36722028508SToomas Soome static int
file_load_dependencies(struct preloaded_file * base_file)36822028508SToomas Soome file_load_dependencies(struct preloaded_file *base_file)
36922028508SToomas Soome {
37022028508SToomas Soome struct file_metadata *md;
37122028508SToomas Soome struct preloaded_file *fp;
37222028508SToomas Soome struct mod_depend *verinfo;
37322028508SToomas Soome struct kernel_module *mp;
37422028508SToomas Soome char *dmodname;
37522028508SToomas Soome int error;
37622028508SToomas Soome
37722028508SToomas Soome md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
37822028508SToomas Soome if (md == NULL)
37922028508SToomas Soome return (0);
38022028508SToomas Soome error = 0;
38122028508SToomas Soome do {
38222028508SToomas Soome verinfo = (struct mod_depend *)md->md_data;
38322028508SToomas Soome dmodname = (char *)(verinfo + 1);
38422028508SToomas Soome if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
38522028508SToomas Soome printf("loading required module '%s'\n", dmodname);
38622028508SToomas Soome error = mod_load(dmodname, verinfo, 0, NULL);
38722028508SToomas Soome if (error)
38822028508SToomas Soome break;
38922028508SToomas Soome /*
39022028508SToomas Soome * If module loaded via kld name which isn't listed
39122028508SToomas Soome * in the linker.hints file, we should check if it have
39222028508SToomas Soome * required version.
39322028508SToomas Soome */
39422028508SToomas Soome mp = file_findmodule(NULL, dmodname, verinfo);
39522028508SToomas Soome if (mp == NULL) {
396fc39bce2SToomas Soome (void) snprintf(command_errbuf,
39722028508SToomas Soome sizeof (command_errbuf),
39822028508SToomas Soome "module '%s' exists but with wrong version",
39922028508SToomas Soome dmodname);
40022028508SToomas Soome error = ENOENT;
40122028508SToomas Soome break;
40222028508SToomas Soome }
40322028508SToomas Soome }
40422028508SToomas Soome md = metadata_next(md, MODINFOMD_DEPLIST);
40522028508SToomas Soome } while (md);
40622028508SToomas Soome if (!error)
40722028508SToomas Soome return (0);
40822028508SToomas Soome /* Load failed; discard everything */
40922028508SToomas Soome while (base_file != NULL) {
41022028508SToomas Soome fp = base_file;
41122028508SToomas Soome base_file = base_file->f_next;
41222028508SToomas Soome file_discard(fp);
41322028508SToomas Soome }
41422028508SToomas Soome return (error);
41522028508SToomas Soome }
41622028508SToomas Soome
41722028508SToomas Soome /*
41822028508SToomas Soome * Calculate the size of the environment module.
41922028508SToomas Soome * The environment is list of name=value C strings, ending with a '\0' byte.
42022028508SToomas Soome */
42122028508SToomas Soome static size_t
env_get_size(void)42222028508SToomas Soome env_get_size(void)
42322028508SToomas Soome {
42422028508SToomas Soome size_t size = 0;
42522028508SToomas Soome struct env_var *ep;
42622028508SToomas Soome
42722028508SToomas Soome /* Traverse the environment. */
42822028508SToomas Soome for (ep = environ; ep != NULL; ep = ep->ev_next) {
42922028508SToomas Soome size += strlen(ep->ev_name);
43022028508SToomas Soome size++; /* "=" */
43122028508SToomas Soome if (ep->ev_value != NULL)
43222028508SToomas Soome size += strlen(ep->ev_value);
43322028508SToomas Soome size++; /* nul byte */
43422028508SToomas Soome }
43522028508SToomas Soome size++; /* nul byte */
43622028508SToomas Soome return (size);
43722028508SToomas Soome }
43822028508SToomas Soome
43922028508SToomas Soome static void
module_hash(struct preloaded_file * fp,void * addr,size_t size)44022028508SToomas Soome module_hash(struct preloaded_file *fp, void *addr, size_t size)
44122028508SToomas Soome {
44222028508SToomas Soome uint8_t hash[SHA1_DIGEST_LENGTH];
44322028508SToomas Soome char ascii[2 * SHA1_DIGEST_LENGTH + 1];
44422028508SToomas Soome int i;
44522028508SToomas Soome
44622028508SToomas Soome sha1(addr, size, hash);
44722028508SToomas Soome for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
448fc39bce2SToomas Soome (void) snprintf(ascii + 2 * i, sizeof (ascii) - 2 * i, "%02x",
44922028508SToomas Soome hash[i] & 0xff);
45022028508SToomas Soome }
45122028508SToomas Soome /* Out of memory here is not fatal issue. */
452fc39bce2SToomas Soome (void) asprintf(&fp->f_args, "hash=%s", ascii);
45322028508SToomas Soome }
45422028508SToomas Soome
45522028508SToomas Soome /*
45622028508SToomas Soome * Create virtual module for environment variables.
45722028508SToomas Soome * This module should be created as late as possible before executing
45822028508SToomas Soome * the OS kernel, or we may miss some environment variable updates.
45922028508SToomas Soome */
46022028508SToomas Soome void
build_environment_module(void)46122028508SToomas Soome build_environment_module(void)
46222028508SToomas Soome {
46322028508SToomas Soome struct preloaded_file *fp;
46422028508SToomas Soome size_t size;
46522028508SToomas Soome char *name = "environment";
46622028508SToomas Soome vm_offset_t laddr;
46722028508SToomas Soome
46822028508SToomas Soome /* We can't load first */
469ab4969f8SToomas Soome if (file_findfile(NULL, NULL) == NULL) {
47022028508SToomas Soome printf("Can not load environment module: %s\n",
47122028508SToomas Soome "the kernel is not loaded");
47222028508SToomas Soome return;
47322028508SToomas Soome }
47422028508SToomas Soome
475ab4969f8SToomas Soome if (file_findfile(name, name) != NULL) {
476ab4969f8SToomas Soome printf("warning: '%s' is already loaded\n", name);
477ab4969f8SToomas Soome return;
478ab4969f8SToomas Soome }
479ab4969f8SToomas Soome
48022028508SToomas Soome tem_save_state(); /* Ask tem to save it's state in env. */
48122028508SToomas Soome size = env_get_size();
48222028508SToomas Soome
48322028508SToomas Soome fp = file_alloc();
48422028508SToomas Soome if (fp != NULL) {
48522028508SToomas Soome fp->f_name = strdup(name);
48622028508SToomas Soome fp->f_type = strdup(name);
48722028508SToomas Soome }
48822028508SToomas Soome
48922028508SToomas Soome if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) {
49022028508SToomas Soome printf("Can not load environment module: %s\n",
49122028508SToomas Soome "out of memory");
49222028508SToomas Soome file_discard(fp);
49322028508SToomas Soome return;
49422028508SToomas Soome }
49522028508SToomas Soome
49622028508SToomas Soome
49722028508SToomas Soome if (archsw.arch_loadaddr != NULL)
49822028508SToomas Soome loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr);
49922028508SToomas Soome
50022028508SToomas Soome if (loadaddr == 0) {
50122028508SToomas Soome printf("Can not load environment module: %s\n",
50222028508SToomas Soome "out of memory");
50322028508SToomas Soome file_discard(fp);
50422028508SToomas Soome return;
50522028508SToomas Soome }
50622028508SToomas Soome
50722028508SToomas Soome laddr = bi_copyenv(loadaddr);
50822028508SToomas Soome /* Looks OK so far; populate control structure */
50922028508SToomas Soome module_hash(fp, PTOV(loadaddr), laddr - loadaddr);
51022028508SToomas Soome fp->f_loader = -1;
51122028508SToomas Soome fp->f_addr = loadaddr;
51222028508SToomas Soome fp->f_size = laddr - loadaddr;
51322028508SToomas Soome
51422028508SToomas Soome /* recognise space consumption */
51522028508SToomas Soome loadaddr = laddr;
51622028508SToomas Soome
51722028508SToomas Soome file_insert_tail(fp);
51822028508SToomas Soome }
51922028508SToomas Soome
52022028508SToomas Soome void
build_font_module(void)52122028508SToomas Soome build_font_module(void)
52222028508SToomas Soome {
52322028508SToomas Soome bitmap_data_t *bd;
52422028508SToomas Soome struct font *fd;
52522028508SToomas Soome struct preloaded_file *fp;
52622028508SToomas Soome size_t size;
52722028508SToomas Soome uint32_t checksum;
52822028508SToomas Soome int i;
52922028508SToomas Soome char *name = "console-font";
53022028508SToomas Soome vm_offset_t laddr;
53122028508SToomas Soome struct font_info fi;
53222028508SToomas Soome struct fontlist *fl;
53322028508SToomas Soome
53422028508SToomas Soome if (STAILQ_EMPTY(&fonts))
53522028508SToomas Soome return;
53622028508SToomas Soome
53722028508SToomas Soome /* We can't load first */
538ab4969f8SToomas Soome if (file_findfile(NULL, NULL) == NULL) {
53922028508SToomas Soome printf("Can not load font module: %s\n",
54022028508SToomas Soome "the kernel is not loaded");
54122028508SToomas Soome return;
54222028508SToomas Soome }
54322028508SToomas Soome
544ab4969f8SToomas Soome if (file_findfile(name, name) != NULL) {
545ab4969f8SToomas Soome printf("warning: '%s' is already loaded\n", name);
546ab4969f8SToomas Soome return;
547ab4969f8SToomas Soome }
548ab4969f8SToomas Soome
54922028508SToomas Soome /* helper pointers */
55022028508SToomas Soome bd = NULL;
55122028508SToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) {
55222028508SToomas Soome if (tems.ts_font.vf_width == fl->font_data->width &&
55322028508SToomas Soome tems.ts_font.vf_height == fl->font_data->height) {
55422028508SToomas Soome /*
55522028508SToomas Soome * Kernel does have better built in font.
55622028508SToomas Soome */
55722028508SToomas Soome if (fl->font_flags == FONT_BUILTIN)
55822028508SToomas Soome return;
55922028508SToomas Soome
56022028508SToomas Soome bd = fl->font_data;
56122028508SToomas Soome break;
56222028508SToomas Soome }
56322028508SToomas Soome }
56422028508SToomas Soome if (bd == NULL)
56522028508SToomas Soome return;
56622028508SToomas Soome fd = bd->font;
56722028508SToomas Soome
56822028508SToomas Soome fi.fi_width = fd->vf_width;
56922028508SToomas Soome checksum = fi.fi_width;
57022028508SToomas Soome fi.fi_height = fd->vf_height;
57122028508SToomas Soome checksum += fi.fi_height;
57222028508SToomas Soome fi.fi_bitmap_size = bd->uncompressed_size;
57322028508SToomas Soome checksum += fi.fi_bitmap_size;
57422028508SToomas Soome
57522028508SToomas Soome size = roundup2(sizeof (struct font_info), 8);
57622028508SToomas Soome for (i = 0; i < VFNT_MAPS; i++) {
57722028508SToomas Soome fi.fi_map_count[i] = fd->vf_map_count[i];
57822028508SToomas Soome checksum += fi.fi_map_count[i];
57922028508SToomas Soome size += fd->vf_map_count[i] * sizeof (struct font_map);
58022028508SToomas Soome size += roundup2(size, 8);
58122028508SToomas Soome }
58222028508SToomas Soome size += bd->uncompressed_size;
58322028508SToomas Soome
58422028508SToomas Soome fi.fi_checksum = -checksum;
58522028508SToomas Soome
58622028508SToomas Soome fp = file_alloc();
58722028508SToomas Soome if (fp != NULL) {
58822028508SToomas Soome fp->f_name = strdup(name);
58922028508SToomas Soome fp->f_type = strdup(name);
59022028508SToomas Soome }
59122028508SToomas Soome
59222028508SToomas Soome if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) {
59322028508SToomas Soome printf("Can not load font module: %s\n",
59422028508SToomas Soome "out of memory");
59522028508SToomas Soome file_discard(fp);
59622028508SToomas Soome return;
59722028508SToomas Soome }
59822028508SToomas Soome
59922028508SToomas Soome if (archsw.arch_loadaddr != NULL)
60022028508SToomas Soome loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr);
60122028508SToomas Soome
60222028508SToomas Soome if (loadaddr == 0) {
60322028508SToomas Soome printf("Can not load font module: %s\n",
60422028508SToomas Soome "out of memory");
60522028508SToomas Soome file_discard(fp);
60622028508SToomas Soome return;
60722028508SToomas Soome }
60822028508SToomas Soome
60922028508SToomas Soome laddr = loadaddr;
61022028508SToomas Soome laddr += archsw.arch_copyin(&fi, laddr, sizeof (struct font_info));
61122028508SToomas Soome laddr = roundup2(laddr, 8);
61222028508SToomas Soome
61322028508SToomas Soome /* Copy maps. */
61422028508SToomas Soome for (i = 0; i < VFNT_MAPS; i++) {
61522028508SToomas Soome if (fd->vf_map_count[i] != 0) {
61622028508SToomas Soome laddr += archsw.arch_copyin(fd->vf_map[i], laddr,
61722028508SToomas Soome fd->vf_map_count[i] * sizeof (struct font_map));
61822028508SToomas Soome laddr = roundup2(laddr, 8);
61922028508SToomas Soome }
62022028508SToomas Soome }
62122028508SToomas Soome
62222028508SToomas Soome /* Copy the bitmap. */
62322028508SToomas Soome laddr += archsw.arch_copyin(fd->vf_bytes, laddr, fi.fi_bitmap_size);
62422028508SToomas Soome
62522028508SToomas Soome /* Looks OK so far; populate control structure */
62622028508SToomas Soome module_hash(fp, PTOV(loadaddr), laddr - loadaddr);
62722028508SToomas Soome fp->f_loader = -1;
62822028508SToomas Soome fp->f_addr = loadaddr;
62922028508SToomas Soome fp->f_size = laddr - loadaddr;
63022028508SToomas Soome
63122028508SToomas Soome /* recognise space consumption */
63222028508SToomas Soome loadaddr = laddr;
63322028508SToomas Soome
63422028508SToomas Soome file_insert_tail(fp);
63522028508SToomas Soome }
63622028508SToomas Soome
63722028508SToomas Soome /*
63822028508SToomas Soome * We've been asked to load (fname) as (type), so just suck it in,
63922028508SToomas Soome * no arguments or anything.
64022028508SToomas Soome */
64122028508SToomas Soome struct preloaded_file *
file_loadraw(const char * fname,char * type,int argc,char ** argv,int insert)64222028508SToomas Soome file_loadraw(const char *fname, char *type, int argc, char **argv, int insert)
64322028508SToomas Soome {
64422028508SToomas Soome struct preloaded_file *fp;
64522028508SToomas Soome char *name;
646*9fbdb45aSToomas Soome int fd;
647*9fbdb45aSToomas Soome ssize_t got;
64822028508SToomas Soome struct stat st;
64922028508SToomas Soome
65022028508SToomas Soome /* We can't load first */
65122028508SToomas Soome if ((file_findfile(NULL, NULL)) == NULL) {
65222028508SToomas Soome command_errmsg = "can't load file before kernel";
65322028508SToomas Soome return (NULL);
65422028508SToomas Soome }
65522028508SToomas Soome
65622028508SToomas Soome /* locate the file on the load path */
65722028508SToomas Soome name = file_search(fname, NULL);
65822028508SToomas Soome if (name == NULL) {
659fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
66022028508SToomas Soome "can't find '%s'", fname);
66122028508SToomas Soome return (NULL);
66222028508SToomas Soome }
66322028508SToomas Soome
66422028508SToomas Soome if ((fd = open(name, O_RDONLY)) < 0) {
665fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
66622028508SToomas Soome "can't open '%s': %s", name, strerror(errno));
66722028508SToomas Soome free(name);
66822028508SToomas Soome return (NULL);
66922028508SToomas Soome }
67022028508SToomas Soome if (fstat(fd, &st) < 0) {
671fc39bce2SToomas Soome (void) close(fd);
672fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
67322028508SToomas Soome "stat error '%s': %s", name, strerror(errno));
67422028508SToomas Soome free(name);
67522028508SToomas Soome return (NULL);
67622028508SToomas Soome }
67722028508SToomas Soome
67822028508SToomas Soome if (archsw.arch_loadaddr != NULL)
67922028508SToomas Soome loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
68022028508SToomas Soome if (loadaddr == 0) {
681fc39bce2SToomas Soome (void) close(fd);
682fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
68322028508SToomas Soome "no memory to load %s", name);
68422028508SToomas Soome free(name);
68522028508SToomas Soome return (NULL);
68622028508SToomas Soome }
68722028508SToomas Soome
688*9fbdb45aSToomas Soome got = archsw.arch_readin(fd, loadaddr, st.st_size);
689*9fbdb45aSToomas Soome if ((size_t)got != st.st_size) {
690fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
69122028508SToomas Soome "error reading '%s': %s", name, strerror(errno));
69222028508SToomas Soome free(name);
693fc39bce2SToomas Soome (void) close(fd);
694*9fbdb45aSToomas Soome if (archsw.arch_free_loadaddr != NULL && st.st_size != 0) {
69522028508SToomas Soome archsw.arch_free_loadaddr(loadaddr,
696*9fbdb45aSToomas Soome (uint64_t)(roundup2(st.st_size, PAGE_SIZE) >> 12));
69722028508SToomas Soome }
69822028508SToomas Soome return (NULL);
69922028508SToomas Soome }
70022028508SToomas Soome
70122028508SToomas Soome /* Looks OK so far; create & populate control structure */
70222028508SToomas Soome fp = file_alloc();
70322028508SToomas Soome if (fp == NULL) {
70422028508SToomas Soome if (archsw.arch_free_loadaddr != NULL && st.st_size != 0)
70522028508SToomas Soome archsw.arch_free_loadaddr(loadaddr,
70622028508SToomas Soome (uint64_t)(roundup2(st.st_size, PAGE_SIZE) >> 12));
707fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
70822028508SToomas Soome "no memory to load %s", name);
70922028508SToomas Soome free(name);
710fc39bce2SToomas Soome (void) close(fd);
71122028508SToomas Soome return (NULL);
71222028508SToomas Soome }
71322028508SToomas Soome
71422028508SToomas Soome fp->f_name = name;
71522028508SToomas Soome fp->f_args = unargv(argc, argv);
71622028508SToomas Soome fp->f_type = strdup(type);
71722028508SToomas Soome fp->f_metadata = NULL;
71822028508SToomas Soome fp->f_loader = -1;
71922028508SToomas Soome fp->f_addr = loadaddr;
720*9fbdb45aSToomas Soome fp->f_size = st.st_size;
72122028508SToomas Soome
72222028508SToomas Soome if (fp->f_type == NULL ||
72322028508SToomas Soome (argc != 0 && fp->f_args == NULL)) {
724fc39bce2SToomas Soome (void) close(fd);
725fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
72622028508SToomas Soome "no memory to load %s", name);
72722028508SToomas Soome file_discard(fp);
72822028508SToomas Soome return (NULL);
72922028508SToomas Soome }
73022028508SToomas Soome /* recognise space consumption */
731*9fbdb45aSToomas Soome loadaddr += st.st_size;
73222028508SToomas Soome
73322028508SToomas Soome /* Add to the list of loaded files */
73422028508SToomas Soome if (insert != 0)
73522028508SToomas Soome file_insert_tail(fp);
736fc39bce2SToomas Soome (void) close(fd);
73722028508SToomas Soome return (fp);
73822028508SToomas Soome }
73922028508SToomas Soome
74022028508SToomas Soome /*
74122028508SToomas Soome * Load the module (name), pass it (argc),(argv), add container file
74222028508SToomas Soome * to the list of loaded files.
74322028508SToomas Soome * If module is already loaded just assign new argc/argv.
74422028508SToomas Soome */
74522028508SToomas Soome int
mod_load(char * modname,struct mod_depend * verinfo,int argc,char * argv[])74622028508SToomas Soome mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
74722028508SToomas Soome {
74822028508SToomas Soome struct kernel_module *mp;
74922028508SToomas Soome int err;
75022028508SToomas Soome char *filename;
75122028508SToomas Soome
75222028508SToomas Soome if (file_havepath(modname)) {
75322028508SToomas Soome printf("Warning: mod_load() called instead of mod_loadkld() "
75422028508SToomas Soome "for module '%s'\n", modname);
75522028508SToomas Soome return (mod_loadkld(modname, argc, argv));
75622028508SToomas Soome }
75722028508SToomas Soome /* see if module is already loaded */
75822028508SToomas Soome mp = file_findmodule(NULL, modname, verinfo);
75922028508SToomas Soome if (mp != NULL) {
76022028508SToomas Soome free(mp->m_args);
76122028508SToomas Soome mp->m_args = unargv(argc, argv);
762fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
76322028508SToomas Soome "warning: module '%s' already loaded", mp->m_name);
76422028508SToomas Soome return (0);
76522028508SToomas Soome }
76622028508SToomas Soome /* locate file with the module on the search path */
76722028508SToomas Soome filename = mod_searchmodule(modname, verinfo);
76822028508SToomas Soome if (filename == NULL) {
769fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
77022028508SToomas Soome "can't find '%s'", modname);
77122028508SToomas Soome return (ENOENT);
77222028508SToomas Soome }
77322028508SToomas Soome err = mod_loadkld(filename, argc, argv);
77422028508SToomas Soome free(filename);
77522028508SToomas Soome return (err);
77622028508SToomas Soome }
77722028508SToomas Soome
77822028508SToomas Soome /*
77922028508SToomas Soome * Load specified KLD. If path is omitted, then try to locate it via
78022028508SToomas Soome * search path.
78122028508SToomas Soome */
78222028508SToomas Soome int
mod_loadkld(const char * kldname,int argc,char * argv[])78322028508SToomas Soome mod_loadkld(const char *kldname, int argc, char *argv[])
78422028508SToomas Soome {
78522028508SToomas Soome struct preloaded_file *fp;
78622028508SToomas Soome int err;
78722028508SToomas Soome char *filename;
78822028508SToomas Soome vm_offset_t loadaddr_saved;
78922028508SToomas Soome
79022028508SToomas Soome /*
79122028508SToomas Soome * Get fully qualified KLD name
79222028508SToomas Soome */
79322028508SToomas Soome filename = file_search(kldname, kld_ext_list);
79422028508SToomas Soome if (filename == NULL) {
795fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
79622028508SToomas Soome "can't find '%s'", kldname);
79722028508SToomas Soome return (ENOENT);
79822028508SToomas Soome }
79922028508SToomas Soome /*
80022028508SToomas Soome * Check if KLD already loaded
80122028508SToomas Soome */
80222028508SToomas Soome fp = file_findfile(filename, NULL);
80322028508SToomas Soome if (fp != NULL) {
804fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
80522028508SToomas Soome "warning: KLD '%s' already loaded", filename);
80622028508SToomas Soome free(filename);
80722028508SToomas Soome return (0);
80822028508SToomas Soome }
80922028508SToomas Soome
81022028508SToomas Soome do {
81122028508SToomas Soome err = file_load(filename, loadaddr, &fp);
81222028508SToomas Soome if (err)
81322028508SToomas Soome break;
81422028508SToomas Soome fp->f_args = unargv(argc, argv);
81522028508SToomas Soome loadaddr_saved = loadaddr;
81622028508SToomas Soome loadaddr = fp->f_addr + fp->f_size;
81722028508SToomas Soome file_insert_tail(fp); /* Add to the list of loaded files */
81822028508SToomas Soome if (file_load_dependencies(fp) != 0) {
81922028508SToomas Soome err = ENOENT;
82022028508SToomas Soome file_remove(fp);
82122028508SToomas Soome loadaddr = loadaddr_saved;
82222028508SToomas Soome fp = NULL;
82322028508SToomas Soome break;
82422028508SToomas Soome }
82522028508SToomas Soome } while (0);
82622028508SToomas Soome if (err == EFTYPE) {
827fc39bce2SToomas Soome (void) snprintf(command_errbuf, sizeof (command_errbuf),
82822028508SToomas Soome "don't know how to load module '%s'", filename);
82922028508SToomas Soome }
83022028508SToomas Soome if (err)
83122028508SToomas Soome file_discard(fp);
83222028508SToomas Soome free(filename);
83322028508SToomas Soome return (err);
83422028508SToomas Soome }
83522028508SToomas Soome
83622028508SToomas Soome /*
83722028508SToomas Soome * Find a file matching (name) and (type).
83822028508SToomas Soome * NULL may be passed as a wildcard to either.
83922028508SToomas Soome */
84022028508SToomas Soome struct preloaded_file *
file_findfile(const char * name,const char * type)84122028508SToomas Soome file_findfile(const char *name, const char *type)
84222028508SToomas Soome {
84322028508SToomas Soome struct preloaded_file *fp;
84422028508SToomas Soome
84522028508SToomas Soome for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
84622028508SToomas Soome if (((name == NULL) || strcmp(name, fp->f_name) == 0) &&
84722028508SToomas Soome ((type == NULL) || strcmp(type, fp->f_type) == 0))
84822028508SToomas Soome break;
84922028508SToomas Soome }
85022028508SToomas Soome return (fp);
85122028508SToomas Soome }
85222028508SToomas Soome
85322028508SToomas Soome /*
85422028508SToomas Soome * Find a module matching (name) inside of given file.
85522028508SToomas Soome * NULL may be passed as a wildcard.
85622028508SToomas Soome */
85722028508SToomas Soome struct kernel_module *
file_findmodule(struct preloaded_file * fp,char * modname,struct mod_depend * verinfo)85822028508SToomas Soome file_findmodule(struct preloaded_file *fp, char *modname,
85922028508SToomas Soome struct mod_depend *verinfo)
86022028508SToomas Soome {
86122028508SToomas Soome struct kernel_module *mp, *best;
86222028508SToomas Soome int bestver, mver;
86322028508SToomas Soome
86422028508SToomas Soome if (fp == NULL) {
86522028508SToomas Soome for (fp = preloaded_files; fp; fp = fp->f_next) {
86622028508SToomas Soome mp = file_findmodule(fp, modname, verinfo);
86722028508SToomas Soome if (mp != NULL)
86822028508SToomas Soome return (mp);
86922028508SToomas Soome }
87022028508SToomas Soome return (NULL);
87122028508SToomas Soome }
87222028508SToomas Soome best = NULL;
87322028508SToomas Soome bestver = 0;
87422028508SToomas Soome for (mp = fp->f_modules; mp; mp = mp->m_next) {
87522028508SToomas Soome if (strcmp(modname, mp->m_name) == 0) {
87622028508SToomas Soome if (verinfo == NULL)
87722028508SToomas Soome return (mp);
87822028508SToomas Soome mver = mp->m_version;
87922028508SToomas Soome if (mver == verinfo->md_ver_preferred)
88022028508SToomas Soome return (mp);
88122028508SToomas Soome if (mver >= verinfo->md_ver_minimum &&
88222028508SToomas Soome mver <= verinfo->md_ver_maximum &&
88322028508SToomas Soome mver > bestver) {
88422028508SToomas Soome best = mp;
88522028508SToomas Soome bestver = mver;
88622028508SToomas Soome }
88722028508SToomas Soome }
88822028508SToomas Soome }
88922028508SToomas Soome return (best);
89022028508SToomas Soome }
89122028508SToomas Soome /*
89222028508SToomas Soome * Make a copy of (size) bytes of data from (p), and associate them as
89322028508SToomas Soome * metadata of (type) to the module (mp).
89422028508SToomas Soome */
89522028508SToomas Soome void
file_addmetadata(struct preloaded_file * fp,int type,size_t size,void * p)89622028508SToomas Soome file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
89722028508SToomas Soome {
89822028508SToomas Soome struct file_metadata *md;
89922028508SToomas Soome
90022028508SToomas Soome md = malloc(sizeof (struct file_metadata) - sizeof (md->md_data) +
90122028508SToomas Soome size);
90222028508SToomas Soome if (md != NULL) {
90322028508SToomas Soome md->md_size = size;
90422028508SToomas Soome md->md_type = type;
90522028508SToomas Soome bcopy(p, md->md_data, size);
90622028508SToomas Soome md->md_next = fp->f_metadata;
90722028508SToomas Soome }
90822028508SToomas Soome fp->f_metadata = md;
90922028508SToomas Soome }
91022028508SToomas Soome
91122028508SToomas Soome /*
91222028508SToomas Soome * Find a metadata object of (type) associated with the file (fp)
91322028508SToomas Soome */
91422028508SToomas Soome struct file_metadata *
file_findmetadata(struct preloaded_file * fp,int type)91522028508SToomas Soome file_findmetadata(struct preloaded_file *fp, int type)
91622028508SToomas Soome {
91722028508SToomas Soome struct file_metadata *md;
91822028508SToomas Soome
91922028508SToomas Soome for (md = fp->f_metadata; md != NULL; md = md->md_next)
92022028508SToomas Soome if (md->md_type == type)
92122028508SToomas Soome break;
92222028508SToomas Soome return (md);
92322028508SToomas Soome }
92422028508SToomas Soome
92522028508SToomas Soome struct file_metadata *
metadata_next(struct file_metadata * md,int type)92622028508SToomas Soome metadata_next(struct file_metadata *md, int type)
92722028508SToomas Soome {
92822028508SToomas Soome
92922028508SToomas Soome if (md == NULL)
93022028508SToomas Soome return (NULL);
93122028508SToomas Soome while ((md = md->md_next) != NULL)
93222028508SToomas Soome if (md->md_type == type)
93322028508SToomas Soome break;
93422028508SToomas Soome return (md);
93522028508SToomas Soome }
93622028508SToomas Soome
93722028508SToomas Soome static const char *emptyextlist[] = { "", NULL };
93822028508SToomas Soome
93922028508SToomas Soome /*
94022028508SToomas Soome * Check if the given file is in place and return full path to it.
94122028508SToomas Soome */
94222028508SToomas Soome static char *
file_lookup(const char * path,const char * name,int namelen,const char ** extlist)94322028508SToomas Soome file_lookup(const char *path, const char *name, int namelen,
94422028508SToomas Soome const char **extlist)
94522028508SToomas Soome {
94622028508SToomas Soome struct stat st;
94722028508SToomas Soome char *result, *cp;
94822028508SToomas Soome const char **cpp;
94922028508SToomas Soome int pathlen, extlen, len;
95022028508SToomas Soome
95122028508SToomas Soome pathlen = strlen(path);
95222028508SToomas Soome extlen = 0;
95322028508SToomas Soome if (extlist == NULL)
95422028508SToomas Soome extlist = emptyextlist;
95522028508SToomas Soome for (cpp = extlist; *cpp; cpp++) {
95622028508SToomas Soome len = strlen(*cpp);
95722028508SToomas Soome if (len > extlen)
95822028508SToomas Soome extlen = len;
95922028508SToomas Soome }
96022028508SToomas Soome result = malloc(pathlen + namelen + extlen + 2);
96122028508SToomas Soome if (result == NULL)
96222028508SToomas Soome return (NULL);
96322028508SToomas Soome bcopy(path, result, pathlen);
96422028508SToomas Soome if (pathlen > 0 && result[pathlen - 1] != '/')
96522028508SToomas Soome result[pathlen++] = '/';
96622028508SToomas Soome cp = result + pathlen;
96722028508SToomas Soome bcopy(name, cp, namelen);
96822028508SToomas Soome cp += namelen;
96922028508SToomas Soome for (cpp = extlist; *cpp; cpp++) {
970fc39bce2SToomas Soome (void) strcpy(cp, *cpp);
97122028508SToomas Soome if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
97222028508SToomas Soome return (result);
97322028508SToomas Soome }
97422028508SToomas Soome free(result);
97522028508SToomas Soome return (NULL);
97622028508SToomas Soome }
97722028508SToomas Soome
97822028508SToomas Soome /*
97922028508SToomas Soome * Check if file name have any qualifiers
98022028508SToomas Soome */
98122028508SToomas Soome static int
file_havepath(const char * name)98222028508SToomas Soome file_havepath(const char *name)
98322028508SToomas Soome {
98422028508SToomas Soome const char *cp;
98522028508SToomas Soome
986fc39bce2SToomas Soome (void) archsw.arch_getdev(NULL, name, &cp);
98722028508SToomas Soome return (cp != name || strchr(name, '/') != NULL);
98822028508SToomas Soome }
98922028508SToomas Soome
99022028508SToomas Soome /*
99122028508SToomas Soome * Attempt to find the file (name) on the module searchpath.
99222028508SToomas Soome * If (name) is qualified in any way, we simply check it and
99322028508SToomas Soome * return it or NULL. If it is not qualified, then we attempt
99422028508SToomas Soome * to construct a path using entries in the environment variable
99522028508SToomas Soome * module_path.
99622028508SToomas Soome *
99722028508SToomas Soome * The path we return a pointer to need never be freed, as we manage
99822028508SToomas Soome * it internally.
99922028508SToomas Soome */
100022028508SToomas Soome static char *
file_search(const char * name,const char ** extlist)100122028508SToomas Soome file_search(const char *name, const char **extlist)
100222028508SToomas Soome {
100322028508SToomas Soome struct moduledir *mdp;
100422028508SToomas Soome struct stat sb;
100522028508SToomas Soome char *result;
100622028508SToomas Soome int namelen;
100722028508SToomas Soome
100822028508SToomas Soome /* Don't look for nothing */
100922028508SToomas Soome if (name == NULL)
101022028508SToomas Soome return (NULL);
101122028508SToomas Soome
101222028508SToomas Soome if (*name == '\0')
101322028508SToomas Soome return (strdup(name));
101422028508SToomas Soome
101522028508SToomas Soome if (file_havepath(name)) {
101622028508SToomas Soome /* Qualified, so just see if it exists */
101722028508SToomas Soome if (stat(name, &sb) == 0)
101822028508SToomas Soome return (strdup(name));
101922028508SToomas Soome return (NULL);
102022028508SToomas Soome }
102122028508SToomas Soome moduledir_rebuild();
102222028508SToomas Soome result = NULL;
102322028508SToomas Soome namelen = strlen(name);
102422028508SToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
102522028508SToomas Soome result = file_lookup(mdp->d_path, name, namelen, extlist);
102622028508SToomas Soome if (result != NULL)
102722028508SToomas Soome break;
102822028508SToomas Soome }
102922028508SToomas Soome return (result);
103022028508SToomas Soome }
103122028508SToomas Soome
103222028508SToomas Soome #define INT_ALIGN(base, ptr) ptr = \
103322028508SToomas Soome (base) + (((ptr) - (base) + sizeof (int) - 1) & ~(sizeof (int) - 1))
103422028508SToomas Soome
103522028508SToomas Soome static char *
mod_search_hints(struct moduledir * mdp,const char * modname,struct mod_depend * verinfo)103622028508SToomas Soome mod_search_hints(struct moduledir *mdp, const char *modname,
103722028508SToomas Soome struct mod_depend *verinfo)
103822028508SToomas Soome {
103922028508SToomas Soome uchar_t *cp, *recptr, *bufend, *best;
104022028508SToomas Soome char *result;
104122028508SToomas Soome int *intp, bestver, blen, clen, ival, modnamelen, reclen;
104222028508SToomas Soome bool found;
104322028508SToomas Soome
104422028508SToomas Soome moduledir_readhints(mdp);
104522028508SToomas Soome modnamelen = strlen(modname);
104622028508SToomas Soome found = false;
104722028508SToomas Soome result = NULL;
104822028508SToomas Soome bestver = 0;
104922028508SToomas Soome if (mdp->d_hints == NULL)
105022028508SToomas Soome goto bad;
105122028508SToomas Soome recptr = mdp->d_hints;
105222028508SToomas Soome bufend = recptr + mdp->d_hintsz;
105322028508SToomas Soome clen = blen = 0;
105422028508SToomas Soome best = cp = NULL;
105522028508SToomas Soome while (recptr < bufend && !found) {
105622028508SToomas Soome intp = (int *)recptr;
105722028508SToomas Soome reclen = *intp++;
105822028508SToomas Soome ival = *intp++;
105922028508SToomas Soome cp = (uchar_t *)intp;
106022028508SToomas Soome switch (ival) {
106122028508SToomas Soome case MDT_VERSION:
106222028508SToomas Soome clen = *cp++;
106322028508SToomas Soome if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
106422028508SToomas Soome break;
106522028508SToomas Soome cp += clen;
106622028508SToomas Soome INT_ALIGN(mdp->d_hints, cp);
106722028508SToomas Soome ival = *(int *)cp;
106822028508SToomas Soome cp += sizeof (int);
106922028508SToomas Soome clen = *cp++;
107022028508SToomas Soome if (verinfo == NULL ||
107122028508SToomas Soome ival == verinfo->md_ver_preferred) {
107222028508SToomas Soome found = true;
107322028508SToomas Soome break;
107422028508SToomas Soome }
107522028508SToomas Soome if (ival >= verinfo->md_ver_minimum &&
107622028508SToomas Soome ival <= verinfo->md_ver_maximum &&
107722028508SToomas Soome ival > bestver) {
107822028508SToomas Soome bestver = ival;
107922028508SToomas Soome best = cp;
108022028508SToomas Soome blen = clen;
108122028508SToomas Soome }
108222028508SToomas Soome break;
108322028508SToomas Soome default:
108422028508SToomas Soome break;
108522028508SToomas Soome }
108622028508SToomas Soome recptr += reclen + sizeof (int);
108722028508SToomas Soome }
108822028508SToomas Soome /*
108922028508SToomas Soome * Finally check if KLD is in the place
109022028508SToomas Soome */
109122028508SToomas Soome if (found)
109222028508SToomas Soome result = file_lookup(mdp->d_path, (char *)cp, clen, NULL);
109322028508SToomas Soome else if (best)
109422028508SToomas Soome result = file_lookup(mdp->d_path, (char *)best, blen, NULL);
109522028508SToomas Soome bad:
109622028508SToomas Soome /*
109722028508SToomas Soome * If nothing found or hints is absent - fallback to the old way
109822028508SToomas Soome * by using "kldname[.ko]" as module name.
109922028508SToomas Soome */
110022028508SToomas Soome if (!found && bestver == 0 && result == NULL) {
110122028508SToomas Soome result = file_lookup(mdp->d_path, modname, modnamelen,
110222028508SToomas Soome kld_ext_list);
110322028508SToomas Soome }
110422028508SToomas Soome return (result);
110522028508SToomas Soome }
110622028508SToomas Soome
110722028508SToomas Soome /*
110822028508SToomas Soome * Attempt to locate the file containing the module (name)
110922028508SToomas Soome */
111022028508SToomas Soome static char *
mod_searchmodule(char * name,struct mod_depend * verinfo)111122028508SToomas Soome mod_searchmodule(char *name, struct mod_depend *verinfo)
111222028508SToomas Soome {
111322028508SToomas Soome struct moduledir *mdp;
111422028508SToomas Soome char *result;
111522028508SToomas Soome
111622028508SToomas Soome moduledir_rebuild();
111722028508SToomas Soome /*
111822028508SToomas Soome * Now we ready to lookup module in the given directories
111922028508SToomas Soome */
112022028508SToomas Soome result = NULL;
112122028508SToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
112222028508SToomas Soome result = mod_search_hints(mdp, name, verinfo);
112322028508SToomas Soome if (result != NULL)
112422028508SToomas Soome break;
112522028508SToomas Soome }
112622028508SToomas Soome
112722028508SToomas Soome return (result);
112822028508SToomas Soome }
112922028508SToomas Soome
113022028508SToomas Soome int
file_addmodule(struct preloaded_file * fp,char * modname,int version,struct kernel_module ** newmp)113122028508SToomas Soome file_addmodule(struct preloaded_file *fp, char *modname, int version,
113222028508SToomas Soome struct kernel_module **newmp)
113322028508SToomas Soome {
113422028508SToomas Soome struct kernel_module *mp;
113522028508SToomas Soome struct mod_depend mdepend;
113622028508SToomas Soome
113722028508SToomas Soome bzero(&mdepend, sizeof (mdepend));
113822028508SToomas Soome mdepend.md_ver_preferred = version;
113922028508SToomas Soome mp = file_findmodule(fp, modname, &mdepend);
114022028508SToomas Soome if (mp != NULL)
114122028508SToomas Soome return (EEXIST);
114222028508SToomas Soome mp = calloc(1, sizeof (struct kernel_module));
114322028508SToomas Soome if (mp == NULL)
114422028508SToomas Soome return (ENOMEM);
114522028508SToomas Soome mp->m_name = strdup(modname);
114622028508SToomas Soome if (mp->m_name == NULL) {
114722028508SToomas Soome free(mp);
114822028508SToomas Soome return (ENOMEM);
114922028508SToomas Soome }
115022028508SToomas Soome mp->m_version = version;
115122028508SToomas Soome mp->m_fp = fp;
115222028508SToomas Soome mp->m_next = fp->f_modules;
115322028508SToomas Soome fp->f_modules = mp;
115422028508SToomas Soome if (newmp)
115522028508SToomas Soome *newmp = mp;
115622028508SToomas Soome return (0);
115722028508SToomas Soome }
115822028508SToomas Soome
115922028508SToomas Soome /*
116022028508SToomas Soome * Throw a file away
116122028508SToomas Soome */
116222028508SToomas Soome void
file_discard(struct preloaded_file * fp)116322028508SToomas Soome file_discard(struct preloaded_file *fp)
116422028508SToomas Soome {
116522028508SToomas Soome struct file_metadata *md, *md1;
116622028508SToomas Soome struct kernel_module *mp, *mp1;
116722028508SToomas Soome
116822028508SToomas Soome if (fp == NULL)
116922028508SToomas Soome return;
117022028508SToomas Soome
117122028508SToomas Soome if (archsw.arch_free_loadaddr != NULL && fp->f_addr &&
117222028508SToomas Soome fp->f_size != 0) {
117322028508SToomas Soome archsw.arch_free_loadaddr(fp->f_addr,
117422028508SToomas Soome (uint64_t)(roundup2(fp->f_size, PAGE_SIZE) >> 12));
117522028508SToomas Soome }
117622028508SToomas Soome
117722028508SToomas Soome md = fp->f_metadata;
117822028508SToomas Soome while (md != NULL) {
117922028508SToomas Soome md1 = md;
118022028508SToomas Soome md = md->md_next;
118122028508SToomas Soome free(md1);
118222028508SToomas Soome }
118322028508SToomas Soome mp = fp->f_modules;
118422028508SToomas Soome while (mp != NULL) {
118522028508SToomas Soome free(mp->m_name);
118622028508SToomas Soome mp1 = mp;
118722028508SToomas Soome mp = mp->m_next;
118822028508SToomas Soome free(mp1);
118922028508SToomas Soome }
119022028508SToomas Soome free(fp->f_name);
119122028508SToomas Soome free(fp->f_type);
119222028508SToomas Soome free(fp->f_args);
119322028508SToomas Soome free(fp);
119422028508SToomas Soome }
119522028508SToomas Soome
119622028508SToomas Soome /*
119722028508SToomas Soome * Allocate a new file; must be used instead of malloc()
119822028508SToomas Soome * to ensure safe initialisation.
119922028508SToomas Soome */
120022028508SToomas Soome struct preloaded_file *
file_alloc(void)120122028508SToomas Soome file_alloc(void)
120222028508SToomas Soome {
120322028508SToomas Soome
120422028508SToomas Soome return (calloc(1, sizeof (struct preloaded_file)));
120522028508SToomas Soome }
120622028508SToomas Soome
120722028508SToomas Soome /*
120822028508SToomas Soome * Add a module to the chain
120922028508SToomas Soome */
121022028508SToomas Soome static void
file_insert_tail(struct preloaded_file * fp)121122028508SToomas Soome file_insert_tail(struct preloaded_file *fp)
121222028508SToomas Soome {
121322028508SToomas Soome struct preloaded_file *cm;
121422028508SToomas Soome
121522028508SToomas Soome /* Append to list of loaded file */
121622028508SToomas Soome fp->f_next = NULL;
121722028508SToomas Soome if (preloaded_files == NULL) {
121822028508SToomas Soome preloaded_files = fp;
121922028508SToomas Soome } else {
122022028508SToomas Soome for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
122122028508SToomas Soome ;
122222028508SToomas Soome cm->f_next = fp;
122322028508SToomas Soome }
122422028508SToomas Soome }
122522028508SToomas Soome
122622028508SToomas Soome /*
122722028508SToomas Soome * Remove module from the chain
122822028508SToomas Soome */
122922028508SToomas Soome static void
file_remove(struct preloaded_file * fp)123022028508SToomas Soome file_remove(struct preloaded_file *fp)
123122028508SToomas Soome {
123222028508SToomas Soome struct preloaded_file *cm;
123322028508SToomas Soome
123422028508SToomas Soome if (preloaded_files == NULL)
123522028508SToomas Soome return;
123622028508SToomas Soome
123722028508SToomas Soome if (preloaded_files == fp) {
123822028508SToomas Soome preloaded_files = fp->f_next;
123922028508SToomas Soome return;
124022028508SToomas Soome }
124122028508SToomas Soome for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next) {
124222028508SToomas Soome if (cm->f_next == fp) {
124322028508SToomas Soome cm->f_next = fp->f_next;
124422028508SToomas Soome return;
124522028508SToomas Soome }
124622028508SToomas Soome }
124722028508SToomas Soome }
124822028508SToomas Soome
124922028508SToomas Soome static char *
moduledir_fullpath(struct moduledir * mdp,const char * fname)125022028508SToomas Soome moduledir_fullpath(struct moduledir *mdp, const char *fname)
125122028508SToomas Soome {
125222028508SToomas Soome char *cp;
125322028508SToomas Soome
125422028508SToomas Soome cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
125522028508SToomas Soome if (cp == NULL)
125622028508SToomas Soome return (NULL);
125722028508SToomas Soome strcpy(cp, mdp->d_path);
125822028508SToomas Soome strcat(cp, "/");
125922028508SToomas Soome strcat(cp, fname);
126022028508SToomas Soome return (cp);
126122028508SToomas Soome }
126222028508SToomas Soome
126322028508SToomas Soome /*
126422028508SToomas Soome * Read linker.hints file into memory performing some sanity checks.
126522028508SToomas Soome */
126622028508SToomas Soome static void
moduledir_readhints(struct moduledir * mdp)126722028508SToomas Soome moduledir_readhints(struct moduledir *mdp)
126822028508SToomas Soome {
126922028508SToomas Soome struct stat st;
127022028508SToomas Soome char *path;
127122028508SToomas Soome int fd, size, version;
127222028508SToomas Soome
127322028508SToomas Soome if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
127422028508SToomas Soome return;
127522028508SToomas Soome path = moduledir_fullpath(mdp, "linker.hints");
127622028508SToomas Soome if (stat(path, &st) != 0 ||
127722028508SToomas Soome st.st_size < (ssize_t)(sizeof (version) + sizeof (int)) ||
127822028508SToomas Soome st.st_size > LINKER_HINTS_MAX ||
127922028508SToomas Soome (fd = open(path, O_RDONLY)) < 0) {
128022028508SToomas Soome free(path);
128122028508SToomas Soome mdp->d_flags |= MDIR_NOHINTS;
128222028508SToomas Soome return;
128322028508SToomas Soome }
128422028508SToomas Soome free(path);
128522028508SToomas Soome size = read(fd, &version, sizeof (version));
128622028508SToomas Soome if (size != sizeof (version) || version != LINKER_HINTS_VERSION)
128722028508SToomas Soome goto bad;
128822028508SToomas Soome size = st.st_size - size;
128922028508SToomas Soome mdp->d_hints = malloc(size);
129022028508SToomas Soome if (mdp->d_hints == NULL)
129122028508SToomas Soome goto bad;
129222028508SToomas Soome if (read(fd, mdp->d_hints, size) != size)
129322028508SToomas Soome goto bad;
129422028508SToomas Soome mdp->d_hintsz = size;
1295fc39bce2SToomas Soome (void) close(fd);
129622028508SToomas Soome return;
129722028508SToomas Soome bad:
1298fc39bce2SToomas Soome (void) close(fd);
129922028508SToomas Soome free(mdp->d_hints);
130022028508SToomas Soome mdp->d_hints = NULL;
130122028508SToomas Soome mdp->d_flags |= MDIR_NOHINTS;
130222028508SToomas Soome }
130322028508SToomas Soome
130422028508SToomas Soome /*
130522028508SToomas Soome * Extract directories from the ';' separated list, remove duplicates.
130622028508SToomas Soome */
130722028508SToomas Soome static void
moduledir_rebuild(void)130822028508SToomas Soome moduledir_rebuild(void)
130922028508SToomas Soome {
131022028508SToomas Soome struct moduledir *mdp, *mtmp;
131122028508SToomas Soome const char *path, *cp, *ep;
131222028508SToomas Soome size_t cplen;
131322028508SToomas Soome
131422028508SToomas Soome path = getenv("module_path");
131522028508SToomas Soome if (path == NULL)
131622028508SToomas Soome path = default_searchpath;
131722028508SToomas Soome /*
131822028508SToomas Soome * Rebuild list of module directories if it changed
131922028508SToomas Soome */
132022028508SToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link)
132122028508SToomas Soome mdp->d_flags |= MDIR_REMOVED;
132222028508SToomas Soome
132322028508SToomas Soome for (ep = path; *ep != 0; ep++) {
132422028508SToomas Soome cp = ep;
132522028508SToomas Soome for (; *ep != 0 && *ep != ';'; ep++)
132622028508SToomas Soome ;
132722028508SToomas Soome /*
132822028508SToomas Soome * Ignore trailing slashes
132922028508SToomas Soome */
133022028508SToomas Soome for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/';
133122028508SToomas Soome cplen--)
133222028508SToomas Soome ;
133322028508SToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
133422028508SToomas Soome if (strlen(mdp->d_path) != cplen ||
133522028508SToomas Soome bcmp(cp, mdp->d_path, cplen) != 0)
133622028508SToomas Soome continue;
133722028508SToomas Soome mdp->d_flags &= ~MDIR_REMOVED;
133822028508SToomas Soome break;
133922028508SToomas Soome }
134022028508SToomas Soome if (mdp == NULL) {
134122028508SToomas Soome mdp = malloc(sizeof (*mdp) + cplen + 1);
134222028508SToomas Soome if (mdp == NULL)
134322028508SToomas Soome return;
134422028508SToomas Soome mdp->d_path = (char *)(mdp + 1);
134522028508SToomas Soome bcopy(cp, mdp->d_path, cplen);
134622028508SToomas Soome mdp->d_path[cplen] = 0;
134722028508SToomas Soome mdp->d_hints = NULL;
134822028508SToomas Soome mdp->d_flags = 0;
134922028508SToomas Soome STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
135022028508SToomas Soome }
135122028508SToomas Soome if (*ep == '\0')
135222028508SToomas Soome break;
135322028508SToomas Soome }
135422028508SToomas Soome /*
135522028508SToomas Soome * Delete unused directories if any
135622028508SToomas Soome */
135722028508SToomas Soome mdp = STAILQ_FIRST(&moduledir_list);
135822028508SToomas Soome while (mdp) {
135922028508SToomas Soome if ((mdp->d_flags & MDIR_REMOVED) == 0) {
136022028508SToomas Soome mdp = STAILQ_NEXT(mdp, d_link);
136122028508SToomas Soome } else {
136222028508SToomas Soome free(mdp->d_hints);
136322028508SToomas Soome mtmp = mdp;
136422028508SToomas Soome mdp = STAILQ_NEXT(mdp, d_link);
136522028508SToomas Soome STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
136622028508SToomas Soome free(mtmp);
136722028508SToomas Soome }
136822028508SToomas Soome }
136922028508SToomas Soome }
1370