xref: /freebsd/sbin/mdconfig/mdconfig.c (revision a9ebb311831b25896b6bd0f5d0cbb41fdff84095)
170d586c0SPoul-Henning Kamp /*
270d586c0SPoul-Henning Kamp  * ----------------------------------------------------------------------------
370d586c0SPoul-Henning Kamp  * "THE BEER-WARE LICENSE" (Revision 42):
470d586c0SPoul-Henning Kamp  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
570d586c0SPoul-Henning Kamp  * can do whatever you want with this stuff. If we meet some day, and you think
670d586c0SPoul-Henning Kamp  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
770d586c0SPoul-Henning Kamp  * ----------------------------------------------------------------------------
870d586c0SPoul-Henning Kamp  *
970d586c0SPoul-Henning Kamp  * $FreeBSD$
1070d586c0SPoul-Henning Kamp  *
1170d586c0SPoul-Henning Kamp  */
1270d586c0SPoul-Henning Kamp #include <sys/param.h>
13c27a8954SWojciech A. Koszek #include <sys/devicestat.h>
144bfd989fSWojciech A. Koszek #include <sys/ioctl.h>
1557e9624eSPoul-Henning Kamp #include <sys/linker.h>
1670d586c0SPoul-Henning Kamp #include <sys/mdioctl.h>
174bfd989fSWojciech A. Koszek #include <sys/module.h>
18c27a8954SWojciech A. Koszek #include <sys/resource.h>
19b830359bSPawel Jakub Dawidek #include <sys/stat.h>
20174b5e9aSPoul-Henning Kamp 
214bfd989fSWojciech A. Koszek #include <assert.h>
22c27a8954SWojciech A. Koszek #include <devstat.h>
234bfd989fSWojciech A. Koszek #include <err.h>
244bfd989fSWojciech A. Koszek #include <errno.h>
254bfd989fSWojciech A. Koszek #include <fcntl.h>
264bfd989fSWojciech A. Koszek #include <inttypes.h>
27c27a8954SWojciech A. Koszek #include <libgeom.h>
284bfd989fSWojciech A. Koszek #include <libutil.h>
29c27a8954SWojciech A. Koszek #include <stdarg.h>
304bfd989fSWojciech A. Koszek #include <stdio.h>
314bfd989fSWojciech A. Koszek #include <stdlib.h>
324bfd989fSWojciech A. Koszek #include <string.h>
334bfd989fSWojciech A. Koszek #include <unistd.h>
3470d586c0SPoul-Henning Kamp 
3570d586c0SPoul-Henning Kamp 
364bfd989fSWojciech A. Koszek static struct md_ioctl mdio;
374bfd989fSWojciech A. Koszek static enum {UNSET, ATTACH, DETACH, LIST} action = UNSET;
384bfd989fSWojciech A. Koszek static int nflag;
3970d586c0SPoul-Henning Kamp 
40c27a8954SWojciech A. Koszek static void usage(void);
41c27a8954SWojciech A. Koszek static int md_find(char *, const char *);
42c27a8954SWojciech A. Koszek static int md_query(char *name);
43c27a8954SWojciech A. Koszek static int md_list(char *units, int opt);
44c27a8954SWojciech A. Koszek static char *geom_config_get(struct gconf *g, char *name);
45c27a8954SWojciech A. Koszek static void md_prthumanval(char *length);
46c27a8954SWojciech A. Koszek 
47c27a8954SWojciech A. Koszek #define OPT_VERBOSE	0x01
48c27a8954SWojciech A. Koszek #define OPT_UNIT	0x02
49c27a8954SWojciech A. Koszek #define OPT_DONE	0x04
50c27a8954SWojciech A. Koszek #define OPT_LIST	0x10
51c27a8954SWojciech A. Koszek 
52c27a8954SWojciech A. Koszek #define CLASS_NAME_MD	"MD"
53c27a8954SWojciech A. Koszek 
544bfd989fSWojciech A. Koszek static void
55c2ef0b73SPoul-Henning Kamp usage()
56c2ef0b73SPoul-Henning Kamp {
5778bb1162SRuslan Ermilov 	fprintf(stderr,
5878bb1162SRuslan Ermilov "usage: mdconfig -a -t type [-n] [-o [no]option] ... [-f file]\n"
5978bb1162SRuslan Ermilov "                [-s size] [-S sectorsize] [-u unit]\n"
6078bb1162SRuslan Ermilov "                [-x sectors/track] [-y heads/cyl]\n"
61a9ebb311SEdward Tomasz Napierala "       mdconfig -d -u unit [-o [no]force]\n"
62c94b8307SDmitry Morozovsky "       mdconfig -l [-v] [-n] [-u unit]\n");
63c2ef0b73SPoul-Henning Kamp 	fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n");
643f6f9216SPoul-Henning Kamp 	fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n");
655d19b2f9SPawel Jakub Dawidek 	fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%db (B),\n");
665d19b2f9SPawel Jakub Dawidek 	fprintf(stderr, "\t\t       %%dk (kB), %%dm (MB), %%dg (GB) or\n");
675d19b2f9SPawel Jakub Dawidek 	fprintf(stderr, "\t\t       %%dt (TB)\n");
68c2ef0b73SPoul-Henning Kamp 	exit(1);
69c2ef0b73SPoul-Henning Kamp }
70c2ef0b73SPoul-Henning Kamp 
7170d586c0SPoul-Henning Kamp int
7270d586c0SPoul-Henning Kamp main(int argc, char **argv)
7370d586c0SPoul-Henning Kamp {
74c94b8307SDmitry Morozovsky 	int ch, fd, i, vflag;
75c2ef0b73SPoul-Henning Kamp 	char *p;
76c2ef0b73SPoul-Henning Kamp 	int cmdline = 0;
77c27a8954SWojciech A. Koszek 	char *mdunit;
7870d586c0SPoul-Henning Kamp 
79b830359bSPawel Jakub Dawidek 	bzero(&mdio, sizeof(mdio));
8088b5b78dSPawel Jakub Dawidek 	mdio.md_file = malloc(PATH_MAX);
8188b5b78dSPawel Jakub Dawidek 	if (mdio.md_file == NULL)
8288b5b78dSPawel Jakub Dawidek 		err(1, "could not allocate memory");
83c94b8307SDmitry Morozovsky 	vflag = 0;
8488b5b78dSPawel Jakub Dawidek 	bzero(mdio.md_file, PATH_MAX);
8570d586c0SPoul-Henning Kamp 	for (;;) {
86c94b8307SDmitry Morozovsky 		ch = getopt(argc, argv, "ab:df:lno:s:S:t:u:vx:y:");
8770d586c0SPoul-Henning Kamp 		if (ch == -1)
8870d586c0SPoul-Henning Kamp 			break;
8970d586c0SPoul-Henning Kamp 		switch (ch) {
9070d586c0SPoul-Henning Kamp 		case 'a':
91c2ef0b73SPoul-Henning Kamp 			if (cmdline != 0)
92c2ef0b73SPoul-Henning Kamp 				usage();
9370d586c0SPoul-Henning Kamp 			action = ATTACH;
94c2ef0b73SPoul-Henning Kamp 			cmdline = 1;
9570d586c0SPoul-Henning Kamp 			break;
9670d586c0SPoul-Henning Kamp 		case 'd':
97c2ef0b73SPoul-Henning Kamp 			if (cmdline != 0)
98c2ef0b73SPoul-Henning Kamp 				usage();
9970d586c0SPoul-Henning Kamp 			action = DETACH;
1008f8def9eSPoul-Henning Kamp 			mdio.md_options = MD_AUTOUNIT;
1018f8def9eSPoul-Henning Kamp 			cmdline = 3;
102c2ef0b73SPoul-Henning Kamp 			break;
103174b5e9aSPoul-Henning Kamp 		case 'l':
104174b5e9aSPoul-Henning Kamp 			if (cmdline != 0)
105174b5e9aSPoul-Henning Kamp 				usage();
106174b5e9aSPoul-Henning Kamp 			action = LIST;
107174b5e9aSPoul-Henning Kamp 			mdio.md_options = MD_AUTOUNIT;
108174b5e9aSPoul-Henning Kamp 			cmdline = 3;
109174b5e9aSPoul-Henning Kamp 			break;
110f79c46d3SRobert Watson 		case 'n':
111f79c46d3SRobert Watson 			nflag = 1;
112f79c46d3SRobert Watson 			break;
113c2ef0b73SPoul-Henning Kamp 		case 't':
114c2ef0b73SPoul-Henning Kamp 			if (cmdline != 1)
115c2ef0b73SPoul-Henning Kamp 				usage();
116c2ef0b73SPoul-Henning Kamp 			if (!strcmp(optarg, "malloc")) {
117c2ef0b73SPoul-Henning Kamp 				mdio.md_type = MD_MALLOC;
118c2ef0b73SPoul-Henning Kamp 				mdio.md_options = MD_AUTOUNIT | MD_COMPRESS;
119c2ef0b73SPoul-Henning Kamp 			} else if (!strcmp(optarg, "preload")) {
120c2ef0b73SPoul-Henning Kamp 				mdio.md_type = MD_PRELOAD;
121c2ef0b73SPoul-Henning Kamp 				mdio.md_options = 0;
122c2ef0b73SPoul-Henning Kamp 			} else if (!strcmp(optarg, "vnode")) {
123c2ef0b73SPoul-Henning Kamp 				mdio.md_type = MD_VNODE;
124c2ef0b73SPoul-Henning Kamp 				mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS;
125c2ef0b73SPoul-Henning Kamp 			} else if (!strcmp(optarg, "swap")) {
126c2ef0b73SPoul-Henning Kamp 				mdio.md_type = MD_SWAP;
127c2ef0b73SPoul-Henning Kamp 				mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS;
128c2ef0b73SPoul-Henning Kamp 			} else {
129c2ef0b73SPoul-Henning Kamp 				usage();
130c2ef0b73SPoul-Henning Kamp 			}
131c2ef0b73SPoul-Henning Kamp 			cmdline=2;
13270d586c0SPoul-Henning Kamp 			break;
13370d586c0SPoul-Henning Kamp 		case 'f':
1341253fe1eSNick Hibma 			if (cmdline == 0) {
1351253fe1eSNick Hibma 				action = ATTACH;
1361253fe1eSNick Hibma 				cmdline = 1;
1371253fe1eSNick Hibma 			}
138ed23a390SMaxim Sobolev 			if (cmdline == 1) {
139ed23a390SMaxim Sobolev 				/* Imply ``-t vnode'' */
140ed23a390SMaxim Sobolev 				mdio.md_type = MD_VNODE;
141ed23a390SMaxim Sobolev 				mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS;
142252bcf45SYaroslav Tykhiy 				cmdline = 2;
143ed23a390SMaxim Sobolev 			}
14435ce0ff2SNick Hibma  			if (cmdline != 2)
14535ce0ff2SNick Hibma  				usage();
14661a6eb62SPawel Jakub Dawidek 			if (realpath(optarg, mdio.md_file) == NULL) {
14761a6eb62SPawel Jakub Dawidek 				err(1, "could not find full path for %s",
14861a6eb62SPawel Jakub Dawidek 				    optarg);
14961a6eb62SPawel Jakub Dawidek 			}
15061a6eb62SPawel Jakub Dawidek 			fd = open(mdio.md_file, O_RDONLY);
151e869d377SPoul-Henning Kamp 			if (fd < 0)
152e869d377SPoul-Henning Kamp 				err(1, "could not open %s", optarg);
153b830359bSPawel Jakub Dawidek 			else if (mdio.md_mediasize == 0) {
154b830359bSPawel Jakub Dawidek 				struct stat sb;
155b830359bSPawel Jakub Dawidek 
156b830359bSPawel Jakub Dawidek 				if (fstat(fd, &sb) == -1)
157b830359bSPawel Jakub Dawidek 					err(1, "could not stat %s", optarg);
158b830359bSPawel Jakub Dawidek 				mdio.md_mediasize = sb.st_size;
159b830359bSPawel Jakub Dawidek 			}
160e869d377SPoul-Henning Kamp 			close(fd);
16170d586c0SPoul-Henning Kamp 			break;
16270d586c0SPoul-Henning Kamp 		case 'o':
163a9ebb311SEdward Tomasz Napierala 			if (action == DETACH) {
164a9ebb311SEdward Tomasz Napierala 				if (!strcmp(optarg, "force"))
165a9ebb311SEdward Tomasz Napierala 					mdio.md_options |= MD_FORCE;
166a9ebb311SEdward Tomasz Napierala 				else if (!strcmp(optarg, "noforce"))
167a9ebb311SEdward Tomasz Napierala 					mdio.md_options &= ~MD_FORCE;
168a9ebb311SEdward Tomasz Napierala 				else
169a9ebb311SEdward Tomasz Napierala 					errx(1, "Unknown option: %s.", optarg);
170a9ebb311SEdward Tomasz Napierala 				break;
171a9ebb311SEdward Tomasz Napierala 			}
172a9ebb311SEdward Tomasz Napierala 
173c2ef0b73SPoul-Henning Kamp 			if (cmdline != 2)
174c2ef0b73SPoul-Henning Kamp 				usage();
1757a6b2b64SPoul-Henning Kamp 			if (!strcmp(optarg, "async"))
1767a6b2b64SPoul-Henning Kamp 				mdio.md_options |= MD_ASYNC;
1777a6b2b64SPoul-Henning Kamp 			else if (!strcmp(optarg, "noasync"))
1787a6b2b64SPoul-Henning Kamp 				mdio.md_options &= ~MD_ASYNC;
1797a6b2b64SPoul-Henning Kamp 			else if (!strcmp(optarg, "cluster"))
18070d586c0SPoul-Henning Kamp 				mdio.md_options |= MD_CLUSTER;
18170d586c0SPoul-Henning Kamp 			else if (!strcmp(optarg, "nocluster"))
18270d586c0SPoul-Henning Kamp 				mdio.md_options &= ~MD_CLUSTER;
183c2ef0b73SPoul-Henning Kamp 			else if (!strcmp(optarg, "compress"))
184c2ef0b73SPoul-Henning Kamp 				mdio.md_options |= MD_COMPRESS;
185c2ef0b73SPoul-Henning Kamp 			else if (!strcmp(optarg, "nocompress"))
186c2ef0b73SPoul-Henning Kamp 				mdio.md_options &= ~MD_COMPRESS;
18726a0ee75SDima Dorfman 			else if (!strcmp(optarg, "force"))
18826a0ee75SDima Dorfman 				mdio.md_options |= MD_FORCE;
18926a0ee75SDima Dorfman 			else if (!strcmp(optarg, "noforce"))
19026a0ee75SDima Dorfman 				mdio.md_options &= ~MD_FORCE;
191d31ba625SJohn-Mark Gurney 			else if (!strcmp(optarg, "readonly"))
192d31ba625SJohn-Mark Gurney 				mdio.md_options |= MD_READONLY;
193d31ba625SJohn-Mark Gurney 			else if (!strcmp(optarg, "noreadonly"))
194d31ba625SJohn-Mark Gurney 				mdio.md_options &= ~MD_READONLY;
19570d586c0SPoul-Henning Kamp 			else if (!strcmp(optarg, "reserve"))
19670d586c0SPoul-Henning Kamp 				mdio.md_options |= MD_RESERVE;
19770d586c0SPoul-Henning Kamp 			else if (!strcmp(optarg, "noreserve"))
19870d586c0SPoul-Henning Kamp 				mdio.md_options &= ~MD_RESERVE;
19970d586c0SPoul-Henning Kamp 			else
200d31ba625SJohn-Mark Gurney 				errx(1, "Unknown option: %s.", optarg);
20170d586c0SPoul-Henning Kamp 			break;
202ebe789d6SPoul-Henning Kamp 		case 'S':
203ebe789d6SPoul-Henning Kamp 			if (cmdline != 2)
204ebe789d6SPoul-Henning Kamp 				usage();
205b830359bSPawel Jakub Dawidek 			mdio.md_sectorsize = strtoul(optarg, &p, 0);
206ebe789d6SPoul-Henning Kamp 			break;
20770d586c0SPoul-Henning Kamp 		case 's':
20835ce0ff2SNick Hibma 			if (cmdline == 0) {
20935ce0ff2SNick Hibma 				/* Imply ``-a'' */
21035ce0ff2SNick Hibma 				action = ATTACH;
21135ce0ff2SNick Hibma 				cmdline = 1;
21235ce0ff2SNick Hibma 			}
21335ce0ff2SNick Hibma 			if (cmdline == 1) {
2147090e3d1SNick Hibma 				/* Imply ``-t swap'' */
2157090e3d1SNick Hibma 				mdio.md_type = MD_SWAP;
2167090e3d1SNick Hibma 				mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS;
21735ce0ff2SNick Hibma 				cmdline = 2;
21835ce0ff2SNick Hibma 			}
219c2ef0b73SPoul-Henning Kamp 			if (cmdline != 2)
220c2ef0b73SPoul-Henning Kamp 				usage();
221b830359bSPawel Jakub Dawidek 			mdio.md_mediasize = (off_t)strtoumax(optarg, &p, 0);
222c2ef0b73SPoul-Henning Kamp 			if (p == NULL || *p == '\0')
223b830359bSPawel Jakub Dawidek 				mdio.md_mediasize *= DEV_BSIZE;
2240d79319aSPawel Jakub Dawidek 			else if (*p == 'b' || *p == 'B')
2250d79319aSPawel Jakub Dawidek 				; /* do nothing */
226c2ef0b73SPoul-Henning Kamp 			else if (*p == 'k' || *p == 'K')
227b830359bSPawel Jakub Dawidek 				mdio.md_mediasize <<= 10;
228c2ef0b73SPoul-Henning Kamp 			else if (*p == 'm' || *p == 'M')
229b830359bSPawel Jakub Dawidek 				mdio.md_mediasize <<= 20;
230c2ef0b73SPoul-Henning Kamp 			else if (*p == 'g' || *p == 'G')
231b830359bSPawel Jakub Dawidek 				mdio.md_mediasize <<= 30;
232b830359bSPawel Jakub Dawidek 			else if (*p == 't' || *p == 'T') {
233b830359bSPawel Jakub Dawidek 				mdio.md_mediasize <<= 30;
234b830359bSPawel Jakub Dawidek 				mdio.md_mediasize <<= 10;
235b830359bSPawel Jakub Dawidek 			} else
236c2ef0b73SPoul-Henning Kamp 				errx(1, "Unknown suffix on -s argument");
23770d586c0SPoul-Henning Kamp 			break;
23870d586c0SPoul-Henning Kamp 		case 'u':
2398f8def9eSPoul-Henning Kamp 			if (cmdline != 2 && cmdline != 3)
240c2ef0b73SPoul-Henning Kamp 				usage();
241ea3d97aeSWojciech A. Koszek 			if (!strncmp(optarg, "/dev/", 5))
242ea3d97aeSWojciech A. Koszek 				optarg += 5;
243ea3d97aeSWojciech A. Koszek 			if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1))
244ea3d97aeSWojciech A. Koszek 				optarg += sizeof(MD_NAME) - 1;
245ea3d97aeSWojciech A. Koszek 			mdio.md_unit = strtoul(optarg, &p, 0);
246ea3d97aeSWojciech A. Koszek 			if (mdio.md_unit == (unsigned)ULONG_MAX || *p != '\0')
247ea3d97aeSWojciech A. Koszek 				errx(1, "bad unit: %s", optarg);
248c27a8954SWojciech A. Koszek 			mdunit = optarg;
24970d586c0SPoul-Henning Kamp 			mdio.md_options &= ~MD_AUTOUNIT;
25070d586c0SPoul-Henning Kamp 			break;
251c94b8307SDmitry Morozovsky 		case 'v':
252c94b8307SDmitry Morozovsky 			if (cmdline != 3)
253c94b8307SDmitry Morozovsky 				usage();
254c94b8307SDmitry Morozovsky 			vflag = OPT_VERBOSE;
255c94b8307SDmitry Morozovsky 			break;
2564e8bfe14SPoul-Henning Kamp 		case 'x':
2574e8bfe14SPoul-Henning Kamp 			if (cmdline != 2)
2584e8bfe14SPoul-Henning Kamp 				usage();
2594e8bfe14SPoul-Henning Kamp 			mdio.md_fwsectors = strtoul(optarg, &p, 0);
2604e8bfe14SPoul-Henning Kamp 			break;
2614e8bfe14SPoul-Henning Kamp 		case 'y':
2624e8bfe14SPoul-Henning Kamp 			if (cmdline != 2)
2634e8bfe14SPoul-Henning Kamp 				usage();
2644e8bfe14SPoul-Henning Kamp 			mdio.md_fwheads = strtoul(optarg, &p, 0);
2654e8bfe14SPoul-Henning Kamp 			break;
26670d586c0SPoul-Henning Kamp 		default:
267c2ef0b73SPoul-Henning Kamp 			usage();
26870d586c0SPoul-Henning Kamp 		}
26970d586c0SPoul-Henning Kamp 	}
27053d745bcSDima Dorfman 	mdio.md_version = MDIOVERSION;
27170d586c0SPoul-Henning Kamp 
272a921cb31SPawel Jakub Dawidek 	if (!kld_isloaded("g_md") && kld_load("geom_md") == -1)
273a921cb31SPawel Jakub Dawidek 		err(1, "failed to load geom_md module");
274a921cb31SPawel Jakub Dawidek 
275174b5e9aSPoul-Henning Kamp 	fd = open("/dev/" MDCTL_NAME, O_RDWR, 0);
27670d586c0SPoul-Henning Kamp 	if (fd < 0)
277174b5e9aSPoul-Henning Kamp 		err(1, "open(/dev/%s)", MDCTL_NAME);
2782885b421SDima Dorfman 	if (cmdline == 2
2792885b421SDima Dorfman 	    && (mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP))
280b830359bSPawel Jakub Dawidek 		if (mdio.md_mediasize == 0)
2812885b421SDima Dorfman 			errx(1, "must specify -s for -t malloc or -t swap");
282252bcf45SYaroslav Tykhiy 	if (cmdline == 2 && mdio.md_type == MD_VNODE)
28388b5b78dSPawel Jakub Dawidek 		if (mdio.md_file[0] == '\0')
284252bcf45SYaroslav Tykhiy 			errx(1, "must specify -f for -t vnode");
285c313f09bSChristian S.J. Peron 	if (mdio.md_type == MD_VNODE &&
286c313f09bSChristian S.J. Peron 	    (mdio.md_options & MD_READONLY) == 0) {
287c313f09bSChristian S.J. Peron 		if (access(mdio.md_file, W_OK) < 0 &&
288c313f09bSChristian S.J. Peron 		    (errno == EACCES || errno == EPERM || errno == EROFS)) {
289c313f09bSChristian S.J. Peron 			fprintf(stderr,
290c313f09bSChristian S.J. Peron 			    "WARNING: opening backing store: %s readonly\n",
291c313f09bSChristian S.J. Peron 			    mdio.md_file);
292c313f09bSChristian S.J. Peron 			mdio.md_options |= MD_READONLY;
293c313f09bSChristian S.J. Peron 		}
294c313f09bSChristian S.J. Peron 	}
295174b5e9aSPoul-Henning Kamp 	if (action == LIST) {
296c27a8954SWojciech A. Koszek 		if (mdio.md_options & MD_AUTOUNIT) {
297c27a8954SWojciech A. Koszek 			/*
298c27a8954SWojciech A. Koszek 			 * Listing all devices. This is why we pass NULL
299c27a8954SWojciech A. Koszek 			 * together with OPT_LIST.
300c27a8954SWojciech A. Koszek 			 */
301c94b8307SDmitry Morozovsky 			md_list(NULL, OPT_LIST | vflag);
302c27a8954SWojciech A. Koszek 		} else {
30369fcb537SFlorent Thoumie 			return (md_query(mdunit));
304c27a8954SWojciech A. Koszek 		}
305174b5e9aSPoul-Henning Kamp 	} else if (action == ATTACH) {
306252bcf45SYaroslav Tykhiy 		if (cmdline < 2)
307252bcf45SYaroslav Tykhiy 			usage();
30870d586c0SPoul-Henning Kamp 		i = ioctl(fd, MDIOCATTACH, &mdio);
309174b5e9aSPoul-Henning Kamp 		if (i < 0)
310174b5e9aSPoul-Henning Kamp 			err(1, "ioctl(/dev/%s)", MDCTL_NAME);
31183da2a90SPoul-Henning Kamp 		if (mdio.md_options & MD_AUTOUNIT)
312f79c46d3SRobert Watson 			printf("%s%d\n", nflag ? "" : MD_NAME, mdio.md_unit);
31383da2a90SPoul-Henning Kamp 	} else if (action == DETACH) {
3148f8def9eSPoul-Henning Kamp 		if (mdio.md_options & MD_AUTOUNIT)
3158f8def9eSPoul-Henning Kamp 			usage();
316c2ef0b73SPoul-Henning Kamp 		i = ioctl(fd, MDIOCDETACH, &mdio);
31770d586c0SPoul-Henning Kamp 		if (i < 0)
318174b5e9aSPoul-Henning Kamp 			err(1, "ioctl(/dev/%s)", MDCTL_NAME);
31983da2a90SPoul-Henning Kamp 	} else
32083da2a90SPoul-Henning Kamp 		usage();
321174b5e9aSPoul-Henning Kamp 	close (fd);
322174b5e9aSPoul-Henning Kamp 	return (0);
323174b5e9aSPoul-Henning Kamp }
324174b5e9aSPoul-Henning Kamp 
325c27a8954SWojciech A. Koszek /*
326c27a8954SWojciech A. Koszek  * Lists md(4) disks. Is used also as a query routine, since it handles XML
327c27a8954SWojciech A. Koszek  * interface. 'units' can be NULL for listing memory disks. It might be
328c27a8954SWojciech A. Koszek  * coma-separated string containing md(4) disk names. 'opt' distinguished
329c27a8954SWojciech A. Koszek  * between list and query mode.
330c27a8954SWojciech A. Koszek  */
3317e06d7bcSDima Dorfman static int
332c27a8954SWojciech A. Koszek md_list(char *units, int opt)
3337e06d7bcSDima Dorfman {
334c27a8954SWojciech A. Koszek 	struct gmesh gm;
335c27a8954SWojciech A. Koszek 	struct gprovider *pp;
336c27a8954SWojciech A. Koszek 	struct gconf *gc;
337c27a8954SWojciech A. Koszek 	struct gident *gid;
338c3345c66SJason Evans 	struct devstat *gsp;
339c27a8954SWojciech A. Koszek 	struct ggeom *gg;
340c27a8954SWojciech A. Koszek 	struct gclass *gcl;
341c27a8954SWojciech A. Koszek 	void *sq;
34269fcb537SFlorent Thoumie 	int retcode, found;
343c27a8954SWojciech A. Koszek 	char *type, *file, *length;
3447e06d7bcSDima Dorfman 
345c27a8954SWojciech A. Koszek 	type = file = length = NULL;
346174b5e9aSPoul-Henning Kamp 
347c27a8954SWojciech A. Koszek 	retcode = geom_gettree(&gm);
348c27a8954SWojciech A. Koszek 	if (retcode != 0)
349c27a8954SWojciech A. Koszek 		return (-1);
350c27a8954SWojciech A. Koszek 	retcode = geom_stats_open();
351c27a8954SWojciech A. Koszek 	if (retcode != 0)
352c27a8954SWojciech A. Koszek 		return (-1);
353c27a8954SWojciech A. Koszek 	sq = geom_stats_snapshot_get();
354c27a8954SWojciech A. Koszek 	if (sq == NULL)
355c27a8954SWojciech A. Koszek 		return (-1);
356c27a8954SWojciech A. Koszek 
35769fcb537SFlorent Thoumie 	found = 0;
358c27a8954SWojciech A. Koszek 	while ((gsp = geom_stats_snapshot_next(sq)) != NULL) {
359c27a8954SWojciech A. Koszek 		gid = geom_lookupid(&gm, gsp->id);
360c27a8954SWojciech A. Koszek 		if (gid == NULL)
361c27a8954SWojciech A. Koszek 			continue;
362c27a8954SWojciech A. Koszek 		if (gid->lg_what == ISPROVIDER) {
363c27a8954SWojciech A. Koszek 			pp = gid->lg_ptr;
364c27a8954SWojciech A. Koszek 			gg = pp->lg_geom;
365c27a8954SWojciech A. Koszek 			gcl = gg->lg_class;
366c27a8954SWojciech A. Koszek 			if (strcmp(gcl->lg_name, CLASS_NAME_MD) != 0)
367c27a8954SWojciech A. Koszek 				continue;
368c27a8954SWojciech A. Koszek 			if ((opt & OPT_UNIT) && (units != NULL)) {
369c27a8954SWojciech A. Koszek 				retcode = md_find(units, pp->lg_name);
370c27a8954SWojciech A. Koszek 				if (retcode != 1)
371c27a8954SWojciech A. Koszek 					continue;
37269fcb537SFlorent Thoumie 				else
37369fcb537SFlorent Thoumie 					found = 1;
374174b5e9aSPoul-Henning Kamp 			}
375c27a8954SWojciech A. Koszek 			gc = &pp->lg_config;
376c27a8954SWojciech A. Koszek 			printf("%s", pp->lg_name);
377c27a8954SWojciech A. Koszek 			if (opt & OPT_VERBOSE || opt & OPT_UNIT) {
378c27a8954SWojciech A. Koszek 				type = geom_config_get(gc, "type");
379c27a8954SWojciech A. Koszek 				if (strcmp(type, "vnode") == 0)
380c27a8954SWojciech A. Koszek 					file = geom_config_get(gc, "file");
381c27a8954SWojciech A. Koszek 				length = geom_config_get(gc, "length");
382c27a8954SWojciech A. Koszek 				if (length == NULL)
383c27a8954SWojciech A. Koszek 					length = "<a>";
384c27a8954SWojciech A. Koszek 				printf("\t%s\t", type);
385c27a8954SWojciech A. Koszek 				md_prthumanval(length);
386c27a8954SWojciech A. Koszek 				if (file != NULL) {
387c27a8954SWojciech A. Koszek 					printf("\t%s", file);
388c27a8954SWojciech A. Koszek 					file = NULL;
389c27a8954SWojciech A. Koszek 				}
390c27a8954SWojciech A. Koszek 			}
391c27a8954SWojciech A. Koszek 			opt |= OPT_DONE;
392c94b8307SDmitry Morozovsky 			if ((opt & OPT_LIST) && !(opt & OPT_VERBOSE))
393c27a8954SWojciech A. Koszek 				printf(" ");
394c27a8954SWojciech A. Koszek 			else
395e39eff98SPoul-Henning Kamp 				printf("\n");
396c27a8954SWojciech A. Koszek 		}
397c27a8954SWojciech A. Koszek 	}
398c94b8307SDmitry Morozovsky 	if ((opt & OPT_LIST) && (opt & OPT_DONE) && !(opt & OPT_VERBOSE))
399c27a8954SWojciech A. Koszek 		printf("\n");
400c27a8954SWojciech A. Koszek 	/* XXX: Check if it's enough to clean everything. */
401c27a8954SWojciech A. Koszek 	geom_stats_snapshot_free(sq);
40269fcb537SFlorent Thoumie 	if ((opt & OPT_UNIT) && found)
40369fcb537SFlorent Thoumie 		return (0);
40469fcb537SFlorent Thoumie 	else
405c27a8954SWojciech A. Koszek 		return (-1);
406c27a8954SWojciech A. Koszek }
407c27a8954SWojciech A. Koszek 
408c27a8954SWojciech A. Koszek /*
409c27a8954SWojciech A. Koszek  * Returns value of 'name' from gconfig structure.
410c27a8954SWojciech A. Koszek  */
411c27a8954SWojciech A. Koszek static char *
412c27a8954SWojciech A. Koszek geom_config_get(struct gconf *g, char *name)
413c27a8954SWojciech A. Koszek {
414c27a8954SWojciech A. Koszek 	struct gconfig *gce;
415c27a8954SWojciech A. Koszek 
416c27a8954SWojciech A. Koszek 	LIST_FOREACH(gce, g, lg_config) {
417c27a8954SWojciech A. Koszek 		if (strcmp(gce->lg_name, name) == 0)
418c27a8954SWojciech A. Koszek 			return (gce->lg_val);
419c27a8954SWojciech A. Koszek 	}
420c27a8954SWojciech A. Koszek 	return (NULL);
421c27a8954SWojciech A. Koszek }
422c27a8954SWojciech A. Koszek 
423c27a8954SWojciech A. Koszek /*
424c27a8954SWojciech A. Koszek  * List is comma separated list of MD disks. name is a
425c27a8954SWojciech A. Koszek  * device name we look for.  Returns 1 if found and 0
426c27a8954SWojciech A. Koszek  * otherwise.
427c27a8954SWojciech A. Koszek  */
428c27a8954SWojciech A. Koszek static int
429c27a8954SWojciech A. Koszek md_find(char *list, const char *name)
430c27a8954SWojciech A. Koszek {
431c27a8954SWojciech A. Koszek 	int ret;
432c27a8954SWojciech A. Koszek 	char num[16];
433c27a8954SWojciech A. Koszek 	char *ptr, *p, *u;
434c27a8954SWojciech A. Koszek 
435c27a8954SWojciech A. Koszek 	ret = 0;
436c27a8954SWojciech A. Koszek 	ptr = strdup(list);
437c27a8954SWojciech A. Koszek 	if (ptr == NULL)
438c27a8954SWojciech A. Koszek 		return (-1);
439c27a8954SWojciech A. Koszek 	for (p = ptr; (u = strsep(&p, ",")) != NULL;) {
440c27a8954SWojciech A. Koszek 		if (strncmp(u, "/dev/", 5) == 0)
441c27a8954SWojciech A. Koszek 			u += 5;
442c27a8954SWojciech A. Koszek 		/* Just in case user specified number instead of full name */
443c27a8954SWojciech A. Koszek 		snprintf(num, sizeof(num), "md%s", u);
444c27a8954SWojciech A. Koszek 		if (strcmp(u, name) == 0 || strcmp(num, name) == 0) {
445c27a8954SWojciech A. Koszek 			ret = 1;
446c27a8954SWojciech A. Koszek 			break;
447c27a8954SWojciech A. Koszek 		}
448c27a8954SWojciech A. Koszek 	}
449c27a8954SWojciech A. Koszek 	free(ptr);
450c27a8954SWojciech A. Koszek 	return (ret);
451174b5e9aSPoul-Henning Kamp }
452174b5e9aSPoul-Henning Kamp 
453b830359bSPawel Jakub Dawidek static void
454c27a8954SWojciech A. Koszek md_prthumanval(char *length)
455b830359bSPawel Jakub Dawidek {
456b830359bSPawel Jakub Dawidek 	char buf[6];
457c27a8954SWojciech A. Koszek 	uint64_t bytes;
458c27a8954SWojciech A. Koszek 	char *endptr;
459b830359bSPawel Jakub Dawidek 
460c27a8954SWojciech A. Koszek 	bytes = strtoul(length, &endptr, 10);
461c27a8954SWojciech A. Koszek 	if (bytes == (unsigned)ULONG_MAX || *endptr != '\0')
462c27a8954SWojciech A. Koszek 		return;
463b830359bSPawel Jakub Dawidek 	humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
464b830359bSPawel Jakub Dawidek 	    bytes, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
465b830359bSPawel Jakub Dawidek 	(void)printf("%6s", buf);
466b830359bSPawel Jakub Dawidek }
467b830359bSPawel Jakub Dawidek 
468c27a8954SWojciech A. Koszek int
469c27a8954SWojciech A. Koszek md_query(char *name)
470174b5e9aSPoul-Henning Kamp {
471c27a8954SWojciech A. Koszek 	return (md_list(name, OPT_UNIT));
47270d586c0SPoul-Henning Kamp }
473