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