1 /*- 2 * Copyright (c) 2004 Lukas Ertl 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/libkern.h> 33 #include <sys/malloc.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 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 66 sc = gp->softc; 67 68 sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN); 69 70 /* Figure out which command was given. */ 71 cmd = gctl_get_param(req, "cmd", NULL); 72 73 /* List specific objects or everything. */ 74 if (!strcmp(cmd, "list") || !strcmp(cmd, "l")) { 75 if (*argc) { 76 for (i = 0; i < *argc; i++) { 77 snprintf(buf, sizeof(buf), "argv%d", i); 78 arg = gctl_get_param(req, buf, NULL); 79 if (arg == NULL) 80 continue; 81 type = gv_object_type(sc, arg); 82 switch (type) { 83 case GV_TYPE_VOL: 84 v = gv_find_vol(sc, arg); 85 gv_lvi(v, sb, *flags); 86 break; 87 case GV_TYPE_PLEX: 88 p = gv_find_plex(sc, arg); 89 gv_lpi(p, sb, *flags); 90 break; 91 case GV_TYPE_SD: 92 s = gv_find_sd(sc, arg); 93 gv_lsi(s, sb, *flags); 94 break; 95 case GV_TYPE_DRIVE: 96 d = gv_find_drive(sc, arg); 97 gv_ldi(d, sb, *flags); 98 break; 99 default: 100 gctl_error(req, "unknown object '%s'", 101 arg); 102 break; 103 } 104 } 105 } else { 106 gv_ld(gp, req, sb); 107 sbuf_printf(sb, "\n"); 108 gv_lv(gp, req, sb); 109 sbuf_printf(sb, "\n"); 110 gv_lp(gp, req, sb); 111 sbuf_printf(sb, "\n"); 112 gv_ls(gp, req, sb); 113 } 114 115 /* List drives. */ 116 } else if (!strcmp(cmd, "ld")) { 117 if (*argc) { 118 for (i = 0; i < *argc; i++) { 119 snprintf(buf, sizeof(buf), "argv%d", i); 120 arg = gctl_get_param(req, buf, NULL); 121 if (arg == NULL) 122 continue; 123 type = gv_object_type(sc, arg); 124 if (type != GV_TYPE_DRIVE) { 125 gctl_error(req, "'%s' is not a drive", 126 arg); 127 continue; 128 } else { 129 d = gv_find_drive(sc, arg); 130 gv_ldi(d, sb, *flags); 131 } 132 } 133 } else 134 gv_ld(gp, req, sb); 135 136 /* List volumes. */ 137 } else if (!strcmp(cmd, "lv")) { 138 if (*argc) { 139 for (i = 0; i < *argc; i++) { 140 snprintf(buf, sizeof(buf), "argv%d", i); 141 arg = gctl_get_param(req, buf, NULL); 142 if (arg == NULL) 143 continue; 144 type = gv_object_type(sc, arg); 145 if (type != GV_TYPE_VOL) { 146 gctl_error(req, "'%s' is not a volume", 147 arg); 148 continue; 149 } else { 150 v = gv_find_vol(sc, arg); 151 gv_lvi(v, sb, *flags); 152 } 153 } 154 } else 155 gv_lv(gp, req, sb); 156 157 /* List plexes. */ 158 } else if (!strcmp(cmd, "lp")) { 159 if (*argc) { 160 for (i = 0; i < *argc; i++) { 161 snprintf(buf, sizeof(buf), "argv%d", i); 162 arg = gctl_get_param(req, buf, NULL); 163 if (arg == NULL) 164 continue; 165 type = gv_object_type(sc, arg); 166 if (type != GV_TYPE_PLEX) { 167 gctl_error(req, "'%s' is not a plex", 168 arg); 169 continue; 170 } else { 171 p = gv_find_plex(sc, arg); 172 gv_lpi(p, sb, *flags); 173 } 174 } 175 } else 176 gv_lp(gp, req, sb); 177 178 /* List subdisks. */ 179 } else if (!strcmp(cmd, "ls")) { 180 if (*argc) { 181 for (i = 0; i < *argc; i++) { 182 snprintf(buf, sizeof(buf), "argv%d", i); 183 arg = gctl_get_param(req, buf, NULL); 184 if (arg == NULL) 185 continue; 186 type = gv_object_type(sc, arg); 187 if (type != GV_TYPE_SD) { 188 gctl_error(req, "'%s' is not a subdisk", 189 arg); 190 continue; 191 } else { 192 s = gv_find_sd(sc, arg); 193 gv_lsi(s, sb, *flags); 194 } 195 } 196 } else 197 gv_ls(gp, req, sb); 198 199 } else 200 gctl_error(req, "unknown command '%s'", cmd); 201 202 sbuf_finish(sb); 203 gctl_set_param(req, "config", sbuf_data(sb), sbuf_len(sb) + 1); 204 sbuf_delete(sb); 205 } 206 207 /* List one or more volumes. */ 208 void 209 gv_lv(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb) 210 { 211 struct gv_softc *sc; 212 struct gv_volume *v; 213 int i, *flags; 214 215 sc = gp->softc; 216 i = 0; 217 218 LIST_FOREACH(v, &sc->volumes, volume) 219 i++; 220 221 sbuf_printf(sb, "%d volume%s:\n", i, i == 1 ? "" : "s"); 222 223 if (i) { 224 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 225 LIST_FOREACH(v, &sc->volumes, volume) 226 gv_lvi(v, sb, *flags); 227 } 228 } 229 230 /* List a single volume. */ 231 void 232 gv_lvi(struct gv_volume *v, struct sbuf *sb, int flags) 233 { 234 struct gv_plex *p; 235 int i; 236 237 if (flags & GV_FLAG_V) { 238 sbuf_printf(sb, "Volume %s:\tSize: %jd bytes (%jd MB)\n", 239 v->name, (intmax_t)v->size, (intmax_t)v->size / MEGABYTE); 240 sbuf_printf(sb, "\t\tState: %s\n", gv_volstate(v->state)); 241 } else { 242 sbuf_printf(sb, "V %-21s State: %s\tPlexes: %7d\tSize: %s\n", 243 v->name, gv_volstate(v->state), v->plexcount, 244 gv_roughlength(v->size, 0)); 245 } 246 247 if (flags & GV_FLAG_VV) { 248 i = 0; 249 LIST_FOREACH(p, &v->plexes, in_volume) { 250 sbuf_printf(sb, "\t\tPlex %2d:\t%s\t(%s), %s\n", i, 251 p->name, gv_plexstate(p->state), 252 gv_roughlength(p->size, 0)); 253 i++; 254 } 255 } 256 257 if (flags & GV_FLAG_R) { 258 LIST_FOREACH(p, &v->plexes, in_volume) 259 gv_lpi(p, sb, flags); 260 } 261 } 262 263 /* List one or more plexes. */ 264 void 265 gv_lp(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb) 266 { 267 struct gv_softc *sc; 268 struct gv_plex *p; 269 int i, *flags; 270 271 sc = gp->softc; 272 i = 0; 273 274 LIST_FOREACH(p, &sc->plexes, plex) 275 i++; 276 277 sbuf_printf(sb, "%d plex%s:\n", i, i == 1 ? "" : "es"); 278 279 if (i) { 280 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 281 LIST_FOREACH(p, &sc->plexes, plex) 282 gv_lpi(p, sb, *flags); 283 } 284 } 285 286 /* List a single plex. */ 287 void 288 gv_lpi(struct gv_plex *p, struct sbuf *sb, int flags) 289 { 290 struct gv_sd *s; 291 int i; 292 293 if (flags & GV_FLAG_V) { 294 sbuf_printf(sb, "Plex %s:\tSize:\t%9jd bytes (%jd MB)\n", 295 p->name, (intmax_t)p->size, (intmax_t)p->size / MEGABYTE); 296 sbuf_printf(sb, "\t\tSubdisks: %8d\n", p->sdcount); 297 sbuf_printf(sb, "\t\tState: %s\n\t\tOrganization: %s", 298 gv_plexstate(p->state), gv_plexorg(p->org)); 299 if (gv_is_striped(p)) { 300 sbuf_printf(sb, "\tStripe size: %s\n", 301 gv_roughlength(p->stripesize, 1)); 302 } 303 if (p->vol_sc != NULL) { 304 sbuf_printf(sb, "\t\tPart of volume %s\n", p->volume); 305 } 306 } else { 307 sbuf_printf(sb, "P %-18s %2s State: %s\tSubdisks: %5d" 308 "\tSize: %s\n", p->name, gv_plexorg_short(p->org), 309 gv_plexstate(p->state), p->sdcount, 310 gv_roughlength(p->size, 0)); 311 } 312 313 if (flags & GV_FLAG_VV) { 314 i = 0; 315 LIST_FOREACH(s, &p->subdisks, in_plex) { 316 sbuf_printf(sb, "\t\tSubdisk %d:\t%s\n", i, s->name); 317 sbuf_printf(sb, "\t\t state: %s\tsize %11jd " 318 "(%jd MB)\n", gv_sdstate(s->state), 319 (intmax_t)s->size, (intmax_t)s->size / MEGABYTE); 320 if (p->org == GV_PLEX_CONCAT) { 321 sbuf_printf(sb, "\t\t\toffset %9jd (0x%jx)\n", 322 (intmax_t)s->plex_offset, 323 (intmax_t)s->plex_offset); 324 } 325 i++; 326 } 327 } 328 329 if (flags & GV_FLAG_R) { 330 LIST_FOREACH(s, &p->subdisks, in_plex) 331 gv_lsi(s, sb, flags); 332 } 333 } 334 335 /* List one or more subdisks. */ 336 void 337 gv_ls(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb) 338 { 339 struct gv_softc *sc; 340 struct gv_sd *s; 341 int i, *flags; 342 343 sc = gp->softc; 344 i = 0; 345 346 LIST_FOREACH(s, &sc->subdisks, sd) 347 i++; 348 349 sbuf_printf(sb, "%d subdisk%s:\n", i, i == 1 ? "" : "s"); 350 351 if (i) { 352 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 353 LIST_FOREACH(s, &sc->subdisks, sd) 354 gv_lsi(s, sb, *flags); 355 } 356 } 357 358 /* List a single subdisk. */ 359 void 360 gv_lsi(struct gv_sd *s, struct sbuf *sb, int flags) 361 { 362 if (flags & GV_FLAG_V) { 363 sbuf_printf(sb, "Subdisk %s:\n", s->name); 364 sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n", 365 (intmax_t)s->size, (intmax_t)s->size / MEGABYTE); 366 sbuf_printf(sb, "\t\tState: %s\n", gv_sdstate(s->state)); 367 368 if (s->state == GV_SD_INITIALIZING || 369 s->state == GV_SD_REVIVING) { 370 if (s->state == GV_SD_INITIALIZING) 371 sbuf_printf(sb, "\t\tInitialized: "); 372 else 373 sbuf_printf(sb, "\t\tRevived: "); 374 375 sbuf_printf(sb, "%16jd bytes (%d%%)\n", 376 (intmax_t)s->initialized, 377 (int)((s->initialized * 100) / s->size)); 378 } 379 380 if (s->plex_sc != NULL) { 381 sbuf_printf(sb, "\t\tPlex %s at offset %jd (%s)\n", 382 s->plex, (intmax_t)s->plex_offset, 383 gv_roughlength(s->plex_offset, 1)); 384 } 385 386 sbuf_printf(sb, "\t\tDrive %s (%s) at offset %jd (%s)\n", 387 s->drive, 388 s->drive_sc == NULL ? "*missing*" : s->drive_sc->name, 389 (intmax_t)s->drive_offset, 390 gv_roughlength(s->drive_offset, 1)); 391 } else { 392 sbuf_printf(sb, "S %-21s State: ", s->name); 393 if (s->state == GV_SD_INITIALIZING || 394 s->state == GV_SD_REVIVING) { 395 if (s->state == GV_SD_INITIALIZING) 396 sbuf_printf(sb, "I "); 397 else 398 sbuf_printf(sb, "R "); 399 sbuf_printf(sb, "%d%%\t", 400 (int)((s->initialized * 100) / s->size)); 401 } else { 402 sbuf_printf(sb, "%s\t", gv_sdstate(s->state)); 403 } 404 sbuf_printf(sb, "D: %-12s Size: %s\n", s->drive, 405 gv_roughlength(s->size, 0)); 406 } 407 } 408 409 /* List one or more drives. */ 410 void 411 gv_ld(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb) 412 { 413 struct gv_softc *sc; 414 struct gv_drive *d; 415 int i, *flags; 416 417 sc = gp->softc; 418 i = 0; 419 420 LIST_FOREACH(d, &sc->drives, drive) 421 i++; 422 423 sbuf_printf(sb, "%d drive%s:\n", i, i == 1 ? "" : "s"); 424 425 if (i) { 426 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 427 LIST_FOREACH(d, &sc->drives, drive) 428 gv_ldi(d, sb, *flags); 429 } 430 } 431 432 /* List a single drive. */ 433 void 434 gv_ldi(struct gv_drive *d, struct sbuf *sb, int flags) 435 { 436 struct gv_freelist *fl; 437 struct gv_sd *s; 438 439 /* Verbose listing. */ 440 if (flags & GV_FLAG_V) { 441 sbuf_printf(sb, "Drive %s:\tDevice %s\n", d->name, d->device); 442 sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n", 443 (intmax_t)d->size, (intmax_t)d->size / MEGABYTE); 444 sbuf_printf(sb, "\t\tUsed: %16jd bytes (%jd MB)\n", 445 (intmax_t)d->size - d->avail, 446 (intmax_t)(d->size - d->avail) / MEGABYTE); 447 sbuf_printf(sb, "\t\tAvailable: %11jd bytes (%jd MB)\n", 448 (intmax_t)d->avail, (intmax_t)d->avail / MEGABYTE); 449 sbuf_printf(sb, "\t\tState: %s\n", gv_drivestate(d->state)); 450 451 /* Be very verbose. */ 452 if (flags & GV_FLAG_VV) { 453 sbuf_printf(sb, "\t\tFree list contains %d entries:\n", 454 d->freelist_entries); 455 sbuf_printf(sb, "\t\t Offset\t Size\n"); 456 LIST_FOREACH(fl, &d->freelist, freelist) 457 sbuf_printf(sb, "\t\t%9jd\t%9jd\n", 458 (intmax_t)fl->offset, (intmax_t)fl->size); 459 } 460 } else { 461 sbuf_printf(sb, "D %-21s State: %s\t/dev/%s\tA: %jd/%jd MB " 462 "(%d%%)\n", d->name, gv_drivestate(d->state), d->device, 463 (intmax_t)d->avail / MEGABYTE, (intmax_t)d->size / MEGABYTE, 464 (int)((d->avail * 100) / d->size)); 465 } 466 467 /* Recursive listing. */ 468 if (flags & GV_FLAG_R) { 469 LIST_FOREACH(s, &d->subdisks, from_drive) 470 gv_lsi(s, sb, flags); 471 } 472 } 473