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