Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/mdconfig/mdconfig.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2000-2004 Poul-Henning Kamp <[email protected]>
5
* Copyright (c) 2012 The FreeBSD Foundation
6
* All rights reserved.
7
*
8
* Portions of this software were developed by Edward Tomasz Napierala
9
* under sponsorship from the FreeBSD Foundation.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
*
20
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
* SUCH DAMAGE.
31
*/
32
33
#include <sys/param.h>
34
#include <sys/devicestat.h>
35
#include <sys/ioctl.h>
36
#include <sys/linker.h>
37
#include <sys/mdioctl.h>
38
#include <sys/module.h>
39
#include <sys/resource.h>
40
#include <sys/stat.h>
41
42
#include <assert.h>
43
#include <devstat.h>
44
#include <err.h>
45
#include <errno.h>
46
#include <fcntl.h>
47
#include <inttypes.h>
48
#include <libgeom.h>
49
#include <libutil.h>
50
#include <paths.h>
51
#include <stdarg.h>
52
#include <stdio.h>
53
#include <stdlib.h>
54
#include <string.h>
55
#include <unistd.h>
56
57
static struct md_ioctl mdio;
58
static enum {UNSET, ATTACH, DETACH, RESIZE, LIST} action = UNSET;
59
static int md_fd, nflag;
60
61
static void usage(void) __dead2;
62
static void md_set_file(const char *);
63
static int md_find(const char *, const char *);
64
static int md_query(const char *, const int, const char *);
65
static int md_list(const char *, int, const char *);
66
static char *geom_config_get(struct gconf *g, const char *name);
67
static void md_prthumanval(char *length);
68
static void print_options(const char *s, const char *);
69
70
#define OPT_VERBOSE 0x01
71
#define OPT_UNIT 0x02
72
#define OPT_DONE 0x04
73
#define OPT_LIST 0x10
74
75
#define CLASS_NAME_MD "MD"
76
77
static void
78
usage(void)
79
{
80
81
fprintf(stderr,
82
"usage: mdconfig -a -t type [-n] [-o [no]option] ... [-f file]\n"
83
" [-s size] [-S sectorsize] [-u unit] [-L label]\n"
84
" [-x sectors/track] [-y heads/cylinder]\n"
85
" mdconfig -d -u unit [-o [no]force]\n"
86
" mdconfig -r -u unit -s size [-o [no]force]\n"
87
" mdconfig -l [-v] [-n] [-f file] [-u unit]\n"
88
" mdconfig file\n");
89
fprintf(stderr, "\t\ttype = {malloc, vnode, swap}\n");
90
fprintf(stderr, "\t\toption = {async, cache, compress,\n");
91
fprintf(stderr, "\t\t force, mustdealloc, readonly, ro,\n");
92
fprintf(stderr, "\t\t reserve, verify}\n");
93
fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%db (B),\n");
94
fprintf(stderr, "\t\t %%dk (kB), %%dm (MB), %%dg (GB),\n");
95
fprintf(stderr, "\t\t %%dt (TB), or %%dp (PB)\n");
96
exit(1);
97
}
98
99
int
100
main(int argc, char **argv)
101
{
102
int ch, i, vflag;
103
char *p;
104
char *fflag = NULL, *sflag = NULL, *tflag = NULL, *uflag = NULL;
105
106
bzero(&mdio, sizeof(mdio));
107
mdio.md_file = malloc(PATH_MAX);
108
mdio.md_label = malloc(PATH_MAX);
109
if (mdio.md_file == NULL || mdio.md_label == NULL)
110
err(1, "could not allocate memory");
111
vflag = 0;
112
bzero(mdio.md_file, PATH_MAX);
113
bzero(mdio.md_label, PATH_MAX);
114
115
if (argc == 1)
116
usage();
117
118
while ((ch = getopt(argc, argv, "ab:df:lno:rs:S:t:u:vx:y:L:")) != -1) {
119
switch (ch) {
120
case 'a':
121
if (action != UNSET && action != ATTACH)
122
errx(1, "-a is mutually exclusive "
123
"with -d, -r, and -l");
124
action = ATTACH;
125
break;
126
case 'd':
127
if (action != UNSET && action != DETACH)
128
errx(1, "-d is mutually exclusive "
129
"with -a, -r, and -l");
130
action = DETACH;
131
mdio.md_options |= MD_AUTOUNIT;
132
break;
133
case 'r':
134
if (action != UNSET && action != RESIZE)
135
errx(1, "-r is mutually exclusive "
136
"with -a, -d, and -l");
137
action = RESIZE;
138
mdio.md_options |= MD_AUTOUNIT;
139
break;
140
case 'l':
141
if (action != UNSET && action != LIST)
142
errx(1, "-l is mutually exclusive "
143
"with -a, -r, and -d");
144
action = LIST;
145
mdio.md_options |= MD_AUTOUNIT;
146
break;
147
case 'n':
148
nflag = 1;
149
break;
150
case 't':
151
if (tflag != NULL)
152
errx(1, "-t can be passed only once");
153
tflag = optarg;
154
if (!strcmp(optarg, "malloc")) {
155
mdio.md_type = MD_MALLOC;
156
mdio.md_options |= MD_AUTOUNIT | MD_COMPRESS;
157
} else if (!strcmp(optarg, "vnode")) {
158
mdio.md_type = MD_VNODE;
159
mdio.md_options |= MD_AUTOUNIT | MD_COMPRESS;
160
} else if (!strcmp(optarg, "swap")) {
161
mdio.md_type = MD_SWAP;
162
mdio.md_options |= MD_AUTOUNIT | MD_COMPRESS;
163
} else if (!strcmp(optarg, "null")) {
164
mdio.md_type = MD_NULL;
165
mdio.md_options |= MD_AUTOUNIT | MD_COMPRESS;
166
} else
167
errx(1, "unknown type: %s", optarg);
168
break;
169
case 'f':
170
if (fflag != NULL)
171
errx(1, "-f can be passed only once");
172
fflag = realpath(optarg, NULL);
173
if (fflag == NULL)
174
err(1, "realpath");
175
break;
176
case 'o':
177
if (!strcmp(optarg, "async"))
178
mdio.md_options |= MD_ASYNC;
179
else if (!strcmp(optarg, "noasync"))
180
mdio.md_options &= ~MD_ASYNC;
181
else if (!strcmp(optarg, "cache"))
182
mdio.md_options |= MD_CACHE;
183
else if (!strcmp(optarg, "nocache"))
184
mdio.md_options &= ~MD_CACHE;
185
/*
186
* For backwards-compatibility, continue to recognize
187
* "cluster"
188
*/
189
else if (!strcmp(optarg, "cluster") ||
190
!strcmp(optarg, "nocluster"))
191
{
192
warnx("Option cluster is ignored");
193
}
194
else if (!strcmp(optarg, "compress"))
195
mdio.md_options |= MD_COMPRESS;
196
else if (!strcmp(optarg, "nocompress"))
197
mdio.md_options &= ~MD_COMPRESS;
198
else if (!strcmp(optarg, "force"))
199
mdio.md_options |= MD_FORCE;
200
else if (!strcmp(optarg, "noforce"))
201
mdio.md_options &= ~MD_FORCE;
202
else if (!strcmp(optarg, "mustdealloc"))
203
mdio.md_options |= MD_MUSTDEALLOC;
204
else if (!strcmp(optarg, "nomustdealloc"))
205
mdio.md_options &= ~MD_MUSTDEALLOC;
206
else if (!strcmp(optarg, "readonly"))
207
mdio.md_options |= MD_READONLY;
208
else if (!strcmp(optarg, "noreadonly"))
209
mdio.md_options &= ~MD_READONLY;
210
else if (!strcmp(optarg, "ro"))
211
mdio.md_options |= MD_READONLY;
212
else if (!strcmp(optarg, "noro"))
213
mdio.md_options &= ~MD_READONLY;
214
else if (!strcmp(optarg, "reserve"))
215
mdio.md_options |= MD_RESERVE;
216
else if (!strcmp(optarg, "noreserve"))
217
mdio.md_options &= ~MD_RESERVE;
218
else if (!strcmp(optarg, "verify"))
219
mdio.md_options |= MD_VERIFY;
220
else if (!strcmp(optarg, "noverify"))
221
mdio.md_options &= ~MD_VERIFY;
222
else
223
errx(1, "unknown option: %s", optarg);
224
break;
225
case 'S':
226
mdio.md_sectorsize = strtoul(optarg, &p, 0);
227
break;
228
case 's':
229
if (sflag != NULL)
230
errx(1, "-s can be passed only once");
231
sflag = optarg;
232
mdio.md_mediasize = (off_t)strtoumax(optarg, &p, 0);
233
if (p == NULL || *p == '\0')
234
mdio.md_mediasize *= DEV_BSIZE;
235
else if (*p == 'b' || *p == 'B')
236
; /* do nothing */
237
else if (*p == 'k' || *p == 'K')
238
mdio.md_mediasize <<= 10;
239
else if (*p == 'm' || *p == 'M')
240
mdio.md_mediasize <<= 20;
241
else if (*p == 'g' || *p == 'G')
242
mdio.md_mediasize <<= 30;
243
else if (*p == 't' || *p == 'T') {
244
mdio.md_mediasize <<= 30;
245
mdio.md_mediasize <<= 10;
246
} else if (*p == 'p' || *p == 'P') {
247
mdio.md_mediasize <<= 30;
248
mdio.md_mediasize <<= 20;
249
} else
250
errx(1, "unknown suffix on -s argument");
251
break;
252
case 'u':
253
if (!strncmp(optarg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
254
optarg += sizeof(_PATH_DEV) - 1;
255
if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1))
256
optarg += sizeof(MD_NAME) - 1;
257
uflag = optarg;
258
break;
259
case 'v':
260
vflag = OPT_VERBOSE;
261
break;
262
case 'x':
263
mdio.md_fwsectors = strtoul(optarg, &p, 0);
264
break;
265
case 'y':
266
mdio.md_fwheads = strtoul(optarg, &p, 0);
267
break;
268
case 'L':
269
strlcpy(mdio.md_label, optarg, PATH_MAX);
270
break;
271
default:
272
usage();
273
}
274
}
275
276
argc -= optind;
277
argv += optind;
278
279
if (action == UNSET)
280
action = ATTACH;
281
282
if (action == ATTACH) {
283
if (tflag == NULL) {
284
/*
285
* Try to infer the type based on other arguments.
286
*/
287
if (fflag != NULL || argc > 0) {
288
/* Imply ``-t vnode'' */
289
mdio.md_type = MD_VNODE;
290
mdio.md_options |= MD_AUTOUNIT | MD_COMPRESS;
291
} else if (sflag != NULL) {
292
/* Imply ``-t swap'' */
293
mdio.md_type = MD_SWAP;
294
mdio.md_options |= MD_AUTOUNIT | MD_COMPRESS;
295
} else
296
errx(1, "unable to determine type");
297
}
298
299
if ((fflag != NULL || argc > 0) && mdio.md_type != MD_VNODE)
300
errx(1, "only -t vnode can be used with file name");
301
302
if (mdio.md_type == MD_VNODE) {
303
if (fflag != NULL) {
304
if (argc != 0)
305
usage();
306
md_set_file(fflag);
307
} else {
308
if (argc != 1)
309
usage();
310
md_set_file(*argv);
311
}
312
313
if ((mdio.md_options & MD_READONLY) == 0 &&
314
access(mdio.md_file, W_OK) < 0 &&
315
(errno == EACCES || errno == EPERM ||
316
errno == EROFS)) {
317
warnx("WARNING: opening backing store: %s "
318
"readonly", mdio.md_file);
319
mdio.md_options |= MD_READONLY;
320
}
321
}
322
323
if ((mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP ||
324
mdio.md_type == MD_NULL) && sflag == NULL)
325
errx(1, "must specify -s for -t malloc, -t swap, "
326
"or -t null");
327
if (mdio.md_type == MD_VNODE && mdio.md_file[0] == '\0')
328
errx(1, "must specify -f for -t vnode");
329
} else {
330
if (mdio.md_sectorsize != 0)
331
errx(1, "-S can only be used with -a");
332
if (action != RESIZE && sflag != NULL)
333
errx(1, "-s can only be used with -a and -r");
334
if (mdio.md_fwsectors != 0)
335
errx(1, "-x can only be used with -a");
336
if (mdio.md_fwheads != 0)
337
errx(1, "-y can only be used with -a");
338
if (fflag != NULL && action != LIST)
339
errx(1, "-f can only be used with -a and -l");
340
if (tflag != NULL)
341
errx(1, "-t can only be used with -a");
342
if (argc > 0)
343
errx(1, "file can only be used with -a");
344
if ((action != DETACH && action != RESIZE) &&
345
(mdio.md_options & ~MD_AUTOUNIT) != 0)
346
errx(1, "-o can only be used with -a, -d, and -r");
347
if (action == DETACH &&
348
(mdio.md_options & ~(MD_FORCE | MD_AUTOUNIT)) != 0)
349
errx(1, "only -o [no]force can be used with -d");
350
if (action == RESIZE &&
351
(mdio.md_options & ~(MD_FORCE | MD_RESERVE | MD_AUTOUNIT)) != 0)
352
errx(1, "only -o [no]force and -o [no]reserve can be used with -r");
353
}
354
355
if (action == RESIZE && sflag == NULL)
356
errx(1, "must specify -s for -r");
357
358
if (action != LIST && vflag == OPT_VERBOSE)
359
errx(1, "-v can only be used with -l");
360
361
if (uflag != NULL) {
362
mdio.md_unit = strtoul(uflag, &p, 0);
363
if (mdio.md_unit == (unsigned)ULONG_MAX || *p != '\0')
364
errx(1, "bad unit: %s", uflag);
365
mdio.md_options &= ~MD_AUTOUNIT;
366
}
367
368
mdio.md_version = MDIOVERSION;
369
370
if (!kld_isloaded("g_md") && kld_load("geom_md") == -1)
371
err(1, "failed to load geom_md module");
372
373
md_fd = open(_PATH_DEV MDCTL_NAME, O_RDWR, 0);
374
if (md_fd < 0)
375
err(1, "open(%s%s)", _PATH_DEV, MDCTL_NAME);
376
377
if (action == ATTACH) {
378
i = ioctl(md_fd, MDIOCATTACH, &mdio);
379
if (i < 0)
380
err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME);
381
if (mdio.md_options & MD_AUTOUNIT)
382
printf("%s%d\n", nflag ? "" : MD_NAME, mdio.md_unit);
383
} else if (action == DETACH) {
384
if (mdio.md_options & MD_AUTOUNIT)
385
errx(1, "-d requires -u");
386
i = ioctl(md_fd, MDIOCDETACH, &mdio);
387
if (i < 0)
388
err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME);
389
} else if (action == RESIZE) {
390
if (mdio.md_options & MD_AUTOUNIT)
391
errx(1, "-r requires -u");
392
i = ioctl(md_fd, MDIOCRESIZE, &mdio);
393
if (i < 0)
394
err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME);
395
} else if (action == LIST) {
396
if (mdio.md_options & MD_AUTOUNIT) {
397
/*
398
* Listing all devices. This is why we pass NULL
399
* together with OPT_LIST.
400
*/
401
return (md_list(NULL, OPT_LIST | vflag, fflag));
402
} else
403
return (md_query(uflag, vflag, fflag));
404
} else
405
usage();
406
close(md_fd);
407
return (0);
408
}
409
410
static void
411
print_options(const char *dev, const char *file)
412
{
413
struct md_ioctl mdiox;
414
int unit;
415
const char *sep = "";
416
417
if (sscanf(dev, "md%d", &unit) != 1)
418
err(1, "invalid device: %s", dev);
419
420
memset(&mdiox, 0, sizeof(mdiox));
421
mdiox.md_version = MDIOVERSION;
422
mdiox.md_unit = unit;
423
mdiox.md_file = file[0] == '-' ? NULL : strdup(file);
424
425
if (ioctl(md_fd, MDIOCQUERY, &mdiox) < 0)
426
err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME);
427
428
if (mdiox.md_file != NULL)
429
free(mdiox.md_file);
430
431
printf("\t");
432
if (mdiox.md_options & MD_ASYNC) {
433
printf("%sasync", sep);
434
sep = ",";
435
}
436
if (mdiox.md_options & MD_CACHE) {
437
printf("%scache", sep);
438
sep = ",";
439
}
440
if (mdiox.md_options & MD_COMPRESS) {
441
printf("%scompress", sep);
442
sep = ",";
443
}
444
if (mdiox.md_options & MD_FORCE) {
445
printf("%sforce", sep);
446
sep = ",";
447
}
448
if (mdiox.md_options & MD_READONLY) {
449
printf("%sreadonly", sep);
450
sep = ",";
451
}
452
if (mdiox.md_options & MD_RESERVE) {
453
printf("%sreserve", sep);
454
sep = ",";
455
}
456
if (mdiox.md_options & MD_VERIFY) {
457
printf("%sverify", sep);
458
sep = ",";
459
}
460
if (mdiox.md_options & MD_MUSTDEALLOC) {
461
printf("%smustdealloc", sep);
462
sep = ",";
463
}
464
}
465
466
static void
467
md_set_file(const char *fn)
468
{
469
struct stat sb;
470
int fd;
471
472
if (realpath(fn, mdio.md_file) == NULL)
473
err(1, "could not find full path for %s", fn);
474
fd = open(mdio.md_file, O_RDONLY);
475
if (fd < 0)
476
err(1, "could not open %s", fn);
477
if (fstat(fd, &sb) == -1)
478
err(1, "could not stat %s", fn);
479
if (!S_ISREG(sb.st_mode))
480
errx(1, "%s is not a regular file", fn);
481
if (mdio.md_mediasize == 0)
482
mdio.md_mediasize = sb.st_size;
483
close(fd);
484
}
485
486
/*
487
* Lists md(4) disks. Is used also as a query routine, since it handles XML
488
* interface. 'units' can be NULL for listing memory disks. It might be
489
* comma-separated string containing md(4) disk names. 'opt' distinguished
490
* between list and query mode.
491
*/
492
static int
493
md_list(const char *units, int opt, const char *fflag)
494
{
495
struct gmesh gm;
496
struct gprovider *pp;
497
struct gconf *gc;
498
struct gident *gid;
499
struct devstat *gsp;
500
struct ggeom *gg;
501
struct gclass *gcl;
502
void *sq;
503
int retcode, ffound, ufound;
504
char *length;
505
const char *type, *file, *label;
506
507
type = file = length = NULL;
508
509
retcode = geom_gettree(&gm);
510
if (retcode != 0)
511
return (-1);
512
retcode = geom_stats_open();
513
if (retcode != 0)
514
return (-1);
515
sq = geom_stats_snapshot_get();
516
if (sq == NULL)
517
return (-1);
518
519
ffound = ufound = 0;
520
while ((gsp = geom_stats_snapshot_next(sq)) != NULL) {
521
gid = geom_lookupid(&gm, gsp->id);
522
if (gid == NULL)
523
continue;
524
if (gid->lg_what == ISPROVIDER) {
525
pp = gid->lg_ptr;
526
gg = pp->lg_geom;
527
gcl = gg->lg_class;
528
if (strcmp(gcl->lg_name, CLASS_NAME_MD) != 0)
529
continue;
530
if ((opt & OPT_UNIT) && (units != NULL)) {
531
retcode = md_find(units, pp->lg_name);
532
if (retcode != 1)
533
continue;
534
else
535
ufound = 1;
536
}
537
gc = &pp->lg_config;
538
type = geom_config_get(gc, "type");
539
if (type != NULL && (strcmp(type, "vnode") == 0 ||
540
strcmp(type, "preload") == 0)) {
541
file = geom_config_get(gc, "file");
542
if (fflag != NULL &&
543
strcmp(fflag, file) != 0)
544
continue;
545
else
546
ffound = 1;
547
} else if (fflag != NULL)
548
continue;
549
if (nflag && strncmp(pp->lg_name, MD_NAME, 2) == 0)
550
printf("%s", pp->lg_name + 2);
551
else
552
printf("%s", pp->lg_name);
553
554
if (opt & OPT_VERBOSE ||
555
((opt & OPT_UNIT) && fflag == NULL)) {
556
length = geom_config_get(gc, "length");
557
printf("\t%s\t", type);
558
if (length != NULL)
559
md_prthumanval(length);
560
if (file == NULL)
561
file = "-";
562
printf("\t%s", file);
563
label = geom_config_get(gc, "label");
564
if (label == NULL)
565
label = "-";
566
printf("\t%s", label);
567
print_options(pp->lg_name, file);
568
file = label = NULL;
569
}
570
opt |= OPT_DONE;
571
if ((opt & OPT_LIST) && !(opt & OPT_VERBOSE))
572
printf(" ");
573
else
574
printf("\n");
575
}
576
}
577
if ((opt & OPT_LIST) && (opt & OPT_DONE) && !(opt & OPT_VERBOSE))
578
printf("\n");
579
/* XXX: Check if it's enough to clean everything. */
580
geom_stats_snapshot_free(sq);
581
if (opt & OPT_UNIT) {
582
if (((fflag == NULL) && ufound) ||
583
((fflag == NULL) && (units != NULL) && ufound) ||
584
((fflag != NULL) && ffound) ||
585
((fflag != NULL) && (units != NULL) && ufound && ffound))
586
return (0);
587
} else if (opt & OPT_LIST) {
588
if ((fflag == NULL) ||
589
((fflag != NULL) && ffound))
590
return (0);
591
}
592
return (-1);
593
}
594
595
/*
596
* Returns value of 'name' from gconfig structure.
597
*/
598
static char *
599
geom_config_get(struct gconf *g, const char *name)
600
{
601
struct gconfig *gce;
602
603
LIST_FOREACH(gce, g, lg_config) {
604
if (strcmp(gce->lg_name, name) == 0)
605
return (gce->lg_val);
606
}
607
return (NULL);
608
}
609
610
/*
611
* List is comma separated list of MD disks. name is a
612
* device name we look for. Returns 1 if found and 0
613
* otherwise.
614
*/
615
static int
616
md_find(const char *list, const char *name)
617
{
618
int ret;
619
char num[PATH_MAX];
620
char *ptr, *p, *u;
621
622
ret = 0;
623
ptr = strdup(list);
624
if (ptr == NULL)
625
return (-1);
626
for (p = ptr; (u = strsep(&p, ",")) != NULL;) {
627
if (strncmp(u, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
628
u += sizeof(_PATH_DEV) - 1;
629
/* Just in case user specified number instead of full name */
630
snprintf(num, sizeof(num), "%s%s", MD_NAME, u);
631
if (strcmp(u, name) == 0 || strcmp(num, name) == 0) {
632
ret = 1;
633
break;
634
}
635
}
636
free(ptr);
637
return (ret);
638
}
639
640
static void
641
md_prthumanval(char *length)
642
{
643
char buf[6];
644
uintmax_t bytes;
645
char *endptr;
646
647
errno = 0;
648
bytes = strtoumax(length, &endptr, 10);
649
if (errno != 0 || *endptr != '\0' || bytes > INT64_MAX)
650
return;
651
humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
652
HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
653
(void)printf("%6s", buf);
654
}
655
656
static int
657
md_query(const char *name, const int opt, const char *fflag)
658
{
659
660
return (md_list(name, opt | OPT_UNIT, fflag));
661
}
662
663