Home | History | Annotate | Download | only in fault_injection
      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