1 /* list.c: vinum interface program, list routines 2 */ 3 /*- 4 * Copyright (c) 1997, 1998 5 * Nan Yang Computer Services Limited. All rights reserved. 6 * 7 * Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project. 8 * 9 * Written by Greg Lehey 10 * 11 * This software is distributed under the so-called ``Berkeley 12 * License'': 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. Neither the name of the Company nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * This software is provided ``as is'', and any express or implied 27 * warranties, including, but not limited to, the implied warranties of 28 * merchantability and fitness for a particular purpose are disclaimed. 29 * In no event shall the company or contributors be liable for any 30 * direct, indirect, incidental, special, exemplary, or consequential 31 * damages (including, but not limited to, procurement of substitute 32 * goods or services; loss of use, data, or profits; or business 33 * interruption) however caused and on any theory of liability, whether 34 * in contract, strict liability, or tort (including negligence or 35 * otherwise) arising in any way out of the use of this software, even if 36 * advised of the possibility of such damage. 37 * 38 * $Id: list.c,v 1.25 2000/12/20 03:38:43 grog Exp grog $ 39 * $FreeBSD: src/sbin/vinum/list.c,v 1.25.2.4 2001/05/28 05:58:04 grog Exp $ 40 * $DragonFly: src/sbin/vinum/list.c,v 1.10 2007/06/18 05:13:41 dillon Exp $ 41 */ 42 43 #define _KERNEL_STRUCTURES 44 45 #include <ctype.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <sys/mman.h> 49 #include <netdb.h> 50 #include <setjmp.h> 51 #include <signal.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 #include <sys/ioctl.h> 57 #include <sys/utsname.h> 58 #include <sys/disklabel32.h> 59 #include <dev/raid/vinum/vinumhdr.h> 60 #include "vext.h" 61 #include <dev/raid/vinum/request.h> 62 #include <devstat.h> 63 64 /* 65 * When a subdisk is reviving or initializing, we 66 * check to see whether it is still progressing 67 * and print a warning if not. We check every 50 68 * ms, up to a maximum of 5 seconds. This is the 69 * counter value. 70 */ 71 #define STALLCOUNT 100 72 73 /* 74 * Take a size in sectors and return a pointer to 75 * a string which represents the size best. If lj 76 * is != 0, return left justified, otherwise in a 77 * fixed 10 character field suitable for columnar 78 * printing. 79 * 80 * Note this uses a static string: it's only 81 * intended to be used immediately for printing. 82 */ 83 char * 84 roughlength(int64_t bytes, int lj) 85 { 86 static char description[16]; 87 88 if (bytes > (int64_t) MEGABYTE * 10000) /* gigabytes */ 89 sprintf(description, lj ? "%lld GB" : "%10lld GB", 90 (long long)bytes / GIGABYTE); 91 else if (bytes > KILOBYTE * 10000) /* megabytes */ 92 sprintf(description, lj ? "%lld MB" : "%10lld MB", 93 (long long)bytes / MEGABYTE); 94 else if (bytes > 10000) /* kilobytes */ 95 sprintf(description, lj ? "%lld kB" : "%10lld kB", 96 (long long)bytes / KILOBYTE); 97 else /* bytes */ 98 sprintf(description, lj ? "%lld B" : "%10lld B", 99 (long long)bytes); 100 return description; 101 } 102 103 void 104 vinum_list(int argc, char *argv[], char *argv0[]) 105 { 106 int object; 107 int i; 108 enum objecttype type; 109 110 if (sflag & (!vflag)) /* just summary stats, */ 111 printf("Object\t\t Reads\t\tBytes\tAverage\tRecover\t Writes" 112 "\t\tBytes\tAverage\t Mblock Mstripe\n\n"); 113 if (argc == 0) 114 listconfig(); /* list everything */ 115 else { 116 for (i = 0; i < argc; i++) { 117 object = find_object(argv[i], &type); /* look for it */ 118 if (vinum_li(object, type)) 119 fprintf(stderr, "Can't find object: %s\n", argv[i]); 120 } 121 } 122 } 123 124 /* List an object */ 125 int 126 vinum_li(int object, enum objecttype type) 127 { 128 switch (type) { 129 case drive_object: 130 vinum_ldi(object, recurse); 131 break; 132 133 case sd_object: 134 vinum_lsi(object, recurse); 135 break; 136 137 case plex_object: 138 vinum_lpi(object, recurse); 139 break; 140 141 case volume_object: 142 vinum_lvi(object, recurse); 143 break; 144 145 default: 146 return -1; 147 } 148 return 0; 149 } 150 151 void 152 vinum_ldi(int driveno, int recurse) 153 { 154 time_t t; /* because Bruce says so */ 155 int sdno; /* for recursion */ 156 157 get_drive_info(&drive, driveno); 158 if (drive.state != drive_unallocated) { 159 if (vflag) { 160 printf("Drive %s:\tDevice %s\n", 161 drive.label.name, 162 drive.devicename); 163 t = drive.label.date_of_birth.tv_sec; 164 printf("\t\tCreated on %s at %s", 165 drive.label.sysname, 166 ctime(&t)); 167 t = drive.label.last_update.tv_sec; 168 printf("\t\tConfig last updated %s", /* care: \n at end */ 169 ctime(&t)); 170 printf("\t\tSize: %16lld bytes (%lld MB)\n\t\tUsed: %16lld bytes (%lld MB)\n" 171 "\t\tAvailable: %11qd bytes (%d MB)\n", 172 (long long) drive.label.drive_size, /* bytes used */ 173 (long long) (drive.label.drive_size / MEGABYTE), 174 (long long) (drive.label.drive_size - drive.sectors_available 175 * DEV_BSIZE), 176 (long long) (drive.label.drive_size - drive.sectors_available 177 * DEV_BSIZE) / MEGABYTE, 178 (long long) drive.sectors_available * DEV_BSIZE, 179 (int) (drive.sectors_available * DEV_BSIZE / MEGABYTE)); 180 printf("\t\tState: %s\n", drive_state(drive.state)); 181 if (drive.lasterror != 0) 182 printf("\t\tLast error: %s\n", strerror(drive.lasterror)); 183 else 184 printf("\t\tLast error: none\n"); 185 printf("\t\tActive requests:\t%d\n\t\tMaximum active:\t\t%d\n", 186 drive.active, 187 drive.maxactive); 188 if (Verbose) { /* print the free list */ 189 int fe; /* freelist entry */ 190 union freeunion { 191 struct drive_freelist freelist; 192 struct ferq { /* request to pass to ioctl */ 193 int driveno; 194 int fe; 195 } ferq; 196 } freeunion; 197 198 printf("\t\tFree list contains %d entries:\n\t\t Offset\t Size\n", 199 drive.freelist_entries); 200 for (fe = 0; fe < drive.freelist_entries; fe++) { 201 freeunion.ferq.driveno = drive.driveno; 202 freeunion.ferq.fe = fe; 203 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) { 204 fprintf(stderr, 205 "Can't get free list element %d: %s\n", 206 fe, 207 strerror(errno)); 208 longjmp(command_fail, -1); 209 } 210 printf("\t\t%9lld\t%9lld\n", 211 (long long) freeunion.freelist.offset, 212 (long long) freeunion.freelist.sectors); 213 } 214 } 215 } else if (!sflag) { 216 printf("D %-21s State: %s\tDevice %s\tAvail: %lld/%lld MB", 217 drive.label.name, 218 drive_state(drive.state), 219 drive.devicename, 220 (long long) drive.sectors_available * DEV_BSIZE / MEGABYTE, 221 (long long) (drive.label.drive_size / MEGABYTE)); 222 if (drive.label.drive_size != 0) 223 printf(" (%d%%)", 224 (int) ((drive.sectors_available * 100 * DEV_BSIZE) 225 / (drive.label.drive_size - (DATASTART * DEV_BSIZE)))); 226 } 227 if (sflag) { 228 if (vflag || Verbose) { 229 printf("\t\tReads: \t%16lld\n\t\tBytes read:\t%16lld (%s)\n", 230 (long long) drive.reads, 231 (long long) drive.bytes_read, 232 roughlength(drive.bytes_read, 1)); 233 if (drive.reads != 0) 234 printf("\t\tAverage read:\t%16lld bytes\n", 235 (long long) drive.bytes_read / drive.reads); 236 printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n", 237 (long long) drive.writes, 238 (long long) drive.bytes_written, 239 roughlength(drive.bytes_written, 1)); 240 if (drive.writes != 0) 241 printf("\t\tAverage write:\t%16lld bytes\n", 242 (long long) (drive.bytes_written / drive.writes)); 243 } else { /* non-verbose stats */ 244 printf("%-15s\t%7lld\t%15lld\t", 245 drive.label.name, 246 (long long) drive.reads, 247 (long long) drive.bytes_read); 248 if (drive.reads != 0) 249 printf("%7lld\t\t", 250 (long long) (drive.bytes_read / drive.reads)); 251 else 252 printf("\t\t"); 253 printf("%7lld\t%15lld\t", 254 (long long) drive.writes, 255 (long long) drive.bytes_written); 256 if (drive.writes != 0) 257 printf("%7lld", 258 (long long) (drive.bytes_written / drive.writes)); 259 } 260 } 261 if (recurse) { 262 printf("\n"); 263 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) { 264 get_sd_info(&sd, sdno); 265 if ((sd.state != sd_unallocated) 266 && (sd.driveno == drive.driveno)) 267 vinum_lsi(sd.sdno, 0); 268 } 269 } 270 printf("\n"); 271 } 272 } 273 274 void 275 vinum_ld(int argc, char *argv[], char *argv0[]) 276 { 277 int i; 278 int driveno; 279 enum objecttype type; 280 281 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 282 perror("Can't get vinum config"); 283 return; 284 } 285 if (argc == 0) { 286 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) 287 vinum_ldi(driveno, recurse); 288 } else { 289 for (i = 0; i < argc; i++) { 290 driveno = find_object(argv[i], &type); 291 if (type == drive_object) 292 vinum_ldi(driveno, recurse); 293 else 294 fprintf(stderr, "%s is not a drive\n", argv[i]); 295 } 296 } 297 } 298 299 void 300 vinum_lvi(int volno, int recurse) 301 { 302 get_volume_info(&vol, volno); 303 if (vol.state != volume_unallocated) { 304 if (vflag) { 305 printf("Volume %s:\tSize: %lld bytes (%lld MB)\n" 306 "\t\tState: %s\n\t\tFlags: %s%s%s\n", 307 vol.name, 308 ((long long) vol.size) * DEV_BSIZE, 309 ((long long) vol.size) * DEV_BSIZE / MEGABYTE, 310 volume_state(vol.state), 311 vol.flags & VF_OPEN ? "open " : "", 312 (vol.flags & VF_WRITETHROUGH ? "writethrough " : ""), 313 (vol.flags & VF_RAW ? "raw" : "")); 314 printf("\t\t%d plexes\n\t\tRead policy: ", vol.plexes); 315 if (vol.preferred_plex < 0) /* round robin */ 316 printf("round robin\n"); 317 else { 318 get_plex_info(&plex, vol.plex[vol.preferred_plex]); 319 printf("plex %d (%s)\n", vol.preferred_plex, plex.name); 320 } 321 } else if (!sflag) /* brief */ 322 printf("V %-21s State: %s\tPlexes: %7d\tSize: %s\n", 323 vol.name, 324 volume_state(vol.state), 325 vol.plexes, 326 roughlength(vol.size << DEV_BSHIFT, 0)); 327 if (sflag) { 328 if (vflag || Verbose) { 329 printf("\t\tReads: \t%16lld\n\t\tRecovered:\t%16lld\n\t\tBytes read:\t%16lld (%s)\n", 330 (long long) vol.reads, 331 (long long) vol.recovered_reads, 332 (long long) vol.bytes_read, 333 roughlength(vol.bytes_read, 1)); 334 if (vol.reads != 0) 335 printf("\t\tAverage read:\t%16lld bytes\n", 336 (long long) (vol.bytes_read / vol.reads)); 337 printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n", 338 (long long) vol.writes, 339 (long long) vol.bytes_written, 340 roughlength(vol.bytes_written, 1)); 341 if (vol.writes != 0) 342 printf("\t\tAverage write:\t%16lld bytes\n", 343 (long long) (vol.bytes_written / vol.writes)); 344 printf("\t\tActive requests:\t%8d\n", vol.active); 345 } else { /* brief stats listing */ 346 printf("%-15s\t%7lld\t%15lld\t", 347 vol.name, 348 (long long) vol.reads, 349 (long long) vol.bytes_read); 350 if (vol.reads != 0) 351 printf("%7lld\t", 352 (long long) (vol.bytes_read / vol.reads)); 353 else 354 printf("\t"); 355 printf("%7lld\t", (long long) vol.recovered_reads); 356 printf("%7lld\t%15lld\t", 357 (long long)vol.writes, 358 (long long)vol.bytes_written); 359 if (vol.writes != 0) 360 printf("%7lld\n", 361 (long long) (vol.bytes_written / vol.writes)); 362 else 363 printf("\n"); 364 } 365 } 366 if (vol.plexes > 0) { 367 int plexno; 368 if (Verbose) { /* brief list */ 369 for (plexno = 0; plexno < vol.plexes; plexno++) { 370 get_plex_info(&plex, vol.plex[plexno]); 371 /* Just a brief summary here */ 372 printf("\t\tPlex %2d:\t%s\t(%s), %s\n", 373 plexno, 374 plex.name, 375 plex_org(plex.organization), 376 roughlength(plex.length << DEV_BSHIFT, 0)); 377 } 378 } 379 if (recurse) { 380 for (plexno = 0; plexno < vol.plexes; plexno++) 381 vinum_lpi(vol.plex[plexno], 0); /* first show the plexes */ 382 for (plexno = 0; plexno < vol.plexes; plexno++) { /* then the subdisks */ 383 get_plex_info(&plex, vol.plex[plexno]); 384 if (plex.subdisks > 0) { 385 int sdno; 386 387 for (sdno = 0; sdno < plex.subdisks; sdno++) { 388 get_plex_sd_info(&sd, vol.plex[plexno], sdno); 389 vinum_lsi(sd.sdno, 0); 390 } 391 } 392 } 393 printf("\n"); 394 } 395 } 396 } 397 } 398 399 void 400 vinum_lv(int argc, char *argv[], char *argv0[]) 401 { 402 int i; 403 int volno; 404 enum objecttype type; 405 406 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 407 perror("Can't get vinum config"); 408 return; 409 } 410 if (argc == 0) 411 for (volno = 0; volno < vinum_conf.volumes_allocated; volno++) 412 vinum_lvi(volno, recurse); 413 else { 414 for (i = 0; i < argc; i++) { 415 volno = find_object(argv[i], &type); 416 if (type == volume_object) 417 vinum_lvi(volno, recurse); 418 else 419 fprintf(stderr, "%s is not a volume\n", argv[i]); 420 } 421 } 422 } 423 424 void 425 vinum_lpi(int plexno, int recurse) 426 { 427 get_plex_info(&plex, plexno); 428 if (plex.state != plex_unallocated) { 429 if (vflag) { 430 printf("Plex %s:\tSize:\t%9lld bytes (%lld MB)\n\t\tSubdisks: %8d\n", 431 plex.name, 432 (long long) plex.length * DEV_BSIZE, 433 (long long) plex.length * DEV_BSIZE / MEGABYTE, 434 plex.subdisks); 435 printf("\t\tState: %s\n\t\tOrganization: %s", 436 plex_state(plex.state), 437 plex_org(plex.organization)); 438 if (isstriped((&plex))) 439 printf("\tStripe size: %s\n", roughlength(plex.stripesize * DEV_BSIZE, 1)); 440 else 441 printf("\n"); 442 if ((isparity((&plex))) 443 && (plex.checkblock != 0)) 444 printf("\t\tCheck block pointer:\t\t%s (%d%%)\n", 445 roughlength((plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1), 0), 446 (int) (((u_int64_t) (plex.checkblock * 100)) * (plex.subdisks - 1) / plex.length)); 447 if (plex.volno >= 0) { 448 get_volume_info(&vol, plex.volno); 449 printf("\t\tPart of volume %s\n", vol.name); 450 } 451 } else if (!sflag) { /* non-verbose list */ 452 char *org = ""; /* organization */ 453 454 switch (plex.organization) { 455 case plex_disorg: /* disorganized */ 456 org = "??"; 457 break; 458 case plex_concat: /* concatenated plex */ 459 org = "C"; 460 break; 461 case plex_striped: /* striped plex */ 462 org = "S"; 463 break; 464 case plex_raid4: /* RAID4 plex */ 465 org = "R4"; 466 break; 467 case plex_raid5: /* RAID5 plex */ 468 org = "R5"; 469 break; 470 } 471 printf("P %-18s %2s State: %s\tSubdisks: %5d\tSize: %s", 472 plex.name, 473 org, 474 plex_state(plex.state), 475 plex.subdisks, 476 roughlength(plex.length << DEV_BSHIFT, 0)); 477 } 478 if (sflag) { 479 if (vflag || Verbose) { 480 printf("\t\tReads: \t%16lld\n\t\tBytes read:\t%16lld (%s)\n", 481 (long long) plex.reads, 482 (long long) plex.bytes_read, 483 roughlength(plex.bytes_read, 1)); 484 if (plex.reads != 0) 485 printf("\t\tAverage read:\t%16lld bytes\n", 486 (long long) (plex.bytes_read / plex.reads)); 487 printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n", 488 (long long) plex.writes, 489 (long long) plex.bytes_written, 490 roughlength(plex.bytes_written, 1)); 491 if (plex.writes != 0) 492 printf("\t\tAverage write:\t%16lld bytes\n", 493 (long long) (plex.bytes_written / plex.writes)); 494 if (((plex.reads + plex.writes) > 0) 495 && isstriped((&plex))) 496 printf("\t\tMultiblock:\t%16lld (%d%%)\n" 497 "\t\tMultistripe:\t%16lld (%d%%)\n", 498 (long long) plex.multiblock, 499 (int) (plex.multiblock * 100 / (plex.reads + plex.writes)), 500 (long long) plex.multistripe, 501 (int) (plex.multistripe * 100 / (plex.reads + plex.writes))); 502 if (plex.recovered_reads) 503 printf("\t\tRecovered reads:%16lld\n", 504 (long long) plex.recovered_reads); 505 if (plex.degraded_writes) 506 printf("\t\tDegraded writes:%16lld\n", 507 (long long) plex.degraded_writes); 508 if (plex.parityless_writes) 509 printf("\t\tParityless writes:%14lld\n", 510 (long long) plex.parityless_writes); 511 } else { 512 printf("%-15s\t%7lld\t%15lld\t", 513 plex.name, 514 (long long) plex.reads, 515 (long long) plex.bytes_read); 516 if (plex.reads != 0) 517 printf("%7lld\t", 518 (long long) (plex.bytes_read / plex.reads)); 519 else 520 printf("\t"); 521 printf("%7lld\t", (long long) plex.recovered_reads); 522 printf("%7lld\t%15lld\t", 523 (long long) plex.writes, 524 (long long) plex.bytes_written); 525 if (plex.writes != 0) 526 printf("%7lld\t", 527 (long long) (plex.bytes_written / plex.writes)); 528 else 529 printf("\t"); 530 printf("%7lld\t%7lld\n", 531 (long long) plex.multiblock, 532 (long long) plex.multistripe); 533 } 534 } 535 if (plex.subdisks > 0) { 536 int sdno; 537 538 if (Verbose) { 539 printf("\n"); 540 for (sdno = 0; sdno < plex.subdisks; sdno++) { 541 get_plex_sd_info(&sd, plexno, sdno); 542 printf("\t\tSubdisk %d:\t%s\n\t\t state: %s\tsize %11lld (%lld MB)\n", 543 sdno, 544 sd.name, 545 sd_state(sd.state), 546 (long long) sd.sectors * DEV_BSIZE, 547 (long long) sd.sectors * DEV_BSIZE / MEGABYTE); 548 if (plex.organization == plex_concat) 549 printf("\t\t\toffset %9ld (0x%lx)\n", 550 (long) sd.plexoffset, 551 (long) sd.plexoffset); 552 } 553 } 554 if (recurse) { 555 printf("\n"); 556 for (sdno = 0; sdno < plex.subdisks; sdno++) { 557 get_plex_sd_info(&sd, plexno, sdno); 558 vinum_lsi(sd.sdno, 0); 559 } 560 } 561 } 562 printf("\n"); 563 } 564 } 565 566 void 567 vinum_lp(int argc, char *argv[], char *argv0[]) 568 { 569 int i; 570 int plexno; 571 enum objecttype type; 572 573 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 574 perror("Can't get vinum config"); 575 return; 576 } 577 if (argc == 0) { 578 for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++) 579 vinum_lpi(plexno, recurse); 580 } else { 581 for (i = 0; i < argc; i++) { 582 plexno = find_object(argv[i], &type); 583 if (type == plex_object) 584 vinum_lpi(plexno, recurse); 585 else 586 fprintf(stderr, "%s is not a plex\n", argv[i]); 587 } 588 } 589 } 590 591 void 592 vinum_lsi(int sdno, int recurse) 593 { 594 long long revived; /* keep an eye on revive progress */ 595 int times; 596 597 get_sd_info(&sd, sdno); 598 if (sd.state != sd_unallocated) { 599 if (vflag) { 600 printf("Subdisk %s:\n\t\tSize: %16lld bytes (%lld MB)\n\t\tState: %s\n", 601 sd.name, 602 (long long) sd.sectors * DEV_BSIZE, 603 (long long) sd.sectors / (MEGABYTE / DEV_BSIZE), 604 sd_state(sd.state)); 605 if (sd.flags & VF_RETRYERRORS) 606 printf("\t\tretryerrors\n"); 607 if (sd.plexno >= 0) { 608 get_plex_info(&plex, sd.plexno); 609 printf("\t\tPlex %s", plex.name); 610 printf(" at offset %lld (%s)\n", 611 (long long) sd.plexoffset * DEV_BSIZE, 612 roughlength((long long) sd.plexoffset * DEV_BSIZE, 1)); 613 } 614 if (sd.state == sd_reviving) { 615 if (sd.reviver == 0) 616 printf("\t\t*** Start subdisk with 'start' command ***\n"); 617 else { 618 printf("\t\tReviver PID:\t%d\n", sd.reviver); 619 if (kill(sd.reviver, 0) == -1) { 620 if (errno == ESRCH) /* no process */ 621 printf("\t\t*** Revive process has died ***\n"); 622 /* Don't report a problem that "can't happen" */ 623 } else { 624 revived = sd.revived; /* note how far we were */ 625 626 /* 627 * Wait for up to a second until we 628 * see some progress with the revive. 629 * Do it like this so we don't have 630 * annoying delays in the listing. 631 */ 632 for (times = 0; times < STALLCOUNT; times++) { 633 get_sd_info(&sd, sdno); 634 if (sd.revived != revived) /* progress? */ 635 break; 636 usleep(50000); 637 } 638 if (times == STALLCOUNT) 639 printf("\t\t*** Revive has stalled ***\n"); 640 } 641 } 642 printf("\t\tRevive pointer:\t\t%s (%d%%)\n", 643 roughlength(sd.revived << DEV_BSHIFT, 0), 644 (int) (((u_int64_t) (sd.revived * 100)) / sd.sectors)); 645 printf("\t\tRevive blocksize:\t%s\n" 646 "\t\tRevive interval:\t%10d seconds\n", 647 roughlength(sd.revive_blocksize, 0), 648 sd.revive_interval); 649 } 650 if (sd.state == sd_initializing) { 651 printf("\t\tInitialize pointer:\t%s (%d%%)\n", 652 roughlength(sd.initialized << DEV_BSHIFT, 0), 653 (int) (((u_int64_t) (sd.initialized * 100)) / sd.sectors)); 654 printf("\t\tInitialize blocksize:\t%s\n" 655 "\t\tInitialize interval:\t%10d seconds\n", 656 roughlength(sd.init_blocksize, 0), 657 sd.init_interval); 658 } 659 get_drive_info(&drive, sd.driveno); 660 if (sd.driveoffset < 0) 661 printf("\t\tDrive %s (%s), no offset\n", 662 drive.label.name, 663 drive.devicename); 664 else if (drive.devicename[0] != '\0') /* has a name */ 665 printf("\t\tDrive %s (%s) at offset %lld (%s)\n", 666 drive.label.name, 667 drive.devicename, 668 (long long) (sd.driveoffset * DEV_BSIZE), 669 roughlength(sd.driveoffset * DEV_BSIZE, 1)); 670 else 671 printf("\t\tDrive %s (*missing*) at offset %lld (%s)\n", 672 drive.label.name, 673 (long long) (sd.driveoffset * DEV_BSIZE), 674 roughlength(sd.driveoffset * DEV_BSIZE, 1)); 675 } else if (!sflag) { /* brief listing, no stats */ 676 if (sd.state == sd_reviving) 677 printf("S %-21s State: R %d%%\t", 678 sd.name, 679 (int) (((u_int64_t) (sd.revived * 100)) / sd.sectors)); 680 else if (sd.state == sd_initializing) 681 printf("S %-21s State: I %d%%\t", 682 sd.name, 683 (int) (((u_int64_t) (sd.initialized * 100)) / sd.sectors)); 684 else 685 printf("S %-21s State: %s\t", 686 sd.name, 687 sd_state(sd.state)); 688 if (sd.plexno == -1) 689 printf("(detached)\t"); 690 else 691 printf("PO: %s ", 692 &(roughlength(sd.plexoffset << DEV_BSHIFT, 0))[2]); /* what a kludge! */ 693 printf("Size: %s\n", 694 roughlength(sd.sectors << DEV_BSHIFT, 0)); 695 if (sd.state == sd_reviving) { 696 if (sd.reviver == 0) 697 printf("\t\t\t*** Start %s with 'start' command ***\n", 698 sd.name); 699 else if (kill(sd.reviver, 0) == -1) { 700 if (errno == ESRCH) /* no process */ 701 printf("\t\t\t*** Revive process for %s has died ***\n", 702 sd.name); 703 /* Don't report a problem that "can't happen" */ 704 } else { 705 revived = sd.revived; /* note how far we were */ 706 707 /* 708 * Wait for up to a second until we 709 * see some progress with the revive. 710 * Do it like this so we don't have 711 * annoying delays in the listing. 712 */ 713 for (times = 0; times < STALLCOUNT; times++) { 714 get_sd_info(&sd, sdno); 715 if (sd.revived != revived) /* progress? */ 716 break; 717 usleep(50000); 718 } 719 if (times == STALLCOUNT) 720 printf("\t\t\t*** Revive of %s has stalled ***\n", 721 sd.name); 722 } 723 } 724 } 725 if (sflag) { 726 if (vflag || Verbose) { 727 printf("\t\tReads: \t%16lld\n\t\tBytes read:\t%16lld (%s)\n", 728 (long long) sd.reads, 729 (long long) sd.bytes_read, 730 roughlength(sd.bytes_read, 1)); 731 if (sd.reads != 0) 732 printf("\t\tAverage read:\t%16lld bytes\n", 733 (long long) (sd.bytes_read / sd.reads)); 734 printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n", 735 (long long) sd.writes, 736 (long long) sd.bytes_written, 737 roughlength(sd.bytes_written, 1)); 738 if (sd.writes != 0) 739 printf("\t\tAverage write:\t%16lld bytes\n", 740 (long long) (sd.bytes_written / sd.writes)); 741 } else { 742 printf("%-15s\t%7lld\t%15lld\t", 743 sd.name, 744 (long long) sd.reads, 745 (long long) sd.bytes_read); 746 if (sd.reads != 0) 747 printf("%7lld\t\t", 748 (long long) (sd.bytes_read / sd.reads)); 749 else 750 printf("\t\t"); 751 printf("%7lld\t%15lld\t", 752 (long long) sd.writes, 753 (long long) sd.bytes_written); 754 if (sd.writes != 0) 755 printf("%7lld\n", 756 (long long) (sd.bytes_written / sd.writes)); 757 else 758 printf("\n"); 759 } 760 } 761 if (recurse) 762 vinum_ldi(sd.driveno, 0); 763 if (vflag) 764 printf("\n"); /* make it more readable */ 765 } 766 } 767 768 void 769 vinum_ls(int argc, char *argv[], char *argv0[]) 770 { 771 int i; 772 int sdno; 773 774 /* Structures to read kernel data into */ 775 struct _vinum_conf vinum_conf; 776 enum objecttype type; 777 778 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 779 perror("Can't get vinum config"); 780 return; 781 } 782 if (argc == 0) { 783 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) 784 vinum_lsi(sdno, recurse); 785 } else { /* specific subdisks */ 786 for (i = 0; i < argc; i++) { 787 sdno = find_object(argv[i], &type); 788 if (type == sd_object) 789 vinum_lsi(sdno, recurse); 790 else 791 fprintf(stderr, "%s is not a subdisk\n", argv[i]); 792 } 793 } 794 } 795 796 797 /* List the complete configuration. 798 799 * XXX Change this to specific lists */ 800 void 801 listconfig(void) 802 { 803 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 804 perror("Can't get vinum config"); 805 return; 806 } 807 printf("%d drives:\n", vinum_conf.drives_used); 808 if (vinum_conf.drives_used > 0) { 809 vinum_ld(0, NULL, NULL); 810 printf("\n"); 811 } 812 printf("%d volumes:\n", vinum_conf.volumes_used); 813 if (vinum_conf.volumes_used > 0) { 814 vinum_lv(0, NULL, NULL); 815 printf("\n"); 816 } 817 printf("%d plexes:\n", vinum_conf.plexes_used); 818 if (vinum_conf.plexes_used > 0) { 819 vinum_lp(0, NULL, NULL); 820 printf("\n"); 821 } 822 printf("%d subdisks:\n", vinum_conf.subdisks_used); 823 if (vinum_conf.subdisks_used > 0) 824 vinum_ls(0, NULL, NULL); 825 } 826 827 /* Convert a timeval to Tue Oct 13 13:54:14.0434324 828 * Return pointer to text */ 829 char * 830 timetext(struct timeval *time) 831 { 832 static char text[30]; 833 time_t t; /* to keep Bruce happy */ 834 835 t = time->tv_sec; 836 strcpy(text, ctime(&t)); /* to the second */ 837 sprintf(&text[19], ".%06ld", time->tv_usec); /* and the microseconds */ 838 return &text[11]; 839 } 840 841 void 842 vinum_info(int argc, char *argv[], char *argv0[]) 843 { 844 struct meminfo meminfo; 845 struct mc malloced; 846 int i; 847 #if VINUMDEBUG 848 struct rqinfo rq; 849 #endif 850 851 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 852 perror("Can't get vinum config"); 853 return; 854 } 855 printf("Flags: 0x%x\n", vinum_conf.flags); 856 if (ioctl(superdev, VINUM_MEMINFO, &meminfo) < 0) { 857 perror("Can't get information"); 858 return; 859 } 860 printf("Total of %d blocks malloced, total memory: %d\nMaximum allocs: %8d, malloc table at %p\n", 861 meminfo.mallocs, 862 meminfo.total_malloced, 863 meminfo.highwater, 864 meminfo.malloced); 865 866 printf("%d requests active, maximum %d active\n", 867 vinum_conf.active, 868 vinum_conf.maxactive); 869 if (vflag && (!Verbose)) 870 for (i = 0; i < meminfo.mallocs; i++) { 871 malloced.seq = i; 872 if (ioctl(superdev, VINUM_MALLOCINFO, &malloced) < 0) { 873 perror("Can't get information"); 874 return; 875 } 876 if (!(i & 63)) 877 printf("Block\tSequence\t size\t address\t line\t\tfile\n\n"); 878 printf("%6d\t%6d\t\t%6d\t%p\t%6d\t\t%s\n", 879 i, 880 malloced.seq, 881 malloced.size, 882 malloced.address, 883 malloced.line, 884 (char *) &malloced.file); 885 } 886 #if VINUMDEBUG 887 if (Verbose) { 888 printf("\nTime\t\t Event\t Buf\tDev\t Offset\tBytes\tSD\tSDoff\tDoffset\tGoffset\n\n"); 889 for (i = RQINFO_SIZE - 1; i >= 0; i--) { /* go through the request list in order */ 890 *((int *) &rq) = i; 891 if (ioctl(superdev, VINUM_RQINFO, &rq) < 0) { 892 perror("Can't get information"); 893 return; 894 } 895 /* Compress devminor into something printable. */ 896 rq.devminor = (rq.devminor & 0xff) 897 | ((rq.devminor & 0xfff0000) >> 8); 898 switch (rq.type) { 899 case loginfo_unused: /* never been used */ 900 break; 901 902 case loginfo_user_bp: /* this is the bp when strategy is called */ 903 printf("%s %dVS %s %p\t%d.%-6d 0x%-9llx\t%d\n", 904 timetext(&rq.timestamp), 905 rq.type, 906 rq.info.b.b_flags & BUF_CMD_READ ? "Read " : "Write", 907 rq.bio, 908 rq.devmajor, 909 rq.devminor, 910 rq.info.bio.bio_offset, 911 rq.info.b.b_bcount); 912 break; 913 914 case loginfo_sdiol: /* subdisk I/O launch */ 915 case loginfo_user_bpl: /* and this is the bp at launch time */ 916 printf("%s %dLR %s %p\t%d.%-6d 0x%-9llx\t%d\n", 917 timetext(&rq.timestamp), 918 rq.type, 919 rq.info.b.b_flags & BUF_CMD_READ ? "Read " : "Write", 920 rq.bio, 921 rq.devmajor, 922 rq.devminor, 923 rq.info.bio.bio_offset, 924 rq.info.b.b_bcount); 925 break; 926 927 case loginfo_rqe: /* user RQE */ 928 printf("%s 3RQ %s %p\t%d.%-6d 0x%-9llx\t%d\t%d\t%llx\t%x\t%x\n", 929 timetext(&rq.timestamp), 930 rq.info.rqe.b.b_flags & BUF_CMD_READ ? "Read " : "Write", 931 rq.bio, 932 rq.devmajor, 933 rq.devminor, 934 rq.info.rqe.b.b_bio1.bio_offset, 935 rq.info.rqe.b.b_bcount, 936 rq.info.rqe.sdno, 937 rq.info.rqe.sdoffset, 938 rq.info.rqe.dataoffset, 939 rq.info.rqe.groupoffset); 940 break; 941 942 case loginfo_iodone: /* iodone called */ 943 printf("%s 4DN %s %p\t%d.%-6d 0x%-9llx\t%d\t%d\t%llx\t%x\t%x\n", 944 timetext(&rq.timestamp), 945 rq.info.rqe.b.b_flags & BUF_CMD_READ ? "Read " : "Write", 946 rq.bio, 947 rq.devmajor, 948 rq.devminor, 949 rq.info.rqe.b.b_bio1.bio_offset, 950 rq.info.rqe.b.b_bcount, 951 rq.info.rqe.sdno, 952 rq.info.rqe.sdoffset, 953 rq.info.rqe.dataoffset, 954 rq.info.rqe.groupoffset); 955 break; 956 957 case loginfo_raid5_data: /* RAID-5 write data block */ 958 printf("%s 5RD %s %p\t%d.%-6d 0x%-9llx\t%d\t%d\t%llx\t%x\t%x\n", 959 timetext(&rq.timestamp), 960 rq.info.rqe.b.b_flags & BUF_CMD_READ ? "Read " : "Write", 961 rq.bio, 962 rq.devmajor, 963 rq.devminor, 964 rq.info.rqe.b.b_bio1.bio_offset, 965 rq.info.rqe.b.b_bcount, 966 rq.info.rqe.sdno, 967 rq.info.rqe.sdoffset, 968 rq.info.rqe.dataoffset, 969 rq.info.rqe.groupoffset); 970 break; 971 972 case loginfo_raid5_parity: /* RAID-5 write parity block */ 973 printf("%s 6RP %s %p\t%d.%-6d 0x%-9llx\t%d\t%d\t%llx\t%x\t%x\n", 974 timetext(&rq.timestamp), 975 rq.info.rqe.b.b_flags & BUF_CMD_READ ? "Read " : "Write", 976 rq.bio, 977 rq.devmajor, 978 rq.devminor, 979 rq.info.rqe.b.b_bio1.bio_offset, 980 rq.info.rqe.b.b_bcount, 981 rq.info.rqe.sdno, 982 rq.info.rqe.sdoffset, 983 rq.info.rqe.dataoffset, 984 rq.info.rqe.groupoffset); 985 break; 986 987 case loginfo_sdio: /* subdisk I/O */ 988 printf("%s %dVS %s %p\t\t 0x%-9llx\t%d\t%d\n", 989 timetext(&rq.timestamp), 990 rq.type, 991 rq.info.b.b_flags & BUF_CMD_READ ? "Read " : "Write", 992 rq.bio, 993 rq.info.bio.bio_offset, 994 rq.info.b.b_bcount, 995 rq.devminor); 996 break; 997 998 case loginfo_sdiodone: /* subdisk I/O done */ 999 printf("%s %dSD %s %p\t\t 0x%-9llx\t%d\t%d\n", 1000 timetext(&rq.timestamp), 1001 rq.type, 1002 rq.info.b.b_flags & BUF_CMD_READ ? "Read " : "Write", 1003 rq.bio, 1004 rq.info.bio.bio_offset, 1005 rq.info.b.b_bcount, 1006 rq.devminor); 1007 break; 1008 1009 case loginfo_lockwait: 1010 printf("%s Lockwait %p\t 0x%llx\n", 1011 timetext(&rq.timestamp), 1012 rq.bio, 1013 rq.info.lockinfo.stripe); 1014 break; 1015 1016 case loginfo_lock: 1017 printf("%s Lock %p\t 0x%llx\n", 1018 timetext(&rq.timestamp), 1019 rq.bio, 1020 rq.info.lockinfo.stripe); 1021 break; 1022 1023 case loginfo_unlock: 1024 printf("%s Unlock\t %p\t 0x%llx\n", 1025 timetext(&rq.timestamp), 1026 rq.bio, 1027 rq.info.lockinfo.stripe); 1028 break; 1029 } 1030 } 1031 } 1032 #endif 1033 } 1034 1035 /* 1036 * Print config file to a file. This is a userland version 1037 * of kernel format_config 1038 */ 1039 void 1040 vinum_printconfig(int argc, char *argv[], char *argv0[]) 1041 { 1042 FILE *of; 1043 1044 if (argc > 1) { 1045 fprintf(stderr, "Usage: \tprintconfig [<outfile>]\n"); 1046 return; 1047 } else if (argc == 1) 1048 of = fopen(argv[0], "w"); 1049 else 1050 of = stdout; 1051 if (of == NULL) { 1052 fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno)); 1053 return; 1054 } 1055 printconfig(of, ""); 1056 if (argc == 1) 1057 fclose(of); 1058 } 1059 1060 /* 1061 * The guts of printconfig. This is called from 1062 * vinum_printconfig and from vinum_create when 1063 * called without an argument, in order to give 1064 * the user something to edit. 1065 */ 1066 void 1067 printconfig(FILE * of, char *comment) 1068 { 1069 struct utsname uname_s; 1070 time_t now; 1071 int i; 1072 struct volume vol; 1073 struct plex plex; 1074 struct sd sd; 1075 struct drive drive; 1076 1077 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 1078 perror("Can't get vinum config"); 1079 return; 1080 } 1081 uname(&uname_s); /* get our system name */ 1082 time(&now); /* and the current time */ 1083 fprintf(of, 1084 "# Vinum configuration of %s, saved at %s", 1085 uname_s.nodename, 1086 ctime(&now)); /* say who did it */ 1087 1088 if (comment[0] != 0) /* abuse this for commented version */ 1089 fprintf(of, "# Current configuration:\n"); 1090 for (i = 0; i < vinum_conf.drives_allocated; i++) { 1091 get_drive_info(&drive, i); 1092 if (drive.state != drive_unallocated) { 1093 fprintf(of, 1094 "%sdrive %s device %s\n", 1095 comment, 1096 drive.label.name, 1097 drive.devicename); 1098 } 1099 } 1100 1101 for (i = 0; i < vinum_conf.volumes_allocated; i++) { 1102 get_volume_info(&vol, i); 1103 if (vol.state != volume_unallocated) { 1104 if (vol.preferred_plex >= 0) /* preferences, */ 1105 fprintf(of, 1106 "%svolume %s readpol prefer %s\n", 1107 comment, 1108 vol.name, 1109 vinum_conf.plex[vol.preferred_plex].name); 1110 else /* default round-robin */ 1111 fprintf(of, "%svolume %s\n", comment, vol.name); 1112 } 1113 } 1114 1115 /* Then the plex configuration */ 1116 for (i = 0; i < vinum_conf.plexes_allocated; i++) { 1117 get_plex_info(&plex, i); 1118 if (plex.state != plex_unallocated) { 1119 fprintf(of, "%splex name %s org %s ", 1120 comment, 1121 plex.name, 1122 plex_org(plex.organization)); 1123 if (isstriped((&plex))) 1124 fprintf(of, "%ds ", (int) plex.stripesize); 1125 if (plex.volno >= 0) { /* we have a volume */ 1126 get_volume_info(&vol, plex.volno); 1127 fprintf(of, "vol %s ", vol.name); 1128 } else 1129 fprintf(of, "detached "); 1130 fprintf(of, "\n"); 1131 } 1132 } 1133 1134 /* And finally the subdisk configuration */ 1135 for (i = 0; i < vinum_conf.subdisks_allocated; i++) { 1136 get_sd_info(&sd, i); 1137 if (sd.state != sd_unallocated) { 1138 get_drive_info(&drive, sd.driveno); 1139 if (sd.plexno >= 0) { 1140 get_plex_info(&plex, sd.plexno); 1141 fprintf(of, 1142 "%ssd name %s drive %s plex %s len %llds driveoffset %llds plexoffset %llds\n", 1143 comment, 1144 sd.name, 1145 drive.label.name, 1146 plex.name, 1147 (long long) sd.sectors, 1148 (long long) sd.driveoffset, 1149 (long long) sd.plexoffset); 1150 } else 1151 fprintf(of, 1152 "%ssd name %s drive %s detached len %llds driveoffset %llds\n", 1153 comment, 1154 sd.name, 1155 drive.label.name, 1156 (long long) sd.sectors, 1157 (long long) sd.driveoffset); 1158 } 1159 } 1160 } 1161 1162 void 1163 list_defective_objects(void) 1164 { 1165 int o; /* object */ 1166 int heading_needed = 1; 1167 1168 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 1169 perror("Can't get vinum config"); 1170 return; 1171 } 1172 for (o = 0; o < vinum_conf.drives_allocated; o++) { 1173 get_drive_info(&drive, o); 1174 if ((drive.state != drive_unallocated) /* drive exists */ 1175 &&(drive.state != drive_up)) { /* but it's not up */ 1176 if (heading_needed) { 1177 printf("Warning: defective objects\n\n"); 1178 heading_needed = 0; 1179 } 1180 vinum_ldi(o, 0); /* print info */ 1181 } 1182 } 1183 1184 for (o = 0; o < vinum_conf.volumes_allocated; o++) { 1185 get_volume_info(&vol, o); 1186 if ((vol.state != volume_unallocated) /* volume exists */ 1187 &&(vol.state != volume_up)) { /* but it's not up */ 1188 if (heading_needed) { 1189 printf("Warning: defective objects\n\n"); 1190 heading_needed = 0; 1191 } 1192 vinum_lvi(o, 0); /* print info */ 1193 } 1194 } 1195 1196 for (o = 0; o < vinum_conf.plexes_allocated; o++) { 1197 get_plex_info(&plex, o); 1198 if ((plex.state != plex_unallocated) /* plex exists */ 1199 &&(plex.state != plex_up)) { /* but it's not up */ 1200 if (heading_needed) { 1201 printf("Warning: defective objects\n\n"); 1202 heading_needed = 0; 1203 } 1204 vinum_lpi(o, 0); /* print info */ 1205 } 1206 } 1207 1208 for (o = 0; o < vinum_conf.subdisks_allocated; o++) { 1209 get_sd_info(&sd, o); 1210 if ((sd.state != sd_unallocated) /* sd exists */ 1211 &&(sd.state != sd_up)) { /* but it's not up */ 1212 if (heading_needed) { 1213 printf("Warning: defective objects\n\n"); 1214 heading_needed = 0; 1215 } 1216 vinum_lsi(o, 0); /* print info */ 1217 } 1218 } 1219 } 1220 1221 /* Dump config from specified disk drives */ 1222 void 1223 vinum_dumpconfig(int argc, char *argv[], char *argv0[]) 1224 { 1225 int i; 1226 1227 if (argc == 0) { /* start everything */ 1228 int devs = getnumdevs(); 1229 struct statinfo statinfo; 1230 char *namelist; 1231 char *enamelist; /* end of name list */ 1232 int i; 1233 char **token; /* list of tokens */ 1234 int tokens; /* and their number */ 1235 1236 bzero(&statinfo, sizeof(struct statinfo)); 1237 statinfo.dinfo = malloc(devs * sizeof(struct statinfo)); 1238 namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8)); 1239 token = malloc((devs + 1) * sizeof(char *)); 1240 if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) { 1241 fprintf(stderr, "Can't allocate memory for drive list\n"); 1242 return; 1243 } 1244 bzero(statinfo.dinfo, sizeof(struct devinfo)); 1245 1246 tokens = 0; /* no tokens yet */ 1247 if (getdevs(&statinfo) < 0) { /* find out what devices we have */ 1248 perror("Can't get device list"); 1249 return; 1250 } 1251 namelist[0] = '\0'; /* start with empty namelist */ 1252 enamelist = namelist; /* point to the end of the list */ 1253 1254 for (i = 0; i < devs; i++) { 1255 struct devstat *stat = &statinfo.dinfo->devices[i]; 1256 1257 if (((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */ 1258 &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */ 1259 &&((stat->device_name[0] != '\0'))) { /* and it has a name */ 1260 sprintf(enamelist, "/dev/%s%d", stat->device_name, stat->unit_number); 1261 token[tokens] = enamelist; /* point to it */ 1262 tokens++; /* one more token */ 1263 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */ 1264 } 1265 } 1266 free(statinfo.dinfo); /* don't need the list any more */ 1267 for (i = 0; i < tokens; i++) 1268 dumpconfig(token[i]); 1269 free(namelist); 1270 free(token); 1271 } else { /* list specified drives */ 1272 for (i = 0; i < argc; i++) 1273 dumpconfig(argv[i]); 1274 } 1275 } 1276 1277 #define DEVLEN 5 1278 void 1279 dumpconfig(char *part) 1280 { 1281 char partname[MAXPATHLEN]; 1282 char *partid; 1283 int partition; /* UNIX partition */ 1284 int slice; 1285 int founddrive; /* flag when we find a vinum drive */ 1286 struct disklabel32 label; /* label of this drive */ 1287 int driveno; /* fd of drive */ 1288 int found; 1289 u_int64_t drivelength; 1290 1291 if (memcmp(part, "/dev/", DEVLEN) == 0) /* starts with /dev */ 1292 memcpy(partname, part, MAXPATHLEN); 1293 else { /* prepend */ 1294 strcpy(partname, "/dev/"); 1295 strncat(&partname[DEVLEN], part, MAXPATHLEN - DEVLEN); 1296 } 1297 partid = &partname[strlen(partname)]; 1298 founddrive = 0; /* no vinum drive found yet on this spindle */ 1299 /* first try the partition table */ 1300 for (slice = 1; slice < 5; slice++) { 1301 sprintf(partid, "s%dc", slice); /* c partition */ 1302 driveno = open(partname, O_RDONLY); 1303 if (driveno < 0) { 1304 if (errno != ENOENT) 1305 fprintf(stderr, "Can't open %s: %s (%d)\n", partname, strerror(errno), errno); 1306 continue; 1307 } 1308 if (ioctl(driveno, DIOCGDINFO32, &label) < 0) { 1309 fprintf(stderr, "Can't get label from %s: %s (%d)\n", partname, strerror(errno), errno); 1310 continue; 1311 } 1312 for (partition = 0; partition < MAXPARTITIONS; partition++) { 1313 if ((partition != 2) /* it's not the c partition */ 1314 &&((label.d_partitions[partition].p_fstype == FS_VINUM) /* and it's a Vinum partition */ 1315 ||Verbose)) { /* or we're just plain curious */ 1316 sprintf(partid, "s%d%c", slice, partition + 'a'); 1317 found = check_drive(partname); /* try to open it */ 1318 founddrive |= found; /* and note if we were successful at all */ 1319 if (label.d_partitions[partition].p_fstype == FS_VINUM) { /* it's a Vinum partition */ 1320 drivelength = ((u_int64_t) label.d_partitions[partition].p_size) * DEV_BSIZE; 1321 printf("Drive %s: %s (%lld bytes)\n", 1322 partname, 1323 roughlength(drivelength, 1), 1324 (long long)drivelength); 1325 if ((!found) && vflag) /* we're talkative */ 1326 printf("*** no configuration found ***\n"); 1327 } 1328 } 1329 } 1330 } 1331 if (founddrive == 0) { /* didn't find anything, */ 1332 sprintf(partid, "c"); /* c partition */ 1333 driveno = open(partname, O_RDONLY); 1334 if (driveno < 0) { 1335 if (errno != ENOENT) 1336 fprintf(stderr, "Can't open %s: %s (%d)\n", partname, strerror(errno), errno); 1337 return; 1338 } 1339 if (ioctl(driveno, DIOCGDINFO32, &label) < 0) { 1340 fprintf(stderr, "Can't get label from %s: %s (%d)\n", partname, strerror(errno), errno); 1341 return; 1342 } 1343 for (partition = 0; partition < MAXPARTITIONS; partition++) { /* try the compatibility partition */ 1344 if ((partition != 2) /* it's not the c partition */ 1345 &&((label.d_partitions[partition].p_fstype == FS_VINUM) /* and it's a Vinum partition */ 1346 ||Verbose)) { /* or we're just plain curious */ 1347 sprintf(partid, "%c", partition + 'a'); 1348 found = check_drive(partname); /* try to open it */ 1349 founddrive |= found; /* and note if we were successful at all */ 1350 if (label.d_partitions[partition].p_fstype == FS_VINUM) { /* it's a Vinum partition */ 1351 drivelength = ((u_int64_t) label.d_partitions[partition].p_size) * DEV_BSIZE; 1352 printf("Drive %s: %s (%lld bytes)\n", 1353 partname, 1354 roughlength(drivelength, 1), 1355 (long long)drivelength); 1356 if ((!found) && vflag) /* we're talkative */ 1357 printf("*** no configuration found ***\n"); 1358 } 1359 } 1360 } 1361 } 1362 } 1363 1364 /* 1365 * Check a drive for a Vinum header. If found, 1366 * print configuration information from the drive. 1367 * 1368 * Return 1 if Vinum config found. 1369 */ 1370 int 1371 check_drive(char *devicename) 1372 { 1373 int fd; 1374 char vinumlabel[DEV_BSIZE]; /* one sector for label */ 1375 struct vinum_hdr *hdr = (struct vinum_hdr *) vinumlabel; /* with this structure */ 1376 char *config_text; /* read the config info from disk into here */ 1377 time_t t; 1378 1379 fd = open(devicename, O_RDONLY); 1380 if (fd >= 0) { 1381 if (lseek(fd, VINUM_LABEL_OFFSET, SEEK_SET) < 0) { 1382 fprintf(stderr, 1383 "Can't seek label for %s: %s (%d)\n", 1384 devicename, 1385 strerror(errno), 1386 errno); 1387 close(fd); 1388 return 0; 1389 } 1390 if (read(fd, vinumlabel, DEV_BSIZE) != DEV_BSIZE) { 1391 if (errno != EINVAL) 1392 fprintf(stderr, 1393 "Can't read label from %s: %s (%d)\n", 1394 devicename, 1395 strerror(errno), 1396 errno); 1397 close(fd); 1398 return 0; 1399 } 1400 if ((hdr->magic == VINUM_MAGIC) 1401 || (vflag && (hdr->magic == VINUM_NOMAGIC))) { 1402 printf("Drive %s:\tDevice %s\n", 1403 hdr->label.name, 1404 devicename); 1405 if (hdr->magic == VINUM_NOMAGIC) 1406 printf("*** Drive has been obliterated ***\n"); 1407 t = hdr->label.date_of_birth.tv_sec; 1408 printf("\t\tCreated on %s at %s", 1409 hdr->label.sysname, 1410 ctime(&t)); 1411 t = hdr->label.last_update.tv_sec; 1412 printf("\t\tConfig last updated %s", /* care: \n at end */ 1413 ctime(&t)); 1414 printf("\t\tSize: %16lld bytes (%lld MB)\n", 1415 (long long) hdr->label.drive_size, /* bytes used */ 1416 (long long) (hdr->label.drive_size / MEGABYTE)); 1417 config_text = (char *) malloc(MAXCONFIG); 1418 if (config_text == NULL) 1419 fprintf(stderr, "Can't allocate memory\n"); 1420 else { 1421 if (read(fd, config_text, MAXCONFIG) != MAXCONFIG) 1422 fprintf(stderr, 1423 "Can't read config from %s: %s (%d)\n", 1424 devicename, 1425 strerror(errno), 1426 errno); 1427 else 1428 puts(config_text); 1429 free(config_text); 1430 } 1431 } 1432 close(fd); 1433 return 1; 1434 } 1435 return 0; 1436 } 1437 1438 /* Local Variables: */ 1439 /* fill-column: 50 */ 1440 /* End: */ 1441