| /* |
| * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of version 2 of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| * |
| * Further, this software is distributed without any warranty that it is |
| * free of the rightful claim of any third person regarding infringement |
| * or the like. Any license provided herein, whether implied or |
| * otherwise, applies only to this software file. Patent licenses, if |
| * any, provided herein do not apply to combinations of this program with |
| * other software, or any other product whatsoever. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, |
| * Mountain View, CA 94043, or: |
| * |
| * http://www.sgi.com |
| * |
| * For further information regarding this notice, see: |
| * |
| * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ |
| */ |
| /* |
| * 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 if 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 <stdio.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <sys/types.h> |
| #include <time.h> |
| #include <sys/file.h> |
| #include <unistd.h> |
| #include <sys/stat.h> |
| #include <sys/time.h> |
| #include <sys/param.h> |
| #include <sys/signal.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <inttypes.h> |
| #include "dataascii.h" |
| #include "random_range.h" |
| #include "databin.h" |
| #include "open_flags.h" |
| #include "forker.h" |
| #include "file_lock.h" |
| |
| #ifdef CRAY |
| #include <sys/panic.h> |
| #include <sys/category.h> |
| #endif |
| |
| #include "test.h" |
| |
| int set_sig(void); |
| void sig_handler(int sig); |
| static void notify_others(void); |
| int handle_error(void); |
| int cleanup(void); |
| void usage(void); |
| void help(void); |
| void prt_examples(FILE * stream); |
| int growfile(int fd, char *file, int grow_incr, char *buf, |
| unsigned long *curr_size_ptr); |
| int shrinkfile(int fd, char *filename, int trunc_incr, |
| int trunc_inter, int just_trunc); |
| int check_write(int fd, int cf_inter, char *filename, int mode); |
| int check_file(int fd, int cf_inter, char *filename, int no_file_check); |
| int file_size(int fd); |
| int lkfile(int fd, int operation, int lklevel); |
| |
| #ifndef linux |
| int pre_alloc(int fd, long size); |
| #endif /* !linux */ |
| |
| extern int datapidgen(int, char *, int, int); |
| extern int datapidchk(int, char *, int, int, char **); |
| |
| /* LTP status reporting */ |
| char *TCID = "growfiles"; /* Default test program identifier. */ |
| int TST_TOTAL = 1; /* Total number of test cases. */ |
| |
| /* To avoid extensive modifications to the code, use this bodge */ |
| #define exit(x) myexit(x) |
| void myexit(int x) |
| { |
| if (x) |
| tst_resm(TFAIL, "Test failed"); |
| else |
| tst_resm(TPASS, "Test passed"); |
| tst_exit(); |
| } |
| |
| #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 = 0; |
| |
| int Pid = 0; |
| |
| int io_type = 0; /* I/O type -sync */ |
| |
| #ifdef O_LARGEFILE |
| int open_flags = O_RDWR | O_CREAT | O_LARGEFILE; /* open flags */ |
| #else |
| #warning O_LARGEFILE is not defined! |
| int open_flags = O_RDWR | O_CREAT; /* open flags */ |
| #endif |
| |
| #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 */ |
| #ifdef CRAY |
| int Pattern = PATTERN_OFFSET; /* This pattern is 64 bit word based */ |
| #else |
| int Pattern = PATTERN_ASCII; |
| #endif |
| 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 */ |
| |
| off_t 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[] = { |
| #ifdef CRAY |
| O_RDWR | O_CREAT, |
| O_RDWR | O_CREAT | O_RAW, |
| O_RDWR | O_CREAT | O_BIG, |
| O_RDWR | O_CREAT | O_APPEND, |
| O_RDWR | O_CREAT | O_NDELAY, |
| O_RDWR | O_CREAT | O_PLACE, |
| O_RDWR | O_CREAT | O_SYNC, |
| O_RDWR | O_CREAT | O_RAW | O_SYNC, |
| O_RDWR | O_CREAT | O_NDELAY | O_SYNC, |
| O_RDWR | O_CREAT | O_NDELAY | O_SYNC | O_BIG, |
| O_RDWR | O_CREAT | O_RAW, |
| O_RDWR | O_CREAT | O_RAW | O_APPEND, |
| O_RDWR | O_CREAT | O_RAW | O_BIG, |
| O_RDWR | O_CREAT | O_RAW | O_APPEND | O_BIG, |
| /*** |
| * O_WELLFORMED makes -o random require well formed i/o |
| ***/ |
| #if ALLOW_O_WELLFORMED |
| #if O_PARALLEL |
| O_RDWR | O_CREAT | O_PARALLEL | O_WELLFORMED | O_RAW, |
| O_RDWR | O_CREAT | O_PARALLEL | O_WELLFORMED | O_RAW | O_TRUNC, |
| #endif /* O_PARALLEL */ |
| #endif |
| |
| #else /* CRAY */ |
| 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, |
| |
| #endif /* CRAY */ |
| }; |
| |
| #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 |
| #ifdef CRAY |
| #define BSIZE 1024 |
| #else |
| #define BSIZE 512 |
| #endif /* CRAY */ |
| #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(int argc, char **argv) |
| { |
| extern char *optarg; /* used by getopt */ |
| extern int optind; |
| |
| 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 */ |
| |
| unsigned long curr_size = 0; /* BUG:14136 (keep track of file size) */ |
| const unsigned long ext2_limit = 2147483647; /* BUG:14136 (2GB ext2 filesize limit) */ |
| |
| int tmp; |
| char chr; |
| int ret; |
| int pre_alloc_space = 0; |
| #ifndef linux |
| long total_grow_value; /* used in pre-allocations */ |
| #endif |
| int backgrnd = 1; /* return control to user */ |
| struct stat statbuf; |
| int time_iterval = -1; |
| time_t start_time = 0; |
| char reason[128]; /* 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 */ |
| struct timeval tv1; |
| |
| 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(); |
| tst_exit(); |
| |
| 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; |
| #ifdef CRAY |
| unsetenv("TMPDIR"); /* force the use of auto_dir */ |
| #endif |
| 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 || |
| Alignment < 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 */ |
| #ifdef linux |
| printf("%s%s: --p is illegal option on linux system\n", |
| Progname, TagName); |
| exit(1); |
| #else |
| pre_alloc_space++; |
| #endif |
| break; |
| |
| case 'P': |
| #ifdef CRAY |
| if (strcmp(optarg, "PANIC") != 0) { |
| fprintf(stderr, "%s%s: --P arg must be PANIC\n", |
| Progname, TagName); |
| exit(1); |
| } |
| Upanic_on_error++; |
| printf("%s%s: Will call upanic after writes\n", Progname, TagName); |
| #else |
| printf |
| ("%s%s: --P is illegal option on non-cray system\n", |
| Progname, TagName); |
| exit(1); |
| #endif |
| 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 = 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': |
| TCID = optarg; |
| sprintf(TagName, "(%.39s)", 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, 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, |
| 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 CRAY |
| if (Sync_with_others) |
| setpgrp(); |
| #endif |
| |
| 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) { |
| struct timeval ts; |
| gettimeofday(&ts, NULL); |
| Seed = ts.tv_sec + 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. |
| */ |
| struct timeval ts; |
| gettimeofday(&ts, NULL); |
| Seed = ts.tv_sec + Pid; /* default random seed */ |
| //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 = |
| (int)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] = 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 = 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++) { |
| gettimeofday(&tv1, NULL); |
| sprintf((char *)filenames + (num * PATH_MAX), |
| "%s/%s%ld%ld%d.%d", auto_dir, auto_file, |
| (long)tv1.tv_sec, (long)tv1.tv_usec, rand(), 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) { |
| struct timeval ts; |
| gettimeofday(&ts, NULL); |
| start_time = ts.tv_sec; |
| //start_time=time(0); |
| } |
| |
| /* |
| * get space for I/O buffer |
| */ |
| if (grow_incr) { |
| if ((Buffer = 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); |
| } |
| #ifndef linux |
| 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; |
| } |
| } |
| #endif |
| |
| /* |
| * If delaying between iterations, get amount time to |
| * delaysecs in clocks or usecs. |
| * If on the CRAY, delaytime is in clocks since |
| * _rtc() will be used, which does not have the overhead |
| * of gettimeofday(2). |
| */ |
| if (delaysecs) { |
| #if CRAY |
| int hz; |
| hz = sysconf(_SC_CLK_TCK); |
| delaytime = (int)((float)hz * delaysecs); |
| #else |
| delaytime = (int)((float)USECS_PER_SEC * delaysecs); |
| #endif |
| } |
| |
| /* |
| * 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++) { |
| struct timeval ts; |
| if (iterations && (Iter_cnt >= iterations + 1)) { |
| strcpy(reason, "Hit iteration value"); |
| stop = 1; |
| continue; |
| } |
| gettimeofday(&ts, NULL); |
| if ((time_iterval > 0) |
| && (start_time + time_iterval < ts.tv_sec)) { |
| |
| 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 */ |
| |
| #ifndef linux |
| /* |
| * preallocation is only done once, if specified. |
| */ |
| if (pre_alloc_space) { |
| if (pre_alloc(fd, total_grow_value) != 0) { |
| cleanup(); |
| exit(2); |
| } |
| if (Debug > 1) { |
| printf |
| ("%s: %d DEBUG2 %s/%d: pre_allocated %ld 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; |
| } |
| #endif |
| |
| /* |
| * 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. |
| */ |
| |
| /* BUG:14136 (don't go past ext2's filesize limit) */ |
| curr_size = file_size(fd); |
| if (curr_size + grow_incr >= ext2_limit) { |
| lkfile(fd, LOCK_UN, LKLVL1); /* release lock */ |
| close(fd); |
| sprintf(reason, |
| "Reached %ld filesize which is almost %ld limit.", |
| curr_size, ext2_limit); |
| stop = 1; |
| continue; |
| } |
| |
| if (growfile(fd, filename, grow_incr, Buffer, &curr_size) != 0) { /* BUG:14136 */ |
| 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; |
| #ifdef CRAY |
| ct = _rtc(); |
| end = ct + delaytime; |
| while (ct < end) { |
| ct = _rtc(); |
| } |
| #else |
| 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; |
| } |
| #endif |
| } |
| } |
| #ifndef linux |
| /* |
| * 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; |
| } |
| #endif |
| |
| } /* 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); |
| tst_exit(); /* to keep compiler happy */ |
| } |
| |
| /*********************************************************************** |
| * |
| ***********************************************************************/ |
| int set_sig(void) |
| { |
| 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 CRAY |
| case SIGINFO: |
| case SIGRECOVERY: |
| #endif /* CRAY */ |
| #ifdef SIGCKPT |
| case SIGCKPT: |
| #endif /* SIGCKPT */ |
| #ifdef SIGRESTART |
| case SIGRESTART: |
| #endif /* SIGRESTART */ |
| case SIGCHLD: |
| break; |
| |
| default: |
| #ifdef sgi |
| sigset(sig, sig_handler); |
| #else |
| /* linux and cray */ |
| signal(sig, sig_handler); |
| #endif |
| break; |
| } |
| } /* endfor */ |
| |
| return 0; |
| } |
| |
| /*********************************************************************** |
| * |
| ***********************************************************************/ |
| void sig_handler(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); |
| #ifndef sgi |
| signal(sig, sig_handler); /* allow us to get this signal more than once */ |
| #endif |
| |
| } 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(void) |
| { |
| static int send_signals = 0; |
| int ind; |
| |
| if (Sync_with_others && send_signals == 0) { |
| |
| #if CRAY |
| send_signals = 1; /* only send signals once */ |
| if (Debug > 1) |
| printf |
| ("%s%s: %d DEBUG2 %s/%d: Sending SIGUSR2 to pgrp\n", |
| Progname, TagName, Pid, __FILE__, __LINE__); |
| killm(C_PGRP, getpgrp(), SIGUSR2); |
| #else |
| 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); |
| } |
| #endif |
| } |
| |
| } |
| |
| /*********************************************************************** |
| * 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(void) |
| { |
| Errors++; |
| |
| #ifdef CRAY |
| if (Errors & Upanic_on_error) { |
| upanic(PA_PANIC); |
| } |
| #endif |
| |
| 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(void) |
| { |
| 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(void) |
| { |
| 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(void) |
| { |
| 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 /* BUG:14136 */ growfile(int fd, char *file, int grow_incr, char *buf, |
| unsigned long *curr_size_ptr) |
| { |
| off_t noffset; |
| int ret; |
| int cur_offset; |
| char *errmsg; |
| off_t fsize; /* current size of file */ |
| int size_grew; /* size the file grew */ |
| struct stat stbuf; |
| off_t off_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 %ld\n", |
| Progname, Pid, __FILE__, __LINE__, (long)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, %ld, " |
| "SEEK_SET) l2 failed: %s\n", Progname, |
| TagName, Pid, __FILE__, __LINE__, fd, |
| (long)noffset, strerror(errno)); |
| return -1; |
| } else if (Debug > 2) |
| printf("%s: %d DEBUG3 %s/%d: lseeked to " |
| "random offset %ld (fsz:%d)\n", |
| Progname, Pid, __FILE__, __LINE__, |
| (long)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 %ld\n", |
| Progname, Pid, __FILE__, __LINE__, |
| (long)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, 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, 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); |
| |
| off_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, 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. |
| */ |
| off_tmp = Woffset + grow_incr; |
| } else { |
| if ((off_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; |
| } |
| #if NEWIO |
| #if defined(sgi) || defined(__linux__) |
| /* If this is POSIX I/O and it is via aio_{read,write} |
| * or lio_listio then after completion of the I/O the |
| * value of the file offset for the file is |
| * unspecified--which means we cannot trust what |
| * tell() told us. Fudge it here. |
| */ |
| if ((io_type & LIO_IO_ASYNC_TYPES) |
| || (io_type & LIO_RANDOM)) { |
| if (off_tmp != Woffset + grow_incr) { |
| if (Debug > 5) { |
| printf |
| ("%s: %d DEBUG6 %s/%d: posix fudge, forcing tmp (%" |
| PRId64 |
| ") to match Woffset+grow_incr (%" |
| PRId64 ")\n", Progname, |
| Pid, __FILE__, __LINE__, |
| (int64_t) off_tmp, |
| (int64_t) Woffset + |
| grow_incr); |
| } |
| off_tmp = Woffset + grow_incr; |
| } |
| } |
| #endif /* sgi __linux__ */ |
| #endif |
| } |
| *curr_size_ptr = off_tmp; /* BUG:14136 */ |
| |
| 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 (off_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(%ld) not as exp(%ld+%d=%ld)\n", |
| Progname, TagName, Pid, __FILE__, |
| __LINE__, (long)off_tmp, (long)Woffset, |
| grow_incr, (long)(Woffset + grow_incr)); |
| printf |
| ("%s%s: %d DEBUG1 %s/%d: %d Assuming file " |
| "changed by another process, resetting " |
| "offset:%ld (expect pattern mismatch)\n", |
| Progname, TagName, Pid, __FILE__, __LINE__, |
| Iter_cnt, (long)(off_tmp - grow_incr)); |
| } |
| if (Debug > 4) { |
| printf |
| ("%s: %d DEBUG5 %s/%d: about to chop Woffset. " |
| "tmp=%ld, grow_incr=%d, Woffset was %ld\n", |
| Progname, Pid, __FILE__, __LINE__, |
| (long)off_tmp, grow_incr, (long)Woffset); |
| } |
| Woffset = off_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:%ld), " |
| "grew file by %d bytes\n", Progname, Pid, __FILE__, |
| __LINE__, Iter_cnt, Grow_incr, (long)Woffset, |
| size_grew); |
| else |
| printf |
| ("%s: %d DEBUG2 %s/%d: %d wrote %d bytes(off:%ld), " |
| "did not grow file\n", Progname, Pid, __FILE__, |
| __LINE__, Iter_cnt, Grow_incr, (long)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(int fd, char *filename, int trunc_incr, int trunc_inter, |
| int just_trunc) |
| { |
| static int shrink_cnt = 0; |
| int cur_offset; |
| int new_offset; |
| int ret; |
| #ifdef CRAY |
| int offset; |
| #endif |
| |
| 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); |
| } |
| |
| #ifdef CRAY |
| if ((offset = lseek(fd, new_offset, SEEK_SET)) == -1) { |
| fprintf(stderr, |
| "%s%s: %d %s/%d: lseek(%d, %d, SEEK_SET) l3 failed: %s\n", |
| Progname, TagName, Pid, __FILE__, __LINE__, fd, |
| new_offset, strerror(errno)); |
| lkfile(fd, LOCK_UN, LKLVL0); |
| return -1; |
| } else if (Debug > 3) |
| printf |
| ("%s: %d DEBUG4 %s/%d: lseeked to random offset %d\n", |
| Progname, Pid, __FILE__, __LINE__, offset); |
| |
| #endif |
| } |
| |
| else { /* remove trunc_incr from file */ |
| |
| new_offset = cur_offset - trunc_incr; |
| |
| if (new_offset < 0) |
| new_offset = 0; |
| |
| #ifdef CRAY |
| if (lseek(fd, new_offset, SEEK_SET) == -1) { |
| fprintf(stderr, |
| "%s%s: %d %s/%d: lseek(fd, %d, SEEK_SET) l4 failed: %s\n", |
| Progname, TagName, Pid, __FILE__, __LINE__, |
| new_offset, strerror(errno)); |
| lkfile(fd, LOCK_UN, LKLVL0); |
| return -1; |
| } else if (Debug > 3) |
| printf |
| ("%s: %d DEBUG4 %s/%d: lseeked to offset %d, %d bytes from end\n", |
| Progname, Pid, __FILE__, __LINE__, new_offset, |
| trunc_incr); |
| #endif |
| } |
| |
| #ifdef CRAY |
| ret = trunc(fd); |
| #else |
| 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); |
| } |
| #endif |
| |
| lkfile(fd, LOCK_UN, LKLVL0); |
| |
| if (ret == -1) { |
| #ifdef CRAY |
| fprintf(stderr, "%s%s: %d %s/%d: trunc failed: %s\n", |
| Progname, TagName, Pid, __FILE__, __LINE__, |
| strerror(errno)); |
| #else |
| fprintf(stderr, "%s%s: %d %s/%d: ftruncate failed: %s\n", |
| Progname, TagName, Pid, __FILE__, __LINE__, |
| strerror(errno)); |
| #endif |
| 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(int fd, int cf_inter, char *filename, int 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 = %ld\n", |
| Progname, Pid, __FILE__, __LINE__, Grow_incr, |
| (long)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 (%ld)- no write validation\n", |
| Progname, TagName, Pid, __FILE__, __LINE__, |
| Iter_cnt, fsize, (long)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:%ld, sz:%d), adj=%d\n", Progname, |
| TagName, Pid, __FILE__, __LINE__, Iter_cnt, |
| fsize, tmp - Grow_incr, (long)Woffset, tmp, |
| Grow_incr); |
| } |
| |
| } |
| |
| if (Debug > 2) |
| printf("%s: %d DEBUG3 %s/%d: about to do write validation, " |
| "offset = %ld, size = %d\n", |
| Progname, Pid, __FILE__, __LINE__, (long)Woffset, |
| Grow_incr); |
| |
| if (!(mode & MODE_FIFO)) { |
| |
| if (lseek(fd, Woffset, 0) == -1) { |
| fprintf(stderr, |
| "%s%s: %d %s/%d: lseek(fd, %ld, 0) failed: %s\n", |
| Progname, TagName, Pid, __FILE__, __LINE__, |
| (long)Woffset, strerror(errno)); |
| } |
| if (Debug > 3) |
| printf("%s: %d DEBUG4 %s/%d: lseeked to offset:%ld\n", |
| Progname, Pid, __FILE__, __LINE__, |
| (long)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:%ld, sz:%d open flags:%#o %s\n", |
| Progname, TagName, Pid, __FILE__, __LINE__, fd, |
| lockfile, (long)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 = %ld, size = %d\n", |
| Progname, Pid, __FILE__, __LINE__, (long)Woffset, |
| Grow_incr); |
| |
| return 0; /* all is well */ |
| } |
| |
| /*********************************************************************** |
| * |
| ***********************************************************************/ |
| int check_file(int fd, int cf_inter, char *filename, int no_file_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 = 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) { |
| rd_size = MIN(MAX_FC_READ, 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 = 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; |
| } |
| |
| #ifndef linux |
| /*********************************************************************** |
| * |
| ***********************************************************************/ |
| int pre_alloc(int fd, long size) |
| { |
| |
| #ifdef CRAY |
| long avl; |
| |
| if (ialloc(fd, size, IA_CONT, &avl) == -1) { |
| fprintf(stderr, |
| "%s%s %s/%d: Unable to pre-alloc space: ialloc failed: %d %s\n", |
| Progname, TagName, __FILE__, __LINE__, errno, |
| strerror(errno)); |
| return -1; |
| } |
| #endif |
| |
| #ifdef sgi |
| struct flock f; |
| |
| f.l_whence = 0; |
| f.l_start = 0; |
| f.l_len = size; |
| |
| /* non-zeroing reservation */ |
| if (fcntl(fd, F_RESVSP, &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; |
| } |
| #endif |