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