1/* $NetBSD: main.c,v 1.26 2021/04/07 14:45:28 simonb 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: main.c,v 1.26 2021/04/07 14:45:28 simonb Exp $"); 32#endif /* !lint */ 33 34#include <sys/module.h> 35#include <sys/param.h> 36#include <sys/sysctl.h> 37 38#include <err.h> 39#include <errno.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <unistd.h> 44#include <stdbool.h> 45 46#include "prog_ops.h" 47 48static void usage(void) __dead; 49static int modstatcmp(const void *, const void *); 50 51static const char *classes[] = { 52 "any", 53 "misc", 54 "vfs", 55 "driver", 56 "exec", 57 "secmodel", 58 "bufq" 59}; 60const unsigned int class_max = __arraycount(classes); 61 62static const char *sources[] = { 63 "builtin", 64 "boot", 65 "filesys", 66}; 67const unsigned int source_max = __arraycount(sources); 68 69static const char *modflags[] = { 70 "-", "f", "a", "af" 71}; 72 73int 74main(int argc, char **argv) 75{ 76 struct iovec iov; 77 modstat_t *ms; 78 size_t len; 79 const char *name; 80 char sbuf[32]; 81 int ch, rc, modauto = 1; 82 size_t maxnamelen = 16, i, modautolen; 83 char loadable = '\0'; 84 const char *reqoff, *req; 85 bool address = false; 86 87 name = NULL; 88 89 while ((ch = getopt(argc, argv, "Aaekn:")) != -1) { 90 switch (ch) { 91 case 'A': /* FALLTHROUGH */ 92 case 'a': /* FALLTHROUGH */ 93 case 'e': 94 loadable = (char)ch; 95 break; 96 case 'k': 97 address = true; 98 break; 99 case 'n': 100 name = optarg; 101 break; 102 default: 103 usage(); 104 /* NOTREACHED */ 105 } 106 } 107 108 argc -= optind; 109 argv += optind; 110 if (argc == 1 && name == NULL) 111 name = argv[0]; 112 else if (argc != 0) 113 usage(); 114 115 if (prog_init && prog_init() == -1) 116 err(1, "prog init failed"); 117 118 if (loadable == 'A' || loadable == 'a') { 119 if (prog_modctl(MODCTL_EXISTS, (void *)(uintptr_t)1)) { 120 switch (errno) { 121 case ENOSYS: 122 errx(EXIT_FAILURE, "The kernel was compiled " 123 "without options MODULAR."); 124 break; 125 case EPERM: 126 errx(EXIT_FAILURE, "Modules can not be " 127 "autoloaded right now."); 128 break; 129 default: 130 err(EXIT_FAILURE, "modctl_exists for autoload"); 131 break; 132 } 133 } else { 134 if (loadable == 'A') { 135 modautolen = sizeof(modauto); 136 rc = sysctlbyname("kern.module.autoload", 137 &modauto, &modautolen, NULL, 0); 138 if (rc != 0) { 139 err(EXIT_FAILURE, "sysctl " 140 "kern.module.autoload failed."); 141 } 142 } 143 errx(EXIT_SUCCESS, "Modules can be autoloaded%s.", 144 modauto ? "" : ", but kern.module.autoload = 0"); 145 } 146 } 147 148 if (loadable == 'e') { 149 if (prog_modctl(MODCTL_EXISTS, (void *)(uintptr_t)0)) { 150 switch (errno) { 151 case ENOSYS: 152 errx(EXIT_FAILURE, "The kernel was compiled " 153 "without options MODULAR."); 154 break; 155 case EPERM: 156 errx(EXIT_FAILURE, "You are not allowed to " 157 "load modules right now."); 158 break; 159 default: 160 err(EXIT_FAILURE, "modctl_exists for autoload"); 161 break; 162 } 163 } else { 164 errx(EXIT_SUCCESS, "You can load modules."); 165 } 166 } 167 168 for (len = 8192;;) { 169 iov.iov_base = malloc(len); 170 iov.iov_len = len; 171 if (prog_modctl(MODCTL_STAT, &iov)) { 172 err(EXIT_FAILURE, "modctl(MODCTL_STAT)"); 173 } 174 if (len >= iov.iov_len) { 175 break; 176 } 177 free(iov.iov_base); 178 len = iov.iov_len; 179 } 180 181 len = *(int *)iov.iov_base; 182 ms = (modstat_t *)((char *)iov.iov_base + sizeof(int)); 183 184 qsort(ms, len, sizeof(modstat_t), modstatcmp); 185 for (i = 0; i < len; i++, ms++) { 186 size_t namelen = strlen(ms->ms_name); 187 if (maxnamelen < namelen) 188 maxnamelen = namelen; 189 } 190 ms = (modstat_t *)((char *)iov.iov_base + sizeof(int)); 191 reqoff = (char *)(&ms[len]); 192 193 printf("%-*s %-8s %-8s %-4s %5s ", 194 (int)maxnamelen, "NAME", "CLASS", "SOURCE", "FLAG", "REFS"); 195 if (address) 196 printf("%-16s ", "ADDRESS"); 197 printf("%7s %s \n", "SIZE", "REQUIRES"); 198 199 for (; len != 0; ms++, len--) { 200 const char *class; 201 const char *source; 202 203 if (ms->ms_reqoffset == 0) 204 req = "-"; 205 else { 206 req = &reqoff[ms->ms_reqoffset]; 207 } 208 if (name != NULL && strcmp(ms->ms_name, name) != 0) { 209 continue; 210 } 211 if (ms->ms_size == 0) { 212 sbuf[0] = '-'; 213 sbuf[1] = '\0'; 214 } else { 215 snprintf(sbuf, sizeof(sbuf), "%u", ms->ms_size); 216 } 217 if (ms->ms_class <= class_max) 218 class = classes[ms->ms_class]; 219 else 220 class = "UNKNOWN"; 221 if (ms->ms_source < source_max) 222 source = sources[ms->ms_source]; 223 else 224 source = "UNKNOWN"; 225 226 printf("%-*s %-8s %-8s %-4s %5d ", 227 (int)maxnamelen, ms->ms_name, class, source, 228 modflags[ms->ms_flags & (__arraycount(modflags) - 1)], 229 ms->ms_refcnt); 230 if (address) 231 printf("%-16" PRIx64 " ", ms->ms_addr); 232 printf("%7s %s\n", sbuf, (req)); 233 } 234 235 exit(EXIT_SUCCESS); 236} 237 238static void 239usage(void) 240{ 241 242 (void)fprintf(stderr, "Usage: %s [-Aaek] [-n name | name]\n", 243 getprogname()); 244 exit(EXIT_FAILURE); 245} 246 247static int 248modstatcmp(const void *a, const void *b) 249{ 250 const modstat_t *msa, *msb; 251 252 msa = a; 253 msb = b; 254 255 return strcmp(msa->ms_name, msb->ms_name); 256} 257