Deleted Added
full compact
module.c (321232) module.c (328889)
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/sys/boot/common/module.c 321232 2017-07-19 19:06:19Z ngie $");
28__FBSDID("$FreeBSD: stable/11/sys/boot/common/module.c 328889 2018-02-05 17:01:18Z kevans $");
29
30/*
31 * file/module function dispatcher, support, etc.
32 */
33
34#include <stand.h>
35#include <string.h>
36#include <sys/param.h>
37#include <sys/linker.h>
38#include <sys/module.h>
39#include <sys/queue.h>
40#include <sys/stdint.h>
41
42#include "bootstrap.h"
43
44#define MDIR_REMOVED 0x0001
45#define MDIR_NOHINTS 0x0002
46
47struct moduledir {
48 char *d_path; /* path of modules directory */
49 u_char *d_hints; /* content of linker.hints file */
50 int d_hintsz; /* size of hints data */
51 int d_flags;
52 STAILQ_ENTRY(moduledir) d_link;
53};
54
55static int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
56static int file_load_dependencies(struct preloaded_file *base_mod);
57static char * file_search(const char *name, char **extlist);
58static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
59static int file_havepath(const char *name);
60static char *mod_searchmodule(char *name, struct mod_depend *verinfo);
61static void file_insert_tail(struct preloaded_file *mp);
62struct file_metadata* metadata_next(struct file_metadata *base_mp, int type);
63static void moduledir_readhints(struct moduledir *mdp);
64static void moduledir_rebuild(void);
65
66/* load address should be tweaked by first module loaded (kernel) */
67static vm_offset_t loadaddr = 0;
68
69#if defined(LOADER_FDT_SUPPORT)
70static const char *default_searchpath =
71 "/boot/kernel;/boot/modules;/boot/dtb";
72#else
73static const char *default_searchpath ="/boot/kernel;/boot/modules";
74#endif
75
76static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list);
77
78struct preloaded_file *preloaded_files = NULL;
79
80static char *kld_ext_list[] = {
81 ".ko",
82 "",
83 ".debug",
84 NULL
85};
86
87
88/*
89 * load an object, either a disk file or code module.
90 *
91 * To load a file, the syntax is:
92 *
93 * load -t <type> <path>
94 *
95 * code modules are loaded as:
96 *
97 * load <path> <options>
98 */
99
100COMMAND_SET(load, "load", "load a kernel or module", command_load);
101
102static int
103command_load(int argc, char *argv[])
104{
105 struct preloaded_file *fp;
106 char *typestr;
107 int dofile, dokld, ch, error;
108
109 dokld = dofile = 0;
110 optind = 1;
111 optreset = 1;
112 typestr = NULL;
113 if (argc == 1) {
114 command_errmsg = "no filename specified";
115 return (CMD_CRIT);
116 }
117 while ((ch = getopt(argc, argv, "kt:")) != -1) {
118 switch(ch) {
119 case 'k':
120 dokld = 1;
121 break;
122 case 't':
123 typestr = optarg;
124 dofile = 1;
125 break;
126 case '?':
127 default:
128 /* getopt has already reported an error */
129 return (CMD_OK);
130 }
131 }
132 argv += (optind - 1);
133 argc -= (optind - 1);
134
135 /*
136 * Request to load a raw file?
137 */
138 if (dofile) {
139 if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) {
140 command_errmsg = "invalid load type";
141 return (CMD_CRIT);
142 }
143
144 fp = file_findfile(argv[1], typestr);
145 if (fp) {
146 sprintf(command_errbuf, "warning: file '%s' already loaded", argv[1]);
147 return (CMD_WARN);
148 }
149
150 if (file_loadraw(argv[1], typestr, 1) != NULL)
151 return (CMD_OK);
152
153 /* Failing to load mfs_root is never going to end well! */
154 if (strcmp("mfs_root", typestr) == 0)
155 return (CMD_FATAL);
156
157 return (CMD_ERROR);
158 }
159 /*
160 * Do we have explicit KLD load ?
161 */
162 if (dokld || file_havepath(argv[1])) {
163 error = mod_loadkld(argv[1], argc - 2, argv + 2);
164 if (error == EEXIST) {
165 sprintf(command_errbuf, "warning: KLD '%s' already loaded", argv[1]);
166 return (CMD_WARN);
167 }
168
169 return (error == 0 ? CMD_OK : CMD_CRIT);
170 }
171 /*
172 * Looks like a request for a module.
173 */
174 error = mod_load(argv[1], NULL, argc - 2, argv + 2);
175 if (error == EEXIST) {
176 sprintf(command_errbuf, "warning: module '%s' already loaded", argv[1]);
177 return (CMD_WARN);
178 }
179
180 return (error == 0 ? CMD_OK : CMD_CRIT);
181}
182
183#ifdef LOADER_GELI_SUPPORT
184COMMAND_SET(load_geli, "load_geli", "load a geli key", command_load_geli);
185
186static int
187command_load_geli(int argc, char *argv[])
188{
189 char typestr[80];
190 char *cp;
191 int ch, num;
192
193 if (argc < 3) {
194 command_errmsg = "usage is [-n key#] <prov> <file>";
195 return(CMD_ERROR);
196 }
197
198 num = 0;
199 optind = 1;
200 optreset = 1;
201 while ((ch = getopt(argc, argv, "n:")) != -1) {
202 switch(ch) {
203 case 'n':
204 num = strtol(optarg, &cp, 0);
205 if (cp == optarg) {
206 sprintf(command_errbuf, "bad key index '%s'", optarg);
207 return(CMD_ERROR);
208 }
209 break;
210 case '?':
211 default:
212 /* getopt has already reported an error */
213 return(CMD_OK);
214 }
215 }
216 argv += (optind - 1);
217 argc -= (optind - 1);
218 sprintf(typestr, "%s:geli_keyfile%d", argv[1], num);
219 return (file_loadraw(argv[2], typestr, 1) ? CMD_OK : CMD_ERROR);
220}
221#endif
222
223void
224unload(void)
225{
226 struct preloaded_file *fp;
227
228 while (preloaded_files != NULL) {
229 fp = preloaded_files;
230 preloaded_files = preloaded_files->f_next;
231 file_discard(fp);
232 }
233 loadaddr = 0;
234 unsetenv("kernelname");
235}
236
237COMMAND_SET(unload, "unload", "unload all modules", command_unload);
238
239static int
240command_unload(int argc, char *argv[])
241{
242 unload();
243 return(CMD_OK);
244}
245
246COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
247
248static int
249command_lsmod(int argc, char *argv[])
250{
251 struct preloaded_file *fp;
252 struct kernel_module *mp;
253 struct file_metadata *md;
254 char lbuf[80];
29
30/*
31 * file/module function dispatcher, support, etc.
32 */
33
34#include <stand.h>
35#include <string.h>
36#include <sys/param.h>
37#include <sys/linker.h>
38#include <sys/module.h>
39#include <sys/queue.h>
40#include <sys/stdint.h>
41
42#include "bootstrap.h"
43
44#define MDIR_REMOVED 0x0001
45#define MDIR_NOHINTS 0x0002
46
47struct moduledir {
48 char *d_path; /* path of modules directory */
49 u_char *d_hints; /* content of linker.hints file */
50 int d_hintsz; /* size of hints data */
51 int d_flags;
52 STAILQ_ENTRY(moduledir) d_link;
53};
54
55static int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
56static int file_load_dependencies(struct preloaded_file *base_mod);
57static char * file_search(const char *name, char **extlist);
58static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
59static int file_havepath(const char *name);
60static char *mod_searchmodule(char *name, struct mod_depend *verinfo);
61static void file_insert_tail(struct preloaded_file *mp);
62struct file_metadata* metadata_next(struct file_metadata *base_mp, int type);
63static void moduledir_readhints(struct moduledir *mdp);
64static void moduledir_rebuild(void);
65
66/* load address should be tweaked by first module loaded (kernel) */
67static vm_offset_t loadaddr = 0;
68
69#if defined(LOADER_FDT_SUPPORT)
70static const char *default_searchpath =
71 "/boot/kernel;/boot/modules;/boot/dtb";
72#else
73static const char *default_searchpath ="/boot/kernel;/boot/modules";
74#endif
75
76static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list);
77
78struct preloaded_file *preloaded_files = NULL;
79
80static char *kld_ext_list[] = {
81 ".ko",
82 "",
83 ".debug",
84 NULL
85};
86
87
88/*
89 * load an object, either a disk file or code module.
90 *
91 * To load a file, the syntax is:
92 *
93 * load -t <type> <path>
94 *
95 * code modules are loaded as:
96 *
97 * load <path> <options>
98 */
99
100COMMAND_SET(load, "load", "load a kernel or module", command_load);
101
102static int
103command_load(int argc, char *argv[])
104{
105 struct preloaded_file *fp;
106 char *typestr;
107 int dofile, dokld, ch, error;
108
109 dokld = dofile = 0;
110 optind = 1;
111 optreset = 1;
112 typestr = NULL;
113 if (argc == 1) {
114 command_errmsg = "no filename specified";
115 return (CMD_CRIT);
116 }
117 while ((ch = getopt(argc, argv, "kt:")) != -1) {
118 switch(ch) {
119 case 'k':
120 dokld = 1;
121 break;
122 case 't':
123 typestr = optarg;
124 dofile = 1;
125 break;
126 case '?':
127 default:
128 /* getopt has already reported an error */
129 return (CMD_OK);
130 }
131 }
132 argv += (optind - 1);
133 argc -= (optind - 1);
134
135 /*
136 * Request to load a raw file?
137 */
138 if (dofile) {
139 if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) {
140 command_errmsg = "invalid load type";
141 return (CMD_CRIT);
142 }
143
144 fp = file_findfile(argv[1], typestr);
145 if (fp) {
146 sprintf(command_errbuf, "warning: file '%s' already loaded", argv[1]);
147 return (CMD_WARN);
148 }
149
150 if (file_loadraw(argv[1], typestr, 1) != NULL)
151 return (CMD_OK);
152
153 /* Failing to load mfs_root is never going to end well! */
154 if (strcmp("mfs_root", typestr) == 0)
155 return (CMD_FATAL);
156
157 return (CMD_ERROR);
158 }
159 /*
160 * Do we have explicit KLD load ?
161 */
162 if (dokld || file_havepath(argv[1])) {
163 error = mod_loadkld(argv[1], argc - 2, argv + 2);
164 if (error == EEXIST) {
165 sprintf(command_errbuf, "warning: KLD '%s' already loaded", argv[1]);
166 return (CMD_WARN);
167 }
168
169 return (error == 0 ? CMD_OK : CMD_CRIT);
170 }
171 /*
172 * Looks like a request for a module.
173 */
174 error = mod_load(argv[1], NULL, argc - 2, argv + 2);
175 if (error == EEXIST) {
176 sprintf(command_errbuf, "warning: module '%s' already loaded", argv[1]);
177 return (CMD_WARN);
178 }
179
180 return (error == 0 ? CMD_OK : CMD_CRIT);
181}
182
183#ifdef LOADER_GELI_SUPPORT
184COMMAND_SET(load_geli, "load_geli", "load a geli key", command_load_geli);
185
186static int
187command_load_geli(int argc, char *argv[])
188{
189 char typestr[80];
190 char *cp;
191 int ch, num;
192
193 if (argc < 3) {
194 command_errmsg = "usage is [-n key#] <prov> <file>";
195 return(CMD_ERROR);
196 }
197
198 num = 0;
199 optind = 1;
200 optreset = 1;
201 while ((ch = getopt(argc, argv, "n:")) != -1) {
202 switch(ch) {
203 case 'n':
204 num = strtol(optarg, &cp, 0);
205 if (cp == optarg) {
206 sprintf(command_errbuf, "bad key index '%s'", optarg);
207 return(CMD_ERROR);
208 }
209 break;
210 case '?':
211 default:
212 /* getopt has already reported an error */
213 return(CMD_OK);
214 }
215 }
216 argv += (optind - 1);
217 argc -= (optind - 1);
218 sprintf(typestr, "%s:geli_keyfile%d", argv[1], num);
219 return (file_loadraw(argv[2], typestr, 1) ? CMD_OK : CMD_ERROR);
220}
221#endif
222
223void
224unload(void)
225{
226 struct preloaded_file *fp;
227
228 while (preloaded_files != NULL) {
229 fp = preloaded_files;
230 preloaded_files = preloaded_files->f_next;
231 file_discard(fp);
232 }
233 loadaddr = 0;
234 unsetenv("kernelname");
235}
236
237COMMAND_SET(unload, "unload", "unload all modules", command_unload);
238
239static int
240command_unload(int argc, char *argv[])
241{
242 unload();
243 return(CMD_OK);
244}
245
246COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
247
248static int
249command_lsmod(int argc, char *argv[])
250{
251 struct preloaded_file *fp;
252 struct kernel_module *mp;
253 struct file_metadata *md;
254 char lbuf[80];
255 int ch, verbose;
255 int ch, verbose, ret = 0;
256
257 verbose = 0;
258 optind = 1;
259 optreset = 1;
260 while ((ch = getopt(argc, argv, "v")) != -1) {
261 switch(ch) {
262 case 'v':
263 verbose = 1;
264 break;
265 case '?':
266 default:
267 /* getopt has already reported an error */
268 return(CMD_OK);
269 }
270 }
271
272 pager_open();
273 for (fp = preloaded_files; fp; fp = fp->f_next) {
256
257 verbose = 0;
258 optind = 1;
259 optreset = 1;
260 while ((ch = getopt(argc, argv, "v")) != -1) {
261 switch(ch) {
262 case 'v':
263 verbose = 1;
264 break;
265 case '?':
266 default:
267 /* getopt has already reported an error */
268 return(CMD_OK);
269 }
270 }
271
272 pager_open();
273 for (fp = preloaded_files; fp; fp = fp->f_next) {
274 sprintf(lbuf, " %p: ", (void *) fp->f_addr);
274 snprintf(lbuf, sizeof(lbuf), " %p: ", (void *) fp->f_addr);
275 pager_output(lbuf);
276 pager_output(fp->f_name);
275 pager_output(lbuf);
276 pager_output(fp->f_name);
277 sprintf(lbuf, " (%s, 0x%lx)\n", fp->f_type, (long)fp->f_size);
278 pager_output(lbuf);
277 snprintf(lbuf, sizeof(lbuf), " (%s, 0x%lx)\n", fp->f_type,
278 (long)fp->f_size);
279 if (pager_output(lbuf))
280 break;
279 if (fp->f_args != NULL) {
280 pager_output(" args: ");
281 pager_output(fp->f_args);
282 if (pager_output("\n"))
283 break;
284 }
285 if (fp->f_modules) {
286 pager_output(" modules: ");
287 for (mp = fp->f_modules; mp; mp = mp->m_next) {
281 if (fp->f_args != NULL) {
282 pager_output(" args: ");
283 pager_output(fp->f_args);
284 if (pager_output("\n"))
285 break;
286 }
287 if (fp->f_modules) {
288 pager_output(" modules: ");
289 for (mp = fp->f_modules; mp; mp = mp->m_next) {
288 sprintf(lbuf, "%s.%d ", mp->m_name, mp->m_version);
290 snprintf(lbuf, sizeof(lbuf), "%s.%d ", mp->m_name,
291 mp->m_version);
289 pager_output(lbuf);
290 }
291 if (pager_output("\n"))
292 break;
293 }
294 if (verbose) {
295 /* XXX could add some formatting smarts here to display some better */
296 for (md = fp->f_metadata; md != NULL; md = md->md_next) {
292 pager_output(lbuf);
293 }
294 if (pager_output("\n"))
295 break;
296 }
297 if (verbose) {
298 /* XXX could add some formatting smarts here to display some better */
299 for (md = fp->f_metadata; md != NULL; md = md->md_next) {
297 sprintf(lbuf, " 0x%04x, 0x%lx\n", md->md_type, (long) md->md_size);
300 snprintf(lbuf, sizeof(lbuf), " 0x%04x, 0x%lx\n",
301 md->md_type, (long) md->md_size);
298 if (pager_output(lbuf))
299 break;
300 }
301 }
302 if (pager_output(lbuf))
303 break;
304 }
305 }
306 if (ret)
307 break;
302 }
303 pager_close();
304 return(CMD_OK);
305}
306
307/*
308 * File level interface, functions file_*
309 */
310int
311file_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
312{
313 static int last_file_format = 0;
314 struct preloaded_file *fp;
315 int error;
316 int i;
317
318 if (archsw.arch_loadaddr != NULL)
319 dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest);
320
321 error = EFTYPE;
322 for (i = last_file_format, fp = NULL;
323 file_formats[i] && fp == NULL; i++) {
324 error = (file_formats[i]->l_load)(filename, dest, &fp);
325 if (error == 0) {
326 fp->f_loader = last_file_format = i; /* remember the loader */
327 *result = fp;
328 break;
329 } else if (last_file_format == i && i != 0) {
330 /* Restart from the beginning */
331 i = -1;
332 last_file_format = 0;
333 fp = NULL;
334 continue;
335 }
336 if (error == EFTYPE)
337 continue; /* Unknown to this handler? */
338 if (error) {
339 sprintf(command_errbuf, "can't load file '%s': %s",
340 filename, strerror(error));
341 break;
342 }
343 }
344 return (error);
345}
346
347static int
348file_load_dependencies(struct preloaded_file *base_file)
349{
350 struct file_metadata *md;
351 struct preloaded_file *fp;
352 struct mod_depend *verinfo;
353 struct kernel_module *mp;
354 char *dmodname;
355 int error;
356
357 md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
358 if (md == NULL)
359 return (0);
360 error = 0;
361 do {
362 verinfo = (struct mod_depend*)md->md_data;
363 dmodname = (char *)(verinfo + 1);
364 if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
365 printf("loading required module '%s'\n", dmodname);
366 error = mod_load(dmodname, verinfo, 0, NULL);
367 if (error)
368 break;
369 /*
370 * If module loaded via kld name which isn't listed
371 * in the linker.hints file, we should check if it have
372 * required version.
373 */
374 mp = file_findmodule(NULL, dmodname, verinfo);
375 if (mp == NULL) {
376 sprintf(command_errbuf, "module '%s' exists but with wrong version",
377 dmodname);
378 error = ENOENT;
379 break;
380 }
381 }
382 md = metadata_next(md, MODINFOMD_DEPLIST);
383 } while (md);
384 if (!error)
385 return (0);
386 /* Load failed; discard everything */
387 while (base_file != NULL) {
388 fp = base_file;
389 base_file = base_file->f_next;
390 file_discard(fp);
391 }
392 return (error);
393}
394
395/*
396 * We've been asked to load (fname) as (type), so just suck it in,
397 * no arguments or anything.
398 */
399struct preloaded_file *
400file_loadraw(const char *fname, char *type, int insert)
401{
402 struct preloaded_file *fp;
403 char *name;
404 int fd, got;
405 vm_offset_t laddr;
406
407 /* We can't load first */
408 if ((file_findfile(NULL, NULL)) == NULL) {
409 command_errmsg = "can't load file before kernel";
410 return(NULL);
411 }
412
413 /* locate the file on the load path */
414 name = file_search(fname, NULL);
415 if (name == NULL) {
416 sprintf(command_errbuf, "can't find '%s'", fname);
417 return(NULL);
418 }
419
420 if ((fd = open(name, O_RDONLY)) < 0) {
421 sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno));
422 free(name);
423 return(NULL);
424 }
425
426 if (archsw.arch_loadaddr != NULL)
427 loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
428
429 printf("%s ", name);
430
431 laddr = loadaddr;
432 for (;;) {
433 /* read in 4k chunks; size is not really important */
434 got = archsw.arch_readin(fd, laddr, 4096);
435 if (got == 0) /* end of file */
436 break;
437 if (got < 0) { /* error */
438 sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno));
439 free(name);
440 close(fd);
441 return(NULL);
442 }
443 laddr += got;
444 }
445
446 printf("size=%#jx\n", (uintmax_t)(laddr - loadaddr));
447
448 /* Looks OK so far; create & populate control structure */
449 fp = file_alloc();
450 fp->f_name = strdup(name);
451 fp->f_type = strdup(type);
452 fp->f_args = NULL;
453 fp->f_metadata = NULL;
454 fp->f_loader = -1;
455 fp->f_addr = loadaddr;
456 fp->f_size = laddr - loadaddr;
457
458 /* recognise space consumption */
459 loadaddr = laddr;
460
461 /* Add to the list of loaded files */
462 if (insert != 0)
463 file_insert_tail(fp);
464 close(fd);
465 return(fp);
466}
467
468/*
469 * Load the module (name), pass it (argc),(argv), add container file
470 * to the list of loaded files.
471 * If module is already loaded just assign new argc/argv.
472 */
473int
474mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
475{
476 struct kernel_module *mp;
477 int err;
478 char *filename;
479
480 if (file_havepath(modname)) {
481 printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
482 return (mod_loadkld(modname, argc, argv));
483 }
484 /* see if module is already loaded */
485 mp = file_findmodule(NULL, modname, verinfo);
486 if (mp) {
487#ifdef moduleargs
488 if (mp->m_args)
489 free(mp->m_args);
490 mp->m_args = unargv(argc, argv);
491#endif
492 sprintf(command_errbuf, "warning: module '%s' already loaded", mp->m_name);
493 return (0);
494 }
495 /* locate file with the module on the search path */
496 filename = mod_searchmodule(modname, verinfo);
497 if (filename == NULL) {
498 sprintf(command_errbuf, "can't find '%s'", modname);
499 return (ENOENT);
500 }
501 err = mod_loadkld(filename, argc, argv);
502 return (err);
503}
504
505/*
506 * Load specified KLD. If path is omitted, then try to locate it via
507 * search path.
508 */
509int
510mod_loadkld(const char *kldname, int argc, char *argv[])
511{
512 struct preloaded_file *fp, *last_file;
513 int err;
514 char *filename;
515
516 /*
517 * Get fully qualified KLD name
518 */
519 filename = file_search(kldname, kld_ext_list);
520 if (filename == NULL) {
521 sprintf(command_errbuf, "can't find '%s'", kldname);
522 return (ENOENT);
523 }
524 /*
525 * Check if KLD already loaded
526 */
527 fp = file_findfile(filename, NULL);
528 if (fp) {
529 sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename);
530 free(filename);
531 return (0);
532 }
533 for (last_file = preloaded_files;
534 last_file != NULL && last_file->f_next != NULL;
535 last_file = last_file->f_next)
536 ;
537
538 do {
539 err = file_load(filename, loadaddr, &fp);
540 if (err)
541 break;
542 fp->f_args = unargv(argc, argv);
543 loadaddr = fp->f_addr + fp->f_size;
544 file_insert_tail(fp); /* Add to the list of loaded files */
545 if (file_load_dependencies(fp) != 0) {
546 err = ENOENT;
547 last_file->f_next = NULL;
548 loadaddr = last_file->f_addr + last_file->f_size;
549 fp = NULL;
550 break;
551 }
552 } while(0);
553 if (err == EFTYPE)
554 sprintf(command_errbuf, "don't know how to load module '%s'", filename);
555 if (err && fp)
556 file_discard(fp);
557 free(filename);
558 return (err);
559}
560
561/*
562 * Find a file matching (name) and (type).
563 * NULL may be passed as a wildcard to either.
564 */
565struct preloaded_file *
566file_findfile(const char *name, const char *type)
567{
568 struct preloaded_file *fp;
569
570 for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
571 if (((name == NULL) || !strcmp(name, fp->f_name)) &&
572 ((type == NULL) || !strcmp(type, fp->f_type)))
573 break;
574 }
575 return (fp);
576}
577
578/*
579 * Find a module matching (name) inside of given file.
580 * NULL may be passed as a wildcard.
581 */
582struct kernel_module *
583file_findmodule(struct preloaded_file *fp, char *modname,
584 struct mod_depend *verinfo)
585{
586 struct kernel_module *mp, *best;
587 int bestver, mver;
588
589 if (fp == NULL) {
590 for (fp = preloaded_files; fp; fp = fp->f_next) {
591 mp = file_findmodule(fp, modname, verinfo);
592 if (mp)
593 return (mp);
594 }
595 return (NULL);
596 }
597 best = NULL;
598 bestver = 0;
599 for (mp = fp->f_modules; mp; mp = mp->m_next) {
600 if (strcmp(modname, mp->m_name) == 0) {
601 if (verinfo == NULL)
602 return (mp);
603 mver = mp->m_version;
604 if (mver == verinfo->md_ver_preferred)
605 return (mp);
606 if (mver >= verinfo->md_ver_minimum &&
607 mver <= verinfo->md_ver_maximum &&
608 mver > bestver) {
609 best = mp;
610 bestver = mver;
611 }
612 }
613 }
614 return (best);
615}
616/*
617 * Make a copy of (size) bytes of data from (p), and associate them as
618 * metadata of (type) to the module (mp).
619 */
620void
621file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
622{
623 struct file_metadata *md;
624
625 md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
626 md->md_size = size;
627 md->md_type = type;
628 bcopy(p, md->md_data, size);
629 md->md_next = fp->f_metadata;
630 fp->f_metadata = md;
631}
632
633/*
634 * Find a metadata object of (type) associated with the file (fp)
635 */
636struct file_metadata *
637file_findmetadata(struct preloaded_file *fp, int type)
638{
639 struct file_metadata *md;
640
641 for (md = fp->f_metadata; md != NULL; md = md->md_next)
642 if (md->md_type == type)
643 break;
644 return(md);
645}
646
647/*
648 * Remove all metadata from the file.
649 */
650void
651file_removemetadata(struct preloaded_file *fp)
652{
653 struct file_metadata *md, *next;
654
655 for (md = fp->f_metadata; md != NULL; md = next)
656 {
657 next = md->md_next;
658 free(md);
659 }
660 fp->f_metadata = NULL;
661}
662
663struct file_metadata *
664metadata_next(struct file_metadata *md, int type)
665{
666 if (md == NULL)
667 return (NULL);
668 while((md = md->md_next) != NULL)
669 if (md->md_type == type)
670 break;
671 return (md);
672}
673
674static char *emptyextlist[] = { "", NULL };
675
676/*
677 * Check if the given file is in place and return full path to it.
678 */
679static char *
680file_lookup(const char *path, const char *name, int namelen, char **extlist)
681{
682 struct stat st;
683 char *result, *cp, **cpp;
684 int pathlen, extlen, len;
685
686 pathlen = strlen(path);
687 extlen = 0;
688 if (extlist == NULL)
689 extlist = emptyextlist;
690 for (cpp = extlist; *cpp; cpp++) {
691 len = strlen(*cpp);
692 if (len > extlen)
693 extlen = len;
694 }
695 result = malloc(pathlen + namelen + extlen + 2);
696 if (result == NULL)
697 return (NULL);
698 bcopy(path, result, pathlen);
699 if (pathlen > 0 && result[pathlen - 1] != '/')
700 result[pathlen++] = '/';
701 cp = result + pathlen;
702 bcopy(name, cp, namelen);
703 cp += namelen;
704 for (cpp = extlist; *cpp; cpp++) {
705 strcpy(cp, *cpp);
706 if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
707 return result;
708 }
709 free(result);
710 return NULL;
711}
712
713/*
714 * Check if file name have any qualifiers
715 */
716static int
717file_havepath(const char *name)
718{
719 const char *cp;
720
721 archsw.arch_getdev(NULL, name, &cp);
722 return (cp != name || strchr(name, '/') != NULL);
723}
724
725/*
726 * Attempt to find the file (name) on the module searchpath.
727 * If (name) is qualified in any way, we simply check it and
728 * return it or NULL. If it is not qualified, then we attempt
729 * to construct a path using entries in the environment variable
730 * module_path.
731 *
732 * The path we return a pointer to need never be freed, as we manage
733 * it internally.
734 */
735static char *
736file_search(const char *name, char **extlist)
737{
738 struct moduledir *mdp;
739 struct stat sb;
740 char *result;
741 int namelen;
742
743 /* Don't look for nothing */
744 if (name == NULL)
745 return(NULL);
746
747 if (*name == 0)
748 return(strdup(name));
749
750 if (file_havepath(name)) {
751 /* Qualified, so just see if it exists */
752 if (stat(name, &sb) == 0)
753 return(strdup(name));
754 return(NULL);
755 }
756 moduledir_rebuild();
757 result = NULL;
758 namelen = strlen(name);
759 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
760 result = file_lookup(mdp->d_path, name, namelen, extlist);
761 if (result)
762 break;
763 }
764 return(result);
765}
766
767#define INT_ALIGN(base, ptr) ptr = \
768 (base) + roundup2((ptr) - (base), sizeof(int))
769
770static char *
771mod_search_hints(struct moduledir *mdp, const char *modname,
772 struct mod_depend *verinfo)
773{
774 u_char *cp, *recptr, *bufend, *best;
775 char *result;
776 int *intp, bestver, blen, clen, found, ival, modnamelen, reclen;
777
778 moduledir_readhints(mdp);
779 modnamelen = strlen(modname);
780 found = 0;
781 result = NULL;
782 bestver = 0;
783 if (mdp->d_hints == NULL)
784 goto bad;
785 recptr = mdp->d_hints;
786 bufend = recptr + mdp->d_hintsz;
787 clen = blen = 0;
788 best = cp = NULL;
789 while (recptr < bufend && !found) {
790 intp = (int*)recptr;
791 reclen = *intp++;
792 ival = *intp++;
793 cp = (u_char*)intp;
794 switch (ival) {
795 case MDT_VERSION:
796 clen = *cp++;
797 if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
798 break;
799 cp += clen;
800 INT_ALIGN(mdp->d_hints, cp);
801 ival = *(int*)cp;
802 cp += sizeof(int);
803 clen = *cp++;
804 if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
805 found = 1;
806 break;
807 }
808 if (ival >= verinfo->md_ver_minimum &&
809 ival <= verinfo->md_ver_maximum &&
810 ival > bestver) {
811 bestver = ival;
812 best = cp;
813 blen = clen;
814 }
815 break;
816 default:
817 break;
818 }
819 recptr += reclen + sizeof(int);
820 }
821 /*
822 * Finally check if KLD is in the place
823 */
824 if (found)
825 result = file_lookup(mdp->d_path, (const char *)cp, clen, NULL);
826 else if (best)
827 result = file_lookup(mdp->d_path, (const char *)best, blen, NULL);
828bad:
829 /*
830 * If nothing found or hints is absent - fallback to the old way
831 * by using "kldname[.ko]" as module name.
832 */
833 if (!found && !bestver && result == NULL)
834 result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
835 return result;
836}
837
838/*
839 * Attempt to locate the file containing the module (name)
840 */
841static char *
842mod_searchmodule(char *name, struct mod_depend *verinfo)
843{
844 struct moduledir *mdp;
845 char *result;
846
847 moduledir_rebuild();
848 /*
849 * Now we ready to lookup module in the given directories
850 */
851 result = NULL;
852 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
853 result = mod_search_hints(mdp, name, verinfo);
854 if (result)
855 break;
856 }
857
858 return(result);
859}
860
861int
862file_addmodule(struct preloaded_file *fp, char *modname, int version,
863 struct kernel_module **newmp)
864{
865 struct kernel_module *mp;
866 struct mod_depend mdepend;
867
868 bzero(&mdepend, sizeof(mdepend));
869 mdepend.md_ver_preferred = version;
870 mp = file_findmodule(fp, modname, &mdepend);
871 if (mp)
872 return (EEXIST);
873 mp = malloc(sizeof(struct kernel_module));
874 if (mp == NULL)
875 return (ENOMEM);
876 bzero(mp, sizeof(struct kernel_module));
877 mp->m_name = strdup(modname);
878 mp->m_version = version;
879 mp->m_fp = fp;
880 mp->m_next = fp->f_modules;
881 fp->f_modules = mp;
882 if (newmp)
883 *newmp = mp;
884 return (0);
885}
886
887/*
888 * Throw a file away
889 */
890void
891file_discard(struct preloaded_file *fp)
892{
893 struct file_metadata *md, *md1;
894 struct kernel_module *mp, *mp1;
895 if (fp == NULL)
896 return;
897 md = fp->f_metadata;
898 while (md) {
899 md1 = md;
900 md = md->md_next;
901 free(md1);
902 }
903 mp = fp->f_modules;
904 while (mp) {
905 if (mp->m_name)
906 free(mp->m_name);
907 mp1 = mp;
908 mp = mp->m_next;
909 free(mp1);
910 }
911 if (fp->f_name != NULL)
912 free(fp->f_name);
913 if (fp->f_type != NULL)
914 free(fp->f_type);
915 if (fp->f_args != NULL)
916 free(fp->f_args);
917 free(fp);
918}
919
920/*
921 * Allocate a new file; must be used instead of malloc()
922 * to ensure safe initialisation.
923 */
924struct preloaded_file *
925file_alloc(void)
926{
927 struct preloaded_file *fp;
928
929 if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
930 bzero(fp, sizeof(struct preloaded_file));
931 }
932 return (fp);
933}
934
935/*
936 * Add a module to the chain
937 */
938static void
939file_insert_tail(struct preloaded_file *fp)
940{
941 struct preloaded_file *cm;
942
943 /* Append to list of loaded file */
944 fp->f_next = NULL;
945 if (preloaded_files == NULL) {
946 preloaded_files = fp;
947 } else {
948 for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
949 ;
950 cm->f_next = fp;
951 }
952}
953
954static char *
955moduledir_fullpath(struct moduledir *mdp, const char *fname)
956{
957 char *cp;
958
959 cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
960 if (cp == NULL)
961 return NULL;
962 strcpy(cp, mdp->d_path);
963 strcat(cp, "/");
964 strcat(cp, fname);
965 return (cp);
966}
967
968/*
969 * Read linker.hints file into memory performing some sanity checks.
970 */
971static void
972moduledir_readhints(struct moduledir *mdp)
973{
974 struct stat st;
975 char *path;
976 int fd, size, version;
977
978 if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
979 return;
980 path = moduledir_fullpath(mdp, "linker.hints");
981 if (stat(path, &st) != 0 ||
982 st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
983 st.st_size > LINKER_HINTS_MAX || (fd = open(path, O_RDONLY)) < 0) {
984 free(path);
985 mdp->d_flags |= MDIR_NOHINTS;
986 return;
987 }
988 free(path);
989 size = read(fd, &version, sizeof(version));
990 if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
991 goto bad;
992 size = st.st_size - size;
993 mdp->d_hints = malloc(size);
994 if (mdp->d_hints == NULL)
995 goto bad;
996 if (read(fd, mdp->d_hints, size) != size)
997 goto bad;
998 mdp->d_hintsz = size;
999 close(fd);
1000 return;
1001bad:
1002 close(fd);
1003 if (mdp->d_hints) {
1004 free(mdp->d_hints);
1005 mdp->d_hints = NULL;
1006 }
1007 mdp->d_flags |= MDIR_NOHINTS;
1008 return;
1009}
1010
1011/*
1012 * Extract directories from the ';' separated list, remove duplicates.
1013 */
1014static void
1015moduledir_rebuild(void)
1016{
1017 struct moduledir *mdp, *mtmp;
1018 const char *path, *cp, *ep;
1019 size_t cplen;
1020
1021 path = getenv("module_path");
1022 if (path == NULL)
1023 path = default_searchpath;
1024 /*
1025 * Rebuild list of module directories if it changed
1026 */
1027 STAILQ_FOREACH(mdp, &moduledir_list, d_link)
1028 mdp->d_flags |= MDIR_REMOVED;
1029
1030 for (ep = path; *ep != 0; ep++) {
1031 cp = ep;
1032 for (; *ep != 0 && *ep != ';'; ep++)
1033 ;
1034 /*
1035 * Ignore trailing slashes
1036 */
1037 for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
1038 ;
1039 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1040 if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
1041 continue;
1042 mdp->d_flags &= ~MDIR_REMOVED;
1043 break;
1044 }
1045 if (mdp == NULL) {
1046 mdp = malloc(sizeof(*mdp) + cplen + 1);
1047 if (mdp == NULL)
1048 return;
1049 mdp->d_path = (char*)(mdp + 1);
1050 bcopy(cp, mdp->d_path, cplen);
1051 mdp->d_path[cplen] = 0;
1052 mdp->d_hints = NULL;
1053 mdp->d_flags = 0;
1054 STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1055 }
1056 if (*ep == 0)
1057 break;
1058 }
1059 /*
1060 * Delete unused directories if any
1061 */
1062 mdp = STAILQ_FIRST(&moduledir_list);
1063 while (mdp) {
1064 if ((mdp->d_flags & MDIR_REMOVED) == 0) {
1065 mdp = STAILQ_NEXT(mdp, d_link);
1066 } else {
1067 if (mdp->d_hints)
1068 free(mdp->d_hints);
1069 mtmp = mdp;
1070 mdp = STAILQ_NEXT(mdp, d_link);
1071 STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
1072 free(mtmp);
1073 }
1074 }
1075 return;
1076}
308 }
309 pager_close();
310 return(CMD_OK);
311}
312
313/*
314 * File level interface, functions file_*
315 */
316int
317file_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
318{
319 static int last_file_format = 0;
320 struct preloaded_file *fp;
321 int error;
322 int i;
323
324 if (archsw.arch_loadaddr != NULL)
325 dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest);
326
327 error = EFTYPE;
328 for (i = last_file_format, fp = NULL;
329 file_formats[i] && fp == NULL; i++) {
330 error = (file_formats[i]->l_load)(filename, dest, &fp);
331 if (error == 0) {
332 fp->f_loader = last_file_format = i; /* remember the loader */
333 *result = fp;
334 break;
335 } else if (last_file_format == i && i != 0) {
336 /* Restart from the beginning */
337 i = -1;
338 last_file_format = 0;
339 fp = NULL;
340 continue;
341 }
342 if (error == EFTYPE)
343 continue; /* Unknown to this handler? */
344 if (error) {
345 sprintf(command_errbuf, "can't load file '%s': %s",
346 filename, strerror(error));
347 break;
348 }
349 }
350 return (error);
351}
352
353static int
354file_load_dependencies(struct preloaded_file *base_file)
355{
356 struct file_metadata *md;
357 struct preloaded_file *fp;
358 struct mod_depend *verinfo;
359 struct kernel_module *mp;
360 char *dmodname;
361 int error;
362
363 md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
364 if (md == NULL)
365 return (0);
366 error = 0;
367 do {
368 verinfo = (struct mod_depend*)md->md_data;
369 dmodname = (char *)(verinfo + 1);
370 if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
371 printf("loading required module '%s'\n", dmodname);
372 error = mod_load(dmodname, verinfo, 0, NULL);
373 if (error)
374 break;
375 /*
376 * If module loaded via kld name which isn't listed
377 * in the linker.hints file, we should check if it have
378 * required version.
379 */
380 mp = file_findmodule(NULL, dmodname, verinfo);
381 if (mp == NULL) {
382 sprintf(command_errbuf, "module '%s' exists but with wrong version",
383 dmodname);
384 error = ENOENT;
385 break;
386 }
387 }
388 md = metadata_next(md, MODINFOMD_DEPLIST);
389 } while (md);
390 if (!error)
391 return (0);
392 /* Load failed; discard everything */
393 while (base_file != NULL) {
394 fp = base_file;
395 base_file = base_file->f_next;
396 file_discard(fp);
397 }
398 return (error);
399}
400
401/*
402 * We've been asked to load (fname) as (type), so just suck it in,
403 * no arguments or anything.
404 */
405struct preloaded_file *
406file_loadraw(const char *fname, char *type, int insert)
407{
408 struct preloaded_file *fp;
409 char *name;
410 int fd, got;
411 vm_offset_t laddr;
412
413 /* We can't load first */
414 if ((file_findfile(NULL, NULL)) == NULL) {
415 command_errmsg = "can't load file before kernel";
416 return(NULL);
417 }
418
419 /* locate the file on the load path */
420 name = file_search(fname, NULL);
421 if (name == NULL) {
422 sprintf(command_errbuf, "can't find '%s'", fname);
423 return(NULL);
424 }
425
426 if ((fd = open(name, O_RDONLY)) < 0) {
427 sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno));
428 free(name);
429 return(NULL);
430 }
431
432 if (archsw.arch_loadaddr != NULL)
433 loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
434
435 printf("%s ", name);
436
437 laddr = loadaddr;
438 for (;;) {
439 /* read in 4k chunks; size is not really important */
440 got = archsw.arch_readin(fd, laddr, 4096);
441 if (got == 0) /* end of file */
442 break;
443 if (got < 0) { /* error */
444 sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno));
445 free(name);
446 close(fd);
447 return(NULL);
448 }
449 laddr += got;
450 }
451
452 printf("size=%#jx\n", (uintmax_t)(laddr - loadaddr));
453
454 /* Looks OK so far; create & populate control structure */
455 fp = file_alloc();
456 fp->f_name = strdup(name);
457 fp->f_type = strdup(type);
458 fp->f_args = NULL;
459 fp->f_metadata = NULL;
460 fp->f_loader = -1;
461 fp->f_addr = loadaddr;
462 fp->f_size = laddr - loadaddr;
463
464 /* recognise space consumption */
465 loadaddr = laddr;
466
467 /* Add to the list of loaded files */
468 if (insert != 0)
469 file_insert_tail(fp);
470 close(fd);
471 return(fp);
472}
473
474/*
475 * Load the module (name), pass it (argc),(argv), add container file
476 * to the list of loaded files.
477 * If module is already loaded just assign new argc/argv.
478 */
479int
480mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
481{
482 struct kernel_module *mp;
483 int err;
484 char *filename;
485
486 if (file_havepath(modname)) {
487 printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
488 return (mod_loadkld(modname, argc, argv));
489 }
490 /* see if module is already loaded */
491 mp = file_findmodule(NULL, modname, verinfo);
492 if (mp) {
493#ifdef moduleargs
494 if (mp->m_args)
495 free(mp->m_args);
496 mp->m_args = unargv(argc, argv);
497#endif
498 sprintf(command_errbuf, "warning: module '%s' already loaded", mp->m_name);
499 return (0);
500 }
501 /* locate file with the module on the search path */
502 filename = mod_searchmodule(modname, verinfo);
503 if (filename == NULL) {
504 sprintf(command_errbuf, "can't find '%s'", modname);
505 return (ENOENT);
506 }
507 err = mod_loadkld(filename, argc, argv);
508 return (err);
509}
510
511/*
512 * Load specified KLD. If path is omitted, then try to locate it via
513 * search path.
514 */
515int
516mod_loadkld(const char *kldname, int argc, char *argv[])
517{
518 struct preloaded_file *fp, *last_file;
519 int err;
520 char *filename;
521
522 /*
523 * Get fully qualified KLD name
524 */
525 filename = file_search(kldname, kld_ext_list);
526 if (filename == NULL) {
527 sprintf(command_errbuf, "can't find '%s'", kldname);
528 return (ENOENT);
529 }
530 /*
531 * Check if KLD already loaded
532 */
533 fp = file_findfile(filename, NULL);
534 if (fp) {
535 sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename);
536 free(filename);
537 return (0);
538 }
539 for (last_file = preloaded_files;
540 last_file != NULL && last_file->f_next != NULL;
541 last_file = last_file->f_next)
542 ;
543
544 do {
545 err = file_load(filename, loadaddr, &fp);
546 if (err)
547 break;
548 fp->f_args = unargv(argc, argv);
549 loadaddr = fp->f_addr + fp->f_size;
550 file_insert_tail(fp); /* Add to the list of loaded files */
551 if (file_load_dependencies(fp) != 0) {
552 err = ENOENT;
553 last_file->f_next = NULL;
554 loadaddr = last_file->f_addr + last_file->f_size;
555 fp = NULL;
556 break;
557 }
558 } while(0);
559 if (err == EFTYPE)
560 sprintf(command_errbuf, "don't know how to load module '%s'", filename);
561 if (err && fp)
562 file_discard(fp);
563 free(filename);
564 return (err);
565}
566
567/*
568 * Find a file matching (name) and (type).
569 * NULL may be passed as a wildcard to either.
570 */
571struct preloaded_file *
572file_findfile(const char *name, const char *type)
573{
574 struct preloaded_file *fp;
575
576 for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
577 if (((name == NULL) || !strcmp(name, fp->f_name)) &&
578 ((type == NULL) || !strcmp(type, fp->f_type)))
579 break;
580 }
581 return (fp);
582}
583
584/*
585 * Find a module matching (name) inside of given file.
586 * NULL may be passed as a wildcard.
587 */
588struct kernel_module *
589file_findmodule(struct preloaded_file *fp, char *modname,
590 struct mod_depend *verinfo)
591{
592 struct kernel_module *mp, *best;
593 int bestver, mver;
594
595 if (fp == NULL) {
596 for (fp = preloaded_files; fp; fp = fp->f_next) {
597 mp = file_findmodule(fp, modname, verinfo);
598 if (mp)
599 return (mp);
600 }
601 return (NULL);
602 }
603 best = NULL;
604 bestver = 0;
605 for (mp = fp->f_modules; mp; mp = mp->m_next) {
606 if (strcmp(modname, mp->m_name) == 0) {
607 if (verinfo == NULL)
608 return (mp);
609 mver = mp->m_version;
610 if (mver == verinfo->md_ver_preferred)
611 return (mp);
612 if (mver >= verinfo->md_ver_minimum &&
613 mver <= verinfo->md_ver_maximum &&
614 mver > bestver) {
615 best = mp;
616 bestver = mver;
617 }
618 }
619 }
620 return (best);
621}
622/*
623 * Make a copy of (size) bytes of data from (p), and associate them as
624 * metadata of (type) to the module (mp).
625 */
626void
627file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
628{
629 struct file_metadata *md;
630
631 md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
632 md->md_size = size;
633 md->md_type = type;
634 bcopy(p, md->md_data, size);
635 md->md_next = fp->f_metadata;
636 fp->f_metadata = md;
637}
638
639/*
640 * Find a metadata object of (type) associated with the file (fp)
641 */
642struct file_metadata *
643file_findmetadata(struct preloaded_file *fp, int type)
644{
645 struct file_metadata *md;
646
647 for (md = fp->f_metadata; md != NULL; md = md->md_next)
648 if (md->md_type == type)
649 break;
650 return(md);
651}
652
653/*
654 * Remove all metadata from the file.
655 */
656void
657file_removemetadata(struct preloaded_file *fp)
658{
659 struct file_metadata *md, *next;
660
661 for (md = fp->f_metadata; md != NULL; md = next)
662 {
663 next = md->md_next;
664 free(md);
665 }
666 fp->f_metadata = NULL;
667}
668
669struct file_metadata *
670metadata_next(struct file_metadata *md, int type)
671{
672 if (md == NULL)
673 return (NULL);
674 while((md = md->md_next) != NULL)
675 if (md->md_type == type)
676 break;
677 return (md);
678}
679
680static char *emptyextlist[] = { "", NULL };
681
682/*
683 * Check if the given file is in place and return full path to it.
684 */
685static char *
686file_lookup(const char *path, const char *name, int namelen, char **extlist)
687{
688 struct stat st;
689 char *result, *cp, **cpp;
690 int pathlen, extlen, len;
691
692 pathlen = strlen(path);
693 extlen = 0;
694 if (extlist == NULL)
695 extlist = emptyextlist;
696 for (cpp = extlist; *cpp; cpp++) {
697 len = strlen(*cpp);
698 if (len > extlen)
699 extlen = len;
700 }
701 result = malloc(pathlen + namelen + extlen + 2);
702 if (result == NULL)
703 return (NULL);
704 bcopy(path, result, pathlen);
705 if (pathlen > 0 && result[pathlen - 1] != '/')
706 result[pathlen++] = '/';
707 cp = result + pathlen;
708 bcopy(name, cp, namelen);
709 cp += namelen;
710 for (cpp = extlist; *cpp; cpp++) {
711 strcpy(cp, *cpp);
712 if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
713 return result;
714 }
715 free(result);
716 return NULL;
717}
718
719/*
720 * Check if file name have any qualifiers
721 */
722static int
723file_havepath(const char *name)
724{
725 const char *cp;
726
727 archsw.arch_getdev(NULL, name, &cp);
728 return (cp != name || strchr(name, '/') != NULL);
729}
730
731/*
732 * Attempt to find the file (name) on the module searchpath.
733 * If (name) is qualified in any way, we simply check it and
734 * return it or NULL. If it is not qualified, then we attempt
735 * to construct a path using entries in the environment variable
736 * module_path.
737 *
738 * The path we return a pointer to need never be freed, as we manage
739 * it internally.
740 */
741static char *
742file_search(const char *name, char **extlist)
743{
744 struct moduledir *mdp;
745 struct stat sb;
746 char *result;
747 int namelen;
748
749 /* Don't look for nothing */
750 if (name == NULL)
751 return(NULL);
752
753 if (*name == 0)
754 return(strdup(name));
755
756 if (file_havepath(name)) {
757 /* Qualified, so just see if it exists */
758 if (stat(name, &sb) == 0)
759 return(strdup(name));
760 return(NULL);
761 }
762 moduledir_rebuild();
763 result = NULL;
764 namelen = strlen(name);
765 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
766 result = file_lookup(mdp->d_path, name, namelen, extlist);
767 if (result)
768 break;
769 }
770 return(result);
771}
772
773#define INT_ALIGN(base, ptr) ptr = \
774 (base) + roundup2((ptr) - (base), sizeof(int))
775
776static char *
777mod_search_hints(struct moduledir *mdp, const char *modname,
778 struct mod_depend *verinfo)
779{
780 u_char *cp, *recptr, *bufend, *best;
781 char *result;
782 int *intp, bestver, blen, clen, found, ival, modnamelen, reclen;
783
784 moduledir_readhints(mdp);
785 modnamelen = strlen(modname);
786 found = 0;
787 result = NULL;
788 bestver = 0;
789 if (mdp->d_hints == NULL)
790 goto bad;
791 recptr = mdp->d_hints;
792 bufend = recptr + mdp->d_hintsz;
793 clen = blen = 0;
794 best = cp = NULL;
795 while (recptr < bufend && !found) {
796 intp = (int*)recptr;
797 reclen = *intp++;
798 ival = *intp++;
799 cp = (u_char*)intp;
800 switch (ival) {
801 case MDT_VERSION:
802 clen = *cp++;
803 if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
804 break;
805 cp += clen;
806 INT_ALIGN(mdp->d_hints, cp);
807 ival = *(int*)cp;
808 cp += sizeof(int);
809 clen = *cp++;
810 if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
811 found = 1;
812 break;
813 }
814 if (ival >= verinfo->md_ver_minimum &&
815 ival <= verinfo->md_ver_maximum &&
816 ival > bestver) {
817 bestver = ival;
818 best = cp;
819 blen = clen;
820 }
821 break;
822 default:
823 break;
824 }
825 recptr += reclen + sizeof(int);
826 }
827 /*
828 * Finally check if KLD is in the place
829 */
830 if (found)
831 result = file_lookup(mdp->d_path, (const char *)cp, clen, NULL);
832 else if (best)
833 result = file_lookup(mdp->d_path, (const char *)best, blen, NULL);
834bad:
835 /*
836 * If nothing found or hints is absent - fallback to the old way
837 * by using "kldname[.ko]" as module name.
838 */
839 if (!found && !bestver && result == NULL)
840 result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
841 return result;
842}
843
844/*
845 * Attempt to locate the file containing the module (name)
846 */
847static char *
848mod_searchmodule(char *name, struct mod_depend *verinfo)
849{
850 struct moduledir *mdp;
851 char *result;
852
853 moduledir_rebuild();
854 /*
855 * Now we ready to lookup module in the given directories
856 */
857 result = NULL;
858 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
859 result = mod_search_hints(mdp, name, verinfo);
860 if (result)
861 break;
862 }
863
864 return(result);
865}
866
867int
868file_addmodule(struct preloaded_file *fp, char *modname, int version,
869 struct kernel_module **newmp)
870{
871 struct kernel_module *mp;
872 struct mod_depend mdepend;
873
874 bzero(&mdepend, sizeof(mdepend));
875 mdepend.md_ver_preferred = version;
876 mp = file_findmodule(fp, modname, &mdepend);
877 if (mp)
878 return (EEXIST);
879 mp = malloc(sizeof(struct kernel_module));
880 if (mp == NULL)
881 return (ENOMEM);
882 bzero(mp, sizeof(struct kernel_module));
883 mp->m_name = strdup(modname);
884 mp->m_version = version;
885 mp->m_fp = fp;
886 mp->m_next = fp->f_modules;
887 fp->f_modules = mp;
888 if (newmp)
889 *newmp = mp;
890 return (0);
891}
892
893/*
894 * Throw a file away
895 */
896void
897file_discard(struct preloaded_file *fp)
898{
899 struct file_metadata *md, *md1;
900 struct kernel_module *mp, *mp1;
901 if (fp == NULL)
902 return;
903 md = fp->f_metadata;
904 while (md) {
905 md1 = md;
906 md = md->md_next;
907 free(md1);
908 }
909 mp = fp->f_modules;
910 while (mp) {
911 if (mp->m_name)
912 free(mp->m_name);
913 mp1 = mp;
914 mp = mp->m_next;
915 free(mp1);
916 }
917 if (fp->f_name != NULL)
918 free(fp->f_name);
919 if (fp->f_type != NULL)
920 free(fp->f_type);
921 if (fp->f_args != NULL)
922 free(fp->f_args);
923 free(fp);
924}
925
926/*
927 * Allocate a new file; must be used instead of malloc()
928 * to ensure safe initialisation.
929 */
930struct preloaded_file *
931file_alloc(void)
932{
933 struct preloaded_file *fp;
934
935 if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
936 bzero(fp, sizeof(struct preloaded_file));
937 }
938 return (fp);
939}
940
941/*
942 * Add a module to the chain
943 */
944static void
945file_insert_tail(struct preloaded_file *fp)
946{
947 struct preloaded_file *cm;
948
949 /* Append to list of loaded file */
950 fp->f_next = NULL;
951 if (preloaded_files == NULL) {
952 preloaded_files = fp;
953 } else {
954 for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
955 ;
956 cm->f_next = fp;
957 }
958}
959
960static char *
961moduledir_fullpath(struct moduledir *mdp, const char *fname)
962{
963 char *cp;
964
965 cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
966 if (cp == NULL)
967 return NULL;
968 strcpy(cp, mdp->d_path);
969 strcat(cp, "/");
970 strcat(cp, fname);
971 return (cp);
972}
973
974/*
975 * Read linker.hints file into memory performing some sanity checks.
976 */
977static void
978moduledir_readhints(struct moduledir *mdp)
979{
980 struct stat st;
981 char *path;
982 int fd, size, version;
983
984 if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
985 return;
986 path = moduledir_fullpath(mdp, "linker.hints");
987 if (stat(path, &st) != 0 ||
988 st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
989 st.st_size > LINKER_HINTS_MAX || (fd = open(path, O_RDONLY)) < 0) {
990 free(path);
991 mdp->d_flags |= MDIR_NOHINTS;
992 return;
993 }
994 free(path);
995 size = read(fd, &version, sizeof(version));
996 if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
997 goto bad;
998 size = st.st_size - size;
999 mdp->d_hints = malloc(size);
1000 if (mdp->d_hints == NULL)
1001 goto bad;
1002 if (read(fd, mdp->d_hints, size) != size)
1003 goto bad;
1004 mdp->d_hintsz = size;
1005 close(fd);
1006 return;
1007bad:
1008 close(fd);
1009 if (mdp->d_hints) {
1010 free(mdp->d_hints);
1011 mdp->d_hints = NULL;
1012 }
1013 mdp->d_flags |= MDIR_NOHINTS;
1014 return;
1015}
1016
1017/*
1018 * Extract directories from the ';' separated list, remove duplicates.
1019 */
1020static void
1021moduledir_rebuild(void)
1022{
1023 struct moduledir *mdp, *mtmp;
1024 const char *path, *cp, *ep;
1025 size_t cplen;
1026
1027 path = getenv("module_path");
1028 if (path == NULL)
1029 path = default_searchpath;
1030 /*
1031 * Rebuild list of module directories if it changed
1032 */
1033 STAILQ_FOREACH(mdp, &moduledir_list, d_link)
1034 mdp->d_flags |= MDIR_REMOVED;
1035
1036 for (ep = path; *ep != 0; ep++) {
1037 cp = ep;
1038 for (; *ep != 0 && *ep != ';'; ep++)
1039 ;
1040 /*
1041 * Ignore trailing slashes
1042 */
1043 for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
1044 ;
1045 STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1046 if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
1047 continue;
1048 mdp->d_flags &= ~MDIR_REMOVED;
1049 break;
1050 }
1051 if (mdp == NULL) {
1052 mdp = malloc(sizeof(*mdp) + cplen + 1);
1053 if (mdp == NULL)
1054 return;
1055 mdp->d_path = (char*)(mdp + 1);
1056 bcopy(cp, mdp->d_path, cplen);
1057 mdp->d_path[cplen] = 0;
1058 mdp->d_hints = NULL;
1059 mdp->d_flags = 0;
1060 STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1061 }
1062 if (*ep == 0)
1063 break;
1064 }
1065 /*
1066 * Delete unused directories if any
1067 */
1068 mdp = STAILQ_FIRST(&moduledir_list);
1069 while (mdp) {
1070 if ((mdp->d_flags & MDIR_REMOVED) == 0) {
1071 mdp = STAILQ_NEXT(mdp, d_link);
1072 } else {
1073 if (mdp->d_hints)
1074 free(mdp->d_hints);
1075 mtmp = mdp;
1076 mdp = STAILQ_NEXT(mdp, d_link);
1077 STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
1078 free(mtmp);
1079 }
1080 }
1081 return;
1082}