/* * Disktest * Copyright (c) International Business Machines Corp., 2001 * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Please send e-mail to yardleyb@us.ibm.com if you have * questions or comments. * * Project Website: TBD * * $Id: parse.c,v 1.8 2009/02/26 12:02:23 subrata_modak Exp $ * */ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <signal.h> #include <time.h> #include <errno.h> #include <fcntl.h> #include <string.h> #include <ctype.h> #include <sys/stat.h> #include "globals.h" #include "threading.h" #include "main.h" #include "usage.h" #include "sfunc.h" #include "parse.h" int fill_cld_args(int argc, char **argv, child_args_t * args) { extern char *optarg; extern int optind; extern unsigned long glb_flags; signed char c; char *leftovers; while ((c = getopt(argc, argv, "?a:A:B:cC:dD:E:f:Fh:I:K:L:m:M:nN:o:p:P:qQrR:s:S:t:T:wvV:z")) != -1) { switch (c) { case ':': pMsg(WARN, args, "Missing argument for perameter.\n"); usage(); return (-1); case 'V': #ifdef _DEBUG if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); exit(1); } if (!isdigit(optarg[0])) { pMsg(WARN, args, "-%c argument is non numeric.\n", c); exit(1); } gbl_dbg_lvl = atoi(optarg); #else pMsg(ERR, args, "Debug code not compiled in, recompile with _DEBUG directive.\n", c); exit(1); #endif break; case 'd': glb_flags |= GLB_FLG_QUIET; args->flags |= CLD_FLG_DUMP; break; case 'a': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (!isdigit(optarg[0])) { pMsg(WARN, args, "-%c arguments is non numeric.\n", c); return (-1); } args->seed = (unsigned int)strtol(optarg, NULL, 0); break; case 'A': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); exit(1); } if (strchr(optarg, 'g')) { glb_flags |= GLB_FLG_KILL; } if (strchr(optarg, 'c')) { args->flags &= ~CLD_FLG_ALLDIE; } if (strchr(optarg, 'm')) { args->flags |= CLD_FLG_ERR_MARK; } if (strchr(optarg, 'r')) { args->flags &= ~CLD_FLG_ERR_REREAD; } if (strchr(optarg, 's')) { args->flags &= ~CLD_FLG_LBA_SYNC; } if (strchr(optarg, 'S')) { args->flags |= CLD_FLG_IO_SERIAL; } if (strchr(optarg, 'w')) { args->flags |= CLD_FLG_WRITE_ONCE; } if (strchr(optarg, 'W')) { args->flags |= CLD_FLG_UNIQ_WRT; } if (strchr(optarg, 't')) { args->flags |= CLD_FLG_TMO_ERROR; } break; case 'q': glb_flags |= GLB_FLG_QUIET; break; case 'Q': glb_flags |= GLB_FLG_SUPRESS; break; case 'v': pMsg(INFO, args, "Version %s\n", VER_STR); exit(0); case 'p': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (args->flags & (CLD_FLG_LINEAR | CLD_FLG_RANDOM)) { pMsg(WARN, args, "Only one seek type, -p, can be specified.\n"); return (-1); } /* seek pattern type */ if (strchr(optarg, 'L')) args->flags |= CLD_FLG_LINEAR; else if (strchr(optarg, 'l')) args->flags |= (CLD_FLG_LINEAR | CLD_FLG_NTRLVD); else if (strchr(optarg, 'R')) args->flags |= CLD_FLG_RANDOM; else if (strchr(optarg, 'r')) args->flags |= (CLD_FLG_RANDOM | CLD_FLG_NTRLVD); else { pMsg(WARN, args, "Unknown Seek pattern\n"); usage(); return (-1); } if (strchr(optarg, 'U') || strchr(optarg, 'u')) if ((args->flags & (CLD_FLG_LINEAR)) && !(args->flags & CLD_FLG_LUND)) args->flags |= CLD_FLG_LUNU; if (strchr(optarg, 'D') || strchr(optarg, 'd')) if ((args->flags & (CLD_FLG_LINEAR)) && !(args->flags & CLD_FLG_LUNU)) args->flags |= CLD_FLG_LUND; break; case 'B': if (!isdigit(optarg[0])) { pMsg(WARN, args, "-%c arguments is non numeric.\n", c); return (-1); } if (strchr(optarg, ':') != NULL) { /* we are given a range of transfer sizes */ args->flags |= CLD_FLG_RTRSIZ; args->ltrsiz = strtoul(optarg, &leftovers, 10); if (leftovers == strchr(leftovers, 'k')) { /* first value had a 'k' */ args->ltrsiz *= 2; leftovers++; } else if (leftovers == strchr(leftovers, 'm')) { /* first value had a 'm' */ args->ltrsiz *= (2 * 1024); leftovers++; } else { if (args->ltrsiz > 256) args->ltrsiz /= BLK_SIZE; } if (!isdigit(leftovers[1])) { pMsg(WARN, args, "-%c arguments is non numeric.\n", c); return (-1); } args->htrsiz = atol((char *)strchr(leftovers, ':') + 1); if ((strchr(leftovers, 'k')) != NULL) { /* second value had a 'k' */ args->htrsiz *= 2; } else if ((strchr(leftovers, 'm')) != NULL) { /* second value had a 'm' */ args->htrsiz *= (2 * 1024); } else { if (args->htrsiz > 256) args->htrsiz /= BLK_SIZE; } } else { /* only a single value given for transfer size */ args->ltrsiz = atoi(optarg); if (strchr(optarg, 'k')) { args->ltrsiz *= 2; } else if (strchr(optarg, 'm')) { args->ltrsiz *= (2 * 1024); } else { if (args->ltrsiz > 256) args->ltrsiz /= BLK_SIZE; } args->htrsiz = args->ltrsiz; } #ifdef _DEBUG PDBG5(DBUG, args, "Parsed Transfer size: %ld\n", args->htrsiz); #endif break; case 'c': if (args->flags & CLD_FLG_PTYPS) { pMsg(WARN, args, "Please specify only one pattern type\n"); usage(); return (-1); } args->flags |= CLD_FLG_CPTYPE; break; case 'n': if (args->flags & CLD_FLG_PTYPS) { pMsg(WARN, args, "Please specify only one pattern type\n"); usage(); return (-1); } args->flags |= CLD_FLG_LPTYPE; break; case 'f': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (args->flags & CLD_FLG_PTYPS) { pMsg(WARN, args, "Please specify only one pattern type\n"); usage(); return (-1); } args->pattern = my_strtofft(optarg); args->flags |= CLD_FLG_FPTYPE; break; case 'F': /* the filespec is a list of filespecs in a file */ args->flags |= CLD_FLG_FSLIST; break; case 'z': if (args->flags & CLD_FLG_PTYPS) { pMsg(WARN, args, "Please specify only one pattern type\n"); usage(); return (-1); } args->flags |= CLD_FLG_RPTYPE; break; case 'h': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (!isdigit(optarg[0])) { pMsg(WARN, args, "-%c arguments is non numeric.\n", c); usage(); return (-1); } args->flags |= CLD_FLG_HBEAT; args->hbeat = atoi(optarg); if (strchr(optarg, 'm')) { /* multiply by sec */ args->hbeat *= 60; } else if (strchr(optarg, 'h')) { /* multiply sec*min */ args->hbeat *= (time_t) (60 * 60); } else if (strchr(optarg, 'd')) { /* multiply by sec*min*hours */ args->hbeat *= (time_t) (60 * 60 * 24); } break; case 'D': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (!isdigit(optarg[0])) { pMsg(WARN, args, "-%c arguments is non numeric.\n", c); usage(); return (-1); } args->rperc = atoi(optarg); args->wperc = atoi((char *)(strchr(optarg, ':') + 1)); args->flags |= CLD_FLG_DUTY; break; case 'r': args->flags |= CLD_FLG_R; break; case 'w': args->flags |= CLD_FLG_W; break; case 'o': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } args->offset = atol(optarg); args->flags |= CLD_FLG_OFFSET; break; case 'R': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (strchr(optarg, ':') != NULL) { /* we are given a retry delay */ args->retries = strtol(optarg, &leftovers, 10); args->retry_delay = (time_t) atol((char *)strchr(leftovers, ':') + 1); } else { /* only a retry count given */ args->retries = atoi(optarg); } break; case 'M': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } args->flags |= CLD_FLG_ALT_MARK; args->alt_mark = my_strtofft(optarg); break; case 'm': args->flags |= CLD_FLG_MBLK; if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (strchr(optarg, 'l')) { /* returns NULL if char is not found */ args->flags |= CLD_FLG_MRK_LBA; } if (strchr(optarg, 'p')) { args->flags |= CLD_FLG_MRK_PASS; } if (strchr(optarg, 't')) { args->flags |= CLD_FLG_MRK_TIME; } if (strchr(optarg, 's')) { args->flags |= CLD_FLG_MRK_SEED; } if (strchr(optarg, 'h')) { args->flags |= CLD_FLG_MRK_HOST; } if (strchr(optarg, 'f')) { args->flags |= CLD_FLG_MRK_TARGET; } if (strchr(optarg, 'a')) { args->flags |= CLD_FLG_MRK_ALL; } if (!strchr(optarg, 'l') && !strchr(optarg, 'p') && !strchr(optarg, 't') && !strchr(optarg, 's') && !strchr(optarg, 'h') && !strchr(optarg, 'f') && !strchr(optarg, 'a')) { pMsg(WARN, args, "Unknown header mark option\n"); return (-1); } break; case 'E': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (!isdigit(optarg[0])) { pMsg(WARN, args, "-%c arguments are non numeric.\n", c); usage(); return (-1); } args->flags |= CLD_FLG_CMPR; args->cmp_lng = strtol(optarg, NULL, 0); if (strchr(optarg, 'k')) { /* multiply by 2^10 */ args->cmp_lng <<= 10; } else if (strchr(optarg, 'K')) { /* multiply 10^3 */ args->cmp_lng *= 1000; } else if (strchr(optarg, 'm')) { /* multiply by 2^20 */ args->cmp_lng <<= 20; } else if (strchr(optarg, 'M')) { /* multiply by 10^6 */ args->cmp_lng *= 1000000; } break; case 'N': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (!isdigit(optarg[0])) { pMsg(WARN, args, "-%c arguments are non numeric.\n", c); return (-1); } args->flags |= CLD_FLG_VSIZ; args->vsiz = my_strtofft(optarg); if (strchr(optarg, 'k')) { /* multiply by 2^10 */ args->vsiz <<= 10; } else if (strchr(optarg, 'K')) { /* multiply 10^3 */ args->vsiz *= 1000; } else if (strchr(optarg, 'm')) { /* multiply by 2^20 */ args->vsiz <<= 20; } else if (strchr(optarg, 'M')) { /* multiply by 10^6 */ args->vsiz *= 1000000; } else if (strchr(optarg, 'g')) { /* multiply by 2^30 */ args->vsiz <<= 30; } else if (strchr(optarg, 'G')) { /* multiply by 10^9 */ args->vsiz *= 1000000000; } break; case 'I': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (strchr(optarg, 'R') || strchr(optarg, 'r')) { if (!(args->flags & CLD_FLG_BLK) && !(args->flags & CLD_FLG_FILE)) { args->flags |= CLD_FLG_RAW; } else { pMsg(WARN, args, "Can only specify one IO type\n"); return (-1); } } if (strchr(optarg, 'B') || strchr(optarg, 'b')) { if (!(args->flags & CLD_FLG_RAW) && !(args->flags & CLD_FLG_FILE)) { args->flags |= CLD_FLG_BLK; } else { pMsg(WARN, args, "Can only specify one IO type\n"); return (-1); } } if (strchr(optarg, 'F') || strchr(optarg, 'f')) { if (!(args->flags & CLD_FLG_RAW) && !(args->flags & CLD_FLG_BLK)) { args->flags |= CLD_FLG_FILE; } else { pMsg(WARN, args, "Can only specify one IO type\n"); return (-1); } } if (strchr(optarg, 'D') || strchr(optarg, 'd')) { args->flags |= CLD_FLG_DIRECT; } if (strchr(optarg, 's')) { args->sync_interval = strtoul((char *)strchr(optarg, 's') + 1, NULL, 10); #ifdef _DEBUG PDBG3(DBUG, args, "Parsed sync interval: %ld\n", args->sync_interval); #endif if ((args->flags & CLD_FLG_DIRECT)) { pMsg(ERR, args, "Can't specify sync with Direct IO\n"); return (-1); } args->flags |= CLD_FLG_WFSYNC; } break; case 't': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (strchr(optarg, ':') != NULL) { /* we are given a option for delay & timeout */ args->delayTimeMin = strtoul(optarg, &leftovers, 10); /* check to see if we have one or more then one ':' */ if ((char *)strchr(optarg, ':') == (char *)strrchr(optarg, ':')) { /* only one ':', assume no random delayTime, and ioTimeout */ args->delayTimeMax = args->delayTimeMin; args->ioTimeout = (time_t) atol((char *) strchr(leftovers, ':') + 1); } else { /* more then one ':', assume random delayTime, and ioTimeout */ args->delayTimeMax = strtoul(leftovers + 1, &leftovers, 10); args->ioTimeout = (time_t) atol((char *) strchr(leftovers, ':') + 1); } if (strchr(leftovers, 'm')) { /* multiply by sec */ args->ioTimeout *= 60; } else if (strchr(leftovers, 'h')) { /* multiply sec*min */ args->ioTimeout *= (time_t) (60 * 60); } else if (strchr(leftovers, 'd')) { /* multiply by sec*min*hours */ args->ioTimeout *= (time_t) (60 * 60 * 24); } } else { args->delayTimeMin = strtoul(optarg, NULL, 10); args->delayTimeMax = args->delayTimeMin; } break; case 'T': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } args->run_time = atoi(optarg); args->flags |= CLD_FLG_TMD; if (strchr(optarg, 'm')) { /* multiply by sec */ args->run_time *= 60; } else if (strchr(optarg, 'h')) { /* multiply sec*min */ args->run_time *= (time_t) (60 * 60); } else if (strchr(optarg, 'd')) { /* multiply by sec*min*hours */ args->run_time *= (time_t) (60 * 60 * 24); } break; case 'L': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } args->seeks = atoi(optarg); args->flags |= CLD_FLG_SKS; if (strchr(optarg, 'k')) { /* multiply by 2^10 */ args->seeks <<= 10; } else if (strchr(optarg, 'K')) { /* multiply 10^3 */ args->seeks *= 1000; } else if (strchr(optarg, 'm')) { /* multiply by 2^20 */ args->seeks <<= 20; } else if (strchr(optarg, 'M')) { /* multiply by 10^6 */ args->seeks *= 1000000; } else if (strchr(optarg, 'g')) { /* multiply by 2^30 */ args->seeks <<= 30; } else if (strchr(optarg, 'G')) { /* multiply by 10^9 */ args->seeks *= 1000000000; } break; case 'C': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (!isdigit(optarg[0])) { pMsg(WARN, args, "-%c arguments is non numeric.\n", c); usage(); return (-1); } args->flags |= CLD_FLG_CYC; args->cycles = atol(optarg); break; case 'K': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (!isdigit(optarg[0])) { pMsg(WARN, args, "-%c arguments is non numeric.\n", c); usage(); return (-1); } if (atoi(optarg) > MAX_THREADS) { pMsg(WARN, args, "%u exceeds max of %u threads.\n", atoi(optarg), MAX_THREADS); return (-1); } args->t_kids = atoi(optarg); break; case 'P': if (optarg == NULL) { pMsg(WARN, args, "-%c option requires an argument.\n", c); return (-1); } if (strchr(optarg, 'X')) { /* returns NULL if char is not found */ args->flags |= CLD_FLG_XFERS; } if (strchr(optarg, 'T')) { args->flags |= CLD_FLG_TPUTS; } if (strchr(optarg, 'P')) { glb_flags |= GLB_FLG_PERFP; } if (strchr(optarg, 'R')) { args->flags |= CLD_FLG_RUNT; } if (strchr(optarg, 'C')) { args->flags |= CLD_FLG_PCYC; } if (strchr(optarg, 'A')) { args->flags |= CLD_FLG_PRFTYPS; } if (!strchr(optarg, 'P') && !strchr(optarg, 'A') && !strchr(optarg, 'X') && !strchr(optarg, 'R') && !strchr(optarg, 'C') && !strchr(optarg, 'T')) { pMsg(WARN, args, "Unknown performance option\n"); return (-1); } break; case 'S': if (!isdigit((int)optarg[0])) { pMsg(WARN, args, "-%c arguments is non numeric.\n", c); return (-1); } args->flags |= CLD_FLG_BLK_RNG; if (strchr(optarg, ':') != NULL) { /* we are given a range */ args->start_blk = (OFF_T) strtoul(optarg, &leftovers, 0); if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */ args->start_blk <<= 10; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */ args->start_blk *= 1000; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */ args->start_blk <<= 20; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */ args->start_blk *= 1000000; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */ args->start_blk <<= 30; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */ args->start_blk *= 1000000000; leftovers++; /* at the ':' */ } leftovers++; /* should be at the next value */ if (!isdigit((int)leftovers[0])) { pMsg(WARN, args, "-%c arguments is non numeric.\n", c); return (-1); } args->stop_blk = (OFF_T) strtoul(leftovers, &leftovers, 0); if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */ args->stop_blk <<= 10; } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */ args->stop_blk *= 1000; } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */ args->stop_blk <<= 20; } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */ args->stop_blk *= 1000000; } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */ args->stop_blk <<= 30; } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */ args->stop_blk *= 1000000000; } } else { /* only a single value given */ args->start_blk = (OFF_T) strtoul(optarg, &leftovers, 0); if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */ args->start_blk <<= 10; } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */ args->start_blk *= 1000; } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */ args->start_blk <<= 20; } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */ args->start_blk *= 1000000; } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */ args->start_blk <<= 30; } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */ args->start_blk *= 1000000000; } } break; case 's': if (!isdigit((int)optarg[0])) { pMsg(WARN, args, "-%c argument is non numeric.\n", c); return (-1); } args->flags |= CLD_FLG_LBA_RNG; if (strchr(optarg, ':') != NULL) { /* we are given a range */ args->start_lba = (OFF_T) strtoul(optarg, &leftovers, 0); if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */ args->start_lba <<= 10; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */ args->start_lba *= 1000; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */ args->start_lba <<= 20; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */ args->start_lba *= 1000000; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */ args->start_lba <<= 30; leftovers++; /* at the ':' */ } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */ args->start_lba *= 1000000000; leftovers++; /* at the ':' */ } leftovers++; /* should be at the next value */ if (!isdigit((int)leftovers[0])) { pMsg(WARN, args, "-%c second argument is non numeric.\n", c); return (-1); } args->stop_lba = (OFF_T) strtoul(leftovers, &leftovers, 0); if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */ args->stop_lba <<= 10; } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */ args->stop_lba *= 1000; } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */ args->stop_lba <<= 20; } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */ args->stop_lba *= 1000000; } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */ args->stop_lba <<= 30; } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */ args->stop_lba *= 1000000000; } } else { /* only a single value given */ args->start_lba = (OFF_T) strtoul(optarg, &leftovers, 0); if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */ args->start_lba <<= 10; } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */ args->start_lba *= 1000; } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */ args->start_lba <<= 20; } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */ args->start_lba *= 1000000; } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */ args->start_lba <<= 30; } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */ args->start_lba *= 1000000000; } } break; case '?': default: usage(); return (-1); } } if (argv[optind] == NULL) { pMsg(WARN, args, "Unspecified target.\n"); return (-1); } strncpy(args->device, argv[optind], (DEV_NAME_LEN - 1)); return 0; } int make_assumptions(child_args_t * args) { char TmpStr[80]; struct stat stat_buf; int rv; if (!(args->flags & CLD_FLG_IOTYPS)) { /* use stat to get file properties, and use to set -I */ rv = stat(args->device, &stat_buf); if (0 == rv) { if (IS_FILE(stat_buf.st_mode)) { strncat(args->argstr, "(-I f) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_FILE; } else if (IS_BLK(stat_buf.st_mode)) { strncat(args->argstr, "(-I b) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_BLK; #ifndef WINDOWS } else if (S_ISCHR(stat_buf.st_mode)) { strncat(args->argstr, "(-I r) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_RAW; #endif } } else { pMsg(WARN, args, "Can't get status on %s, defaulting to file, errno = %d\n", args->device, GETLASTERROR()); strncat(args->argstr, "(-I f) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_FILE; } } if ((args->flags & CLD_FLG_WFSYNC) && (0 == args->sync_interval)) { pMsg(INFO, args, "Sync interval set to zero, assuming interval of 1.\n"); args->sync_interval = 1; } if (args->ltrsiz <= 0) { sprintf(TmpStr, "(-B %d) ", TRSIZ * BLK_SIZE); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->ltrsiz = TRSIZ; args->htrsiz = TRSIZ; } if (args->flags & CLD_FLG_LBA_RNG) { args->start_blk = args->start_lba / args->htrsiz; if (!(args->stop_lba < 0)) args->stop_blk = args->stop_lba / args->htrsiz; } if (args->flags & CLD_FLG_BLK_RNG) { args->start_lba = args->start_blk * args->htrsiz; if (!(args->stop_blk < 0)) args->stop_lba = (args->stop_blk * args->htrsiz) + (args->htrsiz - 1); } /* if vsiz is still not set, try and get it from the file */ if ((args->vsiz <= 0) && (args->flags & CLD_FLG_FILE)) { if (0 != get_file_size(args->device)) { /* file size retrieved */ args->vsiz = get_file_size(args->device); } } /* if vsiz is still not set, try and get it from the device */ if ((args->vsiz <= 0) && !(args->flags & CLD_FLG_FILE)) { args->vsiz = get_vsiz(args->device); } /* if vsiz is still not set, set based on given range */ if ((args->vsiz <= 0) && (args->flags & (CLD_FLG_LBA_RNG | CLD_FLG_BLK_RNG))) { if (!(args->stop_lba < 0)) args->vsiz = args->stop_lba + 1; else args->vsiz = args->start_lba + 1; } /* if vsiz is still not set, then set it to the default size */ if (args->vsiz <= 0) { args->vsiz = VSIZ; } if (!(args->flags & CLD_FLG_VSIZ)) { sprintf(TmpStr, N_ASSUME, args->vsiz); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); } if (args->stop_lba == -1) { args->stop_lba = args->vsiz - 1; } if (args->stop_blk == -1) { args->stop_blk = (args->stop_lba / (OFF_T) args->htrsiz); } if (args->t_kids == 0) { sprintf(TmpStr, "(-K %d) ", KIDS); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->t_kids = KIDS; } if ((args->flags & (CLD_FLG_W | CLD_FLG_R)) == 0) { if (args->flags & CLD_FLG_DUTY) { /* no read/write but duty cycle specified */ if (args->rperc > 0) { args->flags |= CLD_FLG_R; strncat(args->argstr, "(-r) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); } if (args->wperc > 0) { args->flags |= CLD_FLG_W; strncat(args->argstr, "(-w) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); } } else { strncat(args->argstr, "(-r) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_R; } } if (!(args->flags & CLD_FLG_PTYPS)) { strncat(args->argstr, "(-c) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_CPTYPE; } if (!(args->flags & CLD_FLG_SKTYPS)) { strncat(args->argstr, "(-p R) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_RANDOM; } if (!(args->flags & CLD_FLG_SKS)) { if (args->start_blk == args->stop_blk) { /* diskcache test, w/ no seek count set */ args->seeks = SEEKS; } else if (args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG)) { /* range set, w/ no seek count */ args->seeks = args->stop_blk - args->start_blk + 1; } else { /* if vsiz is available, calculated seeks are in terms of the largest transfer size */ args->seeks = (args->vsiz > 0) ? (args->vsiz / args->htrsiz) : SEEKS; } if ((args->flags & CLD_FLG_LINEAR) && (args->flags & CLD_FLG_R) && (args->flags & CLD_FLG_W)) { args->seeks *= 2; } if (!(args->flags & CLD_FLG_TMD)) { sprintf(TmpStr, L_ASSUME, args->seeks); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); } } if (!(args->flags & (CLD_FLG_SKS | CLD_FLG_TMD)) || ((args->flags & CLD_FLG_CYC) && !(args->flags & (CLD_FLG_SKS | CLD_FLG_TMD)))) { args->flags |= CLD_FLG_SKS; } if (args->flags & (CLD_FLG_LINEAR)) { if (!(args->flags & (CLD_FLG_LUNU | CLD_FLG_LUND))) { strncat(args->argstr, "(-p u) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_LUNU; } } normalize_percs(args); if (!(args->flags & CLD_FLG_DUTY) && (args->flags & CLD_FLG_RANDOM) && !(args->flags & CLD_FLG_NTRLVD)) { sprintf(TmpStr, "(-D %d:%d) ", args->rperc, args->wperc); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_DUTY; } if ((args->delayTimeMin == 0) && (args->delayTimeMax == 0) && (args->ioTimeout == DEFAULT_IO_TIMEOUT)) { strncat(args->argstr, "(-t 0:2m) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); } if (!(args->flags & CLD_FLG_OFFSET)) { strncat(args->argstr, "(-o 0) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); } return 0; } /* * checks validity of data after parsing * args and make assumtions. returns 0 on * success and -1 on failure. */ int check_conclusions(child_args_t * args) { extern unsigned long glb_flags; struct stat stat_buf; int rv; if ((args->flags & CLD_FLG_DUTY) && ((args->flags & CLD_FLG_LINEAR) || (args->flags & CLD_FLG_NTRLVD))) { pMsg(WARN, args, "Duty cycle testing is supported for random (-pR) tests only.\n"); return (-1); } if ((args->flags & CLD_FLG_BLK_RNG) && (args->flags & CLD_FLG_RTRSIZ)) { pMsg(WARN, args, "Can't have unfixed block sizes and specify seek range in terms of blocks.\n"); return (-1); } if ((args->vsiz < 0) || (args->ltrsiz < 1) || (args->htrsiz < 1)) { pMsg(WARN, args, "Bounds exceeded for transfer size and/or volume size.\n"); pMsg(WARN, args, MAXTRSIZ, (args->htrsiz * BLK_SIZE), args->vsiz); return (-1); } if (args->htrsiz < args->ltrsiz) { pMsg(ERR, args, "Min transfer size, %lu, greater then Max transfer size, %lu.\n", args->ltrsiz, args->htrsiz); return (-1); } if (args->vsiz < (args->stop_lba - args->start_lba + 1)) { pMsg(ERR, args, "Volume stop block/lba exceeds volume size.\n"); return (-1); } if (args->vsiz < args->htrsiz) { pMsg(WARN, args, VSIZETS, args->vsiz, args->htrsiz); return (-1); } if ((args->flags & CLD_FLG_TMD) == 0 && (args->seeks <= 0)) { pMsg(WARN, args, TSEEK, args->seeks); return (-1); } if ((args->flags & CLD_FLG_SKS) && (args->t_kids > args->seeks)) { pMsg(WARN, args, "Can't have more children then max number of seeks, use -K/-L to adjust.\n"); return (-1); } if ((args->start_blk > args->vsiz) && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) { pMsg(WARN, args, STBGTTLBA, args->start_blk, (args->vsiz / args->htrsiz)); return (-1); } if ((args->stop_blk > args->vsiz) && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) { pMsg(WARN, args, SBGTTLBA, args->stop_blk, (args->vsiz / args->htrsiz)); return (-1); } if ((args->start_lba > args->vsiz) && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) { pMsg(WARN, args, STLBAGTLBA, args->start_lba, args->vsiz); return (-1); } if ((args->stop_lba > args->vsiz) && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) { pMsg(WARN, args, SLBAGTLBA, args->stop_lba, args->vsiz); return (-1); } if (args->start_blk > args->stop_blk) { pMsg(WARN, args, SBRSB, args->stop_blk, args->start_blk); return (-1); } if (args->start_lba > args->stop_lba) { pMsg(ERR, args, SLBARSLBA, args->stop_lba, args->start_lba); return (-1); } if ((args->flags & CLD_FLG_LBA_RNG) && (args->flags & CLD_FLG_BLK_RNG)) { pMsg(ERR, args, "Can't specify range in both block and LBA, use -s or -S.\n"); return (-1); } /* use stat to get file properties, and test then agains specified -I */ rv = stat(args->device, &stat_buf); if (0 == rv) { /* no error on call to stat, compare against -I option */ /* files are usually file type */ if ((args->flags & CLD_FLG_FILE) && !IS_FILE(stat_buf.st_mode)) { pMsg(ERR, args, "Can't open non-file filespec with file device type, -If.\n"); return (-1); } /* block devices, are usually block type */ if ((args->flags & CLD_FLG_BLK) && !IS_BLK(stat_buf.st_mode)) { pMsg(ERR, args, "Can't open non-block filespec with block device type, -Ib.\n"); return (-1); } #ifndef WINDOWS /* raw devices, are usually character type */ if ((args->flags & CLD_FLG_RAW) && !S_ISCHR(stat_buf.st_mode)) { pMsg(ERR, args, "Can't open non-raw filespec with raw device type, -Ir.\n"); return (-1); } #else if (args->flags & CLD_FLG_RAW) { pMsg(ERR, args, "RAW IO type not supported in Windows, use direct IO instead.\n"); return (-1); } #endif #ifdef _DEBUG } else { PDBG1(DBUG, args, "Can't get status on %s, assuming a new file, errno = %d\n", args->device, GETLASTERROR()); #endif } if ((args->hbeat > 0) && (args->flags & CLD_FLG_TMD) && (args->hbeat > args->run_time)) { pMsg(ERR, args, "Heartbeat should be at least equal to runtime, use -h/-T to adjust.\n"); return (-1); } if ((args->hbeat > 0) && !(args->flags & CLD_FLG_PRFTYPS)) { pMsg(ERR, args, "At least one performance option, -P, must be specified when using -h.\n"); return (-1); } if ((args->flags & CLD_FLG_W) && !(args->flags & CLD_FLG_R) && (args->flags & CLD_FLG_CMPR)) { pMsg(ERR, args, "Write only, ignoring option -E.\n"); } if ((args->flags & CLD_FLG_TMD) && (args->flags & CLD_FLG_SKS)) { pMsg(ERR, args, "Can't specify both -L and -T they are mutually exclusive.\n"); return (-1); } if (((args->flags & CLD_FLG_R) && !(args->flags & CLD_FLG_W)) && (args->flags & CLD_FLG_ERR_MARK)) { pMsg(ERR, args, "Can't specify mark on error, -Am, in read only mode.\n"); return (-1); } if (!(args->flags & CLD_FLG_ALLDIE) && (args->flags & CLD_FLG_ERR_MARK)) { pMsg(ERR, args, "Can't specify mark on error, -Am, when continue on error is set.\n"); return (-1); } if ((glb_flags & GLB_FLG_KILL) && !(args->flags & CLD_FLG_ALLDIE)) { pMsg(ERR, args, "Can't specify global kill, -Ag, when continue on error is set, -Ac.\n"); return (-1); } if ((args->flags & CLD_FLG_LINEAR) && !(args->flags & CLD_FLG_NTRLVD) && (args->flags & CLD_FLG_TMD)) { pMsg(ERR, args, "Linear read / write test can not be timed.\n"); return (-1); } if ((args->flags & CLD_FLG_CMPR) && (args->cmp_lng > (args->ltrsiz * BLK_SIZE))) { pMsg(ERR, args, "Compare length, %lu, is greater then transfer size, %lu\n", args->cmp_lng, args->ltrsiz * BLK_SIZE); return (-1); } if ((args->flags & CLD_FLG_OFFSET) && (args->offset > args->stop_lba)) { pMsg(ERR, args, LBAOFFGSLBA, args->offset, args->stop_lba); return (-1); } if ((args->flags & CLD_FLG_OFFSET) && ((args->offset + args->ltrsiz - 1) > args->stop_lba)) { pMsg(ERR, args, LBAOTSGSLBA, args->offset, args->ltrsiz, args->stop_lba); return (-1); } return 0; }