Add missing section number.
[dragonfly.git] / sbin / vinum / list.c
blob10ee31ca44d0490ebdb0a9b6cb58887e72098e49
1 /* list.c: vinum interface program, list routines
2 */
3 /*-
4 * Copyright (c) 1997, 1998
5 * Nan Yang Computer Services Limited. All rights reserved.
7 * Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project.
9 * Written by Greg Lehey
11 * This software is distributed under the so-called ``Berkeley
12 * License'':
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.
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.
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 $
43 #define _KERNEL_STRUCTURES
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>
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.
71 #define STALLCOUNT 100
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.
80 * Note this uses a static string: it's only
81 * intended to be used immediately for printing.
83 char *
84 roughlength(int64_t bytes, int lj)
86 static char description[16];
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;
99 void
100 vinum_list(int argc, char *argv[], char *argv0[])
102 int object;
103 int i;
104 enum objecttype type;
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]);
120 /* List an object */
122 vinum_li(int object, enum objecttype type)
124 switch (type) {
125 case drive_object:
126 vinum_ldi(object, recurse);
127 break;
129 case sd_object:
130 vinum_lsi(object, recurse);
131 break;
133 case plex_object:
134 vinum_lpi(object, recurse);
135 break;
137 case volume_object:
138 vinum_lvi(object, recurse);
139 break;
141 default:
142 return -1;
144 return 0;
147 void
148 vinum_ldi(int driveno, int recurse)
150 time_t t; /* because Bruce says so */
151 int sdno; /* for recursion */
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;
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",
203 strerror(errno));
204 longjmp(command_fail, -1);
206 printf("\t\t%9lld\t%9lld\n",
207 (long long) freeunion.freelist.offset,
208 (long long) freeunion.freelist.sectors);
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))));
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));
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);
266 printf("\n");
270 void
271 vinum_ld(int argc, char *argv[], char *argv0[])
273 int i;
274 int driveno;
275 enum objecttype type;
277 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
278 perror("Can't get vinum config");
279 return;
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]);
295 void
296 vinum_lvi(int volno, int recurse)
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);
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");
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));
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;
383 for (sdno = 0; sdno < plex.subdisks; sdno++) {
384 get_plex_sd_info(&sd, vol.plex[plexno], sdno);
385 vinum_lsi(sd.sdno, 0);
389 printf("\n");
395 void
396 vinum_lv(int argc, char *argv[], char *argv0[])
398 int i;
399 int volno;
400 enum objecttype type;
402 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
403 perror("Can't get vinum config");
404 return;
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]);
420 void
421 vinum_lpi(int plexno, int recurse)
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);
447 } else if (!sflag) { /* non-verbose list */
448 char *org = ""; /* organization */
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;
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));
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);
531 if (plex.subdisks > 0) {
532 int sdno;
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);
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);
558 printf("\n");
562 void
563 vinum_lp(int argc, char *argv[], char *argv0[])
565 int i;
566 int plexno;
567 enum objecttype type;
569 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
570 perror("Can't get vinum config");
571 return;
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]);
587 void
588 vinum_lsi(int sdno, int recurse)
590 long long revived; /* keep an eye on revive progress */
591 int times;
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));
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 */
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.
628 for (times = 0; times < STALLCOUNT; times++) {
629 get_sd_info(&sd, sdno);
630 if (sd.revived != revived) /* progress? */
631 break;
632 usleep(50000);
634 if (times == STALLCOUNT)
635 printf("\t\t*** Revive has stalled ***\n");
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);
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);
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 */
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.
709 for (times = 0; times < STALLCOUNT; times++) {
710 get_sd_info(&sd, sdno);
711 if (sd.revived != revived) /* progress? */
712 break;
713 usleep(50000);
715 if (times == STALLCOUNT)
716 printf("\t\t\t*** Revive of %s has stalled ***\n",
717 sd.name);
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");
757 if (recurse)
758 vinum_ldi(sd.driveno, 0);
759 if (vflag)
760 printf("\n"); /* make it more readable */
764 void
765 vinum_ls(int argc, char *argv[], char *argv0[])
767 int i;
768 int sdno;
770 /* Structures to read kernel data into */
771 struct _vinum_conf vinum_conf;
772 enum objecttype type;
774 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
775 perror("Can't get vinum config");
776 return;
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]);
793 /* List the complete configuration.
795 * XXX Change this to specific lists */
796 void
797 listconfig(void)
799 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
800 perror("Can't get vinum config");
801 return;
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");
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");
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");
818 printf("%d subdisks:\n", vinum_conf.subdisks_used);
819 if (vinum_conf.subdisks_used > 0)
820 vinum_ls(0, NULL, NULL);
823 /* Convert a timeval to Tue Oct 13 13:54:14.0434324
824 * Return pointer to text */
825 char *
826 timetext(struct timeval *time)
828 static char text[30];
829 time_t t; /* to keep Bruce happy */
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];
837 void
838 vinum_info(int argc, char *argv[], char *argv0[])
840 struct meminfo meminfo;
841 struct mc malloced;
842 int i;
843 #if VINUMDEBUG
844 struct rqinfo rq;
845 #endif
847 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
848 perror("Can't get vinum config");
849 return;
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;
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);
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;
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",
876 malloced.seq,
877 malloced.size,
878 (int) malloced.address,
879 malloced.line,
880 (char *) &malloced.file);
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
1028 #endif
1032 * Print config file to a file. This is a userland version
1033 * of kernel format_config
1035 void
1036 vinum_printconfig(int argc, char *argv[], char *argv0[])
1038 FILE *of;
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;
1051 printconfig(of, "");
1052 if (argc == 1)
1053 fclose(of);
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.
1062 void
1063 printconfig(FILE * of, char *comment)
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;
1073 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1074 perror("Can't get vinum config");
1075 return;
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 */
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);
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);
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");
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);
1158 void
1159 list_defective_objects(void)
1161 int o; /* object */
1162 int heading_needed = 1;
1164 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1165 perror("Can't get vinum config");
1166 return;
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;
1176 vinum_ldi(o, 0); /* print info */
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;
1188 vinum_lvi(o, 0); /* print info */
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;
1200 vinum_lpi(o, 0); /* print info */
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;
1212 vinum_lsi(o, 0); /* print info */
1217 /* Dump config from specified disk drives */
1218 void
1219 vinum_dumpconfig(int argc, char *argv[], char *argv0[])
1221 int i;
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 */
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;
1240 bzero(statinfo.dinfo, sizeof(struct devinfo));
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;
1247 namelist[0] = '\0'; /* start with empty namelist */
1248 enamelist = namelist; /* point to the end of the list */
1250 for (i = 0; i < devs; i++) {
1251 struct devstat *stat = &statinfo.dinfo->devices[i];
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 */
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]);
1273 #define DEVLEN 5
1274 void
1275 dumpconfig(char *part)
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;
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);
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;
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;
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");
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;
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;
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");
1361 * Check a drive for a Vinum header. If found,
1362 * print configuration information from the drive.
1364 * Return 1 if Vinum config found.
1367 check_drive(char *devicename)
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;
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;
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;
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);
1428 close(fd);
1429 return 1;
1431 return 0;
1434 /* Local Variables: */
1435 /* fill-column: 50 */
1436 /* End: */