mdconfig.c revision 134965
1/* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 * 9 * $FreeBSD: head/sbin/mdconfig/mdconfig.c 134965 2004-09-08 20:28:29Z jmg $ 10 * 11 */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <fcntl.h> 16#include <unistd.h> 17#include <string.h> 18#include <err.h> 19#include <sys/ioctl.h> 20#include <sys/param.h> 21#include <sys/module.h> 22#include <sys/linker.h> 23#include <sys/mdioctl.h> 24#include <sys/sysctl.h> 25#include <sys/queue.h> 26 27int list(const int); 28void mdmaybeload(void); 29int query(const int, const int); 30void usage(void); 31 32struct md_ioctl mdio; 33 34enum {UNSET, ATTACH, DETACH, LIST} action = UNSET; 35 36int nflag; 37 38void 39usage() 40{ 41 fprintf(stderr, "usage:\n"); 42 fprintf(stderr, "\tmdconfig -a -t type [-n] [-o [no]option]... [ -f file] [-s size] [-S sectorsize] [-u unit]\n"); 43 fprintf(stderr, "\tmdconfig -d -u unit\n"); 44 fprintf(stderr, "\tmdconfig -l [-n] [-u unit]\n"); 45 fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n"); 46 fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n"); 47 fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%dk (kB), %%dm (MB) or %%dg (GB)\n"); 48 exit(1); 49} 50 51int 52main(int argc, char **argv) 53{ 54 int ch, fd, i; 55 char *p; 56 int cmdline = 0; 57 58 for (;;) { 59 ch = getopt(argc, argv, "ab:df:lno:s:S:t:u:x:y:"); 60 if (ch == -1) 61 break; 62 switch (ch) { 63 case 'a': 64 if (cmdline != 0) 65 usage(); 66 action = ATTACH; 67 cmdline = 1; 68 break; 69 case 'd': 70 if (cmdline != 0) 71 usage(); 72 action = DETACH; 73 mdio.md_options = MD_AUTOUNIT; 74 cmdline = 3; 75 break; 76 case 'l': 77 if (cmdline != 0) 78 usage(); 79 action = LIST; 80 mdio.md_options = MD_AUTOUNIT; 81 cmdline = 3; 82 break; 83 case 'n': 84 nflag = 1; 85 break; 86 case 't': 87 if (cmdline != 1) 88 usage(); 89 if (!strcmp(optarg, "malloc")) { 90 mdio.md_type = MD_MALLOC; 91 mdio.md_options = MD_AUTOUNIT | MD_COMPRESS; 92 } else if (!strcmp(optarg, "preload")) { 93 mdio.md_type = MD_PRELOAD; 94 mdio.md_options = 0; 95 } else if (!strcmp(optarg, "vnode")) { 96 mdio.md_type = MD_VNODE; 97 mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 98 } else if (!strcmp(optarg, "swap")) { 99 mdio.md_type = MD_SWAP; 100 mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 101 } else { 102 usage(); 103 } 104 cmdline=2; 105 break; 106 case 'f': 107 if (cmdline != 1 && cmdline != 2) 108 usage(); 109 if (cmdline == 1) { 110 /* Imply ``-t vnode'' */ 111 mdio.md_type = MD_VNODE; 112 mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 113 cmdline = 2; 114 } 115 mdio.md_file = optarg; 116 fd = open(optarg, O_RDONLY); 117 if (fd < 0) 118 err(1, "could not open %s", optarg); 119 close(fd); 120 break; 121 case 'o': 122 if (cmdline != 2) 123 usage(); 124 if (!strcmp(optarg, "async")) 125 mdio.md_options |= MD_ASYNC; 126 else if (!strcmp(optarg, "noasync")) 127 mdio.md_options &= ~MD_ASYNC; 128 else if (!strcmp(optarg, "cluster")) 129 mdio.md_options |= MD_CLUSTER; 130 else if (!strcmp(optarg, "nocluster")) 131 mdio.md_options &= ~MD_CLUSTER; 132 else if (!strcmp(optarg, "compress")) 133 mdio.md_options |= MD_COMPRESS; 134 else if (!strcmp(optarg, "nocompress")) 135 mdio.md_options &= ~MD_COMPRESS; 136 else if (!strcmp(optarg, "force")) 137 mdio.md_options |= MD_FORCE; 138 else if (!strcmp(optarg, "noforce")) 139 mdio.md_options &= ~MD_FORCE; 140 else if (!strcmp(optarg, "readonly")) 141 mdio.md_options |= MD_READONLY; 142 else if (!strcmp(optarg, "noreadonly")) 143 mdio.md_options &= ~MD_READONLY; 144 else if (!strcmp(optarg, "reserve")) 145 mdio.md_options |= MD_RESERVE; 146 else if (!strcmp(optarg, "noreserve")) 147 mdio.md_options &= ~MD_RESERVE; 148 else 149 errx(1, "Unknown option: %s.", optarg); 150 break; 151 case 'S': 152 if (cmdline != 2) 153 usage(); 154 mdio.md_secsize = strtoul(optarg, &p, 0); 155 break; 156 case 's': 157 if (cmdline != 2) 158 usage(); 159 mdio.md_size = strtoul(optarg, &p, 0); 160 if (p == NULL || *p == '\0') 161 ; 162 else if (*p == 'k' || *p == 'K') 163 mdio.md_size *= (1024 / DEV_BSIZE); 164 else if (*p == 'm' || *p == 'M') 165 mdio.md_size *= (1024 * 1024 / DEV_BSIZE); 166 else if (*p == 'g' || *p == 'G') 167 mdio.md_size *= (1024 * 1024 * 1024 / DEV_BSIZE); 168 else 169 errx(1, "Unknown suffix on -s argument"); 170 break; 171 case 'u': 172 if (cmdline != 2 && cmdline != 3) 173 usage(); 174 if (!strncmp(optarg, "/dev/", 5)) 175 optarg += 5; 176 if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1)) 177 optarg += sizeof(MD_NAME) - 1; 178 mdio.md_unit = strtoul(optarg, &p, 0); 179 if (mdio.md_unit == (unsigned)ULONG_MAX || *p != '\0') 180 errx(1, "bad unit: %s", optarg); 181 mdio.md_options &= ~MD_AUTOUNIT; 182 break; 183 case 'x': 184 if (cmdline != 2) 185 usage(); 186 mdio.md_fwsectors = strtoul(optarg, &p, 0); 187 break; 188 case 'y': 189 if (cmdline != 2) 190 usage(); 191 mdio.md_fwheads = strtoul(optarg, &p, 0); 192 break; 193 default: 194 usage(); 195 } 196 } 197 mdio.md_version = MDIOVERSION; 198 199 mdmaybeload(); 200 fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 201 if (fd < 0) 202 err(1, "open(/dev/%s)", MDCTL_NAME); 203 if (cmdline == 2 204 && (mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP)) 205 if (mdio.md_size == 0) 206 errx(1, "must specify -s for -t malloc or -t swap"); 207 if (cmdline == 2 && mdio.md_type == MD_VNODE) 208 if (mdio.md_file == NULL) 209 errx(1, "must specify -f for -t vnode"); 210 if (action == LIST) { 211 if (mdio.md_options & MD_AUTOUNIT) 212 list(fd); 213 else 214 query(fd, mdio.md_unit); 215 } else if (action == ATTACH) { 216 if (cmdline < 2) 217 usage(); 218 i = ioctl(fd, MDIOCATTACH, &mdio); 219 if (i < 0) 220 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 221 if (mdio.md_options & MD_AUTOUNIT) 222 printf("%s%d\n", nflag ? "" : MD_NAME, mdio.md_unit); 223 } else if (action == DETACH) { 224 if (mdio.md_options & MD_AUTOUNIT) 225 usage(); 226 i = ioctl(fd, MDIOCDETACH, &mdio); 227 if (i < 0) 228 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 229 } else 230 usage(); 231 close (fd); 232 return (0); 233} 234 235struct dl { 236 int unit; 237 SLIST_ENTRY(dl) slist; 238}; 239 240SLIST_HEAD(, dl) dlist = SLIST_HEAD_INITIALIZER(&dlist); 241 242int 243list(const int fd) 244{ 245 int unit; 246 247 if (ioctl(fd, MDIOCLIST, &mdio) < 0) 248 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 249 for (unit = 0; unit < mdio.md_pad[0] && unit < MDNPAD - 1; unit++) { 250 printf("%s%s%d", unit > 0 ? " " : "", 251 nflag ? "" : MD_NAME, mdio.md_pad[unit + 1]); 252 } 253 if (mdio.md_pad[0] - unit > 0) 254 printf(" ... %d more", mdio.md_pad[0] - unit); 255 printf("\n"); 256 return (0); 257} 258 259int 260query(const int fd, const int unit) 261{ 262 263 mdio.md_version = MDIOVERSION; 264 mdio.md_unit = unit; 265 266 if (ioctl(fd, MDIOCQUERY, &mdio) < 0) 267 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 268 269 switch (mdio.md_type) { 270 case MD_MALLOC: 271 (void)printf("%s%d\tmalloc\t%d KBytes\n", MD_NAME, 272 mdio.md_unit, mdio.md_size / 2); 273 break; 274 case MD_PRELOAD: 275 (void)printf("%s%d\tpreload\t%d KBytes\n", MD_NAME, 276 mdio.md_unit, mdio.md_size / 2); 277 break; 278 case MD_SWAP: 279 (void)printf("%s%d\tswap\t%d KBytes\n", MD_NAME, 280 mdio.md_unit, mdio.md_size / 2); 281 break; 282 case MD_VNODE: 283 (void)printf("%s%d\tvnode\t%d KBytes\n", MD_NAME, 284 mdio.md_unit, mdio.md_size / 2); 285 break; 286 } 287 288 return (0); 289} 290 291void 292mdmaybeload(void) 293{ 294 struct module_stat mstat; 295 int fileid, modid; 296 const char *name; 297 char *cp; 298 299 name = MD_MODNAME; 300 /* scan files in kernel */ 301 mstat.version = sizeof(struct module_stat); 302 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 303 /* scan modules in file */ 304 for (modid = kldfirstmod(fileid); modid > 0; 305 modid = modfnext(modid)) { 306 if (modstat(modid, &mstat) < 0) 307 continue; 308 /* strip bus name if present */ 309 if ((cp = strchr(mstat.name, '/')) != NULL) { 310 cp++; 311 } else { 312 cp = mstat.name; 313 } 314 /* already loaded? */ 315 if (!strcmp(name, cp)) 316 return; 317 } 318 } 319 /* not present, we should try to load it */ 320 kldload(name); 321} 322 323