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] [-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:t:u:"); 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 } 109 mdio.md_file = optarg; 110 break; 111 case 'o': 112 if (cmdline != 2) 113 usage(); 114 if (!strcmp(optarg, "cluster")) 115 mdio.md_options |= MD_CLUSTER; 116 else if (!strcmp(optarg, "nocluster")) 117 mdio.md_options &= ~MD_CLUSTER; 118 else if (!strcmp(optarg, "compress")) 119 mdio.md_options |= MD_COMPRESS; 120 else if (!strcmp(optarg, "nocompress")) 121 mdio.md_options &= ~MD_COMPRESS; 122 else if (!strcmp(optarg, "force")) 123 mdio.md_options |= MD_FORCE; 124 else if (!strcmp(optarg, "noforce")) 125 mdio.md_options &= ~MD_FORCE; 126 else if (!strcmp(optarg, "reserve")) 127 mdio.md_options |= MD_RESERVE; 128 else if (!strcmp(optarg, "noreserve")) 129 mdio.md_options &= ~MD_RESERVE; 130 else 131 errx(1, "Unknown option."); 132 break; 133 case 's': 134 if (cmdline != 2) 135 usage(); 136 mdio.md_size = strtoul(optarg, &p, 0); 137 if (p == NULL || *p == '\0') 138 ; 139 else if (*p == 'k' || *p == 'K') 140 mdio.md_size *= (1024 / DEV_BSIZE); 141 else if (*p == 'm' || *p == 'M') 142 mdio.md_size *= (1024 * 1024 / DEV_BSIZE); 143 else if (*p == 'g' || *p == 'G') 144 mdio.md_size *= (1024 * 1024 * 1024 / DEV_BSIZE); 145 else 146 errx(1, "Unknown suffix on -s argument"); 147 break; 148 case 'u': 149 if (cmdline != 2 && cmdline != 3) 150 usage(); 151 if (!strncmp(optarg, "/dev/", 5)) 152 optarg += 5; 153 if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1)) 154 optarg += sizeof(MD_NAME) - 1; 155 mdio.md_unit = strtoul(optarg, &p, 0); 156 if ((unsigned)mdio.md_unit == ULONG_MAX || *p != '\0') 157 errx(1, "bad unit: %s", optarg); 158 mdio.md_options &= ~MD_AUTOUNIT; 159 break; 160 default: 161 usage(); 162 } 163 } 164 mdio.md_version = MDIOVERSION; 165 166 mdmaybeload(); 167 fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 168 if (fd < 0) 169 err(1, "open(/dev/%s)", MDCTL_NAME); 170 if (cmdline == 2 171 && (mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP)) 172 if (mdio.md_size == 0) 173 errx(1, "must specify -s for -t malloc or -t swap"); 174 if (action == LIST) { 175 if (mdio.md_options & MD_AUTOUNIT) 176 list(fd); 177 else 178 query(fd, mdio.md_unit); 179 } else if (action == ATTACH) { 180 i = ioctl(fd, MDIOCATTACH, &mdio); 181 if (i < 0) 182 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 183 if (mdio.md_options & MD_AUTOUNIT) 184 printf("%s%d\n", MD_NAME, mdio.md_unit); 185 } else if (action == DETACH) { 186 if (mdio.md_options & MD_AUTOUNIT) 187 usage(); 188 i = ioctl(fd, MDIOCDETACH, &mdio); 189 if (i < 0) 190 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 191 } else 192 usage(); 193 close (fd); 194 return (0); 195 } 196 197 struct dl { 198 int unit; 199 SLIST_ENTRY(dl) slist; 200 }; 201 202 SLIST_HEAD(, dl) dlist = SLIST_HEAD_INITIALIZER(&dlist); 203 204 int 205 list(const int fd) 206 { 207 char *disklist, *p, *p2, *p3; 208 int unit; 209 size_t dll; 210 struct dl *dp, *di, *dn; 211 212 if (sysctlbyname("kern.disks", NULL, &dll, NULL, 0) == -1) 213 err(1, "sysctlbyname: kern.disks"); 214 if ( (disklist = malloc(dll)) == NULL) 215 err(1, "malloc"); 216 if (sysctlbyname("kern.disks", disklist, &dll, NULL, NULL) == -1) 217 err(1, "sysctlbyname: kern.disks"); 218 219 for (p = disklist; 220 (p2 = strsep(&p, " ")) != NULL;) { 221 if (strncmp(p2, MD_NAME, sizeof(MD_NAME) - 1) != 0) 222 continue; 223 p2 += sizeof(MD_NAME) - 1; 224 unit = strtoul(p2, &p3, 10); 225 if (p2 == p3) 226 continue; 227 dp = calloc(sizeof *dp, 1); 228 dp->unit = unit; 229 dn = SLIST_FIRST(&dlist); 230 if (dn == NULL || dn->unit > unit) { 231 SLIST_INSERT_HEAD(&dlist, dp, slist); 232 } else { 233 SLIST_FOREACH(di, &dlist, slist) { 234 dn = SLIST_NEXT(di, slist); 235 if (dn == NULL || dn->unit > unit) { 236 SLIST_INSERT_AFTER(di, dp, slist); 237 break; 238 } 239 } 240 } 241 } 242 SLIST_FOREACH(di, &dlist, slist) 243 query(fd, di->unit); 244 while (!SLIST_EMPTY(&dlist)) { 245 di = SLIST_FIRST(&dlist); 246 SLIST_REMOVE_HEAD(&dlist, slist); 247 free(di); 248 } 249 free(disklist); 250 return (0); 251 } 252 253 int 254 query(const int fd, const int unit) 255 { 256 257 mdio.md_version = MDIOVERSION; 258 mdio.md_unit = unit; 259 260 if (ioctl(fd, MDIOCQUERY, &mdio) < 0) 261 err(1, "ioctl(/dev/%s)", MDCTL_NAME); 262 263 switch (mdio.md_type) { 264 case MD_MALLOC: 265 (void)printf("%s%d\tmalloc\t%d KBytes\n", MD_NAME, 266 mdio.md_unit, mdio.md_size / 2); 267 break; 268 case MD_PRELOAD: 269 (void)printf("%s%d\tpreload\t%d KBytes\n", MD_NAME, 270 mdio.md_unit, mdio.md_size / 2); 271 break; 272 case MD_SWAP: 273 (void)printf("%s%d\tswap\t%d KBytes\n", MD_NAME, 274 mdio.md_unit, mdio.md_size / 2); 275 break; 276 case MD_VNODE: 277 (void)printf("%s%d\tvnode\t%d KBytes\n", MD_NAME, 278 mdio.md_unit, mdio.md_size / 2); 279 break; 280 } 281 282 return (0); 283 } 284 285 void 286 mdmaybeload(void) 287 { 288 struct module_stat mstat; 289 int fileid, modid; 290 const char *name; 291 char *cp; 292 293 name = MD_NAME; 294 /* scan files in kernel */ 295 mstat.version = sizeof(struct module_stat); 296 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 297 /* scan modules in file */ 298 for (modid = kldfirstmod(fileid); modid > 0; 299 modid = modfnext(modid)) { 300 if (modstat(modid, &mstat) < 0) 301 continue; 302 /* strip bus name if present */ 303 if ((cp = strchr(mstat.name, '/')) != NULL) { 304 cp++; 305 } else { 306 cp = mstat.name; 307 } 308 /* already loaded? */ 309 if (!strcmp(name, cp)) 310 return; 311 } 312 } 313 /* not present, we should try to load it */ 314 kldload(name); 315 } 316 317