1 /*
2 * Disktest
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * Please send e-mail to yardleyb@us.ibm.com if you have
21 * questions or comments.
22 *
23 * Project Website: TBD
24 *
25 * $Id: parse.c,v 1.8 2009/02/26 12:02:23 subrata_modak Exp $
26 *
27 */
28 #include <sys/types.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <signal.h>
33 #include <time.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <sys/stat.h>
39
40 #include "globals.h"
41 #include "threading.h"
42 #include "main.h"
43 #include "usage.h"
44 #include "sfunc.h"
45 #include "parse.h"
46
fill_cld_args(int argc,char ** argv,child_args_t * args)47 int fill_cld_args(int argc, char **argv, child_args_t * args)
48 {
49 extern char *optarg;
50 extern int optind;
51 extern unsigned long glb_flags;
52
53 signed char c;
54 char *leftovers;
55
56 while ((c =
57 getopt(argc, argv,
58 "?a:A:B:cC:dD:E:f:Fh:I:K:L:m:M:nN:o:p:P:qQrR:s:S:t:T:wvV:z"))
59 != -1) {
60 switch (c) {
61 case ':':
62 pMsg(WARN, args, "Missing argument for perameter.\n");
63 usage();
64 return (-1);
65 case 'V':
66 #ifdef _DEBUG
67 if (optarg == NULL) {
68 pMsg(WARN, args,
69 "-%c option requires an argument.\n", c);
70 exit(1);
71 }
72 if (!isdigit(optarg[0])) {
73 pMsg(WARN, args,
74 "-%c argument is non numeric.\n", c);
75 exit(1);
76 }
77 gbl_dbg_lvl = atoi(optarg);
78 #else
79 pMsg(ERR, args,
80 "Debug code not compiled in, recompile with _DEBUG directive.\n",
81 c);
82 exit(1);
83 #endif
84 break;
85 case 'd':
86 glb_flags |= GLB_FLG_QUIET;
87 args->flags |= CLD_FLG_DUMP;
88 break;
89 case 'a':
90 if (optarg == NULL) {
91 pMsg(WARN, args,
92 "-%c option requires an argument.\n", c);
93 return (-1);
94 }
95 if (!isdigit(optarg[0])) {
96 pMsg(WARN, args,
97 "-%c arguments is non numeric.\n", c);
98 return (-1);
99 }
100 args->seed = (unsigned int)strtol(optarg, NULL, 0);
101 break;
102 case 'A':
103 if (optarg == NULL) {
104 pMsg(WARN, args,
105 "-%c option requires an argument.\n", c);
106 exit(1);
107 }
108 if (strchr(optarg, 'g')) {
109 glb_flags |= GLB_FLG_KILL;
110 }
111 if (strchr(optarg, 'c')) {
112 args->flags &= ~CLD_FLG_ALLDIE;
113 }
114 if (strchr(optarg, 'm')) {
115 args->flags |= CLD_FLG_ERR_MARK;
116 }
117 if (strchr(optarg, 'r')) {
118 args->flags &= ~CLD_FLG_ERR_REREAD;
119 }
120 if (strchr(optarg, 's')) {
121 args->flags &= ~CLD_FLG_LBA_SYNC;
122 }
123 if (strchr(optarg, 'S')) {
124 args->flags |= CLD_FLG_IO_SERIAL;
125 }
126 if (strchr(optarg, 'w')) {
127 args->flags |= CLD_FLG_WRITE_ONCE;
128 }
129 if (strchr(optarg, 'W')) {
130 args->flags |= CLD_FLG_UNIQ_WRT;
131 }
132 if (strchr(optarg, 't')) {
133 args->flags |= CLD_FLG_TMO_ERROR;
134 }
135 break;
136 case 'q':
137 glb_flags |= GLB_FLG_QUIET;
138 break;
139 case 'Q':
140 glb_flags |= GLB_FLG_SUPRESS;
141 break;
142 case 'v':
143 pMsg(INFO, args, "Version %s\n", VER_STR);
144 exit(0);
145 case 'p':
146 if (optarg == NULL) {
147 pMsg(WARN, args,
148 "-%c option requires an argument.\n", c);
149 return (-1);
150 }
151 if (args->flags & (CLD_FLG_LINEAR | CLD_FLG_RANDOM)) {
152 pMsg(WARN, args,
153 "Only one seek type, -p, can be specified.\n");
154 return (-1);
155 }
156 /* seek pattern type */
157 if (strchr(optarg, 'L'))
158 args->flags |= CLD_FLG_LINEAR;
159 else if (strchr(optarg, 'l'))
160 args->flags |=
161 (CLD_FLG_LINEAR | CLD_FLG_NTRLVD);
162 else if (strchr(optarg, 'R'))
163 args->flags |= CLD_FLG_RANDOM;
164 else if (strchr(optarg, 'r'))
165 args->flags |=
166 (CLD_FLG_RANDOM | CLD_FLG_NTRLVD);
167 else {
168 pMsg(WARN, args, "Unknown Seek pattern\n");
169 usage();
170 return (-1);
171 }
172 if (strchr(optarg, 'U') || strchr(optarg, 'u'))
173 if ((args->flags & (CLD_FLG_LINEAR)) &&
174 !(args->flags & CLD_FLG_LUND))
175 args->flags |= CLD_FLG_LUNU;
176 if (strchr(optarg, 'D') || strchr(optarg, 'd'))
177 if ((args->flags & (CLD_FLG_LINEAR)) &&
178 !(args->flags & CLD_FLG_LUNU))
179 args->flags |= CLD_FLG_LUND;
180 break;
181 case 'B':
182 if (!isdigit(optarg[0])) {
183 pMsg(WARN, args,
184 "-%c arguments is non numeric.\n", c);
185 return (-1);
186 }
187 if (strchr(optarg, ':') != NULL) { /* we are given a range of transfer sizes */
188 args->flags |= CLD_FLG_RTRSIZ;
189 args->ltrsiz = strtoul(optarg, &leftovers, 10);
190 if (leftovers == strchr(leftovers, 'k')) { /* first value had a 'k' */
191 args->ltrsiz *= 2;
192 leftovers++;
193 } else if (leftovers == strchr(leftovers, 'm')) { /* first value had a 'm' */
194 args->ltrsiz *= (2 * 1024);
195 leftovers++;
196 } else {
197 if (args->ltrsiz > 256)
198 args->ltrsiz /= BLK_SIZE;
199 }
200 if (!isdigit(leftovers[1])) {
201 pMsg(WARN, args,
202 "-%c arguments is non numeric.\n",
203 c);
204 return (-1);
205 }
206 args->htrsiz =
207 atol((char *)strchr(leftovers, ':') + 1);
208 if ((strchr(leftovers, 'k')) != NULL) { /* second value had a 'k' */
209 args->htrsiz *= 2;
210 } else if ((strchr(leftovers, 'm')) != NULL) { /* second value had a 'm' */
211 args->htrsiz *= (2 * 1024);
212 } else {
213 if (args->htrsiz > 256)
214 args->htrsiz /= BLK_SIZE;
215 }
216 } else { /* only a single value given for transfer size */
217 args->ltrsiz = atoi(optarg);
218 if (strchr(optarg, 'k')) {
219 args->ltrsiz *= 2;
220 } else if (strchr(optarg, 'm')) {
221 args->ltrsiz *= (2 * 1024);
222 } else {
223 if (args->ltrsiz > 256)
224 args->ltrsiz /= BLK_SIZE;
225 }
226 args->htrsiz = args->ltrsiz;
227 }
228 #ifdef _DEBUG
229 PDBG5(DBUG, args, "Parsed Transfer size: %ld\n",
230 args->htrsiz);
231 #endif
232 break;
233 case 'c':
234 if (args->flags & CLD_FLG_PTYPS) {
235 pMsg(WARN, args,
236 "Please specify only one pattern type\n");
237 usage();
238 return (-1);
239 }
240 args->flags |= CLD_FLG_CPTYPE;
241 break;
242 case 'n':
243 if (args->flags & CLD_FLG_PTYPS) {
244 pMsg(WARN, args,
245 "Please specify only one pattern type\n");
246 usage();
247 return (-1);
248 }
249 args->flags |= CLD_FLG_LPTYPE;
250 break;
251 case 'f':
252 if (optarg == NULL) {
253 pMsg(WARN, args,
254 "-%c option requires an argument.\n", c);
255 return (-1);
256 }
257 if (args->flags & CLD_FLG_PTYPS) {
258 pMsg(WARN, args,
259 "Please specify only one pattern type\n");
260 usage();
261 return (-1);
262 }
263 args->pattern = my_strtofft(optarg);
264 args->flags |= CLD_FLG_FPTYPE;
265 break;
266 case 'F':
267 /* the filespec is a list of filespecs in a file */
268 args->flags |= CLD_FLG_FSLIST;
269 break;
270 case 'z':
271 if (args->flags & CLD_FLG_PTYPS) {
272 pMsg(WARN, args,
273 "Please specify only one pattern type\n");
274 usage();
275 return (-1);
276 }
277 args->flags |= CLD_FLG_RPTYPE;
278 break;
279 case 'h':
280 if (optarg == NULL) {
281 pMsg(WARN, args,
282 "-%c option requires an argument.\n", c);
283 return (-1);
284 }
285 if (!isdigit(optarg[0])) {
286 pMsg(WARN, args,
287 "-%c arguments is non numeric.\n", c);
288 usage();
289 return (-1);
290 }
291 args->flags |= CLD_FLG_HBEAT;
292 args->hbeat = atoi(optarg);
293 if (strchr(optarg, 'm')) { /* multiply by sec */
294 args->hbeat *= 60;
295 } else if (strchr(optarg, 'h')) { /* multiply sec*min */
296 args->hbeat *= (time_t) (60 * 60);
297 } else if (strchr(optarg, 'd')) { /* multiply by sec*min*hours */
298 args->hbeat *= (time_t) (60 * 60 * 24);
299 }
300 break;
301 case 'D':
302 if (optarg == NULL) {
303 pMsg(WARN, args,
304 "-%c option requires an argument.\n", c);
305 return (-1);
306 }
307 if (!isdigit(optarg[0])) {
308 pMsg(WARN, args,
309 "-%c arguments is non numeric.\n", c);
310 usage();
311 return (-1);
312 }
313 args->rperc = atoi(optarg);
314 args->wperc = atoi((char *)(strchr(optarg, ':') + 1));
315 args->flags |= CLD_FLG_DUTY;
316 break;
317 case 'r':
318 args->flags |= CLD_FLG_R;
319 break;
320 case 'w':
321 args->flags |= CLD_FLG_W;
322 break;
323 case 'o':
324 if (optarg == NULL) {
325 pMsg(WARN, args,
326 "-%c option requires an argument.\n", c);
327 return (-1);
328 }
329 args->offset = atol(optarg);
330 args->flags |= CLD_FLG_OFFSET;
331 break;
332 case 'R':
333 if (optarg == NULL) {
334 pMsg(WARN, args,
335 "-%c option requires an argument.\n", c);
336 return (-1);
337 }
338 if (strchr(optarg, ':') != NULL) { /* we are given a retry delay */
339 args->retries = strtol(optarg, &leftovers, 10);
340 args->retry_delay =
341 (time_t) atol((char *)strchr(leftovers, ':')
342 + 1);
343 } else { /* only a retry count given */
344 args->retries = atoi(optarg);
345 }
346 break;
347 case 'M':
348 if (optarg == NULL) {
349 pMsg(WARN, args,
350 "-%c option requires an argument.\n", c);
351 return (-1);
352 }
353 args->flags |= CLD_FLG_ALT_MARK;
354 args->alt_mark = my_strtofft(optarg);
355 break;
356 case 'm':
357 args->flags |= CLD_FLG_MBLK;
358 if (optarg == NULL) {
359 pMsg(WARN, args,
360 "-%c option requires an argument.\n", c);
361 return (-1);
362 }
363 if (strchr(optarg, 'l')) { /* returns NULL if char is not found */
364 args->flags |= CLD_FLG_MRK_LBA;
365 }
366 if (strchr(optarg, 'p')) {
367 args->flags |= CLD_FLG_MRK_PASS;
368 }
369 if (strchr(optarg, 't')) {
370 args->flags |= CLD_FLG_MRK_TIME;
371 }
372 if (strchr(optarg, 's')) {
373 args->flags |= CLD_FLG_MRK_SEED;
374 }
375 if (strchr(optarg, 'h')) {
376 args->flags |= CLD_FLG_MRK_HOST;
377 }
378 if (strchr(optarg, 'f')) {
379 args->flags |= CLD_FLG_MRK_TARGET;
380 }
381 if (strchr(optarg, 'a')) {
382 args->flags |= CLD_FLG_MRK_ALL;
383 }
384 if (!strchr(optarg, 'l') &&
385 !strchr(optarg, 'p') &&
386 !strchr(optarg, 't') &&
387 !strchr(optarg, 's') &&
388 !strchr(optarg, 'h') &&
389 !strchr(optarg, 'f') && !strchr(optarg, 'a')) {
390 pMsg(WARN, args,
391 "Unknown header mark option\n");
392 return (-1);
393 }
394 break;
395 case 'E':
396 if (optarg == NULL) {
397 pMsg(WARN, args,
398 "-%c option requires an argument.\n", c);
399 return (-1);
400 }
401 if (!isdigit(optarg[0])) {
402 pMsg(WARN, args,
403 "-%c arguments are non numeric.\n", c);
404 usage();
405 return (-1);
406 }
407 args->flags |= CLD_FLG_CMPR;
408 args->cmp_lng = strtol(optarg, NULL, 0);
409 if (strchr(optarg, 'k')) { /* multiply by 2^10 */
410 args->cmp_lng <<= 10;
411 } else if (strchr(optarg, 'K')) { /* multiply 10^3 */
412 args->cmp_lng *= 1000;
413 } else if (strchr(optarg, 'm')) { /* multiply by 2^20 */
414 args->cmp_lng <<= 20;
415 } else if (strchr(optarg, 'M')) { /* multiply by 10^6 */
416 args->cmp_lng *= 1000000;
417 }
418 break;
419 case 'N':
420 if (optarg == NULL) {
421 pMsg(WARN, args,
422 "-%c option requires an argument.\n", c);
423 return (-1);
424 }
425 if (!isdigit(optarg[0])) {
426 pMsg(WARN, args,
427 "-%c arguments are non numeric.\n", c);
428 return (-1);
429 }
430 args->flags |= CLD_FLG_VSIZ;
431 args->vsiz = my_strtofft(optarg);
432 if (strchr(optarg, 'k')) { /* multiply by 2^10 */
433 args->vsiz <<= 10;
434 } else if (strchr(optarg, 'K')) { /* multiply 10^3 */
435 args->vsiz *= 1000;
436 } else if (strchr(optarg, 'm')) { /* multiply by 2^20 */
437 args->vsiz <<= 20;
438 } else if (strchr(optarg, 'M')) { /* multiply by 10^6 */
439 args->vsiz *= 1000000;
440 } else if (strchr(optarg, 'g')) { /* multiply by 2^30 */
441 args->vsiz <<= 30;
442 } else if (strchr(optarg, 'G')) { /* multiply by 10^9 */
443 args->vsiz *= 1000000000;
444 }
445 break;
446 case 'I':
447 if (optarg == NULL) {
448 pMsg(WARN, args,
449 "-%c option requires an argument.\n", c);
450 return (-1);
451 }
452 if (strchr(optarg, 'R') || strchr(optarg, 'r')) {
453 if (!(args->flags & CLD_FLG_BLK) &&
454 !(args->flags & CLD_FLG_FILE)) {
455 args->flags |= CLD_FLG_RAW;
456 } else {
457 pMsg(WARN, args,
458 "Can only specify one IO type\n");
459 return (-1);
460 }
461 }
462 if (strchr(optarg, 'B') || strchr(optarg, 'b')) {
463 if (!(args->flags & CLD_FLG_RAW) &&
464 !(args->flags & CLD_FLG_FILE)) {
465 args->flags |= CLD_FLG_BLK;
466 } else {
467 pMsg(WARN, args,
468 "Can only specify one IO type\n");
469 return (-1);
470 }
471 }
472 if (strchr(optarg, 'F') || strchr(optarg, 'f')) {
473 if (!(args->flags & CLD_FLG_RAW) &&
474 !(args->flags & CLD_FLG_BLK)) {
475 args->flags |= CLD_FLG_FILE;
476 } else {
477 pMsg(WARN, args,
478 "Can only specify one IO type\n");
479 return (-1);
480 }
481 }
482 if (strchr(optarg, 'D') || strchr(optarg, 'd')) {
483 args->flags |= CLD_FLG_DIRECT;
484 }
485 if (strchr(optarg, 's')) {
486 args->sync_interval =
487 strtoul((char *)strchr(optarg, 's') + 1,
488 NULL, 10);
489 #ifdef _DEBUG
490 PDBG3(DBUG, args, "Parsed sync interval: %ld\n",
491 args->sync_interval);
492 #endif
493 if ((args->flags & CLD_FLG_DIRECT)) {
494 pMsg(ERR, args,
495 "Can't specify sync with Direct IO\n");
496 return (-1);
497 }
498 args->flags |= CLD_FLG_WFSYNC;
499 }
500 break;
501 case 't':
502 if (optarg == NULL) {
503 pMsg(WARN, args,
504 "-%c option requires an argument.\n", c);
505 return (-1);
506 }
507
508 if (strchr(optarg, ':') != NULL) { /* we are given a option for delay & timeout */
509 args->delayTimeMin =
510 strtoul(optarg, &leftovers, 10);
511 /* check to see if we have one or more then one ':' */
512 if ((char *)strchr(optarg, ':') ==
513 (char *)strrchr(optarg, ':')) {
514 /* only one ':', assume no random delayTime, and ioTimeout */
515 args->delayTimeMax = args->delayTimeMin;
516 args->ioTimeout =
517 (time_t) atol((char *)
518 strchr(leftovers,
519 ':') + 1);
520 } else {
521 /* more then one ':', assume random delayTime, and ioTimeout */
522 args->delayTimeMax =
523 strtoul(leftovers + 1, &leftovers,
524 10);
525 args->ioTimeout =
526 (time_t) atol((char *)
527 strchr(leftovers,
528 ':') + 1);
529 }
530 if (strchr(leftovers, 'm')) { /* multiply by sec */
531 args->ioTimeout *= 60;
532 } else if (strchr(leftovers, 'h')) { /* multiply sec*min */
533 args->ioTimeout *= (time_t) (60 * 60);
534 } else if (strchr(leftovers, 'd')) { /* multiply by sec*min*hours */
535 args->ioTimeout *=
536 (time_t) (60 * 60 * 24);
537 }
538 } else {
539 args->delayTimeMin =
540 strtoul(optarg, NULL, 10);
541 args->delayTimeMax = args->delayTimeMin;
542 }
543 break;
544 case 'T':
545 if (optarg == NULL) {
546 pMsg(WARN, args,
547 "-%c option requires an argument.\n", c);
548 return (-1);
549 }
550 args->run_time = atoi(optarg);
551 args->flags |= CLD_FLG_TMD;
552 if (strchr(optarg, 'm')) { /* multiply by sec */
553 args->run_time *= 60;
554 } else if (strchr(optarg, 'h')) { /* multiply sec*min */
555 args->run_time *= (time_t) (60 * 60);
556 } else if (strchr(optarg, 'd')) { /* multiply by sec*min*hours */
557 args->run_time *= (time_t) (60 * 60 * 24);
558 }
559 break;
560 case 'L':
561 if (optarg == NULL) {
562 pMsg(WARN, args,
563 "-%c option requires an argument.\n", c);
564 return (-1);
565 }
566 args->seeks = atoi(optarg);
567 args->flags |= CLD_FLG_SKS;
568 if (strchr(optarg, 'k')) { /* multiply by 2^10 */
569 args->seeks <<= 10;
570 } else if (strchr(optarg, 'K')) { /* multiply 10^3 */
571 args->seeks *= 1000;
572 } else if (strchr(optarg, 'm')) { /* multiply by 2^20 */
573 args->seeks <<= 20;
574 } else if (strchr(optarg, 'M')) { /* multiply by 10^6 */
575 args->seeks *= 1000000;
576 } else if (strchr(optarg, 'g')) { /* multiply by 2^30 */
577 args->seeks <<= 30;
578 } else if (strchr(optarg, 'G')) { /* multiply by 10^9 */
579 args->seeks *= 1000000000;
580 }
581 break;
582 case 'C':
583 if (optarg == NULL) {
584 pMsg(WARN, args,
585 "-%c option requires an argument.\n", c);
586 return (-1);
587 }
588 if (!isdigit(optarg[0])) {
589 pMsg(WARN, args,
590 "-%c arguments is non numeric.\n", c);
591 usage();
592 return (-1);
593 }
594 args->flags |= CLD_FLG_CYC;
595 args->cycles = atol(optarg);
596 break;
597 case 'K':
598 if (optarg == NULL) {
599 pMsg(WARN, args,
600 "-%c option requires an argument.\n", c);
601 return (-1);
602 }
603 if (!isdigit(optarg[0])) {
604 pMsg(WARN, args,
605 "-%c arguments is non numeric.\n", c);
606 usage();
607 return (-1);
608 }
609 if (atoi(optarg) > MAX_THREADS) {
610 pMsg(WARN, args,
611 "%u exceeds max of %u threads.\n",
612 atoi(optarg), MAX_THREADS);
613 return (-1);
614 }
615 args->t_kids = atoi(optarg);
616 break;
617 case 'P':
618 if (optarg == NULL) {
619 pMsg(WARN, args,
620 "-%c option requires an argument.\n", c);
621 return (-1);
622 }
623 if (strchr(optarg, 'X')) { /* returns NULL if char is not found */
624 args->flags |= CLD_FLG_XFERS;
625 }
626 if (strchr(optarg, 'T')) {
627 args->flags |= CLD_FLG_TPUTS;
628 }
629 if (strchr(optarg, 'P')) {
630 glb_flags |= GLB_FLG_PERFP;
631 }
632 if (strchr(optarg, 'R')) {
633 args->flags |= CLD_FLG_RUNT;
634 }
635 if (strchr(optarg, 'C')) {
636 args->flags |= CLD_FLG_PCYC;
637 }
638 if (strchr(optarg, 'A')) {
639 args->flags |= CLD_FLG_PRFTYPS;
640 }
641 if (!strchr(optarg, 'P') &&
642 !strchr(optarg, 'A') &&
643 !strchr(optarg, 'X') &&
644 !strchr(optarg, 'R') &&
645 !strchr(optarg, 'C') && !strchr(optarg, 'T')) {
646 pMsg(WARN, args,
647 "Unknown performance option\n");
648 return (-1);
649 }
650 break;
651 case 'S':
652 if (!isdigit((int)optarg[0])) {
653 pMsg(WARN, args,
654 "-%c arguments is non numeric.\n", c);
655 return (-1);
656 }
657 args->flags |= CLD_FLG_BLK_RNG;
658 if (strchr(optarg, ':') != NULL) { /* we are given a range */
659 args->start_blk =
660 (OFF_T) strtoul(optarg, &leftovers, 0);
661 if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */
662 args->start_blk <<= 10;
663 leftovers++; /* at the ':' */
664 } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */
665 args->start_blk *= 1000;
666 leftovers++; /* at the ':' */
667 } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */
668 args->start_blk <<= 20;
669 leftovers++; /* at the ':' */
670 } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */
671 args->start_blk *= 1000000;
672 leftovers++; /* at the ':' */
673 } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */
674 args->start_blk <<= 30;
675 leftovers++; /* at the ':' */
676 } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */
677 args->start_blk *= 1000000000;
678 leftovers++; /* at the ':' */
679 }
680 leftovers++; /* should be at the next value */
681 if (!isdigit((int)leftovers[0])) {
682 pMsg(WARN, args,
683 "-%c arguments is non numeric.\n",
684 c);
685 return (-1);
686 }
687 args->stop_blk =
688 (OFF_T) strtoul(leftovers, &leftovers, 0);
689 if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */
690 args->stop_blk <<= 10;
691 } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */
692 args->stop_blk *= 1000;
693 } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */
694 args->stop_blk <<= 20;
695 } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */
696 args->stop_blk *= 1000000;
697 } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */
698 args->stop_blk <<= 30;
699 } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */
700 args->stop_blk *= 1000000000;
701 }
702 } else { /* only a single value given */
703 args->start_blk =
704 (OFF_T) strtoul(optarg, &leftovers, 0);
705 if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */
706 args->start_blk <<= 10;
707 } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */
708 args->start_blk *= 1000;
709 } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */
710 args->start_blk <<= 20;
711 } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */
712 args->start_blk *= 1000000;
713 } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */
714 args->start_blk <<= 30;
715 } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */
716 args->start_blk *= 1000000000;
717 }
718 }
719 break;
720 case 's':
721 if (!isdigit((int)optarg[0])) {
722 pMsg(WARN, args,
723 "-%c argument is non numeric.\n", c);
724 return (-1);
725 }
726 args->flags |= CLD_FLG_LBA_RNG;
727 if (strchr(optarg, ':') != NULL) { /* we are given a range */
728 args->start_lba =
729 (OFF_T) strtoul(optarg, &leftovers, 0);
730 if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */
731 args->start_lba <<= 10;
732 leftovers++; /* at the ':' */
733 } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */
734 args->start_lba *= 1000;
735 leftovers++; /* at the ':' */
736 } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */
737 args->start_lba <<= 20;
738 leftovers++; /* at the ':' */
739 } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */
740 args->start_lba *= 1000000;
741 leftovers++; /* at the ':' */
742 } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */
743 args->start_lba <<= 30;
744 leftovers++; /* at the ':' */
745 } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */
746 args->start_lba *= 1000000000;
747 leftovers++; /* at the ':' */
748 }
749 leftovers++; /* should be at the next value */
750 if (!isdigit((int)leftovers[0])) {
751 pMsg(WARN, args,
752 "-%c second argument is non numeric.\n",
753 c);
754 return (-1);
755 }
756 args->stop_lba =
757 (OFF_T) strtoul(leftovers, &leftovers, 0);
758 if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */
759 args->stop_lba <<= 10;
760 } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */
761 args->stop_lba *= 1000;
762 } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */
763 args->stop_lba <<= 20;
764 } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */
765 args->stop_lba *= 1000000;
766 } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */
767 args->stop_lba <<= 30;
768 } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */
769 args->stop_lba *= 1000000000;
770 }
771 } else { /* only a single value given */
772 args->start_lba =
773 (OFF_T) strtoul(optarg, &leftovers, 0);
774 if (leftovers == strchr(leftovers, 'k')) { /* multiply by 2^10 */
775 args->start_lba <<= 10;
776 } else if (leftovers == strchr(leftovers, 'K')) { /* multiply 10^3 */
777 args->start_lba *= 1000;
778 } else if (leftovers == strchr(leftovers, 'm')) { /* multiply by 2^20 */
779 args->start_lba <<= 20;
780 } else if (leftovers == strchr(leftovers, 'M')) { /* multiply by 10^6 */
781 args->start_lba *= 1000000;
782 } else if (leftovers == strchr(leftovers, 'g')) { /* multiply by 2^30 */
783 args->start_lba <<= 30;
784 } else if (leftovers == strchr(leftovers, 'G')) { /* multiply by 10^9 */
785 args->start_lba *= 1000000000;
786 }
787 }
788 break;
789 case '?':
790 default:
791 usage();
792 return (-1);
793 }
794 }
795 if (argv[optind] == NULL) {
796 pMsg(WARN, args, "Unspecified target.\n");
797 return (-1);
798 }
799 strncpy(args->device, argv[optind], (DEV_NAME_LEN - 1));
800 return 0;
801 }
802
make_assumptions(child_args_t * args)803 int make_assumptions(child_args_t * args)
804 {
805 char TmpStr[80];
806 struct stat stat_buf;
807 int rv;
808
809 if (!(args->flags & CLD_FLG_IOTYPS)) {
810 /* use stat to get file properties, and use to set -I */
811 rv = stat(args->device, &stat_buf);
812 if (0 == rv) {
813 if (IS_FILE(stat_buf.st_mode)) {
814 strncat(args->argstr, "(-I f) ",
815 (MAX_ARG_LEN - 1) -
816 strlen(args->argstr));
817 args->flags |= CLD_FLG_FILE;
818 } else if (IS_BLK(stat_buf.st_mode)) {
819 strncat(args->argstr, "(-I b) ",
820 (MAX_ARG_LEN - 1) -
821 strlen(args->argstr));
822 args->flags |= CLD_FLG_BLK;
823 #ifndef WINDOWS
824 } else if (S_ISCHR(stat_buf.st_mode)) {
825 strncat(args->argstr, "(-I r) ",
826 (MAX_ARG_LEN - 1) -
827 strlen(args->argstr));
828 args->flags |= CLD_FLG_RAW;
829 #endif
830 }
831 } else {
832 pMsg(WARN, args,
833 "Can't get status on %s, defaulting to file, errno = %d\n",
834 args->device, GETLASTERROR());
835 strncat(args->argstr, "(-I f) ",
836 (MAX_ARG_LEN - 1) - strlen(args->argstr));
837 args->flags |= CLD_FLG_FILE;
838 }
839 }
840 if ((args->flags & CLD_FLG_WFSYNC) && (0 == args->sync_interval)) {
841 pMsg(INFO, args,
842 "Sync interval set to zero, assuming interval of 1.\n");
843 args->sync_interval = 1;
844 }
845
846 if (args->ltrsiz <= 0) {
847 sprintf(TmpStr, "(-B %d) ", TRSIZ * BLK_SIZE);
848 strncat(args->argstr, TmpStr,
849 (MAX_ARG_LEN - 1) - strlen(args->argstr));
850 args->ltrsiz = TRSIZ;
851 args->htrsiz = TRSIZ;
852 }
853 if (args->flags & CLD_FLG_LBA_RNG) {
854 args->start_blk = args->start_lba / args->htrsiz;
855 if (!(args->stop_lba < 0))
856 args->stop_blk = args->stop_lba / args->htrsiz;
857 }
858 if (args->flags & CLD_FLG_BLK_RNG) {
859 args->start_lba = args->start_blk * args->htrsiz;
860 if (!(args->stop_blk < 0))
861 args->stop_lba =
862 (args->stop_blk * args->htrsiz) + (args->htrsiz -
863 1);
864 }
865 /* if vsiz is still not set, try and get it from the file */
866 if ((args->vsiz <= 0) && (args->flags & CLD_FLG_FILE)) {
867 if (0 != get_file_size(args->device)) { /* file size retrieved */
868 args->vsiz = get_file_size(args->device);
869 }
870 }
871 /* if vsiz is still not set, try and get it from the device */
872 if ((args->vsiz <= 0) && !(args->flags & CLD_FLG_FILE)) {
873 args->vsiz = get_vsiz(args->device);
874 }
875 /* if vsiz is still not set, set based on given range */
876 if ((args->vsiz <= 0)
877 && (args->flags & (CLD_FLG_LBA_RNG | CLD_FLG_BLK_RNG))) {
878 if (!(args->stop_lba < 0))
879 args->vsiz = args->stop_lba + 1;
880 else
881 args->vsiz = args->start_lba + 1;
882 }
883 /* if vsiz is still not set, then set it to the default size */
884 if (args->vsiz <= 0) {
885 args->vsiz = VSIZ;
886 }
887 if (!(args->flags & CLD_FLG_VSIZ)) {
888 sprintf(TmpStr, N_ASSUME, args->vsiz);
889 strncat(args->argstr, TmpStr,
890 (MAX_ARG_LEN - 1) - strlen(args->argstr));
891 }
892
893 if (args->stop_lba == -1) {
894 args->stop_lba = args->vsiz - 1;
895 }
896 if (args->stop_blk == -1) {
897 args->stop_blk = (args->stop_lba / (OFF_T) args->htrsiz);
898 }
899 if (args->t_kids == 0) {
900 sprintf(TmpStr, "(-K %d) ", KIDS);
901 strncat(args->argstr, TmpStr,
902 (MAX_ARG_LEN - 1) - strlen(args->argstr));
903 args->t_kids = KIDS;
904 }
905 if ((args->flags & (CLD_FLG_W | CLD_FLG_R)) == 0) {
906 if (args->flags & CLD_FLG_DUTY) { /* no read/write but duty cycle specified */
907 if (args->rperc > 0) {
908 args->flags |= CLD_FLG_R;
909 strncat(args->argstr, "(-r) ",
910 (MAX_ARG_LEN - 1) -
911 strlen(args->argstr));
912 }
913 if (args->wperc > 0) {
914 args->flags |= CLD_FLG_W;
915 strncat(args->argstr, "(-w) ",
916 (MAX_ARG_LEN - 1) -
917 strlen(args->argstr));
918 }
919 } else {
920 strncat(args->argstr, "(-r) ",
921 (MAX_ARG_LEN - 1) - strlen(args->argstr));
922 args->flags |= CLD_FLG_R;
923 }
924 }
925 if (!(args->flags & CLD_FLG_PTYPS)) {
926 strncat(args->argstr, "(-c) ",
927 (MAX_ARG_LEN - 1) - strlen(args->argstr));
928 args->flags |= CLD_FLG_CPTYPE;
929 }
930 if (!(args->flags & CLD_FLG_SKTYPS)) {
931 strncat(args->argstr, "(-p R) ",
932 (MAX_ARG_LEN - 1) - strlen(args->argstr));
933 args->flags |= CLD_FLG_RANDOM;
934 }
935 if (!(args->flags & CLD_FLG_SKS)) {
936 if (args->start_blk == args->stop_blk) { /* diskcache test, w/ no seek count set */
937 args->seeks = SEEKS;
938 } else if (args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG)) { /* range set, w/ no seek count */
939 args->seeks = args->stop_blk - args->start_blk + 1;
940 } else {
941 /* if vsiz is available, calculated seeks are in terms of the largest transfer size */
942 args->seeks =
943 (args->vsiz >
944 0) ? (args->vsiz / args->htrsiz) : SEEKS;
945 }
946 if ((args->flags & CLD_FLG_LINEAR) && (args->flags & CLD_FLG_R)
947 && (args->flags & CLD_FLG_W)) {
948 args->seeks *= 2;
949 }
950
951 if (!(args->flags & CLD_FLG_TMD)) {
952 sprintf(TmpStr, L_ASSUME, args->seeks);
953 strncat(args->argstr, TmpStr,
954 (MAX_ARG_LEN - 1) - strlen(args->argstr));
955 }
956 }
957 if (!(args->flags & (CLD_FLG_SKS | CLD_FLG_TMD))
958 || ((args->flags & CLD_FLG_CYC)
959 && !(args->flags & (CLD_FLG_SKS | CLD_FLG_TMD)))) {
960 args->flags |= CLD_FLG_SKS;
961 }
962 if (args->flags & (CLD_FLG_LINEAR)) {
963 if (!(args->flags & (CLD_FLG_LUNU | CLD_FLG_LUND))) {
964 strncat(args->argstr, "(-p u) ",
965 (MAX_ARG_LEN - 1) - strlen(args->argstr));
966 args->flags |= CLD_FLG_LUNU;
967 }
968 }
969 normalize_percs(args);
970 if (!(args->flags & CLD_FLG_DUTY) && (args->flags & CLD_FLG_RANDOM)
971 && !(args->flags & CLD_FLG_NTRLVD)) {
972 sprintf(TmpStr, "(-D %d:%d) ", args->rperc, args->wperc);
973 strncat(args->argstr, TmpStr,
974 (MAX_ARG_LEN - 1) - strlen(args->argstr));
975 args->flags |= CLD_FLG_DUTY;
976 }
977 if ((args->delayTimeMin == 0) && (args->delayTimeMax == 0)
978 && (args->ioTimeout == DEFAULT_IO_TIMEOUT)) {
979 strncat(args->argstr, "(-t 0:2m) ",
980 (MAX_ARG_LEN - 1) - strlen(args->argstr));
981 }
982 if (!(args->flags & CLD_FLG_OFFSET)) {
983 strncat(args->argstr, "(-o 0) ",
984 (MAX_ARG_LEN - 1) - strlen(args->argstr));
985 }
986
987 return 0;
988 }
989
990 /*
991 * checks validity of data after parsing
992 * args and make assumtions. returns 0 on
993 * success and -1 on failure.
994 */
check_conclusions(child_args_t * args)995 int check_conclusions(child_args_t * args)
996 {
997 extern unsigned long glb_flags;
998 struct stat stat_buf;
999 int rv;
1000
1001 if ((args->flags & CLD_FLG_DUTY)
1002 && ((args->flags & CLD_FLG_LINEAR)
1003 || (args->flags & CLD_FLG_NTRLVD))) {
1004 pMsg(WARN, args,
1005 "Duty cycle testing is supported for random (-pR) tests only.\n");
1006 return (-1);
1007 }
1008 if ((args->flags & CLD_FLG_BLK_RNG) && (args->flags & CLD_FLG_RTRSIZ)) {
1009 pMsg(WARN, args,
1010 "Can't have unfixed block sizes and specify seek range in terms of blocks.\n");
1011 return (-1);
1012 }
1013 if ((args->vsiz < 0) || (args->ltrsiz < 1) || (args->htrsiz < 1)) {
1014 pMsg(WARN, args,
1015 "Bounds exceeded for transfer size and/or volume size.\n");
1016 pMsg(WARN, args, MAXTRSIZ, (args->htrsiz * BLK_SIZE),
1017 args->vsiz);
1018 return (-1);
1019 }
1020 if (args->htrsiz < args->ltrsiz) {
1021 pMsg(ERR, args,
1022 "Min transfer size, %lu, greater then Max transfer size, %lu.\n",
1023 args->ltrsiz, args->htrsiz);
1024 return (-1);
1025 }
1026 if (args->vsiz < (args->stop_lba - args->start_lba + 1)) {
1027 pMsg(ERR, args, "Volume stop block/lba exceeds volume size.\n");
1028 return (-1);
1029 }
1030 if (args->vsiz < args->htrsiz) {
1031 pMsg(WARN, args, VSIZETS, args->vsiz, args->htrsiz);
1032 return (-1);
1033 }
1034 if ((args->flags & CLD_FLG_TMD) == 0 && (args->seeks <= 0)) {
1035 pMsg(WARN, args, TSEEK, args->seeks);
1036 return (-1);
1037 }
1038 if ((args->flags & CLD_FLG_SKS) && (args->t_kids > args->seeks)) {
1039 pMsg(WARN, args,
1040 "Can't have more children then max number of seeks, use -K/-L to adjust.\n");
1041 return (-1);
1042 }
1043 if ((args->start_blk > args->vsiz)
1044 && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) {
1045 pMsg(WARN, args, STBGTTLBA, args->start_blk,
1046 (args->vsiz / args->htrsiz));
1047 return (-1);
1048 }
1049 if ((args->stop_blk > args->vsiz)
1050 && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) {
1051 pMsg(WARN, args, SBGTTLBA, args->stop_blk,
1052 (args->vsiz / args->htrsiz));
1053 return (-1);
1054 }
1055 if ((args->start_lba > args->vsiz)
1056 && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) {
1057 pMsg(WARN, args, STLBAGTLBA, args->start_lba, args->vsiz);
1058 return (-1);
1059 }
1060 if ((args->stop_lba > args->vsiz)
1061 && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) {
1062 pMsg(WARN, args, SLBAGTLBA, args->stop_lba, args->vsiz);
1063 return (-1);
1064 }
1065 if (args->start_blk > args->stop_blk) {
1066 pMsg(WARN, args, SBRSB, args->stop_blk, args->start_blk);
1067 return (-1);
1068 }
1069 if (args->start_lba > args->stop_lba) {
1070 pMsg(ERR, args, SLBARSLBA, args->stop_lba, args->start_lba);
1071 return (-1);
1072 }
1073 if ((args->flags & CLD_FLG_LBA_RNG) && (args->flags & CLD_FLG_BLK_RNG)) {
1074 pMsg(ERR, args,
1075 "Can't specify range in both block and LBA, use -s or -S.\n");
1076 return (-1);
1077 }
1078
1079 /* use stat to get file properties, and test then agains specified -I */
1080 rv = stat(args->device, &stat_buf);
1081 if (0 == rv) { /* no error on call to stat, compare against -I option */
1082 /* files are usually file type */
1083 if ((args->flags & CLD_FLG_FILE) && !IS_FILE(stat_buf.st_mode)) {
1084 pMsg(ERR, args,
1085 "Can't open non-file filespec with file device type, -If.\n");
1086 return (-1);
1087 }
1088 /* block devices, are usually block type */
1089 if ((args->flags & CLD_FLG_BLK) && !IS_BLK(stat_buf.st_mode)) {
1090 pMsg(ERR, args,
1091 "Can't open non-block filespec with block device type, -Ib.\n");
1092 return (-1);
1093 }
1094 #ifndef WINDOWS
1095 /* raw devices, are usually character type */
1096 if ((args->flags & CLD_FLG_RAW) && !S_ISCHR(stat_buf.st_mode)) {
1097 pMsg(ERR, args,
1098 "Can't open non-raw filespec with raw device type, -Ir.\n");
1099 return (-1);
1100 }
1101 #else
1102 if (args->flags & CLD_FLG_RAW) {
1103 pMsg(ERR, args,
1104 "RAW IO type not supported in Windows, use direct IO instead.\n");
1105 return (-1);
1106 }
1107 #endif
1108 #ifdef _DEBUG
1109 } else {
1110 PDBG1(DBUG, args,
1111 "Can't get status on %s, assuming a new file, errno = %d\n",
1112 args->device, GETLASTERROR());
1113 #endif
1114 }
1115
1116 if ((args->hbeat > 0) && (args->flags & CLD_FLG_TMD)
1117 && (args->hbeat > args->run_time)) {
1118 pMsg(ERR, args,
1119 "Heartbeat should be at least equal to runtime, use -h/-T to adjust.\n");
1120 return (-1);
1121 }
1122 if ((args->hbeat > 0) && !(args->flags & CLD_FLG_PRFTYPS)) {
1123 pMsg(ERR, args,
1124 "At least one performance option, -P, must be specified when using -h.\n");
1125 return (-1);
1126 }
1127 if ((args->flags & CLD_FLG_W) && !(args->flags & CLD_FLG_R)
1128 && (args->flags & CLD_FLG_CMPR)) {
1129 pMsg(ERR, args, "Write only, ignoring option -E.\n");
1130 }
1131 if ((args->flags & CLD_FLG_TMD) && (args->flags & CLD_FLG_SKS)) {
1132 pMsg(ERR, args,
1133 "Can't specify both -L and -T they are mutually exclusive.\n");
1134 return (-1);
1135 }
1136 if (((args->flags & CLD_FLG_R) && !(args->flags & CLD_FLG_W))
1137 && (args->flags & CLD_FLG_ERR_MARK)) {
1138 pMsg(ERR, args,
1139 "Can't specify mark on error, -Am, in read only mode.\n");
1140 return (-1);
1141 }
1142 if (!(args->flags & CLD_FLG_ALLDIE) && (args->flags & CLD_FLG_ERR_MARK)) {
1143 pMsg(ERR, args,
1144 "Can't specify mark on error, -Am, when continue on error is set.\n");
1145 return (-1);
1146 }
1147 if ((glb_flags & GLB_FLG_KILL) && !(args->flags & CLD_FLG_ALLDIE)) {
1148 pMsg(ERR, args,
1149 "Can't specify global kill, -Ag, when continue on error is set, -Ac.\n");
1150 return (-1);
1151 }
1152 if ((args->flags & CLD_FLG_LINEAR) && !(args->flags & CLD_FLG_NTRLVD)
1153 && (args->flags & CLD_FLG_TMD)) {
1154 pMsg(ERR, args, "Linear read / write test can not be timed.\n");
1155 return (-1);
1156 }
1157 if ((args->flags & CLD_FLG_CMPR)
1158 && (args->cmp_lng > (args->ltrsiz * BLK_SIZE))) {
1159 pMsg(ERR, args,
1160 "Compare length, %lu, is greater then transfer size, %lu\n",
1161 args->cmp_lng, args->ltrsiz * BLK_SIZE);
1162 return (-1);
1163 }
1164 if ((args->flags & CLD_FLG_OFFSET) && (args->offset > args->stop_lba)) {
1165 pMsg(ERR, args, LBAOFFGSLBA, args->offset, args->stop_lba);
1166 return (-1);
1167 }
1168 if ((args->flags & CLD_FLG_OFFSET)
1169 && ((args->offset + args->ltrsiz - 1) > args->stop_lba)) {
1170 pMsg(ERR, args, LBAOTSGSLBA, args->offset, args->ltrsiz,
1171 args->stop_lba);
1172 return (-1);
1173 }
1174 return 0;
1175 }
1176