Home | History | Annotate | Line # | Download | only in raidctl
raidctl.c revision 1.10
      1 /*      $NetBSD: raidctl.c,v 1.10 2000/01/05 03:02:41 oster Exp $   */
      2 /*-
      3  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to The NetBSD Foundation
      7  * by Greg Oster
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *        This product includes software developed by the NetBSD
     20  *        Foundation, Inc. and its contributors.
     21  * 4. Neither the name of The NetBSD Foundation nor the names of its
     22  *    contributors may be used to endorse or promote products derived
     23  *    from this software without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     26  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35  * POSSIBILITY OF SUCH DAMAGE.
     36  */
     37 
     38 /*
     39 
     40    This program is a re-write of the original rf_ctrl program
     41    distributed by CMU with RAIDframe 1.1.
     42 
     43    This program is the user-land interface to the RAIDframe kernel
     44    driver in NetBSD.
     45 
     46  */
     47 
     48 #include <sys/param.h>
     49 #include <sys/ioctl.h>
     50 #include <sys/stat.h>
     51 #include <util.h>
     52 #include <stdio.h>
     53 #include <fcntl.h>
     54 #include <ctype.h>
     55 #include <err.h>
     56 #include <errno.h>
     57 #include <sys/types.h>
     58 #include <string.h>
     59 #include <sys/disklabel.h>
     60 #include <machine/disklabel.h>
     61 #include <stdlib.h>
     62 #include <unistd.h>
     63 
     64 #include "rf_raidframe.h"
     65 
     66 extern  char *__progname;
     67 
     68 int     main __P((int, char *[]));
     69 void do_ioctl __P((int, unsigned long, void *, char *));
     70 static  void rf_configure __P((int, char*, int));
     71 static  char *device_status __P((RF_DiskStatus_t));
     72 static  void rf_get_device_status __P((int));
     73 static  void get_component_number __P((int, char *, int *, int *));
     74 static  void rf_fail_disk __P((int, char *, int));
     75 static  void usage __P((void));
     76 static  void get_component_label __P((int, char *));
     77 static  void set_component_label __P((int, char *));
     78 static  void init_component_labels __P((int, int));
     79 static  void add_hot_spare __P((int, char *));
     80 static  void remove_hot_spare __P((int, char *));
     81 static  void rebuild_in_place __P((int, char *));
     82 static  void check_status __P((int));
     83 static  void check_parity __P((int,int,char *));
     84 static  void do_meter __P((int, int));
     85 static  void get_bar __P((char *, double, int));
     86 static  void get_time_string __P((char *, int));
     87 
     88 int verbose = 0;
     89 
     90 int
     91 main(argc,argv)
     92 	int argc;
     93 	char *argv[];
     94 {
     95 	extern char *optarg;
     96 	extern int optind;
     97 	int ch;
     98 	int num_options;
     99 	unsigned long action;
    100 	char config_filename[PATH_MAX];
    101 	char dev_name[PATH_MAX];
    102 	char name[PATH_MAX];
    103 	char component[PATH_MAX];
    104 	int do_recon;
    105 	int do_rewrite;
    106 	int is_clean;
    107 	int raidID;
    108 	int rawpart;
    109 	int serial_number;
    110 	struct stat st;
    111 	int fd;
    112 	int force;
    113 
    114 	num_options = 0;
    115 	action = 0;
    116 	do_recon = 0;
    117 	do_rewrite = 0;
    118 	is_clean = 0;
    119 	force = 0;
    120 
    121 	while ((ch = getopt(argc, argv, "a:Bc:C:f:F:g:iI:l:r:R:sSpPuv")) != -1)
    122 		switch(ch) {
    123 		case 'a':
    124 			action = RAIDFRAME_ADD_HOT_SPARE;
    125 			strncpy(component, optarg, PATH_MAX);
    126 			num_options++;
    127 			break;
    128 		case 'B':
    129 			action = RAIDFRAME_COPYBACK;
    130 			num_options++;
    131 			break;
    132 		case 'c':
    133 			action = RAIDFRAME_CONFIGURE;
    134 			strncpy(config_filename,optarg,PATH_MAX);
    135 			force = 0;
    136 			num_options++;
    137 			break;
    138 		case 'C':
    139 			strncpy(config_filename,optarg,PATH_MAX);
    140 			action = RAIDFRAME_CONFIGURE;
    141 			force = 1;
    142 			num_options++;
    143 			break;
    144 		case 'f':
    145 			action = RAIDFRAME_FAIL_DISK;
    146 			strncpy(component, optarg, PATH_MAX);
    147 			do_recon = 0;
    148 			num_options++;
    149 			break;
    150 		case 'F':
    151 			action = RAIDFRAME_FAIL_DISK;
    152 			strncpy(component, optarg, PATH_MAX);
    153 			do_recon = 1;
    154 			num_options++;
    155 			break;
    156 		case 'g':
    157 			action = RAIDFRAME_GET_COMPONENT_LABEL;
    158 			strncpy(component, optarg, PATH_MAX);
    159 			num_options++;
    160 			break;
    161 		case 'i':
    162 			action = RAIDFRAME_REWRITEPARITY;
    163 			num_options++;
    164 			break;
    165 		case 'I':
    166 			action = RAIDFRAME_INIT_LABELS;
    167 			serial_number = atoi(optarg);
    168 			num_options++;
    169 			break;
    170 		case 'l':
    171 			action = RAIDFRAME_SET_COMPONENT_LABEL;
    172 			strncpy(component, optarg, PATH_MAX);
    173 			num_options++;
    174 			break;
    175 		case 'r':
    176 			action = RAIDFRAME_REMOVE_HOT_SPARE;
    177 			strncpy(component, optarg, PATH_MAX);
    178 			num_options++;
    179 			break;
    180 		case 'R':
    181 			strncpy(component,optarg,PATH_MAX);
    182 			action = RAIDFRAME_REBUILD_IN_PLACE;
    183 			num_options++;
    184 			break;
    185 		case 's':
    186 			action = RAIDFRAME_GET_INFO;
    187 			num_options++;
    188 			break;
    189 		case 'S':
    190 			action = RAIDFRAME_CHECK_RECON_STATUS;
    191 			num_options++;
    192 			break;
    193 		case 'p':
    194 			action = RAIDFRAME_CHECK_PARITY;
    195 			num_options++;
    196 			break;
    197 		case 'P':
    198 			action = RAIDFRAME_CHECK_PARITY;
    199 			do_rewrite = 1;
    200 			num_options++;
    201 			break;
    202 		case 'u':
    203 			action = RAIDFRAME_SHUTDOWN;
    204 			num_options++;
    205 			break;
    206 		case 'v':
    207 			verbose = 1;
    208 			/* Don't bump num_options, as '-v' is not
    209 			   an option like the others */
    210 			/* num_options++; */
    211 			break;
    212 		default:
    213 			usage();
    214 		}
    215 	argc -= optind;
    216 	argv += optind;
    217 
    218 	if ((num_options > 1) || (argc == NULL))
    219 		usage();
    220 
    221 	strncpy(name,argv[0],PATH_MAX);
    222 
    223 	if ((name[0] == '/') || (name[0] == '.')) {
    224 		/* they've (apparently) given a full path... */
    225 		strncpy(dev_name, name, PATH_MAX);
    226 	} else {
    227 		if (isdigit(name[strlen(name)-1])) {
    228 			rawpart = getrawpartition();
    229 			snprintf(dev_name,PATH_MAX,"/dev/%s%c",name,
    230 				 'a'+rawpart);
    231 		} else {
    232 			snprintf(dev_name,PATH_MAX,"/dev/%s",name);
    233 		}
    234 	}
    235 
    236 	if (stat(dev_name, &st) != 0) {
    237 		fprintf(stderr,"%s: stat failure on: %s\n",
    238 			__progname,dev_name);
    239 		return (errno);
    240 	}
    241 	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) {
    242 		fprintf(stderr,"%s: invalid device: %s\n",
    243 			__progname,dev_name);
    244 		return (EINVAL);
    245 	}
    246 
    247 	raidID = RF_DEV2RAIDID(st.st_rdev);
    248 
    249 	if ((fd = open( dev_name, O_RDWR, 0640)) < 0) {
    250 		fprintf(stderr, "%s: unable to open device file: %s\n",
    251 			__progname, dev_name);
    252 		exit(1);
    253 	}
    254 
    255 
    256 	switch(action) {
    257 	case RAIDFRAME_ADD_HOT_SPARE:
    258 		add_hot_spare(fd,component);
    259 		break;
    260 	case RAIDFRAME_REMOVE_HOT_SPARE:
    261 		remove_hot_spare(fd,component);
    262 		break;
    263 	case RAIDFRAME_CONFIGURE:
    264 		rf_configure(fd, config_filename,force);
    265 		break;
    266 	case RAIDFRAME_COPYBACK:
    267 		printf("Copyback.\n");
    268 		do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK");
    269 		if (verbose) {
    270 			sleep(3); /* XXX give the copyback a chance to start */
    271 			printf("Copyback status:\n");
    272 			do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS);
    273 		}
    274 		break;
    275 	case RAIDFRAME_FAIL_DISK:
    276 		rf_fail_disk(fd,component,do_recon);
    277 		break;
    278 	case RAIDFRAME_SET_COMPONENT_LABEL:
    279 		set_component_label(fd,component);
    280 		break;
    281 	case RAIDFRAME_GET_COMPONENT_LABEL:
    282 		get_component_label(fd,component);
    283 		break;
    284 	case RAIDFRAME_INIT_LABELS:
    285 		init_component_labels(fd,serial_number);
    286 		break;
    287 	case RAIDFRAME_REWRITEPARITY:
    288 		printf("Initiating re-write of parity\n");
    289 		do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
    290 			 "RAIDFRAME_REWRITEPARITY");
    291 		if (verbose) {
    292 			sleep(3); /* XXX give it time to get started */
    293 			printf("Parity Re-write status:\n");
    294 			do_meter(fd,RAIDFRAME_CHECK_PARITYREWRITE_STATUS);
    295 		}
    296 		break;
    297 	case RAIDFRAME_CHECK_RECON_STATUS:
    298 		check_status(fd);
    299 		break;
    300 	case RAIDFRAME_GET_INFO:
    301 		rf_get_device_status(fd);
    302 		break;
    303 	case RAIDFRAME_REBUILD_IN_PLACE:
    304 		rebuild_in_place(fd,component);
    305 		break;
    306 	case RAIDFRAME_CHECK_PARITY:
    307 		check_parity(fd,do_rewrite,dev_name);
    308 		break;
    309 	case RAIDFRAME_SHUTDOWN:
    310 		do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN");
    311 		break;
    312 	default:
    313 		break;
    314 	}
    315 
    316 	close(fd);
    317 	exit(0);
    318 }
    319 
    320 void
    321 do_ioctl(fd, command, arg, ioctl_name)
    322 	int fd;
    323 	unsigned long command;
    324 	void *arg;
    325 	char *ioctl_name;
    326 {
    327 	if (ioctl(fd, command, arg) < 0) {
    328 		warn("ioctl (%s) failed", ioctl_name);
    329 		printf("ioctl (%s) failed", ioctl_name);
    330 		exit(1);
    331 	}
    332 }
    333 
    334 
    335 static void
    336 rf_configure(fd,config_file,force)
    337 	int fd;
    338 	char *config_file;
    339 	int force;
    340 {
    341 	void *generic;
    342 	RF_Config_t cfg;
    343 
    344 	if (rf_MakeConfig( config_file, &cfg ) != 0) {
    345 		fprintf(stderr,"%s: unable to create RAIDframe %s\n",
    346 			__progname, "configuration structure\n");
    347 		exit(1);
    348 	}
    349 
    350 	cfg.force = force;
    351 
    352 	/*
    353 
    354 	   Note the extra level of redirection needed here, since
    355 	   what we really want to pass in is a pointer to the pointer to
    356 	   the configuration structure.
    357 
    358 	 */
    359 
    360 	generic = (void *) &cfg;
    361 	do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE");
    362 }
    363 
    364 static char *
    365 device_status(status)
    366 	RF_DiskStatus_t status;
    367 {
    368 	static char status_string[256];
    369 
    370 	switch (status) {
    371 	case rf_ds_optimal:
    372 		strcpy(status_string,"optimal");
    373 		break;
    374 	case rf_ds_failed:
    375 		strcpy(status_string,"failed");
    376 		break;
    377 	case rf_ds_reconstructing:
    378 		strcpy(status_string,"reconstructing");
    379 		break;
    380 	case rf_ds_dist_spared:
    381 		strcpy(status_string,"dist_spared");
    382 		break;
    383 	case rf_ds_spared:
    384 		strcpy(status_string,"spared");
    385 		break;
    386 	case rf_ds_spare:
    387 		strcpy(status_string,"spare");
    388 		break;
    389 	case rf_ds_used_spare:
    390 		strcpy(status_string,"used_spare");
    391 		break;
    392 	default:
    393 		strcpy(status_string,"UNKNOWN");
    394 		break;
    395 	}
    396 	return(status_string);
    397 }
    398 
    399 static void
    400 rf_get_device_status(fd)
    401 	int fd;
    402 {
    403 	RF_DeviceConfig_t device_config;
    404 	void *cfg_ptr;
    405 	int is_clean;
    406 	int i;
    407 
    408 	cfg_ptr = &device_config;
    409 
    410 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO");
    411 
    412 	printf("Components:\n");
    413 	for(i=0; i < device_config.ndevs; i++) {
    414 		printf("%20s: %s\n", device_config.devs[i].devname,
    415 		       device_status(device_config.devs[i].status));
    416 	}
    417 	if (device_config.nspares > 0) {
    418 		printf("Spares:\n");
    419 		for(i=0; i < device_config.nspares; i++) {
    420 			printf("%20s: %s\n",
    421 			       device_config.spares[i].devname,
    422 			       device_status(device_config.spares[i].status));
    423 		}
    424 	} else {
    425 		printf("No spares.\n");
    426 	}
    427 	do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean,
    428 		 "RAIDFRAME_CHECK_PARITY");
    429 	if (is_clean) {
    430 		printf("Parity status: clean\n");
    431 	} else {
    432 		printf("Parity status: DIRTY\n");
    433 	}
    434 	check_status(fd);
    435 }
    436 
    437 static void
    438 get_component_number(fd, component_name, component_number, num_columns)
    439 	int fd;
    440 	char *component_name;
    441 	int *component_number;
    442 	int *num_columns;
    443 {
    444 	RF_DeviceConfig_t device_config;
    445 	void *cfg_ptr;
    446 	int i;
    447 	int found;
    448 
    449 	*component_number = -1;
    450 
    451 	/* Assuming a full path spec... */
    452 	cfg_ptr = &device_config;
    453 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr,
    454 		 "RAIDFRAME_GET_INFO");
    455 
    456 	*num_columns = device_config.cols;
    457 
    458 	found = 0;
    459 	for(i=0; i < device_config.ndevs; i++) {
    460 		if (strncmp(component_name, device_config.devs[i].devname,
    461 			    PATH_MAX)==0) {
    462 			found = 1;
    463 			*component_number = i;
    464 		}
    465 	}
    466 	if (!found) {
    467 		fprintf(stderr,"%s: %s is not a component %s", __progname,
    468 			component_name, "of this device\n");
    469 		exit(1);
    470 	}
    471 }
    472 
    473 static void
    474 rf_fail_disk(fd, component_to_fail, do_recon)
    475 	int fd;
    476 	char *component_to_fail;
    477 	int do_recon;
    478 {
    479 	struct rf_recon_req recon_request;
    480 	int component_num;
    481 	int num_cols;
    482 
    483 	get_component_number(fd, component_to_fail, &component_num, &num_cols);
    484 
    485 	recon_request.row = component_num / num_cols;
    486 	recon_request.col = component_num % num_cols;
    487 	if (do_recon) {
    488 		recon_request.flags = RF_FDFLAGS_RECON;
    489 	} else {
    490 		recon_request.flags = RF_FDFLAGS_NONE;
    491 	}
    492 	do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request,
    493 		 "RAIDFRAME_FAIL_DISK");
    494 	if (do_recon && verbose) {
    495 		printf("Reconstruction status:\n");
    496 		sleep(3); /* XXX give reconstruction a chance to start */
    497 		do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS);
    498 	}
    499 }
    500 
    501 static void
    502 get_component_label(fd, component)
    503 	int fd;
    504 	char *component;
    505 {
    506 	RF_ComponentLabel_t component_label;
    507 	void *label_ptr;
    508 	int component_num;
    509 	int num_cols;
    510 
    511 	get_component_number(fd, component, &component_num, &num_cols);
    512 
    513 	memset( &component_label, 0, sizeof(RF_ComponentLabel_t));
    514 	component_label.row = component_num / num_cols;
    515 	component_label.column = component_num % num_cols;
    516 
    517 	label_ptr = &component_label;
    518 	do_ioctl( fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr,
    519 		  "RAIDFRAME_GET_COMPONENT_LABEL");
    520 
    521 	printf("Component label for %s:\n",component);
    522 	printf("Version: %d\n",component_label.version);
    523 	printf("Serial Number: %d\n",component_label.serial_number);
    524 	printf("Mod counter: %d\n",component_label.mod_counter);
    525 	printf("Row: %d\n", component_label.row);
    526 	printf("Column: %d\n", component_label.column);
    527 	printf("Num Rows: %d\n", component_label.num_rows);
    528 	printf("Num Columns: %d\n", component_label.num_columns);
    529 	printf("Clean: %d\n", component_label.clean);
    530 	printf("Status: %s\n", device_status(component_label.status));
    531 }
    532 
    533 static void
    534 set_component_label(fd, component)
    535 	int fd;
    536 	char *component;
    537 {
    538 	RF_ComponentLabel_t component_label;
    539 	int component_num;
    540 	int num_cols;
    541 
    542 	get_component_number(fd, component, &component_num, &num_cols);
    543 
    544 	/* XXX This is currently here for testing, and future expandability */
    545 
    546 	component_label.version = 1;
    547 	component_label.serial_number = 123456;
    548 	component_label.mod_counter = 0;
    549 	component_label.row = component_num / num_cols;
    550 	component_label.column = component_num % num_cols;
    551 	component_label.num_rows = 0;
    552 	component_label.num_columns = 5;
    553 	component_label.clean = 0;
    554 	component_label.status = 1;
    555 
    556 	do_ioctl( fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label,
    557 		  "RAIDFRAME_SET_COMPONENT_LABEL");
    558 }
    559 
    560 
    561 static void
    562 init_component_labels(fd, serial_number)
    563 	int fd;
    564 	int serial_number;
    565 {
    566 	RF_ComponentLabel_t component_label;
    567 
    568 	component_label.version = 0;
    569 	component_label.serial_number = serial_number;
    570 	component_label.mod_counter = 0;
    571 	component_label.row = 0;
    572 	component_label.column = 0;
    573 	component_label.num_rows = 0;
    574 	component_label.num_columns = 0;
    575 	component_label.clean = 0;
    576 	component_label.status = 0;
    577 
    578 	do_ioctl( fd, RAIDFRAME_INIT_LABELS, &component_label,
    579 		  "RAIDFRAME_SET_COMPONENT_LABEL");
    580 }
    581 
    582 static void
    583 add_hot_spare(fd, component)
    584 	int fd;
    585 	char *component;
    586 {
    587 	RF_SingleComponent_t hot_spare;
    588 
    589 	hot_spare.row = 0;
    590 	hot_spare.column = 0;
    591 	strncpy(hot_spare.component_name, component,
    592 		sizeof(hot_spare.component_name));
    593 
    594 	do_ioctl( fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare,
    595 		  "RAIDFRAME_ADD_HOT_SPARE");
    596 }
    597 
    598 static void
    599 remove_hot_spare(fd, component)
    600 	int fd;
    601 	char *component;
    602 {
    603 	RF_SingleComponent_t hot_spare;
    604 	int component_num;
    605 	int num_cols;
    606 
    607 	get_component_number(fd, component, &component_num, &num_cols);
    608 
    609 	hot_spare.row = component_num / num_cols;
    610 	hot_spare.column = component_num % num_cols;
    611 
    612 	strncpy(hot_spare.component_name, component,
    613 		sizeof(hot_spare.component_name));
    614 
    615 	do_ioctl( fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare,
    616 		  "RAIDFRAME_REMOVE_HOT_SPARE");
    617 }
    618 
    619 static void
    620 rebuild_in_place( fd, component )
    621 	int fd;
    622 	char *component;
    623 {
    624 	RF_SingleComponent_t comp;
    625 	int component_num;
    626 	int num_cols;
    627 
    628 	get_component_number(fd, component, &component_num, &num_cols);
    629 
    630 	comp.row = 0;
    631 	comp.column = component_num;
    632 	strncpy(comp.component_name, component, sizeof(comp.component_name));
    633 
    634 	do_ioctl( fd, RAIDFRAME_REBUILD_IN_PLACE, &comp,
    635 		  "RAIDFRAME_REBUILD_IN_PLACE");
    636 
    637 	if (verbose) {
    638 		printf("Reconstruction status:\n");
    639 		sleep(3); /* XXX give reconstruction a chance to start */
    640 		do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS);
    641 	}
    642 
    643 }
    644 
    645 static void
    646 check_parity( fd, do_rewrite, dev_name )
    647 	int fd;
    648 	int do_rewrite;
    649 	char *dev_name;
    650 {
    651 	int is_clean;
    652 	int percent_done;
    653 
    654 	is_clean = 0;
    655 	percent_done = 0;
    656 	do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean,
    657 		 "RAIDFRAME_CHECK_PARITY");
    658 	if (is_clean) {
    659 		printf("%s: Parity status: clean\n",dev_name);
    660 	} else {
    661 		printf("%s: Parity status: DIRTY\n",dev_name);
    662 		if (do_rewrite) {
    663 			printf("%s: Initiating re-write of parity\n",
    664 			       dev_name);
    665 			do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
    666 				 "RAIDFRAME_REWRITEPARITY");
    667 			sleep(3); /* XXX give it time to
    668 				     get started. */
    669 			if (verbose) {
    670 				printf("Parity Re-write status:\n");
    671 				do_meter(fd,
    672 					 RAIDFRAME_CHECK_PARITYREWRITE_STATUS);
    673 			} else {
    674 				do_ioctl(fd,
    675 					 RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
    676 					 &percent_done,
    677 					 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"
    678 					 );
    679 				while( percent_done < 100 ) {
    680 					do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
    681 						 &percent_done, "RAIDFRAME_CHECK_PARITYREWRITE_STATUS");
    682 				}
    683 
    684 			}
    685 			       printf("%s: Parity Re-write complete\n",
    686 				      dev_name);
    687 		} else {
    688 			/* parity is wrong, and is not being fixed.
    689 			   Exit w/ an error. */
    690 			exit(1);
    691 		}
    692 	}
    693 }
    694 
    695 
    696 static void
    697 check_status( fd )
    698 	int fd;
    699 {
    700 	int recon_percent_done = 0;
    701 	int parity_percent_done = 0;
    702 	int copyback_percent_done = 0;
    703 
    704 	do_ioctl(fd, RAIDFRAME_CHECK_RECON_STATUS, &recon_percent_done,
    705 		 "RAIDFRAME_CHECK_RECON_STATUS");
    706 	printf("Reconstruction is %d%% complete.\n", recon_percent_done);
    707 	do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
    708 		 &parity_percent_done,
    709 		 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS");
    710 	printf("Parity Re-write is %d%% complete.\n", parity_percent_done);
    711 	do_ioctl(fd, RAIDFRAME_CHECK_COPYBACK_STATUS, &copyback_percent_done,
    712 		 "RAIDFRAME_CHECK_COPYBACK_STATUS");
    713 	printf("Copyback is %d%% complete.\n", copyback_percent_done);
    714 
    715 	/* These 3 should be mutually exclusive at this point */
    716 	if (recon_percent_done < 100) {
    717 		printf("Reconstruction status:\n");
    718 		do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS);
    719 	} else if (parity_percent_done < 100) {
    720 		printf("Parity Re-write status:\n");
    721 		do_meter(fd,RAIDFRAME_CHECK_PARITYREWRITE_STATUS);
    722 	} else if (copyback_percent_done < 100) {
    723 		printf("Copyback status:\n");
    724 		do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS);
    725 	}
    726 }
    727 
    728 char *tbits = "|/-\\";
    729 
    730 static void
    731 do_meter( fd, option )
    732 	int fd;
    733 	int option;
    734 {
    735 	int percent_done;
    736 	int last_percent;
    737 	int start_percent;
    738 	struct timeval start_time;
    739 	struct timeval last_time;
    740 	struct timeval current_time;
    741 	double elapsed;
    742 	int elapsed_sec;
    743 	int elapsed_usec;
    744 	int simple_eta,last_eta;
    745 	double rate;
    746 	int amount;
    747 	int tbit_value;
    748 	int wait_for_more_data;
    749 	char buffer[1024];
    750 	char bar_buffer[1024];
    751 	char eta_buffer[1024];
    752 
    753 	if (gettimeofday(&start_time,NULL)) {
    754 		fprintf(stderr,"%s: gettimeofday failed!?!?\n",__progname);
    755 		exit(errno);
    756 	}
    757 	percent_done = 0;
    758 	do_ioctl( fd, option, &percent_done, "");
    759 	last_percent = percent_done;
    760 	start_percent = percent_done;
    761 	last_time = start_time;
    762 	current_time = start_time;
    763 
    764 	wait_for_more_data = 0;
    765 	tbit_value = 0;
    766 
    767 	while(percent_done < 100) {
    768 
    769 		get_bar(bar_buffer, percent_done, 40);
    770 
    771 		elapsed_sec = current_time.tv_sec - last_time.tv_sec;
    772 
    773 		elapsed_usec = current_time.tv_usec - last_time.tv_usec;
    774 
    775 		if (elapsed_usec < 0) {
    776 			elapsed_usec-=1000000;
    777 			elapsed_sec++;
    778 		}
    779 
    780 		elapsed = (double) elapsed_sec +
    781 			(double) elapsed_usec / 1000000.0;
    782 		if (elapsed <= 0.0) {
    783 			elapsed = 0.0001; /* XXX */
    784 		}
    785 
    786 		amount = percent_done - last_percent;
    787 		if (amount <= 0) { /* we don't do negatives (yet?) */
    788 			amount = 0;
    789 			wait_for_more_data = 1;
    790 		} else {
    791 			wait_for_more_data = 0;
    792 		}
    793 		rate = amount / elapsed;
    794 
    795 
    796 		if (rate > 0.0) {
    797 			simple_eta = (int) ((100.0 - (double) last_percent ) / rate);
    798 		} else {
    799 			simple_eta = -1;
    800 		}
    801 		if (simple_eta <=0) {
    802 			simple_eta = last_eta;
    803 		} else {
    804 			last_eta = simple_eta;
    805 		}
    806 
    807 		get_time_string(eta_buffer, simple_eta);
    808 
    809 		snprintf(buffer,1024,"\r%3d%% |%s| ETA: %s %c",
    810 			 percent_done,bar_buffer,eta_buffer,tbits[tbit_value]);
    811 
    812 		write(fileno(stdout),buffer,strlen(buffer));
    813 		fflush(stdout);
    814 
    815 		/* resolution wasn't high enough... wait until we get another
    816 		   timestamp and perhaps more "work" done. */
    817 
    818 		if (!wait_for_more_data) {
    819 			last_time = current_time;
    820 			last_percent = percent_done;
    821 		}
    822 
    823 		if (++tbit_value>3)
    824 			tbit_value = 0;
    825 
    826 		sleep(2);
    827 
    828 		if (gettimeofday(&current_time,NULL)) {
    829 			fprintf(stderr,"%s: gettimeofday failed!?!?\n",
    830 				__progname);
    831 			exit(errno);
    832 		}
    833 
    834 		do_ioctl( fd, option, &percent_done, "");
    835 
    836 
    837 	}
    838 	printf("\n");
    839 }
    840 /* 40 '*''s per line, then 40 ' ''s line. */
    841 /* If you've got a screen wider than 160 characters, "tough" */
    842 
    843 #define STAR_MIDPOINT 4*40
    844 const char stars[] = "****************************************"
    845                      "****************************************"
    846                      "****************************************"
    847                      "****************************************"
    848                      "                                        "
    849                      "                                        "
    850                      "                                        "
    851                      "                                        "
    852                      "                                        ";
    853 
    854 static void
    855 get_bar(string,percent,max_strlen)
    856 	char *string;
    857 	double percent;
    858 	int max_strlen;
    859 {
    860 	int offset;
    861 
    862 	if (max_strlen > STAR_MIDPOINT) {
    863 		max_strlen = STAR_MIDPOINT;
    864 	}
    865 	offset = STAR_MIDPOINT -
    866 		(int)((percent * max_strlen)/ 100);
    867 	if (offset < 0)
    868 		offset = 0;
    869 	snprintf(string,max_strlen,"%s",&stars[offset]);
    870 }
    871 
    872 static void
    873 get_time_string(string,simple_time)
    874 	char *string;
    875 	int simple_time;
    876 {
    877 	int minutes, seconds, hours;
    878 	char hours_buffer[5];
    879 	char minutes_buffer[5];
    880 	char seconds_buffer[5];
    881 
    882 	if (simple_time >= 0) {
    883 
    884 		minutes = (int) simple_time / 60;
    885 		seconds = ((int)simple_time - 60*minutes);
    886 		hours = minutes / 60;
    887 		minutes = minutes - 60*hours;
    888 
    889 		if (hours > 0) {
    890 			snprintf(hours_buffer,5,"%02d:",hours);
    891 		} else {
    892 			snprintf(hours_buffer,5,"   ");
    893 		}
    894 
    895 		snprintf(minutes_buffer,5,"%02d:",minutes);
    896 		snprintf(seconds_buffer,5,"%02d",seconds);
    897 		snprintf(string,1024,"%s%s%s",
    898 			 hours_buffer, minutes_buffer, seconds_buffer);
    899 	} else {
    900 		snprintf(string,1024,"   --:--");
    901 	}
    902 
    903 }
    904 
    905 static void
    906 usage()
    907 {
    908 	fprintf(stderr, "usage: %s [-v] -a component dev\n", __progname);
    909 	fprintf(stderr, "       %s [-v] -B dev\n", __progname);
    910 	fprintf(stderr, "       %s [-v] -c config_file dev\n", __progname);
    911 	fprintf(stderr, "       %s [-v] -C config_file dev\n", __progname);
    912 	fprintf(stderr, "       %s [-v] -f component dev\n", __progname);
    913 	fprintf(stderr, "       %s [-v] -F component dev\n", __progname);
    914 	fprintf(stderr, "       %s [-v] -g component dev\n", __progname);
    915 	fprintf(stderr, "       %s [-v] -i dev\n", __progname);
    916 	fprintf(stderr, "       %s [-v] -I serial_number dev\n", __progname);
    917 	fprintf(stderr, "       %s [-v] -r component dev\n", __progname);
    918 	fprintf(stderr, "       %s [-v] -R component dev\n", __progname);
    919 	fprintf(stderr, "       %s [-v] -s dev\n", __progname);
    920 	fprintf(stderr, "       %s [-v] -S dev\n", __progname);
    921 	fprintf(stderr, "       %s [-v] -u dev\n", __progname);
    922 #if 0
    923 	fprintf(stderr, "usage: %s %s\n", __progname,
    924 		"-a | -f | -F | -g | -r | -R component dev");
    925 	fprintf(stderr, "       %s -B | -i | -s | -S -u dev\n", __progname);
    926 	fprintf(stderr, "       %s -c | -C config_file dev\n", __progname);
    927 	fprintf(stderr, "       %s -I serial_number dev\n", __progname);
    928 #endif
    929 	exit(1);
    930 	/* NOTREACHED */
    931 }
    932