1230423Strasz/*-
2230423Strasz * Copyright (c) 2000-2004 Poul-Henning Kamp <phk@FreeBSD.org>
3230612Strasz * Copyright (c) 2012 The FreeBSD Foundation
4230423Strasz * All rights reserved.
570448Sphk *
6230612Strasz * Portions of this software were developed by Edward Tomasz Napierala
7230612Strasz * under sponsorship from the FreeBSD Foundation.
8230612Strasz *
9230423Strasz * Redistribution and use in source and binary forms, with or without
10230423Strasz * modification, are permitted provided that the following conditions
11230423Strasz * are met:
12230423Strasz * 1. Redistributions of source code must retain the above copyright
13230423Strasz *    notice, this list of conditions and the following disclaimer.
14230423Strasz * 2. Redistributions in binary form must reproduce the above copyright
15230423Strasz *    notice, this list of conditions and the following disclaimer in the
16230423Strasz *    documentation and/or other materials provided with the distribution.
17230423Strasz *
18230423Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19230423Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20230423Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21230423Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22230423Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23230423Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24230423Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25230423Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26230423Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27230423Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28230423Strasz * SUCH DAMAGE.
29230423Strasz *
3070448Sphk * $FreeBSD$
3170448Sphk */
32230423Strasz
33157159Swkoszek#include <sys/param.h>
34157160Swkoszek#include <sys/devicestat.h>
35157159Swkoszek#include <sys/ioctl.h>
36157159Swkoszek#include <sys/linker.h>
37157159Swkoszek#include <sys/mdioctl.h>
38157159Swkoszek#include <sys/module.h>
39157160Swkoszek#include <sys/resource.h>
40157159Swkoszek#include <sys/stat.h>
4170448Sphk
42157159Swkoszek#include <assert.h>
43157160Swkoszek#include <devstat.h>
44157159Swkoszek#include <err.h>
45149638Scsjp#include <errno.h>
4670448Sphk#include <fcntl.h>
47135340Spjd#include <inttypes.h>
48157160Swkoszek#include <libgeom.h>
49135340Spjd#include <libutil.h>
50252033Shrs#include <paths.h>
51157160Swkoszek#include <stdarg.h>
52157159Swkoszek#include <stdio.h>
53157159Swkoszek#include <stdlib.h>
5470448Sphk#include <string.h>
55157159Swkoszek#include <unistd.h>
56135340Spjd
57157159Swkoszekstatic struct md_ioctl mdio;
58238215Straszstatic enum {UNSET, ATTACH, DETACH, RESIZE, LIST} action = UNSET;
59157159Swkoszekstatic int nflag;
6073026Sphk
61157160Swkoszekstatic void usage(void);
62221232Sdesstatic void md_set_file(const char *);
63252033Shrsstatic int md_find(const char *, const char *);
64252033Shrsstatic int md_query(const char *, const int, const char *);
65252033Shrsstatic int md_list(const char *, int, const char *);
66202784Sjhstatic char *geom_config_get(struct gconf *g, const char *name);
67157160Swkoszekstatic void md_prthumanval(char *length);
68157160Swkoszek
69157160Swkoszek#define OPT_VERBOSE	0x01
70157160Swkoszek#define OPT_UNIT	0x02
71157160Swkoszek#define OPT_DONE	0x04
72157160Swkoszek#define OPT_LIST	0x10
73157160Swkoszek
74157160Swkoszek#define CLASS_NAME_MD	"MD"
75157160Swkoszek
76157159Swkoszekstatic void
77202784Sjhusage(void)
7870538Sphk{
79230612Strasz
80137669Sru	fprintf(stderr,
81141611Sru"usage: mdconfig -a -t type [-n] [-o [no]option] ... [-f file]\n"
82137669Sru"                [-s size] [-S sectorsize] [-u unit]\n"
83215247Sjoel"                [-x sectors/track] [-y heads/cylinder]\n"
84187027Strasz"       mdconfig -d -u unit [-o [no]force]\n"
85238215Strasz"       mdconfig -r -u unit -s size [-o [no]force]\n"
86252033Shrs"       mdconfig -l [-v] [-n] [-f file] [-u unit]\n"
87221232Sdes"       mdconfig file\n");
88243372Sjh	fprintf(stderr, "\t\ttype = {malloc, vnode, swap}\n");
8973094Sphk	fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n");
90142926Spjd	fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%db (B),\n");
91142926Spjd	fprintf(stderr, "\t\t       %%dk (kB), %%dm (MB), %%dg (GB) or\n");
92142926Spjd	fprintf(stderr, "\t\t       %%dt (TB)\n");
9370538Sphk	exit(1);
9470538Sphk}
9570538Sphk
9670448Sphkint
9770448Sphkmain(int argc, char **argv)
9870448Sphk{
99179910Smarck	int ch, fd, i, vflag;
10070538Sphk	char *p;
101238215Strasz	char *fflag = NULL, *sflag = NULL, *tflag = NULL, *uflag = NULL;
10270448Sphk
103135340Spjd	bzero(&mdio, sizeof(mdio));
104139359Spjd	mdio.md_file = malloc(PATH_MAX);
105139359Spjd	if (mdio.md_file == NULL)
106139359Spjd		err(1, "could not allocate memory");
107179910Smarck	vflag = 0;
108139359Spjd	bzero(mdio.md_file, PATH_MAX);
109230612Strasz
110230612Strasz	if (argc == 1)
111230612Strasz		usage();
112230612Strasz
113238215Strasz	while ((ch = getopt(argc, argv, "ab:df:lno:rs:S:t:u:vx:y:")) != -1) {
11470448Sphk		switch (ch) {
11570448Sphk		case 'a':
116230612Strasz			if (action != UNSET && action != ATTACH)
117238215Strasz				errx(1, "-a is mutually exclusive "
118238215Strasz				    "with -d, -r, and -l");
11970448Sphk			action = ATTACH;
12070448Sphk			break;
12170448Sphk		case 'd':
122230612Strasz			if (action != UNSET && action != DETACH)
123238215Strasz				errx(1, "-d is mutually exclusive "
124238215Strasz				    "with -a, -r, and -l");
12570448Sphk			action = DETACH;
126230612Strasz			mdio.md_options |= MD_AUTOUNIT;
12770448Sphk			break;
128238215Strasz		case 'r':
129238215Strasz			if (action != UNSET && action != RESIZE)
130238215Strasz				errx(1, "-r is mutually exclusive "
131238215Strasz				    "with -a, -d, and -l");
132238215Strasz			action = RESIZE;
133238215Strasz			mdio.md_options |= MD_AUTOUNIT;
134238215Strasz			break;
13573026Sphk		case 'l':
136230612Strasz			if (action != UNSET && action != LIST)
137238215Strasz				errx(1, "-l is mutually exclusive "
138238215Strasz				    "with -a, -r, and -d");
13973026Sphk			action = LIST;
140230612Strasz			mdio.md_options |= MD_AUTOUNIT;
14173026Sphk			break;
142116194Srwatson		case 'n':
143116194Srwatson			nflag = 1;
144116194Srwatson			break;
14570538Sphk		case 't':
146230612Strasz			if (tflag != NULL)
147230612Strasz				errx(1, "-t can be passed only once");
148230612Strasz			tflag = optarg;
14970538Sphk			if (!strcmp(optarg, "malloc")) {
15070538Sphk				mdio.md_type = MD_MALLOC;
151230612Strasz				mdio.md_options |= MD_AUTOUNIT | MD_COMPRESS;
15270538Sphk			} else if (!strcmp(optarg, "vnode")) {
15370538Sphk				mdio.md_type = MD_VNODE;
154230612Strasz				mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS;
15570538Sphk			} else if (!strcmp(optarg, "swap")) {
15670538Sphk				mdio.md_type = MD_SWAP;
157230612Strasz				mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS;
158230612Strasz			} else
159230612Strasz				errx(1, "unknown type: %s", optarg);
16070538Sphk			break;
16170448Sphk		case 'f':
162230612Strasz			if (fflag != NULL)
163230612Strasz				errx(1, "-f can be passed only once");
164253833Sdelphij			fflag = realpath(optarg, NULL);
165253833Sdelphij			if (fflag == NULL)
166253833Sdelphij				err(1, "realpath");
16770448Sphk			break;
16870448Sphk		case 'o':
169126821Sphk			if (!strcmp(optarg, "async"))
170126821Sphk				mdio.md_options |= MD_ASYNC;
171126821Sphk			else if (!strcmp(optarg, "noasync"))
172126821Sphk				mdio.md_options &= ~MD_ASYNC;
173126821Sphk			else if (!strcmp(optarg, "cluster"))
17470448Sphk				mdio.md_options |= MD_CLUSTER;
17570448Sphk			else if (!strcmp(optarg, "nocluster"))
17670448Sphk				mdio.md_options &= ~MD_CLUSTER;
17770538Sphk			else if (!strcmp(optarg, "compress"))
17870538Sphk				mdio.md_options |= MD_COMPRESS;
17970538Sphk			else if (!strcmp(optarg, "nocompress"))
18070538Sphk				mdio.md_options &= ~MD_COMPRESS;
18181257Sdd			else if (!strcmp(optarg, "force"))
18281257Sdd				mdio.md_options |= MD_FORCE;
18381257Sdd			else if (!strcmp(optarg, "noforce"))
18481257Sdd				mdio.md_options &= ~MD_FORCE;
185134965Sjmg			else if (!strcmp(optarg, "readonly"))
186134965Sjmg				mdio.md_options |= MD_READONLY;
187134965Sjmg			else if (!strcmp(optarg, "noreadonly"))
188134965Sjmg				mdio.md_options &= ~MD_READONLY;
18970448Sphk			else if (!strcmp(optarg, "reserve"))
19070448Sphk				mdio.md_options |= MD_RESERVE;
19170448Sphk			else if (!strcmp(optarg, "noreserve"))
19270448Sphk				mdio.md_options &= ~MD_RESERVE;
19370448Sphk			else
194230612Strasz				errx(1, "unknown option: %s", optarg);
19570448Sphk			break;
196111818Sphk		case 'S':
197135340Spjd			mdio.md_sectorsize = strtoul(optarg, &p, 0);
198111818Sphk			break;
19970448Sphk		case 's':
200238215Strasz			if (sflag != NULL)
201238215Strasz				errx(1, "-s can be passed only once");
202238215Strasz			sflag = optarg;
203135340Spjd			mdio.md_mediasize = (off_t)strtoumax(optarg, &p, 0);
20470538Sphk			if (p == NULL || *p == '\0')
205135340Spjd				mdio.md_mediasize *= DEV_BSIZE;
206140627Spjd			else if (*p == 'b' || *p == 'B')
207140627Spjd				; /* do nothing */
20870538Sphk			else if (*p == 'k' || *p == 'K')
209135340Spjd				mdio.md_mediasize <<= 10;
21070538Sphk			else if (*p == 'm' || *p == 'M')
211135340Spjd				mdio.md_mediasize <<= 20;
21270538Sphk			else if (*p == 'g' || *p == 'G')
213135340Spjd				mdio.md_mediasize <<= 30;
214135340Spjd			else if (*p == 't' || *p == 'T') {
215135340Spjd				mdio.md_mediasize <<= 30;
216135340Spjd				mdio.md_mediasize <<= 10;
217135340Spjd			} else
218230612Strasz				errx(1, "unknown suffix on -s argument");
21970448Sphk			break;
22070448Sphk		case 'u':
221252051Shrs			if (!strncmp(optarg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
222252051Shrs				optarg += sizeof(_PATH_DEV) - 1;
223157166Swkoszek			if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1))
224157166Swkoszek				optarg += sizeof(MD_NAME) - 1;
225230612Strasz			uflag = optarg;
22670448Sphk			break;
227179910Smarck		case 'v':
228179910Smarck			vflag = OPT_VERBOSE;
229179910Smarck			break;
230113289Sphk		case 'x':
231113289Sphk			mdio.md_fwsectors = strtoul(optarg, &p, 0);
232113289Sphk			break;
233113289Sphk		case 'y':
234113289Sphk			mdio.md_fwheads = strtoul(optarg, &p, 0);
235113289Sphk			break;
23670448Sphk		default:
23770538Sphk			usage();
23870448Sphk		}
23970448Sphk	}
240221232Sdes
241221232Sdes	argc -= optind;
242221232Sdes	argv += optind;
243230612Strasz
244230612Strasz	if (action == UNSET)
245221232Sdes		action = ATTACH;
246230612Strasz
247230612Strasz	if (action == ATTACH) {
248230612Strasz		if (tflag == NULL) {
249230612Strasz			/*
250230612Strasz			 * Try to infer the type based on other arguments.
251230612Strasz			 */
252230612Strasz			if (fflag != NULL || argc > 0) {
253230612Strasz				/* Imply ``-t vnode'' */
254230612Strasz				mdio.md_type = MD_VNODE;
255230612Strasz				mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT |
256230612Strasz				    MD_COMPRESS;
257238215Strasz			} else if (sflag != NULL) {
258230612Strasz				/* Imply ``-t swap'' */
259230612Strasz				mdio.md_type = MD_SWAP;
260230612Strasz				mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT |
261230612Strasz				    MD_COMPRESS;
262230612Strasz			} else
263230612Strasz				errx(1, "unable to determine type");
264230612Strasz		}
265230612Strasz
266230612Strasz		if ((fflag != NULL || argc > 0) && mdio.md_type != MD_VNODE)
267230612Strasz			errx(1, "only -t vnode can be used with file name");
268230612Strasz
269230612Strasz		if (mdio.md_type == MD_VNODE) {
270230612Strasz			if (fflag != NULL) {
271230612Strasz				if (argc != 0)
272230612Strasz					usage();
273230612Strasz				md_set_file(fflag);
274230612Strasz			} else {
275230612Strasz				if (argc != 1)
276230612Strasz					usage();
277230612Strasz				md_set_file(*argv);
278230612Strasz			}
279230612Strasz
280230612Strasz			if ((mdio.md_options & MD_READONLY) == 0 &&
281230612Strasz			    access(mdio.md_file, W_OK) < 0 &&
282230612Strasz			    (errno == EACCES || errno == EPERM ||
283230612Strasz			     errno == EROFS)) {
284230612Strasz				warnx("WARNING: opening backing store: %s "
285230612Strasz				    "readonly", mdio.md_file);
286230612Strasz				mdio.md_options |= MD_READONLY;
287230612Strasz			}
288230612Strasz		}
289230612Strasz
290230612Strasz		if ((mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP) &&
291238215Strasz		    sflag == NULL)
292230612Strasz			errx(1, "must specify -s for -t malloc or -t swap");
293230612Strasz		if (mdio.md_type == MD_VNODE && mdio.md_file[0] == '\0')
294230612Strasz			errx(1, "must specify -f for -t vnode");
295230612Strasz	} else {
296230612Strasz		if (mdio.md_sectorsize != 0)
297230612Strasz			errx(1, "-S can only be used with -a");
298238215Strasz		if (action != RESIZE && sflag != NULL)
299238215Strasz			errx(1, "-s can only be used with -a and -r");
300230612Strasz		if (mdio.md_fwsectors != 0)
301230612Strasz			errx(1, "-x can only be used with -a");
302230612Strasz		if (mdio.md_fwheads != 0)
303230612Strasz			errx(1, "-y can only be used with -a");
304252033Shrs		if (fflag != NULL && action != LIST)
305252033Shrs			errx(1, "-f can only be used with -a and -l");
306230612Strasz		if (tflag != NULL)
307230612Strasz			errx(1, "-t can only be used with -a");
308230612Strasz		if (argc > 0)
309230612Strasz			errx(1, "file can only be used with -a");
310238215Strasz		if ((action != DETACH && action != RESIZE) &&
311238215Strasz		    (mdio.md_options & ~MD_AUTOUNIT) != 0)
312238215Strasz			errx(1, "-o can only be used with -a, -d, and -r");
313230612Strasz		if (action == DETACH &&
314230612Strasz		    (mdio.md_options & ~(MD_FORCE | MD_AUTOUNIT)) != 0)
315230612Strasz			errx(1, "only -o [no]force can be used with -d");
316238215Strasz		if (action == RESIZE &&
317238215Strasz		    (mdio.md_options & ~(MD_FORCE | MD_RESERVE | MD_AUTOUNIT)) != 0)
318238215Strasz			errx(1, "only -o [no]force and -o [no]reserve can be used with -r");
319221232Sdes	}
320221232Sdes
321238215Strasz	if (action == RESIZE && sflag == NULL)
322238215Strasz		errx(1, "must specify -s for -r");
323238215Strasz
324230612Strasz	if (action != LIST && vflag == OPT_VERBOSE)
325230612Strasz		errx(1, "-v can only be used with -l");
326230612Strasz
327230612Strasz	if (uflag != NULL) {
328230612Strasz		mdio.md_unit = strtoul(uflag, &p, 0);
329230612Strasz		if (mdio.md_unit == (unsigned)ULONG_MAX || *p != '\0')
330230612Strasz			errx(1, "bad unit: %s", uflag);
331230612Strasz		mdio.md_options &= ~MD_AUTOUNIT;
332230612Strasz	}
333230612Strasz
33488249Sdd	mdio.md_version = MDIOVERSION;
33570448Sphk
336155807Spjd	if (!kld_isloaded("g_md") && kld_load("geom_md") == -1)
337155807Spjd		err(1, "failed to load geom_md module");
338155807Spjd
339252033Shrs	fd = open(_PATH_DEV MDCTL_NAME, O_RDWR, 0);
34070448Sphk	if (fd < 0)
341252033Shrs		err(1, "open(%s%s)", _PATH_DEV, MDCTL_NAME);
342230612Strasz
343230612Strasz	if (action == ATTACH) {
34470448Sphk		i = ioctl(fd, MDIOCATTACH, &mdio);
34573026Sphk		if (i < 0)
346252033Shrs			err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME);
34770541Sphk		if (mdio.md_options & MD_AUTOUNIT)
348116194Srwatson			printf("%s%d\n", nflag ? "" : MD_NAME, mdio.md_unit);
34974044Sphk	} else if (action == DETACH) {
35074044Sphk		if (mdio.md_options & MD_AUTOUNIT)
351230612Strasz			errx(1, "-d requires -u");
35270448Sphk		i = ioctl(fd, MDIOCDETACH, &mdio);
35373026Sphk		if (i < 0)
354252033Shrs			err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME);
355238215Strasz	} else if (action == RESIZE) {
356238215Strasz		if (mdio.md_options & MD_AUTOUNIT)
357238215Strasz			errx(1, "-r requires -u");
358238215Strasz		i = ioctl(fd, MDIOCRESIZE, &mdio);
359238215Strasz		if (i < 0)
360252033Shrs			err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME);
361230612Strasz	} else if (action == LIST) {
362230612Strasz		if (mdio.md_options & MD_AUTOUNIT) {
363230612Strasz			/*
364230612Strasz			 * Listing all devices. This is why we pass NULL
365230612Strasz			 * together with OPT_LIST.
366230612Strasz			 */
367252036Shrs			return (md_list(NULL, OPT_LIST | vflag, fflag));
368230612Strasz		} else
369252033Shrs			return (md_query(uflag, vflag, fflag));
37074044Sphk	} else
37174044Sphk		usage();
372230612Strasz	close(fd);
37370448Sphk	return (0);
37470448Sphk}
37570448Sphk
376221232Sdesstatic void
377221232Sdesmd_set_file(const char *fn)
378221232Sdes{
379221232Sdes	struct stat sb;
380221232Sdes	int fd;
381221232Sdes
382221232Sdes	if (realpath(fn, mdio.md_file) == NULL)
383221232Sdes		err(1, "could not find full path for %s", fn);
384221232Sdes	fd = open(mdio.md_file, O_RDONLY);
385221232Sdes	if (fd < 0)
386221232Sdes		err(1, "could not open %s", fn);
387221232Sdes	if (fstat(fd, &sb) == -1)
388221232Sdes		err(1, "could not stat %s", fn);
389221232Sdes	if (!S_ISREG(sb.st_mode))
390221232Sdes		errx(1, "%s is not a regular file", fn);
391221232Sdes	if (mdio.md_mediasize == 0)
392221232Sdes		mdio.md_mediasize = sb.st_size;
393221232Sdes	close(fd);
394221232Sdes}
395221232Sdes
396157160Swkoszek/*
397157160Swkoszek * Lists md(4) disks. Is used also as a query routine, since it handles XML
398157160Swkoszek * interface. 'units' can be NULL for listing memory disks. It might be
399157160Swkoszek * coma-separated string containing md(4) disk names. 'opt' distinguished
400157160Swkoszek * between list and query mode.
401157160Swkoszek */
402153636Sddstatic int
403252033Shrsmd_list(const char *units, int opt, const char *fflag)
404153636Sdd{
405157160Swkoszek	struct gmesh gm;
406157160Swkoszek	struct gprovider *pp;
407157160Swkoszek	struct gconf *gc;
408157160Swkoszek	struct gident *gid;
409157173Sjasone	struct devstat *gsp;
410157160Swkoszek	struct ggeom *gg;
411157160Swkoszek	struct gclass *gcl;
412157160Swkoszek	void *sq;
413252036Shrs	int retcode, ffound, ufound;
414157160Swkoszek	char *type, *file, *length;
415157160Swkoszek
416157160Swkoszek	type = file = length = NULL;
417157160Swkoszek
418157160Swkoszek	retcode = geom_gettree(&gm);
419157160Swkoszek	if (retcode != 0)
420157160Swkoszek		return (-1);
421157160Swkoszek	retcode = geom_stats_open();
422157160Swkoszek	if (retcode != 0)
423157160Swkoszek		return (-1);
424157160Swkoszek	sq = geom_stats_snapshot_get();
425157160Swkoszek	if (sq == NULL)
426157160Swkoszek		return (-1);
427157160Swkoszek
428252036Shrs	ffound = ufound = 0;
429157160Swkoszek	while ((gsp = geom_stats_snapshot_next(sq)) != NULL) {
430157160Swkoszek		gid = geom_lookupid(&gm, gsp->id);
431157160Swkoszek		if (gid == NULL)
432157160Swkoszek			continue;
433157160Swkoszek		if (gid->lg_what == ISPROVIDER) {
434157160Swkoszek			pp = gid->lg_ptr;
435157160Swkoszek			gg = pp->lg_geom;
436157160Swkoszek			gcl = gg->lg_class;
437157160Swkoszek			if (strcmp(gcl->lg_name, CLASS_NAME_MD) != 0)
438157160Swkoszek				continue;
439157160Swkoszek			if ((opt & OPT_UNIT) && (units != NULL)) {
440157160Swkoszek				retcode = md_find(units, pp->lg_name);
441157160Swkoszek				if (retcode != 1)
442157160Swkoszek					continue;
443173676Sflz				else
444252036Shrs					ufound = 1;
445157160Swkoszek			}
446157160Swkoszek			gc = &pp->lg_config;
447252033Shrs			type = geom_config_get(gc, "type");
448252033Shrs			if (strcmp(type, "vnode") == 0) {
449252033Shrs				file = geom_config_get(gc, "file");
450252033Shrs				if (fflag != NULL &&
451252033Shrs				    strcmp(fflag, file) != 0)
452252033Shrs					continue;
453252036Shrs				else
454252036Shrs					ffound = 1;
455252523Sdelphij			} else if (fflag != NULL)
456252523Sdelphij					continue;
457252033Shrs			if (nflag && strncmp(pp->lg_name, MD_NAME, 2) == 0)
458218677Sbrucec				printf("%s", pp->lg_name + 2);
459218677Sbrucec			else
460218677Sbrucec				printf("%s", pp->lg_name);
461218677Sbrucec
462252033Shrs			if (opt & OPT_VERBOSE ||
463252033Shrs			    ((opt & OPT_UNIT) && fflag == NULL)) {
464157160Swkoszek				length = geom_config_get(gc, "length");
465157160Swkoszek				printf("\t%s\t", type);
466202784Sjh				if (length != NULL)
467202784Sjh					md_prthumanval(length);
468157160Swkoszek				if (file != NULL) {
469157160Swkoszek					printf("\t%s", file);
470157160Swkoszek					file = NULL;
471157160Swkoszek				}
472157160Swkoszek			}
473157160Swkoszek			opt |= OPT_DONE;
474179910Smarck			if ((opt & OPT_LIST) && !(opt & OPT_VERBOSE))
475157160Swkoszek				printf(" ");
476157160Swkoszek			else
477157160Swkoszek				printf("\n");
478157160Swkoszek		}
479157160Swkoszek	}
480179910Smarck	if ((opt & OPT_LIST) && (opt & OPT_DONE) && !(opt & OPT_VERBOSE))
481157160Swkoszek		printf("\n");
482157160Swkoszek	/* XXX: Check if it's enough to clean everything. */
483157160Swkoszek	geom_stats_snapshot_free(sq);
484273188Shrs	if (opt & OPT_UNIT) {
485273188Shrs		if (((fflag == NULL) && ufound) ||
486273188Shrs		    ((fflag == NULL) && (units != NULL) && ufound) ||
487273188Shrs		    ((fflag != NULL) && ffound) ||
488273188Shrs		    ((fflag != NULL) && (units != NULL) && ufound && ffound))
489273188Shrs			return (0);
490273188Shrs	} else if (opt & OPT_LIST) {
491273188Shrs		if ((fflag == NULL) ||
492273188Shrs		    ((fflag != NULL) && ffound))
493273188Shrs			return (0);
494273188Shrs	}
495273188Shrs	return (-1);
496153636Sdd}
497153636Sdd
498157160Swkoszek/*
499157160Swkoszek * Returns value of 'name' from gconfig structure.
500157160Swkoszek */
501157160Swkoszekstatic char *
502202784Sjhgeom_config_get(struct gconf *g, const char *name)
503157160Swkoszek{
504157160Swkoszek	struct gconfig *gce;
505157160Swkoszek
506157160Swkoszek	LIST_FOREACH(gce, g, lg_config) {
507157160Swkoszek		if (strcmp(gce->lg_name, name) == 0)
508157160Swkoszek			return (gce->lg_val);
509157160Swkoszek	}
510157160Swkoszek	return (NULL);
511157160Swkoszek}
512157160Swkoszek
513157160Swkoszek/*
514157160Swkoszek * List is comma separated list of MD disks. name is a
515157160Swkoszek * device name we look for.  Returns 1 if found and 0
516157160Swkoszek * otherwise.
517157160Swkoszek */
518157159Swkoszekstatic int
519252033Shrsmd_find(const char *list, const char *name)
52073026Sphk{
521157160Swkoszek	int ret;
522252051Shrs	char num[PATH_MAX];
523157160Swkoszek	char *ptr, *p, *u;
52473026Sphk
525157160Swkoszek	ret = 0;
526157160Swkoszek	ptr = strdup(list);
527157160Swkoszek	if (ptr == NULL)
528157160Swkoszek		return (-1);
529157160Swkoszek	for (p = ptr; (u = strsep(&p, ",")) != NULL;) {
530252051Shrs		if (strncmp(u, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
531252051Shrs			u += sizeof(_PATH_DEV) - 1;
532157160Swkoszek		/* Just in case user specified number instead of full name */
533252051Shrs		snprintf(num, sizeof(num), "%s%s", MD_NAME, u);
534157160Swkoszek		if (strcmp(u, name) == 0 || strcmp(num, name) == 0) {
535157160Swkoszek			ret = 1;
536157160Swkoszek			break;
537157160Swkoszek		}
53873026Sphk	}
539157160Swkoszek	free(ptr);
540157160Swkoszek	return (ret);
54173026Sphk}
54273026Sphk
543135340Spjdstatic void
544157160Swkoszekmd_prthumanval(char *length)
545135340Spjd{
546135340Spjd	char buf[6];
547202573Sjh	uintmax_t bytes;
548157160Swkoszek	char *endptr;
549135340Spjd
550202573Sjh	errno = 0;
551202573Sjh	bytes = strtoumax(length, &endptr, 10);
552202573Sjh	if (errno != 0 || *endptr != '\0' || bytes > INT64_MAX)
553157160Swkoszek		return;
554202573Sjh	humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
555202573Sjh	    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
556135340Spjd	(void)printf("%6s", buf);
557135340Spjd}
558135340Spjd
559232964Straszstatic int
560252033Shrsmd_query(const char *name, const int opt, const char *fflag)
56173026Sphk{
562230612Strasz
563252033Shrs	return (md_list(name, opt | OPT_UNIT, fflag));
56473026Sphk}
565