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