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