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 66extern char *__progname; 67 68int main __P((int, char *[])); 69void do_ioctl __P((int, unsigned long, void *, char *)); 70static void rf_configure __P((int, char*, int)); 71static char *device_status __P((RF_DiskStatus_t)); 72static void rf_get_device_status __P((int)); 73static void get_component_number __P((int, char *, int *, int *)); 74static void rf_fail_disk __P((int, char *, int)); 75static void usage __P((void)); 76static void get_component_label __P((int, char *)); 77static void set_component_label __P((int, char *)); 78static void init_component_labels __P((int, int)); 79static void add_hot_spare __P((int, char *)); 80static void remove_hot_spare __P((int, char *)); 81static void rebuild_in_place __P((int, char *)); 82static void check_status __P((int)); 83static void check_parity __P((int,int,char *)); 84static void do_meter __P((int, int)); 85static void get_bar __P((char *, double, int)); 86static void get_time_string __P((char *, int)); 87 88int verbose = 0; 89 90int 91main(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 320void 321do_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 335static void 336rf_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 364static char * 365device_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 399static void 400rf_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 437static void 438get_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 473static void 474rf_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 501static void 502get_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 533static void 534set_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 561static void 562init_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 582static void 583add_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 598static void 599remove_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 619static void 620rebuild_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 645static void 646check_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 696static void 697check_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, ©back_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 728char *tbits = "|/-\\"; 729 730static void 731do_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(¤t_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 844const char stars[] = "****************************************" 845 "****************************************" 846 "****************************************" 847 "****************************************" 848 " " 849 " " 850 " " 851 " " 852 " "; 853 854static void 855get_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 872static void 873get_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 905static void 906usage() 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