1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * raidctl.c is the entry file of RAID configuration utility. 26 */ 27 28 #include <ctype.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <fcntl.h> 32 #include <langinfo.h> 33 #include <regex.h> 34 #include <locale.h> 35 #include <libintl.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <strings.h> 40 #include <unistd.h> 41 #include <errno.h> 42 #include <libgen.h> 43 #include <raidcfg.h> 44 45 46 #define TRUE 1 47 #define FALSE 0 48 49 #ifndef TEXT_DOMAIN 50 #define TEXT_DOMAIN "SYS_TEST" 51 #endif 52 53 /* 54 * Return value of command 55 */ 56 #define SUCCESS 0 57 #define INVALID_ARG 1 58 #define FAILURE 2 59 60 /* 61 * Initial value of variables 62 */ 63 #define INIT_HANDLE_VALUE -3 64 #define MAX64BIT 0xffffffffffffffffull 65 #define MAX32BIT 0xfffffffful 66 67 /* 68 * Flag of set or unset HSP 69 */ 70 #define HSP_SET 1 71 #define HSP_UNSET 0 72 73 /* 74 * Operate codes of command 75 */ 76 #define DO_HW_RAID_NOP -1 77 #define DO_HW_RAID_HELP 0 78 #define DO_HW_RAID_CREATEO 1 79 #define DO_HW_RAID_CREATEN 2 80 #define DO_HW_RAID_DELETE 3 81 #define DO_HW_RAID_LIST 4 82 #define DO_HW_RAID_FLASH 5 83 #define DO_HW_RAID_HSP 6 84 #define DO_HW_RAID_SET_ATTR 7 85 #define DO_HW_RAID_SNAPSHOT 8 86 87 #define LOWER_H (1 << 0) 88 #define LOWER_C (1 << 1) 89 #define LOWER_D (1 << 2) 90 #define LOWER_L (1 << 3) 91 #define LOWER_R (1 << 4) 92 #define LOWER_Z (1 << 5) 93 #define LOWER_G (1 << 6) 94 #define LOWER_A (1 << 7) 95 #define LOWER_S (1 << 8) 96 #define LOWER_P (1 << 9) 97 #define LOWER_F (1 << 10) 98 #define UPPER_S (1 << 11) 99 #define UPPER_C (1 << 12) 100 #define UPPER_F (1 << 13) 101 102 /* Add a ARRAY state (temporary) */ 103 #define ARRAY_STATE_SYNC 100 104 105 /* 106 * Function and strings to properly localize our prompt. 107 * So for example in German it would ask (ja/nein) or (yes/no) in 108 * english. 109 */ 110 #ifndef SCHAR_MAX 111 #define SCHAR_MAX 10 112 #endif 113 114 #define RAIDCTL_LOCKF "/var/run/lockf_raidctl" 115 116 /* Locale setting */ 117 static int yes(void); 118 static int rpmatch(char *s); 119 static char *yesstr = NULL; 120 static char *nostr = NULL; 121 static char *yesexpr = NULL; 122 123 static char *default_yesexpr = "^[yY]"; 124 static char *default_yesstr = "yes"; 125 static char *default_nostr = "no"; 126 127 static regex_t re; 128 129 #define SET_DEFAULT_STRS \ 130 regfree(&re); \ 131 free(yesexpr); \ 132 free(yesstr); \ 133 free(nostr); \ 134 yesexpr = default_yesexpr; \ 135 yesstr = default_yesstr; \ 136 nostr = default_nostr; 137 138 #define FREE_STRS \ 139 if (yesexpr != default_yesexpr) \ 140 free(yesexpr); \ 141 if (yesstr != default_yesstr) \ 142 free(yesstr); \ 143 if (nostr != default_nostr) \ 144 free(nostr); 145 146 /* program name */ 147 static char *prog_namep; 148 149 150 /* 151 * Functions declaration 152 */ 153 static void helpinfo(char *prog_namep); 154 static int do_create_cidl(char *raid_levelp, char *capacityp, char *disk_argp, 155 char *stripe_sizep, uint32_t f_flag, char **argv, uint32_t optind); 156 static int do_create_ctd(char *raid_levelp, char **disks_argpp, 157 uint32_t disks_num, uint32_t argindex, uint32_t f_flag); 158 static int do_list(char *disk_argp, char **argv, uint32_t optind, 159 uint8_t is_snapshot); 160 static int do_delete(uint32_t f_flag, char **argv, uint32_t optind); 161 static int do_flash(uint8_t f_flag, char *filep, char **ctls_argpp, 162 uint32_t index, uint32_t ctl_num); 163 static int do_set_hsp(char *a_argp, char *disk_argp, char **argv, 164 uint32_t optind); 165 static int do_set_array_attr(uint32_t f_flag, char *p_argp, char **argv, 166 uint32_t optind); 167 static int snapshot_raidsystem(uint8_t recursive, uint8_t indent, 168 uint8_t is_snapshot); 169 static int snapshot_ctl(raid_obj_handle_t ctl_handle, uint8_t recursive, 170 uint8_t indent, uint8_t is_snapshot); 171 static int snapshot_array(raid_obj_handle_t array_handle, 172 uint8_t indent, uint8_t is_sub, uint8_t is_snapshot); 173 static int snapshot_disk(uint32_t ctl_tag, raid_obj_handle_t disk_handle, 174 uint8_t indent, uint8_t is_snapshot); 175 static int print_ctl_table(raid_obj_handle_t ctl_handle); 176 static int print_array_table(raid_obj_handle_t ctl_handle, 177 raid_obj_handle_t array_handle); 178 static int print_disk_table(raid_obj_handle_t ctl_handle, 179 raid_obj_handle_t disk_handle); 180 static int print_ctl_attr(raidcfg_controller_t *attrp); 181 static int print_array_attr(raidcfg_array_t *attrp); 182 static int print_arraypart_attr(raidcfg_arraypart_t *attrp); 183 static int print_disk_attr(raid_obj_handle_t ctl_handle, 184 raid_obj_handle_t disk_handle, raidcfg_disk_t *attrp); 185 static void print_indent(uint8_t indent); 186 static int get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp, 187 int *comps_nump, raid_obj_handle_t **handlespp); 188 static int get_disk_handle_ctd(int disks_num, char **disks_argpp, 189 uint32_t *ctl_tagp, raid_obj_handle_t *disks_handlep); 190 static int get_ctl_tag(char *argp, uint32_t *ctl_tagp); 191 static int get_array_tag(char *argp, uint32_t *ctl_tagp, 192 array_tag_t *array_tagp); 193 static int get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp, 194 uint32_t *controller_id); 195 static int get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp); 196 static int calc_size(char *sizep, uint64_t *valp); 197 static int is_fully_numeric(char *strp); 198 static int size_to_string(uint64_t size, char *string, int len); 199 static int enter_raidctl_lock(int *fd); 200 static void exit_raidctl_lock(int fd); 201 202 /* 203 * Entry function of raidctl command 204 */ 205 int 206 main(int argc, char **argv) 207 { 208 /* operation index */ 209 int8_t findex = DO_HW_RAID_NOP; 210 211 /* argument pointers */ 212 char *r_argp = NULL; 213 char *z_argp = NULL; 214 char *g_argp = NULL; 215 char *a_argp = NULL; 216 char *s_argp = NULL; 217 char *p_argp = NULL; 218 char *F_argp = NULL; 219 char *C_argp = NULL; 220 221 /* 222 * operation flags. 223 */ 224 uint8_t r_flag = FALSE; 225 uint8_t f_flag = FALSE; 226 uint8_t action = FALSE; 227 uint64_t options = 0; 228 229 /* index and temporary variables */ 230 int ret; 231 int status; 232 char c = '\0'; 233 234 /* fd for the filelock */ 235 int fd; 236 237 if (enter_raidctl_lock(&fd) != SUCCESS) { 238 return (FAILURE); 239 } 240 241 (void) setlocale(LC_ALL, ""); 242 (void) textdomain(TEXT_DOMAIN); 243 244 /* parse command line, and get program name */ 245 if ((prog_namep = strrchr(argv[0], '/')) == NULL) { 246 prog_namep = argv[0]; 247 } else { 248 prog_namep++; 249 } 250 251 /* close error option messages from getopt */ 252 opterr = 0; 253 254 /* get yes expression according to current locale */ 255 yesexpr = strdup(nl_langinfo(YESEXPR)); 256 yesstr = strdup(nl_langinfo(YESSTR)); 257 nostr = strdup(nl_langinfo(NOSTR)); 258 if (yesexpr == NULL || yesstr == NULL || nostr == NULL) { 259 return (FAILURE); 260 } 261 262 /* 263 * If the was no expression or if there is a compile error 264 * use default yes expression. 265 */ 266 status = regcomp(&re, yesexpr, REG_EXTENDED | REG_NOSUB); 267 if ((*yesexpr == '\0') || 268 (*yesstr == '\0') || 269 (*nostr == '\0') || 270 (status != 0)) { 271 SET_DEFAULT_STRS; 272 if (regcomp(&re, default_yesexpr, 273 REG_EXTENDED | REG_NOSUB) != 0) { 274 return (FALSE); 275 } 276 } 277 278 while ((c = getopt(argc, argv, 279 "?hC:cdlF:r:z:g:a:s:p:fS")) != EOF) { 280 switch (c) { 281 case 'h': 282 case '?': 283 if (action == FALSE) { 284 findex = DO_HW_RAID_HELP; 285 action = TRUE; 286 options |= LOWER_H; 287 } else { 288 findex = DO_HW_RAID_NOP; 289 } 290 break; 291 case 'C': 292 if (action == FALSE) { 293 findex = DO_HW_RAID_CREATEN; 294 C_argp = optarg; 295 action = TRUE; 296 options |= UPPER_C; 297 } else { 298 findex = DO_HW_RAID_NOP; 299 } 300 break; 301 case 'c': 302 if (action == FALSE) { 303 findex = DO_HW_RAID_CREATEO; 304 action = TRUE; 305 options |= LOWER_C; 306 } else { 307 findex = DO_HW_RAID_NOP; 308 } 309 break; 310 case 'd': 311 if (action == FALSE) { 312 findex = DO_HW_RAID_DELETE; 313 action = TRUE; 314 options |= LOWER_D; 315 } else { 316 findex = DO_HW_RAID_NOP; 317 } 318 break; 319 case 'l': 320 if (action == FALSE) { 321 findex = DO_HW_RAID_LIST; 322 action = TRUE; 323 options |= LOWER_L; 324 } else { 325 findex = DO_HW_RAID_NOP; 326 } 327 break; 328 case 'F': 329 if (action == FALSE) { 330 findex = DO_HW_RAID_FLASH; 331 F_argp = optarg; 332 action = TRUE; 333 options |= UPPER_F; 334 } else { 335 findex = DO_HW_RAID_NOP; 336 } 337 break; 338 case 'a': 339 if (action == FALSE) { 340 findex = DO_HW_RAID_HSP; 341 a_argp = optarg; 342 action = TRUE; 343 options |= LOWER_A; 344 } else { 345 findex = DO_HW_RAID_NOP; 346 } 347 break; 348 case 'p': 349 if (action == FALSE) { 350 findex = DO_HW_RAID_SET_ATTR; 351 p_argp = optarg; 352 action = TRUE; 353 options |= LOWER_P; 354 } else { 355 findex = DO_HW_RAID_NOP; 356 } 357 break; 358 case 'r': 359 r_argp = optarg; 360 r_flag = TRUE; 361 options |= LOWER_R; 362 break; 363 case 'z': 364 z_argp = optarg; 365 options |= LOWER_Z; 366 break; 367 case 'g': 368 g_argp = optarg; 369 options |= LOWER_G; 370 break; 371 case 's': 372 s_argp = optarg; 373 options |= LOWER_S; 374 break; 375 case 'f': 376 f_flag = TRUE; 377 options |= LOWER_F; 378 break; 379 case 'S': 380 if (action == FALSE) { 381 findex = DO_HW_RAID_SNAPSHOT; 382 action = TRUE; 383 options |= UPPER_S; 384 } else { 385 findex = DO_HW_RAID_NOP; 386 } 387 break; 388 default: 389 (void) fprintf(stderr, 390 gettext("Invalid argument(s).\n")); 391 exit_raidctl_lock(fd); 392 FREE_STRS; 393 regfree(&re); 394 return (INVALID_ARG); 395 } 396 } 397 398 /* parse options */ 399 switch (findex) { 400 case DO_HW_RAID_HELP: 401 if ((options & ~(LOWER_H)) != 0) { 402 ret = INVALID_ARG; 403 } else { 404 helpinfo(prog_namep); 405 ret = SUCCESS; 406 } 407 break; 408 case DO_HW_RAID_CREATEO: 409 if ((options & ~(LOWER_F | LOWER_C | LOWER_R)) != 0) { 410 ret = INVALID_ARG; 411 } else { 412 if (r_flag != FALSE && f_flag == FALSE) { 413 ret = do_create_ctd(r_argp, argv, argc - 4, 414 optind, f_flag); 415 } else if (r_flag == FALSE && f_flag == FALSE) { 416 ret = do_create_ctd(NULL, argv, argc - 2, 417 optind, f_flag); 418 } else if (r_flag != FALSE && f_flag != FALSE) { 419 ret = do_create_ctd(r_argp, argv, argc - 5, 420 optind, f_flag); 421 } else { 422 ret = do_create_ctd(NULL, argv, argc - 3, 423 optind, f_flag); 424 } 425 } 426 break; 427 case DO_HW_RAID_CREATEN: 428 if ((options & ~(LOWER_F | UPPER_C | LOWER_R | LOWER_Z | 429 LOWER_S)) != 0) { 430 ret = INVALID_ARG; 431 } else { 432 ret = do_create_cidl(r_argp, z_argp, C_argp, s_argp, 433 f_flag, argv, optind); 434 } 435 break; 436 case DO_HW_RAID_DELETE: 437 if ((options & ~(LOWER_F | LOWER_D)) != 0) { 438 ret = INVALID_ARG; 439 } else { 440 ret = do_delete(f_flag, argv, optind); 441 } 442 break; 443 case DO_HW_RAID_LIST: 444 if ((options & ~(LOWER_L | LOWER_G)) != 0) { 445 ret = INVALID_ARG; 446 } else { 447 ret = do_list(g_argp, argv, optind, FALSE); 448 } 449 break; 450 case DO_HW_RAID_SNAPSHOT: 451 if ((options & ~(UPPER_S | LOWER_G)) != 0) { 452 ret = INVALID_ARG; 453 } else { 454 ret = do_list(g_argp, argv, optind, TRUE); 455 } 456 break; 457 case DO_HW_RAID_FLASH: 458 if ((options & ~(LOWER_F | UPPER_F)) != 0) { 459 ret = INVALID_ARG; 460 } else { 461 if (f_flag == FALSE) { 462 ret = do_flash(f_flag, F_argp, argv, optind, 463 argc - 3); 464 } else { 465 ret = do_flash(f_flag, F_argp, argv, optind, 466 argc - 4); 467 } 468 } 469 break; 470 case DO_HW_RAID_HSP: 471 if ((options & ~(LOWER_A | LOWER_G)) != 0) { 472 ret = INVALID_ARG; 473 } else { 474 ret = do_set_hsp(a_argp, g_argp, argv, optind); 475 } 476 break; 477 case DO_HW_RAID_SET_ATTR: 478 if ((options & ~(LOWER_F | LOWER_P)) != 0) { 479 ret = INVALID_ARG; 480 } else { 481 ret = do_set_array_attr(f_flag, p_argp, argv, optind); 482 } 483 break; 484 case DO_HW_RAID_NOP: 485 if (argc == 1) { 486 ret = do_list(g_argp, argv, optind, FALSE); 487 } else { 488 ret = INVALID_ARG; 489 } 490 break; 491 default: 492 ret = INVALID_ARG; 493 break; 494 } 495 496 if (ret == INVALID_ARG) { 497 (void) fprintf(stderr, 498 gettext("Invalid argument(s).\n")); 499 } 500 exit_raidctl_lock(fd); 501 502 FREE_STRS; 503 regfree(&re); 504 return (ret); 505 } 506 507 /* 508 * helpinfo(prog_namep) 509 * This function prints help informations for usrs. 510 */ 511 static void 512 helpinfo(char *prog_namep) 513 { 514 char quote = '"'; 515 516 (void) printf(gettext("%s [-f] -C %c<disks>%c [-r <raid_level>] " 517 "[-z <capacity>] [-s <stripe_size>] <controller>\n"), prog_namep, 518 quote, quote); 519 520 (void) printf(gettext("%s [-f] -d <volume>\n"), prog_namep); 521 522 (void) printf(gettext("%s [-f] -F <filename> <controller1> " 523 "[<controller2> ...]\n"), prog_namep); 524 525 (void) printf(gettext("%s [-f] -p %c<param>=<value>%c <volume>\n"), 526 prog_namep, quote, quote); 527 528 (void) printf(gettext("%s [-f] -c [-r <raid_level>] <disk1> <disk2> " 529 "[<disk3> ...]\n"), prog_namep); 530 531 (void) printf(gettext("%s [-l]\n"), prog_namep); 532 533 (void) printf(gettext("%s -l -g <disk> <controller>\n"), prog_namep); 534 535 (void) printf(gettext("%s -l <volume>\n"), prog_namep); 536 537 (void) printf(gettext("%s -l <controller1> [<controller2> ...]\n"), 538 prog_namep); 539 540 (void) printf(gettext("%s -a {set | unset} -g <disk> " 541 "{<volume> | <controller>}\n"), prog_namep); 542 543 (void) printf(gettext("%s -S [<volume> | <controller>]\n"), prog_namep); 544 545 (void) printf(gettext("%s -S -g <disk> <controller>\n"), prog_namep); 546 547 (void) printf(gettext("%s -h\n"), prog_namep); 548 } 549 550 /* 551 * do_create_cidl(raid_levelp, capacityp, disks_argp, stripe_sizep, 552 * f_flag, argv, optind) 553 * This function creates a new RAID volume with specified arguments, 554 * and returns result as SUCCESS, INVALID_ARG or FAILURE. 555 * The "c.id.l" is used to express single physical disk. 'c' expresses 556 * bus number, 'id' expresses target number, and 'l' expresses lun. 557 * The physical disks represented by c.id.l may be invisible to OS, which 558 * means physical disks attached to controllers are not accessible by 559 * OS directly. The disks should be organized as a logical volume, and 560 * the logical volume is exported to OS as a single unit. Some hardware 561 * RAID controllers also support physical disks accessed by OS directly, 562 * for example LSI1068. In this case, it's both OK to express physical 563 * disk by c.id.l format or canonical ctd format. 564 */ 565 static int 566 do_create_cidl(char *raid_levelp, char *capacityp, char *disks_argp, 567 char *stripe_sizep, uint32_t f_flag, char **argv, uint32_t optind) 568 { 569 uint32_t ctl_tag = MAX32BIT; 570 raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; 571 uint32_t raid_level = RAID_LEVEL_1; 572 uint64_t capacity = 0; 573 uint64_t stripe_size = (uint64_t)OBJ_ATTR_NONE; 574 raid_obj_handle_t *disk_handlesp = NULL; 575 raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; 576 raidcfg_controller_t ctl_attr; 577 int comps_num = 0; 578 int ret = 0; 579 580 raidcfg_array_t array_attr; 581 582 if (argv[optind] == NULL || argv[optind + 1] != NULL) { 583 return (INVALID_ARG); 584 } 585 586 if (disks_argp == NULL) { 587 return (INVALID_ARG); 588 } 589 590 /* Check controller tag */ 591 if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) { 592 return (INVALID_ARG); 593 } 594 595 ctl_handle = raidcfg_get_controller(ctl_tag); 596 if (ctl_handle <= 0) { 597 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle)); 598 return (FAILURE); 599 } 600 601 if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { 602 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 603 return (FAILURE); 604 } 605 606 /* Get raid level */ 607 if (raid_levelp != NULL) { 608 if (*raid_levelp == '1' && 609 (*(raid_levelp + 1) == 'E' || *(raid_levelp + 1) == 'e')) { 610 raid_level = RAID_LEVEL_1E; 611 } else { 612 if (is_fully_numeric(raid_levelp) == FALSE) { 613 return (INVALID_ARG); 614 } 615 616 switch (atoi(raid_levelp)) { 617 case 0: 618 raid_level = RAID_LEVEL_0; 619 break; 620 case 1: 621 raid_level = RAID_LEVEL_1; 622 break; 623 case 5: 624 raid_level = RAID_LEVEL_5; 625 break; 626 case 10: 627 raid_level = RAID_LEVEL_10; 628 break; 629 case 50: 630 raid_level = RAID_LEVEL_50; 631 break; 632 default: 633 return (INVALID_ARG); 634 } 635 } 636 } 637 638 /* 639 * The rang check of capacity and stripe size is performed in library, 640 * and it relates to hardware feature. 641 */ 642 643 /* Capacity in bytes. Capacity 0 means max available space. */ 644 if (capacityp != NULL) { 645 if (*capacityp == '-' || 646 calc_size(capacityp, &capacity) != SUCCESS) { 647 return (INVALID_ARG); 648 } 649 } 650 651 /* Stripe size in bytes */ 652 if (stripe_sizep != NULL) { 653 if (calc_size(stripe_sizep, &stripe_size) != SUCCESS || 654 *stripe_sizep == '-') { 655 return (INVALID_ARG); 656 } 657 } 658 659 /* Open controller before accessing its object */ 660 if ((ret = raidcfg_open_controller(ctl_handle, NULL)) < 0) { 661 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 662 return (FAILURE); 663 } 664 665 /* Get disks' handles */ 666 if ((ret = get_disk_handle_cidl(ctl_tag, disks_argp, &comps_num, 667 &disk_handlesp)) != SUCCESS) { 668 (void) raidcfg_close_controller(ctl_handle, NULL); 669 return (ret); 670 } 671 672 if (f_flag == FALSE) { 673 (void) fprintf(stdout, gettext("Creating RAID volume " 674 "will destroy all data on spare space of member disks, " 675 "proceed (%s/%s)? "), yesstr, nostr); 676 if (!yes()) { 677 (void) fprintf(stdout, gettext("RAID volume " 678 "not created.\n\n")); 679 (void) raidcfg_close_controller(ctl_handle, NULL); 680 free(disk_handlesp); 681 return (SUCCESS); 682 } 683 } 684 685 /* Create array */ 686 array_handle = raidcfg_create_array(comps_num, 687 disk_handlesp, raid_level, capacity, stripe_size, NULL); 688 689 if (array_handle <= 0) { 690 (void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle)); 691 free(disk_handlesp); 692 (void) raidcfg_close_controller(ctl_handle, NULL); 693 return (FAILURE); 694 } 695 696 /* Get attribute of the new created array */ 697 if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) { 698 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 699 free(disk_handlesp); 700 (void) raidcfg_close_controller(ctl_handle, NULL); 701 return (FAILURE); 702 } 703 704 (void) fprintf(stdout, gettext("Volume c%ut%llud%llu is created " 705 "successfully!\n"), ctl_tag, array_attr.tag.idl.target_id, 706 array_attr.tag.idl.lun); 707 708 /* Print attribute of array */ 709 (void) print_array_table(ctl_handle, array_handle); 710 711 /* Close controller */ 712 (void) raidcfg_close_controller(ctl_handle, NULL); 713 714 free(disk_handlesp); 715 return (SUCCESS); 716 } 717 718 /* 719 * do_create_ctd(raid_levelp, disks_argpp, disks_num, argindex, f_flag) 720 * This function creates array with specified arguments, and return result 721 * as SUCCESS, FAILURE, or INVALID_ARG. It only supports LSI MPT controller 722 * to be compatible with old raidctl. The capacity and stripe size can't 723 * be specified for LSI MPT controller, and they use zero and default value. 724 * The "ctd" is the canonical expression of physical disks which are 725 * accessible by OS. 726 */ 727 static int 728 do_create_ctd(char *raid_levelp, char **disks_argpp, uint32_t disks_num, 729 uint32_t argindex, uint32_t f_flag) 730 { 731 uint32_t ctl_tag = MAX32BIT; 732 raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; 733 uint32_t raid_level = RAID_LEVEL_1; 734 uint64_t capacity = 0; 735 uint32_t stripe_size = (uint32_t)OBJ_ATTR_NONE; 736 raid_obj_handle_t *disk_handlesp = NULL; 737 raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; 738 raidcfg_controller_t ctl_attr; 739 int ret; 740 741 raidcfg_array_t array_attr; 742 int i, j; 743 744 /* Check disks parameter */ 745 if (disks_argpp == NULL || disks_num < 2) { 746 return (INVALID_ARG); 747 } 748 749 for (i = 0, j = argindex; i < disks_num; i++, j++) { 750 if (disks_argpp[j] == NULL) { 751 return (INVALID_ARG); 752 } 753 } 754 755 /* 756 * We need check if the raid_level string is fully numeric. If user 757 * input string with unsupported letters, such as "s10", atoi() will 758 * return zero because it is an illegal string, but it doesn't mean 759 * RAID_LEVEL_0. 760 */ 761 if (raid_levelp != NULL) { 762 if (*raid_levelp == '1' && 763 (*(raid_levelp + 1) == 'E' || *(raid_levelp + 1) == 'e')) { 764 raid_level = RAID_LEVEL_1E; 765 } else { 766 if (is_fully_numeric(raid_levelp) == FALSE) { 767 return (INVALID_ARG); 768 } 769 770 switch (atoi(raid_levelp)) { 771 case 0: 772 raid_level = RAID_LEVEL_0; 773 break; 774 case 1: 775 raid_level = RAID_LEVEL_1; 776 break; 777 case 5: 778 raid_level = RAID_LEVEL_5; 779 break; 780 default: 781 return (INVALID_ARG); 782 } 783 } 784 } 785 786 /* Get disks tag and controller tag */ 787 disk_handlesp = (raid_obj_handle_t *)calloc(disks_num + 2, 788 sizeof (raid_obj_handle_t)); 789 if (disk_handlesp == NULL) { 790 return (FAILURE); 791 } 792 793 disk_handlesp[0] = OBJ_SEPARATOR_BEGIN; 794 disk_handlesp[disks_num + 1] = OBJ_SEPARATOR_END; 795 796 if ((ret = get_disk_handle_ctd(disks_num, &disks_argpp[argindex], 797 &ctl_tag, &disk_handlesp[1])) != SUCCESS) { 798 free(disk_handlesp); 799 return (ret); 800 } 801 802 /* LIB API should check whether all disks here belong to one ctl. */ 803 /* get_disk_handle_ctd has opened controller. */ 804 ctl_handle = raidcfg_get_controller(ctl_tag); 805 806 if (ctl_handle <= 0) { 807 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle)); 808 (void) raidcfg_close_controller(ctl_handle, NULL); 809 free(disk_handlesp); 810 return (FAILURE); 811 } 812 813 /* Check if the controller is host raid type */ 814 if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { 815 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 816 (void) raidcfg_close_controller(ctl_handle, NULL); 817 free(disk_handlesp); 818 return (FAILURE); 819 } 820 821 if ((ctl_attr.capability & RAID_CAP_DISK_TRANS) == 0) { 822 /* -c only support host raid controller, return failure here */ 823 (void) fprintf(stderr, 824 gettext("Option -c only supports host raid controller.\n")); 825 (void) raidcfg_close_controller(ctl_handle, NULL); 826 free(disk_handlesp); 827 return (FAILURE); 828 } 829 830 if (f_flag == FALSE) { 831 (void) fprintf(stdout, gettext("Creating RAID volume " 832 "will destroy all data on spare space of member disks, " 833 "proceed (%s/%s)? "), yesstr, nostr); 834 if (!yes()) { 835 (void) fprintf(stdout, gettext("RAID volume " 836 "not created.\n\n")); 837 free(disk_handlesp); 838 (void) raidcfg_close_controller(ctl_handle, NULL); 839 return (SUCCESS); 840 } 841 } 842 843 /* 844 * For old raidctl, capacity is 0, which means to creates 845 * max possible capacity of array. 846 */ 847 848 array_handle = raidcfg_create_array(disks_num + 2, 849 disk_handlesp, raid_level, capacity, stripe_size, NULL); 850 851 if (array_handle <= 0) { 852 (void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle)); 853 free(disk_handlesp); 854 (void) raidcfg_close_controller(ctl_handle, NULL); 855 return (FAILURE); 856 } 857 858 /* Get attribute of array */ 859 if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) { 860 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 861 free(disk_handlesp); 862 (void) raidcfg_close_controller(ctl_handle, NULL); 863 return (FAILURE); 864 } 865 866 /* Close controller */ 867 (void) raidcfg_close_controller(ctl_handle, NULL); 868 869 /* Print feedback for user */ 870 (void) fprintf(stdout, 871 gettext("Volume c%ut%llud%llu is created successfully!\n"), 872 ctl_tag, array_attr.tag.idl.target_id, 873 array_attr.tag.idl.lun); 874 free(disk_handlesp); 875 return (SUCCESS); 876 } 877 878 /* 879 * do_list(disk_arg, argv, optind, is_snapshot) 880 * This function lists RAID's system configuration. It supports various RAID 881 * controller. The return value can be SUCCESS, FAILURE, or INVALID_ARG. 882 */ 883 static int 884 do_list(char *disk_argp, char **argv, uint32_t optind, uint8_t is_snapshot) 885 { 886 uint32_t ctl_tag = MAX32BIT; 887 raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; 888 raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE; 889 raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; 890 disk_tag_t disk_tag; 891 array_tag_t array_tag; 892 893 int ret; 894 895 /* print RAID system */ 896 if (disk_argp == NULL) { 897 if (argv[optind] == NULL) { 898 ret = snapshot_raidsystem(TRUE, 0, is_snapshot); 899 return (ret); 900 } else { 901 if (is_fully_numeric(argv[optind]) == TRUE) { 902 while (argv[optind] != NULL) { 903 if (get_ctl_tag(argv[optind], &ctl_tag) 904 != SUCCESS) { 905 ret = INVALID_ARG; 906 optind++; 907 continue; 908 } 909 ctl_handle = 910 raidcfg_get_controller(ctl_tag); 911 if (ctl_handle <= 0) { 912 (void) fprintf(stderr, "%s\n", 913 raidcfg_errstr(ctl_handle)); 914 ret = FAILURE; 915 optind++; 916 continue; 917 } 918 ret = 919 raidcfg_open_controller(ctl_handle, 920 NULL); 921 if (ret < 0) { 922 (void) fprintf(stderr, "%s\n", 923 raidcfg_errstr(ret)); 924 ret = FAILURE; 925 optind++; 926 continue; 927 } 928 if (is_snapshot == FALSE) { 929 ret = 930 print_ctl_table(ctl_handle); 931 } else { 932 ret = 933 snapshot_ctl(ctl_handle, 934 FALSE, 0, is_snapshot); 935 } 936 (void) raidcfg_close_controller( 937 ctl_handle, NULL); 938 optind++; 939 } 940 } else { 941 if (get_array_tag(argv[optind], 942 &ctl_tag, &array_tag) != SUCCESS) { 943 return (INVALID_ARG); 944 } 945 ctl_handle = raidcfg_get_controller(ctl_tag); 946 if (ctl_handle <= 0) { 947 (void) fprintf(stderr, "%s\n", 948 raidcfg_errstr(ctl_handle)); 949 return (FAILURE); 950 } 951 952 ret = raidcfg_open_controller(ctl_handle, NULL); 953 if (ret < 0) { 954 (void) fprintf(stderr, "%s\n", 955 raidcfg_errstr(ret)); 956 return (FAILURE); 957 } 958 959 array_handle = raidcfg_get_array(ctl_handle, 960 array_tag.idl.target_id, array_tag.idl.lun); 961 if (array_handle <= 0) { 962 (void) fprintf(stderr, "%s\n", 963 raidcfg_errstr(array_handle)); 964 (void) raidcfg_close_controller( 965 ctl_handle, NULL); 966 return (FAILURE); 967 } 968 if (is_snapshot == FALSE) { 969 ret = print_array_table(ctl_handle, 970 array_handle); 971 } else { 972 ret = snapshot_array(array_handle, 0, 973 FALSE, is_snapshot); 974 } 975 (void) raidcfg_close_controller( 976 ctl_handle, NULL); 977 } 978 } 979 } else { 980 if (argv[optind + 1] != NULL) { 981 return (INVALID_ARG); 982 } 983 984 if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) { 985 return (INVALID_ARG); 986 } 987 988 ctl_handle = raidcfg_get_controller(ctl_tag); 989 if (ctl_handle <= 0) { 990 (void) fprintf(stderr, "%s\n", 991 raidcfg_errstr(ctl_handle)); 992 return (FAILURE); 993 } 994 995 if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) { 996 return (INVALID_ARG); 997 } 998 999 ret = raidcfg_open_controller(ctl_handle, NULL); 1000 if (ret < 0) { 1001 (void) fprintf(stderr, "%s\n", 1002 raidcfg_errstr(ret)); 1003 return (FAILURE); 1004 } 1005 1006 disk_handle = raidcfg_get_disk(ctl_handle, disk_tag); 1007 if (disk_handle <= 0) { 1008 (void) fprintf(stderr, "%s\n", 1009 raidcfg_errstr(disk_handle)); 1010 (void) raidcfg_close_controller(ctl_handle, NULL); 1011 return (FAILURE); 1012 } 1013 1014 if (is_snapshot == FALSE) { 1015 ret = print_disk_table(ctl_handle, disk_handle); 1016 } else { 1017 ret = snapshot_disk(ctl_tag, disk_handle, 0, 1018 is_snapshot); 1019 } 1020 (void) raidcfg_close_controller(ctl_handle, NULL); 1021 } 1022 return (ret); 1023 } 1024 1025 /* 1026 * do_delete(f_flag, argv, optind) 1027 * This function deletes a specified array, and return result as SUCCESS, 1028 * FAILURE or INVALID_ARG. 1029 */ 1030 static int 1031 do_delete(uint32_t f_flag, char **argv, uint32_t optind) 1032 { 1033 uint32_t ctl_tag; 1034 char *array_argp; 1035 array_tag_t array_tag; 1036 raid_obj_handle_t ctl_handle; 1037 raid_obj_handle_t array_handle; 1038 int ret; 1039 1040 array_argp = argv[optind]; 1041 if (array_argp == NULL || argv[optind + 1] != NULL) { 1042 return (INVALID_ARG); 1043 } 1044 1045 if (get_array_tag(array_argp, &ctl_tag, &array_tag) != SUCCESS) { 1046 return (INVALID_ARG); 1047 } 1048 1049 ctl_handle = raidcfg_get_controller(ctl_tag); 1050 if (ctl_handle <= 0) { 1051 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle)); 1052 return (INVALID_ARG); 1053 } 1054 1055 ret = raidcfg_open_controller(ctl_handle, NULL); 1056 if (ret < 0) { 1057 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1058 return (FAILURE); 1059 } 1060 1061 array_handle = raidcfg_get_array(ctl_handle, array_tag.idl.target_id, 1062 array_tag.idl.lun); 1063 if (array_handle <= 0) { 1064 (void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle)); 1065 (void) raidcfg_close_controller(ctl_handle, NULL); 1066 return (FAILURE); 1067 } 1068 1069 if (f_flag == FALSE) { 1070 (void) fprintf(stdout, gettext("Deleting RAID volume " 1071 "%s will destroy all data it contains, " 1072 "proceed (%s/%s)? "), array_argp, yesstr, nostr); 1073 if (!yes()) { 1074 (void) fprintf(stdout, gettext("RAID Volume " 1075 "%s not deleted.\n\n"), array_argp); 1076 (void) raidcfg_close_controller(ctl_handle, NULL); 1077 return (SUCCESS); 1078 } 1079 } 1080 1081 1082 if ((ret = raidcfg_delete_array(array_handle, NULL)) < 0) { 1083 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1084 (void) raidcfg_close_controller(ctl_handle, NULL); 1085 return (FAILURE); 1086 } 1087 1088 (void) fprintf(stdout, gettext("Volume %s is deleted successfully!\n"), 1089 array_argp); 1090 (void) raidcfg_close_controller(ctl_handle, NULL); 1091 1092 return (SUCCESS); 1093 } 1094 1095 /* 1096 * do_flash(f_flag, filep, ctls_argpp, index, ctl_num) 1097 * This function downloads and updates firmware for specified controller, and 1098 * return result as SUCCESS, FAILURE or INVALID_ARG. 1099 */ 1100 static int 1101 do_flash(uint8_t f_flag, char *filep, char **ctls_argpp, 1102 uint32_t index, uint32_t ctl_num) 1103 { 1104 uint32_t ctl_tag = MAX32BIT; 1105 char *ctl_argp = NULL; 1106 raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; 1107 int ret; 1108 int i, j; 1109 1110 if (ctl_num == 0) 1111 return (INVALID_ARG); 1112 1113 for (i = 0, j = index; i < ctl_num; i++, j++) { 1114 ctl_argp = ctls_argpp[j]; 1115 if (get_ctl_tag(ctl_argp, &ctl_tag) != SUCCESS) { 1116 return (INVALID_ARG); 1117 } 1118 1119 /* Ask user to confirm operation. */ 1120 if (f_flag == FALSE) { 1121 (void) fprintf(stdout, gettext("Update flash image on " 1122 "controller %d (%s/%s)? "), ctl_tag, yesstr, nostr); 1123 if (!yes()) { 1124 (void) fprintf(stdout, 1125 gettext("Controller %d not " 1126 "flashed.\n\n"), ctl_tag); 1127 return (SUCCESS); 1128 } 1129 } 1130 1131 if ((ctl_handle = raidcfg_get_controller(ctl_tag)) < 0) { 1132 (void) fprintf(stderr, "%s\n", 1133 raidcfg_errstr(ctl_handle)); 1134 return (FAILURE); 1135 } 1136 1137 ret = raidcfg_open_controller(ctl_handle, NULL); 1138 if (ret < 0) { 1139 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1140 return (FAILURE); 1141 } 1142 1143 (void) fprintf(stdout, gettext("Start updating controller " 1144 "c%u firmware....\n"), ctl_tag); 1145 1146 if ((ret = raidcfg_update_fw(ctl_handle, filep, NULL)) < 0) { 1147 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1148 (void) raidcfg_close_controller(ctl_handle, NULL); 1149 return (FAILURE); 1150 } 1151 1152 (void) fprintf(stdout, gettext("Update controller " 1153 "c%u firmware successfully.\n"), ctl_tag); 1154 1155 (void) raidcfg_close_controller(ctl_handle, NULL); 1156 } 1157 1158 return (SUCCESS); 1159 } 1160 1161 /* 1162 * do_set_hsp(a_argp, disk_argp, argv, optind) 1163 * This function set or unset HSP relationship between disk and controller/ 1164 * array, and return result as SUCCESS, FAILURE or INVALID_ARG. 1165 */ 1166 static int 1167 do_set_hsp(char *a_argp, char *disk_argp, char **argv, uint32_t optind) 1168 { 1169 uint32_t flag = MAX32BIT; 1170 uint32_t ctl_tag = MAX32BIT; 1171 array_tag_t array_tag; 1172 raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; 1173 raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE; 1174 raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; 1175 raidcfg_controller_t ctl_attr; 1176 disk_tag_t disk_tag; 1177 1178 int ret; 1179 int hsp_type; 1180 raidcfg_hsp_relation_t hsp_relation; 1181 1182 (void) memset(&hsp_relation, 0, sizeof (raidcfg_hsp_relation_t)); 1183 1184 if (a_argp == NULL) { 1185 return (INVALID_ARG); 1186 } 1187 1188 if (strcmp(a_argp, "set") == 0) { 1189 flag = HSP_SET; 1190 } else if (strcmp(a_argp, "unset") == 0) { 1191 flag = HSP_UNSET; 1192 } else { 1193 return (INVALID_ARG); 1194 } 1195 1196 if (disk_argp == NULL) { 1197 return (INVALID_ARG); 1198 } 1199 1200 if (argv[optind] == NULL || argv[optind + 1] != NULL) { 1201 return (INVALID_ARG); 1202 } else if (is_fully_numeric(argv[optind]) == TRUE) { 1203 /* Global HSP */ 1204 hsp_type = 0; 1205 if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) { 1206 return (INVALID_ARG); 1207 } 1208 1209 if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) { 1210 return (INVALID_ARG); 1211 } 1212 1213 ctl_handle = raidcfg_get_controller(ctl_tag); 1214 if (ctl_handle <= 0) { 1215 (void) fprintf(stderr, "%s\n", 1216 raidcfg_errstr(ctl_handle)); 1217 return (FAILURE); 1218 } 1219 1220 ret = raidcfg_open_controller(ctl_handle, NULL); 1221 if (ret < 0) { 1222 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1223 return (FAILURE); 1224 } 1225 1226 disk_handle = raidcfg_get_disk(ctl_handle, disk_tag); 1227 if (disk_handle <= 0) { 1228 (void) fprintf(stderr, "%s\n", 1229 raidcfg_errstr(disk_handle)); 1230 (void) raidcfg_close_controller(ctl_handle, NULL); 1231 return (FAILURE); 1232 } 1233 } else { 1234 /* Local HSP */ 1235 hsp_type = 1; 1236 if (get_array_tag(argv[optind], &ctl_tag, &array_tag) != 1237 SUCCESS) { 1238 return (INVALID_ARG); 1239 } 1240 1241 /* Open controller */ 1242 ctl_handle = raidcfg_get_controller(ctl_tag); 1243 if (ctl_handle <= 0) { 1244 (void) fprintf(stderr, "%s\n", 1245 raidcfg_errstr(ctl_handle)); 1246 return (FAILURE); 1247 } 1248 1249 ret = raidcfg_open_controller(ctl_handle, NULL); 1250 if (ret < 0) { 1251 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1252 return (FAILURE); 1253 } 1254 1255 /* Get controller's attribute */ 1256 if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { 1257 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1258 (void) raidcfg_close_controller(ctl_handle, NULL); 1259 return (FAILURE); 1260 } 1261 1262 if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) { 1263 (void) raidcfg_close_controller(ctl_handle, NULL); 1264 return (INVALID_ARG); 1265 } 1266 1267 /* Get disk handle */ 1268 disk_handle = raidcfg_get_disk(ctl_handle, disk_tag); 1269 if (disk_handle <= 0) { 1270 (void) fprintf(stderr, "%s\n", 1271 raidcfg_errstr(disk_handle)); 1272 (void) raidcfg_close_controller(ctl_handle, NULL); 1273 return (FAILURE); 1274 } 1275 1276 /* Get array handle */ 1277 array_handle = raidcfg_get_array(ctl_handle, 1278 array_tag.idl.target_id, array_tag.idl.lun); 1279 if (array_handle <= 0) { 1280 (void) fprintf(stderr, "%s\n", 1281 raidcfg_errstr(array_handle)); 1282 (void) raidcfg_close_controller(ctl_handle, NULL); 1283 return (FAILURE); 1284 } 1285 } 1286 1287 hsp_relation.disk_handle = disk_handle; 1288 if (hsp_type) { 1289 /* Set or unset local HSP */ 1290 hsp_relation.array_handle = array_handle; 1291 } else { 1292 /* Set or unset global HSP */ 1293 hsp_relation.array_handle = OBJ_ATTR_NONE; 1294 } 1295 1296 /* Perform operation of set or unset */ 1297 if (flag == HSP_SET) { 1298 if ((ret = raidcfg_set_hsp(&hsp_relation, NULL)) < 0) { 1299 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1300 (void) raidcfg_close_controller(ctl_handle, NULL); 1301 return (FAILURE); 1302 } 1303 1304 if (hsp_type) { 1305 (void) printf(gettext("Set local HSP between disk %s " 1306 "and RAID volume %s successfully.\n"), 1307 disk_argp, argv[optind]); 1308 } else { 1309 (void) printf(gettext("Set global HSP between disk %s " 1310 "and controller %s successfully.\n"), 1311 disk_argp, argv[optind]); 1312 } 1313 } else { 1314 if ((ret = raidcfg_unset_hsp(&hsp_relation, NULL)) < 0) { 1315 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1316 (void) raidcfg_close_controller(ctl_handle, NULL); 1317 return (FAILURE); 1318 } 1319 1320 if (hsp_type) { 1321 (void) printf(gettext("Unset local HSP between " 1322 "disk %s and RAID volume %s successfully.\n"), 1323 disk_argp, argv[optind]); 1324 } else { 1325 (void) printf(gettext("Unset global HSP between " 1326 "disk %s and controller %s successfully.\n"), 1327 disk_argp, argv[optind]); 1328 } 1329 } 1330 (void) raidcfg_close_controller(ctl_handle, NULL); 1331 return (SUCCESS); 1332 } 1333 1334 /* 1335 * do_set_array_attr(f_flag, p_argp, argv, optind) 1336 * This function changes array's attribute when array is running. 1337 * The changeable attribute is up to controller's feature. 1338 * The return value can be SUCCESS, FAILURE or INVALID_ARG. 1339 */ 1340 static int 1341 do_set_array_attr(uint32_t f_flag, char *p_argp, char **argv, uint32_t optind) 1342 { 1343 uint32_t ctl_tag = MAX32BIT; 1344 array_tag_t array_tag; 1345 uint32_t type = MAX32BIT; 1346 uint32_t value = MAX32BIT; 1347 raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; 1348 raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; 1349 1350 char *param, *op = "="; 1351 1352 int ret; 1353 1354 if (argv[optind] == NULL || argv[optind + 1] != NULL) { 1355 return (INVALID_ARG); 1356 } 1357 1358 if (p_argp != NULL) { 1359 param = strtok(p_argp, op); 1360 if (strcmp(param, "wp") == 0) { 1361 type = SET_CACHE_WR_PLY; 1362 param = strtok(NULL, op); 1363 if (strcmp(param, "on") == 0) { 1364 value = CACHE_WR_ON; 1365 } else if (strcmp(param, "off") == 0) { 1366 value = CACHE_WR_OFF; 1367 } else { 1368 return (INVALID_ARG); 1369 } 1370 } else if (strcmp(param, "state") == 0) { 1371 type = SET_ACTIVATION_PLY; 1372 param = strtok(NULL, op); 1373 if (strcmp(param, "activate") == 0) { 1374 value = ARRAY_ACT_ACTIVATE; 1375 } else { 1376 return (INVALID_ARG); 1377 } 1378 } else { 1379 return (INVALID_ARG); 1380 } 1381 } else { 1382 return (INVALID_ARG); 1383 } 1384 1385 if (get_array_tag(argv[optind], &ctl_tag, &array_tag) != SUCCESS) { 1386 return (INVALID_ARG); 1387 } 1388 1389 ctl_handle = raidcfg_get_controller(ctl_tag); 1390 if (ctl_handle <= 0) { 1391 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle)); 1392 return (FAILURE); 1393 } 1394 1395 ret = raidcfg_open_controller(ctl_handle, NULL); 1396 if (ret < 0) { 1397 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1398 return (FAILURE); 1399 } 1400 1401 array_handle = raidcfg_get_array(ctl_handle, array_tag.idl.target_id, 1402 array_tag.idl.lun); 1403 if (array_handle <= 0) { 1404 (void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle)); 1405 return (FAILURE); 1406 } 1407 1408 /* Ask user to confirm operation. */ 1409 if (f_flag == FALSE) { 1410 (void) fprintf(stdout, gettext("Update attribute of " 1411 "array %s (%s/%s)? "), argv[optind], yesstr, nostr); 1412 if (!yes()) { 1413 (void) fprintf(stdout, 1414 gettext("Array %s not " 1415 "changed.\n\n"), argv[optind]); 1416 (void) raidcfg_close_controller(ctl_handle, NULL); 1417 return (SUCCESS); 1418 } 1419 } 1420 1421 if ((ret = raidcfg_set_attr(array_handle, type, &value, NULL)) < 0) { 1422 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1423 (void) raidcfg_close_controller(ctl_handle, NULL); 1424 return (FAILURE); 1425 } 1426 1427 (void) printf(gettext("Set attribute of RAID volume %s " 1428 "successfully.\n"), argv[optind]); 1429 (void) raidcfg_close_controller(ctl_handle, NULL); 1430 1431 return (SUCCESS); 1432 } 1433 1434 /* 1435 * snapshot_raidsystem(recursive, indent, is_snapshot) 1436 * This function prints the snapshot of whole RAID's system configuration, 1437 * and return result as SUCCESS or FAILURE. 1438 */ 1439 static int 1440 snapshot_raidsystem(uint8_t recursive, uint8_t indent, uint8_t is_snapshot) 1441 { 1442 raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; 1443 int ret; 1444 1445 ctl_handle = raidcfg_list_head(OBJ_SYSTEM, OBJ_TYPE_CONTROLLER); 1446 while (ctl_handle > 0) { 1447 ret = raidcfg_open_controller(ctl_handle, NULL); 1448 if (ret == 0) { 1449 if (snapshot_ctl(ctl_handle, recursive, indent, 1450 is_snapshot) == FAILURE) { 1451 (void) raidcfg_close_controller(ctl_handle, 1452 NULL); 1453 } 1454 } 1455 ctl_handle = raidcfg_list_next(ctl_handle); 1456 } 1457 return (SUCCESS); 1458 } 1459 1460 /* 1461 * snapshot_ctl(ctl_handle, recursive, indent, is_snapshot) 1462 * This function prints snapshot of specified controller's configuration, 1463 * and return result as SUCCESS or FAILURE. 1464 */ 1465 static int 1466 snapshot_ctl(raid_obj_handle_t ctl_handle, uint8_t recursive, uint8_t indent, 1467 uint8_t is_snapshot) 1468 { 1469 raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; 1470 raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE; 1471 raidcfg_controller_t ctl_attr; 1472 uint32_t ctl_tag; 1473 char ctlbuf[256]; 1474 int ret; 1475 1476 if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { 1477 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1478 return (FAILURE); 1479 } 1480 1481 ctl_tag = ctl_attr.controller_id; 1482 if (is_snapshot == FALSE) { 1483 print_indent(indent); 1484 (void) fprintf(stdout, gettext("Controller: %u\n"), ctl_tag); 1485 } else { 1486 (void) snprintf(ctlbuf, sizeof (ctlbuf), "%u \"%s\"", 1487 ctl_tag, ctl_attr.controller_type); 1488 (void) fprintf(stdout, "%s", ctlbuf); 1489 1490 (void) fprintf(stdout, "\n"); 1491 } 1492 1493 if (recursive == TRUE) { 1494 array_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_ARRAY); 1495 while (array_handle > 0) { 1496 if (snapshot_array(array_handle, 1497 indent + 1, FALSE, is_snapshot) == FAILURE) { 1498 return (FAILURE); 1499 } 1500 1501 array_handle = raidcfg_list_next(array_handle); 1502 } 1503 1504 disk_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_DISK); 1505 while (disk_handle > 0) { 1506 if (snapshot_disk(ctl_tag, disk_handle, 1507 indent + 1, is_snapshot) == FAILURE) { 1508 return (FAILURE); 1509 } 1510 1511 disk_handle = raidcfg_list_next(disk_handle); 1512 } 1513 } 1514 return (SUCCESS); 1515 } 1516 1517 1518 /* 1519 * snapshot_array(array_handle, indent, is_sub, is_snapshot) 1520 * This function prints snapshot of specified array's configuration, 1521 * and return result as SUCCESS or FAILURE. 1522 */ 1523 static int 1524 snapshot_array(raid_obj_handle_t array_handle, uint8_t indent, uint8_t is_sub, 1525 uint8_t is_snapshot) 1526 { 1527 raid_obj_handle_t ctl_handle; 1528 raid_obj_handle_t subarray_handle; 1529 raid_obj_handle_t arraypart_handle; 1530 raid_obj_handle_t task_handle; 1531 1532 raidcfg_controller_t ctl_attr; 1533 raidcfg_array_t array_attr; 1534 raidcfg_arraypart_t arraypart_attr; 1535 raidcfg_task_t task_attr; 1536 1537 char arraybuf[256] = "\0"; 1538 char diskbuf[256] = "\0"; 1539 char tempbuf[256] = "\0"; 1540 int disknum = 0; 1541 1542 uint32_t ctl_tag; 1543 int ret; 1544 1545 ctl_handle = raidcfg_get_container(array_handle); 1546 ret = raidcfg_get_attr(ctl_handle, &ctl_attr); 1547 if (ret < 0) { 1548 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1549 return (FAILURE); 1550 } 1551 ctl_tag = ctl_attr.controller_id; 1552 1553 /* Print array attribute */ 1554 if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) { 1555 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1556 return (FAILURE); 1557 } 1558 1559 if (is_snapshot == FALSE) { 1560 print_indent(indent); 1561 if (is_sub == FALSE) { 1562 (void) fprintf(stdout, gettext("Volume:" 1563 "c%ut%llud%llu\n"), 1564 ctl_tag, array_attr.tag.idl.target_id, 1565 array_attr.tag.idl.lun); 1566 } else { 1567 (void) fprintf(stdout, gettext("Sub-Volume\n")); 1568 } 1569 } else { 1570 (void) snprintf(arraybuf, sizeof (arraybuf), "c%ut%llud%llu ", 1571 ctl_tag, array_attr.tag.idl.target_id, 1572 array_attr.tag.idl.lun); 1573 1574 /* Check if array is in sync state */ 1575 task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK); 1576 if (task_handle > 0) { 1577 (void) raidcfg_get_attr(task_handle, &task_attr); 1578 if (task_attr.task_func == TASK_FUNC_BUILD) { 1579 array_attr.state = ARRAY_STATE_SYNC; 1580 } 1581 } else { 1582 subarray_handle = raidcfg_list_head(array_handle, 1583 OBJ_TYPE_ARRAY); 1584 while (subarray_handle > 0) { 1585 task_handle = raidcfg_list_head(subarray_handle, 1586 OBJ_TYPE_TASK); 1587 if (task_handle > 0) { 1588 (void) raidcfg_get_attr(task_handle, 1589 &task_attr); 1590 if (task_attr.task_func == 1591 TASK_FUNC_BUILD) { 1592 array_attr.state = 1593 ARRAY_STATE_SYNC; 1594 } 1595 break; 1596 } 1597 subarray_handle = 1598 raidcfg_list_next(subarray_handle); 1599 } 1600 } 1601 1602 /* Print sub array */ 1603 subarray_handle = raidcfg_list_head(array_handle, 1604 OBJ_TYPE_ARRAY); 1605 while (subarray_handle > 0) { 1606 /* print subarraypart */ 1607 arraypart_handle = raidcfg_list_head(subarray_handle, 1608 OBJ_TYPE_ARRAY_PART); 1609 while (arraypart_handle > 0) { 1610 if ((ret = raidcfg_get_attr(arraypart_handle, 1611 &arraypart_attr)) < 0) { 1612 (void) fprintf(stderr, "%s\n", 1613 raidcfg_errstr(ret)); 1614 return (FAILURE); 1615 } 1616 1617 if (arraypart_attr.tag.cidl.bus == MAX64BIT) { 1618 (void) snprintf(tempbuf, 1619 sizeof (tempbuf), 1620 gettext("N/A")); 1621 } else { 1622 (void) snprintf(tempbuf, 1623 sizeof (tempbuf), 1624 "%llu.%llu.%llu", 1625 arraypart_attr.tag.cidl.bus, 1626 arraypart_attr.tag.cidl.target_id, 1627 arraypart_attr.tag.cidl.lun); 1628 } 1629 (void) strlcat(diskbuf, tempbuf, 1630 sizeof (diskbuf)); 1631 (void) strcat(diskbuf, " "); 1632 disknum++; 1633 arraypart_handle = 1634 raidcfg_list_next(arraypart_handle); 1635 } 1636 subarray_handle = raidcfg_list_next(subarray_handle); 1637 } 1638 1639 /* Print arraypart */ 1640 arraypart_handle = raidcfg_list_head(array_handle, 1641 OBJ_TYPE_ARRAY_PART); 1642 while (arraypart_handle > 0) { 1643 if ((ret = raidcfg_get_attr(arraypart_handle, 1644 &arraypart_attr)) < 0) { 1645 (void) fprintf(stderr, "%s\n", 1646 raidcfg_errstr(ret)); 1647 return (FAILURE); 1648 } 1649 1650 if (arraypart_attr.tag.cidl.bus == MAX64BIT) { 1651 (void) snprintf(tempbuf, sizeof (tempbuf), 1652 gettext("N/A")); 1653 } else { 1654 (void) snprintf(tempbuf, sizeof (tempbuf), 1655 "%llu.%llu.%llu", 1656 arraypart_attr.tag.cidl.bus, 1657 arraypart_attr.tag.cidl.target_id, 1658 arraypart_attr.tag.cidl.lun); 1659 } 1660 (void) strlcat(diskbuf, tempbuf, sizeof (diskbuf)); 1661 (void) strcat(diskbuf, " "); 1662 disknum++; 1663 arraypart_handle = raidcfg_list_next(arraypart_handle); 1664 } 1665 (void) snprintf(tempbuf, sizeof (tempbuf), "%u ", disknum); 1666 (void) strlcat(arraybuf, tempbuf, sizeof (arraybuf)); 1667 (void) strlcat(arraybuf, diskbuf, sizeof (arraybuf)); 1668 1669 switch (array_attr.raid_level) { 1670 case RAID_LEVEL_0: 1671 (void) sprintf(tempbuf, "0"); 1672 break; 1673 case RAID_LEVEL_1: 1674 (void) sprintf(tempbuf, "1"); 1675 break; 1676 case RAID_LEVEL_1E: 1677 (void) sprintf(tempbuf, "1E"); 1678 break; 1679 case RAID_LEVEL_5: 1680 (void) sprintf(tempbuf, "5"); 1681 break; 1682 case RAID_LEVEL_10: 1683 (void) sprintf(tempbuf, "10"); 1684 break; 1685 case RAID_LEVEL_50: 1686 (void) sprintf(tempbuf, "50"); 1687 break; 1688 default: 1689 (void) snprintf(tempbuf, sizeof (tempbuf), 1690 gettext("N/A")); 1691 break; 1692 } 1693 (void) strlcat(arraybuf, tempbuf, sizeof (arraybuf)); 1694 (void) fprintf(stdout, "%s ", arraybuf); 1695 1696 switch (array_attr.state) { 1697 case ARRAY_STATE_OPTIMAL: 1698 (void) fprintf(stdout, gettext("OPTIMAL")); 1699 break; 1700 case ARRAY_STATE_DEGRADED: 1701 (void) fprintf(stdout, gettext("DEGRADED")); 1702 break; 1703 case ARRAY_STATE_FAILED: 1704 (void) fprintf(stdout, gettext("FAILED")); 1705 break; 1706 case ARRAY_STATE_SYNC: 1707 (void) fprintf(stdout, gettext("SYNC")); 1708 break; 1709 case ARRAY_STATE_MISSING: 1710 (void) fprintf(stdout, gettext("MISSING")); 1711 break; 1712 default: 1713 (void) fprintf(stdout, gettext("N/A")); 1714 break; 1715 } 1716 (void) fprintf(stdout, "\n"); 1717 } 1718 1719 return (SUCCESS); 1720 } 1721 1722 /* 1723 * snapshot_disk(ctl_tag, disk_handle, indent, is_snapshot) 1724 * This function prints snapshot of specified disk's configuration, and return 1725 * result as SUCCESS or FAILURE. 1726 */ 1727 static int 1728 snapshot_disk(uint32_t ctl_tag, raid_obj_handle_t disk_handle, uint8_t indent, 1729 uint8_t is_snapshot) 1730 { 1731 raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; 1732 raid_obj_handle_t hsp_handle; 1733 1734 raidcfg_controller_t ctl_attr; 1735 raidcfg_disk_t disk_attr; 1736 char diskbuf[256] = ""; 1737 char tempbuf[256] = ""; 1738 1739 int ret; 1740 1741 ctl_handle = raidcfg_get_controller(ctl_tag); 1742 ret = raidcfg_get_attr(ctl_handle, &ctl_attr); 1743 if (ret < 0) { 1744 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1745 return (FAILURE); 1746 } 1747 1748 /* Print attribute of disk */ 1749 if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) { 1750 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1751 return (FAILURE); 1752 } 1753 1754 if (is_snapshot == FALSE) { 1755 print_indent(indent); 1756 1757 hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP); 1758 1759 if (disk_attr.tag.cidl.bus == MAX64BIT) { 1760 (void) fprintf(stdout, gettext("Disk: N/A")); 1761 } else { 1762 (void) fprintf(stdout, gettext("Disk: %llu.%llu.%llu"), 1763 disk_attr.tag.cidl.bus, 1764 disk_attr.tag.cidl.target_id, 1765 disk_attr.tag.cidl.lun); 1766 } 1767 if (hsp_handle > 0) { 1768 (void) fprintf(stdout, "(HSP)"); 1769 } 1770 (void) fprintf(stdout, "\n"); 1771 } else { 1772 if (disk_attr.tag.cidl.bus == MAX64BIT) { 1773 (void) fprintf(stdout, gettext("N/A")); 1774 } else { 1775 (void) snprintf(diskbuf, sizeof (diskbuf), 1776 "%llu.%llu.%llu ", 1777 disk_attr.tag.cidl.bus, 1778 disk_attr.tag.cidl.target_id, 1779 disk_attr.tag.cidl.lun); 1780 } 1781 hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP); 1782 if (hsp_handle > 0) { 1783 (void) snprintf(tempbuf, sizeof (tempbuf), 1784 gettext("HSP")); 1785 } else if (disk_attr.state == DISK_STATE_GOOD) { 1786 (void) snprintf(tempbuf, sizeof (tempbuf), 1787 gettext("GOOD")); 1788 } else if (disk_attr.state == DISK_STATE_FAILED) { 1789 (void) snprintf(tempbuf, sizeof (tempbuf), 1790 gettext("FAILED")); 1791 } else { 1792 (void) snprintf(tempbuf, sizeof (tempbuf), 1793 gettext("N/A")); 1794 } 1795 1796 (void) strlcat(diskbuf, tempbuf, sizeof (diskbuf)); 1797 (void) fprintf(stdout, "%s\n", diskbuf); 1798 } 1799 1800 return (SUCCESS); 1801 } 1802 1803 static int 1804 print_ctl_table(raid_obj_handle_t ctl_handle) 1805 { 1806 raidcfg_controller_t ctl_attr; 1807 char controller[8]; 1808 int ret; 1809 1810 if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { 1811 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1812 return (FAILURE); 1813 } 1814 1815 (void) fprintf(stdout, gettext("Controller\tType\t\tVersion")); 1816 (void) fprintf(stdout, "\n"); 1817 (void) fprintf(stdout, "--------------------------------"); 1818 (void) fprintf(stdout, "--------------------------------"); 1819 (void) fprintf(stdout, "\n"); 1820 1821 (void) snprintf(controller, sizeof (controller), "%u", 1822 ctl_attr.controller_id); 1823 (void) printf("c%s\t\t", controller); 1824 1825 (void) print_ctl_attr(&ctl_attr); 1826 (void) fprintf(stdout, "\n"); 1827 1828 return (SUCCESS); 1829 } 1830 1831 static int 1832 print_array_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t array_handle) 1833 { 1834 raidcfg_controller_t ctl_attr; 1835 raidcfg_array_t array_attr; 1836 raidcfg_array_t subarray_attr; 1837 raidcfg_arraypart_t arraypart_attr; 1838 raidcfg_task_t task_attr; 1839 1840 raid_obj_handle_t subarray_handle; 1841 raid_obj_handle_t arraypart_handle; 1842 raid_obj_handle_t task_handle; 1843 1844 char array[16]; 1845 char arraypart[8]; 1846 int ret; 1847 int i; 1848 1849 /* Controller attribute */ 1850 if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { 1851 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1852 return (FAILURE); 1853 } 1854 1855 /* Array attribute */ 1856 if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) { 1857 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1858 return (FAILURE); 1859 } 1860 1861 /* print header */ 1862 (void) fprintf(stdout, gettext("Volume\t\t\tSize\tStripe\tStatus\t" 1863 " Cache\tRAID")); 1864 (void) fprintf(stdout, "\n"); 1865 (void) fprintf(stdout, gettext("\tSub\t\t\tSize\t\t\tLevel")); 1866 (void) fprintf(stdout, "\n"); 1867 (void) fprintf(stdout, gettext("\t\tDisk\t\t\t\t\t")); 1868 (void) fprintf(stdout, "\n"); 1869 (void) fprintf(stdout, "--------------------------------"); 1870 (void) fprintf(stdout, "--------------------------------"); 1871 (void) fprintf(stdout, "\n"); 1872 1873 /* print array */ 1874 (void) snprintf(array, sizeof (array), "c%ut%llud%llu", 1875 ctl_attr.controller_id, array_attr.tag.idl.target_id, 1876 array_attr.tag.idl.lun); 1877 (void) fprintf(stdout, "%s\t\t", array); 1878 if (strlen(array) < 8) 1879 (void) fprintf(stdout, "\t"); 1880 1881 1882 /* check if array is in sync state */ 1883 task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK); 1884 if (task_handle > 0) { 1885 (void) raidcfg_get_attr(task_handle, &task_attr); 1886 if (task_attr.task_func == TASK_FUNC_BUILD) { 1887 array_attr.state = ARRAY_STATE_SYNC; 1888 } 1889 } else { 1890 subarray_handle = raidcfg_list_head(array_handle, 1891 OBJ_TYPE_ARRAY); 1892 while (subarray_handle > 0) { 1893 task_handle = raidcfg_list_head(subarray_handle, 1894 OBJ_TYPE_TASK); 1895 if (task_handle > 0) { 1896 (void) raidcfg_get_attr(task_handle, 1897 &task_attr); 1898 if (task_attr.task_func == TASK_FUNC_BUILD) { 1899 array_attr.state = ARRAY_STATE_SYNC; 1900 } 1901 break; 1902 } 1903 subarray_handle = raidcfg_list_next(subarray_handle); 1904 } 1905 } 1906 1907 (void) print_array_attr(&array_attr); 1908 (void) fprintf(stdout, "\n"); 1909 1910 /* Print sub array */ 1911 i = 0; /* Count sub array number */ 1912 subarray_handle = raidcfg_list_head(array_handle, OBJ_TYPE_ARRAY); 1913 while (subarray_handle > 0) { 1914 if ((ret = raidcfg_get_attr(subarray_handle, 1915 &subarray_attr)) < 0) { 1916 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1917 return (FAILURE); 1918 } 1919 1920 /* Use sub0/sub1 here, not cxtxd0 for subarray */ 1921 (void) snprintf(array, sizeof (array), "sub%u", i++); 1922 (void) fprintf(stdout, "\t%s\t\t", array); 1923 1924 /* Check if array is in sync */ 1925 task_handle = raidcfg_list_head(subarray_handle, OBJ_TYPE_TASK); 1926 if (task_handle > 0) { 1927 (void) raidcfg_get_attr(task_handle, &task_attr); 1928 if (task_attr.task_func == TASK_FUNC_BUILD) { 1929 subarray_attr.state = ARRAY_STATE_SYNC; 1930 } 1931 } 1932 1933 (void) print_array_attr(&subarray_attr); 1934 (void) fprintf(stdout, "\n"); 1935 1936 /* Print subarraypart */ 1937 arraypart_handle = raidcfg_list_head(subarray_handle, 1938 OBJ_TYPE_ARRAY_PART); 1939 while (arraypart_handle > 0) { 1940 if ((ret = raidcfg_get_attr(arraypart_handle, 1941 &arraypart_attr)) < 0) { 1942 (void) fprintf(stderr, "%s\n", 1943 raidcfg_errstr(ret)); 1944 return (FAILURE); 1945 } 1946 1947 if (arraypart_attr.tag.cidl.bus == MAX64BIT) { 1948 (void) snprintf(arraypart, sizeof (arraypart), 1949 gettext("N/A")); 1950 } else { 1951 (void) snprintf(arraypart, sizeof (arraypart), 1952 "%llu.%llu.%llu", 1953 arraypart_attr.tag.cidl.bus, 1954 arraypart_attr.tag.cidl.target_id, 1955 arraypart_attr.tag.cidl.lun); 1956 } 1957 1958 (void) fprintf(stdout, "\t\t%s\t", arraypart); 1959 (void) print_arraypart_attr(&arraypart_attr); 1960 (void) fprintf(stdout, "\n"); 1961 arraypart_handle = raidcfg_list_next(arraypart_handle); 1962 } 1963 subarray_handle = raidcfg_list_next(subarray_handle); 1964 } 1965 1966 /* Print arraypart */ 1967 arraypart_handle = raidcfg_list_head(array_handle, 1968 OBJ_TYPE_ARRAY_PART); 1969 while (arraypart_handle > 0) { 1970 if ((ret = raidcfg_get_attr(arraypart_handle, 1971 &arraypart_attr)) < 0) { 1972 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 1973 return (FAILURE); 1974 } 1975 1976 if (arraypart_attr.tag.cidl.bus == MAX64BIT) { 1977 (void) snprintf(arraypart, sizeof (arraypart), 1978 gettext("N/A")); 1979 } else { 1980 (void) snprintf(arraypart, sizeof (arraypart), 1981 "%llu.%llu.%llu", 1982 arraypart_attr.tag.cidl.bus, 1983 arraypart_attr.tag.cidl.target_id, 1984 arraypart_attr.tag.cidl.lun); 1985 } 1986 1987 (void) fprintf(stdout, "\t\t%s\t", arraypart); 1988 (void) print_arraypart_attr(&arraypart_attr); 1989 (void) fprintf(stdout, "\n"); 1990 arraypart_handle = raidcfg_list_next(arraypart_handle); 1991 } 1992 1993 return (SUCCESS); 1994 } 1995 1996 static int 1997 print_disk_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle) 1998 { 1999 raidcfg_controller_t ctl_attr; 2000 raidcfg_disk_t disk_attr; 2001 raidcfg_prop_t *prop_attr, *prop_attr2; 2002 raid_obj_handle_t prop_handle; 2003 char disk[8]; 2004 int ret; 2005 2006 if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { 2007 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 2008 return (FAILURE); 2009 } 2010 2011 if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) { 2012 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 2013 return (FAILURE); 2014 } 2015 2016 /* Print header */ 2017 (void) fprintf(stdout, gettext("Disk\tVendor Product " 2018 "Firmware\tCapacity\tStatus\tHSP")); 2019 (void) fprintf(stdout, "\n"); 2020 (void) fprintf(stdout, "--------------------------------------"); 2021 (void) fprintf(stdout, "--------------------------------------"); 2022 (void) fprintf(stdout, "\n"); 2023 2024 2025 (void) snprintf(disk, sizeof (disk), "%llu.%llu.%llu", 2026 disk_attr.tag.cidl.bus, 2027 disk_attr.tag.cidl.target_id, 2028 disk_attr.tag.cidl.lun); 2029 2030 (void) fprintf(stdout, "%s\t", disk); 2031 2032 (void) print_disk_attr(ctl_handle, disk_handle, &disk_attr); 2033 2034 prop_attr = calloc(1, sizeof (raidcfg_prop_t)); 2035 if (prop_attr == NULL) { 2036 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ERR_NOMEM)); 2037 return (FAILURE); 2038 } 2039 2040 prop_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_PROP); 2041 if (prop_handle == 0) { 2042 free(prop_attr); 2043 return (SUCCESS); 2044 } 2045 2046 do { 2047 prop_attr->prop_size = 0; 2048 if ((ret = raidcfg_get_attr(prop_handle, prop_attr)) < 0) { 2049 free(prop_attr); 2050 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 2051 return (FAILURE); 2052 } 2053 if (prop_attr->prop_type == PROP_GUID) 2054 break; 2055 } while (prop_handle != 0); 2056 2057 prop_attr2 = realloc(prop_attr, 2058 sizeof (raidcfg_prop_t) + prop_attr->prop_size); 2059 free(prop_attr); 2060 if (prop_attr2 == NULL) { 2061 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ERR_NOMEM)); 2062 return (FAILURE); 2063 } 2064 2065 if ((ret = raidcfg_get_attr(prop_handle, prop_attr2)) < 0) { 2066 free(prop_attr2); 2067 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 2068 return (FAILURE); 2069 } 2070 2071 (void) fprintf(stdout, "GUID:%s\n", prop_attr2->prop); 2072 2073 free(prop_attr2); 2074 return (SUCCESS); 2075 } 2076 2077 /* 2078 * print_ctl_attr(attrp) 2079 * This function prints attribute of specified controller, and return 2080 * result as SUCCESS or FAILURE. 2081 */ 2082 static int 2083 print_ctl_attr(raidcfg_controller_t *attrp) 2084 { 2085 char type[CONTROLLER_TYPE_LEN]; 2086 char version[CONTROLLER_FW_LEN]; 2087 2088 if (attrp == NULL) { 2089 return (FAILURE); 2090 } 2091 2092 (void) snprintf(type, sizeof (type), "%s", attrp->controller_type); 2093 (void) fprintf(stdout, "%-16s", type); 2094 2095 (void) snprintf(version, sizeof (version), "%s", attrp->fw_version); 2096 (void) fprintf(stdout, "%s", version); 2097 2098 return (SUCCESS); 2099 } 2100 2101 /* 2102 * print_array_attr(attrp) 2103 * This function prints attribute of specified array, and return 2104 * result as SUCCESS or FAILURE. 2105 */ 2106 static int 2107 print_array_attr(raidcfg_array_t *attrp) 2108 { 2109 char capacity[8]; 2110 char stripe_size[8]; 2111 char raid_level[8]; 2112 2113 if (attrp == NULL) { 2114 return (FAILURE); 2115 } 2116 2117 if (attrp->capacity != MAX64BIT) { 2118 if (size_to_string(attrp->capacity, capacity, 8) != SUCCESS) { 2119 return (FAILURE); 2120 } 2121 (void) printf("%s\t", capacity); 2122 } else { 2123 (void) printf(gettext("N/A\t")); 2124 } 2125 2126 if (attrp->stripe_size != MAX32BIT) { 2127 (void) snprintf(stripe_size, sizeof (stripe_size), "%uK", 2128 attrp->stripe_size / 1024); 2129 (void) printf("%s\t", stripe_size); 2130 } else { 2131 (void) printf(gettext("N/A\t")); 2132 } 2133 2134 if (attrp->state & ARRAY_STATE_INACTIVATE) 2135 (void) printf("%-8s", gettext("INACTIVE")); 2136 else { 2137 switch (attrp->state) { 2138 case ARRAY_STATE_OPTIMAL: 2139 (void) printf("%-8s", gettext("OPTIMAL")); 2140 break; 2141 case ARRAY_STATE_DEGRADED: 2142 (void) printf("%-8s", gettext("DEGRADED")); 2143 break; 2144 case ARRAY_STATE_FAILED: 2145 (void) printf("%-8s", gettext("FAILED")); 2146 break; 2147 case ARRAY_STATE_SYNC: 2148 (void) printf("%-8s", gettext("SYNC")); 2149 break; 2150 case ARRAY_STATE_MISSING: 2151 (void) printf("%-8s", gettext("MISSING")); 2152 break; 2153 default: 2154 (void) printf("%-8s", gettext("N/A")); 2155 break; 2156 } 2157 } 2158 (void) printf(" "); 2159 2160 if (attrp->write_policy == CACHE_WR_OFF) { 2161 (void) printf(gettext("OFF")); 2162 } else if (attrp->write_policy == CACHE_WR_ON) { 2163 (void) printf(gettext("ON")); 2164 } else { 2165 (void) printf(gettext("N/A")); 2166 } 2167 (void) printf("\t"); 2168 2169 switch (attrp->raid_level) { 2170 case RAID_LEVEL_0: 2171 (void) sprintf(raid_level, "RAID0"); 2172 break; 2173 case RAID_LEVEL_1: 2174 (void) sprintf(raid_level, "RAID1"); 2175 break; 2176 case RAID_LEVEL_1E: 2177 (void) sprintf(raid_level, "RAID1E"); 2178 break; 2179 case RAID_LEVEL_5: 2180 (void) sprintf(raid_level, "RAID5"); 2181 break; 2182 case RAID_LEVEL_10: 2183 (void) sprintf(raid_level, "RAID10"); 2184 break; 2185 case RAID_LEVEL_50: 2186 (void) sprintf(raid_level, "RAID50"); 2187 break; 2188 default: 2189 (void) snprintf(raid_level, sizeof (raid_level), 2190 gettext("N/A")); 2191 break; 2192 } 2193 (void) printf("%s", raid_level); 2194 2195 return (SUCCESS); 2196 } 2197 2198 /* 2199 * print_arraypart_attr(attrp) 2200 * This function print attribute of specified arraypart, and return 2201 * result as SUCCESS or FAILURE. 2202 */ 2203 static int 2204 print_arraypart_attr(raidcfg_arraypart_t *attrp) 2205 { 2206 char size[8]; 2207 2208 if (attrp == NULL) { 2209 return (FAILURE); 2210 } 2211 2212 if (attrp->size != MAX64BIT) { 2213 if (size_to_string(attrp->size, size, 8) != SUCCESS) { 2214 return (FAILURE); 2215 } 2216 (void) printf("%s\t", size); 2217 } else { 2218 (void) printf(gettext("N/A\t")); 2219 } 2220 2221 (void) printf("\t"); 2222 2223 if (attrp->state == DISK_STATE_GOOD) { 2224 (void) printf(gettext("GOOD")); 2225 } else if (attrp->state == DISK_STATE_FAILED) { 2226 (void) printf(gettext("FAILED")); 2227 } else { 2228 (void) printf(gettext("N/A")); 2229 } 2230 (void) printf("\t"); 2231 2232 return (SUCCESS); 2233 } 2234 2235 /* 2236 * print_disk_attr(ctl_handle, disk_handle, attrp) 2237 * This function prints attribute of specified disk, and return 2238 * result as SUCCESS or FAILURE. 2239 */ 2240 static int 2241 print_disk_attr(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle, 2242 raidcfg_disk_t *attrp) 2243 { 2244 char vendor[DISK_VENDER_LEN + 1]; 2245 char product[DISK_PRODUCT_LEN + 1]; 2246 char revision[DISK_REV_LEN + 1]; 2247 char capacity[16]; 2248 char hsp[16]; 2249 2250 raid_obj_handle_t hsp_handle; 2251 raidcfg_hsp_t hsp_attr; 2252 raidcfg_controller_t ctl_attr; 2253 int ret; 2254 char is_indent; 2255 2256 if (attrp == NULL) { 2257 return (FAILURE); 2258 } 2259 2260 (void) memccpy(vendor, attrp->vendorid, '\0', DISK_VENDER_LEN); 2261 vendor[DISK_VENDER_LEN] = '\0'; 2262 (void) printf("%-9s", vendor); 2263 2264 (void) memccpy(product, attrp->productid, '\0', DISK_PRODUCT_LEN); 2265 product[DISK_PRODUCT_LEN] = '\0'; 2266 (void) printf("%-17s", product); 2267 2268 (void) memccpy(revision, attrp->revision, '\0', DISK_REV_LEN); 2269 revision[DISK_REV_LEN] = '\0'; 2270 (void) printf("%s\t\t", revision); 2271 2272 if (attrp->capacity != MAX64BIT) { 2273 if (size_to_string(attrp->capacity, capacity, 16) != SUCCESS) { 2274 return (FAILURE); 2275 } 2276 (void) printf("%s\t\t", capacity); 2277 } else { 2278 (void) printf(gettext("N/A")); 2279 } 2280 2281 if (attrp->state == DISK_STATE_GOOD) { 2282 (void) printf(gettext("GOOD")); 2283 } else if (attrp->state == DISK_STATE_FAILED) { 2284 (void) printf(gettext("FAILED")); 2285 } else { 2286 (void) printf(gettext("N/A")); 2287 } 2288 (void) printf("\t"); 2289 2290 /* Controller attribute */ 2291 if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { 2292 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 2293 return (FAILURE); 2294 } 2295 2296 hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP); 2297 if (hsp_handle == 0) { 2298 (void) printf(gettext("N/A\n")); 2299 } else { 2300 is_indent = FALSE; 2301 while (hsp_handle > 0) { 2302 if ((ret = raidcfg_get_attr(hsp_handle, 2303 &hsp_attr)) < 0) { 2304 (void) fprintf(stderr, "%s\n", 2305 raidcfg_errstr(ret)); 2306 return (FAILURE); 2307 } 2308 2309 if (is_indent == TRUE) { 2310 (void) printf("\t\t\t\t\t\t\t"); 2311 } else { 2312 is_indent = TRUE; 2313 } 2314 2315 if (hsp_attr.type == HSP_TYPE_LOCAL) { 2316 (void) snprintf(hsp, sizeof (hsp), 2317 "c%ut%llud%llu", 2318 ctl_attr.controller_id, 2319 hsp_attr.tag.idl.target_id, 2320 hsp_attr.tag.idl.lun); 2321 (void) printf("%s\n", hsp); 2322 } else if (hsp_attr.type == HSP_TYPE_GLOBAL) { 2323 (void) printf(gettext("Global\n")); 2324 } else { 2325 return (FAILURE); 2326 } 2327 2328 hsp_handle = raidcfg_list_next(hsp_handle); 2329 } 2330 } 2331 return (SUCCESS); 2332 } 2333 2334 2335 /* 2336 * print_indent(indent) 2337 * This function prints specified number of tab characters. It's used to 2338 * format layout. 2339 */ 2340 static void 2341 print_indent(uint8_t indent) 2342 { 2343 uint32_t i; 2344 for (i = 0; i < indent; i++) { 2345 (void) fprintf(stdout, "\t"); 2346 } 2347 } 2348 2349 /* 2350 * get_disk_handle_cidl(ctl_tag, disks_argp, comps_num, handlespp) 2351 * This function parses the string of disk argument, and gets the disks tag 2352 * and separators from the string. Then it translates the tag to handle, and 2353 * stores handles and separators to new buffer pointed by parameter handlespp. 2354 * The format of disk_arg must be C:ID:L, for example, it is 0.1.0. The first 2355 * "0" is channel number, and the second "1" is target number, and the third 2356 * "0" is LUN number. The disk tags are separated by comma and parenthesis. 2357 * Function returns SUCCESS or FAILURE. 2358 */ 2359 static int 2360 get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp, int *comps_nump, 2361 raid_obj_handle_t **handlespp) 2362 { 2363 int len = 0; 2364 int i = 0, j = 0; 2365 char *p, *t; 2366 char *delimit = " "; 2367 char *disks_str; 2368 disk_tag_t disk_tag; 2369 2370 if (disks_argp == NULL || comps_nump == NULL) { 2371 return (FAILURE); 2372 } 2373 2374 p = disks_argp; 2375 len = strlen(disks_argp); 2376 2377 if ((disks_str = (char *)malloc(3 * len + 4)) == NULL) { 2378 return (FAILURE); 2379 } 2380 2381 /* Insert whitespace between disk tags, '(' , and ')' */ 2382 disks_str[j ++] = '('; 2383 disks_str[j ++] = ' '; 2384 2385 while (p[i] != '\0') { 2386 if (p[i] == ')' || p[i] == '(') { 2387 disks_str[j ++] = ' '; 2388 disks_str[j ++] = p[i]; 2389 disks_str[j ++] = ' '; 2390 } else 2391 disks_str[j ++] = p[i]; 2392 i ++; 2393 } 2394 disks_str[j ++] = ' '; 2395 disks_str[j ++] = ')'; 2396 disks_str[j] = '\0'; 2397 2398 len = strlen(disks_str) + 1; 2399 2400 if ((t = (char *)malloc(len)) == NULL) { 2401 return (FAILURE); 2402 } 2403 (void) memcpy(t, disks_str, len); 2404 p = strtok(t, delimit); 2405 while (p != NULL) { 2406 (*comps_nump)++; 2407 p = strtok(NULL, delimit); 2408 } 2409 free(t); 2410 2411 *handlespp = calloc(*comps_nump, sizeof (raid_obj_handle_t)); 2412 if (*handlespp == NULL) { 2413 return (FAILURE); 2414 } 2415 2416 for (i = 0; i < *comps_nump; i++) 2417 (*handlespp)[i] = INIT_HANDLE_VALUE; 2418 2419 i = 0; 2420 p = strtok(disks_str, delimit); 2421 while (p != NULL) { 2422 if (*p == '(') { 2423 (*handlespp)[i] = OBJ_SEPARATOR_BEGIN; 2424 } else if (*p == ')') { 2425 (*handlespp)[i] = OBJ_SEPARATOR_END; 2426 } else { 2427 if (get_disk_tag_cidl(p, &disk_tag) != SUCCESS) { 2428 free(*handlespp); 2429 free(disks_str); 2430 return (INVALID_ARG); 2431 } 2432 (*handlespp)[i] = 2433 raidcfg_get_disk(raidcfg_get_controller(ctl_tag), 2434 disk_tag); 2435 if ((*handlespp)[i] <= 0) { 2436 (void) fprintf(stderr, "%s\n", 2437 raidcfg_errstr((*handlespp)[i])); 2438 free(*handlespp); 2439 free(disks_str); 2440 return (FAILURE); 2441 } 2442 } 2443 p = strtok(NULL, delimit); 2444 i++; 2445 } 2446 2447 free(disks_str); 2448 return (SUCCESS); 2449 } 2450 2451 /* 2452 * get_disk_handle_ctd(disks_num, disks_argpp, ctl_tagp, disks_handlep) 2453 * This function parses string of single disk with "ctd" format, for example, 2454 * c0t0d0, and translates it to controller tag and disk tag. 2455 * Then it calls lib api and get disk handle. The controller tag and disk 2456 * handle are both returned by out parameters. 2457 * The return value is SUCCESS or FAILURE. 2458 */ 2459 static int 2460 get_disk_handle_ctd(int disks_num, char **disks_argpp, uint32_t *ctl_tagp, 2461 raid_obj_handle_t *disks_handlep) 2462 { 2463 raid_obj_handle_t ctl_handle; 2464 disk_tag_t disk_tag; 2465 uint32_t ctl_id; 2466 int i; 2467 int ret; 2468 2469 if (disks_handlep == NULL) { 2470 return (FAILURE); 2471 } 2472 2473 for (i = 0; i < disks_num; i++) { 2474 if (get_disk_tag_ctd(disks_argpp[i], &disk_tag, &ctl_id) != 2475 SUCCESS) { 2476 return (INVALID_ARG); 2477 } 2478 2479 *ctl_tagp = ctl_id; 2480 2481 if (i == 0) { 2482 ctl_handle = raidcfg_get_controller(*ctl_tagp); 2483 if (ctl_handle <= 0) { 2484 (void) fprintf(stderr, "%s\n", 2485 raidcfg_errstr(ctl_handle)); 2486 return (FAILURE); 2487 } 2488 ret = raidcfg_open_controller(ctl_handle, NULL); 2489 if (ret < 0) { 2490 (void) fprintf(stderr, "%s\n", 2491 raidcfg_errstr(ret)); 2492 return (FAILURE); 2493 } 2494 } 2495 2496 if ((disks_handlep[i] = 2497 raidcfg_get_disk(ctl_handle, disk_tag)) < 0) { 2498 (void) fprintf(stderr, "%s\n", 2499 raidcfg_errstr(disks_handlep[i])); 2500 (void) raidcfg_close_controller(ctl_handle, NULL); 2501 return (FAILURE); 2502 } 2503 } 2504 2505 return (SUCCESS); 2506 } 2507 2508 /* 2509 * get_ctl_tag(argp) 2510 * This function translates controller string to tag. The return value is 2511 * SUCCESS if the string has legal format and is parsed successfully, 2512 * or FAILURE if it fails. 2513 */ 2514 static int 2515 get_ctl_tag(char *argp, uint32_t *ctl_tagp) 2516 { 2517 if (argp == NULL || is_fully_numeric(argp) == FALSE || 2518 ctl_tagp == NULL) { 2519 return (FAILURE); 2520 } 2521 *ctl_tagp = (atoi(argp)); 2522 return (SUCCESS); 2523 } 2524 2525 /* 2526 * get_array_tag(argp, ctl_tagp, array_tagp) 2527 * This function parses array string to get array tag and controller tag. 2528 * The return value is SUCCESS if the string has legal format, or 2529 * FAILURE if it fails. 2530 */ 2531 static int 2532 get_array_tag(char *argp, uint32_t *ctl_tagp, array_tag_t *array_tagp) 2533 { 2534 char *t = NULL; 2535 char *cp = NULL; 2536 char *tp = NULL; 2537 char *dp = NULL; 2538 2539 uint32_t value_c = MAX32BIT; 2540 uint32_t value_t = MAX32BIT; 2541 uint32_t value_d = MAX32BIT; 2542 2543 int len = 0; 2544 2545 if (argp == NULL || (len = strlen(argp)) == 0 || 2546 array_tagp == NULL) { 2547 return (FAILURE); 2548 } 2549 2550 t = (char *)malloc(len + 1); 2551 if (t == NULL) { 2552 return (FAILURE); 2553 } 2554 2555 (void) memcpy(t, argp, len + 1); 2556 2557 /* Now remmber to release t memory if exception occurs */ 2558 if (((dp = strchr(t, 'd')) == NULL) || 2559 ((tp = strchr(t, 't')) == NULL) || 2560 ((cp = strchr(t, 'c')) == NULL)) { 2561 free(t); 2562 return (FAILURE); 2563 } 2564 cp = t; 2565 2566 *dp = '\0'; 2567 dp++; 2568 *tp = '\0'; 2569 tp++; 2570 cp++; 2571 2572 if (is_fully_numeric(dp) == FALSE || 2573 is_fully_numeric(tp) == FALSE || 2574 is_fully_numeric(cp) == FALSE) { 2575 free(t); 2576 return (FAILURE); 2577 } 2578 2579 value_c = atoi(cp); 2580 value_t = atoi(tp); 2581 value_d = atoi(dp); 2582 2583 array_tagp->idl.target_id = value_t; 2584 array_tagp->idl.lun = value_d; 2585 2586 if (ctl_tagp != NULL) { 2587 *ctl_tagp = value_c; 2588 } 2589 2590 free(t); 2591 return (SUCCESS); 2592 } 2593 2594 /* 2595 * get_disk_tag_ctd(argp, disk_tagp) 2596 * This function parses disk string of ctd format, and translates it to 2597 * disk tag and controller tag. The tags is returned by out parameters. 2598 * The return value is SUCCESS if the string has legal format, or FAILURE 2599 * if it fails. 2600 */ 2601 static int 2602 get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp, uint32_t *ctl_tag) 2603 { 2604 char *t = NULL; 2605 char *cp = NULL; 2606 char *tp = NULL; 2607 char *dp = NULL; 2608 2609 uint32_t value_c = MAX32BIT; 2610 uint32_t value_t = MAX32BIT; 2611 uint32_t value_d = MAX32BIT; 2612 2613 int len = 0; 2614 2615 if (argp == NULL || (len = strlen(argp)) == 0 || 2616 disk_tagp == NULL) { 2617 return (FAILURE); 2618 } 2619 2620 t = (char *)malloc(len + 1); 2621 if (t == NULL) { 2622 return (FAILURE); 2623 } 2624 2625 (void) memcpy(t, argp, len + 1); 2626 2627 /* Now remmber to release t memory if exception occurs */ 2628 if (((dp = strchr(t, 'd')) == NULL) || 2629 ((tp = strchr(t, 't')) == NULL) || 2630 ((cp = strchr(t, 'c')) == NULL)) { 2631 free(t); 2632 return (FAILURE); 2633 } 2634 cp = t; 2635 2636 *dp = '\0'; 2637 dp++; 2638 *tp = '\0'; 2639 tp++; 2640 cp++; 2641 2642 if (is_fully_numeric(dp) == FALSE || 2643 is_fully_numeric(tp) == FALSE || 2644 is_fully_numeric(cp) == FALSE) { 2645 free(t); 2646 return (FAILURE); 2647 } 2648 2649 value_c = atoi(cp); 2650 value_t = atoi(tp); 2651 value_d = atoi(dp); 2652 2653 disk_tagp->cidl.bus = 0; 2654 disk_tagp->cidl.target_id = value_t; 2655 disk_tagp->cidl.lun = value_d; 2656 *ctl_tag = value_c; 2657 2658 free(t); 2659 return (SUCCESS); 2660 } 2661 2662 /* 2663 * get_disk_tag_cidl(argp, disk_tagp) 2664 * This function parses disk string of cidl format and translates it to tag. 2665 * The return value is disk tag if the string has legal format, or FAILURE 2666 * if it fails. 2667 */ 2668 static int 2669 get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp) 2670 { 2671 int len = 0; 2672 char *p = NULL; 2673 char *t = NULL; 2674 char *dot1p = NULL; 2675 char *dot2p = NULL; 2676 2677 if (argp == NULL || (len = strlen(argp)) == 0) { 2678 return (FAILURE); 2679 } 2680 2681 if (disk_tagp == NULL) { 2682 return (FAILURE); 2683 } 2684 2685 t = (char *)malloc(len + 1); 2686 if (t == NULL) { 2687 return (FAILURE); 2688 } 2689 2690 (void) memcpy(t, argp, len + 1); 2691 p = t; 2692 2693 dot2p = strrchr(p, '.'); 2694 if (dot2p == NULL) { 2695 free(t); 2696 return (FAILURE); 2697 } 2698 *dot2p = '\0'; 2699 dot2p++; 2700 2701 dot1p = strrchr(p, '.'); 2702 if (dot1p == NULL) { 2703 free(t); 2704 return (FAILURE); 2705 } 2706 *dot1p = '\0'; 2707 dot1p++; 2708 2709 /* Assert only 2 dots in this string */ 2710 if (strrchr(p, '.') != NULL) { 2711 free(t); 2712 return (FAILURE); 2713 } 2714 2715 while (*p == ' ') 2716 p++; 2717 2718 if (is_fully_numeric(p) == FALSE || 2719 is_fully_numeric(dot1p) == FALSE || 2720 is_fully_numeric(dot2p) == FALSE) { 2721 free(t); 2722 return (FAILURE); 2723 } 2724 2725 disk_tagp->cidl.bus = atoi(p); 2726 disk_tagp->cidl.target_id = atoi(dot1p); 2727 disk_tagp->cidl.lun = atoi(dot2p); 2728 2729 free(t); 2730 return (SUCCESS); 2731 } 2732 2733 /* 2734 * calc_size(sizep, valp) 2735 * This function calculates the value represented by string sizep. 2736 * The string sizep can be decomposed into three parts: an initial, 2737 * possibly empty, sequence of white-space characters; a subject digital 2738 * sequence interpreted as an integer with unit k/K/m/M/g/G/t/T; and a 2739 * final string of one or more unrecognized characters or white-sapce 2740 * characters, including the terminating null. If unrecognized character 2741 * exists or overflow happens, the conversion must fail and return 2742 * INVALID_ARG. If the conversion is performed successfully, result will 2743 * be saved into valp and function returns SUCCESS. It returns FAILURE 2744 * when memory allocation fails. 2745 */ 2746 static int 2747 calc_size(char *sizep, uint64_t *valp) 2748 { 2749 int len; 2750 uint64_t size; 2751 uint64_t unit; 2752 char *t = NULL; 2753 char *tailp = NULL; 2754 2755 if (sizep == NULL || valp == NULL) { 2756 return (INVALID_ARG); 2757 } 2758 2759 if (is_fully_numeric(sizep) == TRUE) { 2760 *valp = atoi(sizep); 2761 return (SUCCESS); 2762 } 2763 2764 len = strlen(sizep); 2765 if (len == 0) { 2766 return (INVALID_ARG); 2767 } 2768 2769 t = (char *)malloc(len + 1); 2770 if (t == NULL) { 2771 return (FAILURE); 2772 } 2773 2774 (void) memcpy(t, sizep, len + 1); 2775 2776 switch (*(t + len - 1)) { 2777 case 'k': 2778 case 'K': 2779 unit = 1024ull; 2780 errno = 0; 2781 size = strtoll(t, &tailp, 0); 2782 break; 2783 case 'm': 2784 case 'M': 2785 unit = 1024ull * 1024ull; 2786 errno = 0; 2787 size = strtoll(t, &tailp, 0); 2788 break; 2789 case 'g': 2790 case 'G': 2791 unit = 1024ull * 1024ull * 1024ull; 2792 errno = 0; 2793 size = strtoll(t, &tailp, 0); 2794 break; 2795 case 't': 2796 case 'T': 2797 unit = 1024ull * 1024ull * 1024ull * 1024ull; 2798 errno = 0; 2799 size = strtoll(t, &tailp, 0); 2800 break; 2801 default: 2802 /* The unit must be kilobyte at least. */ 2803 free(t); 2804 return (INVALID_ARG); 2805 } 2806 2807 *(t + len - 1) = '\0'; 2808 if (is_fully_numeric(t) != TRUE) { 2809 free(t); 2810 return (INVALID_ARG); 2811 } 2812 2813 errno = 0; 2814 size = strtoll(t, &tailp, 0); 2815 2816 /* Check overflow condition */ 2817 if (errno == ERANGE || (size > (MAX64BIT / unit))) { 2818 free(t); 2819 return (INVALID_ARG); 2820 } 2821 2822 *valp = size * unit; 2823 free(t); 2824 return (SUCCESS); 2825 } 2826 2827 /* 2828 * is_fully_numeric(str) 2829 * This function checks if the string are legal numeric string. The beginning 2830 * or ending characters can be white spaces. 2831 * Return value is TRUE if the string are legal numeric string, or FALSE 2832 * otherwise. 2833 */ 2834 static int 2835 is_fully_numeric(char *strp) 2836 { 2837 uint32_t len; 2838 uint32_t i; 2839 2840 if (strp == NULL) { 2841 return (FALSE); 2842 } 2843 2844 len = strlen(strp); 2845 if (len == 0) { 2846 return (FALSE); 2847 } 2848 2849 /* Skip whitespace characters */ 2850 for (i = 0; i < len; i++) { 2851 if (strp[i] != ' ') { 2852 break; 2853 } 2854 } 2855 2856 /* if strp points all space characters */ 2857 if (i == len) { 2858 return (FALSE); 2859 } 2860 2861 /* Check the digitals in string */ 2862 for (; i < len; i++) { 2863 if (!isdigit(strp[i])) { 2864 break; 2865 } 2866 } 2867 2868 /* Check the ending string */ 2869 for (; i < len; i++) { 2870 if (strp[i] != ' ') { 2871 return (FALSE); 2872 } 2873 } 2874 2875 return (TRUE); 2876 } 2877 2878 static int 2879 yes(void) 2880 { 2881 int i, b; 2882 char ans[SCHAR_MAX + 1]; 2883 2884 for (i = 0; ; i++) { 2885 b = getchar(); 2886 if (b == '\n' || b == '\0' || b == EOF) { 2887 ans[i] = 0; 2888 break; 2889 } 2890 if (i < SCHAR_MAX) { 2891 ans[i] = b; 2892 } 2893 } 2894 if (i >= SCHAR_MAX) { 2895 i = SCHAR_MAX; 2896 ans[SCHAR_MAX] = 0; 2897 } 2898 2899 return (rpmatch(ans)); 2900 } 2901 2902 /* 2903 * Function: int rpmatch(char *) 2904 * 2905 * Description: 2906 * 2907 * Internationalized get yes / no answer. 2908 * 2909 * Inputs: 2910 * s -> Pointer to answer to compare against. 2911 * 2912 * Returns: 2913 * TRUE -> Answer was affirmative 2914 * FALSE -> Answer was negative 2915 */ 2916 2917 static int 2918 rpmatch(char *s) 2919 { 2920 int status; 2921 2922 /* match yesexpr */ 2923 status = regexec(&re, s, (size_t)0, NULL, 0); 2924 if (status != 0) { 2925 return (FALSE); 2926 } 2927 return (TRUE); 2928 } 2929 2930 static int 2931 size_to_string(uint64_t size, char *string, int len) 2932 { 2933 int i = 0; 2934 uint32_t remainder; 2935 char unit[][2] = {" ", "K", "M", "G", "T"}; 2936 2937 if (string == NULL) { 2938 return (FAILURE); 2939 } 2940 while (size > 1023) { 2941 remainder = size % 1024; 2942 size /= 1024; 2943 i++; 2944 } 2945 2946 if (i > 4) { 2947 return (FAILURE); 2948 } 2949 2950 remainder /= 103; 2951 if (remainder == 0) { 2952 (void) snprintf(string, len, "%llu", size); 2953 } else { 2954 (void) snprintf(string, len, "%llu.%1u", size, 2955 remainder); 2956 } 2957 2958 /* make sure there is one byte for unit */ 2959 if ((strlen(string) + 1) >= len) { 2960 return (FAILURE); 2961 } 2962 (void) strlcat(string, unit[i], len); 2963 2964 return (SUCCESS); 2965 } 2966 2967 /* 2968 * Only one raidctl is running at one time. 2969 */ 2970 static int 2971 enter_raidctl_lock(int *fd) 2972 { 2973 int fd0 = -1; 2974 struct flock lock; 2975 2976 fd0 = open(RAIDCTL_LOCKF, O_CREAT|O_WRONLY, 0600); 2977 if (fd0 < 0) { 2978 if (errno == EACCES) { 2979 (void) fprintf(stderr, 2980 gettext("raidctl:must be root to run raidctl" 2981 ": %s\n"), strerror(errno)); 2982 } else { 2983 (void) fprintf(stderr, 2984 gettext("raidctl:failed to open lockfile" 2985 " '"RAIDCTL_LOCKF"': %s\n"), strerror(errno)); 2986 } 2987 return (FAILURE); 2988 } 2989 2990 *fd = fd0; 2991 lock.l_type = F_WRLCK; 2992 lock.l_whence = SEEK_SET; 2993 lock.l_start = 0; 2994 lock.l_len = 0; 2995 2996 if ((fcntl(fd0, F_SETLK, &lock) == -1) && 2997 (errno == EAGAIN || errno == EDEADLK)) { 2998 if (fcntl(fd0, F_GETLK, &lock) == -1) { 2999 (void) fprintf(stderr, 3000 gettext("raidctl:enter_filelock error\n")); 3001 return (FAILURE); 3002 } 3003 (void) fprintf(stderr, gettext("raidctl:" 3004 "enter_filelock:filelock is owned " 3005 "by 'process %d'\n"), lock.l_pid); 3006 return (FAILURE); 3007 } 3008 3009 return (SUCCESS); 3010 } 3011 3012 static void 3013 exit_raidctl_lock(int fd) 3014 { 3015 struct flock lock; 3016 3017 lock.l_type = F_UNLCK; 3018 lock.l_whence = SEEK_SET; 3019 lock.l_start = 0; 3020 lock.l_len = 0; 3021 if (fcntl(fd, F_SETLK, &lock) == -1) { 3022 (void) fprintf(stderr, gettext("raidctl: failed to" 3023 " exit_filelock: %s\n"), 3024 strerror(errno)); 3025 } 3026 (void) close(fd); 3027 } 3028