199767f8919635c4928607450d9e0abb932109ceToomas Soome/*-
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Redistribution and use in source and binary forms, with or without
199767f8919635c4928607450d9e0abb932109ceToomas Soome * modification, are permitted provided that the following conditions
199767f8919635c4928607450d9e0abb932109ceToomas Soome * are met:
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 1. Redistributions of source code must retain the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer in the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * documentation and/or other materials provided with the distribution.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199767f8919635c4928607450d9e0abb932109ceToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
199767f8919635c4928607450d9e0abb932109ceToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
199767f8919635c4928607450d9e0abb932109ceToomas Soome * SUCH DAMAGE.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/cdefs.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome__FBSDID("$FreeBSD$");
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * file/module function dispatcher, support, etc.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <stand.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <string.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/param.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/linker.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/module.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/queue.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/stdint.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "bootstrap.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define MDIR_REMOVED 0x0001
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define MDIR_NOHINTS 0x0002
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct moduledir {
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *d_path; /* path of modules directory */
199767f8919635c4928607450d9e0abb932109ceToomas Soome u_char *d_hints; /* content of linker.hints file */
199767f8919635c4928607450d9e0abb932109ceToomas Soome int d_hintsz; /* size of hints data */
199767f8919635c4928607450d9e0abb932109ceToomas Soome int d_flags;
199767f8919635c4928607450d9e0abb932109ceToomas Soome STAILQ_ENTRY(moduledir) d_link;
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int file_load_dependencies(struct preloaded_file *base_mod);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char * file_search(const char *name, const char **extlist);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int file_havepath(const char *name);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *mod_searchmodule(char *name, struct mod_depend *verinfo);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void file_insert_tail(struct preloaded_file *mp);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct file_metadata* metadata_next(struct file_metadata *base_mp, int type);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void moduledir_readhints(struct moduledir *mdp);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void moduledir_rebuild(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* load address should be tweaked by first module loaded (kernel) */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic vm_offset_t loadaddr = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#if defined(LOADER_FDT_SUPPORT)
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic const char *default_searchpath =
199767f8919635c4928607450d9e0abb932109ceToomas Soome "/boot/kernel;/boot/modules;/boot/dtb";
199767f8919635c4928607450d9e0abb932109ceToomas Soome#else
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic const char *default_searchpath ="/platform/i86pc";
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct preloaded_file *preloaded_files = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic const char *kld_ext_list[] = {
199767f8919635c4928607450d9e0abb932109ceToomas Soome ".ko",
199767f8919635c4928607450d9e0abb932109ceToomas Soome "",
199767f8919635c4928607450d9e0abb932109ceToomas Soome ".debug",
199767f8919635c4928607450d9e0abb932109ceToomas Soome NULL
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * load an object, either a disk file or code module.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * To load a file, the syntax is:
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * load -t <type> <path>
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * code modules are loaded as:
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * load <path> <options>
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas SoomeCOMMAND_SET(load, "load", "load a kernel or module", command_load);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomecommand_load(int argc, char *argv[])
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *typestr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int dofile, dokld, ch, error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome dokld = dofile = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome optind = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome optreset = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome typestr = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (argc == 1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome command_errmsg = "no filename specified";
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (CMD_CRIT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome while ((ch = getopt(argc, argv, "kt:")) != -1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome switch(ch) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 'k':
199767f8919635c4928607450d9e0abb932109ceToomas Soome dokld = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 't':
199767f8919635c4928607450d9e0abb932109ceToomas Soome typestr = optarg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome dofile = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case '?':
199767f8919635c4928607450d9e0abb932109ceToomas Soome default:
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* getopt has already reported an error */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (CMD_OK);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome argv += (optind - 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome argc -= (optind - 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Loading %s...\n", argv[1]);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Request to load a raw file?
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (dofile) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((typestr == NULL) || (*typestr == 0)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome command_errmsg = "invalid load type";
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (CMD_CRIT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (file_findfile(argv[1], typestr) != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "warning: file '%s' already loaded", argv[1]);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (CMD_WARN);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (file_loadraw(argv[1], typestr, argc - 2, argv + 2, 1) != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (CMD_OK);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Failing to load mfs_root is never going to end well! */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strcmp("mfs_root", typestr) == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (CMD_FATAL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (CMD_ERROR);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Do we have explicit KLD load ?
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (dokld || file_havepath(argv[1])) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = mod_loadkld(argv[1], argc - 2, argv + 2);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error == EEXIST) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "warning: KLD '%s' already loaded", argv[1]);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (CMD_WARN);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (error == 0 ? CMD_OK : CMD_CRIT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Looks like a request for a module.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = mod_load(argv[1], NULL, argc - 2, argv + 2);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error == EEXIST) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "warning: module '%s' already loaded", argv[1]);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (CMD_WARN);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (error == 0 ? CMD_OK : CMD_CRIT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifdef __FreeBSD__
199767f8919635c4928607450d9e0abb932109ceToomas SoomeCOMMAND_SET(load_geli, "load_geli", "load a geli key", command_load_geli);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomecommand_load_geli(int argc, char *argv[])
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome char typestr[80];
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *cp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int ch, num;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (argc < 3) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome command_errmsg = "usage is [-n key#] <prov> <file>";
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(CMD_ERROR);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome num = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome optind = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome optreset = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome while ((ch = getopt(argc, argv, "n:")) != -1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome switch(ch) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 'n':
199767f8919635c4928607450d9e0abb932109ceToomas Soome num = strtol(optarg, &cp, 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cp == optarg) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "bad key index '%s'", optarg);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(CMD_ERROR);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case '?':
199767f8919635c4928607450d9e0abb932109ceToomas Soome default:
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* getopt has already reported an error */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(CMD_OK);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome argv += (optind - 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome argc -= (optind - 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(typestr, "%s:geli_keyfile%d", argv[1], num);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (file_loadraw(argv[2], typestr, 0, NULL, 1) ? CMD_OK : CMD_ERROR);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif /* __FreeBSD__ */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomevoid
199767f8919635c4928607450d9e0abb932109ceToomas Soomeunload(void)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (preloaded_files != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp = preloaded_files;
199767f8919635c4928607450d9e0abb932109ceToomas Soome preloaded_files = preloaded_files->f_next;
199767f8919635c4928607450d9e0abb932109ceToomas Soome file_discard(fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome loadaddr = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome unsetenv("kernelname");
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas SoomeCOMMAND_SET(unload, "unload", "unload all modules", command_unload);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomecommand_unload(int argc __attribute((unused)),
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *argv[] __attribute((unused)))
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome unload();
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(CMD_OK);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas SoomeCOMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomecommand_lsmod(int argc, char *argv[])
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct kernel_module *mp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct file_metadata *md;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char lbuf[80];
199767f8919635c4928607450d9e0abb932109ceToomas Soome int ch, verbose, ret = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome verbose = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome optind = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome optreset = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome while ((ch = getopt(argc, argv, "v")) != -1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome switch(ch) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 'v':
199767f8919635c4928607450d9e0abb932109ceToomas Soome verbose = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case '?':
199767f8919635c4928607450d9e0abb932109ceToomas Soome default:
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* getopt has already reported an error */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(CMD_OK);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome pager_open();
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (fp = preloaded_files; fp; fp = fp->f_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(lbuf, " %p: ", (void *) fp->f_addr);
199767f8919635c4928607450d9e0abb932109ceToomas Soome pager_output(lbuf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome pager_output(fp->f_name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(lbuf, " (%s, 0x%lx)\n", fp->f_type, (long)fp->f_size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (pager_output(lbuf))
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_args != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome pager_output(" args: ");
199767f8919635c4928607450d9e0abb932109ceToomas Soome pager_output(fp->f_args);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (pager_output("\n"))
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_modules) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome pager_output(" modules: ");
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (mp = fp->f_modules; mp; mp = mp->m_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(lbuf, "%s.%d ", mp->m_name, mp->m_version);
199767f8919635c4928607450d9e0abb932109ceToomas Soome pager_output(lbuf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (pager_output("\n"))
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (verbose) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* XXX could add some formatting smarts here to display some better */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (md = fp->f_metadata; md != NULL; md = md->md_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(lbuf, " 0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((ret = pager_output(lbuf)))
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ret)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome pager_close();
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(CMD_OK);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * File level interface, functions file_*
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome static int last_file_format = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int i;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (archsw.arch_loadaddr != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = EFTYPE;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = last_file_format, fp = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome file_formats[i] && fp == NULL; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = (file_formats[i]->l_load)(filename, dest, &fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_loader = last_file_format = i; /* remember the loader */
199767f8919635c4928607450d9e0abb932109ceToomas Soome *result = fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else if (last_file_format == i && i != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Restart from the beginning */
199767f8919635c4928607450d9e0abb932109ceToomas Soome i = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_file_format = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome continue;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error == EFTYPE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome continue; /* Unknown to this handler? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "can't load file '%s': %s", filename, strerror(error));
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_load_dependencies(struct preloaded_file *base_file)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct file_metadata *md;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct mod_depend *verinfo;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct kernel_module *mp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *dmodname;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (md == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome do {
199767f8919635c4928607450d9e0abb932109ceToomas Soome verinfo = (struct mod_depend*)md->md_data;
199767f8919635c4928607450d9e0abb932109ceToomas Soome dmodname = (char *)(verinfo + 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("loading required module '%s'\n", dmodname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = mod_load(dmodname, verinfo, 0, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * If module loaded via kld name which isn't listed
199767f8919635c4928607450d9e0abb932109ceToomas Soome * in the linker.hints file, we should check if it have
199767f8919635c4928607450d9e0abb932109ceToomas Soome * required version.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp = file_findmodule(NULL, dmodname, verinfo);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "module '%s' exists but with wrong version", dmodname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = ENOENT;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome md = metadata_next(md, MODINFOMD_DEPLIST);
199767f8919635c4928607450d9e0abb932109ceToomas Soome } while (md);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (!error)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Load failed; discard everything */
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (base_file != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp = base_file;
199767f8919635c4928607450d9e0abb932109ceToomas Soome base_file = base_file->f_next;
199767f8919635c4928607450d9e0abb932109ceToomas Soome file_discard(fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * We've been asked to load (fname) as (type), so just suck it in,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * no arguments or anything.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct preloaded_file *
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_loadraw(const char *fname, char *type, int argc, char **argv, int insert)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *name;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int fd, got;
199767f8919635c4928607450d9e0abb932109ceToomas Soome vm_offset_t laddr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* We can't load first */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((file_findfile(NULL, NULL)) == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome command_errmsg = "can't load file before kernel";
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* locate the file on the load path */
199767f8919635c4928607450d9e0abb932109ceToomas Soome name = file_search(fname, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (name == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "can't find '%s'", fname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((fd = open(name, O_RDONLY)) < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "can't open '%s': %s", name, strerror(errno));
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (archsw.arch_loadaddr != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome laddr = roundup(loadaddr, PAGE_SIZE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome loadaddr = laddr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (;;) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* read in 4k chunks; size is not really important */
199767f8919635c4928607450d9e0abb932109ceToomas Soome got = archsw.arch_readin(fd, laddr, 4096);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (got == 0) /* end of file */
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (got < 0) { /* error */
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "error reading '%s': %s", name, strerror(errno));
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(fd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome laddr += got;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Looks OK so far; create & populate control structure */
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp = file_alloc();
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_name = strdup(name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_args = unargv(argc, argv);
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_type = strdup(type);
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_metadata = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_loader = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_addr = loadaddr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_size = laddr - loadaddr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* recognise space consumption */
199767f8919635c4928607450d9e0abb932109ceToomas Soome loadaddr = laddr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Add to the list of loaded files */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (insert != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome file_insert_tail(fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(fd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Load the module (name), pass it (argc),(argv), add container file
199767f8919635c4928607450d9e0abb932109ceToomas Soome * to the list of loaded files.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * If module is already loaded just assign new argc/argv.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint
199767f8919635c4928607450d9e0abb932109ceToomas Soomemod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct kernel_module *mp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int err;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *filename;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (file_havepath(modname)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (mod_loadkld(modname, argc, argv));
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* see if module is already loaded */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp = file_findmodule(NULL, modname, verinfo);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mp) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mp->m_args)
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(mp->m_args);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp->m_args = unargv(argc, argv);
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "warning: module '%s' already loaded", mp->m_name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* locate file with the module on the search path */
199767f8919635c4928607450d9e0abb932109ceToomas Soome filename = mod_searchmodule(modname, verinfo);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (filename == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "can't find '%s'", modname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENOENT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome err = mod_loadkld(filename, argc, argv);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (err);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Load specified KLD. If path is omitted, then try to locate it via
199767f8919635c4928607450d9e0abb932109ceToomas Soome * search path.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint
199767f8919635c4928607450d9e0abb932109ceToomas Soomemod_loadkld(const char *kldname, int argc, char *argv[])
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp, *last_file;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int err;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *filename;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Get fully qualified KLD name
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome filename = file_search(kldname, kld_ext_list);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (filename == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "can't find '%s'", kldname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENOENT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Check if KLD already loaded
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp = file_findfile(filename, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "warning: KLD '%s' already loaded", filename);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(filename);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (last_file = preloaded_files;
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_file != NULL && last_file->f_next != NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_file = last_file->f_next)
199767f8919635c4928607450d9e0abb932109ceToomas Soome ;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome do {
199767f8919635c4928607450d9e0abb932109ceToomas Soome err = file_load(filename, loadaddr, &fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (err)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_args = unargv(argc, argv);
199767f8919635c4928607450d9e0abb932109ceToomas Soome loadaddr = fp->f_addr + fp->f_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome file_insert_tail(fp); /* Add to the list of loaded files */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (file_load_dependencies(fp) != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome err = ENOENT;
199767f8919635c4928607450d9e0abb932109ceToomas Soome last_file->f_next = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome loadaddr = last_file->f_addr + last_file->f_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome } while(0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (err == EFTYPE) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "don't know how to load module '%s'", filename);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (err && fp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome file_discard(fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(filename);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (err);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Find a file matching (name) and (type).
199767f8919635c4928607450d9e0abb932109ceToomas Soome * NULL may be passed as a wildcard to either.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct preloaded_file *
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_findfile(const char *name, const char *type)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (((name == NULL) || !strcmp(name, fp->f_name)) &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome ((type == NULL) || !strcmp(type, fp->f_type)))
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Find a module matching (name) inside of given file.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * NULL may be passed as a wildcard.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct kernel_module *
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_findmodule(struct preloaded_file *fp, char *modname,
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct mod_depend *verinfo)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct kernel_module *mp, *best;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bestver, mver;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (fp = preloaded_files; fp; fp = fp->f_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp = file_findmodule(fp, modname, verinfo);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (mp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome best = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bestver = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (mp = fp->f_modules; mp; mp = mp->m_next) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strcmp(modname, mp->m_name) == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (verinfo == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (mp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mver = mp->m_version;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mver == verinfo->md_ver_preferred)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (mp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mver >= verinfo->md_ver_minimum &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome mver <= verinfo->md_ver_maximum &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome mver > bestver) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome best = mp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bestver = mver;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (best);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Make a copy of (size) bytes of data from (p), and associate them as
199767f8919635c4928607450d9e0abb932109ceToomas Soome * metadata of (type) to the module (mp).
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomevoid
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct file_metadata *md;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome md->md_size = size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome md->md_type = type;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcopy(p, md->md_data, size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome md->md_next = fp->f_metadata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_metadata = md;
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Find a metadata object of (type) associated with the file (fp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct file_metadata *
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_findmetadata(struct preloaded_file *fp, int type)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct file_metadata *md;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (md = fp->f_metadata; md != NULL; md = md->md_next)
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (md->md_type == type)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(md);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct file_metadata *
199767f8919635c4928607450d9e0abb932109ceToomas Soomemetadata_next(struct file_metadata *md, int type)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (md == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome while((md = md->md_next) != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (md->md_type == type)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (md);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic const char *emptyextlist[] = { "", NULL };
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Check if the given file is in place and return full path to it.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_lookup(const char *path, const char *name, int namelen, const char **extlist)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct stat st;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *result, *cp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char **cpp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int pathlen, extlen, len;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome pathlen = strlen(path);
199767f8919635c4928607450d9e0abb932109ceToomas Soome extlen = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (extlist == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome extlist = emptyextlist;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (cpp = extlist; *cpp; cpp++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = strlen(*cpp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (len > extlen)
199767f8919635c4928607450d9e0abb932109ceToomas Soome extlen = len;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = malloc(pathlen + namelen + extlen + 2);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (result == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcopy(path, result, pathlen);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (pathlen > 0 && result[pathlen - 1] != '/')
199767f8919635c4928607450d9e0abb932109ceToomas Soome result[pathlen++] = '/';
199767f8919635c4928607450d9e0abb932109ceToomas Soome cp = result + pathlen;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcopy(name, cp, namelen);
199767f8919635c4928607450d9e0abb932109ceToomas Soome cp += namelen;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (cpp = extlist; *cpp; cpp++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome strcpy(cp, *cpp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
199767f8919635c4928607450d9e0abb932109ceToomas Soome return result;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(result);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Check if file name have any qualifiers
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_havepath(const char *name)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *cp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome archsw.arch_getdev(NULL, name, &cp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (cp != name || strchr(name, '/') != NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Attempt to find the file (name) on the module searchpath.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * If (name) is qualified in any way, we simply check it and
199767f8919635c4928607450d9e0abb932109ceToomas Soome * return it or NULL. If it is not qualified, then we attempt
199767f8919635c4928607450d9e0abb932109ceToomas Soome * to construct a path using entries in the environment variable
199767f8919635c4928607450d9e0abb932109ceToomas Soome * module_path.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * The path we return a pointer to need never be freed, as we manage
199767f8919635c4928607450d9e0abb932109ceToomas Soome * it internally.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_search(const char *name, const char **extlist)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct moduledir *mdp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct stat sb;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *result;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int namelen;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Don't look for nothing */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (name == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (*name == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(strdup(name));
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (file_havepath(name)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Qualified, so just see if it exists */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (stat(name, &sb) == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(strdup(name));
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome moduledir_rebuild();
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome namelen = strlen(name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = file_lookup(mdp->d_path, name, namelen, extlist);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (result)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(result);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define INT_ALIGN(base, ptr) ptr = \
199767f8919635c4928607450d9e0abb932109ceToomas Soome (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *
199767f8919635c4928607450d9e0abb932109ceToomas Soomemod_search_hints(struct moduledir *mdp, const char *modname,
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct mod_depend *verinfo)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome u_char *cp, *recptr, *bufend, *best;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *result;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int *intp, bestver, blen, clen, found, ival, modnamelen, reclen;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome moduledir_readhints(mdp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome modnamelen = strlen(modname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome found = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bestver = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mdp->d_hints == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto bad;
199767f8919635c4928607450d9e0abb932109ceToomas Soome recptr = mdp->d_hints;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bufend = recptr + mdp->d_hintsz;
199767f8919635c4928607450d9e0abb932109ceToomas Soome clen = blen = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome best = cp = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (recptr < bufend && !found) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome intp = (int*)recptr;
199767f8919635c4928607450d9e0abb932109ceToomas Soome reclen = *intp++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome ival = *intp++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome cp = (u_char*)intp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome switch (ival) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome case MDT_VERSION:
199767f8919635c4928607450d9e0abb932109ceToomas Soome clen = *cp++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome cp += clen;
199767f8919635c4928607450d9e0abb932109ceToomas Soome INT_ALIGN(mdp->d_hints, cp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome ival = *(int*)cp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome cp += sizeof(int);
199767f8919635c4928607450d9e0abb932109ceToomas Soome clen = *cp++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome found = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ival >= verinfo->md_ver_minimum &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome ival <= verinfo->md_ver_maximum &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome ival > bestver) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome bestver = ival;
199767f8919635c4928607450d9e0abb932109ceToomas Soome best = cp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome blen = clen;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome default:
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome recptr += reclen + sizeof(int);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Finally check if KLD is in the place
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (found)
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = file_lookup(mdp->d_path, (char *)cp, clen, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome else if (best)
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = file_lookup(mdp->d_path, (char *)best, blen, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soomebad:
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * If nothing found or hints is absent - fallback to the old way
199767f8919635c4928607450d9e0abb932109ceToomas Soome * by using "kldname[.ko]" as module name.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (!found && !bestver && result == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return result;
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Attempt to locate the file containing the module (name)
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *
199767f8919635c4928607450d9e0abb932109ceToomas Soomemod_searchmodule(char *name, struct mod_depend *verinfo)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct moduledir *mdp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *result;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome moduledir_rebuild();
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Now we ready to lookup module in the given directories
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = mod_search_hints(mdp, name, verinfo);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (result)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(result);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_addmodule(struct preloaded_file *fp, char *modname, int version,
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct kernel_module **newmp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct kernel_module *mp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct mod_depend mdepend;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzero(&mdepend, sizeof(mdepend));
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdepend.md_ver_preferred = version;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp = file_findmodule(fp, modname, &mdepend);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EEXIST);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp = malloc(sizeof(struct kernel_module));
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mp == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENOMEM);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzero(mp, sizeof(struct kernel_module));
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp->m_name = strdup(modname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp->m_version = version;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp->m_fp = fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp->m_next = fp->f_modules;
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_modules = mp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (newmp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *newmp = mp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Throw a file away
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomevoid
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_discard(struct preloaded_file *fp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct file_metadata *md, *md1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct kernel_module *mp, *mp1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return;
199767f8919635c4928607450d9e0abb932109ceToomas Soome md = fp->f_metadata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (md) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome md1 = md;
199767f8919635c4928607450d9e0abb932109ceToomas Soome md = md->md_next;
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(md1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp = fp->f_modules;
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (mp) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mp->m_name)
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(mp->m_name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp1 = mp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mp = mp->m_next;
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(mp1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_name != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(fp->f_name);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_type != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(fp->f_type);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fp->f_args != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(fp->f_args);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Allocate a new file; must be used instead of malloc()
199767f8919635c4928607450d9e0abb932109ceToomas Soome * to ensure safe initialisation.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct preloaded_file *
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_alloc(void)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzero(fp, sizeof(struct preloaded_file));
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (fp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Add a module to the chain
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void
199767f8919635c4928607450d9e0abb932109ceToomas Soomefile_insert_tail(struct preloaded_file *fp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct preloaded_file *cm;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Append to list of loaded file */
199767f8919635c4928607450d9e0abb932109ceToomas Soome fp->f_next = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (preloaded_files == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome preloaded_files = fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
199767f8919635c4928607450d9e0abb932109ceToomas Soome ;
199767f8919635c4928607450d9e0abb932109ceToomas Soome cm->f_next = fp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic char *
199767f8919635c4928607450d9e0abb932109ceToomas Soomemoduledir_fullpath(struct moduledir *mdp, const char *fname)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *cp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cp == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome strcpy(cp, mdp->d_path);
199767f8919635c4928607450d9e0abb932109ceToomas Soome strcat(cp, "/");
199767f8919635c4928607450d9e0abb932109ceToomas Soome strcat(cp, fname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (cp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Read linker.hints file into memory performing some sanity checks.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void
199767f8919635c4928607450d9e0abb932109ceToomas Soomemoduledir_readhints(struct moduledir *mdp)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct stat st;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *path;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int fd, size, version;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
199767f8919635c4928607450d9e0abb932109ceToomas Soome return;
199767f8919635c4928607450d9e0abb932109ceToomas Soome path = moduledir_fullpath(mdp, "linker.hints");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (stat(path, &st) != 0 ||
199767f8919635c4928607450d9e0abb932109ceToomas Soome st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
199767f8919635c4928607450d9e0abb932109ceToomas Soome st.st_size > LINKER_HINTS_MAX || (fd = open(path, O_RDONLY)) < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(path);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_flags |= MDIR_NOHINTS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(path);
199767f8919635c4928607450d9e0abb932109ceToomas Soome size = read(fd, &version, sizeof(version));
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto bad;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size = st.st_size - size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_hints = malloc(size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mdp->d_hints == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto bad;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (read(fd, mdp->d_hints, size) != size)
199767f8919635c4928607450d9e0abb932109ceToomas Soome goto bad;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_hintsz = size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(fd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return;
199767f8919635c4928607450d9e0abb932109ceToomas Soomebad:
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(fd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mdp->d_hints) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(mdp->d_hints);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_hints = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_flags |= MDIR_NOHINTS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return;
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Extract directories from the ';' separated list, remove duplicates.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void
199767f8919635c4928607450d9e0abb932109ceToomas Soomemoduledir_rebuild(void)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct moduledir *mdp, *mtmp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *path, *cp, *ep;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t cplen;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome path = getenv("module_path");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (path == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome path = default_searchpath;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Rebuild list of module directories if it changed
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link)
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_flags |= MDIR_REMOVED;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (ep = path; *ep != 0; ep++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome cp = ep;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (; *ep != 0 && *ep != ';'; ep++)
199767f8919635c4928607450d9e0abb932109ceToomas Soome ;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Ignore trailing slashes
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
199767f8919635c4928607450d9e0abb932109ceToomas Soome ;
199767f8919635c4928607450d9e0abb932109ceToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome continue;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_flags &= ~MDIR_REMOVED;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mdp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp = malloc(sizeof(*mdp) + cplen + 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mdp == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_path = (char*)(mdp + 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcopy(cp, mdp->d_path, cplen);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_path[cplen] = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_hints = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp->d_flags = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (*ep == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Delete unused directories if any
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp = STAILQ_FIRST(&moduledir_list);
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (mdp) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((mdp->d_flags & MDIR_REMOVED) == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp = STAILQ_NEXT(mdp, d_link);
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (mdp->d_hints)
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(mdp->d_hints);
199767f8919635c4928607450d9e0abb932109ceToomas Soome mtmp = mdp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome mdp = STAILQ_NEXT(mdp, d_link);
199767f8919635c4928607450d9e0abb932109ceToomas Soome STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(mtmp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return;
199767f8919635c4928607450d9e0abb932109ceToomas Soome}