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