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