blob: 7ac44aba0bede0f5e0ddf7ee8c47c46b0fd47bf3 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000 Silicon Graphics, Inc.
* All Rights Reserved.
*/
/*
* This program will grow a list of files.
* Each file will grow by grow_incr before the same
* file grows twice. Each file is open and closed before next file is opened.
*
* To just verify file contents: growfiles -g 0 -c 1 filename
*
* See help and prt_examples functions below.
*
* Basic code layout
* process cmdline
* print debug message about options used
* setup signal handlers
* return control to user (if wanted - default action)
* fork number of desired childern (if wanted)
* re-exec self (if wanted)
* Determine number of files
* malloc space or i/o buffer
* Loop until stop is set
* Determine if hit iteration, time, max errors or num bytes reached
* Loop through each file
* open file
* fstat file - to determine if file is a fifo
* prealloc file space (if wanted)
* growfile
* check last write
* check whole file
* shrink file
* close file
* delay (if wanted)
* End loop
* End loop
* remove all files (if wanted)
*
* Author: Richard Logan
*
*/
#include "global.h"
#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#include "dataascii.h"
#include "random_range.h"
#include "databin.h"
#include "open_flags.h"
#include "forker.h"
#include "file_lock.h"
extern int datapidgen(int pid, unsigned char *buffer, int bsize, int offset);
extern void databingen(int mode, unsigned char *buffer, int bsize, int offset);
extern int datapidchk(int pid, char *buffer, int bsize, int offset, char **errmsg);
extern int databinchk(int mode, char *buffer, int bsize, int offset, char **errmsg);
int file_size(int fd);
int check_write(int fd, int cf_inter, char *filename, int mode);
int shrinkfile(int fd, char *filename, int trunc_incr, int trunc_inter, int just_trunc);
int check_file(int fd, int cf_inter, char *filename, int no_file_check);
int growfile(int fd, char *file, int grow_incr, unsigned char *buf);
int cleanup();
int handle_error();
int lkfile(int fd, int operation, int lklevel);
void usage();
void help();
void prt_examples(FILE *stream);
int set_sig();
void sig_handler();
static void notify_others();
int pre_alloc(char *file, int fd, int size);
#define NEWIO 1 /* Use the tlibio.c functions */
#ifndef NEWIO
#define NEWIO 0 /* specifies to use original iowrite.c */
/* functions instead of tlibio.c functions */
/* Once it is proven tlibio.c functions work properly, */
/* only tlibio.c functions will be used */
#else
#include "tlibio.h"
#endif
#ifndef PATH_MAX
#define PATH_MAX 1023
#endif
#define DEF_DIR "."
#define DEF_FILE "gf"
char *Progname;
int Debug = 1;
int Pid=0;
int io_type = 0; /* I/O type -sync */
int open_flags = O_RDWR|O_CREAT; /* open flags */
#define MAX_FC_READ 196608 /* 4096 * 48 - 48 blocks */
#define PATTERN_ASCII 1 /* repeating alphabet letter pattern */
/* allows multiple writers and to be checked */
#define PATTERN_PID 2 /* <pid><words byte offset><pid> */
/* Assumes 64 bit word. Only allows single */
/* process to write and check */
/*
* 1234567890123456789012345678901234567890123456789012345678901234
* ________________________________________________________________
* < pid >< offset in file of this word >< pid >
*/
#define PATTERN_OFFSET 3 /* Like PATTERN_PID but has a fixed number */
/* (STATIC_NUM) instead of pid. */
/* Allows multiple processes to write/read */
#define PATTERN_ALT 4 /* alternating bit pattern (i.e. 0x5555555...) */
#define PATTERN_CHKER 5 /* checkerboard pattern (i.e. 0xff00ff00ff00...) */
#define PATTERN_CNTING 6 /* counting pattern (i.e. 0 - 07, 0 - 07, ...) */
#define PATTERN_ONES 7 /* all bits set (i.e. 0xffffffffffffff...) */
#define PATTERN_ZEROS 8 /* all bits cleared (i.e. 0x000000000...) */
#define PATTERN_RANDOM 9 /* random integers - can not be checked */
#define STATIC_NUM 221849 /* used instead of pid when PATTERN_OFFSET */
#define MODE_RAND_SIZE 1 /* random write and trunc */
#define MODE_RAND_LSEEK 2 /* random lseek before write */
#define MODE_GROW_BY_LSEEK 4 /* lseek beyond end of file then write a byte */
#define RANDOM_OPEN 999876 /* if Open_flags set to this value, open flags */
/* will be randomly choosen from Open_flags[] */
#define MODE_FIFO S_IFIFO /* defined in stat.h 0010000 */
int num_files = 0; /* num_auto_files + cmd line files */
char *filenames; /* pointer to space containing filenames */
int remove_files = 0; /* if set, cleanup default is not to cleanup */
int bytes_consumed = 0; /* total bytes consumed, all files */
int bytes_to_consume = 0; /* non-zero if -B was specified, total bytes */
int Maxerrs = 100; /* Max number errors before forced exit */
int Errors = 0; /* number of encountered errors */
int Upanic_on_error = 0; /* call upanic if error and this variable set */
/* The *_size variables are only used when random iosize option (-r) is used */
int max_size=5000;
int min_size=1; /* also set in option parsing */
int mult_size=1; /* when random iosz, iosz must be mult of mult_size */
/* the *_lseek variables are only used when radon lseek option (-R) is used */
int min_lseek=0; /* also set in option parsing */
int max_lseek=-1; /* -1 means size of file */
int Pattern=PATTERN_ASCII;
int Seed=-1; /* random number seed, < 0 == uninitialized */
int Nseeds=0; /* Number of seed specified by the user */
int *Seeds; /* malloc'ed arrary of ints holding user spec seeds */
int using_random=0; /* flag indicating randomization is being used */
float delaysecs=0.0; /* delay between iterations (in seconds) */
int delaytime; /* delay between iterations in clocks/uses */
int lockfile=0; /* if set, do file locking */
/* 1 = do file locking around write, trunc */
/* and reads. */
/* 2 = write lock around all file operations */
int Woffset=0; /* offset before last write */
int Grow_incr=4096; /* sz of last write */
int Mode=0; /* bitmask of write/trunc mode */
/* also knows if dealing with fifo */
char *Buffer = NULL; /* buffer used by write and write check */
int Alignment=0; /* if non word multiple, io will not be word aligned */
int Opid=0; /* original pid */
int Sync_with_others = 0; /* Flag indicating to stop other if we stop before DONE */
int Iter_cnt = 0; /* contains current iteration count value */
char TagName[40]; /* name of this growfiles (see Monster) */
struct fileinfo_t {
char *filename;
int fd;
int openflags;
int mode;
} Fileinfo;
/*
* Define open flags that will be used when '-o random' option is used.
* Note: If there is more than one growfiles doing its thing to the same
* file, O_TRUNC will cause data mismatches. How you ask?
* timing of events, example:
* Process one Process two
* --------------- -------------
* get write lock
* fstat file
* lseek
* generate pattern
* open with O_TRUNC
* write with wrong pattern
* because offset is wrong
*
* The second process truncated the file after the pattern was
* determined, thus the pattern is wrong for the file location.
*
* There can also be a timing problem with open flag O_APPEND if
* file locks are not being used (-l option). Things could happen
* between the fstat and the write. Thus, writing the wrong pattern.
* If all processes observe the file locks, O_APPEND should be ok
* to use.
*/
int Open_flags[] = {
O_RDWR|O_CREAT,
O_RDWR|O_CREAT|O_APPEND,
O_RDWR|O_CREAT|O_NDELAY,
O_RDWR|O_CREAT|O_SYNC,
O_RDWR|O_CREAT|O_SYNC|O_NDELAY,
O_RDWR|O_CREAT|O_APPEND|O_NDELAY,
};
#define REXEC_INIT 0 /* don't do re-exec of childern */
#define REXEC_DOIT 1 /* Do re-exec of childern */
#define REXEC_DONE 2 /* We've already been re-exec'ed */
#ifndef BSIZE
#define BSIZE 512
#endif /* BSIZE */
#define USECS_PER_SEC 1000000 /* microseconds per second */
/*
* Define marcos used when dealing with file locks.
*/
#define LKLVL0 1 /* file lock around write/read/trunc */
#define LKLVL1 2 /* file lock after open to before close */
/*
* Define special max lseek values
*/
#define LSK_EOF -1 /* set fptr up to EOF */
#define LSK_EOFPLUSGROW -2 /* set fptr up to EOF + grow - leave whole */
#define LSK_EOFMINUSGROW -3 /* set fptr up to EOF-grow - no grow */
/***********************************************************************
* MAIN
***********************************************************************/
int
main(argc, argv)
int argc;
char **argv;
{
extern char *optarg; /* used by getopt */
extern int optind;
extern int opterr;
int ind;
int first_file_ind = 0;
int num_auto_files = 0; /* files created by tool */
int seq_auto_files = 0; /* auto files created by tool created by tool */
char *auto_dir = DEF_DIR;
char *auto_file = DEF_FILE;
int grow_incr = 4096;
int trunc_incr = 4096;
int trunc_inter = 0; /* 0 means none, */
int unlink_inter = 0; /* 0 means none, 1 means always unlink */
int unlink_inter_ran = -1; /* -1 -use unlink_inter, otherwise randomly choose */
/* between unlink_inter and unlink_inter_ran */
int file_check_inter = 0; /* 0 means never, 1 means always */
int write_check_inter = 1; /* 0 means never, 1 means always */
int iterations = 1; /* number of increments to be added */
int no_file_check = 0; /* if set, no whole file checking will be done */
int num;
int fd; /* file descriptor */
int stop = 0; /* loop stopper if set */
int tmp;
char chr;
int ret;
int pre_alloc_space = 0;
int total_grow_value = 0; /* used in pre-allocations */
int backgrnd = 1; /* return control to user */
struct stat statbuf;
int time_iterval = -1;
time_t start_time = 0;
char reason[40]; /* reason for loop termination */
int num_procs=1;
int forker_mode=0;
int reexec=REXEC_INIT; /* reexec info */
char *exec_path=NULL;
char *strrchr();
char *filename; /* name of file specified by user */
char *cptr; /* temp char pointer */
extern int Forker_npids; /* num of forked pid, defined in forker.c */
if ( argv[0][0] == '-' )
reexec=REXEC_DONE;
/*
* Determine name of file used to invoke this program
*/
if ((Progname=strrchr(argv[0], '/')) != NULL)
Progname++;
else
Progname=argv[0];
TagName[0] = '\0';
/*
* Process options
*/
while ((ind=getopt(argc, argv,
"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) {
switch(ind) {
case 'h' :
help();
exit(0);
case 'B':
switch (sscanf(optarg, "%i%c",
&bytes_to_consume, &chr)) {
case 1: /* noop */
break;
case 2:
if (chr == 'b') {
bytes_to_consume *= BSIZE;
} else {
fprintf(stderr,
"%s%s: --B option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
default:
fprintf(stderr, "%s%s: --B option arg invalid\n",
Progname, TagName);
usage();
exit(1);
break;
}
break;
case 'E' :
prt_examples(stdout);
exit(0);
case 'b' : /* batch */
backgrnd=0;
break;
case 'C':
if (sscanf(optarg, "%i", &write_check_inter) != 1 ) {
fprintf(stderr, "%s%s: --c option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'c':
if (sscanf(optarg, "%i", &file_check_inter) != 1 ) {
fprintf(stderr, "%s%s: --c option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'd':
auto_dir=optarg;
if ( stat(auto_dir, &statbuf) == -1 ) {
if ( mkdir(auto_dir, 0777) == -1 ) {
if ( errno != EEXIST ) {
fprintf(stderr,
"%s%s: Unable to make dir %s\n",
Progname, TagName, auto_dir);
exit(1);
}
}
}
else {
if ( ! (statbuf.st_mode & S_IFDIR) ) {
fprintf(stderr,
"%s%s: %s already exists and is not a directory\n",
Progname, TagName, auto_dir);
exit(1);
}
}
break;
case 'D':
if (sscanf(optarg, "%i", &Debug) != 1 ) {
fprintf(stderr, "%s%s: --D option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'e':
if (sscanf(optarg, "%i", &Maxerrs) != 1 ) {
fprintf(stderr, "%s%s: --e option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'f':
auto_file=optarg;
break;
case 'g':
if ((ret=sscanf(optarg, "%i%c", &grow_incr, &chr)) < 1 ||
grow_incr < 0 ) {
fprintf(stderr, "%s%s: --g option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
if ( ret == 2 ) {
if ( chr == 'b' || chr == 'B' )
grow_incr *= 4096;
else {
fprintf(stderr,
"%s%s: --g option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
}
break;
case 'H':
if (sscanf(optarg, "%f", &delaysecs) != 1 || delaysecs < 0 ) {
fprintf(stderr, "%s%s: --H option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'i':
if (sscanf(optarg, "%i", &iterations) != 1 ||
iterations < 0 ) {
fprintf(stderr, "%s%s: --i option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'I':
#if NEWIO
if((io_type=lio_parse_io_arg1(optarg)) == -1 ) {
fprintf(stderr,
"%s%s: --I arg is invalid, must be s, p, f, a, l, L or r.\n",
Progname, TagName);
exit(1);
}
if( io_type & LIO_RANDOM )
using_random++;
#else
if((io_type=parse_io_arg(optarg)) == -1 ) {
fprintf(stderr,
"%s%s: --I arg is invalid, must be s, p, f, a, l, L or r.\n",
Progname, TagName);
exit(1);
}
if( io_type == 99 ) /* hold-over until tlibio.h */
using_random++;
#endif
break;
case 'l':
lockfile++;
if ( lockfile > 2 )
lockfile=2; /* lockfile can only be 1 or 2 */
break;
case 'L':
if (sscanf(optarg, "%i", &time_iterval) != 1 ||
time_iterval < 0 ) {
fprintf(stderr, "%s%s: --L option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'n':
if (sscanf(optarg, "%i:%i", &num_procs, &forker_mode) < 1 ||
num_procs < 0 ) {
fprintf(stderr, "%s%s: --n option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'N':
if (sscanf(optarg, "%i", &num_auto_files) != 1 ||
num_auto_files < 0 ) {
fprintf(stderr, "%s%s: --N option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'O':
if (sscanf(optarg, "%i", &Alignment) != 1 ||
num_auto_files < 0 ) {
fprintf(stderr, "%s%s: --O option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'o':
if ( strcmp(optarg, "random") == 0 ){
open_flags=RANDOM_OPEN;
using_random++;
} else if ((open_flags=parse_open_flags(optarg, NULL)) == -1 ) {
fprintf(stderr, "%s%s: --o arg contains invalid flag\n",
Progname, TagName);
exit(1);
}
break;
case 'p' : /* pre allocate space */
printf("%s%s: --p is illegal option on this system\n",
Progname, TagName);
exit(1);
break;
case 'P':
printf("%s%s: --P is illegal option on non-cray system\n",
Progname, TagName);
exit(1);
break;
case 'q': /* file content or pattern */
switch(optarg[0]) {
case 'A':
Pattern = PATTERN_ALT;
break;
case 'a':
Pattern = PATTERN_ASCII;
break;
case 'p':
Pattern = PATTERN_PID;
break;
case 'o':
Pattern = PATTERN_OFFSET;
break;
case 'c':
Pattern = PATTERN_CHKER;
break;
case 'C':
Pattern = PATTERN_CNTING;
break;
case 'r':
Pattern = PATTERN_RANDOM;
using_random++;
break;
case 'z':
Pattern = PATTERN_ZEROS;
break;
case 'O':
Pattern = PATTERN_ONES;
break;
default:
fprintf(stderr,
"%s%s: --C option arg invalid, A, a, p, o, c, C, r, z, or 0\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'R': /* random lseek before write arg: [min-]max*/
if (sscanf(optarg, "%i-%i", &min_lseek, &max_lseek) != 2 ) {
min_lseek=1; /* same as default in define */
if (sscanf(optarg, "%i%c", &max_lseek, &chr) != 1 ) {
fprintf(stderr, "%s%s: --R option arg invalid: [min-]max\n",
Progname, TagName);
exit(1);
}
}
if ( max_lseek < LSK_EOFMINUSGROW ) {
fprintf(stderr, "%s%s: --R option, max_lseek is invalid\n",
Progname, TagName);
exit(1);
}
Mode |= MODE_RAND_LSEEK;
using_random++;
break;
case 'r': /* random io size arg: [min-]max[:mult] */
/* min-max:mult format */
if (sscanf(optarg, "%i-%i:%i%c", &min_size, &max_size,
&mult_size, &chr) != 3 ) {
min_size=1;
/* max:mult format */
if (sscanf(optarg, "%i:%i%c", &max_size,
&mult_size, &chr) != 2 ) {
/* min-max format */
if (sscanf(optarg, "%i-%i%c", &min_size,
&max_size, &chr) != 2 ) {
min_size=1;
if (sscanf(optarg, "%i%c", &max_size, &chr) != 1 ) {
fprintf(stderr,
"%s%s: --r option arg invalid: [min-]max[:mult]\n",
Progname, TagName);
exit(1);
}
}
}
}
if ( max_size < 0 ) {
fprintf(stderr, "%s%s: --r option, max_size is invalid\n",
Progname, TagName);
exit(1);
}
/*
* If min and max are the same, no randomness
*/
if ( min_size != max_size ) {
Mode |= MODE_RAND_SIZE;
using_random++;
}
break;
case 'S':
if (sscanf(optarg, "%i", &seq_auto_files) != 1 ||
seq_auto_files < 0 ) {
fprintf(stderr, "%s%s: --S option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 's': /* format: seed[,seed...] */
/* count the number of seeds */
cptr=optarg;
for(Nseeds=1; *cptr ; Nseeds++) {
if ( (filename=strchr(cptr, ',')) == NULL )
break;
cptr=filename;
cptr++;
}
Seeds=(int *)malloc(Nseeds*sizeof(int));
/*
* check that each seed is valid and put them in
* the newly malloc'ed Seeds arrary.
*/
filename=cptr=optarg;
for(Nseeds=0; *cptr; Nseeds++) {
if ( (filename=strchr(cptr, ',')) == NULL ) {
if ( sscanf(cptr, "%i", &Seeds[Nseeds]) < 1 ) {
fprintf(stderr, "%s%s: --s option arg %s invalid\n",
Progname, TagName, cptr);
usage();
exit(1);
}
Nseeds++;
break;
}
*filename='\0';
if ( sscanf(cptr, "%i", &Seeds[Nseeds]) < 1 ) {
fprintf(stderr, "%s%s: --s option arg %s invalid\n",
Progname, TagName, cptr);
usage();
exit(1);
}
*filename=','; /* restore string */
cptr=filename;
cptr++;
}
break;
case 't':
if ((ret=sscanf(optarg, "%i%c", &trunc_incr, &chr)) < 1 ||
trunc_incr < 0 ) {
fprintf(stderr, "%s%s: --t option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
if ( ret == 2 ) {
if ( chr == 'b' || chr == 'B' )
trunc_incr *= 4096;
else {
fprintf(stderr,
"%s%s: --t option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
}
break;
case 'T': /* truncate interval */
if (sscanf(optarg, "%i%c", &trunc_inter, &chr) != 1 ||
trunc_inter < 0 ) {
fprintf(stderr, "%s%s: --T option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'u':
remove_files++;
break;
case 'U': /* how often to unlink file */
/*
* formats:
* A-B - randomly pick interval between A and B
* X - unlink file every X iteration
*/
if (sscanf(optarg, "%i-%i", &unlink_inter,
&unlink_inter_ran) == 2 ) {
if ( unlink_inter < 0 || unlink_inter_ran < 0 ) {
fprintf(stderr, "%s%s: --U option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
/* ensure unlink_inter contains smaller value */
if ( unlink_inter > unlink_inter_ran ) {
tmp=unlink_inter_ran;
unlink_inter_ran=unlink_inter;
unlink_inter=tmp;
}
using_random++;
} else if (sscanf(optarg, "%i%c", &unlink_inter, &chr) != 1 ||
unlink_inter < 0 ) {
fprintf(stderr, "%s%s: --U option arg invalid\n",
Progname, TagName);
usage();
exit(1);
}
break;
case 'x':
if ( reexec != REXEC_DONE )
reexec=REXEC_DOIT;
break;
case 'w':
Mode |= MODE_GROW_BY_LSEEK;
break;
case 'W':
sprintf( TagName, "(%.37s)", optarg );
break;
case 'y':
Sync_with_others=1;
break;
case '?':
usage();
exit(1);
break;
}
}
if( Debug == 1 ){
cptr = getenv("TOUTPUT");
if( (cptr != NULL) && (strcmp( cptr, "NOPASS" ) == 0) ){
Debug = 0;
}
}
if ( Pattern == PATTERN_RANDOM ) {
no_file_check=1;
if ( write_check_inter || file_check_inter )
printf("%s%s: %d Using random pattern - no data checking will be performed!\n",
Progname, TagName, (int)getpid());
}
else if ( max_lseek == LSK_EOFPLUSGROW || Mode & MODE_GROW_BY_LSEEK ) {
no_file_check=1;
if ( file_check_inter )
printf("%s%s: %d Using random lseek beyond EOF or lseek grow,\n\
no whole file checking will be performed!\n", Progname, TagName, (int)getpid());
}
if ( Mode & MODE_RAND_SIZE )
grow_incr=max_size;
set_sig();
Opid=getpid();
Pid=Opid;
if ( backgrnd ) {
if ( Debug > 1 )
printf("%s: %d DEBUG2 forking, returning control to the user\n",
Progname, Opid);
background(Progname); /* give user their prompt back */
}
if ( Debug > 3 ) {
#if NEWIO
lio_set_debug(Debug-3);
#else
set_iowrite_debug(Debug-3);
#endif
}
/*
* Print some program information here if debug is turned on to
* level 3 or higher.
*/
if ( Debug > 2 ) {
if ( Mode & MODE_GROW_BY_LSEEK )
printf("%s: %d DEBUG lseeking past end of file, writting a \"w\"\n",
Progname, Pid);
else if ( Pattern == PATTERN_OFFSET )
printf("%s: %d DEBUG3 %d<byteoffset>%d per word pattern multi-writers.\n",
Progname, Pid, STATIC_NUM, STATIC_NUM);
else if ( Pattern == PATTERN_PID )
printf("%s: %d DEBUG3 <pid><byteoffset><pid> per word pattern - 1 writer\n",
Progname, Pid);
else if ( Pattern == PATTERN_ASCII )
printf("%s: %d DEBUG3 ascii pattern (vi'able)- allows multiple writers\n",
Progname, Pid);
else if ( Pattern == PATTERN_ALT )
printf("%s: %d DEBUG3 alt bit pattern - allows multiple writers\n",
Progname, Pid);
else if ( Pattern == PATTERN_CHKER )
printf("%s: %d DEBUG3 checkerboard pattern - allows multiple writers\n",
Progname, Pid);
else if ( Pattern == PATTERN_CNTING )
printf("%s: %d DEBUG3 counting pattern - allows multiple writers\n",
Progname, Pid);
else if ( Pattern == PATTERN_RANDOM )
printf("%s: %d DEBUG3 random integer pattern - no write/file checking\n",
Progname, Pid);
else if ( Pattern == PATTERN_ONES )
printf("%s: %d DEBUG3 all ones pattern - allows multiple writers\n",
Progname, Pid);
else if ( Pattern == PATTERN_ZEROS )
printf("%s: %d DEBUG3 all zeros pattern - allows multiple writers\n",
Progname, Pid);
else
printf("%s: %d DEBUG3 unknown pattern\n",
Progname, Pid);
if ( bytes_to_consume )
printf("%s: %d DEBUG3 bytes_to_consume = %d\n",
Progname, Pid, bytes_to_consume);
printf("%s: %d DEBUG3 Maxerrs = %d, pre_alloc_space = %d, filelocking = %d\n",
Progname, Pid, Maxerrs, pre_alloc_space, lockfile);
printf("%s: %d DEBUG3 Debug = %d, remove files in cleanup : %d\n",
Progname, Pid, Debug, remove_files);
printf("%s: %d DEBUG3 Mode = %#o\n", Progname, Pid, Mode);
if ( open_flags == RANDOM_OPEN )
printf("%s: %d DEBUG3 open_flags = (random), io_type = %#o\n", Progname,
Pid, io_type);
else
printf("%s: %d DEBUG3 open_flags = %#o, io_type = %#o\n", Progname,
Pid, open_flags, io_type);
if ( Mode & MODE_RAND_SIZE ) {
printf("%s: %d DEBUG3 random write/trunc: min=%d, max=%d, mult = %d\n",
Progname, Pid, min_size, max_size, mult_size);
}
else {
printf("%s: %d DEBUG3 grow_incr = %d\n",
Progname, Pid, grow_incr);
}
if ( Mode & MODE_RAND_LSEEK ) {
if ( max_lseek == LSK_EOF )
printf("%s: %d DEBUG3 random lseek: min=%d, max=<endoffile>\n",
Progname, Pid, min_lseek);
else if ( max_lseek == LSK_EOFPLUSGROW )
printf("%s: %d DEBUG3 random lseek: min=%d, max=<endoffile+iosize>\n",
Progname, Pid, min_lseek);
else if ( max_lseek == LSK_EOFMINUSGROW )
printf("%s: %d DEBUG3 random lseek: min=%d, max=<endoffile-iosize>\n",
Progname, Pid, min_lseek);
else
printf("%s: %d DEBUG3 random lseek: min=%d, max=%d\n",
Progname, Pid, min_lseek, max_lseek);
}
printf("%s: %d DEBUG3 check write interval = %d, check file interval = %d\n",
Progname, Pid, write_check_inter, file_check_inter);
printf("%s: %d DEBUG3 trunc interval = %d, trunc_incr = %d\n",
Progname, Pid, trunc_inter, trunc_incr);
if ( no_file_check )
printf("%s: %d DEBUG3 no whole file checking will be done\n",
Progname, Pid);
if ( unlink_inter_ran == -1 ) {
printf("%s: %d DEBUG3 unlink_inter = %d\n",
Progname, Pid, unlink_inter);
} else {
printf("%s: %d DEBUG3 unlink_inter = %d, unlink_inter_ran = %d\n",
Progname, Pid, unlink_inter, unlink_inter_ran);
}
if ( Debug > 8 ) {
num=sizeof(Open_flags)/sizeof(int);
printf("%s: %d DEBUG9 random open flags values:\n", Progname, Pid);
for(ind=0; ind<num; ind++) {
printf("\t%#o\n", Open_flags[ind]);
}
}
} /* end of DEBUG > 2 */
if ( Debug > 1 && num_procs > 1 ) {
printf("%s: %d DEBUG2 about to fork %d more copies\n", Progname,
Opid, num_procs-1);
}
fflush(stdout); /* ensure pending i/o is flushed before forking */
fflush(stderr);
forker(num_procs, forker_mode, Progname);
Pid=getpid(); /* reset after the forks */
/*
* If user specified random seed(s), get that random seed value.
* get random seed if it was not specified by the user.
* This is done after the forks, because pid is used to get the seed.
*/
if ( Nseeds == 1 ) {
/*
* If only one seed specified, all processes will get that seed.
*/
Seed=Seeds[0];
} else if ( Nseeds > 1 ) {
/*
* More than one seed was specified.
* The original process gets the first seed. Each
* process will be get the next seed in the specified list.
*/
if ( Opid == Pid ) {
Seed=Seeds[0];
} else {
/*
* If user didn't specify enough seeds, use default method.
*/
if ( Forker_npids >= Nseeds )
Seed=time(0) + Pid; /* default random seed */
else {
Seed=Seeds[Forker_npids];
}
}
} else {
/*
* Generate a random seed based on time and pid.
* It has a good chance of being unique for each pid.
*/
Seed=time(0) + Pid; /* default random seed */
}
random_range_seed(Seed);
if ( using_random && Debug > 0 )
printf("%s%s: %d DEBUG1 Using random seed of %d\n",
Progname, TagName, Pid, Seed);
if ( unlink_inter_ran > 0 ) {
/*
* Find unlinking file interval. This must be done after
* the seed was set. This allows multiple copies to
* get different intervals.
*/
tmp=unlink_inter;
unlink_inter=random_range(tmp, unlink_inter_ran, 1, NULL);
if ( Debug > 2 )
printf("%s: %d DEBUG3 Unlink interval is %d (random %d - %d)\n",
Progname, Pid, unlink_inter, tmp, unlink_inter_ran);
}
/*
* re-exec all childern if reexec is set to REXEC_DOIT.
* This is useful on MPP systems to get the
* child process on another PE.
*/
if ( reexec == REXEC_DOIT && Opid != Pid ) {
if ( exec_path == NULL ) {
exec_path = argv[0];
/* Get space for cmd (2 extra, 1 for - and 1 fro NULL */
argv[0] = (char *)malloc(strlen(exec_path) + 2);
sprintf(argv[0], "-%s", exec_path);
}
if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: execvp(%s, argv)\n",
Progname, Pid, __FILE__, __LINE__, argv[0]);
execvp(argv[0], argv);
}
/*** begin filename stuff here *****/
/*
* Determine the number of files to be dealt with
*/
if ( optind == argc ) {
/*
* no cmd line files, therfore, set
* the default number of auto created files
*/
if ( ! num_auto_files && ! seq_auto_files )
num_auto_files=1;
}
else {
first_file_ind=optind;
num_files += argc-optind;
}
if ( num_auto_files ) {
num_files += num_auto_files;
}
if ( seq_auto_files ) {
num_files += seq_auto_files;
}
/*
* get space for file names
*/
if ((filenames=(char *)malloc(num_files*PATH_MAX)) == NULL) {
fprintf(stderr, "%s%s: %d %s/%d: malloc(%d) failed: %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, num_files*PATH_MAX,
strerror(errno));
exit(1);
}
/*
* fill in filename cmd files then auto files.
*/
num=0;
if ( first_file_ind ) {
for(ind=first_file_ind; ind<argc; ind++, num++) {
strcpy((char *)filenames+(num*PATH_MAX), argv[ind]);
}
}
/*
* construct auto filename and insert them into filenames space
*/
for(ind=0;ind<num_auto_files; ind++, num++) {
sprintf((char *)filenames+(num*PATH_MAX), "%s/%s.%d",
auto_dir, auto_file, ind);
}
/*
* construct auto seq filenames
*/
for(ind=1; ind<=seq_auto_files; ind++, num++) {
sprintf((char *)filenames+(num*PATH_MAX), "%s/%s%d",
auto_dir, auto_file, ind);
}
/**** end filename stuff ****/
if ( time_iterval > 0 )
start_time=time(0);
/*
* get space for I/O buffer
*/
if ( grow_incr ) {
if ((Buffer=(char *)malloc(grow_incr+Alignment)) == NULL) {
fprintf(stderr, "%s%s: %d %s/%d: malloc(%d) failed: %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, grow_incr, strerror(errno));
exit(1);
}
if ( Alignment )
Buffer = Buffer + Alignment;
}
if ( Debug > 2 ) {
printf("%s: %d DEBUG3 num_files = %d\n",
Progname, Pid, num_files);
}
if ( pre_alloc_space ) {
if ( iterations == 0 ) {
fprintf(stderr, "%s%s: %d %s/%d: can NOT pre-alloc and grow forever\n",
Progname, TagName, Pid, __FILE__, __LINE__);
exit(1);
}
if ( Mode & MODE_RAND_SIZE ) {
fprintf(stderr,
"%s%s: %d %s/%d: can NOT pre-alloc and do random io size\n",
Progname, TagName, Pid, __FILE__, __LINE__);
exit(1);
}
total_grow_value=grow_incr * iterations;
/*
* attempt to limit
*/
if ( bytes_to_consume && bytes_to_consume < total_grow_value ) {
total_grow_value=bytes_to_consume;
}
}
/*
* If delaying between iterations, get amount time to
* delaysecs in clocks or usecs.
*/
if ( delaysecs ) {
delaytime=(int)((float)USECS_PER_SEC * delaysecs);
}
/*
* This is the main iteration loop.
* Each iteration, all files can be opened, written to,
* read to check the write, check the whole file,
* truncated, and closed.
*/
for(Iter_cnt=1; ! stop ; Iter_cnt++) {
if ( iterations && Iter_cnt >= iterations+1 ) {
strcpy(reason, "Hit iteration value");
stop=1;
continue;
}
if ( (time_iterval > 0) && (start_time + time_iterval < time(0)) ) {
sprintf(reason, "Hit time value of %d", time_iterval);
stop=1;
continue;
}
if ( bytes_to_consume && bytes_consumed >= bytes_to_consume) {
sprintf(reason, "Hit bytes consumed value of %d", bytes_to_consume);
stop=1;
continue;
}
/*
* This loop will loop through all files.
* Each iteration, a single file can be opened, written to,
* read to check the write, check the whole file,
* truncated, and closed.
*/
for(ind=0; ind<num_files; ind++) {
fflush(stdout);
fflush(stderr);
filename=(char *)filenames+(ind*PATH_MAX);
Fileinfo.filename=(char *)filenames+(ind*PATH_MAX);
if ( open_flags == RANDOM_OPEN ) {
ret=Open_flags[random_range(0, sizeof(Open_flags)/sizeof(int)-1, 1, NULL)];
}
else
ret=open_flags;
Fileinfo.openflags=ret;
if ( Debug > 3 ) {
printf("%s: %d DEBUG3 %s/%d: %d Open filename = %s, open flags = %#o %s\n",
Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, ret,
openflags2symbols(ret, ",", 0));
} else if ( Debug > 2 ) {
printf("%s: %d DEBUG3 %s/%d: %d filename = %s, open flags = %#o\n",
Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, ret);
}
/*
* open file with desired flags.
*/
if ( (fd=open(filename, ret, 0777)) == -1 ) {
fprintf(stderr,
"%s%s: %d %s/%d: open(%s, %#o, 0777) returned -1, errno:%d %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, filename, ret, errno, strerror(errno));
handle_error();
continue;
}
Fileinfo.fd=fd;
lkfile(fd, LOCK_EX, LKLVL1); /* lock if lockfile is LKLVL1 */
/*
* preallocation is only done once, if specified.
*/
if ( pre_alloc_space ) {
if (pre_alloc(filename, fd, total_grow_value) != 0 ) {
cleanup();
exit(2);
}
if ( Debug > 1 ) {
printf("%s: %d DEBUG2 %s/%d: pre_allocated %d for file %s\n",
Progname, Pid, __FILE__, __LINE__, total_grow_value, filename);
}
lkfile(fd, LOCK_UN, LKLVL1); /* release lock */
close(fd);
Iter_cnt=0; /* reset outside loop to restart from one */
continue;
}
/*
* grow file by desired amount.
* growfile() will set the Grow_incr variable and
* possiblly update the Mode variable indicating
* if we are dealing with a FIFO file.
*/
if (growfile(fd, filename, grow_incr, (unsigned char *)Buffer) != 0 ) {
handle_error();
lkfile(fd, LOCK_UN, LKLVL1); /* release lock */
close(fd);
continue;
}
/*
* check if last write is not corrupted
*/
if ( check_write(fd, write_check_inter, filename,
Mode) != 0 ) {
handle_error();
}
/*
* Check that whole file is not corrupted.
*/
if ( check_file(fd, file_check_inter, filename,
no_file_check) != 0 ) {
handle_error();
}
/*
* shrink file by desired amount if it is time
*/
if ( shrinkfile(fd, filename, trunc_incr, trunc_inter, Mode) != 0 ) {
handle_error();
}
lkfile(fd, LOCK_UN, LKLVL1); /* release lock */
if ( Debug > 4 )
printf("%s: %d DEBUG5 %s/%d: %d Closing file %s fd:%d \n",
Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, fd);
close(fd);
/*
* Unlink the file if that is desired
*/
if ( unlink_inter && (Iter_cnt % unlink_inter == 0) ) {
if ( Debug > 4 )
printf("%s: %d DEBUG5 %s/%d: %d Unlinking file %s\n",
Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename);
unlink(filename);
}
/*
* delay while staying active for "delaysecs" seconds.
*/
if ( delaytime ) {
int ct, end;
struct timeval curtime;
gettimeofday(&curtime, NULL);
ct=curtime.tv_sec*USECS_PER_SEC + curtime.tv_usec;
end=ct+delaytime;
while ( ct < end ) {
gettimeofday(&curtime, NULL);
ct=curtime.tv_sec*USECS_PER_SEC + curtime.tv_usec;
}
}
}
/*
* if Iter_cnt == 0, then we pre allocated space to all files
* and we are starting outside loop over. Set pre_alloc_space
* to zero otherwise we get in infinite loop
*/
if ( Iter_cnt == 0 ) {
pre_alloc_space=0;
}
} /* end iteration for loop */
if ( Debug ) {
printf("%s%s: %d %s/%d: DONE %d iterations to %d files. %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, num_files, reason);
}
fflush(stdout);
fflush(stderr);
cleanup();
if ( Errors ) {
if ( Debug > 2 ) {
printf("%s%s: %d DEBUG3 %d error(s) encountered\n",
Progname, TagName, Pid, Errors);
printf("%s%s: %d DEBUG3 %s/%d: exiting with value of 1\n", Progname, TagName, Pid, __FILE__, __LINE__);
}
exit(1);
}
if ( Debug > 2 )
printf("%s%s: %d DEBUG3 %s/%d: no errors, exiting with value of 0\n", Progname, TagName, Pid, __FILE__, __LINE__);
exit(0);
}
/***********************************************************************
*
***********************************************************************/
int
set_sig()
{
int sig;
/*
* now loop through all signals and set the handlers
*/
for (sig = 1; sig < NSIG; sig++) {
switch (sig) {
case SIGKILL:
case SIGSTOP:
case SIGCONT:
#ifdef SIGCKPT
case SIGCKPT:
#endif /* SIGCKPT */
#ifdef SIGRESTART
case SIGRESTART:
#endif /* SIGRESTART */
case SIGCHLD:
break;
default:
signal(sig, sig_handler);
break;
}
} /* endfor */
return 0;
}
/***********************************************************************
*
***********************************************************************/
void
sig_handler(sig)
int sig;
{
int exit_stat = 2;
if ( sig == SIGUSR2 ) {
fprintf(stdout, "%s%s: %d %s/%d: received SIGUSR2 (%d) - stopping.\n",
Progname, TagName, Pid, __FILE__, __LINE__, sig);
signal(sig, sig_handler); /* allow us to get this signal more than once */
} else if( sig == SIGINT ){
/* The user has told us to cleanup, don't pretend it's an error. */
exit_stat=0;
if ( Debug != 0 ){
fprintf(stderr, "%s%s: %d %s/%d: received unexpected signal: %d\n", Progname, TagName,
Pid, __FILE__, __LINE__, sig);
}
} else {
fprintf(stderr, "%s%s: %d %s/%d: received unexpected signal: %d\n", Progname, TagName,
Pid, __FILE__, __LINE__, sig);
}
notify_others();
cleanup();
if ( Debug > 2 ){
printf("%s%s: %d DEBUG3 %s/%d: Exiting with a value of %d\n",
Progname, TagName, Pid, __FILE__, __LINE__, exit_stat);
}
exit(exit_stat);
}
/***********************************************************************
* this function attempts to send SIGUSR2 to other growfiles processes
* telling them to stop.
*
***********************************************************************/
static void
notify_others()
{
static int send_signals = 0;
int ind;
extern int Forker_pids[];
extern int Forker_npids;
if ( Sync_with_others && send_signals == 0 ) {
send_signals=1; /* only send signals once */
for (ind=0; ind< Forker_npids; ind++) {
if ( Forker_pids[ind] != Pid ) {
if ( Debug > 1 )
printf("%s%s: %d DEBUG2 %s/%d: Sending SIGUSR2 to pid %d\n",
Progname, TagName, Pid, __FILE__, __LINE__, Forker_pids[ind]);
kill(Forker_pids[ind], SIGUSR2);
}
}
}
}
/***********************************************************************
* this function will count the number of errors encountered.
* This function will call upanic if wanted or cleanup and
* and exit is Maxerrs were encountered.
***********************************************************************/
int
handle_error()
{
Errors++;
if ( Maxerrs && Errors >= Maxerrs ) {
printf("%s%s: %d %s/%d: %d Hit max errors value of %d\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, Maxerrs);
notify_others();
cleanup();
if ( Debug > 2 ) {
printf("%s%s: %d DEBUG3 %d error(s) encountered\n",
Progname, TagName, Pid, Errors);
printf("%s%s: %d DEBUG3 %s/%d: exiting with value of 1\n", Progname, TagName, Pid, __FILE__, __LINE__);
}
exit(1);
}
return 0;
}
/***********************************************************************
*
***********************************************************************/
int
cleanup()
{
int ind;
if ( remove_files ) {
if ( Debug > 2 )
printf("%s: %d DEBUG3 Removing all %d files\n",
Progname, Pid, num_files);
for(ind=0; ind<=num_files; ind++) {
unlink(filenames+(ind*PATH_MAX));
}
}
if ( using_random && Debug > 1 )
printf("%s%s: %d DEBUG2 Used random seed: %d\n",
Progname, TagName, Pid, Seed);
return 0;
}
/***********************************************************************
*
***********************************************************************/
void
usage()
{
fprintf(stderr,
"Usage: %s%s [-bhEluy][[-g grow_incr][-i num][-t trunc_incr][-T trunc_inter]\n",
Progname, TagName );
fprintf(stderr,
"[-d auto_dir][-e maxerrs][-f auto_file][-N num_files][-w][-c chk_inter][-D debug]\n");
fprintf(stderr,
"[-s seed][-S seq_auto_files][-p][-P PANIC][-I io_type][-o open_flags][-B maxbytes]\n");
fprintf(stderr,
"[-r iosizes][-R lseeks][-U unlk_inter][-W tagname] [files]\n");
return;
} /* end of usage */
/***********************************************************************
*
***********************************************************************/
void
help()
{
usage();
fprintf(stdout, "\
-h Specfied to print this help and exit.\n\
-b Specfied to execute in sync mode.(def async mode)\n\
-B maxbytes Max bytes to consume by all files. growfiles exits when more\n\
than maxbytes have been consumed. (def no chk) If maxbytes ends\n\
with the letter 'b', maxbytes is multiplied by BSIZE\n\
-C write_chk Specifies how often to check the last write (default 1)\n\
-c file_chk Specifies how often to check whole file (default 0)\n\
-d auto_dir Specifies the directory to auto created files. (default .)\n\
-D debug_lvl Specifies the debug level (default 1)\n\
-E Print examples and exit\n\
-e errs The number errors that will terminate this program (def 100)\n\
-f auto_file Specifies the base filename files created. (default \"gf\")\n\
-g grow_incr Specfied to grow by incr for each num. (default 4096)\n\
grow_incr may end in b for blocks\n\
If -r option is used, this option is ignored and size is random\n\
-H delay Amount of time to delay between each file (default 0.0)\n\
-I io_type Specifies io type: s - sync, p - polled async, a - async (def s)\n\
l - listio sync, L - listio async, r - random\n\
-i iteration Specfied to grow each file num times. 0 means forever (default 1)\n\
-l Specfied to do file locking around write/read/trunc\n\
If specified twice, file locking after open to just before close\n\
-L time Specfied to exit after time secs, must be used with -i.\n\
-N num_files Specifies the number of files to be created.\n\
The default is zero if cmd line files.\n\
The default is one if no cmd line files.\n\
-n num_procs Specifies the number of copies of this cmd.\n\
-o op_type Specifies open flages: (def O_RDWR,O_CREAT) op_type can be 'random'\n\
-O offset adjust i/o buffer alignment by offset bytes\n\
-P PANIC Specifies to call upanic on error.\n\
-p Specifies to pre-allocate space\n\
-q pattern pattern can be a - ascii, p - pid with boff, o boff (def)\n\
A - Alternating bits, r - random, O - all ones, z - all zeros,\n\
c - checkboard, C - counting\n\
-R [min-]max random lseek before write and trunc, max of -1 means filesz,\n\
-2 means filesz+grow, -3 filesz-grow. (min def is 0)\n\
-r [min-]max random io write size (min def is 1)\n\
-S seq_auto_files Specifies the number of seqental auto files (default 0)\n\
-s seed[,seed...] Specifies the random number seed (default time(0)+pid)\n\
-t trunc_incr Specfied the amount to shrink file. (default 4096)\n\
trunc_inter may end in b for blocks\n\
If -R option is used, this option is ignored and trunc is random\n\
-T trunc_inter Specfied the how many grows happen before shrink. (default 0)\n\
-u unlink files before exit\n\
-U ui[-ui2] Unlink files each ui iteration (def 0)\n\
-w Specfied to grow via lseek instead of writes.\n\
-W tag-name Who-am-i. My Monster tag name. (used by Monster).\n\
-x Re-exec children before continuing - useful on MPP systems\n\
-y Attempt to sync copies - if one fails it will send sigusr2 to others\n\
Action to each file every iteration is open, write, write check\n\
file check, trunc and closed.\n");
return;
}
/***********************************************************************
*
***********************************************************************/
void
prt_examples(FILE *stream)
{
/* This example creates 200 files in directory dir1. It writes */
/* 4090 bytes 100 times then truncates 408990 bytes off the file */
/* The file contents are checked every 1000 grow. */
fprintf(stream,
"# run forever: writes of 4090 bytes then on every 100 iterval\n\
# truncate file by 408990 bytes. Done to 200 files in dir1.\n\
%s -i 0 -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -d dir1 -S 200\n\n", Progname);
/* same as above with 5000 byte grow and a 499990 byte tuncate */
fprintf(stream,
"# same as above with writes of 5000 bytes and truncs of 499990\n\
%s -i 0 -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -d dir2 -S 200\n\n", Progname);
/* This example beats on opens and closes */
fprintf(stream,
"# runs forever: beats on opens and closes of file ocfile - no io\n\
%s -i 0 -g 0 -c 0 -C 0 ocfile\n\n", Progname);
fprintf(stream,
"# writes 4096 to files until 50 blocks are written\n\
%s -i 0 -g 4096 -B 50b file1 file2\n\n", Progname);
fprintf(stream,
"# write one byte to 750 files in gdir then unlinks them\n\
%s -g 1 -C 0 -d gdir -u -S 750\n\n", Progname);
fprintf(stream,
"# run 30 secs: random iosize, random lseek up to eof\n\
%s -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 g_rand1 g_rand2\n\n", Progname);
fprintf(stream,
"# run 30 secs: grow by lseek then write single byte, trunc every 10 itervals\n\
%s -g 5000 -wlu -i 0 -L 30 -C 1 -T 10 g_sleek1 g_lseek2\n\n", Progname);
fprintf(stream,
"# run forever: 5 copies of random iosize, random lseek to beyond eof,\n\
# rand io types doing a trunc every 5 iterations, with unlinks.\n\
%s -i0 -r 1-50000 -R 0--2 -I r -C1 -l -n5 -u -U 100-200 gf_rana gf_ranb\n\n",
Progname);
fprintf(stream,
"# run forever: 5 copies of random iosize, random lseek to beyond eof,\n\
# random open flags, rand io types doing a trunc every 10 iterations.\n\
%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",
Progname);
return;
}
/***********************************************************************
*
* The file descriptor current offset is assumed to be the end of the
* file.
* Woffset will be set to the offset before the write.
* Grow_incr will be set to the size of the write or lseek write.
***********************************************************************/
int
growfile(fd, file, grow_incr, buf)
int fd;
char *file;
int grow_incr;
unsigned char *buf;
{
int noffset;
int ret;
/* REFERENCED */
int cur_offset;
char *errmsg;
int fsize; /* current size of file */
int size_grew; /* size the file grew */
struct stat stbuf;
int tmp = 0;
/*
* Do a stat on the open file.
* If the file is a fifo, set the bit in Mode variable.
* This fifo check must be done prior to growfile() returning.
* Also get the current size of the file.
*/
if ( fstat(fd, &stbuf) != -1 ) {
if ( S_ISFIFO(stbuf.st_mode) ) {
Fileinfo.mode |= MODE_FIFO;
Mode |= MODE_FIFO;
if ( Debug > 3 )
printf("%s: %d DEBUG4 %s/%d: file is a fifo - no lseek or truncs,\n",
Progname, Pid, __FILE__, __LINE__);
}
fsize = stbuf.st_size;
} else {
fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
return -1;
}
if ( grow_incr <= 0 ) { /* don't attempt i/o if grow_incr <= 0 */
Grow_incr=grow_incr;
if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: Not attempting to grow, growsize == %d\n",
Progname, Pid, __FILE__, __LINE__, grow_incr);
return grow_incr;
}
if ( Mode & MODE_RAND_SIZE ) {
grow_incr=random_range(min_size, max_size, mult_size, &errmsg);
if (errmsg != NULL) {
fprintf(stderr, "%s%s: %d %s/%d: random_range() failed - %s\n", Progname, TagName, Pid, __FILE__, __LINE__, errmsg);
return -1;
}
Grow_incr=grow_incr;
}
else
Grow_incr=grow_incr;
if ( ! (Mode & MODE_FIFO) ) {
if ((cur_offset=lseek(fd,0,SEEK_CUR)) == -1 ) {
fprintf(stderr, "%s%s: %d %s/%d: tell failed: %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
return -1;
}
}
if ( Mode & MODE_GROW_BY_LSEEK ) {
Woffset=fsize;
if ( Debug > 2 ) {
printf("%s: %d DEBUG3 %s/%d: Current size of file is %d\n", Progname,
Pid, __FILE__, __LINE__, Woffset);
printf("%s: %d DEBUG3 %s/%d: lseeking to %d byte with SEEK_END\n", Progname,
Pid, __FILE__, __LINE__, grow_incr-1);
}
if ((noffset=lseek(fd, grow_incr-1, SEEK_END)) == -1 ) {
fprintf(stderr, "%s%s: %s/%d: lseek(fd, %d, SEEK_END) failed: %s\n",
Progname, TagName, __FILE__, __LINE__, grow_incr-1, strerror(errno));
return -1;
}
lkfile(fd, LOCK_EX, LKLVL0); /* get exclusive lock */
#if NEWIO
ret=lio_write_buffer(fd, io_type, "w", 1, SIGUSR1, &errmsg,0);
#else
ret=write_buffer(fd, io_type, "w", 1, 0, &errmsg);
#endif
if ( ret != 1 ) {
fprintf(stderr, "%s%s: %d %s/%d: %d %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
if ( ret == -ENOSPC ) {
cleanup();
exit(2);
}
}
/***
write(fd, "w", 1);
****/
lkfile(fd, LOCK_UN, LKLVL0);
if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: %d wrote 1 byte to file\n",
Progname, Pid, __FILE__, __LINE__, Iter_cnt);
} else { /* end of grow by lseek */
if ( Fileinfo.openflags & O_APPEND ) {
/*
* Deal with special case of the open flag containing O_APPEND.
* If it does, the current offset does not matter since the write
* will be done end of the file.
*/
if ( Debug > 4 )
printf("%s: %d DEBUG5 %s/%d: dealing with O_APPEND condition\n",
Progname, Pid, __FILE__, __LINE__ );
lkfile(fd, LOCK_EX, LKLVL0); /* get exclusive lock */
/*
* do fstat again to get size of the file.
* This is done inside a file lock (if locks are being used).
*/
if ( fstat(fd, &stbuf) != -1 ) {
Woffset = stbuf.st_size;
} else {
fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
lkfile(fd, LOCK_UN, LKLVL0); /* release lock */
return -1;
}
if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: dealing with O_APPEND condition (offset:fsz:%d)\n",
Progname, Pid, __FILE__, __LINE__, (int)stbuf.st_size);
} else if ( Mode & MODE_RAND_LSEEK ) {
if ( max_lseek == LSK_EOF ) { /* within file size */
noffset=random_range(min_lseek, fsize, 1, NULL);
}
else if ( max_lseek == LSK_EOFPLUSGROW ) {
/* max to beyond file size */
noffset=random_range(min_lseek, fsize+grow_incr, 1, NULL);
}
else if ( max_lseek == LSK_EOFMINUSGROW ) {
/*
* Attempt to not grow the file.
* If the i/o will fit from min_lseek to EOF,
* pick offset to allow it to fit.
* Otherwise, pick the min_lseek offset and grow
* file by smallest amount.
* If min_lseek is != 0, there will be a problem
* with whole file checking if file is ever smaller
* than min_lseek.
*/
if ( fsize <= min_lseek + grow_incr )
noffset=min_lseek; /* file will still grow */
else
noffset=random_range(min_lseek, fsize-grow_incr, 1, NULL);
}
else {
noffset=random_range(min_lseek, max_lseek, 1, NULL);
}
if ((Woffset=lseek(fd, noffset, SEEK_SET)) == -1 ) {
fprintf(stderr, "%s%s: %d %s/%d: lseek(%d, %d, SEEK_SET) l2 failed: %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, fd, noffset, strerror(errno));
return -1;
}
else if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: lseeked to random offset %d (fsz:%d)\n",
Progname, Pid, __FILE__, __LINE__, Woffset,
(int)stbuf.st_size);
}
/*
* lseek to end of file only if not fifo
*/
else if ( ! (Mode & MODE_FIFO) ) {
if ((Woffset=lseek(fd, 0, SEEK_END)) == -1 ) {
fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, 0, SEEK_END) failed: %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
return -1;
}
else if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: lseeked to end of file, offset %d\n",
Progname, Pid, __FILE__, __LINE__, Woffset);
}
if ( Pattern == PATTERN_OFFSET )
datapidgen(STATIC_NUM, buf, grow_incr, Woffset);
else if ( Pattern == PATTERN_PID )
datapidgen(Pid, buf, grow_incr, Woffset);
else if ( Pattern == PATTERN_ASCII )
dataasciigen(NULL, (char *)buf, grow_incr, Woffset);
else if ( Pattern == PATTERN_RANDOM )
databingen('r', buf, grow_incr, Woffset);
else if ( Pattern == PATTERN_ALT )
databingen('a', buf, grow_incr, Woffset);
else if ( Pattern == PATTERN_CHKER )
databingen('c', buf, grow_incr, Woffset);
else if ( Pattern == PATTERN_CNTING )
databingen('C', buf, grow_incr, Woffset);
else if ( Pattern == PATTERN_ZEROS )
databingen('z', buf, grow_incr, Woffset);
else if ( Pattern == PATTERN_ONES )
databingen('o', buf, grow_incr, Woffset);
else
dataasciigen(NULL, (char *)buf, grow_incr, Woffset);
if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: attempting to write %d bytes\n",
Progname, Pid, __FILE__, __LINE__, grow_incr);
lkfile(fd, LOCK_EX, LKLVL0); /* get exclusive lock */
/*****
ret=write(fd, buf, grow_incr);
tmp=tell(fd);
lkfile(fd, LOCK_UN, LKLVL0);
if ( ret != grow_incr) {
fprintf(stderr, "%s: %s/%d: write failed: %s\n",
Progname, __FILE__, __LINE__, strerror(errno));
return -1;
}
*****/
#if NEWIO
ret=lio_write_buffer(fd, io_type, (char *)buf, grow_incr,
SIGUSR1, &errmsg,0);
#else
ret=write_buffer(fd, io_type, buf, grow_incr, 0, &errmsg);
#endif
if( Mode & MODE_FIFO ){
/* If it is a fifo then just pretend the file
* offset is where we think it should be.
*/
tmp = Woffset + grow_incr;
}
else{
if( (tmp=lseek(fd,0,SEEK_CUR)) < 0 ){ /* get offset after the write */
fprintf(stderr, "%s%s: %s/%d: tell(2) failed: %d %s\n",
Progname, TagName, __FILE__, __LINE__, errno, strerror(errno) );
return -1;
}
}
lkfile(fd, LOCK_UN, LKLVL0);
if ( ret != grow_incr ) {
fprintf(stderr, "%s%s: %d %s/%d: %d %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
if ( ret == -ENOSPC ) {
cleanup();
exit(2);
}
return -1;
}
/*
* Check for a condition where the file was truncated just before
* the write.
*/
if ( tmp != Woffset + grow_incr) {
/*
* The offset after the write was not as expected.
* This could be caused by the following:
* - file truncated after the lseek and before the write.
* - the file was written to after fstat and before the write
* and the file was opened with O_APPEND.
*
* The pattern written to the file will be considered corrupted.
*/
if ( Debug > 0 && lockfile ) {
printf("%s%s: %d DEBUG1 %s/%d: offset after write(%d) not as exp(%d+%d=%d)\n",
Progname, TagName, Pid, __FILE__, __LINE__, tmp, Woffset, grow_incr, Woffset+grow_incr);
printf("%s%s: %d DEBUG1 %s/%d: %d Assuming file changed by another process, resetting offset:%d (expect pattern mismatch)\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, tmp-grow_incr);
}
if( Debug > 4 ){
printf("%s: %d DEBUG5 %s/%d: about to chop Woffset. tmp=%d, grow_incr=%d, Woffset was %d\n",
Progname, Pid, __FILE__, __LINE__, tmp, grow_incr, Woffset);
}
Woffset=tmp-grow_incr;
if( Woffset < 0 )
Woffset = 0;
}
} /* end of grow by write */
/*
* Woffset - holds start of grow (start of write expect in grow by lseek)
* Grow_incr - holds size of grow (write).
* fsize - holds size of file before write
*/
size_grew=(Woffset + Grow_incr) - fsize;
if ( Debug > 1) {
if ( Mode & MODE_FIFO ) {
printf("%s: %d DEBUG2 %s/%d: file is fifo, %d wrote %d bytes\n",
Progname, Pid, __FILE__, __LINE__, Grow_incr, Iter_cnt);
}
else if ( size_grew > 0 )
printf("%s: %d DEBUG2 %s/%d: %d wrote %d bytes(off:%d), grew file by %d bytes\n",
Progname, Pid, __FILE__, __LINE__, Iter_cnt, Grow_incr, Woffset, size_grew);
else
printf("%s: %d DEBUG2 %s/%d: %d wrote %d bytes(off:%d), did not grow file\n",
Progname, Pid, __FILE__, __LINE__, Iter_cnt, Grow_incr, Woffset);
}
bytes_consumed += size_grew;
return 0;
} /* end of growfile */
/***********************************************************************
* shrinkfile file by trunc_incr. file can not be made smaller than
* size zero. Therefore, if trunc_incr is larger than file size,
* file will be truncated to zero.
* The file descriptor current offset is assumed to be the end of the
* file.
*
***********************************************************************/
int
shrinkfile(fd, filename, trunc_incr, trunc_inter, just_trunc)
int fd;
char *filename;
int trunc_incr;
int trunc_inter; /* interval */
int just_trunc; /* lseek has already been done for you */
{
static int shrink_cnt = 0;
int cur_offset;
int new_offset;
int ret;
shrink_cnt++;
if ( trunc_inter == 0 || (shrink_cnt % trunc_inter != 0)) {
if ( Debug > 3 )
printf("%s: %d DEBUG4 %s/%d: Not shrinking file - not time, iter=%d, cnt=%d\n",
Progname, Pid, __FILE__, __LINE__, trunc_inter, shrink_cnt);
return 0; /* not this time */
}
if ( Mode & MODE_FIFO ) {
if ( Debug > 5 )
printf("%s: %d DEBUG5 %s/%d: Not attempting to shrink a FIFO\n",
Progname, Pid, __FILE__, __LINE__);
return 0; /* can not truncate fifo */
}
lkfile(fd, LOCK_EX, LKLVL0);
if ((cur_offset=lseek(fd,0,SEEK_CUR)) == -1 ) {
fprintf(stderr, "%s%s: %d %s/%d: tell(%d) failed: %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, fd, strerror(errno));
lkfile(fd, LOCK_UN, LKLVL0);
return -1;
}
if ( Mode & MODE_RAND_LSEEK ) {
if ( max_lseek <= -1 ) {
if ( (new_offset=file_size(fd)) == -1 ) {
lkfile(fd, LOCK_UN, LKLVL0);
return -1;
}
if ( new_offset < min_lseek )
new_offset=min_lseek;
else
new_offset=random_range(min_lseek, new_offset, 1, NULL);
}
else {
new_offset=random_range(min_lseek, max_lseek, 1, NULL);
}
}
else { /* remove trunc_incr from file */
new_offset = cur_offset-trunc_incr;
if ( new_offset < 0 )
new_offset=0;
}
ret=ftruncate(fd, new_offset );
if( (ret == 0) && (Debug > 3) ){
printf("%s: %d DEBUG4 %s/%d: ftruncated to offset %d, %d bytes from end\n",
Progname, Pid, __FILE__, __LINE__, new_offset, trunc_incr);
}
lkfile(fd, LOCK_UN, LKLVL0);
if ( ret == -1 ) {
fprintf(stderr, "%s%s: %d %s/%d: ftruncate failed: %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
return -1;
}
if ( Debug > 2 ) {
printf("%s: %d DEBUG2 %s/%d: trunc file by %d bytes, to size of = %d bytes\n",
Progname, Pid, __FILE__, __LINE__, cur_offset-new_offset, new_offset);
}
bytes_consumed -= (cur_offset - new_offset);
return 0;
} /* end of shrinkfile */
/***********************************************************************
*
***********************************************************************/
int
check_write(fd, cf_inter, filename, mode)
int fd;
int cf_inter; /* check file interval */
char *filename; /* needed for error messages */
int mode; /* write mode */
{
int fsize;
static int cf_count = 0;
int ret = 0;
int tmp;
char *errmsg;
char *ptr;
cf_count++;
if ( cf_inter == 0 || (cf_count % cf_inter != 0)) {
if ( Debug > 4 )
printf("%s: %d DEBUG5 %s/%d: no write check, not time iter=%d, cnt=%d\n",
Progname, Pid, __FILE__, __LINE__, cf_inter, cf_count);
return 0; /* no check done */
}
if ( Grow_incr <= 0 ) {
if ( Debug > 3 )
printf("%s: %d DEBUG4 %s/%d: No write validation, Grow_incr = %d, offset = %d\n",
Progname, Pid, __FILE__, __LINE__, Grow_incr, Woffset);
return 0; /* no check */
}
/*
* Get the shared file lock. We need to hold the lock from before
* we do the stat until after the read.
*/
lkfile(fd, LOCK_SH, LKLVL0);
if ((fsize=file_size(fd)) == -1 ) {
lkfile(fd, LOCK_UN, LKLVL0);
return -1;
} else if ( fsize <= Woffset ) {
/*
* The file was truncated between write and now.
* The contents of our last write is totally gone, no check.
*/
if ( Debug > 1 )
printf("%s%s: %d DEBUG2 %s/%d: %d File size (%d) smaller than where last wrote (%d)- no write validation\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, fsize, Woffset);
lkfile(fd, LOCK_UN, LKLVL0);
return 0; /* no validation, but not an error */
} else if ( fsize < (Woffset + Grow_incr)) {
/*
* The file was truncated between write and now.
* Part of our last write has been truncated, adjust our Grow_incr
* to reflect this.
*/
tmp=Grow_incr;
Grow_incr=fsize-Woffset;
if ( Debug > 1 ) {
printf("%s%s: %d DEBUG2 %s/%d: %d fsz:%d, lost(%d)of wrt(off:%d, sz:%d), adj=%d\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, fsize, tmp-Grow_incr, Woffset, tmp, Grow_incr);
}
}
if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: about to do write validation, offset = %d, size = %d\n",
Progname, Pid, __FILE__, __LINE__, Woffset, Grow_incr);
if ( ! (mode & MODE_FIFO) ) {
if ( lseek(fd, Woffset, 0) == -1 ) {
fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, %d, 0) failed: %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, Woffset, strerror(errno));
}
if ( Debug > 3 )
printf("%s: %d DEBUG4 %s/%d: lseeked to offset:%d\n",
Progname, Pid, __FILE__, __LINE__, Woffset);
}
/*
* Read last writes data
*/
#if NEWIO
ret=lio_read_buffer(fd, io_type, Buffer, Grow_incr, SIGUSR1, &errmsg,0);
#else
ret=read_buffer(fd, io_type, Buffer, Grow_incr, 0, &errmsg);
#endif
/*
* report the error and debug information before releasing
* the file lock
*/
if ( ret != Grow_incr ) {
fprintf(stderr, "%s%s: %d %s/%d: %d CW %s\n", Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
{
struct stat stbuf;
fstat(fd, &stbuf);
if ( Debug > 2 )
printf("%s%s: %d DEBUG3 %s/%d: fd:%d, offset:%d, fsize:%d, openflags:%#o\n",
Progname, TagName, Pid, __FILE__, __LINE__, fd,
(int)lseek(fd,SEEK_CUR,0), /* FIXME: 64bit/LFS ? */
(int)stbuf.st_size,
Fileinfo.openflags);
}
lkfile(fd, LOCK_UN, LKLVL0);
return 1;
}
lkfile(fd, LOCK_UN, LKLVL0);
if ( Mode & MODE_GROW_BY_LSEEK ) {
/* check that all zeros upto last character */
for(ptr=Buffer; ptr < (Buffer+Grow_incr-1); ptr++) {
if ( *ptr != '\0' ) {
fprintf(stderr,
"%s%s: %d %s/%d: data mismatch at offset %d, exp:%#o(zerofilled), act:%#o in file %s\n",
Progname, TagName, Pid, __FILE__, __LINE__,
(int)(Woffset+(Grow_incr-(Buffer-ptr))),
0, *ptr, filename);
fflush(stderr);
return 1;
}
}
/* check that the last char is a 'w' */
if ( *ptr != 'w' ) {
fprintf(stderr,
"%s%s: %d %s/%d: data mismatch at offset %d, exp:%#o(zerofilled), act:%#o in file %s\n",
Progname, TagName, Pid, __FILE__, __LINE__,
(int)(Woffset+(Grow_incr-(Buffer-ptr))), 'w',
*ptr, filename);
fflush(stderr);
return 1;
}
return 0; /* all is well */
}
else if ( Pattern == PATTERN_OFFSET )
ret=datapidchk(STATIC_NUM, Buffer, Grow_incr, Woffset, &errmsg);
else if ( Pattern == PATTERN_PID )
ret=datapidchk(Pid, Buffer, Grow_incr, Woffset, &errmsg);
else if ( Pattern == PATTERN_ASCII )
ret=dataasciichk(NULL, Buffer, Grow_incr, Woffset, &errmsg);
else if ( Pattern == PATTERN_RANDOM )
; /* no check for random */
else if ( Pattern == PATTERN_ALT )
ret=databinchk('a', Buffer, Grow_incr, Woffset, &errmsg);
else if ( Pattern == PATTERN_CHKER )
ret=databinchk('c', Buffer, Grow_incr, Woffset, &errmsg);
else if ( Pattern == PATTERN_CNTING )
ret=databinchk('C', Buffer, Grow_incr, Woffset, &errmsg);
else if ( Pattern == PATTERN_ZEROS )
ret=databinchk('z', Buffer, Grow_incr, Woffset, &errmsg);
else if ( Pattern == PATTERN_ONES )
ret=databinchk('o', Buffer, Grow_incr, Woffset, &errmsg);
else
ret=dataasciichk(NULL, Buffer, Grow_incr, Woffset, &errmsg);
if ( ret >= 0 ) {
fprintf(stderr, "%s%s: %d %s/%d: %d CW %s in file %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
if ( Debug > 0 )
printf("%s%s: %d DEBUG1 %s/%d: **fd:%d, lk:%d, offset:%d, sz:%d open flags:%#o %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, fd, lockfile,
Woffset, Grow_incr, Fileinfo.openflags, openflags2symbols(Fileinfo.openflags, ",", 0));
fflush(stderr);
return 1;
}
if ( Debug > 6 )
printf("%s: %d DEBUG7 %s/%d: No corruption detected on write validation , offset = %d, size = %d\n",
Progname, Pid, __FILE__, __LINE__, Woffset, Grow_incr);
return 0; /* all is well */
}
/***********************************************************************
*
***********************************************************************/
int
check_file(fd, cf_inter, filename, no_file_check)
int fd;
int cf_inter; /* check file interval */
char *filename; /* needed for error messages */
int no_file_check; /* if set, do not do file content check */
{
int fsize;
static int cf_count = 0;
char *buf;
int ret;
int ret_val = 0;
int rd_cnt;
int rd_size;
char *errmsg;
cf_count++;
if ( cf_inter == 0 || (cf_count % cf_inter != 0)) {
if ( Debug > 4 )
printf("%s: %d DEBUG5 %s/%d: No file check - not time, iter=%d, cnt=%d\n",
Progname, Pid, __FILE__, __LINE__, cf_inter, cf_count);
return 0; /* no check done */
}
/*
* if we can't determine file content, don't bother checking
*/
if ( no_file_check ) {
if ( Debug > 4 )
printf("%s: %d DEBUG5 %s/%d: No file check, lseek grow or random lseeks\n",
Progname, Pid, __FILE__, __LINE__);
return 0;
}
/*
* Lock the file. We need to have the file lock before
* the stat and until after the last read to prevent
* a trunc/truncate from "corrupting" our data.
*/
lkfile(fd, LOCK_SH, LKLVL0);
if ((fsize=file_size(fd)) == -1 ) {
lkfile(fd, LOCK_UN, LKLVL0);
return -1;
}
if ( fsize == 0 ) {
if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: No file validation, file size == 0\n",
Progname, Pid, __FILE__, __LINE__);
lkfile(fd, LOCK_UN, LKLVL0);
return 0;
}
if ( Debug > 2 )
printf("%s: %d DEBUG3 %s/%d: about to do file validation\n",
Progname, Pid, __FILE__, __LINE__);
if ( fsize > MAX_FC_READ ) {
/*
* read the file in MAX_FC_READ chuncks.
*/
if ((buf=(char *)malloc(MAX_FC_READ)) == NULL ) {
fprintf(stderr, "%s%s: %s/%d: malloc(%d) failed: %s\n", Progname, TagName,
__FILE__, __LINE__, MAX_FC_READ, strerror(errno));
lkfile(fd, LOCK_UN, LKLVL0);
return -1;
}
lseek(fd, 0, SEEK_SET);
lkfile(fd, LOCK_SH, LKLVL0); /* get lock on file before getting file size */
rd_cnt=0;
while (rd_cnt < fsize ) {
if ( fsize - rd_cnt > MAX_FC_READ )
rd_size=MAX_FC_READ;
else
rd_size=fsize - rd_cnt;
#if NEWIO
ret=lio_read_buffer(fd, io_type, buf, rd_size,
SIGUSR1, &errmsg,0);
#else
ret=read_buffer(fd, io_type, buf, rd_size, 0, &errmsg);
#endif
if (ret != rd_size ) {
fprintf(stderr, "%s%s: %d %s/%d: %d CFa %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
free(buf);
lkfile(fd, LOCK_UN, LKLVL0);
return -1;
}
/**
read(fd, buf, rd_size);
***/
if ( Pattern == PATTERN_OFFSET )
ret=datapidchk(STATIC_NUM, buf, rd_size, rd_cnt, &errmsg);
else if ( Pattern == PATTERN_PID )
ret=datapidchk(Pid, buf, rd_size, rd_cnt, &errmsg);
else if ( Pattern == PATTERN_ASCII )
ret=dataasciichk(NULL, buf, rd_size, rd_cnt, &errmsg);
else if ( Pattern == PATTERN_RANDOM )
; /* no checks for random */
else if ( Pattern == PATTERN_ALT )
ret=databinchk('a', buf, rd_size, rd_cnt, &errmsg);
else if ( Pattern == PATTERN_CHKER )
ret=databinchk('c', buf, rd_size, rd_cnt, &errmsg);
else if ( Pattern == PATTERN_CNTING )
ret=databinchk('C', buf, rd_size, rd_cnt, &errmsg);
else if ( Pattern == PATTERN_ZEROS )
ret=databinchk('z', buf, rd_size, rd_cnt, &errmsg);
else if ( Pattern == PATTERN_ONES )
ret=databinchk('o', buf, rd_size, rd_cnt, &errmsg);
else
ret=dataasciichk(NULL, buf, rd_size, rd_cnt, &errmsg);
if ( ret >= 0 ) {
fprintf(stderr,
"%s%s: %d %s/%d: %d CFp %s in file %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
fflush(stderr);
ret_val=1;
lkfile(fd, LOCK_UN, LKLVL0);
break;
}
rd_cnt += rd_size;
}
lkfile(fd, LOCK_UN, LKLVL0);
free(buf);
}
else {
/*
* Read the whole file in a single read
*/
if((buf=(char *)malloc(fsize)) == NULL ) {
fprintf(stderr, "%s%s: %s/%d: malloc(%d) failed: %s\n", Progname, TagName,
__FILE__, __LINE__, fsize, strerror(errno));
fflush(stderr);
return -1;
}
lseek(fd, 0, SEEK_SET);
/****
read(fd, buf, fsize);
****/
#if NEWIO
ret=lio_read_buffer(fd, io_type, buf, fsize, SIGUSR1, &errmsg,0);
#else
ret=read_buffer(fd, io_type, buf, fsize, 0, &errmsg);
#endif
/* unlock the file as soon as we can */
lkfile(fd, LOCK_UN, LKLVL0);
if ( ret != fsize ) {
fprintf(stderr, "%s%s: %d %s/%d: %d CFw %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
ret_val=1;
}
else {
if ( Pattern == PATTERN_OFFSET )
ret=datapidchk(STATIC_NUM, buf, fsize, 0, &errmsg);
else if ( Pattern == PATTERN_PID )
ret=datapidchk(Pid, buf, fsize, 0, &errmsg);
else if ( Pattern == PATTERN_ASCII )
ret=dataasciichk(NULL, buf, fsize, 0, &errmsg);
else if ( Pattern == PATTERN_RANDOM )
; /* no check for random */
else if ( Pattern == PATTERN_ALT )
ret=databinchk('a', buf, fsize, 0, &errmsg);
else if ( Pattern == PATTERN_CHKER )
ret=databinchk('c', buf, fsize, 0, &errmsg);
else if ( Pattern == PATTERN_CNTING )
ret=databinchk('C', buf, fsize, 0, &errmsg);
else if ( Pattern == PATTERN_ZEROS )
ret=databinchk('z', buf, fsize, 0, &errmsg);
else if ( Pattern == PATTERN_ONES )
ret=databinchk('o', buf, fsize, 0, &errmsg);
else
ret=dataasciichk(NULL, buf, fsize, 0, &errmsg);
if ( ret >= 0 ) {
fprintf(stderr, "%s%s: %d %s/%d: %d CFw %s in file %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
fflush(stderr);
ret_val=1;
}
}
free(buf);
}
return ret_val;
} /* end of check_file */
/***********************************************************************
*
***********************************************************************/
int
file_size(int fd)
{
struct stat sb;
if (fstat(fd, &sb) < 0) {
fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
return -1;
}
return sb.st_size;
}
/***********************************************************************
* do file lock/unlock action.
***********************************************************************/
int
lkfile(int fd, int operation, int lklevel)
{
char *errmsg;
if ( lockfile == lklevel) {
if ( Debug > 5 ) {
switch (operation) {
case LOCK_UN:
printf("%s: %d DEBUG6 %s/%d: Attempting to release lock on fd %d\n",
Progname, Pid, __FILE__, __LINE__, fd);
break;
case LOCK_SH:
printf("%s: %d DEBUG6 %s/%d: Attempting to get read/shared lock on fd %d\n",
Progname, Pid, __FILE__, __LINE__, fd);
break;
case LOCK_EX:
printf("%s: %d DEBUG6 %s/%d: Attempting to get write/exclusive lock on fd %d\n",
Progname, Pid, __FILE__, __LINE__, fd);
break;
}
}
/*
* Attempt to get/release desired lock.
* file_lock will attempt to do action over and over again until
* either an unretryable error or the action is completed.
*/
if ( file_lock(fd, operation, &errmsg) != 0 ) {
printf("%s%s: %d %s/%d: Unable to perform lock operation. %s\n",
Progname, TagName, Pid, __FILE__, __LINE__, errmsg);
/* do we count this as an error? handle_error(); */
return -1;
}
if ( Debug > 2 ) {
switch (operation) {
case LOCK_UN:
printf("%s: %d DEBUG3 %s/%d: Released lock on fd %d\n",
Progname, Pid, __FILE__, __LINE__, fd);
break;
case LOCK_SH:
printf("%s: %d DEBUG3 %s/%d: Got read/shared lock on fd %d\n",
Progname, Pid, __FILE__, __LINE__, fd);
break;
case LOCK_EX:
printf("%s: %d DEBUG3 %s/%d: Got write/exclusive lock on fd %d\n",
Progname, Pid, __FILE__, __LINE__, fd);
break;
default:
printf("%s: %d DEBUG3 %s/%d: Completed action %d on fd %d\n",
Progname, Pid, __FILE__, __LINE__, operation, fd);
break;
}
}
}
return 0;
}
/***********************************************************************
*
***********************************************************************/
int
pre_alloc(file, fd, size)
char *file;
int fd;
int size;
{
#ifdef XFS_IOC_RESVSP
struct xfs_flock64 f;
f.l_whence = 0;
f.l_start = 0;
f.l_len = size;
/* non-zeroing reservation */
if( xfsctl( file, fd, XFS_IOC_RESVSP, &f ) == -1 ){
fprintf(stderr, "%s%s %s/%d: Unable to pre-alloc space: xfsctl(XFS_IOC_RESVSP) failed: %d %s\n",
Progname, TagName,
__FILE__, __LINE__, errno, strerror(errno));
return -1;
}
#else
struct flock64 f;
f.l_whence = 0;
f.l_start = 0;
f.l_len = size;
/* non-zeroing reservation */
if( fcntl( fd, F_RESVSP64, &f ) == -1 ){
fprintf(stderr, "%s%s %s/%d: Unable to pre-alloc space: fcntl(F_RESVSP) failed: %d %s\n",
Progname, TagName,
__FILE__, __LINE__, errno, strerror(errno));
return -1;
}
#endif
return 0;
}