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