a987b5a8aaa870c0226a4821076e84d332997e1b
[xfstests-dev.git] / ltp / growfiles.c
1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 /*
19  * This program will grow a list of files.
20  * Each file will grow by grow_incr before the same
21  * file grows twice.  Each file is open and closed before next file is opened.
22  *
23  * To just verify file contents: growfiles -g 0 -c 1 filename
24  *
25  * See help and prt_examples functions below.
26  *
27  * Basic code layout
28  *  process cmdline 
29  *  print debug message about options used
30  *  setup signal handlers
31  *  return control to user (if wanted - default action)
32  *  fork number of desired childern (if wanted)
33  *  re-exec self (if wanted)
34  *  Determine number of files
35  *  malloc space or i/o buffer
36  *  Loop until stop is set
37  *    Determine if hit iteration, time, max errors or num bytes reached
38  *    Loop through each file
39  *      open file
40  *      fstat file - to determine if file is a fifo
41  *      prealloc file space (if wanted)
42  *      growfile
43  *      check last write
44  *      check whole file
45  *      shrink file
46  *      close file
47  *      delay (if wanted)
48  *    End loop
49  *  End loop
50  *  remove all files (if wanted)
51  *
52  * Author: Richard Logan
53  *
54  */
55
56 #include "global.h"
57
58 #ifdef HAVE_SYS_FILE_H
59 #include <sys/file.h>
60 #endif
61
62 #include "dataascii.h"
63 #include "random_range.h"
64 #include "databin.h"
65
66
67 extern char *openflags2symbols();
68
69 extern int parse_open_flags();
70 extern int background();
71 extern int forker();
72 extern int datapidgen();
73 extern void databingen();
74 extern int datapidchk();
75 extern int databinchk();
76 extern int file_lock();
77
78 int file_size();
79 int check_write();
80 int shrinkfile();
81 int check_file();
82 int growfile();
83 int cleanup();
84 int handle_error();
85 int lkfile();
86 void usage();
87 void help();
88 void prt_examples();
89 int set_sig();
90 void sig_handler();
91 static void notify_others();
92 #ifndef NO_XFS
93 int pre_alloc();
94 #endif
95
96
97 #define NEWIO   1       /* Use the tlibio.c functions */
98
99 #ifndef NEWIO
100 #define NEWIO   0       /* specifies to use original iowrite.c */
101                         /* functions instead of tlibio.c functions */
102                         /* Once it is proven tlibio.c functions work properly, */
103                         /* only tlibio.c functions will be used */
104 #else
105 #include "tlibio.h"
106 #endif
107
108 #ifndef PATH_MAX
109 #define PATH_MAX        1023
110 #endif
111
112
113 #define DEF_DIR         "."
114 #define DEF_FILE        "gf"
115
116 char *Progname;
117 int Debug  = 1;
118
119 int Pid=0;
120
121 int io_type = 0;                        /* I/O type -sync */
122 int open_flags = O_RDWR|O_CREAT;        /* open flags */
123
124 #define MAX_FC_READ     196608          /* 4096 * 48 - 48 blocks */
125
126 #define PATTERN_ASCII   1       /* repeating alphabet letter pattern */
127                                 /* allows multiple writers and to be checked */
128 #define PATTERN_PID     2       /* <pid><words byte offset><pid> */
129                                 /* Assumes 64 bit word. Only allows single */
130                                 /* process to write and check */
131 /*
132  *      1234567890123456789012345678901234567890123456789012345678901234
133  *      ________________________________________________________________
134  *      <    pid       >< offset in file of this word  ><    pid       >
135  */
136         
137 #define PATTERN_OFFSET  3       /* Like PATTERN_PID but has a fixed number */
138                                 /* (STATIC_NUM) instead of pid. */
139                                 /* Allows multiple processes to write/read */
140 #define PATTERN_ALT     4       /* alternating bit pattern (i.e. 0x5555555...) */
141 #define PATTERN_CHKER   5       /* checkerboard pattern (i.e. 0xff00ff00ff00...) */
142 #define PATTERN_CNTING  6       /* counting pattern (i.e. 0 - 07, 0 - 07, ...) */
143 #define PATTERN_ONES    7       /* all bits set (i.e. 0xffffffffffffff...) */
144 #define PATTERN_ZEROS   8       /* all bits cleared (i.e. 0x000000000...) */
145 #define PATTERN_RANDOM  9       /* random integers - can not be checked */
146 #define STATIC_NUM      221849  /* used instead of pid when PATTERN_OFFSET */
147
148 #define MODE_RAND_SIZE  1       /* random write and trunc */
149 #define MODE_RAND_LSEEK 2       /* random lseek before write */
150 #define MODE_GROW_BY_LSEEK 4    /* lseek beyond end of file then write a byte */
151 #define RANDOM_OPEN     999876  /* if Open_flags set to this value, open flags */
152                                 /* will be randomly choosen from Open_flags[] */
153 #define MODE_FIFO       S_IFIFO /* defined in stat.h  0010000 */
154
155 int num_files = 0;              /* num_auto_files + cmd line files */
156 char *filenames;                /* pointer to space containing filenames */
157 int remove_files = 0;           /* if set, cleanup default is not to cleanup */
158 int bytes_consumed = 0;         /* total bytes consumed, all files */
159 int bytes_to_consume = 0;       /* non-zero if -B was specified, total bytes */
160 int Maxerrs = 100;              /* Max number errors before forced exit */
161 int Errors = 0;                 /* number of encountered errors */
162 int Upanic_on_error = 0;        /* call upanic if error and this variable set */
163
164 /* The *_size variables are only used when random iosize option (-r) is used */
165 int max_size=5000;
166 int min_size=1;                 /* also set in option parsing */
167 int mult_size=1;                /* when random iosz, iosz must be mult of mult_size */
168 /* the *_lseek variables are only used when radon lseek option (-R) is used */
169 int min_lseek=0;                /* also set in option parsing */
170 int max_lseek=-1;               /* -1 means size of file */
171 #ifdef CRAY
172 int Pattern=PATTERN_OFFSET;     /* This pattern is 64 bit word based */
173 #else
174 int Pattern=PATTERN_ASCII;
175 #endif
176 int Seed=-1;                    /* random number seed, < 0 == uninitialized  */
177 int Nseeds=0;                   /* Number of seed specified by the user */
178 int *Seeds;                     /* malloc'ed arrary of ints holding user spec seeds */
179
180 int using_random=0;             /* flag indicating randomization is being used */
181 float delaysecs=0.0;            /* delay between iterations (in seconds) */
182 int delaytime;                  /* delay between iterations in clocks/uses */
183 int lockfile=0;                 /* if set, do file locking */
184                                 /* 1 = do file locking around write, trunc */
185                                 /* and reads. */
186                                 /* 2 = write lock around all file operations */
187
188 int Woffset=0;                  /* offset before last write */
189 int Grow_incr=4096;             /* sz of last write */
190 int Mode=0;                     /* bitmask of write/trunc mode */
191                                 /* also knows if dealing with fifo */
192 char *Buffer = NULL;            /* buffer used by write and write check */
193 int Alignment=0;                /* if non word multiple, io will not be word aligned */
194 int Opid=0;                     /* original pid */
195
196 int Sync_with_others = 0;       /* Flag indicating to stop other if we stop before DONE */
197 int Iter_cnt = 0;               /* contains current iteration count value */
198 char    TagName[40];            /* name of this growfiles (see Monster)     */
199
200 struct fileinfo_t {
201     char *filename;
202     int fd;
203     int openflags;
204     int mode;
205 }  Fileinfo;
206
207 /*
208  * Define open flags that will be used when '-o random' option is used.
209  * Note: If there is more than one growfiles doing its thing to the same
210  * file, O_TRUNC will cause data mismatches.  How you ask?
211  * timing of events, example:
212  *   Process one                Process two
213  *   ---------------            -------------
214  *   get write lock
215  *   fstat file
216  *   lseek
217  *   generate pattern
218  *                              open with O_TRUNC 
219  *   write with wrong pattern
220  *      because offset is wrong
221  *
222  *  The second process truncated the file after the pattern was
223  *  determined, thus the pattern is wrong for the file location.
224  *
225  * There can also be a timing problem with open flag O_APPEND if
226  * file locks are not being used (-l option).  Things could happen
227  * between the fstat and the write. Thus, writing the wrong pattern.
228  * If all processes observe the file locks, O_APPEND should be ok
229  * to use.
230  */
231 int Open_flags[] = { 
232 #ifdef CRAY
233         O_RDWR|O_CREAT,
234         O_RDWR|O_CREAT|O_RAW,
235         O_RDWR|O_CREAT|O_BIG,
236         O_RDWR|O_CREAT|O_APPEND,
237         O_RDWR|O_CREAT|O_NDELAY,
238         O_RDWR|O_CREAT|O_PLACE,
239         O_RDWR|O_CREAT|O_SYNC,
240         O_RDWR|O_CREAT|O_RAW|O_SYNC,
241         O_RDWR|O_CREAT|O_NDELAY|O_SYNC,
242         O_RDWR|O_CREAT|O_NDELAY|O_SYNC|O_BIG,
243         O_RDWR|O_CREAT|O_RAW,
244         O_RDWR|O_CREAT|O_RAW|O_APPEND,
245         O_RDWR|O_CREAT|O_RAW|O_BIG,
246         O_RDWR|O_CREAT|O_RAW|O_APPEND|O_BIG,
247 /***
248  * O_WELLFORMED makes -o random require well formed i/o
249  ***/
250 #if ALLOW_O_WELLFORMED
251 #if O_PARALLEL
252         O_RDWR|O_CREAT|O_PARALLEL|O_WELLFORMED|O_RAW,
253         O_RDWR|O_CREAT|O_PARALLEL|O_WELLFORMED|O_RAW|O_TRUNC,
254 #endif /* O_PARALLEL */
255 #endif
256
257 #else /* CRAY */
258         O_RDWR|O_CREAT,
259         O_RDWR|O_CREAT|O_APPEND,
260         O_RDWR|O_CREAT|O_NDELAY,
261         O_RDWR|O_CREAT|O_SYNC,
262         O_RDWR|O_CREAT|O_SYNC|O_NDELAY,
263         O_RDWR|O_CREAT|O_APPEND|O_NDELAY,
264
265 #endif /* CRAY */
266 };
267
268 #define REXEC_INIT      0       /* don't do re-exec of childern */
269 #define REXEC_DOIT      1       /* Do re-exec of childern */
270 #define REXEC_DONE      2       /* We've already been re-exec'ed */
271
272 #ifndef BSIZE
273 #ifdef CRAY
274 #define BSIZE   1024
275 #else
276 #define BSIZE   512
277 #endif  /* CRAY */
278 #endif  /* BSIZE */
279
280 #define USECS_PER_SEC   1000000  /* microseconds per second */
281
282 /*
283  * Define marcos used when dealing with file locks.
284  */
285 #define LKLVL0          1       /* file lock around write/read/trunc */
286 #define LKLVL1          2       /* file lock after open to before close */
287
288 /*
289  * Define special max lseek values
290  */
291 #define LSK_EOF             -1  /* set fptr up to EOF */
292 #define LSK_EOFPLUSGROW     -2  /* set fptr up to EOF + grow - leave whole */
293 #define LSK_EOFMINUSGROW    -3  /* set fptr up to EOF-grow - no grow */
294
295
296 /***********************************************************************
297  * MAIN
298  ***********************************************************************/
299 int
300 main(argc, argv)
301 int argc;
302 char **argv;
303 {
304 extern char *optarg;            /* used by getopt */
305 extern int optind;
306 extern int opterr;
307
308 int ind;
309 int first_file_ind = 0;
310 int num_auto_files = 0;         /* files created by tool */
311 int seq_auto_files = 0;         /* auto files created by tool created by tool */
312 char *auto_dir = DEF_DIR;
313 char *auto_file = DEF_FILE;
314 int grow_incr = 4096;
315 int trunc_incr = 4096;
316 int trunc_inter = 0;            /* 0 means none, */
317 int unlink_inter = 0;           /* 0 means none, 1 means always unlink */
318 int unlink_inter_ran = -1;      /* -1 -use unlink_inter, otherwise randomly choose */
319                                 /* between unlink_inter and unlink_inter_ran */
320 int file_check_inter = 0;       /* 0 means never, 1 means always */
321 int write_check_inter = 1;      /* 0 means never, 1 means always */
322 int iterations = 1;             /* number of increments to be added */
323 int no_file_check = 0;          /* if set, no whole file checking will be done */
324 int num;
325 int fd;                         /* file descriptor */
326 int stop = 0;                   /* loop stopper if set */
327 int tmp;
328 char chr;
329 int ret;
330 int pre_alloc_space = 0;
331 #ifndef NO_XFS
332 int total_grow_value = 0;       /* used in pre-allocations */
333 #endif
334 int backgrnd = 1;               /* return control to user */
335 struct stat statbuf;
336 int time_iterval = -1;
337 time_t start_time = 0;
338 char reason[40];                /* reason for loop termination */
339 int num_procs=1;
340 int forker_mode=0;
341 int reexec=REXEC_INIT;          /* reexec info */
342 char *exec_path=NULL;
343
344 char *strrchr();
345
346 char *filename;                 /* name of file specified by user */
347 char *cptr;                     /* temp char pointer */
348 extern int Forker_npids;        /* num of forked pid, defined in forker.c */
349
350
351         if ( argv[0][0] == '-' )
352            reexec=REXEC_DONE;
353         /*
354          * Determine name of file used to invoke this program
355          */
356         if ((Progname=strrchr(argv[0], '/')) != NULL)
357                 Progname++;
358         else
359                 Progname=argv[0];
360
361         TagName[0] = '\0';
362
363         /*
364          * Process options
365          */
366         while ((ind=getopt(argc, argv, 
367             "hB:C:c:bd:D:e:Ef:g:H:I:i:lL:n:N:O:o:pP:q:wt:r:R:s:S:T:uU:W:xy")) != EOF) {
368                 switch(ind) {
369
370                 case 'h' :
371                         help();
372                         exit(0);
373
374                 case 'B':
375                         switch (sscanf(optarg, "%i%c",
376                                    &bytes_to_consume, &chr)) {
377                         case 1: /* noop */
378                                 break;
379
380                         case 2:
381                                 if (chr == 'b') {
382                                     bytes_to_consume *= BSIZE;
383                                 } else {
384                                     fprintf(stderr,
385                                         "%s%s:  --B option arg invalid\n",
386                                         Progname, TagName);
387                                     usage();
388                                     exit(1);
389                                 }
390                                 break;
391
392                         default:
393                                 fprintf(stderr, "%s%s: --B option arg invalid\n",
394                                         Progname, TagName);
395                                 usage();
396                                 exit(1);
397                                 break;
398                         }
399
400                         break;
401
402                 case 'E' :
403                         prt_examples(stdout);
404                         exit(0);
405
406                 case 'b' :      /* batch */
407                         backgrnd=0;
408                         break;
409
410                 case 'C':
411                         if (sscanf(optarg, "%i", &write_check_inter) != 1 ) {
412                                 fprintf(stderr, "%s%s: --c option arg invalid\n",
413                                         Progname, TagName);
414                                 usage();
415                                 exit(1);
416                         }
417                        break;
418
419                 case 'c':
420                         if (sscanf(optarg, "%i", &file_check_inter) != 1 ) {
421                                 fprintf(stderr, "%s%s: --c option arg invalid\n",
422                                         Progname, TagName);
423                                 usage();
424                                 exit(1);
425                         }
426                         break;
427
428
429                 case 'd':
430                         auto_dir=optarg;
431 #ifdef CRAY
432                         unsetenv("TMPDIR");     /* force the use of auto_dir */
433 #endif
434                         if ( stat(auto_dir, &statbuf) == -1 ) {
435                             if ( mkdir(auto_dir, 0777) == -1 ) {
436                                 if ( errno != EEXIST ) {
437                                     fprintf(stderr,
438                                         "%s%s: Unable to make dir %s\n", 
439                                         Progname, TagName, auto_dir);
440                                     exit(1);
441                                 }
442                             }
443                         }
444                         else {
445                             if ( ! (statbuf.st_mode & S_IFDIR) )  {
446                                 fprintf(stderr,
447                                     "%s%s: %s already exists and is not a directory\n",
448                                     Progname, TagName, auto_dir);
449                                 exit(1);
450                             }
451                         }
452                         break;
453
454                 case 'D':
455                         if (sscanf(optarg, "%i", &Debug) != 1 ) {
456                                 fprintf(stderr, "%s%s: --D option arg invalid\n",
457                                         Progname, TagName);
458                                 usage();
459                                 exit(1);
460                         }
461                         break;
462
463                 case 'e':
464                         if (sscanf(optarg, "%i", &Maxerrs) != 1 ) {
465                                 fprintf(stderr, "%s%s: --e option arg invalid\n",
466                                         Progname, TagName);
467                                 usage();
468                                 exit(1);
469                         }
470                         break;
471
472                 case 'f':
473                         auto_file=optarg;
474                         break;
475
476                 case 'g':
477                         if ((ret=sscanf(optarg, "%i%c", &grow_incr, &chr)) < 1 ||
478                                 grow_incr < 0 ) {
479
480                                 fprintf(stderr, "%s%s: --g option arg invalid\n",
481                                         Progname, TagName);
482                                 usage();
483                                 exit(1);
484                         }
485                         if ( ret == 2 ) {
486                                 if ( chr == 'b' || chr == 'B' )
487                                         grow_incr *= 4096;
488                                 else {
489                                         fprintf(stderr,
490                                                 "%s%s: --g option arg invalid\n",
491                                                 Progname, TagName);
492                                         usage();
493                                         exit(1);
494                                 }
495                         }
496                         break;
497
498                 case 'H':
499                         if (sscanf(optarg, "%f", &delaysecs) != 1 || delaysecs < 0 ) {
500
501                                 fprintf(stderr, "%s%s: --H option arg invalid\n",
502                                         Progname, TagName);
503                                 usage();
504                                 exit(1);
505                         }
506                         break;
507
508                 case 'i':
509                         if (sscanf(optarg, "%i", &iterations) != 1 ||
510                                 iterations < 0 ) {
511
512                                 fprintf(stderr, "%s%s: --i option arg invalid\n",
513                                         Progname, TagName);
514                                 usage();
515                                 exit(1);
516                         }
517                         break;
518
519                 case 'I':
520 #if NEWIO
521                         if((io_type=lio_parse_io_arg1(optarg)) == -1 ) {
522                             fprintf(stderr,
523                                 "%s%s: --I arg is invalid, must be s, p, f, a, l, L or r.\n",
524                                 Progname, TagName);
525                             exit(1);
526                         }
527                         if( io_type & LIO_RANDOM )
528                                 using_random++;
529 #else
530                         if((io_type=parse_io_arg(optarg)) == -1 ) {
531                             fprintf(stderr,
532                                 "%s%s: --I arg is invalid, must be s, p, f, a, l, L or r.\n",
533                                 Progname, TagName);
534                             exit(1);
535                         }
536                         if( io_type == 99 ) /* hold-over until tlibio.h */
537                                 using_random++;
538 #endif
539                         break;
540
541                 case 'l':
542                         lockfile++;
543                         if ( lockfile > 2 )
544                            lockfile=2;  /* lockfile can only be 1 or 2 */
545                         break;
546
547                 case 'L':
548                         if (sscanf(optarg, "%i", &time_iterval) != 1 ||
549                                 time_iterval < 0 ) {
550                                 fprintf(stderr, "%s%s: --L option arg invalid\n",
551                                         Progname, TagName);
552                                 usage();
553                                 exit(1);
554                         }
555                         break;
556
557                 case 'n':
558                         if (sscanf(optarg, "%i:%i", &num_procs, &forker_mode) < 1 ||
559                                 num_procs < 0 ) {
560
561                                 fprintf(stderr, "%s%s: --n option arg invalid\n",
562                                         Progname, TagName);
563                                 usage();
564                                 exit(1);
565                         }
566
567                         break;
568
569                 case 'N':
570                         if (sscanf(optarg, "%i", &num_auto_files) != 1 ||
571                                 num_auto_files < 0 ) {
572
573                                 fprintf(stderr, "%s%s: --N option arg invalid\n",
574                                         Progname, TagName);
575                                 usage();
576                                 exit(1);
577                         }
578                         break;
579
580                 case 'O':
581                         if (sscanf(optarg, "%i", &Alignment) != 1 ||
582                                 num_auto_files < 0 ) {
583
584                                 fprintf(stderr, "%s%s: --O option arg invalid\n",
585                                         Progname, TagName);
586                                 usage();
587                                 exit(1);
588                         }
589                         break;
590
591                 case 'o':
592                         if ( strcmp(optarg, "random") == 0 ){
593                             open_flags=RANDOM_OPEN;
594                             using_random++;
595
596                         } else if ((open_flags=parse_open_flags(optarg, NULL)) == -1 ) {
597                             fprintf(stderr, "%s%s: --o arg contains invalid flag\n",
598                                 Progname, TagName);
599                             exit(1);
600                         }
601                         break;
602
603
604                 case 'p' :      /* pre allocate space */
605 #ifdef NO_XFS
606                         printf("%s%s: --p is illegal option on this system\n",
607                                 Progname, TagName);
608                         exit(1);
609 #else
610                         pre_alloc_space++;
611 #endif
612                         break;
613
614                 case 'P':
615 #ifdef CRAY
616                         if (strcmp(optarg, "PANIC") != 0 ) {
617                                 fprintf(stderr, "%s%s: --P arg must be PANIC\n", Progname, TagName);
618                                 exit(1);
619                         }
620                         Upanic_on_error++;
621                         printf("%s: Will call upanic after writes\n");
622 #else
623                         printf("%s%s: --P is illegal option on non-cray system\n",
624                                 Progname, TagName);
625                         exit(1);
626 #endif
627                         break;
628
629                 case 'q':       /* file content or pattern */
630                         switch(optarg[0]) {
631                         case 'A':
632                             Pattern = PATTERN_ALT;
633                             break;
634                         case 'a':
635                             Pattern = PATTERN_ASCII;
636                             break;
637                         case 'p':
638                             Pattern = PATTERN_PID;
639                             break;
640                         case 'o':
641                             Pattern = PATTERN_OFFSET;
642                             break;
643                         case 'c':
644                             Pattern = PATTERN_CHKER;
645                             break;
646                         case 'C':
647                             Pattern = PATTERN_CNTING;
648                             break;
649                         case 'r':
650                             Pattern = PATTERN_RANDOM;
651                             using_random++;
652                             break;
653                         case 'z':
654                             Pattern = PATTERN_ZEROS;
655                             break;
656                         case 'O':
657                             Pattern = PATTERN_ONES;
658                             break;
659                         default:
660                             fprintf(stderr,
661                                 "%s%s: --C option arg invalid, A, a, p, o, c, C, r, z, or 0\n",
662                                 Progname, TagName);
663                             usage();
664                             exit(1);
665                         }
666                         break;
667
668                 case 'R':       /* random lseek before write arg: [min-]max*/
669                         if (sscanf(optarg, "%i-%i", &min_lseek, &max_lseek) != 2 ) {
670                             min_lseek=1;    /* same as default in define */
671                             if (sscanf(optarg, "%i%c", &max_lseek, &chr) != 1 ) {
672                                 fprintf(stderr, "%s%s: --R option arg invalid: [min-]max\n",
673                                     Progname, TagName);
674                                 exit(1);
675                             }
676                         }
677                         if ( max_lseek < LSK_EOFMINUSGROW ) {
678                             fprintf(stderr, "%s%s: --R option, max_lseek is invalid\n",
679                                 Progname, TagName);
680                             exit(1);
681                         }
682                         Mode |= MODE_RAND_LSEEK;
683                         using_random++;
684                         break;
685
686                 case 'r':       /* random io size arg: [min-]max[:mult] */
687
688                         /* min-max:mult format */
689                         if (sscanf(optarg, "%i-%i:%i%c", &min_size, &max_size,
690                                                         &mult_size, &chr) != 3 ) {
691                           min_size=1;   
692                           /* max:mult format */
693                           if (sscanf(optarg, "%i:%i%c", &max_size,
694                                                         &mult_size, &chr) != 2 ) {
695                             /* min-max format */
696                             if (sscanf(optarg, "%i-%i%c", &min_size,
697                                                         &max_size, &chr) != 2 ) {
698                               min_size=1;   
699                               if (sscanf(optarg, "%i%c", &max_size, &chr) != 1 ) {
700                                 fprintf(stderr,
701                                      "%s%s: --r option arg invalid: [min-]max[:mult]\n",
702                                 Progname, TagName);
703                                 exit(1);
704                               }
705                             }
706                           }
707                         }
708
709                         if ( max_size < 0 ) {
710                             fprintf(stderr, "%s%s: --r option, max_size is invalid\n",
711                                 Progname, TagName);
712                             exit(1);
713                         }
714                         /*
715                          * If min and max are the same, no randomness
716                          */
717                         if ( min_size != max_size ) {
718                             Mode |= MODE_RAND_SIZE;
719                             using_random++;
720                         }
721                         break;
722
723                 case 'S':
724                         if (sscanf(optarg, "%i", &seq_auto_files) != 1 ||
725                                 seq_auto_files < 0 ) {
726
727                                 fprintf(stderr, "%s%s: --S option arg invalid\n",
728                                         Progname, TagName);
729                                 usage();
730                                 exit(1);
731                         }
732                         break;
733
734                 case 's':       /* format: seed[,seed...] */
735                         
736                         /* count the number of seeds */
737                         cptr=optarg;
738                         for(Nseeds=1; *cptr ; Nseeds++) {
739                             if ( (filename=strchr(cptr, ',')) == NULL )
740                                 break;
741                             cptr=filename;
742                             cptr++;
743                         }
744                         Seeds=(int *)malloc(Nseeds*sizeof(int));
745
746                         /*
747                          * check that each seed is valid and put them in 
748                          * the newly malloc'ed Seeds arrary.
749                          */
750                         filename=cptr=optarg;
751                         for(Nseeds=0; *cptr; Nseeds++) {
752                             if ( (filename=strchr(cptr, ',')) == NULL ) {
753                                 if ( sscanf(cptr, "%i", &Seeds[Nseeds]) < 1 ) {
754                                     fprintf(stderr, "%s%s: --s option arg %s invalid\n",
755                                         Progname, TagName, cptr);
756                                     usage();
757                                     exit(1);
758                                 }
759                                 Nseeds++;
760                                 break;
761                             }
762
763                             *filename='\0';
764                             if ( sscanf(cptr, "%i", &Seeds[Nseeds]) < 1 ) {
765                                fprintf(stderr, "%s%s: --s option arg %s invalid\n",
766                                         Progname, TagName, cptr);
767                                 usage();
768                                 exit(1);
769                             }
770                             *filename=',';   /* restore string */
771                             cptr=filename;
772                             cptr++;
773                         }
774                         break;
775
776                 case 't':
777                         if ((ret=sscanf(optarg, "%i%c", &trunc_incr, &chr)) < 1 ||
778                                 trunc_incr < 0 ) {
779
780                                 fprintf(stderr, "%s%s: --t option arg invalid\n",
781                                         Progname, TagName);
782                                 usage();
783                                 exit(1);
784                         }
785                         if ( ret == 2 ) {
786                                 if ( chr == 'b' || chr == 'B' )
787                                         trunc_incr *= 4096;
788                                 else {
789                                         fprintf(stderr,
790                                                 "%s%s: --t option arg invalid\n",
791                                                 Progname, TagName);
792                                         usage();
793                                         exit(1);
794                                 }
795                         }
796                         break;
797
798                 case 'T':       /* truncate interval */
799                         if (sscanf(optarg, "%i%c", &trunc_inter, &chr) != 1 ||
800                                 trunc_inter < 0 ) {
801
802                                 fprintf(stderr, "%s%s: --T option arg invalid\n",
803                                         Progname, TagName);
804                                 usage();
805                                 exit(1);
806                         }
807                         break;
808
809                 case 'u':
810                         remove_files++;
811                         break;
812
813                 case 'U':   /* how often to unlink file */
814                        /* 
815                         * formats:   
816                         *      A-B  - randomly pick interval between A and B 
817                         *      X    - unlink file every X iteration
818                         */
819                        if (sscanf(optarg, "%i-%i", &unlink_inter, 
820                                                 &unlink_inter_ran) == 2 ) {
821
822                            if ( unlink_inter < 0 || unlink_inter_ran < 0 ) {
823                                 fprintf(stderr, "%s%s: --U option arg invalid\n",
824                                         Progname, TagName);
825                                 usage();
826                                 exit(1);
827                            }
828                            /* ensure unlink_inter contains smaller value */
829                            if ( unlink_inter > unlink_inter_ran ) {
830                                 tmp=unlink_inter_ran;
831                                 unlink_inter_ran=unlink_inter;
832                                 unlink_inter=tmp;
833                            }
834                            using_random++;
835
836                        } else if (sscanf(optarg, "%i%c", &unlink_inter, &chr) != 1 ||
837                                 unlink_inter < 0 ) {
838
839                             fprintf(stderr, "%s%s: --U option arg invalid\n",
840                                  Progname, TagName);
841                             usage();
842                             exit(1);
843                         }
844                         break;
845
846                 case 'x':
847                         if ( reexec != REXEC_DONE )
848                             reexec=REXEC_DOIT;
849                         break;
850
851                 case 'w':
852                         Mode |= MODE_GROW_BY_LSEEK;
853                         break;
854
855                 case 'W':
856                         sprintf( TagName, "(%.39s)", optarg );
857                         break;
858
859                 case 'y':
860                         Sync_with_others=1;
861                         break;
862
863                 case '?':
864                         usage();
865                         exit(1);
866                         break;
867                 }
868         }
869
870         if( Debug == 1 ){
871                 cptr = getenv("TOUTPUT");
872                 if( (cptr != NULL) && (strcmp( cptr, "NOPASS" ) == 0) ){
873                         Debug = 0;
874                 }
875         }
876
877         if ( Pattern == PATTERN_RANDOM ) {
878             no_file_check=1;
879             if ( write_check_inter || file_check_inter )
880                 printf("%s%s: %d Using random pattern - no data checking will be performed!\n",
881                     Progname, TagName, (int)getpid());
882         }
883         else if ( max_lseek == LSK_EOFPLUSGROW || Mode & MODE_GROW_BY_LSEEK ) {
884             no_file_check=1;
885
886             if ( file_check_inter )
887                 printf("%s%s: %d Using random lseek beyond EOF or lseek grow,\n\
888 no whole file checking will be performed!\n", Progname, TagName, (int)getpid());
889
890         }
891
892         if ( Mode & MODE_RAND_SIZE )
893             grow_incr=max_size;
894
895         set_sig();
896
897         Opid=getpid();
898         Pid=Opid;
899
900         if ( backgrnd ) {
901             if ( Debug > 1 )
902                 printf("%s: %d DEBUG2 forking, returning control to the user\n",
903                     Progname, Opid);
904             background(Progname);       /* give user their prompt back */
905         }
906
907 #if CRAY
908         if ( Sync_with_others )
909            setpgrp();
910 #endif
911
912         if ( Debug > 3 ) {
913 #if NEWIO
914             lio_set_debug(Debug-3);
915 #else
916             set_iowrite_debug(Debug-3);
917 #endif
918         }
919
920         /*
921          * Print some program information here if debug is turned on to
922          * level 3 or higher.
923          */
924
925         if ( Debug > 2 ) {
926             
927             if (  Mode & MODE_GROW_BY_LSEEK )
928                 printf("%s: %d DEBUG lseeking past end of file, writting a \"w\"\n",
929                     Progname, Pid);
930             else if ( Pattern == PATTERN_OFFSET )
931                 printf("%s: %d DEBUG3 %d<byteoffset>%d per word pattern multi-writers.\n",
932                     Progname, Pid, STATIC_NUM, STATIC_NUM);
933             else if ( Pattern == PATTERN_PID )
934                 printf("%s: %d DEBUG3 <pid><byteoffset><pid> per word pattern - 1 writer\n",
935                     Progname, Pid);
936             else if ( Pattern == PATTERN_ASCII )
937                 printf("%s: %d DEBUG3 ascii pattern (vi'able)- allows multiple writers\n",
938                     Progname, Pid);
939             else if ( Pattern == PATTERN_ALT )
940                 printf("%s: %d DEBUG3 alt bit pattern - allows multiple writers\n",
941                     Progname, Pid);
942             else if ( Pattern == PATTERN_CHKER )
943                 printf("%s: %d DEBUG3 checkerboard pattern - allows multiple writers\n",
944                     Progname, Pid);
945             else if ( Pattern == PATTERN_CNTING )
946                 printf("%s: %d DEBUG3 counting pattern - allows multiple writers\n",
947                     Progname, Pid);
948             else if ( Pattern == PATTERN_RANDOM )
949                 printf("%s: %d DEBUG3 random integer pattern - no write/file checking\n",
950                     Progname, Pid);
951             else if ( Pattern == PATTERN_ONES )
952                 printf("%s: %d DEBUG3 all ones pattern - allows multiple writers\n",
953                     Progname, Pid);
954             else if ( Pattern == PATTERN_ZEROS )
955                 printf("%s: %d DEBUG3 all zeros pattern - allows multiple writers\n",
956                     Progname, Pid);
957         
958             else
959                 printf("%s: %d DEBUG3 unknown pattern\n",
960                     Progname, Pid);
961             if ( bytes_to_consume )
962                 printf("%s: %d DEBUG3 bytes_to_consume = %d\n",
963                     Progname, Pid, bytes_to_consume);
964             printf("%s: %d DEBUG3 Maxerrs = %d, pre_alloc_space = %d, filelocking = %d\n", 
965                 Progname, Pid, Maxerrs, pre_alloc_space, lockfile);
966
967             printf("%s: %d DEBUG3 Debug = %d, remove files in cleanup : %d\n",
968                 Progname, Pid, Debug, remove_files);
969
970             printf("%s: %d DEBUG3 Mode = %#o\n", Progname, Pid, Mode);
971
972             if ( open_flags == RANDOM_OPEN )
973                printf("%s: %d DEBUG3 open_flags = (random), io_type = %#o\n", Progname,
974                  Pid, io_type);
975             else
976                printf("%s: %d DEBUG3 open_flags = %#o, io_type = %#o\n", Progname,
977                  Pid, open_flags, io_type);
978
979             if ( Mode & MODE_RAND_SIZE ) {
980                 printf("%s: %d DEBUG3 random write/trunc:  min=%d, max=%d, mult = %d\n",
981                     Progname, Pid, min_size, max_size, mult_size);
982             }
983             else {
984                 printf("%s: %d DEBUG3 grow_incr = %d\n", 
985                     Progname, Pid, grow_incr);
986             }
987             if ( Mode & MODE_RAND_LSEEK ) {
988                 if ( max_lseek == LSK_EOF )
989                   printf("%s: %d DEBUG3 random lseek:  min=%d, max=<endoffile>\n",
990                     Progname, Pid, min_lseek);
991                 else if ( max_lseek == LSK_EOFPLUSGROW )
992                   printf("%s: %d DEBUG3 random lseek:  min=%d, max=<endoffile+iosize>\n",
993                     Progname, Pid, min_lseek);
994                 else if ( max_lseek == LSK_EOFMINUSGROW )
995                   printf("%s: %d DEBUG3 random lseek:  min=%d, max=<endoffile-iosize>\n",
996                     Progname, Pid, min_lseek);
997                 else
998                   printf("%s: %d DEBUG3 random lseek:  min=%d, max=%d\n",
999                     Progname, Pid, min_lseek, max_lseek);
1000             }
1001
1002             printf("%s: %d DEBUG3 check write interval = %d, check file interval = %d\n",
1003                 Progname, Pid, write_check_inter, file_check_inter);
1004
1005             printf("%s: %d DEBUG3 trunc interval = %d, trunc_incr = %d\n",
1006                 Progname, Pid, trunc_inter, trunc_incr);
1007
1008             if ( no_file_check )
1009                 printf("%s: %d DEBUG3 no whole file checking will be done\n",
1010                     Progname, Pid);
1011             
1012             if ( unlink_inter_ran == -1 ) {
1013                 printf("%s: %d DEBUG3 unlink_inter = %d\n", 
1014                         Progname, Pid, unlink_inter);
1015             } else {
1016                 printf("%s: %d DEBUG3 unlink_inter = %d, unlink_inter_ran = %d\n", 
1017                         Progname, Pid, unlink_inter, unlink_inter_ran);
1018             }  
1019
1020             if ( Debug > 8 ) {
1021                num=sizeof(Open_flags)/sizeof(int);
1022                printf("%s: %d DEBUG9 random open flags values:\n", Progname, Pid);
1023                for(ind=0; ind<num; ind++) {
1024                     printf("\t%#o\n", Open_flags[ind]);
1025                }
1026             }
1027         }  /* end of DEBUG > 2 */
1028
1029         if ( Debug > 1 && num_procs > 1 ) {
1030             printf("%s: %d DEBUG2 about to fork %d more copies\n", Progname,
1031                 Opid, num_procs-1);
1032         }
1033
1034         fflush(stdout); /* ensure pending i/o is flushed before forking */
1035         fflush(stderr);
1036
1037         forker(num_procs, forker_mode, Progname);
1038
1039         Pid=getpid();   /* reset after the forks */
1040         /*
1041          * If user specified random seed(s), get that random seed value.
1042          * get random seed if it was not specified by the user.
1043          * This is done after the forks, because pid is used to get the seed.
1044          */
1045         if ( Nseeds == 1 ) {
1046             /*
1047              * If only one seed specified, all processes will get that seed. 
1048              */
1049             Seed=Seeds[0];
1050         } else if ( Nseeds > 1 ) {
1051             /*
1052              * More than one seed was specified.
1053              * The original process gets the first seed.  Each
1054              * process will be get the next seed in the specified list.
1055              */
1056             if ( Opid == Pid ) {
1057                 Seed=Seeds[0];
1058             } else {
1059                 /*
1060                  * If user didn't specify enough seeds, use default method.
1061                  */
1062                 if ( Forker_npids >= Nseeds ) 
1063                     Seed=time(0) + Pid;  /* default random seed */
1064                 else {
1065                     Seed=Seeds[Forker_npids];
1066                 }
1067             }
1068         } else {
1069             /* 
1070              * Generate a random seed based on time and pid.
1071              * It has a good chance of being unique for each pid.
1072              */
1073             Seed=time(0) + Pid;  /* default random seed */
1074         }
1075
1076         random_range_seed(Seed);
1077
1078         if ( using_random && Debug > 0 )
1079             printf("%s%s: %d DEBUG1 Using random seed of %d\n",
1080                 Progname, TagName, Pid, Seed);
1081
1082         if ( unlink_inter_ran > 0 ) {
1083             /*
1084              * Find unlinking file interval.  This must be done after
1085              * the seed was set.   This allows multiple copies to
1086              * get different intervals.
1087              */
1088             tmp=unlink_inter;
1089             unlink_inter=random_range(tmp, unlink_inter_ran, 1, NULL);
1090
1091             if ( Debug > 2 )
1092                 printf("%s: %d DEBUG3 Unlink interval is %d (random %d - %d)\n",
1093                     Progname, Pid, unlink_inter, tmp, unlink_inter_ran);
1094         }
1095
1096         /*
1097          * re-exec all childern if reexec is set to REXEC_DOIT.
1098          * This is useful on MPP systems to get the
1099          * child process on another PE.
1100          */
1101         if ( reexec == REXEC_DOIT && Opid != Pid ) {
1102             if ( exec_path == NULL ) {
1103                 exec_path = argv[0];
1104                 /* Get space for cmd (2 extra, 1 for - and 1 fro NULL */
1105                 argv[0] = (char *)malloc(strlen(exec_path) + 2);
1106                 sprintf(argv[0], "-%s", exec_path);
1107             }
1108           
1109             if ( Debug > 2 )
1110                 printf("%s: %d DEBUG3 %s/%d: execvp(%s, argv)\n",
1111                     Progname, Pid, __FILE__, __LINE__, argv[0]);
1112
1113             execvp(argv[0], argv);
1114         }
1115
1116         /*** begin filename stuff here *****/
1117         /*
1118          * Determine the number of files to be dealt with
1119          */
1120         if ( optind == argc ) {
1121                 /*
1122                  * no cmd line files, therfore, set
1123                  * the default number of auto created files
1124                  */
1125                 if ( ! num_auto_files && ! seq_auto_files )
1126                         num_auto_files=1;
1127         }
1128         else {
1129                 first_file_ind=optind;
1130                 num_files += argc-optind;
1131         }
1132
1133         if ( num_auto_files ) {
1134                 num_files += num_auto_files;
1135         }
1136
1137         if ( seq_auto_files ) {
1138                 num_files += seq_auto_files;
1139         }
1140
1141         /*
1142          * get space for file names
1143          */
1144         if ((filenames=(char *)malloc(num_files*PATH_MAX)) == NULL) {
1145                 fprintf(stderr, "%s%s: %d %s/%d: malloc(%d) failed: %s\n",
1146                         Progname, TagName, Pid, __FILE__, __LINE__, num_files*PATH_MAX,
1147                         strerror(errno));
1148                 exit(1);
1149         }
1150
1151         /*
1152          * fill in filename cmd files then auto files.
1153          */
1154
1155         num=0;
1156         if ( first_file_ind ) {
1157                 for(ind=first_file_ind; ind<argc; ind++, num++) {
1158                         strcpy((char *)filenames+(num*PATH_MAX), argv[ind]);
1159                 }
1160         }
1161
1162         /*
1163          * construct auto filename and insert them into filenames space
1164          */
1165                 
1166         for(ind=0;ind<num_auto_files; ind++, num++) {
1167                 sprintf((char *)filenames+(num*PATH_MAX), "%s.%d",
1168                         tempnam(auto_dir, auto_file), ind );
1169         }
1170
1171         /*
1172          * construct auto seq filenames
1173          */
1174         for(ind=1; ind<=seq_auto_files; ind++, num++) {
1175                 sprintf((char *)filenames+(num*PATH_MAX), "%s/%s%d",
1176                         auto_dir, auto_file, ind);
1177         }
1178
1179 /**** end filename stuff ****/
1180
1181         if ( time_iterval > 0 )
1182                 start_time=time(0);
1183
1184         /*
1185          * get space for I/O buffer
1186          */
1187         if ( grow_incr ) {
1188                 if ((Buffer=(char *)malloc(grow_incr+Alignment)) == NULL) {
1189                         fprintf(stderr, "%s%s: %d %s/%d: malloc(%d) failed: %s\n",
1190                                 Progname, TagName, Pid, __FILE__, __LINE__, grow_incr, strerror(errno));
1191                         exit(1);
1192                 }
1193                 if ( Alignment )
1194                 Buffer = Buffer + Alignment;
1195
1196         }
1197
1198         if ( Debug > 2 ) {
1199                 printf("%s: %d DEBUG3 num_files = %d\n",
1200                         Progname, Pid, num_files);
1201         }
1202
1203 #ifndef NO_XFS
1204         if ( pre_alloc_space ) {
1205                 if ( iterations == 0 ) {
1206                     fprintf(stderr, "%s%s: %d %s/%d: can NOT pre-alloc and grow forever\n",
1207                         Progname, TagName, Pid, __FILE__, __LINE__);
1208                     exit(1);
1209                 }
1210                 if ( Mode & MODE_RAND_SIZE ) {
1211                     fprintf(stderr,
1212                         "%s%s: %d %s/%d: can NOT pre-alloc and do random io size\n",
1213                         Progname, TagName, Pid, __FILE__, __LINE__);
1214                     exit(1);
1215                 }
1216
1217                 total_grow_value=grow_incr * iterations;
1218
1219                 /*
1220                  * attempt to limit 
1221                  */
1222                 if ( bytes_to_consume && bytes_to_consume < total_grow_value ) {
1223                         total_grow_value=bytes_to_consume;
1224                 }
1225         }
1226 #endif
1227
1228         /*
1229          * If delaying between iterations, get amount time to
1230          * delaysecs in clocks or usecs.
1231          * If on the CRAY, delaytime is in clocks since
1232          * _rtc() will be used, which does not have the overhead
1233          * of gettimeofday(2).
1234          */
1235         if ( delaysecs ) {
1236 #if CRAY
1237            int hz;
1238            hz=sysconf(_SC_CLK_TCK);
1239            delaytime=(int)((float)hz * delaysecs);
1240 #else
1241            delaytime=(int)((float)USECS_PER_SEC * delaysecs);
1242 #endif
1243         }
1244
1245         /*
1246          * This is the main iteration loop.
1247          * Each iteration, all files can  be opened, written to,
1248          * read to check the write, check the whole file, 
1249          * truncated, and closed.   
1250          */
1251         for(Iter_cnt=1; ! stop ; Iter_cnt++) {
1252
1253             if ( iterations && Iter_cnt >= iterations+1 ) {
1254                 strcpy(reason, "Hit iteration value");
1255                 stop=1;
1256                 continue;
1257             }
1258
1259             if (  (time_iterval > 0) && (start_time + time_iterval < time(0)) ) {
1260                 sprintf(reason, "Hit time value of %d", time_iterval);
1261                 stop=1;
1262                 continue;
1263             }
1264
1265             if ( bytes_to_consume && bytes_consumed >= bytes_to_consume) {
1266                 sprintf(reason, "Hit bytes consumed value of %d", bytes_to_consume);
1267                 stop=1;
1268                 continue;
1269             }
1270
1271             /*
1272              * This loop will loop through all files.
1273              * Each iteration, a single file can  be opened, written to,
1274              * read to check the write, check the whole file, 
1275              * truncated, and closed.   
1276              */
1277             for(ind=0; ind<num_files; ind++) {
1278
1279                 fflush(stdout);
1280                 fflush(stderr);
1281
1282                 filename=(char *)filenames+(ind*PATH_MAX);
1283                 Fileinfo.filename=(char *)filenames+(ind*PATH_MAX);
1284
1285
1286                 if ( open_flags ==  RANDOM_OPEN ) {
1287                    ret=Open_flags[random_range(0, sizeof(Open_flags)/sizeof(int)-1, 1, NULL)];
1288                 }
1289
1290                 else
1291                    ret=open_flags;
1292
1293                 Fileinfo.openflags=ret;
1294
1295                 if ( Debug > 3 ) {
1296                     printf("%s: %d DEBUG3 %s/%d: %d Open filename = %s, open flags = %#o %s\n",
1297                         Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, ret, 
1298                         openflags2symbols(ret, ",", NULL));
1299                 } else if ( Debug > 2 ) {
1300                     printf("%s: %d DEBUG3 %s/%d: %d filename = %s, open flags = %#o\n",
1301                         Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, ret);
1302                 }
1303
1304                 /*
1305                  * open file with desired flags.
1306                  */
1307                 if ( (fd=open(filename, ret, 0777)) == -1 ) {
1308                     fprintf(stderr,
1309                         "%s%s: %d %s/%d: open(%s, %#o, 0777) returned -1, errno:%d %s\n",
1310                         Progname, TagName, Pid, __FILE__, __LINE__, filename, ret, errno, strerror(errno));
1311                         handle_error();
1312                         continue;
1313                 }
1314
1315                 Fileinfo.fd=fd;
1316
1317                 lkfile(fd, LOCK_EX, LKLVL1);   /* lock if lockfile is LKLVL1 */
1318
1319 #ifndef NO_XFS
1320                 /*
1321                  * preallocation is only done once, if specified.
1322                  */
1323                 if ( pre_alloc_space ) {
1324                         if (pre_alloc(filename, fd, total_grow_value) != 0 ) {
1325                                 cleanup();
1326                                 exit(2);
1327                         }
1328                         if ( Debug > 1 ) {
1329                                 printf("%s: %d DEBUG2 %s/%d: pre_allocated %d for file %s\n",
1330                                     Progname, Pid, __FILE__, __LINE__, total_grow_value, filename);
1331                         }
1332                         lkfile(fd, LOCK_UN, LKLVL1);   /* release lock */
1333                         close(fd);
1334                         Iter_cnt=0;     /* reset outside loop to restart from one */
1335                         continue;
1336                 }
1337 #endif
1338
1339                 /*
1340                  * grow file by desired amount.
1341                  * growfile() will set the Grow_incr variable and 
1342                  * possiblly update the Mode variable indicating
1343                  * if we are dealing with a FIFO file.
1344                  */
1345
1346                 if (growfile(fd, filename, grow_incr, Buffer) != 0 ) {
1347                         handle_error();
1348                         lkfile(fd, LOCK_UN, LKLVL1);   /* release lock */
1349                         close(fd);
1350                         continue;
1351                 }
1352
1353                 /*
1354                  * check if last write is not corrupted
1355                  */
1356                 if ( check_write(fd, write_check_inter, filename,
1357                                                         Mode) != 0 ) {
1358                     handle_error();
1359                 }
1360
1361                 /*
1362                  * Check that whole file is not corrupted.
1363                  */
1364                 if ( check_file(fd, file_check_inter, filename,
1365                                                 no_file_check) != 0 ) {
1366                     handle_error();
1367                 }
1368
1369                 /*
1370                  * shrink file by desired amount if it is time 
1371                  */
1372
1373                 if ( shrinkfile(fd, filename, trunc_incr, trunc_inter, Mode) != 0 ) {
1374                     handle_error();
1375                 }
1376
1377                 lkfile(fd, LOCK_UN, LKLVL1);   /* release lock */
1378
1379                 if ( Debug > 4 )
1380                     printf("%s: %d DEBUG5 %s/%d: %d Closing file %s fd:%d \n", 
1381                         Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, fd);
1382                 close(fd);
1383
1384                 /*
1385                  * Unlink the file if that is desired
1386                  */
1387                 if ( unlink_inter && (Iter_cnt % unlink_inter == 0) ) {
1388                 
1389                     if ( Debug > 4 )
1390                         printf("%s: %d DEBUG5 %s/%d: %d Unlinking file %s\n", 
1391                             Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename);
1392
1393                     unlink(filename);
1394                 }
1395
1396                 /*
1397                  * delay while staying active for "delaysecs" seconds.
1398                  */
1399                 if ( delaytime ) {
1400                 
1401                     int ct, end;
1402 #ifdef CRAY
1403                     ct=_rtc();
1404                     end=ct+delaytime;
1405                     while ( ct < end ) {
1406                         ct = _rtc();
1407                     }
1408 #else
1409                     struct timeval curtime;
1410                     gettimeofday(&curtime, NULL);
1411                     ct=curtime.tv_sec*USECS_PER_SEC + curtime.tv_usec;
1412                     end=ct+delaytime;
1413                     while ( ct < end ) {
1414
1415                         gettimeofday(&curtime, NULL);
1416                         ct=curtime.tv_sec*USECS_PER_SEC + curtime.tv_usec;
1417                     }
1418 #endif
1419                 }
1420             }
1421 #ifndef NO_XFS
1422             /*
1423              * if Iter_cnt == 0, then we pre allocated space to all files
1424              * and we are starting outside loop over.  Set pre_alloc_space
1425              * to zero otherwise we get in infinite loop
1426              */
1427             if ( Iter_cnt == 0 ) {
1428                 pre_alloc_space=0;
1429             }
1430 #endif
1431
1432
1433         }   /* end iteration for loop */
1434
1435
1436         if ( Debug ) {
1437             printf("%s%s: %d %s/%d: DONE %d iterations to %d files. %s\n",
1438                 Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, num_files, reason);
1439         }
1440         fflush(stdout);
1441         fflush(stderr);
1442
1443         cleanup();
1444
1445         if ( Errors ) {
1446                 if ( Debug > 2 ) {
1447                     printf("%s%s: %d DEBUG3 %d error(s) encountered\n",
1448                         Progname, TagName, Pid, Errors);
1449                     printf("%s%s: %d DEBUG3 %s/%d: exiting with value of 1\n", Progname, TagName, Pid, __FILE__, __LINE__);
1450                 }
1451                 exit(1);
1452         }
1453         if ( Debug > 2 )
1454             printf("%s%s: %d DEBUG3 %s/%d: no errors, exiting with value of 0\n", Progname, TagName, Pid, __FILE__, __LINE__);
1455         exit(0);
1456 }
1457
1458 /***********************************************************************
1459  *
1460  ***********************************************************************/
1461 int
1462 set_sig()
1463 {
1464    int sig;
1465
1466         
1467         /*
1468          * now loop through all signals and set the handlers
1469          */
1470
1471         for (sig = 1; sig < NSIG; sig++) {
1472             switch (sig) {
1473                 case SIGKILL:
1474                 case SIGSTOP:
1475                 case SIGCONT:
1476 #ifdef CRAY
1477                 case SIGINFO:
1478                 case SIGRECOVERY:
1479 #endif /* CRAY */
1480 #ifdef SIGCKPT
1481                 case SIGCKPT:
1482 #endif /* SIGCKPT */
1483 #ifdef SIGRESTART
1484                 case SIGRESTART:
1485 #endif /* SIGRESTART */
1486                 case SIGCLD:
1487                     break;
1488
1489                 default:
1490 #ifdef sgi
1491                     sigset( sig, sig_handler );
1492 #else
1493 /* linux and cray */
1494                     signal(sig, sig_handler);
1495 #endif
1496                 break;
1497             }
1498         } /* endfor */
1499
1500
1501         return 0;
1502 }
1503
1504 /***********************************************************************
1505  *
1506  ***********************************************************************/
1507 void
1508 sig_handler(sig)
1509 int sig;
1510 {
1511     int exit_stat = 2;
1512
1513     if ( sig == SIGUSR2 ) {
1514         fprintf(stdout, "%s%s: %d %s/%d: received SIGUSR2 (%d) - stopping.\n",
1515             Progname, TagName, Pid, __FILE__, __LINE__, sig);
1516 #ifndef sgi
1517         signal(sig, sig_handler);       /* allow us to get this signal more than once */
1518 #endif
1519         
1520     } else if( sig == SIGINT ){
1521         /* The user has told us to cleanup, don't pretend it's an error. */
1522         exit_stat=0;
1523         if ( Debug != 0 ){
1524                 fprintf(stderr, "%s%s: %d %s/%d: received unexpected signal: %d\n", Progname, TagName,
1525                     Pid, __FILE__, __LINE__, sig);
1526         }
1527     } else {
1528         fprintf(stderr, "%s%s: %d %s/%d: received unexpected signal: %d\n", Progname, TagName,
1529             Pid, __FILE__, __LINE__, sig);
1530     }
1531
1532     notify_others();
1533     cleanup();
1534     if ( Debug > 2 ){
1535         printf("%s%s: %d DEBUG3 %s/%d: Exiting with a value of %d\n",
1536                Progname, TagName, Pid, __FILE__, __LINE__, exit_stat);
1537     }
1538     exit(exit_stat);
1539 }
1540
1541 /***********************************************************************
1542  * this function attempts to send SIGUSR2 to other growfiles processes
1543  * telling them to stop.
1544  *  
1545  ***********************************************************************/
1546 static void
1547 notify_others()
1548 {
1549     static int send_signals = 0;
1550     int ind;
1551     extern int Forker_pids[];
1552     extern int Forker_npids;
1553
1554     if ( Sync_with_others && send_signals == 0 ) {
1555
1556 #if CRAY
1557         send_signals=1; /* only send signals once */
1558         if ( Debug > 1 )
1559             printf("%s%s: %d DEBUG2 %s/%d: Sending SIGUSR2 to pgrp\n",
1560                   Progname, TagName, Pid, __FILE__, __LINE__);
1561         killm(C_PGRP, getpgrp(), SIGUSR2);
1562 #else
1563         send_signals=1; /* only send signals once */
1564
1565         for (ind=0; ind< Forker_npids; ind++) {
1566             if ( Forker_pids[ind] != Pid )
1567                 if ( Debug > 1 )
1568                     printf("%s%s: %d DEBUG2 %s/%d: Sending SIGUSR2 to pid %d\n",
1569                         Progname, TagName, Pid, __FILE__, __LINE__, Forker_pids[ind]);
1570                 kill(Forker_pids[ind], SIGUSR2);
1571         }
1572 #endif
1573     }
1574
1575 }
1576
1577 /***********************************************************************
1578  * this function will count the number of errors encountered.
1579  * This function will call upanic if wanted or cleanup and
1580  * and exit is Maxerrs were encountered.
1581  ***********************************************************************/
1582 int
1583 handle_error()
1584 {
1585     Errors++;
1586
1587 #ifdef CRAY
1588     if ( Errors & Upanic_on_error ) {
1589         upanic(PA_PANIC);
1590     }
1591 #endif
1592
1593     if ( Maxerrs && Errors >= Maxerrs ) {
1594         printf("%s%s: %d %s/%d: %d Hit max errors value of %d\n", 
1595             Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, Maxerrs);
1596         notify_others();
1597         cleanup();
1598
1599         if ( Debug > 2 ) {
1600             printf("%s%s: %d DEBUG3 %d error(s) encountered\n",
1601                         Progname, TagName, Pid, Errors);
1602             printf("%s%s: %d DEBUG3 %s/%d: exiting with value of 1\n", Progname, TagName, Pid, __FILE__, __LINE__);
1603         }
1604
1605         exit(1);
1606     }
1607
1608     return 0;
1609 }
1610
1611 /***********************************************************************
1612  *
1613  ***********************************************************************/
1614 int
1615 cleanup()
1616 {
1617     int ind;
1618
1619         if ( remove_files ) {
1620             if ( Debug > 2 )
1621                 printf("%s: %d DEBUG3 Removing all %d files\n", 
1622                     Progname, Pid, num_files);
1623             for(ind=0; ind<=num_files; ind++) {
1624                 unlink(filenames+(ind*PATH_MAX));
1625             }
1626         }
1627         if ( using_random && Debug > 1 )
1628             printf("%s%s: %d DEBUG2 Used random seed: %d\n",
1629                 Progname, TagName, Pid, Seed);
1630         return 0;
1631 }
1632
1633 /***********************************************************************
1634  *
1635  ***********************************************************************/
1636 void
1637 usage()
1638 {
1639         fprintf(stderr,
1640         "Usage: %s%s [-bhEluy][[-g grow_incr][-i num][-t trunc_incr][-T trunc_inter]\n",
1641         Progname, TagName );
1642         fprintf(stderr,
1643         "[-d auto_dir][-e maxerrs][-f auto_file][-N num_files][-w][-c chk_inter][-D debug]\n");
1644         fprintf(stderr,
1645         "[-s seed][-S seq_auto_files][-p][-P PANIC][-I io_type][-o open_flags][-B maxbytes]\n");
1646         fprintf(stderr,
1647         "[-r iosizes][-R lseeks][-U unlk_inter][-W tagname] [files]\n");
1648
1649         return;
1650
1651 }       /* end of usage */
1652
1653 /***********************************************************************
1654  *
1655  ***********************************************************************/
1656 void
1657 help()
1658 {
1659         usage();
1660
1661 fprintf(stdout, "\
1662   -h             Specfied to print this help and exit.\n\
1663   -b             Specfied to execute in sync mode.(def async mode)\n\
1664   -B maxbytes    Max bytes to consume by all files.  growfiles exits when more\n\
1665                  than maxbytes have been consumed. (def no chk)  If maxbytes ends\n\
1666                  with the letter 'b', maxbytes is multiplied by BSIZE\n\
1667   -C write_chk   Specifies how often to check the last write (default 1)\n\
1668   -c file_chk    Specifies how often to check whole file (default 0)\n\
1669   -d auto_dir    Specifies the directory to auto created files. (default .)\n\
1670   -D debug_lvl   Specifies the debug level (default 1)\n\
1671   -E             Print examples and exit\n\
1672   -e errs        The number errors that will terminate this program (def 100)\n\
1673   -f auto_file   Specifies the base filename files created. (default \"gf\")\n\
1674   -g grow_incr   Specfied to grow by incr for each num. (default 4096)\n\
1675                  grow_incr may end in b for blocks\n\
1676                  If -r option is used, this option is ignored and size is random\n\
1677   -H delay       Amount of time to delay between each file (default 0.0)\n\
1678   -I io_type Specifies io type: s - sync, p - polled async, a - async (def s)\n\
1679                  l - listio sync, L - listio async, r - random\n\
1680   -i iteration   Specfied to grow each file num times. 0 means forever (default 1)\n\
1681   -l             Specfied to do file locking around write/read/trunc\n\
1682                  If specified twice, file locking after open to just before close\n\
1683   -L time        Specfied to exit after time secs, must be used with -i.\n\
1684   -N num_files   Specifies the number of files to be created.\n\
1685                  The default is zero if cmd line files.\n\
1686                  The default is one if no cmd line files.\n\
1687   -n num_procs   Specifies the number of copies of this cmd.\n\
1688   -o op_type     Specifies open flages: (def O_RDWR,O_CREAT) op_type can be 'random'\n\
1689   -O offset      adjust i/o buffer alignment by offset bytes\n\
1690   -P PANIC       Specifies to call upanic on error.\n\
1691   -p             Specifies to pre-allocate space\n\
1692   -q pattern     pattern can be a - ascii, p - pid with boff, o boff (def)\n\
1693                  A - Alternating bits, r - random, O - all ones, z - all zeros,\n\
1694                  c - checkboard, C - counting\n\
1695   -R [min-]max   random lseek before write and trunc, max of -1 means filesz,\n\
1696                  -2 means filesz+grow, -3 filesz-grow. (min def is 0)\n\
1697   -r [min-]max   random io write size (min def is 1)\n\
1698   -S seq_auto_files Specifies the number of seqental auto files (default 0)\n\
1699   -s seed[,seed...] Specifies the random number seed (default time(0)+pid)\n\
1700   -t trunc_incr  Specfied the amount to shrink file. (default 4096)\n\
1701                  trunc_inter may end in b for blocks\n\
1702                  If -R option is used, this option is ignored and trunc is random\n\
1703   -T trunc_inter Specfied the how many grows happen before shrink. (default 0)\n\
1704   -u             unlink files before exit\n\
1705   -U ui[-ui2]    Unlink files each ui iteration (def 0)\n\
1706   -w             Specfied to grow via lseek instead of writes.\n\
1707   -W tag-name    Who-am-i.  My Monster tag name.  (used by Monster).\n\
1708   -x             Re-exec children before continuing - useful on MPP systems\n\
1709   -y             Attempt to sync copies - if one fails it will send sigusr2 to others\n\
1710   Action to each file every iteration is open, write, write check\n\
1711   file check, trunc and closed.\n");
1712
1713         return;
1714 }
1715
1716 /***********************************************************************
1717  *
1718  ***********************************************************************/
1719 void
1720 prt_examples(FILE *stream)
1721 {
1722         /* This example creates 200 files in directory dir1.  It writes */
1723         /* 4090 bytes 100 times then truncates 408990 bytes off the file */
1724         /* The file contents are checked every 1000 grow. */
1725     fprintf(stream,
1726          "# run forever: writes of 4090 bytes then on every 100 iterval\n\
1727 # truncate file by 408990 bytes.  Done to 200 files in dir1.\n\
1728 %s -i 0 -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -d dir1 -S 200\n\n", Progname);
1729
1730         /* same as above with 5000 byte grow and a 499990 byte tuncate */
1731     fprintf(stream,
1732          "# same as above with writes of 5000 bytes and truncs of 499990\n\
1733 %s -i 0 -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -d dir2 -S 200\n\n", Progname);
1734
1735         /* This example beats on opens and closes */
1736     fprintf(stream,
1737          "# runs forever: beats on opens and closes of file ocfile - no io\n\
1738 %s -i 0 -g 0 -c 0 -C 0 ocfile\n\n", Progname);
1739
1740     fprintf(stream,
1741          "# writes 4096 to files until 50 blocks are written\n\
1742 %s -i 0 -g 4096 -B 50b file1 file2\n\n", Progname);
1743         
1744     fprintf(stream,
1745          "# write one byte to 750 files in gdir then unlinks them\n\
1746 %s -g 1 -C 0 -d gdir -u -S 750\n\n", Progname);
1747
1748     fprintf(stream,
1749         "# run 30 secs: random iosize, random lseek up to eof\n\
1750 %s -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 g_rand1 g_rand2\n\n", Progname);
1751
1752     fprintf(stream,
1753         "# run 30 secs: grow by lseek then write single byte, trunc every 10 itervals\n\
1754 %s -g 5000 -wlu -i 0 -L 30 -C 1 -T 10  g_sleek1 g_lseek2\n\n", Progname);
1755
1756     fprintf(stream, 
1757         "# run forever: 5 copies of random iosize, random lseek to beyond eof,\n\
1758 # rand io types doing a trunc every 5 iterations, with unlinks.\n\
1759 %s -i0 -r 1-50000 -R 0--2 -I r -C1 -l -n5 -u -U 100-200 gf_rana gf_ranb\n\n", 
1760             Progname);
1761
1762     fprintf(stream, 
1763         "# run forever: 5 copies of random iosize, random lseek to beyond eof,\n\
1764 # random open flags, rand io types doing a trunc every 10 iterations.\n\
1765 %s -i0 -r 1-50000 -R 0--2 -o random -I r -C0 -l -T 20 -uU100-200 -n 5 gf_rand1 gf_rand2\n", 
1766             Progname);
1767
1768
1769         return;
1770 }
1771
1772 /***********************************************************************
1773  *
1774  * The file descriptor current offset is assumed to be the end of the
1775  * file.  
1776  * Woffset will be set to the offset before the write.
1777  * Grow_incr will be set to the size of the write or lseek write.
1778  ***********************************************************************/
1779 int
1780 growfile(fd, file, grow_incr, buf)
1781 int fd;
1782 char *file;
1783 int grow_incr;
1784 unsigned char *buf;
1785 {
1786    int noffset;
1787    int ret;
1788    /* REFERENCED */
1789    int cur_offset;
1790    char *errmsg;
1791    int fsize;           /* current size of file */
1792    int size_grew;       /* size the file grew */
1793    struct stat stbuf;
1794    int tmp = 0;
1795
1796         /*
1797          * Do a stat on the open file.
1798          * If the file is a fifo, set the bit in Mode variable.
1799          * This fifo check must be done prior to growfile() returning.
1800          * Also get the current size of the file.
1801          */
1802         if ( fstat(fd, &stbuf) != -1 ) {
1803             if ( S_ISFIFO(stbuf.st_mode) ) {
1804                 Fileinfo.mode |= MODE_FIFO;
1805                 Mode |= MODE_FIFO;
1806                 if ( Debug > 3 )
1807                     printf("%s: %d DEBUG4 %s/%d: file is a fifo - no lseek or truncs,\n",
1808                         Progname, Pid, __FILE__, __LINE__);
1809             }
1810             fsize = stbuf.st_size;
1811
1812         } else {
1813             fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
1814                 Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
1815
1816             return -1;
1817         }
1818
1819
1820         if ( grow_incr <= 0 ) {   /* don't attempt i/o if grow_incr <= 0 */ 
1821
1822             Grow_incr=grow_incr;
1823             if ( Debug > 2 )
1824                 printf("%s: %d DEBUG3 %s/%d: Not attempting to grow, growsize == %d\n",
1825                     Progname, Pid, __FILE__, __LINE__, grow_incr);
1826             return grow_incr;
1827         }
1828
1829         if ( Mode & MODE_RAND_SIZE ) {
1830             grow_incr=random_range(min_size, max_size, mult_size, &errmsg);
1831             if (errmsg != NULL) {
1832                 fprintf(stderr, "%s%s: %d %s/%d: random_range() failed - %s\n", Progname, TagName, Pid, __FILE__, __LINE__, errmsg);
1833                 return -1;
1834             }
1835             Grow_incr=grow_incr;
1836         }
1837         else
1838             Grow_incr=grow_incr;
1839
1840         if ( ! (Mode & MODE_FIFO) ) {
1841             if ((cur_offset=lseek(fd,0,SEEK_CUR)) == -1 ) {
1842                 fprintf(stderr, "%s%s: %d %s/%d: tell failed: %s\n",
1843                     Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
1844                 return -1;
1845             }
1846         }
1847
1848         if ( Mode & MODE_GROW_BY_LSEEK ) {
1849                 Woffset=fsize;
1850                 if ( Debug > 2 ) {
1851                     printf("%s: %d DEBUG3 %s/%d: Current size of file is %d\n", Progname,
1852                         Pid, __FILE__, __LINE__, Woffset);
1853                     printf("%s: %d DEBUG3 %s/%d: lseeking to %d byte with SEEK_END\n", Progname,
1854                         Pid, __FILE__, __LINE__, grow_incr-1);
1855                 }
1856
1857                 if ((noffset=lseek(fd, grow_incr-1, SEEK_END)) == -1 ) {
1858                         fprintf(stderr, "%s%s: %s/%d: lseek(fd, %d, SEEK_END) failed: %s\n",
1859                                 Progname, TagName, __FILE__, __LINE__, grow_incr-1, strerror(errno));
1860                         return -1;
1861                 }
1862
1863                 lkfile(fd, LOCK_EX, LKLVL0);     /* get exclusive lock */
1864                 
1865 #if NEWIO
1866                 ret=lio_write_buffer(fd, io_type, "w", 1, SIGUSR1, &errmsg,0);
1867 #else
1868                 ret=write_buffer(fd, io_type, "w", 1, 0, &errmsg); 
1869 #endif
1870
1871                 if ( ret != 1 ) {
1872                         fprintf(stderr, "%s%s: %d %s/%d: %d %s\n", 
1873                             Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
1874                         if ( ret == -ENOSPC ) {
1875                                 cleanup();
1876                                 exit(2);
1877                         }
1878                 }
1879 /***
1880                 write(fd, "w", 1);
1881 ****/
1882
1883                 lkfile(fd, LOCK_UN, LKLVL0);
1884
1885                 if ( Debug > 2 )
1886                     printf("%s: %d DEBUG3 %s/%d: %d wrote 1 byte to file\n",
1887                             Progname, Pid, __FILE__, __LINE__, Iter_cnt);
1888
1889         } else {  /* end of grow by lseek */
1890
1891                 if ( Fileinfo.openflags & O_APPEND ) {
1892                    /*
1893                     * Deal with special case of the open flag containing O_APPEND.
1894                     * If it does, the current offset does not matter since the write
1895                     * will be done end of the file.
1896                     */
1897                     if ( Debug > 4 )
1898                         printf("%s: %d DEBUG5 %s/%d: dealing with O_APPEND condition\n",
1899                             Progname, Pid, __FILE__, __LINE__ );
1900                     lkfile(fd, LOCK_EX, LKLVL0);         /* get exclusive lock */
1901
1902                     /*
1903                      * do fstat again to get size of the file.
1904                      * This is done inside a file lock (if locks are being used).
1905                      */
1906                     if ( fstat(fd, &stbuf) != -1 ) {
1907                         Woffset = stbuf.st_size;
1908                     } else {
1909                         fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
1910                         Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
1911         
1912                         lkfile(fd, LOCK_UN, LKLVL0);     /* release lock */
1913                         return -1;
1914                     }
1915                     if ( Debug > 2 )
1916                         printf("%s: %d DEBUG3 %s/%d: dealing with O_APPEND condition (offset:fsz:%d)\n",
1917                             Progname, Pid, __FILE__, __LINE__, (int)stbuf.st_size);
1918
1919
1920                 } else if ( Mode & MODE_RAND_LSEEK ) {
1921                    if ( max_lseek == LSK_EOF ) {        /* within file size */
1922                         noffset=random_range(min_lseek, fsize, 1, NULL);
1923                    }            
1924                    else if ( max_lseek == LSK_EOFPLUSGROW ) {   
1925                         /* max to beyond file size */
1926                         noffset=random_range(min_lseek, fsize+grow_incr, 1, NULL);
1927                    }
1928                    else if ( max_lseek == LSK_EOFMINUSGROW ) {  
1929                         /* 
1930                          * Attempt to not grow the file.
1931                          * If the i/o will fit from min_lseek to EOF,
1932                          * pick offset to allow it to fit.
1933                          * Otherwise, pick the min_lseek offset and grow
1934                          * file by smallest amount.
1935                          * If min_lseek is != 0, there will be a problem
1936                          * with whole file checking if file is ever smaller
1937                          * than min_lseek.
1938                          */
1939                         if ( fsize <= min_lseek + grow_incr )
1940                             noffset=min_lseek;  /* file will still grow */
1941                         else
1942                             noffset=random_range(min_lseek, fsize-grow_incr, 1, NULL);
1943                    }
1944                    else {
1945                         noffset=random_range(min_lseek, max_lseek, 1, NULL);
1946                    }
1947
1948                    if ((Woffset=lseek(fd, noffset, SEEK_SET)) == -1 ) {
1949                         fprintf(stderr, "%s%s: %d %s/%d: lseek(%d, %d, SEEK_SET) l2 failed: %s\n",
1950                                 Progname, TagName, Pid, __FILE__, __LINE__, fd, noffset, strerror(errno));
1951                         return -1;
1952                    }
1953                    else if ( Debug > 2 )
1954                         printf("%s: %d DEBUG3 %s/%d: lseeked to random offset %d (fsz:%d)\n",
1955                             Progname, Pid, __FILE__, __LINE__, Woffset,
1956                             (int)stbuf.st_size);
1957
1958                 }
1959
1960                 /*
1961                  * lseek to end of file only if not fifo
1962                  */
1963                 else if ( ! (Mode & MODE_FIFO) ) {
1964                     if ((Woffset=lseek(fd, 0, SEEK_END)) == -1 ) {
1965                         fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, 0, SEEK_END) failed: %s\n",
1966                                 Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
1967                         return -1;
1968                     }
1969                     else if ( Debug > 2 )
1970                         printf("%s: %d DEBUG3 %s/%d: lseeked to end of file, offset %d\n",
1971                             Progname, Pid, __FILE__, __LINE__, Woffset);
1972                 }
1973
1974                 if ( Pattern == PATTERN_OFFSET )
1975                     datapidgen(STATIC_NUM, buf, grow_incr, Woffset);
1976                 else if ( Pattern == PATTERN_PID )
1977                     datapidgen(Pid, buf, grow_incr, Woffset);
1978                 else if ( Pattern == PATTERN_ASCII )
1979                     dataasciigen(NULL, (char *)buf, grow_incr, Woffset);
1980                 else if ( Pattern == PATTERN_RANDOM )
1981                     databingen('r', buf, grow_incr, Woffset);
1982                 else if ( Pattern == PATTERN_ALT )
1983                     databingen('a', buf, grow_incr, Woffset);
1984                 else if ( Pattern == PATTERN_CHKER )
1985                     databingen('c', buf, grow_incr, Woffset);
1986                 else if ( Pattern == PATTERN_CNTING )
1987                     databingen('C', buf, grow_incr, Woffset);
1988                 else if ( Pattern == PATTERN_ZEROS )
1989                     databingen('z', buf, grow_incr, Woffset);
1990                 else if ( Pattern == PATTERN_ONES )
1991                     databingen('o', buf, grow_incr, Woffset);
1992                 else
1993                     dataasciigen(NULL, (char *)buf, grow_incr, Woffset);
1994
1995                 if ( Debug > 2 )
1996                     printf("%s: %d DEBUG3 %s/%d: attempting to write %d bytes\n",
1997                         Progname, Pid, __FILE__, __LINE__, grow_incr);
1998
1999                 lkfile(fd, LOCK_EX, LKLVL0);     /* get exclusive lock */
2000
2001 /*****
2002                 ret=write(fd, buf, grow_incr);
2003
2004                 tmp=tell(fd);
2005
2006                 lkfile(fd, LOCK_UN, LKLVL0);    
2007
2008                 if ( ret != grow_incr) {
2009                         fprintf(stderr, "%s: %s/%d: write failed: %s\n",
2010                                 Progname, __FILE__, __LINE__, strerror(errno));
2011                         return -1;
2012                 }
2013 *****/
2014
2015 #if NEWIO
2016                 ret=lio_write_buffer(fd, io_type, (char *)buf, grow_incr,
2017                          SIGUSR1, &errmsg,0);
2018 #else
2019                 ret=write_buffer(fd, io_type, buf, grow_incr, 0, &errmsg);
2020 #endif
2021
2022                 if( Mode & MODE_FIFO ){
2023                         /* If it is a fifo then just pretend the file
2024                          * offset is where we think it should be.
2025                          */
2026                         tmp = Woffset + grow_incr;
2027                 }
2028                 else{
2029                         if( (tmp=lseek(fd,0,SEEK_CUR)) < 0 ){ /* get offset after the write */
2030                                 fprintf(stderr, "%s%s: %s/%d: tell(2) failed: %d  %s\n",
2031                                         Progname, TagName, __FILE__, __LINE__, errno, strerror(errno) );
2032                                 return -1;
2033                         }
2034 #if NEWIO
2035 #ifdef sgi
2036                         /* If this is POSIX I/O and it is via aio_{read,write}
2037                          * or lio_listio then after completion of the I/O the
2038                          * value of the file offset for the file is
2039                          * unspecified--which means we cannot trust what
2040                          * tell() told us.  Fudge it here.
2041                          */
2042                         if( (io_type & LIO_IO_ASYNC_TYPES) || (io_type & LIO_RANDOM) ){
2043                                 if( tmp != Woffset + grow_incr ){
2044                                         if( Debug > 5 ){
2045                                                 printf("%s: %d DEBUG6 %s/%d: posix fudge, forcing tmp (%d) to match Woffset+grow_incr (%d)\n",
2046                                                        Progname, Pid, __FILE__, __LINE__, tmp, Woffset+grow_incr);
2047                                         }
2048                                         tmp = Woffset + grow_incr;
2049                                 }
2050                         }
2051 #endif
2052 #endif
2053                 }
2054
2055                 lkfile(fd, LOCK_UN, LKLVL0);    
2056
2057                 if ( ret != grow_incr ) {
2058                         fprintf(stderr, "%s%s: %d %s/%d: %d %s\n", 
2059                             Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
2060                         if ( ret == -ENOSPC ) {
2061                                 cleanup();
2062                                 exit(2);
2063                         }
2064                         return -1;
2065                 }
2066
2067                 /*
2068                  * Check for a condition where the file was truncated just before
2069                  * the write. 
2070                  */
2071                 if ( tmp != Woffset + grow_incr) {
2072                     /*
2073                      * The offset after the write was not as expected.
2074                      * This could be caused by the following:
2075                      *  - file truncated after the lseek and before the write.
2076                      *  - the file was written to after fstat and before the write
2077                      *    and the file was opened with O_APPEND.
2078                      *
2079                      * The pattern written to the file will be considered corrupted.
2080                      */
2081                     if ( Debug > 0 && lockfile ) {
2082                         printf("%s%s: %d DEBUG1 %s/%d: offset after write(%d) not as exp(%d+%d=%d)\n",  
2083                             Progname, TagName, Pid, __FILE__, __LINE__, tmp, Woffset, grow_incr, Woffset+grow_incr);
2084                         printf("%s%s: %d DEBUG1 %s/%d: %d Assuming file changed by another process, resetting offset:%d (expect pattern mismatch)\n",
2085                                 Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, tmp-grow_incr);
2086                     }
2087                     if( Debug > 4 ){
2088                         printf("%s: %d DEBUG5 %s/%d: about to chop Woffset.  tmp=%d, grow_incr=%d, Woffset was %d\n",
2089                                Progname, Pid, __FILE__, __LINE__, tmp, grow_incr, Woffset);
2090                     }
2091                     Woffset=tmp-grow_incr;
2092                     if( Woffset < 0 )
2093                         Woffset = 0;
2094                 }
2095
2096         }  /* end of grow by write */
2097
2098
2099         /*
2100          * Woffset - holds start of grow (start of write expect in grow by lseek)
2101          * Grow_incr - holds size of grow (write).
2102          * fsize - holds size of file before write
2103          */
2104         size_grew=(Woffset + Grow_incr) - fsize;
2105         if ( Debug > 1) {
2106              if ( Mode & MODE_FIFO ) {
2107                 printf("%s: %d DEBUG2 %s/%d: file is fifo, %d wrote %d bytes\n",
2108                     Progname, Pid, __FILE__, __LINE__, Grow_incr, Iter_cnt);
2109              }
2110
2111              else if ( size_grew > 0 )
2112                 printf("%s: %d DEBUG2 %s/%d: %d wrote %d bytes(off:%d), grew file by %d bytes\n",
2113                         Progname, Pid, __FILE__, __LINE__, Iter_cnt, Grow_incr, Woffset, size_grew);
2114              else
2115                 printf("%s: %d DEBUG2 %s/%d: %d wrote %d bytes(off:%d), did not grow file\n",
2116                         Progname, Pid, __FILE__, __LINE__, Iter_cnt, Grow_incr, Woffset);
2117         }
2118
2119         bytes_consumed += size_grew;
2120         return 0;
2121
2122 }       /* end of growfile */
2123
2124 /***********************************************************************
2125  * shrinkfile file by trunc_incr.  file can not be made smaller than
2126  * size zero.  Therefore, if trunc_incr is larger than file size,
2127  * file will be truncated to zero.
2128  * The file descriptor current offset is assumed to be the end of the
2129  * file.
2130  *
2131  ***********************************************************************/
2132 int
2133 shrinkfile(fd, filename, trunc_incr, trunc_inter, just_trunc)
2134 int fd;
2135 char *filename;
2136 int trunc_incr;
2137 int trunc_inter;        /* interval */
2138 int just_trunc;         /* lseek has already been done for you */
2139 {
2140     static int shrink_cnt = 0;
2141     int cur_offset;
2142     int new_offset;
2143     int ret;
2144 #ifdef CRAY
2145     int offset;
2146 #endif
2147
2148         shrink_cnt++;
2149
2150         if ( trunc_inter == 0 || (shrink_cnt % trunc_inter != 0))  {
2151             if ( Debug > 3 )
2152                 printf("%s: %d DEBUG4 %s/%d: Not shrinking file - not time, iter=%d, cnt=%d\n",
2153                     Progname, Pid, __FILE__, __LINE__, trunc_inter, shrink_cnt);
2154             return 0;   /* not this time */
2155         }
2156
2157         if ( Mode & MODE_FIFO ) {
2158             if ( Debug > 5 )
2159                 printf("%s: %d DEBUG5 %s/%d: Not attempting to shrink a FIFO\n",
2160                     Progname, Pid, __FILE__, __LINE__);
2161             return 0;   /* can not truncate fifo */
2162         }
2163
2164         lkfile(fd, LOCK_EX, LKLVL0);
2165
2166         if ((cur_offset=lseek(fd,0,SEEK_CUR)) == -1 ) {
2167             fprintf(stderr, "%s%s: %d %s/%d: tell(%d) failed: %s\n",
2168                 Progname, TagName, Pid, __FILE__, __LINE__, fd, strerror(errno));
2169             lkfile(fd, LOCK_UN, LKLVL0);
2170             return -1;
2171         }
2172
2173         if ( Mode & MODE_RAND_LSEEK ) {
2174             if ( max_lseek <= -1 ) {
2175                 if ( (new_offset=file_size(fd)) == -1 ) {
2176                     lkfile(fd, LOCK_UN, LKLVL0);
2177                     return -1;
2178                 }
2179                         
2180                 if ( new_offset < min_lseek )
2181                     new_offset=min_lseek;
2182                 else
2183                     new_offset=random_range(min_lseek, new_offset, 1, NULL);
2184             }
2185             else {
2186                 new_offset=random_range(min_lseek, max_lseek, 1, NULL);
2187             }
2188
2189 #ifdef CRAY
2190             if ((offset=lseek(fd, new_offset, SEEK_SET)) == -1 ) {
2191                 fprintf(stderr, "%s%s: %d %s/%d: lseek(%d, %d, SEEK_SET) l3 failed: %s\n",
2192                     Progname, TagName, Pid, __FILE__, __LINE__, fd, new_offset, strerror(errno));
2193                 lkfile(fd, LOCK_UN, LKLVL0);
2194                 return -1;
2195             }
2196             else if ( Debug > 3 )
2197                 printf("%s: %d DEBUG4 %s/%d: lseeked to random offset %d\n",
2198                     Progname, Pid, __FILE__, __LINE__, offset);
2199     
2200 #endif
2201         }
2202
2203         else {  /* remove trunc_incr from file */
2204
2205             new_offset = cur_offset-trunc_incr;
2206
2207             if ( new_offset < 0 )
2208                 new_offset=0;
2209         
2210 #ifdef CRAY
2211             if (  lseek(fd, new_offset, SEEK_SET) == -1 ) {
2212                 fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, %d, SEEK_SET) l4 failed: %s\n",
2213                         Progname, TagName, Pid, __FILE__, __LINE__, new_offset, strerror(errno));
2214                 lkfile(fd, LOCK_UN, LKLVL0);
2215                 return -1;
2216             }
2217             else if ( Debug > 3 )
2218                 printf("%s: %d DEBUG4 %s/%d: lseeked to offset %d, %d bytes from end\n",
2219                     Progname, Pid, __FILE__, __LINE__, new_offset, trunc_incr);
2220 #endif
2221         }
2222
2223
2224 #ifdef CRAY
2225         ret=trunc(fd);
2226 #else
2227         ret=ftruncate(fd, new_offset );
2228         if( (ret == 0) && (Debug > 3) ){
2229                 printf("%s: %d DEBUG4 %s/%d: ftruncated to offset %d, %d bytes from end\n",
2230                     Progname, Pid, __FILE__, __LINE__, new_offset, trunc_incr);
2231         }
2232 #endif
2233
2234         lkfile(fd, LOCK_UN, LKLVL0);
2235
2236         if ( ret == -1 ) {
2237 #ifdef CRAY
2238                 fprintf(stderr, "%s%s: %d %s/%d: trunc failed: %s\n",
2239                         Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
2240 #else
2241                 fprintf(stderr, "%s%s: %d %s/%d: ftruncate failed: %s\n",
2242                         Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
2243 #endif
2244                 return -1;
2245         }
2246
2247         if ( Debug > 2 ) {
2248             printf("%s: %d DEBUG2 %s/%d: trunc file by %d bytes, to size of = %d bytes\n",
2249                 Progname, Pid, __FILE__, __LINE__, cur_offset-new_offset, new_offset);
2250         }
2251         
2252
2253         bytes_consumed -= (cur_offset - new_offset);
2254         return 0;
2255
2256 }       /* end of shrinkfile */
2257
2258 /***********************************************************************
2259  *
2260  ***********************************************************************/
2261 int
2262 check_write(fd, cf_inter, filename, mode)
2263 int fd;
2264 int cf_inter;   /* check file interval */
2265 char *filename; /* needed for error messages */
2266 int mode;       /* write mode */
2267 {
2268     int fsize;
2269     static int cf_count = 0;
2270     int ret = 0;
2271     int tmp;
2272     char *errmsg;
2273     char *ptr;
2274
2275     cf_count++;
2276
2277     if ( cf_inter == 0 || (cf_count % cf_inter != 0)) {
2278         if ( Debug > 4 )
2279             printf("%s: %d DEBUG5 %s/%d: no write check, not time iter=%d, cnt=%d\n",
2280                 Progname, Pid, __FILE__, __LINE__, cf_inter, cf_count);
2281         return 0;        /* no check done */
2282     }
2283
2284     if ( Grow_incr <= 0 ) {
2285         if ( Debug > 3 )
2286             printf("%s: %d DEBUG4 %s/%d: No write validation,  Grow_incr = %d, offset = %d\n",
2287                 Progname, Pid, __FILE__, __LINE__, Grow_incr, Woffset);
2288         return 0;       /* no check */
2289     }
2290
2291
2292     
2293     /*  
2294      * Get the shared file lock.  We need to hold the lock from before
2295      * we do the stat until after the read.
2296      */
2297     lkfile(fd, LOCK_SH, LKLVL0);
2298
2299     if ((fsize=file_size(fd)) == -1 )  {
2300         lkfile(fd, LOCK_UN, LKLVL0);
2301         return -1;
2302
2303     } else if ( fsize <= Woffset ) {
2304         /*
2305          * The file was truncated between write and now.
2306          * The contents of our last write is totally gone, no check.
2307          */
2308         if ( Debug > 1 )
2309             printf("%s%s: %d DEBUG2 %s/%d: %d File size (%d) smaller than where last wrote (%d)- no write validation\n",
2310                 Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, fsize, Woffset);
2311         lkfile(fd, LOCK_UN, LKLVL0);
2312         return 0;       /* no validation, but not an error */
2313  
2314     } else if ( fsize < (Woffset + Grow_incr)) {
2315         /*
2316          * The file was truncated between write and now.
2317          * Part of our last write has been truncated, adjust our Grow_incr
2318          * to reflect this.
2319          */
2320
2321         tmp=Grow_incr;
2322         Grow_incr=fsize-Woffset;
2323
2324         if ( Debug > 1 )  {
2325
2326             printf("%s%s: %d DEBUG2 %s/%d: %d fsz:%d, lost(%d)of wrt(off:%d, sz:%d), adj=%d\n",
2327             Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, fsize, tmp-Grow_incr, Woffset, tmp, Grow_incr);
2328         }
2329
2330     }
2331
2332     if ( Debug > 2 )
2333         printf("%s: %d DEBUG3 %s/%d: about to do write validation, offset = %d, size = %d\n",
2334             Progname, Pid, __FILE__, __LINE__, Woffset, Grow_incr);
2335
2336     if ( ! (mode & MODE_FIFO)  ) {
2337
2338         if ( lseek(fd, Woffset, 0) == -1 ) {
2339             fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, %d, 0) failed: %s\n",
2340                 Progname, TagName, Pid, __FILE__, __LINE__, Woffset, strerror(errno));
2341         }
2342         if ( Debug > 3 )
2343             printf("%s: %d DEBUG4 %s/%d: lseeked to offset:%d\n",
2344                 Progname, Pid, __FILE__, __LINE__, Woffset);
2345     }
2346
2347     /*
2348      * Read last writes data
2349      */
2350 #if NEWIO
2351     ret=lio_read_buffer(fd, io_type, Buffer, Grow_incr, SIGUSR1, &errmsg,0);
2352 #else
2353     ret=read_buffer(fd, io_type, Buffer, Grow_incr, 0, &errmsg);
2354 #endif
2355
2356     /*
2357      * report the error and debug information before releasing
2358      * the file lock
2359      */
2360     if ( ret != Grow_incr ) {
2361         fprintf(stderr, "%s%s: %d %s/%d: %d CW %s\n", Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
2362         {
2363             struct stat stbuf;
2364             fstat(fd, &stbuf);
2365             if ( Debug > 2 )
2366                 printf("%s%s: %d DEBUG3 %s/%d: fd:%d, offset:%d, fsize:%d, openflags:%#o\n",
2367                     Progname, TagName, Pid, __FILE__, __LINE__, fd,
2368                     (int)lseek(fd,SEEK_CUR,0),  /* FIXME: 64bit/LFS ? */
2369                     (int)stbuf.st_size,
2370                     Fileinfo.openflags);
2371         }
2372
2373         lkfile(fd, LOCK_UN, LKLVL0);
2374         return 1;
2375     }
2376
2377
2378     lkfile(fd, LOCK_UN, LKLVL0);
2379
2380     if ( Mode & MODE_GROW_BY_LSEEK ) {
2381         /* check that all zeros upto last character */
2382         for(ptr=Buffer; ptr < (Buffer+Grow_incr-1); ptr++) {
2383             if ( *ptr != '\0' ) {
2384                 fprintf(stderr,
2385                     "%s%s: %d %s/%d: data mismatch at offset %d, exp:%#o(zerofilled), act:%#o in file %s\n",
2386                     Progname, TagName, Pid, __FILE__, __LINE__, 
2387                     (int)(Woffset+(Grow_incr-(Buffer-ptr))),
2388                     0, *ptr, filename);
2389                 fflush(stderr);
2390                 return 1;
2391             }
2392         }
2393         /* check that the last char is a 'w' */
2394         if ( *ptr != 'w' ) {
2395             fprintf(stderr,
2396           "%s%s: %d %s/%d: data mismatch at offset %d, exp:%#o(zerofilled), act:%#o in file %s\n",
2397                 Progname, TagName, Pid, __FILE__, __LINE__, 
2398                 (int)(Woffset+(Grow_incr-(Buffer-ptr))), 'w',
2399                 *ptr, filename);
2400             fflush(stderr);
2401             return 1;
2402         }
2403         return 0;   /* all is well */
2404         
2405     }
2406     else if ( Pattern == PATTERN_OFFSET )
2407         ret=datapidchk(STATIC_NUM, Buffer, Grow_incr, Woffset, &errmsg);
2408     else if ( Pattern == PATTERN_PID )
2409         ret=datapidchk(Pid, Buffer, Grow_incr, Woffset, &errmsg);
2410     else if ( Pattern == PATTERN_ASCII )
2411         ret=dataasciichk(NULL, Buffer, Grow_incr, Woffset, &errmsg);
2412     else if ( Pattern == PATTERN_RANDOM )
2413         ;       /* no check for random */
2414     else if ( Pattern == PATTERN_ALT )
2415         ret=databinchk('a', Buffer, Grow_incr, Woffset, &errmsg);
2416     else if ( Pattern == PATTERN_CHKER )
2417         ret=databinchk('c', Buffer, Grow_incr, Woffset, &errmsg);
2418     else if ( Pattern == PATTERN_CNTING )
2419         ret=databinchk('C', Buffer, Grow_incr, Woffset, &errmsg);
2420     else if ( Pattern == PATTERN_ZEROS )
2421         ret=databinchk('z', Buffer, Grow_incr, Woffset, &errmsg);
2422     else if ( Pattern == PATTERN_ONES )
2423         ret=databinchk('o', Buffer, Grow_incr, Woffset, &errmsg);
2424     else
2425         ret=dataasciichk(NULL, Buffer, Grow_incr, Woffset, &errmsg);
2426
2427     if ( ret >= 0 ) {
2428         fprintf(stderr, "%s%s: %d %s/%d: %d CW %s in file %s\n",
2429                 Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
2430
2431         if ( Debug > 0 )
2432             printf("%s%s: %d DEBUG1 %s/%d: **fd:%d, lk:%d, offset:%d, sz:%d open flags:%#o %s\n",
2433                 Progname, TagName, Pid, __FILE__, __LINE__, fd, lockfile, 
2434                 Woffset, Grow_incr, Fileinfo.openflags, openflags2symbols(Fileinfo.openflags, ",", NULL));
2435
2436         fflush(stderr);
2437         return 1;
2438     }
2439
2440     if ( Debug > 6 )
2441         printf("%s: %d DEBUG7 %s/%d: No corruption detected on write validation , offset = %d, size = %d\n",
2442             Progname, Pid, __FILE__, __LINE__, Woffset, Grow_incr);
2443
2444     return 0;   /* all is well */
2445 }
2446
2447
2448
2449 /***********************************************************************
2450  *
2451  ***********************************************************************/
2452 int
2453 check_file(fd, cf_inter, filename, no_file_check)
2454 int fd;
2455 int cf_inter;   /* check file interval */
2456 char *filename; /* needed for error messages */
2457 int no_file_check;      /* if set, do not do file content check */
2458 {
2459     int fsize;
2460     static int cf_count = 0;
2461     char *buf;
2462     int ret;
2463     int ret_val = 0;
2464     int rd_cnt;
2465     int rd_size;
2466     char *errmsg;
2467
2468         cf_count++;
2469
2470         if ( cf_inter == 0 || (cf_count % cf_inter != 0)) {
2471                 if ( Debug > 4 )
2472                     printf("%s: %d DEBUG5 %s/%d: No file check - not time, iter=%d, cnt=%d\n",
2473                         Progname, Pid, __FILE__, __LINE__, cf_inter, cf_count);
2474                 return 0;        /* no check done */
2475         }
2476
2477         /*
2478          * if we can't determine file content, don't bother checking
2479          */
2480         if ( no_file_check ) {
2481                 if ( Debug > 4 )
2482                     printf("%s: %d DEBUG5 %s/%d: No file check, lseek grow or random lseeks\n",
2483                         Progname, Pid, __FILE__, __LINE__);
2484                 return 0;
2485         }
2486
2487         /*
2488          * Lock the file.  We need to have the file lock before
2489          * the stat and until after the last read to prevent
2490          * a trunc/truncate from "corrupting" our data.
2491          */
2492         lkfile(fd, LOCK_SH, LKLVL0);
2493         
2494         if ((fsize=file_size(fd)) == -1 )  {
2495             lkfile(fd, LOCK_UN, LKLVL0);
2496             return -1;
2497         }
2498
2499         if ( fsize == 0 ) {
2500             if ( Debug > 2 )
2501             printf("%s: %d DEBUG3 %s/%d: No file validation, file size == 0\n",
2502                 Progname, Pid, __FILE__, __LINE__);
2503
2504             lkfile(fd, LOCK_UN, LKLVL0);
2505             return 0;
2506         }
2507
2508         if ( Debug > 2 )
2509             printf("%s: %d DEBUG3 %s/%d: about to do file validation\n",
2510                 Progname, Pid, __FILE__, __LINE__);
2511
2512         if ( fsize > MAX_FC_READ ) {
2513             /*
2514              * read the file in MAX_FC_READ chuncks.
2515              */
2516
2517             if ((buf=(char *)malloc(MAX_FC_READ)) == NULL ) {
2518                 fprintf(stderr, "%s%s: %s/%d: malloc(%d) failed: %s\n", Progname, TagName,
2519                     __FILE__, __LINE__, MAX_FC_READ, strerror(errno));
2520                lkfile(fd, LOCK_UN, LKLVL0);
2521                return -1;
2522             }
2523
2524             lseek(fd, 0, SEEK_SET);
2525
2526             lkfile(fd, LOCK_SH, LKLVL0);  /* get lock on file before getting file size */
2527
2528             rd_cnt=0;
2529             while (rd_cnt < fsize ) {
2530                 if ( fsize - rd_cnt > MAX_FC_READ )
2531                     rd_size=MAX_FC_READ;
2532                 else
2533                     rd_size=fsize - rd_cnt;
2534                                 
2535 #if NEWIO
2536                 ret=lio_read_buffer(fd, io_type, buf, rd_size,
2537                     SIGUSR1, &errmsg,0);
2538 #else
2539                 ret=read_buffer(fd, io_type, buf, rd_size, 0, &errmsg);
2540 #endif
2541
2542                 if (ret != rd_size ) {
2543                     fprintf(stderr, "%s%s: %d %s/%d: %d CFa %s\n", 
2544                         Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
2545                     free(buf);
2546                     lkfile(fd, LOCK_UN, LKLVL0);
2547                     return -1;
2548                 }
2549 /**
2550                 read(fd, buf, rd_size);
2551 ***/
2552
2553                 if ( Pattern == PATTERN_OFFSET )
2554                     ret=datapidchk(STATIC_NUM, buf, rd_size, rd_cnt, &errmsg);
2555                 else if ( Pattern == PATTERN_PID )
2556                     ret=datapidchk(Pid, buf, rd_size, rd_cnt, &errmsg);
2557                 else if ( Pattern == PATTERN_ASCII )
2558                     ret=dataasciichk(NULL, buf, rd_size, rd_cnt, &errmsg);
2559                 else if ( Pattern == PATTERN_RANDOM )
2560                         ;  /* no checks for random */
2561                 else if ( Pattern == PATTERN_ALT )
2562                     ret=databinchk('a', buf, rd_size, rd_cnt, &errmsg);
2563                 else if ( Pattern == PATTERN_CHKER )
2564                     ret=databinchk('c', buf, rd_size, rd_cnt, &errmsg);
2565                 else if ( Pattern == PATTERN_CNTING )
2566                     ret=databinchk('C', buf, rd_size, rd_cnt, &errmsg);
2567                 else if ( Pattern == PATTERN_ZEROS )
2568                     ret=databinchk('z', buf, rd_size, rd_cnt, &errmsg);
2569                 else if ( Pattern == PATTERN_ONES )
2570                     ret=databinchk('o', buf, rd_size, rd_cnt, &errmsg);
2571                 else
2572                     ret=dataasciichk(NULL, buf, rd_size, rd_cnt, &errmsg);
2573                 
2574                     
2575                 if ( ret >= 0 ) {
2576                     fprintf(stderr,
2577                         "%s%s: %d %s/%d: %d CFp %s in file %s\n",
2578                         Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
2579                     fflush(stderr);
2580                     ret_val=1;
2581                     lkfile(fd, LOCK_UN, LKLVL0);
2582                     break;
2583                 }
2584                 rd_cnt += rd_size;
2585             }
2586
2587             lkfile(fd, LOCK_UN, LKLVL0);
2588
2589             free(buf);
2590
2591         }
2592         else {
2593             /*
2594              * Read the whole file in a single read 
2595              */
2596             if((buf=(char *)malloc(fsize)) == NULL ) {
2597                         fprintf(stderr, "%s%s: %s/%d: malloc(%d) failed: %s\n", Progname, TagName,
2598                                 __FILE__, __LINE__, fsize, strerror(errno));
2599                         fflush(stderr);
2600                         return -1;
2601             }
2602
2603             lseek(fd, 0, SEEK_SET);
2604
2605 /****
2606             read(fd, buf, fsize);
2607 ****/
2608 #if NEWIO
2609             ret=lio_read_buffer(fd, io_type, buf, fsize, SIGUSR1, &errmsg,0);
2610 #else
2611             ret=read_buffer(fd, io_type, buf, fsize, 0, &errmsg);
2612 #endif
2613
2614             /* unlock the file as soon as we can */
2615             lkfile(fd, LOCK_UN, LKLVL0);
2616
2617
2618             if ( ret != fsize ) {
2619                 fprintf(stderr, "%s%s: %d %s/%d: %d CFw %s\n", 
2620                     Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
2621                 ret_val=1;
2622             }
2623             else  {
2624                 if ( Pattern == PATTERN_OFFSET )
2625                     ret=datapidchk(STATIC_NUM, buf, fsize, 0, &errmsg);
2626                 else if ( Pattern == PATTERN_PID )
2627                     ret=datapidchk(Pid, buf, fsize, 0, &errmsg);
2628                 else if ( Pattern == PATTERN_ASCII )
2629                     ret=dataasciichk(NULL, buf, fsize, 0, &errmsg);
2630                 else if ( Pattern == PATTERN_RANDOM )
2631                     ;   /* no check for random */
2632                 else if ( Pattern == PATTERN_ALT )
2633                     ret=databinchk('a', buf, fsize, 0, &errmsg);
2634                 else if ( Pattern == PATTERN_CHKER )
2635                     ret=databinchk('c', buf, fsize, 0, &errmsg);
2636                 else if ( Pattern == PATTERN_CNTING )
2637                     ret=databinchk('C', buf, fsize, 0, &errmsg);
2638                 else if ( Pattern == PATTERN_ZEROS )
2639                     ret=databinchk('z', buf, fsize, 0, &errmsg);
2640                 else if ( Pattern == PATTERN_ONES )
2641                     ret=databinchk('o', buf, fsize, 0, &errmsg);
2642                 else
2643                     ret=dataasciichk(NULL, buf, fsize, 0, &errmsg);
2644
2645                 if ( ret >= 0 ) {
2646                     fprintf(stderr, "%s%s: %d %s/%d: %d CFw %s in file %s\n",
2647                         Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
2648                     fflush(stderr);
2649                     ret_val=1;
2650                 }
2651             }
2652             free(buf);
2653         }
2654
2655         return ret_val;
2656
2657 }       /* end of check_file */
2658
2659 /***********************************************************************
2660  *
2661  ***********************************************************************/
2662 int
2663 file_size(int fd)
2664 {
2665     struct stat sb;
2666
2667         if (fstat(fd, &sb) < 0) {
2668             fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
2669                 Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
2670             return -1;
2671         
2672         }
2673
2674         return sb.st_size;
2675 }
2676
2677 /***********************************************************************
2678  *  do file lock/unlock action.
2679  ***********************************************************************/
2680 int
2681 lkfile(int fd, int operation, int lklevel)
2682 {
2683     char *errmsg;
2684
2685     
2686     if ( lockfile == lklevel) {
2687         
2688         if ( Debug > 5 ) {
2689             switch (operation) {
2690             case LOCK_UN:
2691                 printf("%s: %d DEBUG6 %s/%d: Attempting to release lock on fd %d\n", 
2692                     Progname, Pid, __FILE__, __LINE__, fd);
2693                 break;
2694
2695             case LOCK_SH:
2696                 printf("%s: %d DEBUG6 %s/%d: Attempting to get read/shared lock on fd %d\n", 
2697                     Progname, Pid, __FILE__, __LINE__, fd);
2698                 break;
2699
2700             case LOCK_EX:
2701                 printf("%s: %d DEBUG6 %s/%d: Attempting to get write/exclusive lock on fd %d\n", 
2702                     Progname, Pid, __FILE__, __LINE__, fd);
2703                 break;
2704             }
2705         }
2706
2707         /*
2708          * Attempt to get/release desired lock.
2709          * file_lock will attempt to do action over and over again until
2710          * either an unretryable error or the action is completed.
2711          */
2712
2713         if ( file_lock(fd, operation, &errmsg) != 0 ) {
2714             printf("%s%s: %d %s/%d: Unable to perform lock operation. %s\n",
2715                 Progname, TagName, Pid, __FILE__, __LINE__, errmsg);
2716
2717             /* do we count this as an error? handle_error();  */
2718             return -1;
2719         }
2720
2721         if ( Debug > 2 ) {
2722             switch (operation) {
2723             case LOCK_UN:
2724                 printf("%s: %d DEBUG3 %s/%d: Released lock on fd %d\n", 
2725                     Progname, Pid, __FILE__, __LINE__, fd);
2726                 break;
2727
2728             case LOCK_SH:
2729                 printf("%s: %d DEBUG3 %s/%d: Got read/shared lock on fd %d\n", 
2730                     Progname, Pid, __FILE__, __LINE__, fd);
2731                 break;
2732
2733             case LOCK_EX:
2734                 printf("%s: %d DEBUG3 %s/%d: Got write/exclusive lock on fd %d\n", 
2735                     Progname, Pid, __FILE__, __LINE__, fd);
2736                 break;
2737         
2738             default:
2739                 printf("%s: %d DEBUG3 %s/%d: Completed action %d on fd %d\n", 
2740                     Progname, Pid, __FILE__, __LINE__, operation, fd);
2741                 break;
2742             }
2743         }
2744    }
2745
2746    return 0;
2747 }
2748
2749 #ifndef NO_XFS
2750 /***********************************************************************
2751  *
2752  ***********************************************************************/
2753 int
2754 pre_alloc(file, fd, size)
2755 char *file;
2756 int fd;
2757 int size;
2758 {
2759
2760 #ifdef CRAY
2761     long avl;
2762
2763         if ( ialloc(fd, size, IA_CONT, &avl) == -1 ) {
2764                 fprintf(stderr, "%s%s %s/%d: Unable to pre-alloc space: ialloc failed: %d  %s\n",
2765                         Progname, TagName,
2766                         __FILE__, __LINE__, errno, strerror(errno));
2767                 return -1;
2768         }
2769 #endif
2770
2771 #ifndef NO_XFS
2772 #ifdef XFS_IOC_RESVSP
2773     struct xfs_flock64 f;
2774
2775         f.l_whence = 0;
2776         f.l_start = 0;
2777         f.l_len = size;
2778
2779         /* non-zeroing reservation */
2780         if( xfsctl( file, fd, XFS_IOC_RESVSP, &f ) == -1 ){
2781                 fprintf(stderr, "%s%s %s/%d: Unable to pre-alloc space: xfsctl(XFS_IOC_RESVSP) failed: %d  %s\n",
2782                         Progname, TagName,
2783                         __FILE__, __LINE__, errno, strerror(errno));
2784                 return -1;
2785         }
2786 #else
2787     struct flock64 f;
2788
2789         f.l_whence = 0;
2790         f.l_start = 0;
2791         f.l_len = size;
2792
2793         /* non-zeroing reservation */
2794         if( fcntl( fd, F_RESVSP64, &f ) == -1 ){
2795                 fprintf(stderr, "%s%s %s/%d: Unable to pre-alloc space: fcntl(F_RESVSP) failed: %d  %s\n",
2796                         Progname, TagName,
2797                         __FILE__, __LINE__, errno, strerror(errno));
2798                 return -1;
2799         }
2800 #endif
2801 #endif
2802
2803         return 0;
2804 }
2805 #endif