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/CDDL.txt 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/CDDL.txt. 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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "@(#)trigger_common.cc 1.16 08/05/20 SMI" 28 29 #if defined(_FAULT_INJECTION) 30 31 // 32 // Common routines for the trigger_* utilities. 33 // 34 35 #include <sys/types.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <stdio.h> 39 #include <limits.h> 40 #include <string.h> 41 #include <errno.h> 42 43 #include "trigger_common.h" 44 45 // 46 // Global structure for storing options and arguments. 47 // 48 49 opts_args_t opts_args; 50 51 static void append_fault_arg(void *arg, size_t len); 52 static int parse_fault_arg_char(char *arg); 53 static int parse_fault_arg_int(char *arg); 54 static int parse_fault_arg_uint(char *arg); 55 static int parse_fault_arg_short(char *arg); 56 static int parse_fault_arg_ushort(char *arg); 57 static int parse_fault_arg_long(char *arg); 58 static int parse_fault_arg_ulong(char *arg); 59 static int parse_fault_arg_longlong(char *arg); 60 static int parse_fault_arg_ulonglong(char *arg); 61 static int parse_fault_arg_string(char *arg); 62 63 // 64 // parse_node_ids() 65 // 66 // Parses the -n option argument which specifies one or more node ID's 67 // separated by commas. 68 // 69 // Parameters: 70 // arg -- points to the option argument. 71 // 72 // Returns: 73 // 0 if successful, -1 otherwise. 74 // 75 // Side Effects: 76 // Modifies the string pointed to by 'arg' (strtok() is used). 77 // Stores the parsed node ID's in a dynamically-allocated array. 78 // If successful, the global opts_args.node_ids structure member will 79 // point to this array, and opts_args.num_node_ids will contain the 80 // number of node ID's in the array. 81 // Prints messages to stderr when an error occurs. 82 // 83 84 int 85 parse_node_ids(char *arg) 86 { 87 int *nids = NULL; // array of node IDs 88 int arrsize = 0, num_nids = 0; 89 int failed = 0; 90 char *ptr; 91 92 // One or more node IDs separated by commas. 93 ptr = strtok(arg, ","); 94 do { 95 char *endptr; 96 long value; 97 98 // If array needs to be enlarged... 99 if (num_nids >= arrsize) { 100 arrsize += 64; 101 nids = (int *)realloc(nids, 102 arrsize * sizeof (nids[0])); 103 if (nids == NULL) { 104 perror("ERROR: realloc() failed"); 105 failed = 1; 106 break; 107 } 108 } 109 110 // If current node... 111 if (strcasecmp(ptr, "this") == 0) { 112 nids[num_nids++] = TRIGGER_THIS_NODE; 113 continue; 114 } 115 116 // If all nodes... 117 if (strcasecmp(ptr, "all") == 0) { 118 // "all" takes precedence. 119 nids[0] = TRIGGER_ALL_NODES; 120 num_nids = 1; 121 break; // we're done 122 } 123 124 // Else convert to number. 125 errno = 0; 126 value = strtol(ptr, &endptr, 0); 127 if (errno) { 128 perror("ERROR: invalid node ID"); 129 failed = 1; 130 break; 131 } 132 133 // If there are extra characters... 134 if (*endptr != '\0') { 135 fprintf(stderr, "ERROR: invalid node ID\n"); 136 failed = 1; 137 break; 138 } 139 140 // Make sure node ID is a positive value. 141 if (value <= 0) { 142 fprintf(stderr, "ERROR: node ID must be > 0\n"); 143 failed = 1; 144 break; 145 } 146 147 nids[num_nids++] = value; 148 } while (ptr = strtok(NULL, ",")); 149 150 if (failed) { 151 free(nids); 152 return (-1); 153 } 154 155 opts_args.node_ids = nids; 156 opts_args.num_node_ids = num_nids; 157 return (0); 158 } 159 160 // 161 // parse_generic_op() 162 // 163 // Parses the generic operation to take when fault triggers 164 // 165 // Parameters: 166 // arg -- points to the command line argument 167 // 168 // Returns: 169 // 0 if succesful, -1 otherwise 170 // 171 // Side effects: 172 // Stores the result sin the global opts_args.generic_op structure member 173 // Prints messages to stderr when an error occurs 174 175 int 176 parse_generic_op(char *arg) 177 { 178 // Set the flag up 179 opts_args.generic = 1; 180 181 if (strcmp(arg, "panic") == 0) { 182 opts_args.generic_op = FaultFunctions::PANIC; 183 184 } else if (strcmp(arg, "reboot") == 0) { 185 opts_args.generic_op = FaultFunctions::REBOOT; 186 187 } else if (strcmp(arg, "reboot_once") == 0) { 188 opts_args.generic_op = FaultFunctions::REBOOT_ONCE; 189 190 } else if (strcmp(arg, "reboot_specified") == 0) { 191 opts_args.generic_op = FaultFunctions::REBOOT_SPECIFIED; 192 193 } else if (strcmp(arg, "cmm_reboot") == 0) { 194 opts_args.generic_op = FaultFunctions::CMM_REBOOT; 195 196 } else if (strcmp(arg, "sleep") == 0) { 197 opts_args.generic_op = FaultFunctions::SLEEP; 198 199 } else if (strcmp(arg, "pxfs_sleep") == 0) { 200 opts_args.generic_op = FaultFunctions::PXFS_SLEEP; 201 202 } else if (strcmp(arg, "pxfs_resolve") == 0) { 203 opts_args.generic_op = FaultFunctions::PXFS_RESOLVE; 204 205 } else if (strcmp(arg, "sleep_once") == 0) { 206 opts_args.generic_op = FaultFunctions::SLEEP_ONCE; 207 208 } else if (strcmp(arg, "sema_p") == 0) { 209 opts_args.generic_op = FaultFunctions::SEMA_P; 210 211 } else if (strcmp(arg, "sema_p_once") == 0) { 212 opts_args.generic_op = FaultFunctions::SEMA_P_ONCE; 213 214 } else if (strcmp(arg, "sema_p_specified") == 0) { 215 opts_args.generic_op = FaultFunctions::SEMA_P_SPECIFIED; 216 217 } else if (strcmp(arg, "sema_v") == 0) { 218 opts_args.generic_op = FaultFunctions::SEMA_V; 219 220 } else if (strcmp(arg, "sema_v_once") == 0) { 221 opts_args.generic_op = FaultFunctions::SEMA_V_ONCE; 222 223 } else if (strcmp(arg, "sema_v_specified") == 0) { 224 opts_args.generic_op = FaultFunctions::SEMA_V_SPECIFIED; 225 226 } else if (strcmp(arg, "switchover") == 0) { 227 opts_args.generic_op = FaultFunctions::SWITCHOVER; 228 229 } else { 230 fprintf(stderr, "ERROR: invalid generic op type\n"); 231 return (-1); 232 } 233 234 return (0); 235 } 236 237 // 238 // parse_fault_num() 239 // 240 // Parses the fault number argument. 241 // 242 // Parameters: 243 // arg -- points to the command line argument. 244 // 245 // Returns: 246 // 0 if successful, -1 otherwise. 247 // 248 // Side Effects: 249 // Stores the result in the global opts_args.fault_num structure member. 250 // Prints messages to stderr when an error occurs. 251 // 252 253 int 254 parse_fault_num(char *arg) 255 { 256 char *endptr; 257 258 errno = 0; 259 opts_args.fault_num = strtoul(arg, &endptr, 0); 260 if (errno) { 261 perror("ERROR: invalid fault number"); 262 return (-1); 263 } 264 265 // If there are extra characters... 266 if (*endptr != '\0') { 267 fprintf(stderr, "ERROR: invalid fault number\n"); 268 return (-1); 269 } 270 271 return (0); 272 } 273 274 // 275 // append_fault_arg() 276 // 277 // Appends a fault argument to opts_args.fault_argp. 278 // 279 // Parameters: 280 // arg -- points to the fault argument. 281 // len -- length, in bytes, of arguments to append. 282 // 283 // Returns: 284 // None. 285 // 286 287 static void 288 append_fault_arg(void *arg, size_t len) 289 { 290 if (len == 0) { 291 return; 292 } 293 294 opts_args.fault_argp = realloc(opts_args.fault_argp, 295 opts_args.fault_argsize + len); 296 memcpy((char *)opts_args.fault_argp + opts_args.fault_argsize, arg, 297 len); 298 opts_args.fault_argsize += len; // update size 299 } 300 301 // 302 // parse_fault_arg() 303 // 304 // Parses and converts the fault argument command-line argument. 305 // The conversion performed is based on the argument's type specifier 306 // (see usage[] for trigger_add for more info). 307 // 308 // Parameters: 309 // arg -- points to the command line argument. 310 // 311 // Returns: 312 // 0 if successful, -1 otherwise. 313 // 314 // Side Effects: 315 // Modifies the string pointed to by 'arg' (changes 1st ':' to '\0'). 316 // Calls the following functions to do the actual conversion: 317 // 318 // parse_fault_arg_char() (type: char) 319 // parse_fault_arg_int() (type: int) 320 // parse_fault_arg_uint() (type: unsigned int) 321 // parse_fault_arg_short() (type: short) 322 // parse_fault_arg_ushort() (type: unsigned short) 323 // parse_fault_arg_long() (type: long) 324 // parse_fault_arg_ulong() (type: unsigned long) 325 // parse_fault_arg_longlong() (type: long long) 326 // parse_fault_arg_ulonglong() (type: unsigned long long) 327 // parse_fault_arg_string() (type: string) 328 // 329 // Prints messages to stderr when an error occurs. 330 // 331 332 int 333 parse_fault_arg(char *arg) 334 { 335 char *colon, *after_colon; 336 337 // If arg doesn't begin with '%', assume string fault arg (default). 338 if (arg[0] != '%') { 339 return (parse_fault_arg_string(arg)); 340 } 341 342 // Find the ':' delimiter. 343 colon = strchr(arg, ':'); 344 if (colon == NULL) { 345 fprintf(stderr, "ERROR: unknown type specifier in fault " 346 "argument\n"); 347 return (-1); 348 } 349 350 *colon = '\0'; // separate type spec 351 after_colon = colon + 1; // string following ':' 352 353 // 354 // Convert fault arg based on type specifier. 355 // 356 357 // char 358 if (strcasecmp(arg, "%c") == 0) { 359 return (parse_fault_arg_char(after_colon)); 360 } 361 362 // int 363 if (strcasecmp(arg, "%d") == 0 || strcasecmp(arg, "%i") == 0) { 364 return (parse_fault_arg_int(after_colon)); 365 } 366 367 // unsigned int 368 if (strcasecmp(arg, "%u") == 0) { 369 return (parse_fault_arg_uint(after_colon)); 370 } 371 372 // short 373 if (strcasecmp(arg, "%hd") == 0 || strcasecmp(arg, "%hi") == 0) { 374 return (parse_fault_arg_short(after_colon)); 375 } 376 377 // unsigned short 378 if (strcasecmp(arg, "%hu") == 0) { 379 return (parse_fault_arg_ushort(after_colon)); 380 } 381 382 // long 383 if (strcasecmp(arg, "%ld") == 0 || strcasecmp(arg, "%li") == 0) { 384 return (parse_fault_arg_long(after_colon)); 385 } 386 387 // unsigned long 388 if (strcasecmp(arg, "%lu") == 0) { 389 return (parse_fault_arg_ulong(after_colon)); 390 } 391 392 // long long 393 if (strcasecmp(arg, "%lld") == 0 || strcasecmp(arg, "%lli") == 0) { 394 return (parse_fault_arg_longlong(after_colon)); 395 } 396 397 // unsigned long long 398 if (strcasecmp(arg, "%llu") == 0) { 399 return (parse_fault_arg_ulonglong(after_colon)); 400 } 401 402 // string 403 if (strcasecmp(arg, "%s") == 0) { 404 return (parse_fault_arg_string(after_colon)); 405 } 406 407 // Otherwise it's an error. 408 fprintf(stderr, "ERROR: unknown type specifier \"%s\" in " 409 "fault argument\n", arg); 410 return (-1); 411 } 412 413 static int 414 parse_fault_arg_char(char *arg) 415 { 416 append_fault_arg(arg, sizeof (char)); 417 return (0); 418 } 419 420 static int 421 parse_fault_arg_int(char *arg) 422 { 423 int flt_arg; 424 425 // Make sure there is fault argument. 426 if (*arg == '\0') { 427 fprintf(stderr, "ERROR: invalid int fault argument\n"); 428 return (-1); 429 } 430 431 // As a convenience allow user to specify "INT_MAX" or "INT_MIN". 432 if (strcasecmp(arg, "INT_MAX") == 0) { 433 flt_arg = INT_MAX; 434 } else if (strcasecmp(arg, "INT_MIN") == 0) { 435 flt_arg = INT_MIN; 436 } else { 437 long value; 438 char *endptr; 439 440 errno = 0; 441 value = strtol(arg, &endptr, 0); 442 if (errno) { 443 perror("ERROR: invalid int fault argument"); 444 return (-1); 445 } 446 447 // If there are extra characters... 448 if (*endptr != '\0') { 449 fprintf(stderr, "ERROR: invalid int fault argument\n"); 450 return (-1); 451 } 452 453 // In case sizeof(long) > sizeof(int). 454 if (value > INT_MAX || value < INT_MIN) { 455 fprintf(stderr, "ERROR: invalid int fault argument: " 456 "%s\n", strerror(ERANGE)); 457 return (-1); 458 } 459 460 flt_arg = (int)value; 461 } 462 463 append_fault_arg(&flt_arg, sizeof (flt_arg)); 464 return (0); 465 } 466 467 static int 468 parse_fault_arg_uint(char *arg) 469 { 470 unsigned int flt_arg; 471 472 // Make sure there is fault argument. 473 if (*arg == '\0') { 474 fprintf(stderr, "ERROR: invalid unsigned int " 475 "fault argument\n"); 476 return (-1); 477 } 478 479 // As a convenience allow user to specify "UINT_MAX" or "UINT_MIN". 480 if (strcasecmp(arg, "UINT_MAX") == 0) { 481 flt_arg = UINT_MAX; 482 } else if (strcasecmp(arg, "UINT_MIN") == 0) { 483 flt_arg = 0; // UINT_MIN is 0 484 } else { 485 unsigned long value; 486 char *endptr; 487 488 errno = 0; 489 value = strtoul(arg, &endptr, 0); 490 if (errno) { 491 perror("ERROR: invalid unsigned int fault argument"); 492 return (-1); 493 } 494 495 // If there are extra characters... 496 if (*endptr != '\0') { 497 fprintf(stderr, "ERROR: invalid unsigned int " 498 "fault argument\n"); 499 return (-1); 500 } 501 502 // In case sizeof(ulong_t) > sizeof(uint_t). 503 if (value > UINT_MAX) { 504 fprintf(stderr, "ERROR: invalid unsigned int " 505 "fault argument: %s\n", strerror(ERANGE)); 506 return (-1); 507 } 508 509 flt_arg = (unsigned int) value; 510 } 511 512 append_fault_arg(&flt_arg, sizeof (flt_arg)); 513 return (0); 514 } 515 516 static int 517 parse_fault_arg_short(char *arg) 518 { 519 short flt_arg; 520 521 // Make sure there is fault argument. 522 if (*arg == '\0') { 523 fprintf(stderr, "ERROR: invalid short fault argument\n"); 524 return (-1); 525 } 526 527 // As a convenience allow user to specify "SHRT_MAX" or "SHRT_MIN". 528 if (strcasecmp(arg, "SHRT_MAX") == 0) { 529 flt_arg = SHRT_MAX; 530 } else if (strcasecmp(arg, "SHRT_MIN") == 0) { 531 flt_arg = SHRT_MIN; 532 } else { 533 long value; 534 char *endptr; 535 536 errno = 0; 537 value = strtol(arg, &endptr, 0); 538 if (errno) { 539 perror("ERROR: invalid short fault argument"); 540 return (-1); 541 } 542 543 // If there are extra characters... 544 if (*endptr != '\0') { 545 fprintf(stderr, "ERROR: invalid short " 546 "fault argument\n"); 547 return (-1); 548 } 549 550 // Verify range. 551 if (value > SHRT_MAX || value < SHRT_MIN) { 552 fprintf(stderr, "ERROR: invalid short " 553 "fault argument: %s\n", strerror(ERANGE)); 554 return (-1); 555 } 556 557 flt_arg = (short)value; 558 } 559 560 append_fault_arg(&flt_arg, sizeof (flt_arg)); 561 return (0); 562 } 563 564 static int 565 parse_fault_arg_ushort(char *arg) 566 { 567 unsigned short flt_arg; 568 569 // Make sure there is fault argument. 570 if (*arg == '\0') { 571 fprintf(stderr, "ERROR: invalid unsigned short " 572 "fault argument\n"); 573 return (-1); 574 } 575 576 // As a convenience allow user to specify "USHRT_MAX" or "USHRT_MIN". 577 if (strcasecmp(arg, "USHRT_MAX") == 0) { 578 flt_arg = USHRT_MAX; 579 } else if (strcasecmp(arg, "USHRT_MIN") == 0) { 580 flt_arg = 0; // USHRT_MIN is 0 581 } else { 582 unsigned long value; 583 char *endptr; 584 585 errno = 0; 586 value = strtoul(arg, &endptr, 0); 587 if (errno) { 588 perror("ERROR: invalid unsigned short fault argument"); 589 return (-1); 590 } 591 592 // If there are extra characters... 593 if (*endptr != '\0') { 594 fprintf(stderr, "ERROR: invalid unsigned short " 595 "fault argument\n"); 596 return (-1); 597 } 598 599 // Verify range. 600 if (value > USHRT_MAX) { 601 fprintf(stderr, "ERROR: invalid unsigned short " 602 "fault argument: %s\n", strerror(ERANGE)); 603 return (-1); 604 } 605 606 flt_arg = (unsigned short) value; 607 } 608 609 append_fault_arg(&flt_arg, sizeof (flt_arg)); 610 return (0); 611 } 612 613 static int 614 parse_fault_arg_long(char *arg) 615 { 616 long flt_arg; 617 618 // Make sure there is fault argument 619 if (*arg == '\0') { 620 fprintf(stderr, "ERROR: invalid long fault argument\n"); 621 return (-1); 622 } 623 624 // As a convenience allow user to specify "LONG_MAX" or "LONG_MIN". 625 if (strcasecmp(arg, "LONG_MAX") == 0) { 626 flt_arg = LONG_MAX; 627 } else if (strcasecmp(arg, "LONG_MIN") == 0) { 628 flt_arg = LONG_MIN; 629 } else { 630 char *endptr; 631 632 errno = 0; 633 flt_arg = strtol(arg, &endptr, 0); 634 if (errno) { 635 perror("ERROR: invalid long fault argument"); 636 return (-1); 637 } 638 639 // If there are extra characters... 640 if (*endptr != '\0') { 641 fprintf(stderr, "ERROR: invalid long " 642 "fault argument\n"); 643 return (-1); 644 } 645 } 646 647 append_fault_arg(&flt_arg, sizeof (flt_arg)); 648 return (0); 649 } 650 651 static int 652 parse_fault_arg_ulong(char *arg) 653 { 654 unsigned long flt_arg; 655 656 // Make sure there is fault argument. 657 if (*arg == '\0') { 658 fprintf(stderr, "ERROR: invalid unsigned long " 659 "fault argument\n"); 660 return (-1); 661 } 662 663 // As a convenience allow user to specify "ULONG_MAX" or "ULONG_MIN". 664 if (strcasecmp(arg, "ULONG_MAX") == 0) { 665 flt_arg = ULONG_MAX; 666 } else if (strcasecmp(arg, "ULONG_MIN") == 0) { 667 flt_arg = 0; // ULONG_MIN is 0 668 } else { 669 char *endptr; 670 671 errno = 0; 672 flt_arg = strtoul(arg, &endptr, 0); 673 if (errno) { 674 perror("ERROR: invalid unsigned long fault argument"); 675 return (-1); 676 } 677 678 // If there are extra characters... 679 if (*endptr != '\0') { 680 fprintf(stderr, "ERROR: invalid unsigned long " 681 "fault argument\n"); 682 return (-1); 683 } 684 } 685 686 append_fault_arg(&flt_arg, sizeof (flt_arg)); 687 return (0); 688 } 689 690 static int 691 parse_fault_arg_longlong(char *arg) 692 { 693 long long flt_arg; 694 695 // Make sure there is fault argument. 696 if (*arg == '\0') { 697 fprintf(stderr, "ERROR: invalid long long " 698 "fault argument\n"); 699 return (-1); 700 } 701 702 // As a convenience allow user to specify "LLONG_MAX" or "LLONG_MIN". 703 if (strcasecmp(arg, "LLONG_MAX") == 0) { 704 flt_arg = LLONG_MAX; 705 } else if (strcasecmp(arg, "LLONG_MIN") == 0) { 706 flt_arg = LLONG_MIN; 707 } else { 708 char *endptr; 709 710 errno = 0; 711 flt_arg = strtoll(arg, &endptr, 0); 712 if (errno) { 713 perror("ERROR: invalid long long fault argument"); 714 return (-1); 715 } 716 717 // If there are extra characters... 718 if (*endptr != '\0') { 719 fprintf(stderr, "ERROR: invalid long long " 720 "fault argument\n"); 721 return (-1); 722 } 723 } 724 725 append_fault_arg(&flt_arg, sizeof (flt_arg)); 726 return (0); 727 } 728 729 static int 730 parse_fault_arg_ulonglong(char *arg) 731 { 732 unsigned long long flt_arg; 733 734 // Make sure there is fault argument. 735 if (*arg == '\0') { 736 fprintf(stderr, "ERROR: invalid unsigned long long " 737 "fault argument\n"); 738 return (-1); 739 } 740 741 // As a convenience allow user to set "ULLONG_MAX" or "ULLONG_MIN". 742 if (strcasecmp(arg, "ULLONG_MAX") == 0) { 743 flt_arg = ULLONG_MAX; 744 } else if (strcasecmp(arg, "ULLONG_MIN") == 0) { 745 flt_arg = 0; // ULLONG_MIN is 0 746 } else { 747 char *endptr; 748 749 errno = 0; 750 flt_arg = strtoull(arg, &endptr, 0); 751 if (errno) { 752 perror("ERROR: invalid unsigned long long " 753 "fault argument"); 754 return (-1); 755 } 756 757 // If there are extra characters... 758 if (*endptr != '\0') { 759 fprintf(stderr, "ERROR: invalid unsigned long long " 760 "fault argument\n"); 761 return (-1); 762 } 763 } 764 765 append_fault_arg(&flt_arg, sizeof (flt_arg)); 766 return (0); 767 } 768 769 static int 770 parse_fault_arg_string(char *arg) 771 { 772 append_fault_arg(arg, strlen(arg) + 1); 773 return (0); 774 } 775 776 #endif // _FAULT_INJECTION 777