]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/nhfsstone/nhfsstone.c
Merge branch 'upstream'
[nfs-utils.git] / utils / nhfsstone / nhfsstone.c
diff --git a/utils/nhfsstone/nhfsstone.c b/utils/nhfsstone/nhfsstone.c
deleted file mode 100644 (file)
index 463bcb5..0000000
+++ /dev/null
@@ -1,1820 +0,0 @@
-#if 0
-static char sccsid[] = "@(#)nhfsstone.c 1.22 90/05/08 Copyright (c) 1990, Legato Systems Inc";
-#endif
-
-/*
- * Copyright (c) 1990 Legato Systems Inc.
- *
- * See DISCLAIMER file for restrictions
- *
- * Ported to Linux by Olaf Kirch <okir@monad.swb.de>
- */
-
-#include "config.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/vfs.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#ifdef BSD
-#include <sys/dir.h>
-#define        dirent  direct
-#else
-#include <dirent.h>
-#endif
-#include <signal.h>
-
-#ifndef NULL
-#define NULL   0
-#endif
-
-/*
- * Usage: nhfsstone [-v] [[-t secs] | [-c calls]] [-l load] [-p nprocs]
- *                                             [-m mixfile] [dir]...
- *
- * Generates an artifical NFS client load based on a given mix of
- * operations.
- *
- * Strategy: loop for some number of NFS calls doing a random sleep
- * followed by a call to one of the op generator routines. The routines
- * are called based on a weighting factor determined by the difference
- * between the current ops percentages (derived from kernel NFS stats)
- * and a set of default percentages or a mix supplied by the caller.
- *
- * The generator routines try very hard to guess how many NFS operations
- * they are generating so that the calling routine can keep a running
- * estimate of the number of calls and the mix to avoid having to get
- * the NFS statistics from the kernel too often.
- *
- * The operations are done in a directory that has a set of file names
- * that are long enough that they won't be cached by the name cache
- * in the kernel. The "lookup" operation steps through the names and
- * creates a file if that name does not exist, or closes and reopens it
- * if it does. This generates a table of open file descriptors. Most of the
- * other operations are done on random descriptors in the table. The "getattr"
- * operation tries to avoid the kernel attribute cache by doing "fstat"
- * system calls on random descriptors in the table. There must be enough
- * files in the directory so that, on average, the getattr operation hits
- * any file less often than once each 6 seconds (the default timeout for
- * the attributes cache).
- *
- * The parent process starts children to do the real work of generating load.
- * The parent coordinates them so that they all start at the same time, and
- * collects statistics from them when they are done. To coordinate the
- * start up, the parent waits for each child to write one byte into
- * a common log file (opened in append mode to avoid overwriting).
- * After they write a byte the children pause, and the parent send SIGUSR1
- * when it has heard from all of the kids. The children write their statistics
- * into the same common log file and the parent reads and accumulates the
- * statics and prints them out.
- *
- * This code will only compile and run on 4.X BSD based systems.
- */
-
-#define        DEFAULT_LOAD    30              /* default calls per sec */
-#define        DEFAULT_CALLS   5000            /* default number of calls */
-#define        NFILES          40              /* number of test files/dir */
-#define        BUFSIZE         8192            /* block size for read and write */
-#define        MAXFILESIZE     32              /* size, in blocks, of large file */
-#define        SAMPLETIME      5               /* secs between samples of NFS stats */
-#define        NPROCS          7               /* number of children to run */
-
-
-/*
- * The names of NFS operations
- */
-char *Opnames[] = {
-       "null", "getattr", "setattr", "root", "lookup", "readlink", "read",
-       "wrcache", "write", "create", "remove", "rename", "link", "symlink",
-       "mkdir", "rmdir", "readdir", "fsstat",
-};
-
-/*
- * NFS operation numbers
- *
- * Used to index the Opnames, Mix and statistics arrays.
- */
-#define        NOPS            18              /* number of NFS ops */
-#define        NULLCALL        0
-#define        GETATTR         1
-#define        SETATTR         2
-#define        ROOT            3
-#define        LOOKUP          4
-#define        READLINK        5
-#define        READ            6
-#define        WRCACHE         7
-#define        WRITE           8
-#define        CREATE          9
-#define        REMOVE          10
-#define        RENAME          11
-#define        LINK            12
-#define        SYMLINK         13
-#define        MKDIR           14
-#define        RMDIR           15
-#define        READDIR         16
-#define        FSSTAT          17
-
-/*
- * Operations counts
- */
-struct count {
-       int             total;
-       int             calls[NOPS];
-};
-
-/*
- * Software development mix for server with about 50/50 mix of
- * diskless and diskful clients running SunOS 4.0.
- */
-int    Mix[NOPS] = {
-       0,              /* null */
-       13,             /* getattr */
-       1,              /* setattr */
-       0,              /* root */
-       34,             /* lookup */
-       8,              /* readlink */
-       22,             /* read */
-       0,              /* wrcache */
-       15,             /* write */
-       2,              /* create */
-       1,              /* remove */
-       0,              /* rename */
-       0,              /* link */
-       0,              /* symlink */
-       0,              /* mkdir */
-       0,              /* rmdir */
-       3,              /* readdir */
-       1,              /* fsstat */
-};
-
-/* Prototype decls */
-int    setmix(FILE *fp);
-void   usage(void);
-void   init_logfile(void);
-void   init_counters(void);
-void   get_delta(struct count *start, struct count *cur);
-void   init_testdir(int dirnum, char *parentdir);
-void   do_op(int rpct);
-void   op(int opnum);
-void   nextfile(void);
-int    createfile(void);
-int    openfile(void);
-int    writefile(void);
-void   collect_counters(void);
-int    check_counters(void);
-void   print(void);
-void   msec_sleep(int msecs);
-void   get_opct(struct count *count);
-int    substr(char *sp, char *subsp);
-int    check_access(struct stat statb);
-void   error(char *str);
-
-/*
- * NFS operations generator routines
- */
-int    op_null();
-int    op_getattr();
-int    op_setattr();
-int    op_root();
-int    op_lookup();
-int    op_readlink();
-int    op_read();
-int    op_wrcache();
-int    op_write();
-int    op_create();
-int    op_remove();
-int    op_rename();
-int    op_link();
-int    op_symlink();
-int    op_mkdir();
-int    op_rmdir();
-int    op_readdir();
-int    op_fsstat();
-
-/*
- * Operations generator vector
- */
-struct op_vect {
-       int     (*funct)();     /* op */
-} Op_vect[NOPS] = {
-       { op_null },
-       { op_getattr },
-       { op_setattr },
-       { op_root },
-       { op_lookup },
-       { op_readlink },
-       { op_read },
-       { op_wrcache },
-       { op_write },
-       { op_create },
-       { op_remove },
-       { op_rename },
-       { op_link },
-       { op_symlink },
-       { op_mkdir },
-       { op_rmdir },
-       { op_readdir },
-       { op_fsstat },
-};
-
-/*
- * Name sub-strings
- */
-#define        DIRSTR  "dir"                   /* directory */
-#define        SYMSTR  "sym"                   /* symbolic link */
-#define        LINSTR  "lin"                   /* hard link */
-
-struct timeval Optime[NOPS+1];         /* cumulative running time for ops */
-struct count Curct;                    /* total number ops called */
-int    Openfd[NFILES];                 /* open file descriptors */
-int    Curnum;                         /* current file number */
-int    Symnum;                         /* current symlink file number */
-int    Linknum;                        /* current link file number */
-int    Dirnum;                         /* current directory number */
-DIR    *Testdir;                       /* my test directory */
-char   Testdirname[MAXNAMLEN*2];       /* my test directory name */
-char   Curname[MAXNAMLEN];             /* current file name */
-char   Dirname[MAXNAMLEN];             /* current directory name */
-char   Symname[MAXNAMLEN];             /* symlink file name */
-char   Linkname[MAXNAMLEN];            /* link file name */
-char   *Otherspec = "%s/%03d";         /* sprintf spec for other names */
-char   *Rename1 = "rename1";           /* first name of rename pair */
-char   *Rename2 = "rename2";           /* second name of rename pair */
-char   *Symlinkpath = "./symlinknamelongstuff";
-                                       /* symlink file data */
-char   *Myname;                        /* name program invoked under */
-char   Namebuf[MAXNAMLEN];             /* unique name for this program */
-int    Log;                            /* synchronization log */
-char   Logname[MAXNAMLEN];             /* synchronization log name */
-int    Kmem;                           /* /dev/kmem file descriptor */
-off_t  Statoffset;                     /* offset to op count in NFS stats */
-int    Nprocs;                         /* sub-processes started */
-int    Verbose;                        /* print more info */
-int    Testop = -1;                    /* operation to test */
-int    Saveerrno;                      /* place to save errno */
-
-#define        subtime(t1, t2) {if ((t1.tv_usec -= t2.tv_usec) >= 1000000) {\
-                               t1.tv_sec += (t1.tv_usec / 1000000); \
-                               t1.tv_usec %= 1000000; \
-                        } else if (t1.tv_usec < 0) { \
-                               t1.tv_usec += 1000000; \
-                               t1.tv_sec--; \
-                        } \
-                        t1.tv_sec -= t2.tv_sec; \
-                       }
-
-#define        addtime(t1, t2) {if ((t1.tv_usec += t2.tv_usec) >= 1000000) {\
-                               t1.tv_sec += (t1.tv_usec / 1000000); \
-                               t1.tv_usec %= 1000000; \
-                        } else if (t1.tv_usec < 0) { \
-                               t1.tv_usec += 1000000; \
-                               t1.tv_sec--; \
-                        } \
-                        t1.tv_sec += t2.tv_sec; \
-                       }
-
-/*
- * Used to catch the parent's "start" signal
- */
-void
-startup()
-{
-
-       return;
-}
-
-/*
- * Clean up and exit
- */
-void
-cleanup()
-{
-
-       (void) unlink(Logname);
-       exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
-       int runtime;            /* length of run, in seconds */
-       int load;               /* load factor, in client loads */
-       int ncalls;             /* total number of calls to make */
-       int avgmspc;            /* average millisec per call */
-       int mspc;               /* millisec per call */
-       int wantcalls;          /* ncalls that should have happend by now */
-       int pid;                /* process id */
-       int delay;              /* msecs since last checked current time */
-       int randnum;            /* a random number */
-#if HAVE_SIGPROCMASK
-       sigset_t oldmask;       /* saved signal mask */
-#else
-       int oldmask;            /* saved signal mask */
-#endif
-       int sampletime;         /* secs between reading kernel stats */
-       char *opts;             /* option parsing */
-       int pct;
-       int procnum;
-       FILE *fp;
-       struct timeval curtime;
-       struct timeval starttime;
-       struct count startct;
-       struct stat statb;
-       char workdir[MAXPATHLEN];
-       char *getwd();
-
-       Myname = argv[0];
-
-       argc--;
-       argv++;
-
-       load = DEFAULT_LOAD;
-       ncalls = 0;
-       runtime = 0;
-       Nprocs = NPROCS;
-       pid = 0;
-
-       (void) umask(0);
-
-       /*
-        * Parse options
-        */
-       while (argc && **argv == '-') {
-               opts = &argv[0][1];
-               while (*opts) {
-                       switch (*opts) {
-
-                       case 'c':
-                               /*
-                                * Set number of calls
-                                */
-                               if (!isdigit(argv[1][0])) {
-                                       (void) fprintf(stderr,
-                                           "%s: illegal calls value %s\n",
-                                           Myname, argv[1]);
-                                       exit(1);
-                               }
-                               ncalls = atoi(argv[1]);
-                               argv++;
-                               argc--;
-                               break;
-
-                       case 'l':
-                               /*
-                                * Set load
-                                */
-                               if (!isdigit(argv[1][0])) {
-                                       (void) fprintf(stderr,
-                                           "%s: illegal load value %s\n",
-                                           Myname, argv[1]);
-                                       exit(1);
-                               }
-                               load = atoi(argv[1]);
-                               argv++;
-                               argc--;
-                               break;
-
-                       case 'm':
-                               /*
-                                * Set mix from a file
-                                */
-                               if ((fp = fopen(argv[1], "r")) == NULL) {
-                                       Saveerrno = errno;
-                                       (void) fprintf(stderr,
-                                           "%s: bad mix file", Myname);
-                                       errno = Saveerrno;
-                                       perror("");
-                                       exit(1);
-                               }
-                               if (setmix(fp) < 0) {
-                                       exit(1);
-                               }
-                               (void) fclose(fp);
-                               argv++;
-                               argc--;
-                               break;
-
-                       case 'p':
-                               /*
-                                * Set number of child processes
-                                */
-                               if (!isdigit(argv[1][0])) {
-                                       (void) fprintf(stderr,
-                                           "%s: illegal procs value %s\n",
-                                           Myname, argv[1]);
-                                       exit(1);
-                               }
-                               Nprocs = atoi(argv[1]);
-                               argv++;
-                               argc--;
-                               break;
-
-                       case 'T':
-                               /*
-                                * Set test mode, number following is opnum
-                                */
-                               if (!isdigit(argv[1][0])) {
-                                       (void) fprintf(stderr,
-                                           "%s: illegal test value %s\n",
-                                           Myname, argv[1]);
-                                       exit(1);
-                               }
-                               Testop = atoi(argv[1]);
-                               if (Testop >= NOPS) {
-                                       (void) fprintf(stderr,
-                                           "%s: illegal test value %d\n",
-                                           Myname, Testop);
-                                       exit(1);
-                               }
-                               argv++;
-                               argc--;
-                               break;
-
-                       case 't':
-                               /*
-                                * Set running time
-                                */
-                               if (!isdigit(argv[1][0])) {
-                                       (void) fprintf(stderr,
-                                           "%s: illegal time value %s\n",
-                                           Myname, argv[1]);
-                                       exit(1);
-                               }
-                               runtime = atoi(argv[1]);
-                               argv++;
-                               argc--;
-                               break;
-
-                       case 'v':
-                               /*
-                                * Set verbose mode
-                                */
-                               Verbose++;
-                               break;
-
-                       default:
-                               usage();
-                               exit(1);
-
-                       }
-                       opts++;
-               }
-               argv++;
-               argc--;
-       }
-
-       init_logfile();         /* Set up synchronizatin log file */
-
-       if (getcwd(workdir, sizeof(workdir)) == (char *) 0) {
-               Saveerrno = errno;
-               (void) fprintf(stderr,
-                   "%s: can't find current directory ", Myname);
-               errno = Saveerrno;
-               perror("");
-               exit(1);
-       }
-
-       (void) signal(SIGINT, cleanup);
-       (void) signal(SIGUSR1, startup);
-#if HAVE_SIGPROCMASK
-       {
-               sigset_t mask;
-               sigemptyset(&mask);
-               sigaddset(&mask, SIGUSR1);
-               sigprocmask(SIG_BLOCK, &mask, &oldmask);
-       }
-#else
-       /*
-        * sigblock() is marked deprecated in modern
-        * glibc and hence generates a warning.
-        */
-       oldmask = sigblock(sigmask(SIGUSR1));
-#endif
-
-       if (ncalls == 0) {
-               if (runtime == 0) {
-                       ncalls = DEFAULT_CALLS;
-               } else {
-                       ncalls = runtime * load;
-               }
-       }
-       avgmspc = Nprocs * 1000 / load;
-
-       /*
-        * Fork kids
-        */
-       for (procnum = 0; procnum < Nprocs; procnum++) {
-               if ((pid = fork()) == -1) {
-                       Saveerrno = errno;
-                       (void) fprintf(stderr, "%s: can't fork ", Myname);
-                       errno = Saveerrno;
-                       perror("");
-                       (void) kill(0, SIGINT);
-                       exit(1);
-               }
-               /*
-                * Kids go initialize
-                */
-               if (pid == 0) {
-                       break;
-               }
-       }
-
-       /*
-        * Parent: wait for kids to get ready, start them, wait for them to
-        * finish, read and accumulate results.
-        */
-       if (pid != 0) {
-               /*
-                * wait for kids to initialize
-                */
-               do {
-                       sleep(1);
-                       if (fstat(Log, &statb) == -1) {
-                               (void) fprintf(stderr, "%s: can't stat log %s",
-                                   Myname, Logname);
-                               (void) kill(0, SIGINT);
-                               exit(1);
-                       }
-               } while (statb.st_size != Nprocs);
-
-               if (ftruncate(Log, 0L) == -1) {
-                       (void) fprintf(stderr, "%s: can't truncate log %s",
-                           Myname, Logname);
-                       (void) kill(0, SIGINT);
-                       exit(1);
-               }
-
-               sync();
-               sleep(3);
-
-               /*
-                * Be sure there isn't something else going on
-                */
-               get_opct(&startct);
-               msec_sleep(2000);
-               get_delta(&startct, &Curct);
-               if (Curct.total > 20) {
-                       (void) fprintf(stderr,
-                           "%s: too much background activity (%d calls/sec)\n",
-                           Myname, Curct.total);
-                       (void) kill(0, SIGINT);
-                       exit(1);
-               }
-
-               /*
-                * get starting stats
-                */
-               get_opct(&startct);
-
-               /*
-                * Start kids
-                */
-               (void) kill(0, SIGUSR1);
-
-               /*
-                * Kids started, wait for first one to finish, signal the
-                * rest and wait for them to finish.
-                */
-               if (wait((union wait *) 0) != -1) {
-                       (void) kill(0, SIGUSR1);
-                       while (wait((union wait *) 0) != -1)
-                               /* nothing */;
-               }
-
-               /*
-                * Initialize and sum up counters
-                */
-               init_counters();
-               get_delta(&startct, &Curct);
-               collect_counters();
-               if (check_counters() == -1) {
-                       Verbose = 1;
-               }
-               print();
-
-               (void) close(Log);
-               (void) unlink(Logname);
-
-               exit(0);
-       }
-
-       /*
-        * Children: initialize, then notify parent through log file,
-        * wait to get signal, beat the snot out of the server, write
-        * stats to the log file, and exit.
-        */
-
-       /*
-        * Change my name for error logging
-        */
-       (void) sprintf(Namebuf, "%s%d", Myname, procnum);
-       Myname = Namebuf;
-
-       /*
-        * Initialize and cd to test directory
-        */
-       if (argc != 0) {
-               init_testdir(procnum, argv[procnum % argc]);
-       } else {
-               init_testdir(procnum, ".");
-       }
-       if ((Testdir = opendir(".")) == NULL) {
-               Saveerrno = errno;
-               (void) fprintf(stderr,
-                   "%s: can't open test directory ", Myname);
-               errno = Saveerrno;
-               perror(Testdirname);
-               exit(1);
-       }
-
-       init_counters();
-       srandom(procnum+1);
-
-       /*
-        * Tell parent I'm ready then wait for go ahead
-        */
-       if (write(Log, " ", 1) != 1) {
-               (void) fprintf(stderr, "%s: can't write sync file %s",
-                   Myname, Logname);
-               (void) kill(0, SIGINT);
-               exit(1);
-       }
-
-#if HAVE_SIGPROCMASK
-       sigsuspend(&oldmask);
-#else
-       sigpause(oldmask);
-#endif
-
-       /*
-        * Initialize counters
-        */
-       get_opct(&startct);
-       (void) gettimeofday(&starttime, (struct timezone *)NULL);
-       sampletime = starttime.tv_sec + ((int) random()) % (2 * SAMPLETIME);
-       curtime = starttime;
-
-       /*
-        * Do pseudo NFS operations and adapt to dynamic changes in load
-        * by adjusting the sleep time between operations based on the
-        * number of calls that should have occured since starttime and
-        * the number that have actually occured.  A delay is used to avoid
-        * doing gettimeofday calls too often, and a sampletime is
-        * used to avoid reading kernel NFS stats too often.
-        * If parent interrupts, get out and clean up.
-        */
-       delay = 0;
-       mspc = avgmspc;
-       for (;;) {
-               randnum = (int) random();
-               if (mspc > 0) {
-                       msec_sleep(randnum % (mspc << 1));
-               }
-
-               /*
-                * Do the NFS operation
-                * We use a random number from 0-199 to avoid starvation
-                * of the operations at the end of the mix.
-                */
-               do_op(randnum % 200);
-
-               /*
-                * Do a gettimeofday call only once per second
-                */
-               delay += mspc;
-               if (delay > 1000 || Curct.total >= ncalls) {
-                       delay = 0;
-                       (void) gettimeofday(&curtime, (struct timezone *)NULL);
-
-                       /*
-                        * If sample time is up, check the kernel stats
-                        * and adjust our parameters to either catch up or
-                        * slow down.
-                        */
-                       if (curtime.tv_sec > sampletime ||
-                           Curct.total >= ncalls) {
-                               sampletime = curtime.tv_sec + SAMPLETIME;
-                               get_delta(&startct, &Curct);
-                               if (Curct.total >= ncalls) {
-                                       break;
-                               }
-                               wantcalls =
-                                   ((curtime.tv_sec - starttime.tv_sec) * 1000
-                                   +(curtime.tv_usec-starttime.tv_usec) / 1000)
-                                   * Nprocs / avgmspc;
-                               pct = 1000 * (Curct.total - wantcalls) / ncalls;
-                               mspc = avgmspc + avgmspc * pct / 20;
-                               if (mspc <= 0) {
-                                       /*
-                                        * mspc must be positive or we will
-                                        * never advance time.
-                                        */
-                                       mspc = 10;
-                               }
-                       }
-               }
-       }
-
-       /*
-        * Store total time in last slot of counts array
-        */
-       Optime[NOPS].tv_sec = curtime.tv_sec - starttime.tv_sec;
-       Optime[NOPS].tv_usec = curtime.tv_usec - starttime.tv_usec;
-
-       /*
-        * write stats to log file (append mode)
-        */
-       if (write(Log, (char *)Optime, sizeof (Optime)) == -1) {
-               Saveerrno = errno;
-               (void) fprintf(stderr, "%s: can't write log ", Myname);
-               errno = Saveerrno;
-               perror("");
-               (void) kill(0, SIGINT);
-               exit(1);
-       }
-       (void) close(Log);
-
-       exit(0);
-}
-
-/*
- * Initialize test directory
- *
- * If the directory already exists, check to see that all of the
- * files exist and we can write them.  If directory doesn't exist
- * create it and fill it using the LOOKUP and WRITE ops.
- * Chdir to the directory.
- */
-void
-init_testdir(int dirnum, char *parentdir)
-{
-       int i;
-       int fd;
-       char cmd[256];
-       struct stat statb;
-
-       (void) sprintf(Testdirname, "%s/testdir%d", parentdir, dirnum);
-       if (stat(Testdirname, &statb) == -1) {
-               if (mkdir(Testdirname, 0777) == -1) {
-                       Saveerrno = errno;
-                       (void) fprintf(stderr,
-                           "%s: can't create test directory ", Myname);
-                       errno = Saveerrno;
-                       perror(Testdirname);
-                       (void) kill(0, SIGINT);
-                       exit(1);
-               }
-               if (chdir(Testdirname) == -1) {
-                       Saveerrno = errno;
-                       (void) fprintf(stderr,
-                           "%s: can't cd to test directory ", Myname);
-                       errno = Saveerrno;
-                       perror(Testdirname);
-                       (void) kill(0, SIGINT);
-                       exit(1);
-               }
-
-               /*
-                * create some files with long names and average size
-                */
-               for (i = 0; i < NFILES; i++) {
-                       nextfile();
-                       (void) createfile();
-                       if (Openfd[Curnum] == 0 || writefile() == 0) {
-                               Saveerrno = errno;
-                               (void) fprintf(stderr,
-                                   "%s: can't create test file '%s'\n",
-                                   Myname, Curname);
-                               errno = Saveerrno;
-                               perror(Testdirname);
-                               (void) kill(0, SIGINT);
-                               exit(1);
-                       }
-               }
-       } else {
-               if (chdir(Testdirname) == -1) {
-                       Saveerrno = errno;
-                       (void) fprintf(stderr,
-                           "%s: can't cd to test directory ", Myname);
-                       errno = Saveerrno;
-                       perror(Testdirname);
-                       (void) kill(0, SIGINT);
-                       exit(1);
-               }
-
-               /*
-                * Verify that we can read and write the test dir
-                */
-               if (check_access(statb) == -1) {
-                       (void) fprintf(stderr,
-                           "%s: wrong permissions on test dir %s\n",
-                           Myname, Testdirname);
-                       (void) kill(0, SIGINT);
-                       exit(1);
-               }
-
-               /*
-                * Verify that we can read and write all the files
-                */
-               for (i = 0; i < NFILES; i++) {
-                       nextfile();
-                       if (stat(Curname, &statb) == -1 || statb.st_size == 0) {
-                               /*
-                                * File doesn't exist or is 0 size
-                                */
-                               (void) createfile();
-                               if (Openfd[Curnum] == 0 || writefile() == 0) {
-                                       (void) kill(0, SIGINT);
-                                       exit(1);
-                               }
-                       } else if (check_access(statb) == -1) {
-                               /*
-                                * should try to remove and recreate it
-                                */
-                               (void) fprintf(stderr,
-                                   "%s: wrong permissions on testfile %s\n",
-                                   Myname, Curname);
-                               (void) kill(0, SIGINT);
-                               exit(1);
-                       } else if (Openfd[Curnum] == 0) {
-                               (void) openfile();
-                               if (Openfd[Curnum] == 0) {
-                                       (void) kill(0, SIGINT);
-                                       exit(1);
-                               }
-                       }
-               }
-       }
-
-       /*
-        * Start with Rename1 and no Rename2 so the
-        * rename op can ping pong back and forth.
-        */
-       (void) unlink(Rename2);
-       if ((fd = open(Rename1, O_CREAT|O_TRUNC|O_RDWR, 0666)) == -1) {
-               Saveerrno = errno;
-               (void) fprintf(stderr, "%s: can't create rename file ", Myname);
-               errno = Saveerrno;
-               perror(Rename1);
-               (void) kill(0, SIGINT);
-               exit(1);
-       }
-
-       /*
-        * Remove and recreate the test sub-directories
-        * for mkdir symlink and hard link.
-        */
-       (void) sprintf(cmd, "rm -rf %s %s %s", DIRSTR, SYMSTR, LINSTR);
-       if (system(cmd) != 0) {
-               (void) fprintf(stderr, "%s: can't %s\n", Myname, cmd);
-               (void) kill(0, SIGINT);
-               exit(1);
-       }
-
-       if (mkdir(DIRSTR, 0777) == -1) {
-               (void) fprintf(stderr,
-                   "%s: can't create subdir %s\n", Myname, DIRSTR);
-               (void) kill(0, SIGINT);
-               exit(1);
-       }
-
-       if (mkdir(SYMSTR, 0777) == -1) {
-               (void) fprintf(stderr,
-                   "%s: can't create subdir %s\n", Myname, SYMSTR);
-               (void) kill(0, SIGINT);
-               exit(1);
-       }
-       op(SYMLINK);
-
-       if (mkdir(LINSTR, 0777) == -1) {
-               (void) fprintf(stderr, "%s: can't create subdir %s\n", Myname,
-                   LINSTR);
-               (void) kill(0, SIGINT);
-               exit(1);
-       }
-
-       (void) close(fd);
-}
-
-/*
- * The routines below attempt to do over-the-wire operations.
- * Each op tries to cause one or more of a particular
- * NFS operation to go over the wire.  OPs return the number
- * of OTW calls they think they have generated.
- *
- * An array of open file descriptors is kept for the files in each
- * test directory. The open fd's are used to get access to the files
- * without generating lookups. An fd value of 0 mean the corresponding
- * file name is closed.  Ops that need a name use Curname.
- */
-
-/*
- * Call an op based on a random number and the current
- * op calling weights. Op weights are derived from the
- * mix percentage and the current NFS stats mix percentage.
- */
-void
-do_op(int rpct)
-{
-       int opnum;
-       int weight;
-       int oppct;
-
-       if (Testop != -1) {
-               nextfile();
-               op(Testop);
-               return;
-       }
-       for (opnum = rpct % NOPS; rpct >= 0; opnum = (opnum + 1) % NOPS) {
-               if (Curct.total) {
-                       oppct = (Curct.calls[opnum] * 100) / Curct.total;
-               } else {
-                       oppct = 0;
-               }
-               /*
-                * Weight is mix percent - (how far off we are * fudge)
-                * fudge factor is required because some ops (read, write)
-                * generate many NFS calls for a single op call
-                */
-               weight = Mix[opnum] - ((oppct - Mix[opnum]) << 4);
-               if (weight <= 0) {
-                       continue;
-               }
-               rpct -= weight;
-               if (rpct < 0) {
-                       if (opnum == RMDIR && Dirnum == 0) {
-                               op(MKDIR);
-                       } else if (opnum != CREATE && opnum != LOOKUP &&
-                           opnum != REMOVE) {
-                               nextfile();
-                       }
-                       op(opnum);
-                       if (Openfd[Curnum] == 0) {
-                               op(CREATE);
-#ifdef XXX
-                               op(WRITE);
-#endif /* XXX */
-                       }
-                       return;
-               }
-       }
-}
-
-/*
- * Call an op generator and keep track of its running time
- */
-void
-op(int opnum)
-{
-       struct timeval start;
-       struct timeval stop;
-       int nops;
-
-       (void) gettimeofday(&start, (struct timezone *)NULL);
-       nops = (*Op_vect[opnum].funct)();
-       (void) gettimeofday(&stop, (struct timezone *)NULL);
-       stop.tv_sec -= start.tv_sec;
-       stop.tv_usec -= start.tv_usec;
-
-#ifdef SUNOS4
-       /*
-        * SunOS 4.0 does a lookup and a getattr on each open
-        * so we have to account for that in the getattr op
-        */
-       if (opnum == GETATTR && nops == 2) {
-               nops = 1;
-               stop.tv_sec /= 2;
-               stop.tv_usec /= 2;
-               Curct.total += Nprocs;
-               Curct.calls[LOOKUP] += Nprocs;
-               addtime(Optime[LOOKUP], stop);
-       }
-#endif
-
-       nops *= Nprocs;
-       Curct.total += nops;
-       Curct.calls[opnum] += nops;
-       addtime(Optime[opnum], stop);
-}
-
-/*
- * Advance file number (Curnum) and name (Curname)
- */
-void
-nextfile(void)
-{
-       static char *numpart = NULL;
-       int num;
-
-       Curnum = (Curnum + 1) % NFILES;
-       if (numpart == NULL) {
-               (void) sprintf(Curname, "%03dabcdefghijklmn", Curnum);
-               numpart = Curname;
-       } else {
-               num = Curnum;
-               numpart[0] = '0' + num / 100;
-               num %= 100;
-               numpart[1] = '0' + num / 10;
-               num %= 10;
-               numpart[2] = '0' + num;
-       }
-}
-
-int
-createfile(void)
-{
-       int ret;
-       int fd;
-
-       ret = 0;
-       fd = Openfd[Curnum];
-
-       if ((fd && close(fd) == -1) ||
-           (fd = open(Curname, O_CREAT|O_RDWR|O_TRUNC, 0666)) == -1) {
-               fd = 0;
-               ret = -1;
-               error("create");
-       }
-       Openfd[Curnum] = fd;
-       return (ret);
-}
-
-int
-openfile(void)
-{
-       int ret;
-       int fd;
-
-       ret = 0;
-       fd = Openfd[Curnum];
-       if (fd == 0 && (fd = open(Curname, O_RDWR, 0666)) == -1) {
-               fd = 0;
-               ret = -1;
-               error("open");
-       }
-       Openfd[Curnum] = fd;
-       return (ret);
-}
-
-int
-writefile(void)
-{
-       int fd;
-       int wrote;
-       int bufs;
-       int size;
-       int randnum;
-       char buf[BUFSIZE];
-
-       fd = Openfd[Curnum];
-
-       if (lseek(fd, 0L, 0) == (off_t) -1) {
-               error("write: lseek");
-               return (-1);
-       }
-
-       randnum = (int) random();
-       bufs = randnum % 100;   /* using this for distribution desired */
-       /*
-        * Attempt to create a distribution of file sizes
-        * to reflect reality.  Most files are small,
-        * but there are a few files that are very large.
-        *
-        * The sprite paper (USENIX 198?) claims :
-        *      50% of all files are < 2.5K
-        *      80% of all file accesses are to files < 10K
-        *      40% of all file I/O is to files > 25K
-        *
-        * static examination of the files in our file system
-        * seems to support the claim that 50% of all files are
-        * smaller than 2.5K
-        */
-       if (bufs < 50)  {
-               bufs = (randnum % 3) + 1;
-               size = 1024;
-       } else if (bufs < 97) {
-               bufs = (randnum % 6) + 1;
-               size = BUFSIZE;
-       } else {
-               bufs = MAXFILESIZE;
-               size = BUFSIZE;
-       }
-
-       for (wrote = 0; wrote < bufs; wrote++) {
-               if (write(fd, buf, size) == -1) {
-                       error("write");
-                       break;
-               }
-       }
-
-       return (wrote);
-}
-
-int
-op_null(void)
-{
-
-       return (1);
-}
-
-
-/*
- * Generate a getattr call by fstat'ing the current file
- * or by closing and re-opening it. This helps to keep the
- * attribute cache cold.
- */
-int
-op_getattr(void)
-{
-       struct stat statb;
-
-       if ((random() % 2) == 0) {
-               (void) close(Openfd[Curnum]);
-               Openfd[Curnum] = 0;
-               if (openfile() == -1) {
-                       return (0);
-               }
-               return (2);
-       }
-       if (fstat(Openfd[Curnum], &statb) == -1) {
-               error("getattr");
-       }
-       return (1);
-}
-
-
-int op_setattr(void)
-{
-
-       if (fchmod(Openfd[Curnum], 0666) == -1) {
-               error("setattr");
-       }
-       return (1);
-}
-
-
-int op_root(void)
-{
-
-       error("root");
-       return (0);
-}
-
-
-/*
- * Generate a lookup by stat'ing the current name.
- */
-int op_lookup(void)
-{
-       struct stat statb;
-
-       if (stat(Curname, &statb) == -1) {
-               error("lookup");
-       }
-       return (1);
-}
-
-
-int op_read(void)
-{
-       int got;
-       int bufs;
-       int fd;
-       char buf[BUFSIZE];
-
-       bufs = 0;
-       fd = Openfd[Curnum];
-
-       if (lseek(fd, 0L, 0) == (off_t) -1) {
-               error("read: lseek");
-               return (0);
-       }
-
-       while ((got = read(fd, buf, sizeof (buf))) > 0) {
-               bufs++;
-       }
-
-       if (got == -1) {
-               error("read");
-       } else {
-               bufs++;         /* did one extra read to find EOF */
-       }
-       return (bufs);
-}
-
-
-int op_wrcache(void)
-{
-       error("wrcache");
-       return 0;
-}
-
-
-int op_write(void)
-{
-       int bufs;
-
-       bufs = writefile();
-       if (bufs == 0) {
-               return (0);
-       }
-       (void) fsync(Openfd[Curnum]);
-
-       return (bufs + 2);
-}
-
-
-int op_create(void)
-{
-
-       if (createfile() == -1) {
-               return (0);
-       }
-       return (1);
-}
-
-
-int op_remove(void)
-{
-       int fd;
-       int got;
-
-       if (Linknum > 0) {
-               got = unlink(Linkname);
-               Linknum--;
-               (void) sprintf(Linkname, Otherspec, LINSTR, Linknum);
-       } else if (Symnum > 1) {
-               got = unlink(Symname);
-               Symnum--;
-               (void) sprintf(Symname, Otherspec, SYMSTR, Symnum);
-       } else {
-               fd = Openfd[Curnum];
-
-               if (fd && (close(fd) == -1)) {
-                       error("remove: close");
-               }
-               Openfd[Curnum] = 0;
-               got = unlink(Curname);
-       }
-       if (got == -1) {
-               error("remove");
-       }
-       return (1);
-}
-
-
-int toggle = 0;
-
-int op_rename(void)
-{
-       int got;
-
-       if (toggle++ & 01) {
-               got = rename(Rename2, Rename1);
-       } else {
-               got = rename(Rename1, Rename2);
-       }
-       if (got == -1) {
-               error("rename");
-       }
-       return (1);
-}
-
-
-int op_link(void)
-{
-
-       Linknum++;
-       (void) sprintf(Linkname, Otherspec, LINSTR, Linknum);
-       if (link(Curname, Linkname) == -1) {
-               error("link");
-       }
-       return (1);
-}
-
-
-int op_readlink(void)
-{
-       char    buf[MAXPATHLEN];
-
-       if (Symnum == 0) {
-               error("readlink");
-               return (0);
-       }
-       if (readlink(Symname, buf, sizeof (buf)) == -1) {
-               error("readlink");
-       }
-       return (1);
-}
-
-
-int op_symlink(void)
-{
-
-       Symnum++;
-       (void) sprintf(Symname, Otherspec, SYMSTR, Symnum);
-       if (symlink(Symlinkpath, Symname) == -1) {
-               error("symlink");
-       }
-       return (1);
-}
-
-
-int op_mkdir(void)
-{
-
-       Dirnum++;
-       (void) sprintf(Dirname, Otherspec, DIRSTR, Dirnum);
-       if (mkdir(Dirname, 0777) == -1) {
-               error("mkdir");
-       }
-       return (1);
-}
-
-
-int op_rmdir(void)
-{
-
-       if (Dirnum == 0) {
-               error("rmdir");
-               return (0);
-       }
-       if (rmdir(Dirname) == -1) {
-               error("rmdir");
-       }
-       Dirnum--;
-       (void) sprintf(Dirname, Otherspec, DIRSTR, Dirnum);
-       return (1);
-}
-
-
-int op_readdir(void)
-{
-
-       rewinddir(Testdir);
-       while (readdir(Testdir) != (struct dirent *)NULL)
-               /* nothing */;
-       return (1);
-}
-
-
-int op_fsstat(void)
-{
-       struct statfs statfsb;
-
-       if (statfs(".", &statfsb) == -1) {
-               error("statfs");
-       }
-       return (1);
-}
-
-
-/*
- * Utility routines
- */
-
-/*
- * Read counter arrays out of log file and accumulate them in "Optime"
- */
-void
-collect_counters(void)
-{
-       int i;
-       int j;
-
-       (void) lseek(Log, 0L, 0);
-
-       for (i = 0; i < Nprocs; i++) {
-               struct timeval buf[NOPS+1];
-
-               if (read(Log, (char *)buf, sizeof (buf)) == -1) {
-                       Saveerrno = errno;
-                       (void) fprintf(stderr, "%s: can't read log ", Myname);
-                       errno = Saveerrno;
-                       perror("");
-                       (void) kill(0, SIGINT);
-                       exit(1);
-               }
-
-               for (j = 0; j < NOPS+1; j++) {
-                       addtime(Optime[j], buf[j]);
-               }
-       }
-}
-
-/*
- * Check consistance of results
- */
-int
-check_counters(void)
-{
-       int i;
-       int mixdiff;
-       int got;
-       int want;
-
-       mixdiff = 0;
-       for (i = 0; i < NOPS; i++) {
-               got = Curct.calls[i] * 10000 / Curct.total;
-               want = Mix[i] * 100;
-               if (got > want) {
-                       mixdiff += got - want;
-               } else {
-                       mixdiff += want - got;
-               }
-       }
-       if (mixdiff > 1000) {
-               (void) fprintf(stdout,
-                   "%s: INVALID RUN, mix generated is off by %d.%02d%%\n",
-                   Myname, mixdiff / 100, mixdiff % 100);
-               return (-1);
-       }
-       return (0);
-}
-
-/*
- * Print results
- */
-void
-print(void)
-{
-       int totalmsec;
-       int runtime;
-       int msec;
-       int i;
-
-       totalmsec = 0;
-       for (i = 0; i < NOPS; i++) {
-               totalmsec += Optime[i].tv_sec * 1000;
-               totalmsec += Optime[i].tv_usec / 1000;
-       }
-
-       if (Verbose) {
-          const char *format = sizeof (Optime[0].tv_sec) == sizeof (long)
-            ? "%-10s%3d%%    %2d.%02d%%   %6d   %4ld.%02ld    %4d.%02d    %2d.%02d%%\n"
-            : "%-10s%3d%%    %2d.%02d%%   %6d   %4d.%02d    %4d.%02d    %2d.%02d%%\n";
-               (void) fprintf(stdout,
-"op        want       got    calls      secs  msec/call    time %%\n");
-               for (i = 0; i < NOPS; i++) {
-                       msec = Optime[i].tv_sec * 1000
-                           + Optime[i].tv_usec / 1000;
-                       (void) fprintf(stdout, format,
-                           Opnames[i], Mix[i],
-                           Curct.calls[i] * 100 / Curct.total,
-                           (Curct.calls[i] * 100 % Curct.total)
-                               * 100 / Curct.total,
-                           Curct.calls[i],
-                           Optime[i].tv_sec, Optime[i].tv_usec / 10000,
-                           Curct.calls[i]
-                               ? msec / Curct.calls[i]
-                               : 0,
-                           Curct.calls[i]
-                               ? (msec % Curct.calls[i]) * 100 / Curct.calls[i]
-                               : 0,
-                           msec * 100 / totalmsec,
-                           (msec * 100 % totalmsec) * 100 / totalmsec);
-               }
-       }
-
-       runtime = Optime[NOPS].tv_sec / Nprocs;
-       (void) fprintf(stdout,
-           "%d sec %d calls %d.%02d calls/sec %d.%02d msec/call\n",
-           runtime, Curct.total,
-           Curct.total / runtime,
-           ((Curct.total % runtime) * 100) / runtime,
-           totalmsec / Curct.total,
-           ((totalmsec % Curct.total) * 100) / Curct.total);
-}
-
-/*
- * Use select to sleep for some number of milliseconds
- * granularity is 20 msec
- */
-void
-msec_sleep(int msecs)
-{
-       struct timeval sleeptime;
-
-       if (msecs < 20) {
-               return;
-       }
-       sleeptime.tv_sec = msecs / 1000;
-       sleeptime.tv_usec = (msecs % 1000) * 1000;
-
-       if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &sleeptime) == -1){
-               Saveerrno = errno;
-               (void) fprintf(stderr, "%s: select failed ", Myname);
-               errno = Saveerrno;
-               perror("");
-               (void) kill(0, SIGINT);
-               exit(1);
-       }
-}
-
-/*
- * Open the synchronization file with append mode
- */
-void
-init_logfile(void)
-{
-
-       (void) sprintf(Logname, "/tmp/nhfsstone%d", getpid());
-       if ((Log = open(Logname, O_RDWR|O_CREAT|O_TRUNC|O_APPEND, 0666)) == -1){
-               Saveerrno = errno;
-               (void) fprintf(stderr,
-                   "%s: can't open log file %s ", Myname, Logname);
-               errno = Saveerrno;
-               perror("");
-               exit(1);
-       }
-}
-
-/*
- * Zero counters
- */
-void
-init_counters(void)
-{
-       int i;
-
-       Curct.total = 0;
-       for (i = 0; i < NOPS; i++) {
-               Curct.calls[i] = 0;
-               Optime[i].tv_sec = 0;
-               Optime[i].tv_usec = 0;
-       }
-       Optime[NOPS].tv_sec = 0;
-       Optime[NOPS].tv_usec = 0;
-}
-
-/*
- * Set cur = cur - start
- */
-void
-get_delta(struct count *start, struct count *cur)
-{
-       int i;
-
-       get_opct(cur);
-       cur->total -= start->total;
-       for (i = 0; i < NOPS; i++) {
-               cur->calls[i] -= start->calls[i];
-       }
-}
-
-/*
- * Read kernel stats
- */
-void
-get_opct(struct count *count)
-{
-       static FILE     *fp = NULL;
-       char            buffer[256];
-       int i;
-
-       if (fp == NULL && !(fp = fopen("/proc/net/rpc/nfs", "r"))) {
-               perror("/proc/net/rpc/nfs");
-               (void) kill(0, SIGINT);
-               exit(1);
-       } else {
-               fflush(fp);
-               rewind(fp);
-       }
-
-       while (fgets(buffer, sizeof(buffer), fp) != NULL) {
-               char    *sp, *line = buffer;
-
-               if ((sp = strchr(line, '\n')) != NULL)
-                       *sp = '\0';
-               if (!(sp = strtok(line, " \t")) || strcmp(line, "proc2"))
-                       continue;
-               if (!(sp = strtok(NULL, " \t")))
-                       goto bummer;
-               count->total = 0;
-               for (i = 0; i < 18; i++) {
-                       if (!(sp = strtok(NULL, " \t")))
-                               goto bummer;
-                       /* printf("call %d -> %s\n", i, sp); */
-                       count->calls[i] = atoi(sp);
-                       count->total += count->calls[i];
-               }
-               /* printf("total calls %d\n", count->total); */
-               break;
-       }
-
-       return;
-
-bummer:
-       fprintf(stderr, "parse error in /proc/net/rpc/nfs!\n");
-       kill(0, SIGINT);
-       exit(1);
-}
-
-#define        LINELEN         128             /* max bytes/line in mix file */
-#define        MIX_START       0
-#define        MIX_DATALINE    1
-#define        MIX_DONE        2
-#define        MIX_FIRSTLINE   3
-
-/*
- * Mix file parser.
- * Assumes that the input file is in the same format as
- * the output of the nfsstat(8) command.
- *
- * Uses a simple state transition to keep track of what to expect.
- * Parsing is done a line at a time.
- *
- * State          Input                action          New state
- * MIX_START      ".*nfs:.*"           skip one line   MIX_FIRSTLINE
- * MIX_FIRSTLINE   ".*[0-9]*.*"                get ncalls      MIX_DATALINE
- * MIX_DATALINE    "[0-9]* [0-9]*%"X6  get op counts   MIX_DATALINE
- * MIX_DATALINE    "[0-9]* [0-9]*%"X4  get op counts   MIX_DONE
- * MIX_DONE       EOF                  return
- */
-int
-setmix(FILE *fp)
-{
-       int state;
-       int got;
-       int opnum;
-       int calls;
-       int len;
-       char line[LINELEN];
-
-       state = MIX_START;
-       opnum = 0;
-
-       while (state != MIX_DONE && fgets(line, LINELEN, fp)) {
-
-               switch (state) {
-
-               case MIX_START:
-                       len = strlen(line);
-                       if (len >= 4 && substr(line, "nfs:")) {
-                               if (fgets(line, LINELEN, fp) == NULL) {
-                                       (void) fprintf(stderr,
-"%s: bad mix format: unexpected EOF after 'nfs:'\n", Myname);
-                                       return (-1);
-                               }
-                               state = MIX_FIRSTLINE;
-                       }
-                       break;
-
-               case MIX_FIRSTLINE:
-                       got = sscanf(line, "%d", &calls);
-                       if (got != 1) {
-                               (void) fprintf(stderr,
-"%s: bad mix format: can't find 'calls' value %d\n", Myname, got);
-                               return (-1);
-                       }
-                       if (fgets(line, LINELEN, fp) == NULL) {
-                               (void) fprintf(stderr,
-"%s: bad mix format: unexpected EOF after 'calls'\n", Myname);
-                               return (-1);
-                       }
-                       state = MIX_DATALINE;
-                       break;
-
-               case MIX_DATALINE:
-                       got = sscanf(line,
-       "%d %*d%% %d %*d%% %d %*d%% %d %*d%% %d %*d%% %d %*d%% %d %*d%%",
-       &Mix[opnum], &Mix[opnum+1], &Mix[opnum+2], &Mix[opnum+3],
-       &Mix[opnum+4], &Mix[opnum+5], &Mix[opnum+6]);
-                       if (got == 4 && opnum == 14) {
-                               /*
-                                * looks like the last line
-                                */
-                               state = MIX_DONE;
-                       } else if (got == 7) {
-                               opnum += 7;
-                               if (fgets(line, LINELEN, fp) == NULL) {
-                                       (void) fprintf(stderr,
-"%s: bad mix format: unexpected EOF after 'calls'\n", Myname);
-                                       return (-1);
-                               }
-                       } else {
-                               (void) fprintf(stderr,
-"%s: bad mix format: can't find %d op values\n", Myname, got);
-                               return (-1);
-                       }
-                       break;
-               default:
-                       (void) fprintf(stderr,
-                           "%s: unknown state %d\n", Myname, state);
-                       return (-1);
-               }
-       }
-       if (state != MIX_DONE) {
-               (void) fprintf(stderr,
-                   "%s: bad mix format: unexpected EOF\n", Myname);
-               return (-1);
-       }
-       for (opnum = 0; opnum < NOPS; opnum++) {
-               Mix[opnum] = Mix[opnum] * 100 / calls
-                   + ((Mix[opnum] * 1000 / calls % 10) >= 5);
-       }
-       return (0);
-}
-
-/*
- * return true if sp contains the substring subsp, false otherwise
- */
-int
-substr(char *sp, char *subsp)
-{
-       int found;
-       int want;
-       char *s2;
-
-       if (sp == NULL || subsp == NULL) {
-               return (0);
-       }
-
-       want = strlen(subsp);
-
-       while (*sp != '\0') {
-               while (*sp != *subsp && *sp != '\0') {
-                       sp++;
-               }
-               found = 0;
-               s2 = subsp;
-               while (*sp == *s2) {
-                       sp++;
-                       s2++;
-                       found++;
-               }
-               if (found == want) {
-                       return (1);
-               }
-       }
-       return (0);
-}
-
-/*
- * check to make sure that we have
- * both read and write permissions
- * for this file or directory.
- */
-int
-check_access(struct stat statb)
-{
-       int gidsetlen;
-       gid_t gidset[NGROUPS];
-       int i;
-
-       if (statb.st_uid == getuid()) {
-               if ((statb.st_mode & 0200) && (statb.st_mode & 0400)) {
-                       return 1;
-               } else {
-                       return -1;
-               }
-       }
-
-       gidsetlen = NGROUPS;
-
-       if (getgroups(gidsetlen, gidset) == -1) {
-               perror("getgroups");
-               return -1;
-       }
-
-       for (i = 0; i < NGROUPS; i++) {
-               if (statb.st_gid == gidset[i]) {
-                       if ((statb.st_mode & 020) && (statb.st_mode & 040)) {
-                               return 1;
-                       } else {
-                               return -1;
-                       }
-               }
-       }
-
-       if ((statb.st_mode & 02) && (statb.st_mode & 04)) {
-               return 1;
-       } else {
-               return -1;
-       }
-}
-
-void
-usage(void)
-{
-
-       (void) fprintf(stderr, "usage: %s [-v] [[-t secs] | [-c calls]] [-l load] [-p nprocs] [-m mixfile] [dir]...\n", Myname);
-}
-
-void
-error(char *str)
-{
-
-       Saveerrno = errno;
-       (void) fprintf(stderr, "%s: op failed: %s ", Myname, str);
-       errno = Saveerrno;
-       perror("");
-}