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 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 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 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 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 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 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 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 214 kmodunload(const char *name) 215 { 216 return modctl(MODCTL_UNLOAD, __UNCONST(name)) == 0; 217 } 218 219 #endif /* USE_LIBKMOD */ 220