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 <string.h> 18 #include <err.h> 19 #include <sys/ioctl.h> 20 #include <sys/param.h> 21 #include <sys/module.h> 22 #include <sys/linker.h> 23 #include <sys/mdioctl.h> 24 #include <sys/sysctl.h> 25 #include <sys/queue.h> 26 27 int list(const int); 28 void mdmaybeload(void); 29 int query(const int, const int); 30 void usage(void); 31 32 struct md_ioctl mdio; 33 34 enum {UNSET, ATTACH, DETACH, LIST} action = UNSET; 35 36 void 37 usage() 38 { 39 fprintf(stderr, "usage:\n"); 40 fprintf(stderr, "\tmdconfig -a -t type [-o [no]option]... [ -f file] [-s size] [-S sectorsize] [-u unit]\n"); 41 fprintf(stderr, "\tmdconfig -d -u unit\n"); 42 fprintf(stderr, "\tmdconfig -l [-u unit]\n"); 43 fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n"); 44 fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n"); 45 fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%dk (kB), %%dm (MB) or %%dg (GB)\n"); 46 exit(1); 47 } 48 49 int 50 main(int argc, char **argv) 51 { 52 int ch, fd, i; 53 char *p; 54 int cmdline = 0; 55 56 for (;;) { 57 ch = getopt(argc, argv, "ab:df:lo:s:S:t:u:x:y:"); 58 if (ch == -1) 59 break; 60 switch (ch) { 61 case 'a': 62 if (cmdline != 0) 63 usage(); 64 action = ATTACH; 65 cmdline = 1; 66 break; 67 case 'd': 68 if (cmdline != 0) 69 usage(); 70 action = DETACH; 71 mdio.md_options = MD_AUTOUNIT; 72 cmdline = 3; 73 break; 74 case 'l': 75 if (cmdline != 0) 76 usage(); 77 action = LIST; 78 mdio.md_options = MD_AUTOUNIT; 79 cmdline = 3; 80 break; 81 case 't': 82 if (cmdline != 1) 83 usage(); 84 if (!strcmp(optarg, "malloc")) { 85 mdio.md_type = MD_MALLOC; 86 mdio.md_options = MD_AUTOUNIT | MD_COMPRESS; 87 } else if (!strcmp(optarg, "preload")) { 88 mdio.md_type = MD_PRELOAD; 89 mdio.md_options = 0; 90 } else if (!strcmp(optarg, "vnode")) { 91 mdio.md_type = MD_VNODE; 92 mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 93 } else if (!strcmp(optarg, "swap")) { 94 mdio.md_type = MD_SWAP; 95 mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 96 } else { 97 usage(); 98 } 99 cmdline=2; 100 break; 101 case 'f': 102 if (cmdline != 1 && cmdline != 2) 103 usage(); 104 if (cmdline == 1) { 105 /* Imply ``-t vnode'' */ 106 mdio.md_type = MD_VNODE; 107 mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 108 cmdline = 2; 109 } 110 mdio.md_file = optarg; 111 break; 112 case 'o': 113 if (cmdline != 2) 114 usage(); 115 if (!strcmp(optarg, "cluster")) 116 mdio.md_options |= MD_CLUSTER; 117 else if (!strcmp(optarg, "nocluster")) 118 mdio.md_options &= ~MD_CLUSTER; 119 else if (!strcmp(optarg, "compress")) 120 mdio.md_options |= MD_COMPRESS; 121 else if (!strcmp(optarg, "nocompress")) 122 mdio.md_options &= ~MD_COMPRESS; 123 else if (!strcmp(optarg, "force")) 124 mdio.md_options |= MD_FORCE; 125 else if (!strcmp(optarg, "noforce")) 126 mdio.md_options &= ~MD_FORCE; 127 else if (!strcmp(optarg, "reserve")) 128 mdio.md_options |= MD_RESERVE; 129 else if (!strcmp(optarg, "noreserve")) 130 mdio.md_options &= ~MD_RESERVE; 131 else 132 errx(1, "Unknown option."); 133 break; 134 case 'S': 135 if (cmdline != 2) 136 usage(); 137 mdio.md_secsize = strtoul(optarg, &p, 0); 138 break; 139 case 's': 140 if (cmdline != 2) 141 usage(); 142 mdio.md_size = strtoul(optarg, &p, 0); 143 if (p == NULL || *p == '\0') 144 ; 145 else if (*p == 'k' || *p == 'K') 146 mdio.md_size *= (1024 / DEV_BSIZE); 147 else if (*p == 'm' || *p == 'M') 148 mdio.md_size *= (1024 * 1024 / DEV_BSIZE); 149 else if (*p == 'g' || *p == 'G') 150 mdio.md_size *= (1024 * 1024 * 1024 / DEV_BSIZE); 151 else 152 errx(1, "Unknown suffix on -s argument"); 153 break; 154 case 'u': 155 if (cmdline != 2 && cmdline != 3) 156 usage(); 157 if (!strncmp(optarg, "/dev/", 5)) 158 optarg += 5; 159 if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1)) 160 optarg += sizeof(MD_NAME) - 1; 161 mdio.md_unit = strtoul(optarg, &p, 0); 162 if ((unsigned)mdio.md_unit == ULONG_MAX || *p != '\0') 163 errx(1, "bad unit: %s", optarg); 164 mdio.md_options &= ~MD_AUTOUNIT; 165 break; 166 case 'x': 167 if (cmdline != 2) 168 usage(); 169 mdio.md_fwsectors = strtoul(optarg, &p, 0); 170 break; 171 case 'y': 172 if (cmdline != 2) 173 usage(); 174 mdio.md_fwheads = strtoul(optarg, &p, 0); 175 break; 176 default: 177 usage(); 178 } 179 } 180 mdio.md_version = MDIOVERSION; 181 182 mdmaybeload(); 183 fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 184 if (fd < 0) 185 err(1, "open(/dev/%s)", MDCTL_NAME); 186 if (cmdline == 2 187 && (mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP)) 188 if (mdio.md_size == 0) 189 errx(1, "must specify -s for -t malloc or -t swap"); 190 if (cmdline == 2 && mdio.md_type == MD_VNODE) 191 if (mdio.md_file == NULL) 192 errx(1, "must specify -f for -t vnode"); 193 if (action == LIST) { 194 if (mdio.md_options & MD_AUTOUNIT) 195 list(fd); 196 else 197 query(fd, mdio.md_unit); 198 } else if (action == ATTACH) { 199 if (cmdline < 2) 200 usage(); 201 i = ioctl(fd, MDIOCATTACH, &mdio); 202 if (i < 0) 203 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 204 if (mdio.md_options & MD_AUTOUNIT) 205 printf("%s%d\n", MD_NAME, mdio.md_unit); 206 } else if (action == DETACH) { 207 if (mdio.md_options & MD_AUTOUNIT) 208 usage(); 209 i = ioctl(fd, MDIOCDETACH, &mdio); 210 if (i < 0) 211 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 212 } else 213 usage(); 214 close (fd); 215 return (0); 216 } 217 218 struct dl { 219 int unit; 220 SLIST_ENTRY(dl) slist; 221 }; 222 223 SLIST_HEAD(, dl) dlist = SLIST_HEAD_INITIALIZER(&dlist); 224 225 int 226 list(const int fd) 227 { 228 int unit; 229 230 if (ioctl(fd, MDIOCLIST, &mdio) < 0) 231 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 232 for (unit = 0; unit < mdio.md_pad[0] && unit < MDNPAD - 1; unit++) { 233 printf("%smd%d", unit > 0 ? " " : "", mdio.md_pad[unit + 1]); 234 } 235 if (mdio.md_pad[0] - unit > 0) 236 printf(" ... %d more", mdio.md_pad[0] - unit); 237 printf("\n"); 238 return (0); 239 } 240 241 int 242 query(const int fd, const int unit) 243 { 244 245 mdio.md_version = MDIOVERSION; 246 mdio.md_unit = unit; 247 248 if (ioctl(fd, MDIOCQUERY, &mdio) < 0) 249 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 250 251 switch (mdio.md_type) { 252 case MD_MALLOC: 253 (void)printf("%s%d\tmalloc\t%d KBytes\n", MD_NAME, 254 mdio.md_unit, mdio.md_size / 2); 255 break; 256 case MD_PRELOAD: 257 (void)printf("%s%d\tpreload\t%d KBytes\n", MD_NAME, 258 mdio.md_unit, mdio.md_size / 2); 259 break; 260 case MD_SWAP: 261 (void)printf("%s%d\tswap\t%d KBytes\n", MD_NAME, 262 mdio.md_unit, mdio.md_size / 2); 263 break; 264 case MD_VNODE: 265 (void)printf("%s%d\tvnode\t%d KBytes\n", MD_NAME, 266 mdio.md_unit, mdio.md_size / 2); 267 break; 268 } 269 270 return (0); 271 } 272 273 void 274 mdmaybeload(void) 275 { 276 struct module_stat mstat; 277 int fileid, modid; 278 const char *name; 279 char *cp; 280 281 name = MD_NAME; 282 /* scan files in kernel */ 283 mstat.version = sizeof(struct module_stat); 284 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 285 /* scan modules in file */ 286 for (modid = kldfirstmod(fileid); modid > 0; 287 modid = modfnext(modid)) { 288 if (modstat(modid, &mstat) < 0) 289 continue; 290 /* strip bus name if present */ 291 if ((cp = strchr(mstat.name, '/')) != NULL) { 292 cp++; 293 } else { 294 cp = mstat.name; 295 } 296 /* already loaded? */ 297 if (!strcmp(name, cp)) 298 return; 299 } 300 } 301 /* not present, we should try to load it */ 302 kldload(name); 303 } 304 305