1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2004, 2007 Lukas Ertl
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
15 *
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
26 * SUCH DAMAGE.
27 *
28 */
29
30 #include <sys/types.h>
31 #include <sys/libkern.h>
32 #include <sys/malloc.h>
33 #include <sys/sbuf.h>
34
35 #include <geom/geom.h>
36 #include <geom/vinum/geom_vinum_var.h>
37 #include <geom/vinum/geom_vinum.h>
38 #include <geom/vinum/geom_vinum_share.h>
39
40 void gv_lvi(struct gv_volume *, struct sbuf *, int);
41 void gv_lpi(struct gv_plex *, struct sbuf *, int);
42 void gv_lsi(struct gv_sd *, struct sbuf *, int);
43 void gv_ldi(struct gv_drive *, struct sbuf *, int);
44
45 void
gv_list(struct g_geom * gp,struct gctl_req * req)46 gv_list(struct g_geom *gp, struct gctl_req *req)
47 {
48 struct gv_softc *sc;
49 struct gv_drive *d;
50 struct gv_plex *p;
51 struct gv_sd *s;
52 struct gv_volume *v;
53 struct sbuf *sb;
54 int *argc, i, *flags, type;
55 char *arg, buf[20], *cmd;
56
57 argc = gctl_get_paraml(req, "argc", sizeof(*argc));
58
59 if (argc == NULL) {
60 gctl_error(req, "no arguments given");
61 return;
62 }
63
64 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
65 if (flags == NULL) {
66 gctl_error(req, "no flags given");
67 return;
68 }
69
70 sc = gp->softc;
71
72 sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN);
73
74 /* Figure out which command was given. */
75 cmd = gctl_get_param(req, "cmd", NULL);
76 if (cmd == NULL) {
77 gctl_error(req, "no command given");
78 return;
79 }
80
81 /* List specific objects or everything. */
82 if (!strcmp(cmd, "list") || !strcmp(cmd, "l")) {
83 if (*argc) {
84 for (i = 0; i < *argc; i++) {
85 snprintf(buf, sizeof(buf), "argv%d", i);
86 arg = gctl_get_param(req, buf, NULL);
87 if (arg == NULL)
88 continue;
89 type = gv_object_type(sc, arg);
90 switch (type) {
91 case GV_TYPE_VOL:
92 v = gv_find_vol(sc, arg);
93 gv_lvi(v, sb, *flags);
94 break;
95 case GV_TYPE_PLEX:
96 p = gv_find_plex(sc, arg);
97 gv_lpi(p, sb, *flags);
98 break;
99 case GV_TYPE_SD:
100 s = gv_find_sd(sc, arg);
101 gv_lsi(s, sb, *flags);
102 break;
103 case GV_TYPE_DRIVE:
104 d = gv_find_drive(sc, arg);
105 gv_ldi(d, sb, *flags);
106 break;
107 default:
108 gctl_error(req, "unknown object '%s'",
109 arg);
110 break;
111 }
112 }
113 } else {
114 gv_ld(gp, req, sb);
115 sbuf_printf(sb, "\n");
116 gv_lv(gp, req, sb);
117 sbuf_printf(sb, "\n");
118 gv_lp(gp, req, sb);
119 sbuf_printf(sb, "\n");
120 gv_ls(gp, req, sb);
121 }
122
123 /* List drives. */
124 } else if (!strcmp(cmd, "ld")) {
125 if (*argc) {
126 for (i = 0; i < *argc; i++) {
127 snprintf(buf, sizeof(buf), "argv%d", i);
128 arg = gctl_get_param(req, buf, NULL);
129 if (arg == NULL)
130 continue;
131 type = gv_object_type(sc, arg);
132 if (type != GV_TYPE_DRIVE) {
133 gctl_error(req, "'%s' is not a drive",
134 arg);
135 continue;
136 } else {
137 d = gv_find_drive(sc, arg);
138 gv_ldi(d, sb, *flags);
139 }
140 }
141 } else
142 gv_ld(gp, req, sb);
143
144 /* List volumes. */
145 } else if (!strcmp(cmd, "lv")) {
146 if (*argc) {
147 for (i = 0; i < *argc; i++) {
148 snprintf(buf, sizeof(buf), "argv%d", i);
149 arg = gctl_get_param(req, buf, NULL);
150 if (arg == NULL)
151 continue;
152 type = gv_object_type(sc, arg);
153 if (type != GV_TYPE_VOL) {
154 gctl_error(req, "'%s' is not a volume",
155 arg);
156 continue;
157 } else {
158 v = gv_find_vol(sc, arg);
159 gv_lvi(v, sb, *flags);
160 }
161 }
162 } else
163 gv_lv(gp, req, sb);
164
165 /* List plexes. */
166 } else if (!strcmp(cmd, "lp")) {
167 if (*argc) {
168 for (i = 0; i < *argc; i++) {
169 snprintf(buf, sizeof(buf), "argv%d", i);
170 arg = gctl_get_param(req, buf, NULL);
171 if (arg == NULL)
172 continue;
173 type = gv_object_type(sc, arg);
174 if (type != GV_TYPE_PLEX) {
175 gctl_error(req, "'%s' is not a plex",
176 arg);
177 continue;
178 } else {
179 p = gv_find_plex(sc, arg);
180 gv_lpi(p, sb, *flags);
181 }
182 }
183 } else
184 gv_lp(gp, req, sb);
185
186 /* List subdisks. */
187 } else if (!strcmp(cmd, "ls")) {
188 if (*argc) {
189 for (i = 0; i < *argc; i++) {
190 snprintf(buf, sizeof(buf), "argv%d", i);
191 arg = gctl_get_param(req, buf, NULL);
192 if (arg == NULL)
193 continue;
194 type = gv_object_type(sc, arg);
195 if (type != GV_TYPE_SD) {
196 gctl_error(req, "'%s' is not a subdisk",
197 arg);
198 continue;
199 } else {
200 s = gv_find_sd(sc, arg);
201 gv_lsi(s, sb, *flags);
202 }
203 }
204 } else
205 gv_ls(gp, req, sb);
206
207 } else
208 gctl_error(req, "unknown command '%s'", cmd);
209
210 sbuf_finish(sb);
211 gctl_set_param(req, "config", sbuf_data(sb), sbuf_len(sb) + 1);
212 sbuf_delete(sb);
213 }
214
215 /* List one or more volumes. */
216 void
gv_lv(struct g_geom * gp,struct gctl_req * req,struct sbuf * sb)217 gv_lv(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
218 {
219 struct gv_softc *sc;
220 struct gv_volume *v;
221 int i, *flags;
222
223 sc = gp->softc;
224 i = 0;
225
226 LIST_FOREACH(v, &sc->volumes, volume)
227 i++;
228
229 sbuf_printf(sb, "%d volume%s:\n", i, i == 1 ? "" : "s");
230
231 if (i) {
232 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
233 LIST_FOREACH(v, &sc->volumes, volume)
234 gv_lvi(v, sb, *flags);
235 }
236 }
237
238 /* List a single volume. */
239 void
gv_lvi(struct gv_volume * v,struct sbuf * sb,int flags)240 gv_lvi(struct gv_volume *v, struct sbuf *sb, int flags)
241 {
242 struct gv_plex *p;
243 int i;
244
245 if (flags & GV_FLAG_V) {
246 sbuf_printf(sb, "Volume %s:\tSize: %jd bytes (%jd MB)\n",
247 v->name, (intmax_t)v->size, (intmax_t)v->size / MEGABYTE);
248 sbuf_printf(sb, "\t\tState: %s\n", gv_volstate(v->state));
249 } else {
250 sbuf_printf(sb, "V %-21s State: %s\tPlexes: %7d\tSize: %s\n",
251 v->name, gv_volstate(v->state), v->plexcount,
252 gv_roughlength(v->size, 0));
253 }
254
255 if (flags & GV_FLAG_VV) {
256 i = 0;
257 LIST_FOREACH(p, &v->plexes, in_volume) {
258 sbuf_printf(sb, "\t\tPlex %2d:\t%s\t(%s), %s\n", i,
259 p->name, gv_plexstate(p->state),
260 gv_roughlength(p->size, 0));
261 i++;
262 }
263 }
264
265 if (flags & GV_FLAG_R) {
266 LIST_FOREACH(p, &v->plexes, in_volume)
267 gv_lpi(p, sb, flags);
268 }
269 }
270
271 /* List one or more plexes. */
272 void
gv_lp(struct g_geom * gp,struct gctl_req * req,struct sbuf * sb)273 gv_lp(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
274 {
275 struct gv_softc *sc;
276 struct gv_plex *p;
277 int i, *flags;
278
279 sc = gp->softc;
280 i = 0;
281
282 LIST_FOREACH(p, &sc->plexes, plex)
283 i++;
284
285 sbuf_printf(sb, "%d plex%s:\n", i, i == 1 ? "" : "es");
286
287 if (i) {
288 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
289 LIST_FOREACH(p, &sc->plexes, plex)
290 gv_lpi(p, sb, *flags);
291 }
292 }
293
294 /* List a single plex. */
295 void
gv_lpi(struct gv_plex * p,struct sbuf * sb,int flags)296 gv_lpi(struct gv_plex *p, struct sbuf *sb, int flags)
297 {
298 struct gv_sd *s;
299 int i;
300
301 if (flags & GV_FLAG_V) {
302 sbuf_printf(sb, "Plex %s:\tSize:\t%9jd bytes (%jd MB)\n",
303 p->name, (intmax_t)p->size, (intmax_t)p->size / MEGABYTE);
304 sbuf_printf(sb, "\t\tSubdisks: %8d\n", p->sdcount);
305 sbuf_printf(sb, "\t\tState: %s\n", gv_plexstate(p->state));
306 if ((p->flags & GV_PLEX_SYNCING) ||
307 (p->flags & GV_PLEX_GROWING) ||
308 (p->flags & GV_PLEX_REBUILDING)) {
309 sbuf_printf(sb, "\t\tSynced: ");
310 sbuf_printf(sb, "%16jd bytes (%d%%)\n",
311 (intmax_t)p->synced,
312 (p->size > 0) ? (int)((p->synced * 100) / p->size) :
313 0);
314 }
315 sbuf_printf(sb, "\t\tOrganization: %s", gv_plexorg(p->org));
316 if (gv_is_striped(p)) {
317 sbuf_printf(sb, "\tStripe size: %s\n",
318 gv_roughlength(p->stripesize, 1));
319 }
320 sbuf_printf(sb, "\t\tFlags: %d\n", p->flags);
321 if (p->vol_sc != NULL) {
322 sbuf_printf(sb, "\t\tPart of volume %s\n", p->volume);
323 }
324 } else {
325 sbuf_printf(sb, "P %-18s %2s State: ", p->name,
326 gv_plexorg_short(p->org));
327 if ((p->flags & GV_PLEX_SYNCING) ||
328 (p->flags & GV_PLEX_GROWING) ||
329 (p->flags & GV_PLEX_REBUILDING)) {
330 sbuf_printf(sb, "S %d%%\t", (int)((p->synced * 100) /
331 p->size));
332 } else {
333 sbuf_printf(sb, "%s\t", gv_plexstate(p->state));
334 }
335 sbuf_printf(sb, "Subdisks: %5d\tSize: %s\n", p->sdcount,
336 gv_roughlength(p->size, 0));
337 }
338
339 if (flags & GV_FLAG_VV) {
340 i = 0;
341 LIST_FOREACH(s, &p->subdisks, in_plex) {
342 sbuf_printf(sb, "\t\tSubdisk %d:\t%s\n", i, s->name);
343 sbuf_printf(sb, "\t\t state: %s\tsize %11jd "
344 "(%jd MB)\n", gv_sdstate(s->state),
345 (intmax_t)s->size, (intmax_t)s->size / MEGABYTE);
346 if (p->org == GV_PLEX_CONCAT) {
347 sbuf_printf(sb, "\t\t\toffset %9jd (0x%jx)\n",
348 (intmax_t)s->plex_offset,
349 (intmax_t)s->plex_offset);
350 }
351 i++;
352 }
353 }
354
355 if (flags & GV_FLAG_R) {
356 LIST_FOREACH(s, &p->subdisks, in_plex)
357 gv_lsi(s, sb, flags);
358 }
359 }
360
361 /* List one or more subdisks. */
362 void
gv_ls(struct g_geom * gp,struct gctl_req * req,struct sbuf * sb)363 gv_ls(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
364 {
365 struct gv_softc *sc;
366 struct gv_sd *s;
367 int i, *flags;
368
369 sc = gp->softc;
370 i = 0;
371
372 LIST_FOREACH(s, &sc->subdisks, sd)
373 i++;
374
375 sbuf_printf(sb, "%d subdisk%s:\n", i, i == 1 ? "" : "s");
376
377 if (i) {
378 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
379 LIST_FOREACH(s, &sc->subdisks, sd)
380 gv_lsi(s, sb, *flags);
381 }
382 }
383
384 /* List a single subdisk. */
385 void
gv_lsi(struct gv_sd * s,struct sbuf * sb,int flags)386 gv_lsi(struct gv_sd *s, struct sbuf *sb, int flags)
387 {
388 if (flags & GV_FLAG_V) {
389 sbuf_printf(sb, "Subdisk %s:\n", s->name);
390 sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n",
391 (intmax_t)s->size, (intmax_t)s->size / MEGABYTE);
392 sbuf_printf(sb, "\t\tState: %s\n", gv_sdstate(s->state));
393
394 if (s->state == GV_SD_INITIALIZING ||
395 s->state == GV_SD_REVIVING) {
396 if (s->state == GV_SD_INITIALIZING)
397 sbuf_printf(sb, "\t\tInitialized: ");
398 else
399 sbuf_printf(sb, "\t\tRevived: ");
400
401 sbuf_printf(sb, "%16jd bytes (%d%%)\n",
402 (intmax_t)s->initialized,
403 (int)((s->initialized * 100) / s->size));
404 }
405
406 if (s->plex_sc != NULL) {
407 sbuf_printf(sb, "\t\tPlex %s at offset %jd (%s)\n",
408 s->plex, (intmax_t)s->plex_offset,
409 gv_roughlength(s->plex_offset, 1));
410 }
411
412 sbuf_printf(sb, "\t\tDrive %s (%s) at offset %jd (%s)\n",
413 s->drive,
414 s->drive_sc == NULL ? "*missing*" : s->drive_sc->name,
415 (intmax_t)s->drive_offset,
416 gv_roughlength(s->drive_offset, 1));
417 sbuf_printf(sb, "\t\tFlags: %d\n", s->flags);
418 } else {
419 sbuf_printf(sb, "S %-21s State: ", s->name);
420 if (s->state == GV_SD_INITIALIZING ||
421 s->state == GV_SD_REVIVING) {
422 if (s->state == GV_SD_INITIALIZING)
423 sbuf_printf(sb, "I ");
424 else
425 sbuf_printf(sb, "R ");
426 sbuf_printf(sb, "%d%%\t",
427 (int)((s->initialized * 100) / s->size));
428 } else {
429 sbuf_printf(sb, "%s\t", gv_sdstate(s->state));
430 }
431 sbuf_printf(sb, "D: %-12s Size: %s\n", s->drive,
432 gv_roughlength(s->size, 0));
433 }
434 }
435
436 /* List one or more drives. */
437 void
gv_ld(struct g_geom * gp,struct gctl_req * req,struct sbuf * sb)438 gv_ld(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
439 {
440 struct gv_softc *sc;
441 struct gv_drive *d;
442 int i, *flags;
443
444 sc = gp->softc;
445 i = 0;
446
447 LIST_FOREACH(d, &sc->drives, drive)
448 i++;
449
450 sbuf_printf(sb, "%d drive%s:\n", i, i == 1 ? "" : "s");
451
452 if (i) {
453 flags = gctl_get_paraml(req, "flags", sizeof(*flags));
454 LIST_FOREACH(d, &sc->drives, drive)
455 gv_ldi(d, sb, *flags);
456 }
457 }
458
459 /* List a single drive. */
460 void
gv_ldi(struct gv_drive * d,struct sbuf * sb,int flags)461 gv_ldi(struct gv_drive *d, struct sbuf *sb, int flags)
462 {
463 struct gv_freelist *fl;
464 struct gv_sd *s;
465
466 /* Verbose listing. */
467 if (flags & GV_FLAG_V) {
468 sbuf_printf(sb, "Drive %s:\tDevice %s\n", d->name, d->device);
469 sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n",
470 (intmax_t)d->size, (intmax_t)d->size / MEGABYTE);
471 sbuf_printf(sb, "\t\tUsed: %16jd bytes (%jd MB)\n",
472 (intmax_t)d->size - d->avail,
473 (intmax_t)(d->size - d->avail) / MEGABYTE);
474 sbuf_printf(sb, "\t\tAvailable: %11jd bytes (%jd MB)\n",
475 (intmax_t)d->avail, (intmax_t)d->avail / MEGABYTE);
476 sbuf_printf(sb, "\t\tState: %s\n", gv_drivestate(d->state));
477 sbuf_printf(sb, "\t\tFlags: %d\n", d->flags);
478
479 /* Be very verbose. */
480 if (flags & GV_FLAG_VV) {
481 sbuf_printf(sb, "\t\tFree list contains %d entries:\n",
482 d->freelist_entries);
483 sbuf_printf(sb, "\t\t Offset\t Size\n");
484 LIST_FOREACH(fl, &d->freelist, freelist)
485 sbuf_printf(sb, "\t\t%9jd\t%9jd\n",
486 (intmax_t)fl->offset, (intmax_t)fl->size);
487 }
488 } else {
489 sbuf_printf(sb, "D %-21s State: %s\t/dev/%s\tA: %jd/%jd MB "
490 "(%d%%)\n", d->name, gv_drivestate(d->state), d->device,
491 (intmax_t)d->avail / MEGABYTE, (intmax_t)d->size / MEGABYTE,
492 d->size > 0 ? (int)((d->avail * 100) / d->size) : 0);
493 }
494
495 /* Recursive listing. */
496 if (flags & GV_FLAG_R) {
497 LIST_FOREACH(s, &d->subdisks, from_drive)
498 gv_lsi(s, sb, flags);
499 }
500 }
501