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