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 2008 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 == (char)NULL) || 268 (*yesstr == (char)NULL) || 269 (*nostr == (char)NULL) || 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\tProduct\t\tFirmware\t" 2018 "Capacity\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]; 2245 char product[DISK_PRODUCT_LEN]; 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) snprintf(vendor, sizeof (vendor), "%s", attrp->vendorid); 2261 (void) printf("%s\t", vendor); 2262 2263 (void) snprintf(product, sizeof (product), "%s", attrp->productid); 2264 (void) printf("%s\t", product); 2265 2266 (void) snprintf(revision, sizeof (revision), "%s", attrp->revision); 2267 (void) printf("%s\t\t", revision); 2268 2269 if (attrp->capacity != MAX64BIT) { 2270 if (size_to_string(attrp->capacity, capacity, 16) != SUCCESS) { 2271 return (FAILURE); 2272 } 2273 (void) printf("%s\t\t", capacity); 2274 } else { 2275 (void) printf(gettext("N/A")); 2276 } 2277 2278 if (attrp->state == DISK_STATE_GOOD) { 2279 (void) printf(gettext("GOOD")); 2280 } else if (attrp->state == DISK_STATE_FAILED) { 2281 (void) printf(gettext("FAILED")); 2282 } else { 2283 (void) printf(gettext("N/A")); 2284 } 2285 (void) printf("\t"); 2286 2287 /* Controller attribute */ 2288 if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { 2289 (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); 2290 return (FAILURE); 2291 } 2292 2293 hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP); 2294 if (hsp_handle == 0) { 2295 (void) printf(gettext("N/A\n")); 2296 } else { 2297 is_indent = FALSE; 2298 while (hsp_handle > 0) { 2299 if ((ret = raidcfg_get_attr(hsp_handle, 2300 &hsp_attr)) < 0) { 2301 (void) fprintf(stderr, "%s\n", 2302 raidcfg_errstr(ret)); 2303 return (FAILURE); 2304 } 2305 2306 if (is_indent == TRUE) { 2307 (void) printf("\t\t\t\t\t\t\t"); 2308 } else { 2309 is_indent = TRUE; 2310 } 2311 2312 if (hsp_attr.type == HSP_TYPE_LOCAL) { 2313 (void) snprintf(hsp, sizeof (hsp), 2314 "c%ut%llud%llu", 2315 ctl_attr.controller_id, 2316 hsp_attr.tag.idl.target_id, 2317 hsp_attr.tag.idl.lun); 2318 (void) printf("%s\n", hsp); 2319 } else if (hsp_attr.type == HSP_TYPE_GLOBAL) { 2320 (void) printf(gettext("Global\n")); 2321 } else { 2322 return (FAILURE); 2323 } 2324 2325 hsp_handle = raidcfg_list_next(hsp_handle); 2326 } 2327 } 2328 return (SUCCESS); 2329 } 2330 2331 2332 /* 2333 * print_indent(indent) 2334 * This function prints specified number of tab characters. It's used to 2335 * format layout. 2336 */ 2337 static void 2338 print_indent(uint8_t indent) 2339 { 2340 uint32_t i; 2341 for (i = 0; i < indent; i++) { 2342 (void) fprintf(stdout, "\t"); 2343 } 2344 } 2345 2346 /* 2347 * get_disk_handle_cidl(ctl_tag, disks_argp, comps_num, handlespp) 2348 * This function parses the string of disk argument, and gets the disks tag 2349 * and separators from the string. Then it translates the tag to handle, and 2350 * stores handles and separators to new buffer pointed by parameter handlespp. 2351 * The format of disk_arg must be C:ID:L, for example, it is 0.1.0. The first 2352 * "0" is channel number, and the second "1" is target number, and the third 2353 * "0" is LUN number. The disk tags are separated by comma and parenthesis. 2354 * Function returns SUCCESS or FAILURE. 2355 */ 2356 static int 2357 get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp, int *comps_nump, 2358 raid_obj_handle_t **handlespp) 2359 { 2360 int len = 0; 2361 int i = 0, j = 0; 2362 char *p, *t; 2363 char *delimit = " "; 2364 char *disks_str; 2365 disk_tag_t disk_tag; 2366 2367 if (disks_argp == NULL || comps_nump == NULL) { 2368 return (FAILURE); 2369 } 2370 2371 p = disks_argp; 2372 len = strlen(disks_argp); 2373 2374 if ((disks_str = (char *)malloc(3 * len + 4)) == NULL) { 2375 return (FAILURE); 2376 } 2377 2378 /* Insert whitespace between disk tags, '(' , and ')' */ 2379 disks_str[j ++] = '('; 2380 disks_str[j ++] = ' '; 2381 2382 while (p[i] != '\0') { 2383 if (p[i] == ')' || p[i] == '(') { 2384 disks_str[j ++] = ' '; 2385 disks_str[j ++] = p[i]; 2386 disks_str[j ++] = ' '; 2387 } else 2388 disks_str[j ++] = p[i]; 2389 i ++; 2390 } 2391 disks_str[j ++] = ' '; 2392 disks_str[j ++] = ')'; 2393 disks_str[j] = '\0'; 2394 2395 len = strlen(disks_str) + 1; 2396 2397 if ((t = (char *)malloc(len)) == NULL) { 2398 return (FAILURE); 2399 } 2400 (void) memcpy(t, disks_str, len); 2401 p = strtok(t, delimit); 2402 while (p != NULL) { 2403 (*comps_nump)++; 2404 p = strtok(NULL, delimit); 2405 } 2406 free(t); 2407 2408 *handlespp = calloc(*comps_nump, sizeof (raid_obj_handle_t)); 2409 if (*handlespp == NULL) { 2410 return (FAILURE); 2411 } 2412 2413 for (i = 0; i < *comps_nump; i++) 2414 (*handlespp)[i] = INIT_HANDLE_VALUE; 2415 2416 i = 0; 2417 p = strtok(disks_str, delimit); 2418 while (p != NULL) { 2419 if (*p == '(') { 2420 (*handlespp)[i] = OBJ_SEPARATOR_BEGIN; 2421 } else if (*p == ')') { 2422 (*handlespp)[i] = OBJ_SEPARATOR_END; 2423 } else { 2424 if (get_disk_tag_cidl(p, &disk_tag) != SUCCESS) { 2425 free(*handlespp); 2426 free(disks_str); 2427 return (INVALID_ARG); 2428 } 2429 (*handlespp)[i] = 2430 raidcfg_get_disk(raidcfg_get_controller(ctl_tag), 2431 disk_tag); 2432 if ((*handlespp)[i] <= 0) { 2433 (void) fprintf(stderr, "%s\n", 2434 raidcfg_errstr((*handlespp)[i])); 2435 free(*handlespp); 2436 free(disks_str); 2437 return (FAILURE); 2438 } 2439 } 2440 p = strtok(NULL, delimit); 2441 i++; 2442 } 2443 2444 free(disks_str); 2445 return (SUCCESS); 2446 } 2447 2448 /* 2449 * get_disk_handle_ctd(disks_num, disks_argpp, ctl_tagp, disks_handlep) 2450 * This function parses string of single disk with "ctd" format, for example, 2451 * c0t0d0, and translates it to controller tag and disk tag. 2452 * Then it calls lib api and get disk handle. The controller tag and disk 2453 * handle are both returned by out parameters. 2454 * The return value is SUCCESS or FAILURE. 2455 */ 2456 static int 2457 get_disk_handle_ctd(int disks_num, char **disks_argpp, uint32_t *ctl_tagp, 2458 raid_obj_handle_t *disks_handlep) 2459 { 2460 raid_obj_handle_t ctl_handle; 2461 disk_tag_t disk_tag; 2462 uint32_t ctl_id; 2463 int i; 2464 int ret; 2465 2466 if (disks_handlep == NULL) { 2467 return (FAILURE); 2468 } 2469 2470 for (i = 0; i < disks_num; i++) { 2471 if (get_disk_tag_ctd(disks_argpp[i], &disk_tag, &ctl_id) != 2472 SUCCESS) { 2473 return (INVALID_ARG); 2474 } 2475 2476 *ctl_tagp = ctl_id; 2477 2478 if (i == 0) { 2479 ctl_handle = raidcfg_get_controller(*ctl_tagp); 2480 if (ctl_handle <= 0) { 2481 (void) fprintf(stderr, "%s\n", 2482 raidcfg_errstr(ctl_handle)); 2483 return (FAILURE); 2484 } 2485 ret = raidcfg_open_controller(ctl_handle, NULL); 2486 if (ret < 0) { 2487 (void) fprintf(stderr, "%s\n", 2488 raidcfg_errstr(ret)); 2489 return (FAILURE); 2490 } 2491 } 2492 2493 if ((disks_handlep[i] = 2494 raidcfg_get_disk(ctl_handle, disk_tag)) < 0) { 2495 (void) fprintf(stderr, "%s\n", 2496 raidcfg_errstr(disks_handlep[i])); 2497 (void) raidcfg_close_controller(ctl_handle, NULL); 2498 return (FAILURE); 2499 } 2500 } 2501 2502 return (SUCCESS); 2503 } 2504 2505 /* 2506 * get_ctl_tag(argp) 2507 * This function translates controller string to tag. The return value is 2508 * SUCCESS if the string has legal format and is parsed successfully, 2509 * or FAILURE if it fails. 2510 */ 2511 static int 2512 get_ctl_tag(char *argp, uint32_t *ctl_tagp) 2513 { 2514 if (argp == NULL || is_fully_numeric(argp) == FALSE || 2515 ctl_tagp == NULL) { 2516 return (FAILURE); 2517 } 2518 *ctl_tagp = (atoi(argp)); 2519 return (SUCCESS); 2520 } 2521 2522 /* 2523 * get_array_tag(argp, ctl_tagp, array_tagp) 2524 * This function parses array string to get array tag and controller tag. 2525 * The return value is SUCCESS if the string has legal format, or 2526 * FAILURE if it fails. 2527 */ 2528 static int 2529 get_array_tag(char *argp, uint32_t *ctl_tagp, array_tag_t *array_tagp) 2530 { 2531 char *t = NULL; 2532 char *cp = NULL; 2533 char *tp = NULL; 2534 char *dp = NULL; 2535 2536 uint32_t value_c = MAX32BIT; 2537 uint32_t value_t = MAX32BIT; 2538 uint32_t value_d = MAX32BIT; 2539 2540 int len = 0; 2541 2542 if (argp == NULL || (len = strlen(argp)) == 0 || 2543 array_tagp == NULL) { 2544 return (FAILURE); 2545 } 2546 2547 t = (char *)malloc(len + 1); 2548 if (t == NULL) { 2549 return (FAILURE); 2550 } 2551 2552 (void) memcpy(t, argp, len + 1); 2553 2554 /* Now remmber to release t memory if exception occurs */ 2555 if (((dp = strchr(t, 'd')) == NULL) || 2556 ((tp = strchr(t, 't')) == NULL) || 2557 ((cp = strchr(t, 'c')) == NULL)) { 2558 free(t); 2559 return (FAILURE); 2560 } 2561 cp = t; 2562 2563 *dp = '\0'; 2564 dp++; 2565 *tp = '\0'; 2566 tp++; 2567 cp++; 2568 2569 if (is_fully_numeric(dp) == FALSE || 2570 is_fully_numeric(tp) == FALSE || 2571 is_fully_numeric(cp) == FALSE) { 2572 free(t); 2573 return (FAILURE); 2574 } 2575 2576 value_c = atoi(cp); 2577 value_t = atoi(tp); 2578 value_d = atoi(dp); 2579 2580 array_tagp->idl.target_id = value_t; 2581 array_tagp->idl.lun = value_d; 2582 2583 if (ctl_tagp != NULL) { 2584 *ctl_tagp = value_c; 2585 } 2586 2587 free(t); 2588 return (SUCCESS); 2589 } 2590 2591 /* 2592 * get_disk_tag_ctd(argp, disk_tagp) 2593 * This function parses disk string of ctd format, and translates it to 2594 * disk tag and controller tag. The tags is returned by out parameters. 2595 * The return value is SUCCESS if the string has legal format, or FAILURE 2596 * if it fails. 2597 */ 2598 static int 2599 get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp, uint32_t *ctl_tag) 2600 { 2601 char *t = NULL; 2602 char *cp = NULL; 2603 char *tp = NULL; 2604 char *dp = NULL; 2605 2606 uint32_t value_c = MAX32BIT; 2607 uint32_t value_t = MAX32BIT; 2608 uint32_t value_d = MAX32BIT; 2609 2610 int len = 0; 2611 2612 if (argp == NULL || (len = strlen(argp)) == 0 || 2613 disk_tagp == NULL) { 2614 return (FAILURE); 2615 } 2616 2617 t = (char *)malloc(len + 1); 2618 if (t == NULL) { 2619 return (FAILURE); 2620 } 2621 2622 (void) memcpy(t, argp, len + 1); 2623 2624 /* Now remmber to release t memory if exception occurs */ 2625 if (((dp = strchr(t, 'd')) == NULL) || 2626 ((tp = strchr(t, 't')) == NULL) || 2627 ((cp = strchr(t, 'c')) == NULL)) { 2628 free(t); 2629 return (FAILURE); 2630 } 2631 cp = t; 2632 2633 *dp = '\0'; 2634 dp++; 2635 *tp = '\0'; 2636 tp++; 2637 cp++; 2638 2639 if (is_fully_numeric(dp) == FALSE || 2640 is_fully_numeric(tp) == FALSE || 2641 is_fully_numeric(cp) == FALSE) { 2642 free(t); 2643 return (FAILURE); 2644 } 2645 2646 value_c = atoi(cp); 2647 value_t = atoi(tp); 2648 value_d = atoi(dp); 2649 2650 disk_tagp->cidl.bus = 0; 2651 disk_tagp->cidl.target_id = value_t; 2652 disk_tagp->cidl.lun = value_d; 2653 *ctl_tag = value_c; 2654 2655 free(t); 2656 return (SUCCESS); 2657 } 2658 2659 /* 2660 * get_disk_tag_cidl(argp, disk_tagp) 2661 * This function parses disk string of cidl format and translates it to tag. 2662 * The return value is disk tag if the string has legal format, or FAILURE 2663 * if it fails. 2664 */ 2665 static int 2666 get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp) 2667 { 2668 int len = 0; 2669 char *p = NULL; 2670 char *t = NULL; 2671 char *dot1p = NULL; 2672 char *dot2p = NULL; 2673 2674 if (argp == NULL || (len = strlen(argp)) == 0) { 2675 return (FAILURE); 2676 } 2677 2678 if (disk_tagp == NULL) { 2679 return (FAILURE); 2680 } 2681 2682 t = (char *)malloc(len + 1); 2683 if (t == NULL) { 2684 return (FAILURE); 2685 } 2686 2687 (void) memcpy(t, argp, len + 1); 2688 p = t; 2689 2690 dot2p = strrchr(p, '.'); 2691 if (dot2p == NULL) { 2692 free(t); 2693 return (FAILURE); 2694 } 2695 *dot2p = '\0'; 2696 dot2p++; 2697 2698 dot1p = strrchr(p, '.'); 2699 if (dot1p == NULL) { 2700 free(t); 2701 return (FAILURE); 2702 } 2703 *dot1p = '\0'; 2704 dot1p++; 2705 2706 /* Assert only 2 dots in this string */ 2707 if (strrchr(p, '.') != NULL) { 2708 free(t); 2709 return (FAILURE); 2710 } 2711 2712 while (*p == ' ') 2713 p++; 2714 2715 if (is_fully_numeric(p) == FALSE || 2716 is_fully_numeric(dot1p) == FALSE || 2717 is_fully_numeric(dot2p) == FALSE) { 2718 free(t); 2719 return (FAILURE); 2720 } 2721 2722 disk_tagp->cidl.bus = atoi(p); 2723 disk_tagp->cidl.target_id = atoi(dot1p); 2724 disk_tagp->cidl.lun = atoi(dot2p); 2725 2726 free(t); 2727 return (SUCCESS); 2728 } 2729 2730 /* 2731 * calc_size(sizep, valp) 2732 * This function calculates the value represented by string sizep. 2733 * The string sizep can be decomposed into three parts: an initial, 2734 * possibly empty, sequence of white-space characters; a subject digital 2735 * sequence interpreted as an integer with unit k/K/m/M/g/G/t/T; and a 2736 * final string of one or more unrecognized characters or white-sapce 2737 * characters, including the terminating null. If unrecognized character 2738 * exists or overflow happens, the conversion must fail and return 2739 * INVALID_ARG. If the conversion is performed successfully, result will 2740 * be saved into valp and function returns SUCCESS. It returns FAILURE 2741 * when memory allocation fails. 2742 */ 2743 static int 2744 calc_size(char *sizep, uint64_t *valp) 2745 { 2746 int len; 2747 uint64_t size; 2748 uint64_t unit; 2749 char *t = NULL; 2750 char *tailp = NULL; 2751 2752 if (sizep == NULL || valp == NULL) { 2753 return (INVALID_ARG); 2754 } 2755 2756 if (is_fully_numeric(sizep) == TRUE) { 2757 *valp = atoi(sizep); 2758 return (SUCCESS); 2759 } 2760 2761 len = strlen(sizep); 2762 if (len == 0) { 2763 return (INVALID_ARG); 2764 } 2765 2766 t = (char *)malloc(len + 1); 2767 if (t == NULL) { 2768 return (FAILURE); 2769 } 2770 2771 (void) memcpy(t, sizep, len + 1); 2772 2773 switch (*(t + len - 1)) { 2774 case 'k': 2775 case 'K': 2776 unit = 1024ull; 2777 errno = 0; 2778 size = strtoll(t, &tailp, 0); 2779 break; 2780 case 'm': 2781 case 'M': 2782 unit = 1024ull * 1024ull; 2783 errno = 0; 2784 size = strtoll(t, &tailp, 0); 2785 break; 2786 case 'g': 2787 case 'G': 2788 unit = 1024ull * 1024ull * 1024ull; 2789 errno = 0; 2790 size = strtoll(t, &tailp, 0); 2791 break; 2792 case 't': 2793 case 'T': 2794 unit = 1024ull * 1024ull * 1024ull * 1024ull; 2795 errno = 0; 2796 size = strtoll(t, &tailp, 0); 2797 break; 2798 default: 2799 /* The unit must be kilobyte at least. */ 2800 free(t); 2801 return (INVALID_ARG); 2802 } 2803 2804 *(t + len - 1) = '\0'; 2805 if (is_fully_numeric(t) != TRUE) { 2806 free(t); 2807 return (INVALID_ARG); 2808 } 2809 2810 errno = 0; 2811 size = strtoll(t, &tailp, 0); 2812 2813 /* Check overflow condition */ 2814 if (errno == ERANGE || (size > (MAX64BIT / unit))) { 2815 free(t); 2816 return (INVALID_ARG); 2817 } 2818 2819 *valp = size * unit; 2820 free(t); 2821 return (SUCCESS); 2822 } 2823 2824 /* 2825 * is_fully_numeric(str) 2826 * This function checks if the string are legal numeric string. The beginning 2827 * or ending characters can be white spaces. 2828 * Return value is TRUE if the string are legal numeric string, or FALSE 2829 * otherwise. 2830 */ 2831 static int 2832 is_fully_numeric(char *strp) 2833 { 2834 uint32_t len; 2835 uint32_t i; 2836 2837 if (strp == NULL) { 2838 return (FALSE); 2839 } 2840 2841 len = strlen(strp); 2842 if (len == 0) { 2843 return (FALSE); 2844 } 2845 2846 /* Skip whitespace characters */ 2847 for (i = 0; i < len; i++) { 2848 if (strp[i] != ' ') { 2849 break; 2850 } 2851 } 2852 2853 /* if strp points all space characters */ 2854 if (i == len) { 2855 return (FALSE); 2856 } 2857 2858 /* Check the digitals in string */ 2859 for (; i < len; i++) { 2860 if (!isdigit(strp[i])) { 2861 break; 2862 } 2863 } 2864 2865 /* Check the ending string */ 2866 for (; i < len; i++) { 2867 if (strp[i] != ' ') { 2868 return (FALSE); 2869 } 2870 } 2871 2872 return (TRUE); 2873 } 2874 2875 static int 2876 yes(void) 2877 { 2878 int i, b; 2879 char ans[SCHAR_MAX + 1]; 2880 2881 for (i = 0; ; i++) { 2882 b = getchar(); 2883 if (b == '\n' || b == '\0' || b == EOF) { 2884 ans[i] = 0; 2885 break; 2886 } 2887 if (i < SCHAR_MAX) { 2888 ans[i] = b; 2889 } 2890 } 2891 if (i >= SCHAR_MAX) { 2892 i = SCHAR_MAX; 2893 ans[SCHAR_MAX] = 0; 2894 } 2895 2896 return (rpmatch(ans)); 2897 } 2898 2899 /* 2900 * Function: int rpmatch(char *) 2901 * 2902 * Description: 2903 * 2904 * Internationalized get yes / no answer. 2905 * 2906 * Inputs: 2907 * s -> Pointer to answer to compare against. 2908 * 2909 * Returns: 2910 * TRUE -> Answer was affirmative 2911 * FALSE -> Answer was negative 2912 */ 2913 2914 static int 2915 rpmatch(char *s) 2916 { 2917 int status; 2918 2919 /* match yesexpr */ 2920 status = regexec(&re, s, (size_t)0, NULL, 0); 2921 if (status != 0) { 2922 return (FALSE); 2923 } 2924 return (TRUE); 2925 } 2926 2927 static int 2928 size_to_string(uint64_t size, char *string, int len) 2929 { 2930 int i = 0; 2931 uint32_t remainder; 2932 char unit[][2] = {" ", "K", "M", "G", "T"}; 2933 2934 if (string == NULL) { 2935 return (FAILURE); 2936 } 2937 while (size > 1023) { 2938 remainder = size % 1024; 2939 size /= 1024; 2940 i++; 2941 } 2942 2943 if (i > 4) { 2944 return (FAILURE); 2945 } 2946 2947 remainder /= 103; 2948 if (remainder == 0) { 2949 (void) snprintf(string, len, "%llu", size); 2950 } else { 2951 (void) snprintf(string, len, "%llu.%1u", size, 2952 remainder); 2953 } 2954 2955 /* make sure there is one byte for unit */ 2956 if ((strlen(string) + 1) >= len) { 2957 return (FAILURE); 2958 } 2959 (void) strlcat(string, unit[i], len); 2960 2961 return (SUCCESS); 2962 } 2963 2964 /* 2965 * Only one raidctl is running at one time. 2966 */ 2967 static int 2968 enter_raidctl_lock(int *fd) 2969 { 2970 int fd0 = -1; 2971 struct flock lock; 2972 2973 fd0 = open(RAIDCTL_LOCKF, O_CREAT|O_WRONLY, 0600); 2974 if (fd0 < 0) { 2975 if (errno == EACCES) { 2976 (void) fprintf(stderr, 2977 gettext("raidctl:must be root to run raidctl" 2978 ": %s\n"), strerror(errno)); 2979 } else { 2980 (void) fprintf(stderr, 2981 gettext("raidctl:failed to open lockfile" 2982 " '"RAIDCTL_LOCKF"': %s\n"), strerror(errno)); 2983 } 2984 return (FAILURE); 2985 } 2986 2987 *fd = fd0; 2988 lock.l_type = F_WRLCK; 2989 lock.l_whence = SEEK_SET; 2990 lock.l_start = 0; 2991 lock.l_len = 0; 2992 2993 if ((fcntl(fd0, F_SETLK, &lock) == -1) && 2994 (errno == EAGAIN || errno == EDEADLK)) { 2995 if (fcntl(fd0, F_GETLK, &lock) == -1) { 2996 (void) fprintf(stderr, 2997 gettext("raidctl:enter_filelock error\n")); 2998 return (FAILURE); 2999 } 3000 (void) fprintf(stderr, gettext("raidctl:" 3001 "enter_filelock:filelock is owned " 3002 "by 'process %d'\n"), lock.l_pid); 3003 return (FAILURE); 3004 } 3005 3006 return (SUCCESS); 3007 } 3008 3009 static void 3010 exit_raidctl_lock(int fd) 3011 { 3012 struct flock lock; 3013 3014 lock.l_type = F_UNLCK; 3015 lock.l_whence = SEEK_SET; 3016 lock.l_start = 0; 3017 lock.l_len = 0; 3018 if (fcntl(fd, F_SETLK, &lock) == -1) { 3019 (void) fprintf(stderr, gettext("raidctl: failed to" 3020 " exit_filelock: %s\n"), 3021 strerror(errno)); 3022 } 3023 (void) close(fd); 3024 } 3025