2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2004, 2007 Lukas Ertl
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
34 #include <sys/libkern.h>
35 #include <sys/malloc.h>
38 #include <geom/geom.h>
39 #include <geom/vinum/geom_vinum_var.h>
40 #include <geom/vinum/geom_vinum.h>
41 #include <geom/vinum/geom_vinum_share.h>
43 void gv_lvi(struct gv_volume *, struct sbuf *, int);
44 void gv_lpi(struct gv_plex *, struct sbuf *, int);
45 void gv_lsi(struct gv_sd *, struct sbuf *, int);
46 void gv_ldi(struct gv_drive *, struct sbuf *, int);
49 gv_list(struct g_geom *gp, struct gctl_req *req)
57 int *argc, i, *flags, type;
58 char *arg, buf[20], *cmd;
60 argc = gctl_get_paraml(req, "argc", sizeof(*argc));
63 gctl_error(req, "no arguments given");
67 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
69 gctl_error(req, "no flags given");
75 sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN);
77 /* Figure out which command was given. */
78 cmd = gctl_get_param(req, "cmd", NULL);
80 gctl_error(req, "no command given");
84 /* List specific objects or everything. */
85 if (!strcmp(cmd, "list") || !strcmp(cmd, "l")) {
87 for (i = 0; i < *argc; i++) {
88 snprintf(buf, sizeof(buf), "argv%d", i);
89 arg = gctl_get_param(req, buf, NULL);
92 type = gv_object_type(sc, arg);
95 v = gv_find_vol(sc, arg);
96 gv_lvi(v, sb, *flags);
99 p = gv_find_plex(sc, arg);
100 gv_lpi(p, sb, *flags);
103 s = gv_find_sd(sc, arg);
104 gv_lsi(s, sb, *flags);
107 d = gv_find_drive(sc, arg);
108 gv_ldi(d, sb, *flags);
111 gctl_error(req, "unknown object '%s'",
118 sbuf_printf(sb, "\n");
120 sbuf_printf(sb, "\n");
122 sbuf_printf(sb, "\n");
127 } else if (!strcmp(cmd, "ld")) {
129 for (i = 0; i < *argc; i++) {
130 snprintf(buf, sizeof(buf), "argv%d", i);
131 arg = gctl_get_param(req, buf, NULL);
134 type = gv_object_type(sc, arg);
135 if (type != GV_TYPE_DRIVE) {
136 gctl_error(req, "'%s' is not a drive",
140 d = gv_find_drive(sc, arg);
141 gv_ldi(d, sb, *flags);
148 } else if (!strcmp(cmd, "lv")) {
150 for (i = 0; i < *argc; i++) {
151 snprintf(buf, sizeof(buf), "argv%d", i);
152 arg = gctl_get_param(req, buf, NULL);
155 type = gv_object_type(sc, arg);
156 if (type != GV_TYPE_VOL) {
157 gctl_error(req, "'%s' is not a volume",
161 v = gv_find_vol(sc, arg);
162 gv_lvi(v, sb, *flags);
169 } else if (!strcmp(cmd, "lp")) {
171 for (i = 0; i < *argc; i++) {
172 snprintf(buf, sizeof(buf), "argv%d", i);
173 arg = gctl_get_param(req, buf, NULL);
176 type = gv_object_type(sc, arg);
177 if (type != GV_TYPE_PLEX) {
178 gctl_error(req, "'%s' is not a plex",
182 p = gv_find_plex(sc, arg);
183 gv_lpi(p, sb, *flags);
190 } else if (!strcmp(cmd, "ls")) {
192 for (i = 0; i < *argc; i++) {
193 snprintf(buf, sizeof(buf), "argv%d", i);
194 arg = gctl_get_param(req, buf, NULL);
197 type = gv_object_type(sc, arg);
198 if (type != GV_TYPE_SD) {
199 gctl_error(req, "'%s' is not a subdisk",
203 s = gv_find_sd(sc, arg);
204 gv_lsi(s, sb, *flags);
211 gctl_error(req, "unknown command '%s'", cmd);
214 gctl_set_param(req, "config", sbuf_data(sb), sbuf_len(sb) + 1);
218 /* List one or more volumes. */
220 gv_lv(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
229 LIST_FOREACH(v, &sc->volumes, volume)
232 sbuf_printf(sb, "%d volume%s:\n", i, i == 1 ? "" : "s");
235 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
236 LIST_FOREACH(v, &sc->volumes, volume)
237 gv_lvi(v, sb, *flags);
241 /* List a single volume. */
243 gv_lvi(struct gv_volume *v, struct sbuf *sb, int flags)
248 if (flags & GV_FLAG_V) {
249 sbuf_printf(sb, "Volume %s:\tSize: %jd bytes (%jd MB)\n",
250 v->name, (intmax_t)v->size, (intmax_t)v->size / MEGABYTE);
251 sbuf_printf(sb, "\t\tState: %s\n", gv_volstate(v->state));
253 sbuf_printf(sb, "V %-21s State: %s\tPlexes: %7d\tSize: %s\n",
254 v->name, gv_volstate(v->state), v->plexcount,
255 gv_roughlength(v->size, 0));
258 if (flags & GV_FLAG_VV) {
260 LIST_FOREACH(p, &v->plexes, in_volume) {
261 sbuf_printf(sb, "\t\tPlex %2d:\t%s\t(%s), %s\n", i,
262 p->name, gv_plexstate(p->state),
263 gv_roughlength(p->size, 0));
268 if (flags & GV_FLAG_R) {
269 LIST_FOREACH(p, &v->plexes, in_volume)
270 gv_lpi(p, sb, flags);
274 /* List one or more plexes. */
276 gv_lp(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
285 LIST_FOREACH(p, &sc->plexes, plex)
288 sbuf_printf(sb, "%d plex%s:\n", i, i == 1 ? "" : "es");
291 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
292 LIST_FOREACH(p, &sc->plexes, plex)
293 gv_lpi(p, sb, *flags);
297 /* List a single plex. */
299 gv_lpi(struct gv_plex *p, struct sbuf *sb, int flags)
304 if (flags & GV_FLAG_V) {
305 sbuf_printf(sb, "Plex %s:\tSize:\t%9jd bytes (%jd MB)\n",
306 p->name, (intmax_t)p->size, (intmax_t)p->size / MEGABYTE);
307 sbuf_printf(sb, "\t\tSubdisks: %8d\n", p->sdcount);
308 sbuf_printf(sb, "\t\tState: %s\n", gv_plexstate(p->state));
309 if ((p->flags & GV_PLEX_SYNCING) ||
310 (p->flags & GV_PLEX_GROWING) ||
311 (p->flags & GV_PLEX_REBUILDING)) {
312 sbuf_printf(sb, "\t\tSynced: ");
313 sbuf_printf(sb, "%16jd bytes (%d%%)\n",
315 (p->size > 0) ? (int)((p->synced * 100) / p->size) :
318 sbuf_printf(sb, "\t\tOrganization: %s", gv_plexorg(p->org));
319 if (gv_is_striped(p)) {
320 sbuf_printf(sb, "\tStripe size: %s\n",
321 gv_roughlength(p->stripesize, 1));
323 sbuf_printf(sb, "\t\tFlags: %d\n", p->flags);
324 if (p->vol_sc != NULL) {
325 sbuf_printf(sb, "\t\tPart of volume %s\n", p->volume);
328 sbuf_printf(sb, "P %-18s %2s State: ", p->name,
329 gv_plexorg_short(p->org));
330 if ((p->flags & GV_PLEX_SYNCING) ||
331 (p->flags & GV_PLEX_GROWING) ||
332 (p->flags & GV_PLEX_REBUILDING)) {
333 sbuf_printf(sb, "S %d%%\t", (int)((p->synced * 100) /
336 sbuf_printf(sb, "%s\t", gv_plexstate(p->state));
338 sbuf_printf(sb, "Subdisks: %5d\tSize: %s\n", p->sdcount,
339 gv_roughlength(p->size, 0));
342 if (flags & GV_FLAG_VV) {
344 LIST_FOREACH(s, &p->subdisks, in_plex) {
345 sbuf_printf(sb, "\t\tSubdisk %d:\t%s\n", i, s->name);
346 sbuf_printf(sb, "\t\t state: %s\tsize %11jd "
347 "(%jd MB)\n", gv_sdstate(s->state),
348 (intmax_t)s->size, (intmax_t)s->size / MEGABYTE);
349 if (p->org == GV_PLEX_CONCAT) {
350 sbuf_printf(sb, "\t\t\toffset %9jd (0x%jx)\n",
351 (intmax_t)s->plex_offset,
352 (intmax_t)s->plex_offset);
358 if (flags & GV_FLAG_R) {
359 LIST_FOREACH(s, &p->subdisks, in_plex)
360 gv_lsi(s, sb, flags);
364 /* List one or more subdisks. */
366 gv_ls(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
375 LIST_FOREACH(s, &sc->subdisks, sd)
378 sbuf_printf(sb, "%d subdisk%s:\n", i, i == 1 ? "" : "s");
381 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
382 LIST_FOREACH(s, &sc->subdisks, sd)
383 gv_lsi(s, sb, *flags);
387 /* List a single subdisk. */
389 gv_lsi(struct gv_sd *s, struct sbuf *sb, int flags)
391 if (flags & GV_FLAG_V) {
392 sbuf_printf(sb, "Subdisk %s:\n", s->name);
393 sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n",
394 (intmax_t)s->size, (intmax_t)s->size / MEGABYTE);
395 sbuf_printf(sb, "\t\tState: %s\n", gv_sdstate(s->state));
397 if (s->state == GV_SD_INITIALIZING ||
398 s->state == GV_SD_REVIVING) {
399 if (s->state == GV_SD_INITIALIZING)
400 sbuf_printf(sb, "\t\tInitialized: ");
402 sbuf_printf(sb, "\t\tRevived: ");
404 sbuf_printf(sb, "%16jd bytes (%d%%)\n",
405 (intmax_t)s->initialized,
406 (int)((s->initialized * 100) / s->size));
409 if (s->plex_sc != NULL) {
410 sbuf_printf(sb, "\t\tPlex %s at offset %jd (%s)\n",
411 s->plex, (intmax_t)s->plex_offset,
412 gv_roughlength(s->plex_offset, 1));
415 sbuf_printf(sb, "\t\tDrive %s (%s) at offset %jd (%s)\n",
417 s->drive_sc == NULL ? "*missing*" : s->drive_sc->name,
418 (intmax_t)s->drive_offset,
419 gv_roughlength(s->drive_offset, 1));
420 sbuf_printf(sb, "\t\tFlags: %d\n", s->flags);
422 sbuf_printf(sb, "S %-21s State: ", s->name);
423 if (s->state == GV_SD_INITIALIZING ||
424 s->state == GV_SD_REVIVING) {
425 if (s->state == GV_SD_INITIALIZING)
426 sbuf_printf(sb, "I ");
428 sbuf_printf(sb, "R ");
429 sbuf_printf(sb, "%d%%\t",
430 (int)((s->initialized * 100) / s->size));
432 sbuf_printf(sb, "%s\t", gv_sdstate(s->state));
434 sbuf_printf(sb, "D: %-12s Size: %s\n", s->drive,
435 gv_roughlength(s->size, 0));
439 /* List one or more drives. */
441 gv_ld(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
450 LIST_FOREACH(d, &sc->drives, drive)
453 sbuf_printf(sb, "%d drive%s:\n", i, i == 1 ? "" : "s");
456 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
457 LIST_FOREACH(d, &sc->drives, drive)
458 gv_ldi(d, sb, *flags);
462 /* List a single drive. */
464 gv_ldi(struct gv_drive *d, struct sbuf *sb, int flags)
466 struct gv_freelist *fl;
469 /* Verbose listing. */
470 if (flags & GV_FLAG_V) {
471 sbuf_printf(sb, "Drive %s:\tDevice %s\n", d->name, d->device);
472 sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n",
473 (intmax_t)d->size, (intmax_t)d->size / MEGABYTE);
474 sbuf_printf(sb, "\t\tUsed: %16jd bytes (%jd MB)\n",
475 (intmax_t)d->size - d->avail,
476 (intmax_t)(d->size - d->avail) / MEGABYTE);
477 sbuf_printf(sb, "\t\tAvailable: %11jd bytes (%jd MB)\n",
478 (intmax_t)d->avail, (intmax_t)d->avail / MEGABYTE);
479 sbuf_printf(sb, "\t\tState: %s\n", gv_drivestate(d->state));
480 sbuf_printf(sb, "\t\tFlags: %d\n", d->flags);
482 /* Be very verbose. */
483 if (flags & GV_FLAG_VV) {
484 sbuf_printf(sb, "\t\tFree list contains %d entries:\n",
485 d->freelist_entries);
486 sbuf_printf(sb, "\t\t Offset\t Size\n");
487 LIST_FOREACH(fl, &d->freelist, freelist)
488 sbuf_printf(sb, "\t\t%9jd\t%9jd\n",
489 (intmax_t)fl->offset, (intmax_t)fl->size);
492 sbuf_printf(sb, "D %-21s State: %s\t/dev/%s\tA: %jd/%jd MB "
493 "(%d%%)\n", d->name, gv_drivestate(d->state), d->device,
494 (intmax_t)d->avail / MEGABYTE, (intmax_t)d->size / MEGABYTE,
495 d->size > 0 ? (int)((d->avail * 100) / d->size) : 0);
498 /* Recursive listing. */
499 if (flags & GV_FLAG_R) {
500 LIST_FOREACH(s, &d->subdisks, from_drive)
501 gv_lsi(s, sb, flags);