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