| /* |
| * 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, (char **)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; |
| } |