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