1 /* $NetBSD: libkmod.c,v 1.2 2009/06/30 02:44:52 agc Exp $ */
2
3 /*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: libkmod.c,v 1.2 2009/06/30 02:44:52 agc Exp $");
32 #endif /* !lint */
33
34 #include <sys/module.h>
35
36 #include <prop/proplib.h>
37
38 #include <assert.h>
39 #include <err.h>
40 #include <stdbool.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #include "libkmod.h"
47
48 #ifdef USE_LIBKMOD
49
50 static const char *classes[] = {
51 "any",
52 "misc",
53 "vfs",
54 "driver",
55 "exec",
56 };
57
58 static const char *sources[] = {
59 "builtin",
60 "boot",
61 "filesys",
62 };
63
64 /* comparison routine for qsort */
65 static int
modcmp(const void * a,const void * b)66 modcmp(const void *a, const void *b)
67 {
68 const modstat_t *msa, *msb;
69
70 msa = a;
71 msb = b;
72 return strcmp(msa->ms_name, msb->ms_name);
73 }
74
75 /* function which "opens" a module */
76 int
openkmod(kernel_t * kernel)77 openkmod(kernel_t *kernel)
78 {
79 kernel->size = 4096;
80 for (;;) {
81 kernel->iov.iov_base = malloc(kernel->size);
82 kernel->iov.iov_len = kernel->size;
83 if (modctl(MODCTL_STAT, &kernel->iov)) {
84 warn("modctl(MODCTL_STAT)");
85 return 0;
86 }
87 if (kernel->size >= kernel->iov.iov_len) {
88 break;
89 }
90 free(kernel->iov.iov_base);
91 kernel->size = kernel->iov.iov_len;
92 }
93 kernel->size = kernel->iov.iov_len / sizeof(modstat_t);
94 qsort(kernel->iov.iov_base, kernel->size, sizeof(modstat_t), modcmp);
95 return 1;
96 }
97
98 /* return details on the module */
99 int
readkmod(kernel_t * kernel,kmod_t * module)100 readkmod(kernel_t *kernel, kmod_t *module)
101 {
102 modstat_t *ms;
103
104 if (kernel->c * sizeof(*ms) >= kernel->iov.iov_len) {
105 return 0;
106 }
107 ms = kernel->iov.iov_base;
108 ms += kernel->c++;
109 (void) memset(module, 0x0, sizeof(*module));
110 module->name = strdup(ms->ms_name);
111 module->class = strdup(classes[ms->ms_class]);
112 module->source = strdup(sources[ms->ms_source]);
113 module->refcnt = ms->ms_refcnt;
114 module->size = ms->ms_size;
115 if (ms->ms_required[0]) {
116 module->required = strdup(ms->ms_required);
117 }
118 return 1;
119 }
120
121 /* free up all resources allocated in a module read */
122 void
freekmod(kmod_t * module)123 freekmod(kmod_t *module)
124 {
125 (void) free(module->name);
126 (void) free(module->class);
127 (void) free(module->source);
128 if (module->required) {
129 (void) free(module->required);
130 }
131 }
132
133 /* "close" the module */
134 int
closekmod(kernel_t * kernel)135 closekmod(kernel_t *kernel)
136 {
137 (void) free(kernel->iov.iov_base);
138 return 1;
139 }
140
141 /* do the modstat operation */
142 int
kmodstat(const char * modname,FILE * fp)143 kmodstat(const char *modname, FILE *fp)
144 {
145 kernel_t kernel;
146 kmod_t module;
147 int modc;
148
149 (void) memset(&kernel, 0x0, sizeof(kernel));
150 (void) memset(&module, 0x0, sizeof(module));
151 if (!openkmod(&kernel)) {
152 (void) fprintf(stderr, "can't read kernel modules\n");
153 return 0;
154 }
155 for (modc = 0 ; readkmod(&kernel, &module) ; ) {
156 if (modname == NULL || strcmp(modname, module.name) == 0) {
157 if (modc++ == 0) {
158 if (fp) {
159 (void) fprintf(fp,
160 "NAME\t\tCLASS\tSOURCE\tREFS"
161 "\tSIZE\tREQUIRES\n");
162 }
163 }
164 if (fp) {
165 (void) fprintf(fp, "%-16s%s\t%s\t%d\t%u\t%s\n",
166 module.name,
167 module.class,
168 module.source,
169 module.refcnt,
170 module.size,
171 (module.required) ? module.required : "-");
172 }
173 freekmod(&module);
174 }
175 }
176 (void) closekmod(&kernel);
177 return modc;
178 }
179
180 /* load the named module into the kernel */
181 int
kmodload(const char * module)182 kmodload(const char *module)
183 {
184 prop_dictionary_t props;
185 modctl_load_t cmdargs;
186 char *propsstr;
187
188 props = prop_dictionary_create();
189
190 propsstr = prop_dictionary_externalize(props);
191 if (propsstr == NULL) {
192 (void) fprintf(stderr, "Failed to process properties");
193 return 0;
194 }
195
196 cmdargs.ml_filename = module;
197 cmdargs.ml_flags = 0;
198 cmdargs.ml_props = propsstr;
199 cmdargs.ml_propslen = strlen(propsstr);
200
201 if (modctl(MODCTL_LOAD, &cmdargs)) {
202 (void) fprintf(stderr, "modctl failure\n");
203 return 0;
204 }
205
206 (void) free(propsstr);
207 prop_object_release(props);
208
209 return 1;
210 }
211
212 /* and unload the module from the kernel */
213 int
kmodunload(const char * name)214 kmodunload(const char *name)
215 {
216 return modctl(MODCTL_UNLOAD, __UNCONST(name)) == 0;
217 }
218
219 #endif /* USE_LIBKMOD */
220