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