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 23 #include <sys/ioctl.h> 24 #include <sys/param.h> 25 #include <sys/module.h> 26 #include <sys/linker.h> 27 #include <sys/mdioctl.h> 28 #include <sys/stat.h> 29 30 int list(const int); 31 void mdmaybeload(void); 32 int query(const int, const int); 33 void usage(void); 34 35 struct md_ioctl mdio; 36 37 enum {UNSET, ATTACH, DETACH, LIST} action = UNSET; 38 39 int nflag; 40 41 void 42 usage() 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 58 int 59 main(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 mdmaybeload(); 227 fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 228 if (fd < 0) 229 err(1, "open(/dev/%s)", MDCTL_NAME); 230 if (cmdline == 2 231 && (mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP)) 232 if (mdio.md_mediasize == 0) 233 errx(1, "must specify -s for -t malloc or -t swap"); 234 if (cmdline == 2 && mdio.md_type == MD_VNODE) 235 if (mdio.md_file[0] == '\0') 236 errx(1, "must specify -f for -t vnode"); 237 if (mdio.md_type == MD_VNODE && 238 (mdio.md_options & MD_READONLY) == 0) { 239 if (access(mdio.md_file, W_OK) < 0 && 240 (errno == EACCES || errno == EPERM || errno == EROFS)) { 241 fprintf(stderr, 242 "WARNING: opening backing store: %s readonly\n", 243 mdio.md_file); 244 mdio.md_options |= MD_READONLY; 245 } 246 } 247 if (action == LIST) { 248 if (mdio.md_options & MD_AUTOUNIT) 249 list(fd); 250 else 251 query(fd, mdio.md_unit); 252 } else if (action == ATTACH) { 253 if (cmdline < 2) 254 usage(); 255 i = ioctl(fd, MDIOCATTACH, &mdio); 256 if (i < 0) 257 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 258 if (mdio.md_options & MD_AUTOUNIT) 259 printf("%s%d\n", nflag ? "" : MD_NAME, mdio.md_unit); 260 } else if (action == DETACH) { 261 if (mdio.md_options & MD_AUTOUNIT) 262 usage(); 263 i = ioctl(fd, MDIOCDETACH, &mdio); 264 if (i < 0) 265 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 266 } else 267 usage(); 268 close (fd); 269 return (0); 270 } 271 272 int 273 list(const int fd) 274 { 275 int unit; 276 277 if (ioctl(fd, MDIOCLIST, &mdio) < 0) 278 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 279 for (unit = 0; unit < mdio.md_pad[0] && unit < MDNPAD - 1; unit++) { 280 printf("%s%s%d", unit > 0 ? " " : "", 281 nflag ? "" : MD_NAME, mdio.md_pad[unit + 1]); 282 } 283 if (mdio.md_pad[0] - unit > 0) 284 printf(" ... %d more", mdio.md_pad[0] - unit); 285 if (unit > 0) 286 printf("\n"); 287 return (0); 288 } 289 290 static void 291 prthumanval(int64_t bytes) 292 { 293 char buf[6]; 294 295 humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), 296 bytes, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 297 (void)printf("%6s", buf); 298 } 299 300 int 301 query(const int fd, const int unit) 302 { 303 304 mdio.md_version = MDIOVERSION; 305 mdio.md_unit = unit; 306 307 if (ioctl(fd, MDIOCQUERY, &mdio) < 0) 308 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 309 310 (void)printf("%s%d\t", MD_NAME, mdio.md_unit); 311 switch (mdio.md_type) { 312 case MD_MALLOC: 313 (void)printf("malloc"); 314 break; 315 case MD_PRELOAD: 316 (void)printf("preload"); 317 break; 318 case MD_SWAP: 319 (void)printf("swap"); 320 break; 321 case MD_VNODE: 322 (void)printf("vnode"); 323 break; 324 } 325 printf("\t"); 326 prthumanval(mdio.md_mediasize); 327 if (mdio.md_type == MD_VNODE) 328 printf("\t%s", mdio.md_file); 329 printf("\n"); 330 331 return (0); 332 } 333 334 void 335 mdmaybeload(void) 336 { 337 char name1[64], name2[64]; 338 339 snprintf(name1, sizeof(name1), "g_%s", MD_NAME); 340 snprintf(name2, sizeof(name2), "geom_%s", MD_NAME); 341 if (modfind(name1) == -1) { 342 /* Not present in kernel, try loading it. */ 343 if (kldload(name2) == -1 || modfind(name1) == -1) { 344 if (errno != EEXIST) { 345 errx(EXIT_FAILURE, 346 "%s module not available!", name2); 347 } 348 } 349 } 350 } 351