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