]> www.infradead.org Git - users/hch/xfstests-dev.git/commitdiff
xfstests updates - rework build to be like other xfs packages, revive some old fs...
authorNathan Scott <nathans@sgi.com>
Mon, 7 Jul 2003 06:36:46 +0000 (06:36 +0000)
committerNathan Scott <nathans@sgi.com>
Mon, 7 Jul 2003 06:36:46 +0000 (06:36 +0000)
52 files changed:
013
022
022.out
049
065
067
068
070
Makefile
common.config
common.dump
configure.in
group
include/Makefile
include/builddefs.in
include/buildmacros [new file with mode: 0644]
include/buildrules
include/dataascii.h [new file with mode: 0644]
include/databin.h [new file with mode: 0644]
include/file_lock.h [new file with mode: 0644]
include/forker.h [new file with mode: 0644]
include/open_flags.h [new file with mode: 0644]
include/pattern.h [new file with mode: 0644]
include/str_to_bytes.h [new file with mode: 0644]
include/test.h [new file with mode: 0644]
include/tlibio.h [new file with mode: 0644]
include/usctest.h [new file with mode: 0644]
lib/Makefile [new file with mode: 0644]
lib/dataascii.c [new file with mode: 0644]
lib/databin.c [new file with mode: 0644]
lib/datapid.c [new file with mode: 0644]
lib/file_lock.c [new file with mode: 0644]
lib/forker.c [new file with mode: 0644]
lib/open_flags.c [new file with mode: 0644]
lib/pattern.c [new file with mode: 0644]
lib/random.c [moved from src/random.c with 100% similarity]
lib/random_range.c [new file with mode: 0644]
lib/str_to_bytes.c [new file with mode: 0644]
lib/string_to_tokens.c [new file with mode: 0644]
lib/tlibio.c [new file with mode: 0644]
lib/write_log.c [new file with mode: 0644]
ltp/Makefile [new file with mode: 0644]
ltp/doio.c [new file with mode: 0644]
ltp/doio.h [new file with mode: 0644]
ltp/fsstress.c [moved from src/fsstress.c with 95% similarity]
ltp/fsx.c [new file with mode: 0644]
ltp/growfiles.c [new file with mode: 0644]
ltp/iogen.c [new file with mode: 0644]
m4/Makefile
soak
src/Makefile
tools/srcdiff

diff --git a/013 b/013
index 68951f8b18c97c89bafa8a298d3e3ad6eb28d9a0..841b003e268992c75e893300fc105dce10dab32a 100755 (executable)
--- a/013
+++ b/013
@@ -85,7 +85,7 @@ _do_test()
     echo "fsstress.$_n : $_param"
     echo "-----------------------------------------------"
     # -v >$tmp.out
-    if ! $here/src/fsstress $_param $FSSTRESS_AVOID -n $_count -d $out >/dev/null 2>&1
+    if ! $here/ltp/fsstress $_param $FSSTRESS_AVOID -n $_count -d $out >/dev/null 2>&1
     then
         echo "    fsstress (count=$_count) returned $? - see $seq.full"
         
diff --git a/022 b/022
index 718f38509fd5b2f91589fc971ddc4a48bece5859..c997b9f4a0c895232c6eb653577a5be5f7decbad 100755 (executable)
--- a/022
+++ b/022
@@ -4,7 +4,7 @@
 # Test out a level 0 dump/restore to a tape of a subdir
 # i.e. it is testing out drive_scsitape.c
 #
-# Use src/fsstress to create a directory structure with a mix of files
+# Use fsstress to create a directory structure with a mix of files
 #
 #-----------------------------------------------------------------------
 # Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
diff --git a/022.out b/022.out
index 91668f632ee508f28c67d48f66e8ecb4a1df99af..95e1639d6f67361fa205e40b424dc38c5ea94604 100644 (file)
--- a/022.out
+++ b/022.out
@@ -1,6 +1,6 @@
 QA output created by 022
 Put scsi tape driver into variable block size mode
-Creating directory system to dump using src/fsstress.
+Creating directory system to dump using fsstress.
 
 -----------------------------------------------
 fsstress : -f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10
diff --git a/049 b/049
index 72a3fd4c4780142079e1e11817611182afa3a93b..a1ec2f67fe482190b08c1ae0de9c2a8ba9cc5040 100755 (executable)
--- a/049
+++ b/049
@@ -106,7 +106,7 @@ mount -t xfs -o loop $SCRATCH_MNT/test.xfs $SCRATCH_MNT/test >> $seq.full 2>&1 \
     || _fail "!!! failed to loop mount xfs"
 
 _log "stress"
-src/fsstress -d $SCRATCH_MNT/test -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \
+ltp/fsstress -d $SCRATCH_MNT/test -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \
     || _fail "!!! stress failed"
     
 _log "clean"
@@ -126,7 +126,7 @@ mount -t ext2 -o loop $SCRATCH_MNT/test/test.ext2 $SCRATCH_MNT/test2 >> $seq.ful
     || _fail "!!! failed to loop mount xfs"
 
 _log "stress ext2 on xfs via loop"
-src/fsstress -d $SCRATCH_MNT/test2 -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \
+ltp/fsstress -d $SCRATCH_MNT/test2 -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \
     || _fail "!!! stress ext2 failed"   
 
 _log "clean"
diff --git a/065 b/065
index 5e2c6a8ee4c725522780b66bdae95a8684a9a3cd..aaa0edfd4511905539f8a14b49736dbc4c701d7a 100755 (executable)
--- a/065
+++ b/065
@@ -98,8 +98,7 @@ umount $SCRATCH_DEV
 #
 
 _wipe_fs
-mkdir -p $dump_dir ||\
-    _error "cannot mkdir \"$dump_dir\""
+mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
 cd $dump_dir
 
 echo "Do the incremental dumps"
diff --git a/067 b/067
index 31d1950d593aad792f384270645d295c44dea08c..8312ac43f1aef5e749de4f29dc23d3e701eb0c76 100755 (executable)
--- a/067
+++ b/067
@@ -59,9 +59,8 @@ _acl_requirements
 _require_scratch
 
 # set up fs for 1K inodes
-export MKFS_OPTIONS="-i size=1024"
-_scratch_mkfs_xfs >>$here/$seq.full || _error "mkfs failed"
-_scratch_mount >>$here/$seq.full || _error "mount failed"
+_scratch_mkfs_xfs -i size=1024 >>$here/$seq.full || _fail "mkfs failed"
+_scratch_mount >>$here/$seq.full || _fail "mount failed"
 cd $SCRATCH_MNT
 
 # xfs_growfs -n $SCRATCH_MNT
diff --git a/068 b/068
index 405304cfbabdbd03807e314cf8f9b32747158228..fec586bfdcad9920fb561eb87e6f8a5fce4a5e39 100755 (executable)
--- a/068
+++ b/068
@@ -181,7 +181,7 @@ then
                # -n 10 makes this take about 10 seconds,
                # This allows the loop to end shortly after $tmp/running
                # is deleted
-               $here/src/fsstress -d "$STRESS_DIR" -n 10  > /dev/null 2>&1
+               $here/ltp/fsstress -d "$STRESS_DIR" -n 10  > /dev/null 2>&1
                sync
        done
 
diff --git a/070 b/070
index 75d3e638fee1180527e754a8e25d31a9bdeafde6..f2eb6e7f091518fdebfd444fce87138b37b0b875 100755 (executable)
--- a/070
+++ b/070
@@ -52,7 +52,7 @@ trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15
 
 # real QA test starts here
 
-$here/src/fsstress \
+$here/ltp/fsstress \
        -d $TEST_DIR/fsstress \
        -f allocsp=0 \
        -f freesp=0 \
index dea3f30df950810d4634178931e74b99066fc305..b4065dd20e350518b6945a756baf87caef52724a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (c) 2000-2003 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
@@ -39,11 +39,11 @@ endif
 
 TESTS = $(shell sed -n -e '/^[0-9][0-9][0-9]*/s/ .*//p' group)
 CONFIGURE = configure include/builddefs
-LSRCFILES = configure configure.in
-LDIRT = *.bad *.new *.core *.full *.raw core a.out *.bak \
-       check.log check.time config.* conftest*
+LSRCFILES = configure configure.in aclocal.m4 README VERSION
+LDIRT = config.log .dep config.status config.cache confdefs.h conftest* \
+       check.log check.time
 
-SUBDIRS = include src
+SUBDIRS = include lib ltp src m4
 
 default: $(CONFIGURE) new remake check $(TESTS)
 ifeq ($(HAVE_BUILDDEFS), no)
@@ -58,14 +58,13 @@ else
 clean:  # if configure hasn't run, nothing to clean
 endif
 
-$(CONFIGURE): configure.in include/builddefs.in
-       rm -f config.cache
+$(CONFIGURE):
        autoconf
        ./configure
 
-install install-dev: default
-       $(SUBDIRS_MAKERULE)
+aclocal.m4::
+       aclocal --acdir=$(TOPDIR)/m4 --output=$@
 
 realclean distclean: clean
        rm -f $(LDIRT) $(CONFIGURE)
-       rm -rf autom4te.cache
+       rm -rf autom4te.cache Logs
index 3ba9a7cea3d8ca9dbcd38232c12466daaa0de100..3202fff61e9a5a01ed55b0c29527d90c196d13a1 100644 (file)
@@ -76,7 +76,7 @@ export MOUNT_OPTIONS=${MOUNT_OPTIONS:=-ologbufs=2}
 export CHECK_OPTIONS=${CHECK_OPTIONS:="-g auto"}
 export BENCH_PASSES=${BENCH_PASSES:=5}
 
-export DEBUG=${DEBUG:=-DEXPERIMENTAL_LARGE_SECTORS}
+#export DEBUG=${DEBUG:=...} # arbitrary CFLAGS really.
 export MALLOCLIB=${MALLOCLIB:=/usr/lib/libefence.a}
 export LOCAL_CONFIGURE_OPTIONS=${LOCAL_CONFIGURE_OPTIONS:=--enable-readline=yes}
 
@@ -105,7 +105,8 @@ in
     flutz)
        MODULAR=0
        EMAIL="nathans@larry"
-        TEST_DEV=/dev/sda5
+       TEST_DEV=/dev/sda5
+       TEST_LOGDEV=/dev/sda9
        TEST_DIR=/xfsqa1
        SCRATCH_DEV=/dev/sda6
        SCRATCH_LOGDEV=/dev/sda7
index c24bec8d26061f8c46fd4b8fa19daa813a4bb186..eeb74cd4b9c3c32a16d86f455624ab42975da977 100644 (file)
@@ -228,20 +228,12 @@ _require_tape()
     _set_variable
 }
 
-_error()
-{
-    echo "Error: $*" | tee -a $here/$seq.full
-    echo "(see $here/$seq.full for details)"
-    status=1
-    exit
-}
-
 _wipe_fs()
 {
     _require_scratch
 
-    _scratch_mkfs_xfs >>$here/$seq.full || _error "mkfs failed"
-    _scratch_mount >>$here/$seq.full || _error "mount failed"
+    _scratch_mkfs_xfs >>$here/$seq.full || _fail "mkfs failed"
+    _scratch_mount >>$here/$seq.full || _fail "mount failed"
 }
 
 # 
@@ -286,20 +278,20 @@ _cleanup()
 _stable_fs()
 {
     _saveddir=`pwd`; cd /
-    umount $SCRATCH_MNT >>$here/$seq.full || _error "unmount failed"
-    _scratch_mount >>$here/$seq.full || _error "mount failed"
+    umount $SCRATCH_MNT >>$here/$seq.full || _fail "unmount failed"
+    _scratch_mount >>$here/$seq.full || _fail "mount failed"
     cd $_saveddir
 }
 
 #
-# Run src/fsstress to create a mixture of 
+# Run fsstress to create a mixture of 
 # files,dirs,links,symlinks
 #
 # Pinched from test 013.
 #
 _create_dumpdir_stress()
 {
-    echo "Creating directory system to dump using src/fsstress."
+    echo "Creating directory system to dump using fsstress."
 
     _wipe_fs
 
@@ -315,7 +307,7 @@ _create_dumpdir_stress()
     echo "-----------------------------------------------"
     echo "fsstress : $_param"
     echo "-----------------------------------------------"
-    if ! $here/src/fsstress $_param -s 1 $FSSTRESS_AVOID -n $_count -d $dump_dir >$tmp.out 2>&1
+    if ! $here/ltp/fsstress $_param -s 1 $FSSTRESS_AVOID -n $_count -d $dump_dir >$tmp.out 2>&1
     then
         echo "    fsstress (count=$_count) returned $? - see $here/$seq.full"
         
@@ -452,8 +444,7 @@ _do_create_dumpdir_fill()
 {
     echo "Creating directory system to dump using src/fill."
 
-    mkdir -p $dump_dir ||\
-       _error "cannot mkdir \"$dump_dir\""
+    mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
     cd $dump_dir
 
     $verbose && echo -n "Setup "
@@ -524,8 +515,7 @@ _do_create_dumpdir_fill()
 _create_dumpdir_largefile()
 {
     _wipe_fs
-    mkdir -p $dump_dir ||\
-       _error "cannot mkdir \"$dump_dir\""
+    mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
     _largesize=4294967297
     _largefile=$dump_dir/largefile
     echo "dd a largefile at offset $_largesize"
@@ -598,8 +588,7 @@ _do_create_dump_symlinks()
 {
     echo "Creating directory system of symlinks to dump."
 
-    mkdir -p $dump_dir ||\
-       _error "cannot mkdir \"$dump_dir\""
+    mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
     cd $dump_dir
 
     $verbose && echo -n "Setup "
@@ -721,8 +710,7 @@ _create_dumpdir_hardlinks()
     _wipe_fs
     echo "Creating directory system of hardlinks to incrementally dump."
 
-    mkdir -p $dump_dir ||\
-       _error "cannot mkdir \"$dump_dir\""
+    mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
     cd $dump_dir
 
     _create_hardset $_numsets
@@ -838,12 +826,12 @@ _parse_args()
         case $1
         in
         -f)
-            [ -z "$2" ] && _error "missing argument for -f"
+            [ -z "$2" ] && _fail "missing argument for -f"
            dumptape=$2 
            shift
             ;;
         -L)
-            [ -z "$2" ] && _error "missing argument for -L"
+            [ -z "$2" ] && _fail "missing argument for -L"
            session_label=$2
            shift
             ;;
@@ -864,12 +852,12 @@ _parse_args()
             do_quota_check=false
             ;;
         -l)
-            [ -z "$2" ] && _error "missing argument for -l"
+            [ -z "$2" ] && _fail "missing argument for -l"
            dump_args="$dump_args -l$2"
            shift
             ;;
        *)
-            _error "invalid argument to common.dump function: $1"
+            _fail "invalid argument to common.dump function: $1"
             ;;
         esac
        shift
@@ -958,8 +946,7 @@ _do_dump_multi_file()
 _prepare_restore_dir()
 {
     rm -rf $restore_dir
-    mkdir $restore_dir ||\
-       _error "failed to mkdir $restore_dir"
+    mkdir $restore_dir || _fail "failed to mkdir $restore_dir"
 }
 
 
index 19966c51becc453c5be5861cbf4b37ead3266c7d..b545b03bd39712e564863e0745dd1481df3d4f4b 100644 (file)
-dnl unpacking check - this file must exist
-AC_INIT(src/fsstress.c)
-pkg_name="xfstests"
-AC_SUBST(pkg_name)
+AC_INIT(src/xfsctl.c)
+AC_PACKAGE_GLOBALS(xfstests)
+AC_PACKAGE_UTILITIES(xfstests)
 
-#
-# Note: the following environment variables may be set to override the
-# defaults (to change paths and/or executables, build parameters, etc):
-#
-#   DEBUG  OPTIMIZER  MAKE  CC  LD  TAR  ZIP  RPM  AWK  SED  ECHO
-#   MALLOCLIB  DISTRIBUTION  PACKAGE_BUILDER  PREFIX  ROOT_PREFIX
-#
+AC_PACKAGE_NEED_UUID_H
+AC_PACKAGE_NEED_UUIDCOMPARE
 
-DEBUG=${DEBUG:-'-DDEBUG'}              # -DNDEBUG
-OPTIMIZER=${OPTIMIZER:-'-g'}           # (-O1 enforced default)
-MALLOCLIB=${MALLOCLIB:-''}             # /usr/lib/libefence.a
+AC_PACKAGE_NEED_XFS_LIBXFS_H
+AC_PACKAGE_NEED_XFSCTL_MACRO
+AC_PACKAGE_NEED_LIBXFSINIT_LIBXFS
+AC_PACKAGE_NEED_XFS_HANDLE_H
+AC_PACKAGE_NEED_ATTRLIST_LIBHANDLE
 
-dnl Debug build?
-debug_build="$DEBUG"
-AC_SUBST(debug_build)
+AC_PACKAGE_NEED_ATTR_XATTR_H
+AC_PACKAGE_NEED_GETXATTR_LIBATTR
+AC_PACKAGE_NEED_SYS_ACL_H
+AC_PACKAGE_NEED_ACL_LIBACL_H
+AC_PACKAGE_NEED_ACLINIT_LIBACL
 
-dnl Optimization options?
-opt_build="$OPTIMIZER"
-AC_SUBST(opt_build)
+AC_PACKAGE_WANT_LIBGDBM
 
-dnl Alternate malloc library?
-malloc_lib="$MALLOCLIB"
-AC_SUBST(malloc_lib)
-
-dnl Set version
-. ./VERSION
-
-pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION}
-pkg_release=$PKG_BUILD
-AC_SUBST(pkg_version)
-AC_SUBST(pkg_release)
-
-pkg_distribution="SGI ProPack"
-test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION"
-AC_SUBST(pkg_distribution)
-
-pkg_builder=`id -u -n`@`hostname`
-test -z "$PACKAGE_BUILDER" || pkg_builder="$PACKAGE_BUILDER"
-AC_SUBST(pkg_builder)
-
-dnl check if user wants their own C compiler
-test -z "$CC" && AC_PROG_CC
-cc=$CC
-AC_SUBST(cc)
-
-dnl check if users wants their own make
-test -z "$MAKE" && AC_PATH_PROG(MAKE, make, /usr/bin/make)
-make=$MAKE
-AC_SUBST(make)
-
-dnl check if users wants their own linker
-test -z "$LD" && AC_PATH_PROG(LD, ld, /usr/bin/ld)
-ld=$LD
-AC_SUBST(ld)
-
-dnl check if the tar program is available
-test -z "$TAR" && AC_PATH_PROG(TAR, tar)
-tar=$TAR
-AC_SUBST(tar)
-
-dnl check if the gzip program is available
-test -z "$ZIP" && AC_PATH_PROG(ZIP, gzip, /bin/gzip)
-zip=$ZIP
-AC_SUBST(zip)
-
-dnl check if the rpm program is available
-test -z "$RPM" && AC_PATH_PROG(RPM, rpm, /bin/rpm)
-rpm=$RPM
-AC_SUBST(rpm)
-
-dnl .. and what version is rpm
-rpm_version=0
-test -x $RPM && \
-       rpm_version=`$RPM --version | awk '{print $NF}' | awk -F. '{print $1}'`
-AC_SUBST(rpm_version)
-
-dnl check if the makedepend program is available
-test -z "$MAKEDEPEND" && AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true)
-makedepend=$MAKEDEPEND
-AC_SUBST(makedepend)
-
-dnl check if symbolic links are supported
-AC_PROG_LN_S
-
-dnl check if user wants their own awk, sed and echo
-test -z "$AWK" && AC_PATH_PROG(AWK, awk, /bin/awk)
-awk=$AWK
-AC_SUBST(awk)
-test -z "$SED" && AC_PATH_PROG(SED, sed, /bin/sed)
-sed=$SED
-AC_SUBST(sed)
-test -z "$ECHO" && AC_PATH_PROG(ECHO, echo, /bin/echo)
-echo=$ECHO
-AC_SUBST(echo)
-
-CPPFLAGS="-I/usr/include/xfs"
-AC_SUBST(CPPFLAGS)
-
-dnl Checks for UUID header and library.
-AC_CHECK_HEADER(uuid/uuid.h,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid UUID header.'
-       echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.'
-       exit 1
-])
-AC_CHECK_LIB(uuid, uuid_generate,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid UUID library.'
-       echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.'
-       exit 1
-])
-libuuid="/usr/lib/libuuid.a"
-AC_SUBST(libuuid)
-
-dnl Checks for base XFS headers and libraries.
-AC_CHECK_HEADER(xfs/libxfs.h,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid XFS library header.'
-       echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.'
-       echo 'Alternatively, run "make install-dev" from the xfsprogs source.'
-       exit 1
-])
-AC_CHECK_LIB(xfs, libxfs_init,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid XFS base library.'
-       echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.'
-       echo 'Alternatively, run "make install-dev" from the xfsprogs source.'
-       exit 1
-])
-AC_CHECK_HEADER(xfs/handle.h,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid XFS handle header.'
-       echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.'
-       echo 'Alternatively, run "make install-dev" from the xfsprogs source.'
-       exit 1
-])
-AC_CHECK_LIB(handle, path_to_handle,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid XFS handle library.'
-       echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.'
-       echo 'Alternatively, run "make install-dev" from the xfsprogs source.'
-       exit 1
-])
-libxfs="-lxfs"
-libhdl="-lhandle"
-AC_SUBST(libxfs)
-AC_SUBST(libhdl)
-
-dnl Checks for Extended Attributes header and library.
-AC_CHECK_HEADER(attr/xattr.h,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid Extended Attributes header.'
-       echo 'Install either the attr-devel (rpm) or the attr-dev (deb) package.'
-       echo 'Alternatively, run "make install-dev" from the attr source.'
-       exit 1
-])
-AC_CHECK_LIB(attr, getxattr,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid Extended Attributes library.'
-       echo 'Install either the libattr (rpm) or the libattr1 (deb) package.'
-       echo 'Alternatively, run "make install-lib" from the attr source.'
-       exit 1
-])
-libattr="-lattr"
-AC_SUBST(libattr)
-
-dnl Checks for Access Control List headers and library.
-AC_CHECK_HEADER(sys/acl.h,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid Access Control List headers.'
-       echo 'Install either the acl-devel (rpm) or the acl (deb) package.'
-       echo 'Alternatively, run "make install-dev" from the acl source.'
-       exit 1
-])
-AC_CHECK_HEADER(acl/libacl.h,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid Access Control List headers.'
-       echo 'Install either the acl-devel (rpm) or the acl (deb) package.'
-       echo 'Alternatively, run "make install-dev" from the acl source.'
-       exit 1
-])
-AC_CHECK_LIB(acl, acl_init,, [
-       echo
-       echo 'FATAL ERROR: could not find a valid Access Control List library.'
-       echo 'Install either the libacl (rpm) or the libacl1 (deb) package.'
-       echo 'Alternatively, run "make install-lib" from the acl source.'
-       exit 1
-])
-libacl="-lacl"
-AC_SUBST(libacl)
-
-dnl Checks for GNU database manager header and library.
-libgdbm=""
-have_db=true
-AC_CHECK_HEADER(gdbm/ndbm.h,, [ have_db=false ])
-if test $have_db = "true" -a -f /usr/lib/libgdbm.a; then
-       libgdbm="/usr/lib/libgdbm.a"
-fi
-AC_SUBST(libgdbm)
-AC_SUBST(have_db)
-
-dnl alternate root and usr prefixes
-test -z "$ROOT_PREFIX" && ROOT_PREFIX=""
-root_prefix="$ROOT_PREFIX"
-test -z "$PREFIX" && PREFIX="/usr"
-prefix="$PREFIX"
-
-dnl man pages (source)
-dnl also check if man page source is gzipped
-dnl (usually on Debian, but not Redhat pre-7.0)
-pkg_man_dir=${prefix}/share/man
-have_zipped_manpages=false
-for d in ${prefix}/share/man ${prefix}/man ; do
-    if test -f $d/man1/man.1.gz
-    then
-       pkg_man_dir=$d
-       have_zipped_manpages=true
-       break
-    fi
-done
-AC_SUBST(pkg_man_dir)
-AC_SUBST(have_zipped_manpages)
-
-dnl binaries
-pkg_bin_dir=${prefix}/sbin
-AC_SUBST(pkg_bin_dir)
-
-dnl static libraries
-pkg_lib_dir=${prefix}/lib
-AC_SUBST(pkg_lib_dir)
-
-dnl runtime shared system libraries
-pkg_slib_dir=${root_prefix}/lib
-AC_SUBST(pkg_slib_dir)
-
-dnl system binaries
-pkg_sbin_dir=${root_prefix}/sbin
-AC_SUBST(pkg_sbin_dir)
-
-dnl include files
-pkg_inc_dir=${prefix}/include
-AC_SUBST(pkg_inc_dir)
-
-dnl doc directory
-pkg_doc_dir=${prefix}/share/doc/${pkg_name}
-AC_SUBST(pkg_doc_dir)
-
-
-dnl
-dnl output files
-dnl
-
-AC_OUTPUT( \
-dnl  Build definitions for use in Makefiles
-    include/builddefs \
-)
+AC_OUTPUT(include/builddefs)
diff --git a/group b/group
index a7eea66003643d54d7979119c18c1665aa7e8436..3b52f2df0d716a1acc49c8302efca7f506c64636 100644 (file)
--- a/group
+++ b/group
@@ -130,4 +130,4 @@ ioctl               nathans@sgi.com
 070 attr auto
 071 rw
 072 rw
-073 copy
+#073 copy
index d6ec04d952af017a0af05de0e122285a4ad087fa..10648e49bee80759f36f182e2bb4409f47007930 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (c) 2000-2003 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
@@ -33,6 +33,8 @@
 TOPDIR = ..
 include $(TOPDIR)/include/builddefs
 
+HFILES = dataascii.h databin.h pattern.h \
+       random_range.h string_to_tokens.h tlibio.h write_log.h
 LSRCFILES = builddefs.in buildrules
 
 default install install-dev:
index 0befc549fccd1f4e79a333b50c8a6481684c6a40..f808ffd1a1da7b36ce66ab77262b564fbf86305c 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (c) 2003 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
@@ -45,124 +45,52 @@ LIBATTR = @libattr@
 LIBGDBM = @libgdbm@
 LIBUUID = @libuuid@
 LIBHANDLE = @libhdl@
-HAVE_DB = @have_db@
-CPPFLAGS = -I/usr/include/xfs -I/usr/include/attr
-
-BUILDRULES = $(TOPDIR)/include/buildrules
-
-# General package information
-PKG_NAME = @pkg_name@
-PKG_RELEASE = @pkg_release@
-PKG_VERSION = @pkg_version@
-PKG_DISTRIBUTION = @pkg_distribution@
-PKG_BUILDER = @pkg_builder@
-PKG_BIN_DIR = @pkg_bin_dir@
-PKG_LIB_DIR = @pkg_lib_dir@
-PKG_SBIN_DIR = @pkg_sbin_dir@
-PKG_SLIB_DIR = @pkg_slib_dir@
-PKG_INC_DIR = @pkg_inc_dir@
-PKG_MAN_DIR = @pkg_man_dir@
-PKG_DOC_DIR = @pkg_doc_dir@
-
-# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in
-# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES)
-# $(CXXFILES), or $(HFILES) and is used to construct the manifest list
-# during the "dist" phase (packaging).
-
-CFLAGS += -O1 $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall $(LCFLAGS) \
-       -I$(TOPDIR)/include '-DVERSION="$(PKG_VERSION)"' -D_GNU_SOURCE \
-       -D_FILE_OFFSET_BITS=64
-
-LDFLAGS = $(LLDFLAGS)
-LDLIBS = $(LLDLIBS) $(MALLOCLIB)
-
-MAKEOPTS = --no-print-directory
-SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES)
-DIRT = $(LDIRT) dep dep.bak $(OBJECTS) $(CMDTARGET) $(LIBTARGET) \
-       $(STATICLIBTARGET) *.[1-9].gz
-
-OBJECTS = $(ASFILES:.s=.o) \
-          $(CFILES:.c=.o) \
-          $(LFILES:.l=.o) \
-          $(YFILES:%.y=%.tab.o)
-
-MAKE   = @make@
-CC     = @cc@
-LD     = @ld@
-AWK    = @awk@
-SED    = @sed@
-INSTALL        = $(TOPDIR)/install-sh -o root -g root
-ECHO   = @echo@
-LN_S   = @LN_S@
-
-CCF    = $(CC) $(CFLAGS)
-MAKEF  = $(MAKE) $(MAKEOPTS)
-CXXF   = $(CXX) $(CXXFLAGS)
-LDF    = $(LD) $(LDFLAGS)
-MAKEDEPEND  = @makedepend@
-
-ZIP    = @zip@
-TAR    = @tar@
-RPM    = @rpm@
-RPM_VERSION = @rpm_version@
-
-HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@
-
-SHELL = /bin/sh
-IMAGES_DIR = $(TOPDIR)/all-images
-DIST_DIR = $(TOPDIR)/dist
-
-SUBDIRS_MAKERULE = \
-       @for d in $(SUBDIRS) ""; do \
-           if test -d "$$d" -a ! -z "$$d"; then \
-               $(ECHO) === $$d ===; \
-               $(MAKEF) -C $$d $@ || exit $$?; \
-           fi; \
-       done
-
-MAN_MAKERULE = \
-    @for f in *.[12345678] ""; do \
-       if test ! -z "$$f"; then \
-           $(ZIP) --best -c < $$f > $$f.gz; \
-       fi; \
-    done
+LIBTEST = $(TOPDIR)/lib/libtest.la
+
+PKG_NAME        = @pkg_name@
+PKG_USER        = @pkg_user@
+PKG_GROUP       = @pkg_group@
+PKG_RELEASE     = @pkg_release@
+PKG_VERSION     = @pkg_version@
+PKG_PLATFORM    = @pkg_platform@
+PKG_DISTRIBUTION= @pkg_distribution@
+
+CC              = @cc@
+AWK             = @awk@
+SED             = @sed@
+TAR             = @tar@
+ZIP             = @zip@
+MAKE            = @make@
+ECHO            = @echo@
+SORT            = @sort@
+LN_S            = @LN_S@
+LIBTOOL         = @LIBTOOL@
+MAKEDEPEND      = @makedepend@
+
+MSGFMT          = @msgfmt@
+MSGMERGE        = @msgmerge@
+
+RPM             = @rpm@
+RPMBUILD        = @rpmbuild@
+RPM_VERSION     = @rpm_version@
+
+ENABLE_SHARED = @enable_shared@
+ENABLE_DBM = @enable_dbm@
+
+ifeq ($(PKG_PLATFORM),linux)
+PCFLAGS = -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
+endif
+ifeq ($(PKG_PLATFORM),darwin)
+PCFLAGS = -traditional-cpp
+endif
 
-INSTALL_MAN = \
-    @for d in $(MAN_PAGES); do \
-       first=true; \
-       for m in `$(AWK) '/^\.SH NAME/ {ok=1; next} ok {print; exit}' $$d \
-       | sed -e 's/,/ /g' -e 's/\\-.*//' -e 's/\\\f[0-9]//g' -e 's/  / /g;q'`; \
-       do \
-           [ -z "$$m" -o "$$m" = "\\" ] && continue; \
-           t=$(MAN_DEST)/$$m.$(MAN_SECTION); \
-           if $$first; then \
-               if $(HAVE_ZIPPED_MANPAGES); then \
-                   $(ZIP) --best -c $$d > $$d.gz; _sfx=.gz; \
-               fi; \
-               u=$$m.$(MAN_SECTION)$$_sfx; \
-               echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \
-               $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \
-           else \
-               echo $(INSTALL) -S $$u $${t}$$_sfx; \
-               $(INSTALL) -S $$u $${t}$$_sfx; \
-           fi; \
-           first=false; \
-       done; \
-    done
+CFLAGS += -O1 $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall -I$(TOPDIR)/include \
+       -DVERSION=\"$(PKG_VERSION)\"
 
-DIST_MAKERULE = \
-       $(MAKEF) -C build dist
+# Global, Platform, Local CFLAGS
+CFLAGS += $(GCFLAGS) $(PCFLAGS) $(LCFLAGS)
 
-SOURCE_MAKERULE = \
-       @test -z "$$DIR" && DIR="."; \
-       for f in $(SRCFILES) ""; do \
-           if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\
-       done; \
-       for d in `echo $(SUBDIRS)` ; do \
-           if test -d "$$d" -a ! -z "$$d"; then \
-               $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \
-           fi; \
-       done
+include $(TOPDIR)/include/buildmacros
 
 endif
 
diff --git a/include/buildmacros b/include/buildmacros
new file mode 100644 (file)
index 0000000..bce094c
--- /dev/null
@@ -0,0 +1,181 @@
+#
+# Copyright (c) 2002-2003 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., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, 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/SGIGPLNoticeExplan/
+#
+
+BUILDRULES = $(TOPDIR)/include/buildrules
+
+# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in
+# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES)
+# $(CXXFILES), or $(HFILES) and is used to construct the manifest list
+# during the "dist" phase (packaging).
+
+LDFLAGS = $(LLDFLAGS)
+LDLIBS = $(LLDLIBS) $(PLDLIBS) $(MALLOCLIB)
+
+MAKEOPTS = --no-print-directory
+SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES)
+
+DEPDIRT = dep dep.bak
+MANDIRT = *.[1-9].gz
+PODIRT = *.tmpo *.mo
+CDIRT = $(OBJECTS) $(LTOBJECTS) $(LTCOMMAND) $(LTLIBRARY)
+DIRT = $(LDIRT) $(DEPDIRT) $(MANDIRT) $(PODIRT) $(CDIRT)
+
+OBJECTS = $(ASFILES:.s=.o) \
+         $(CFILES:.c=.o) \
+         $(LFILES:.l=.o) \
+         $(YFILES:%.y=%.tab.o)
+
+INSTALL        = $(TOPDIR)/install-sh -o $(PKG_USER) -g $(PKG_GROUP)
+
+SHELL = /bin/sh
+IMAGES_DIR = $(TOPDIR)/all-images
+DIST_DIR = $(TOPDIR)/dist
+
+CCF    = $(CC) $(CFLAGS) $(CPPFLAGS)
+MAKEF  = $(MAKE) $(MAKEOPTS)
+CXXF   = $(CXX) $(CXXFLAGS)
+
+# For libtool.
+LIBNAME = $(basename $(LTLIBRARY))
+LTOBJECTS = $(OBJECTS:.o=.lo)
+LTVERSION = $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+LTLINK = $(LIBTOOL) --mode=link $(CC)
+LTEXEC = $(LIBTOOL) --mode=execute
+LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CCF) -D_REENTRANT -fno-strict-aliasing
+
+ifeq ($(ENABLE_SHARED),yes)
+LTLDFLAGS += -rpath $(PKG_LIB_DIR)
+LTLDFLAGS += -version-info $(LTVERSION)
+endif
+
+ifeq ($(ENABLE_SHARED),yes)
+INSTALL_LTLIB = \
+       cd $(TOPDIR)/$(LIBNAME)/.libs; \
+       ../$(INSTALL) -m 755 -d $(PKG_LIB_DIR); \
+       ../$(INSTALL) -m 644 -T so_dot_version $(LIBNAME).lai $(PKG_LIB_DIR); \
+       test "$(PKG_DISTRIBUTION)" = debian || \
+       ../$(INSTALL) -T so_dot_current $(LIBNAME).lai $(PKG_LIB_DIR)
+endif
+
+# Libtool thinks the static and shared libs should be in the same dir, so
+# make the static lib appear in the place we chose as rpath (using the two
+# symlinks below).
+# Other things want the shared libs to appear in /usr/lib, else they'll
+# link with the static libs there.  So, another symlink to get the .so into
+# /usr/lib.
+ifeq ($(ENABLE_SHARED),yes)
+INSTALL_LTLIB_DEV = \
+       cd $(TOPDIR)/$(LIBNAME)/.libs; \
+       ../$(INSTALL) -m 755 -d $(PKG_DEVLIB_DIR); \
+       ../$(INSTALL) -m 644 -T old_lib $(LIBNAME).lai $(PKG_DEVLIB_DIR); \
+       ../$(INSTALL) -m 644 $(LIBNAME).lai $(PKG_DEVLIB_DIR)/$(LIBNAME).la ; \
+       ../$(INSTALL) -m 755 -d $(PKG_LIB_DIR); \
+       ../$(INSTALL) -T so_base $(LIBNAME).lai $(PKG_LIB_DIR); \
+       ../$(INSTALL) -S $(PKG_DEVLIB_DIR)/$(LIBNAME).a $(PKG_LIB_DIR)/$(LIBNAME).a; \
+       ../$(INSTALL) -S $(PKG_DEVLIB_DIR)/$(LIBNAME).la $(PKG_LIB_DIR)/$(LIBNAME).la; \
+       ../$(INSTALL) -S $(PKG_LIB_DIR)/$(LIBNAME).so $(PKG_DEVLIB_DIR)/$(LIBNAME).so
+else
+INSTALL_LTLIB_DEV = $(INSTALL_LTLIB_STATIC)
+endif
+
+INSTALL_LTLIB_STATIC = \
+       cd $(TOPDIR)/$(LIBNAME)/.libs; \
+       ../$(INSTALL) -m 755 -d $(PKG_DEVLIB_DIR); \
+       ../$(INSTALL) -m 644 -T old_lib $(LIBNAME).lai $(PKG_DEVLIB_DIR)
+
+INSTALL_MAN = \
+       @for d in $(MAN_PAGES); do \
+               first=true; \
+               for m in `$(AWK) \
+                       '/^\.S[h|H] NAME/ {ok=1; next} ok {print; exit}' $$d \
+                       | $(SED) \
+                               -e 's/^\.Nm //' -e 's/,/ /g' -e 's/\\-.*//' \
+                               -e 's/\\\f[0-9]//g' -e 's/  / /g;q'`; \
+               do \
+                       [ -z "$$m" -o "$$m" = "\\" ] && continue; \
+                       t=$(MAN_DEST)/$$m.$(MAN_SECTION); \
+                       if $$first; then \
+                               if $(HAVE_ZIPPED_MANPAGES); then \
+                                       $(ZIP) -9 -c $$d > $$d.gz; _sfx=.gz; \
+                               fi; \
+                               u=$$m.$(MAN_SECTION)$$_sfx; \
+                               echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx;\
+                               $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \
+                       else \
+                               echo $(INSTALL) -S $$u $${t}$$_sfx; \
+                               $(INSTALL) -S $$u $${t}$$_sfx; \
+                       fi; \
+                       first=false; \
+               done; \
+       done
+
+ifeq ($(ENABLE_GETTEXT),yes)
+INSTALL_LINGUAS = \
+       @for l in $(LINGUAS) ""; do \
+               if test -f "$$l.mo" ; then \
+                       ldir=$(PKG_LOCALE_DIR)/$$l/LC_MESSAGES; \
+                       $(INSTALL) -m 755 -d $$ldir; \
+                       $(INSTALL) -m 644 $$l.mo $$ldir/$(PKG_NAME).mo; \
+               fi; \
+       done
+endif
+
+SUBDIRS_MAKERULE = \
+       @for d in $(SUBDIRS) ""; do \
+               if test -d "$$d" -a ! -z "$$d"; then \
+                       $(ECHO) === $$d ===; \
+                       $(MAKEF) -C $$d $@ || exit $$?; \
+               fi; \
+       done
+
+MAN_MAKERULE = \
+       @for f in *.[12345678] ""; do \
+               if test ! -z "$$f"; then \
+                       $(ZIP) --best -c < $$f > $$f.gz; \
+               fi; \
+       done
+
+DIST_MAKERULE = \
+       $(MAKEF) -C build dist
+
+SOURCE_MAKERULE = \
+       @test -z "$$DIR" && DIR="."; \
+       for f in $(SRCFILES) ""; do \
+           if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\
+       done; \
+       for d in `echo $(SUBDIRS)` ; do \
+           if test -d "$$d" -a ! -z "$$d"; then \
+               $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \
+           fi; \
+       done
index 9522042d1e49a11261811001d6c79de3b2078e12..cecb4c944a7be4c2ef996985803fdf1e888387cd 100644 (file)
@@ -1,10 +1,10 @@
 #
-# Copyright (c) 1999, 2001 Silicon Graphics, Inc.  All Rights Reserved.
-# 
+# Copyright (c) 1999, 2001-2003 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 Fondation.
-# 
+#
 # 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, any license provided herein,
@@ -15,7 +15,7 @@
 # distributed without any warranty that the program is delivered free of the
 # rightful claim of any third person by way of infringement or the like.  See
 # the GNU General Public License for more details.
-# 
+#
 # You should have received a copy of the GNU General Public License along with
 # this program; if not, write the Free Software Foundation, Inc., 59 Temple
 # Place - Suite 330, Boston MA 02111-1307, USA.
@@ -26,28 +26,9 @@ _BUILDRULES_INCLUDED_ = 1
 
 include $(TOPDIR)/include/builddefs
 
-#
-# Standard targets
-#
-ifdef CMDTARGET
-$(CMDTARGET) : $(SUBDIRS) $(OBJECTS)
-       $(CCF) -o $(CMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS) 
-$(CMDTARGET).static : $(SUBDIRS) $(OBJECTS)
-       $(CCF) -static -o $(CMDTARGET).static $(LDFLAGS) $(OBJECTS) $(LDLIBS) 
-endif
-
-ifdef LIBTARGET
-$(LIBTARGET) : $(SUBDIRS) $(OBJECTS)
-       $(CC) $(LDFLAGS) -fPIC -shared -Wl,-soname,$(LIBTARGET) -o $(LIBTARGET) $(OBJECTS) $(LDLIBS)
-endif
-
-ifdef STATICLIBTARGET
-$(STATICLIBTARGET) : $(SUBDIRS) $(OBJECTS)
-       $(AR) crf $(STATICLIBTARGET) $?
-endif
-
 clean clobber : $(SUBDIRS)
        rm -f $(DIRT)
+       @rm -fr .libs
        $(SUBDIRS_MAKERULE)
 
 # Never blow away subdirs
@@ -57,10 +38,41 @@ $(SUBDIRS):
        $(SUBDIRS_MAKERULE)
 endif
 
+#
+# Standard targets
+#
+
+ifdef LTCOMMAND
+$(LTCOMMAND) : $(SUBDIRS) $(OBJECTS) $(LTDEPENDENCIES)
+       $(LTLINK) -o $@ $(LDFLAGS) $(OBJECTS) $(LDLIBS)
+endif
+
+ifdef LTLIBRARY
+$(LTLIBRARY) : $(SUBDIRS) $(LTOBJECTS)
+       $(LTLINK) $(LTLDFLAGS) -o $(LTLIBRARY) $(LTOBJECTS) $(LTLIBS)
+
+%.lo: %.c
+       $(LTCOMPILE) -c $<
+endif
+
+ifdef LINGUAS
+%.pot: $(XGETTEXTFILES)
+       xgettext --omit-header --language=C --keyword=_ -o $@ $(XGETTEXTFILES)
+
+%.po: $(PKG_NAME).pot
+       $(MSGMERGE) -o $@.tmpo $@ $<
+       @if ! diff $@.tmpo $@ >/dev/null; then \
+               echo "$@ is out of date, see $@.tmpo"; \
+       fi
+
+%.mo: %.po
+       $(MSGFMT) -o $@ $<
+endif
+
 source :
        $(SOURCE_MAKERULE)
 
-endif
+endif # _BUILDRULES_INCLUDED_
 
 $(_FORCE):
 
@@ -68,10 +80,16 @@ $(_FORCE):
 
 depend : $(CFILES) $(HFILES)
        $(SUBDIRS_MAKERULE)
-       touch dep
-       $(MAKEDEPEND) -fdep -- $(CFLAGS) -- $(CFILES)
+       touch .dep
+       $(MAKEDEPEND) -f - -- $(CFLAGS) -- $(CFILES) | \
+       $(SED) -e 's,`pwd`,$(TOPDIR),g' \
+           -e 's,  */[^ ]*,,g' \
+           -e '/^[^ ]*: *$$/d' \
+           -e '/^#.*/d' -e '/^ *$$/d' \
+       > .dep
+       test -s .dep || rm -f .dep
 
 # Include dep, but only if it exists
-ifeq ($(shell test -f dep && echo dep), dep)
-include dep
+ifeq ($(shell test -f .dep && echo .dep), .dep)
+include .dep
 endif
diff --git a/include/dataascii.h b/include/dataascii.h
new file mode 100644 (file)
index 0000000..cd75245
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#ifndef _DATAASCII_H_
+#define _DATAASCII_H_
+
+/***********************************************************************
+ * int dataasciigen(listofchars, buffer, size, offset)
+ *
+ * This function fills buffer with ascii characters.
+ * The ascii characters are obtained from listofchars or the CHARS array
+ *  if listofchars is NULL.
+ * Each char is selected by an index.  The index is the remainder
+ *  of count divided by the array size. 
+ * This method allows more than one process to write to a location
+ *  in a file without corrupting it for another process' point of view.
+ *
+ * The return value will be the number of character written in buffer
+ *  (size).
+ *
+ ***********************************************************************/
+int dataasciigen(char *, char *, int, int);
+
+/***********************************************************************
+ * int dataasciichk(listofchars, buffer, size, count, errmsg)
+ *
+ * This function checks the contents of a buffer produced by
+ *  dataasciigen.
+ *
+ * return values:
+ *     >= 0 : error at character count
+ *     < 0  : no error
+ ***********************************************************************/
+
+int dataasciichk(char *, char *, int, int, char**);
+
+#endif
diff --git a/include/databin.h b/include/databin.h
new file mode 100644 (file)
index 0000000..b71fbc0
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef _DATABIN_H_
+#define _DATABIN_H_
+
+/*******************************************************************************
+* NAME
+*       databingen - fill a buffer with a data pattern
+*
+* SYNOPSIS
+*       (void) databingen(mode, buffer, bsize, offset)
+*       int     mode;
+*       char    *buffer;
+*       int     bsize;
+*      int     offset;
+*
+* DESCRIPTION
+*       datagen fills the buffer pointed to by 'buffer' with 'bsize' bytes
+*       of data of the form indicated by 'mode'.  
+*      All modes (expect r -random) are file offset based.
+*      This allows more than process to do writing to the file without
+*      corrupting it if the same modes were used.
+*      They data modes to choose from, these are:
+*
+*               'a' - writes an alternating bit pattern (i.e. 0x5555555...)
+*
+*               'c' - writes a checkerboard pattern (i.e. 0xff00ff00ff00...)
+*
+*              'C' - writes counting pattern (i.e. 0 - 07, 0 - 07, ...);
+*
+*              'o' - writes all bits set (i.e. 0xffffffffffffff...)
+*
+*              'z' - writes all bits cleared (i.e. 0x000000000...);
+*
+*               'r' - writes random integers
+*
+* RETURN VALUE
+*       None
+*
+*******************************************************************************/
+
+void databingen( int mode, unsigned char *buffer, int bsize, int offset );
+
+void databinchedk( int mode, unsigned char *buffer, int bsize, int offset, char **errmsg);
+
+#endif
diff --git a/include/file_lock.h b/include/file_lock.h
new file mode 100644 (file)
index 0000000..8c9a948
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#ifndef _FILE_LOCK_H_
+#define _FILE_LOCK_H_
+
+extern char Fl_syscall_str[128];
+
+int file_lock( int , int, char ** );
+int record_lock( int , int , int , int , char ** );
+
+#endif /* _FILE_LOCK_H_ */
diff --git a/include/forker.h b/include/forker.h
new file mode 100644 (file)
index 0000000..effd5d6
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#ifndef _FORKER_H_
+#define _FORKER_H_
+
+#define FORKER_MAX_PIDS        4098
+
+extern int Forker_pids[FORKER_MAX_PIDS];      /* holds pids of forked processes */
+extern int Forker_npids;               /* number of entries in Forker_pids */
+
+/*
+ * This function will fork and the parent will exit zero and
+ * the child will return.  This will orphan the returning process
+ * putting it in the background.
+ */
+int background( char * );
+
+/*
+ * Forker will fork ncopies-1 copies of self. 
+ *
+ * arg 1: Number of copies of the process to be running after return.
+ *        This value minus one is the number of forks performed. 
+ * arg 2: mode: 0 - all children are first generation descendents.
+ *              1 - each subsequent child is a descendent of another
+ *              descendent, resulting in only one direct descendent of the
+ *              parent and each other child is a child of another child in
+ *              relation to the parent.
+ * arg 3: prefix: string to preceed any error messages.  A value of NULL
+ *              results in no error messages on failure.
+ * returns: returns to parent the number of children forked.
+ */
+int forker( int , int , char * );
+
+#endif /* _FORKER_H_ */
diff --git a/include/open_flags.h b/include/open_flags.h
new file mode 100644 (file)
index 0000000..87fe6ff
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#ifndef _OPEN_FLAGS_H_
+#define _OPEN_FLAGS_H_
+
+/***********************************************************************
+ * This function attempts to convert open flag bits into human readable
+ * symbols (i.e. O_TRUNC).  If there are more than one symbol,
+ * the <sep> string will be placed as a separator between symbols.
+ * Commonly used separators would be a comma "," or pipe "|".
+ * If <mode> is one and not all <openflags> bits can be converted to
+ * symbols, the "UNKNOWN" symbol will be added to return string.
+ * 
+ * Return Value
+ * openflags2symbols will return the indentified symbols.
+ * If no symbols are recognized the return value will be a empty
+ * string or the "UNKNOWN" symbol.
+ *
+ * Limitations
+ * Currently (05/96) all known symbols are coded into openflags2symbols.
+ * If new open flags are added this code will have to updated
+ * to know about them or they will not be recognized.
+ *
+ * The Open_symbols must be large enough to hold all possible symbols
+ * for a given system.
+ *
+ ***********************************************************************/
+char *openflags2symbols( int, char *, int );
+
+/***********************************************************************
+ * This function will take a string of comma separated open flags symbols
+ * and translate them into an open flag bitmask.
+ * If any symbol is not valid, -1 is returned.  On this error condition
+ * the badname pointer is updated if not NULL.  badname will point
+ * to the beginning location of where the invalid symbol was found.
+ * string will be returned unchanged. 
+ *
+ * A signal received while parsing string could cause the string to
+ * contain a NULL character in the middle of it.
+ *
+ ***********************************************************************/
+int parse_open_flags( char *, char ** );
+
+#endif
diff --git a/include/pattern.h b/include/pattern.h
new file mode 100644 (file)
index 0000000..74f841c
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#ifndef _PATTERN_H_
+#define _PATTERN_H_
+
+/*
+ * pattern_check(buf, buflen, pat, patlen, patshift)
+ *
+ * Check a buffer of length buflen against repeated occurrances of
+ * a pattern whose length is patlen.  Patshift can be used to rotate
+ * the pattern by patshift bytes to the left.
+ *
+ * Patshift may be greater than patlen, the pattern will be rotated by
+ * (patshift % patshift) bytes.
+ *
+ * pattern_check returns -1 if the buffer does not contain repeated
+ * occurrances of the indicated pattern (shifted by patshift).
+ *
+ * The algorithm used to check the buffer relies on the fact that buf is 
+ * supposed to be repeated copies of pattern.  The basic algorithm is
+ * to validate the first patlen bytes of buf against the pat argument
+ * passed in - then validate the next patlen bytes against the 1st patlen
+ * bytes - the next (2*patlen) bytes against the 1st (2*pathen) bytes, and
+ * so on.  This algorithm only works when the assumption of a buffer full
+ * of repeated copies of a pattern holds, and gives MUCH better results
+ * then walking the buffer byte by byte.
+ *
+ * Performance wise, It appears to be about 5% slower than doing a straight
+ * memcmp of 2 buffers, but the big win is that it does not require a
+ * 2nd comparison buffer, only the pattern.
+ */
+int pattern_check( char * , int , char * , int , int );
+
+/*
+ * pattern_fill(buf, buflen, pat, patlen, patshift)
+ *
+ * Fill a buffer of length buflen with repeated occurrances of
+ * a pattern whose length is patlen.  Patshift can be used to rotate
+ * the pattern by patshift bytes to the left.
+ *
+ * Patshift may be greater than patlen, the pattern will be rotated by
+ * (patshift % patlen) bytes.
+ *
+ * If buflen is not a multiple of patlen, a partial pattern will be written
+ * in the last part of the buffer.  This implies that a buffer which is
+ * shorter than the pattern length will receive only a partial pattern ...
+ *
+ * pattern_fill always returns 0 - no validation of arguments is done.
+ *
+ * The algorithm used to fill the buffer relies on the fact that buf is 
+ * supposed to be repeated copies of pattern.  The basic algorithm is
+ * to fill the first patlen bytes of buf with the pat argument
+ * passed in - then copy the next patlen bytes with the 1st patlen
+ * bytes - the next (2*patlen) bytes with the 1st (2*pathen) bytes, and
+ * so on.  This algorithm only works when the assumption of a buffer full
+ * of repeated copies of a pattern holds, and gives MUCH better results
+ * then filling the buffer 1 byte at a time.
+ */
+int pattern_fill( char * , int , char * , int , int );
+
+#endif
diff --git a/include/str_to_bytes.h b/include/str_to_bytes.h
new file mode 100644 (file)
index 0000000..100d37d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#ifndef _STR_TO_BYTES_
+#define _STR_TO_BYTES_
+
+int       str_to_bytes  ( char * );
+long      str_to_lbytes ( char * );
+long long str_to_llbytes( char * );
+
+#endif
diff --git a/include/test.h b/include/test.h
new file mode 100644 (file)
index 0000000..8a7646b
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+
+/* $Id: test.h,v 1.1 2003/07/07 06:36:46 nathans Exp $ */
+
+#ifndef __TEST_H__
+#define __TEST_H__
+
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TPASS    0    /* Test passed flag */
+#define TFAIL    1    /* Test failed flag */
+#define TBROK    2    /* Test broken flag */
+#define TWARN    4    /* Test warning flag */
+#define TRETR    8    /* Test retire flag */
+#define TINFO    16   /* Test information flag */
+#define TCONF    32   /* Test not appropriate for configuration flag */
+
+/*
+ * To determine if you are on a Umk or Unicos system,
+ * use sysconf(_SC_CRAY_SYSTEM).  But since _SC_CRAY_SYSTEM
+ * is not defined until 90, it will be define here if not already
+ * defined.
+ * if ( sysconf(_SC_CRAY_SYSTEM) == 1 )
+ *    on UMK
+ * else   # returned 0 or -1 
+ *    on Unicos
+ * This is only being done on CRAY systems.
+ */
+#ifdef CRAY
+#ifndef _SC_CRAY_SYSTEM
+#define _SC_CRAY_SYSTEM  140
+#endif /* ! _SC_CRAY_SYSTEM */
+#endif /* CRAY */
+
+/*
+ * Ensure that NUMSIGS is defined.
+ * It should be defined in signal.h or sys/signal.h on
+ * UNICOS/mk and IRIX systems.   On UNICOS systems,
+ * it is not defined, thus it is being set to UNICOS's NSIG.
+ * Note:  IRIX's NSIG (signals are 1-(NSIG-1)) 
+ *      is not same meaning as UNICOS/UMK's NSIG  (signals 1-NSIG)
+ */
+#ifndef NUMSIGS
+#define NUMSIGS NSIG
+#endif
+
+
+/* defines for unexpected signal setup routine (set_usig.c) */
+#define FORK    1              /* SIGCLD is to be ignored */
+#define NOFORK  0              /* SIGCLD is to be caught */
+#define DEF_HANDLER 0  /* tells set_usig() to use default signal handler */
+
+/*
+ * The following defines are used to control tst_res and t_result reporting.
+ */
+
+#define TOUTPUT           "TOUTPUT"            /* The name of the environment variable */
+                                       /* that can be set to one of the following */
+                                       /* strings to control tst_res output */
+                                       /* If not set, TOUT_VERBOSE_S is assumed */
+
+#define TOUT_VERBOSE_S  "VERBOSE"      /* All test cases reported */
+#define TOUT_CONDENSE_S "CONDENSE"     /* ranges are used where identical messages*/
+                                       /* occur for sequential test cases */
+#define TOUT_NOPASS_S   "NOPASS"       /* No pass test cases are reported */
+#define TOUT_DISCARD_S  "DISCARD"      /* No output is reported */
+
+#define TST_NOBUF      "TST_NOBUF"     /* The name of the environment variable */
+                                       /* that can be set to control whether or not */
+                                       /* tst_res will buffer output into 4096 byte */
+                                       /* blocks of output */
+                                       /* If not set, buffer is done.  If set, no */
+                                       /* internal buffering will be done in tst_res */
+                                       /* t_result does not have internal buffering */
+
+/*
+ * The following defines are used to control tst_tmpdir, tst_wildcard and t_mkchdir
+ */
+
+#define TDIRECTORY  "TDIRECTORY"       /* The name of the environment variable */
+                                       /* that if is set, the value (directory) */
+                                       /* is used by all tests as their working */
+                                       /* directory.  tst_rmdir and t_rmdir will */
+                                       /* not attempt to clean up. */
+                                       /* This environment variable should only */
+                                       /* be set when doing system testing since */
+                                       /* tests will collide and break and fail */
+                                       /* because of setting it. */
+
+#define TEMPDIR        "/tmp"                  /* This is the default temporary directory. */
+                                       /* The environment variable TMPDIR is */
+                                       /* used prior to this valid by tempnam(3). */
+                                       /* To control the base location of the */
+                                       /* temporary directory, set the TMPDIR */
+                                       /* environment variable to desired path */
+
+/*
+ * The following contains support for error message passing.
+ * See test_error.c for details.
+ */
+#define  TST_ERR_MESG_SIZE      1023    /* max size of error message */
+#define  TST_ERR_FILE_SIZE      511     /* max size of module name used by compiler */
+#define  TST_ERR_FUNC_SIZE      127     /* max size of func name */
+
+typedef struct {
+    int  te_line;                       /* line where last error was reported.  Use */
+                                        /* "__LINE__" and let compiler do the rest */
+    int  te_level;                      /* If set, will prevent current stored */
+                                        /* error to not be overwritten */
+    char te_func[TST_ERR_FUNC_SIZE+1];  /* name of function of last error */
+                                        /* Name of function or NULL */
+    char te_file[TST_ERR_FILE_SIZE+1];  /* module of last error.  Use */
+                                        /* "__FILE__" and let compiler do the rest */
+    char te_mesg[TST_ERR_MESG_SIZE+1];  /* string of last error */
+
+} _TST_ERROR;
+
+extern _TST_ERROR Tst_error;            /* defined in test_error.c */
+#if __STDC__
+extern void tst_set_error(char *file, int line, char *func, char *fmt, ...);
+#else
+extern void tst_set_error();
+#endif
+extern void tst_clear_error();
+
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify the number of iterations.
+ * It is supported in parse_opts.c and USC_setup.c.
+ */
+#define USC_ITERATION_ENV       "USC_ITERATIONS"
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify to iteration until desired time
+ * in floating point seconds has gone by.
+ * Supported in USC_setup.c.
+ */
+#define USC_LOOP_WALLTIME      "USC_LOOP_WALLTIME"
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify that no functional checks are wanted.
+ * It is supported in parse_opts.c and USC_setup.c.
+ */
+#define USC_NO_FUNC_CHECK      "USC_NO_FUNC_CHECK"
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify the delay between each loop iteration.
+ * The value is in seconds (fractional numbers are allowed).
+ * It is supported in parse_opts.c.
+ */
+#define USC_LOOP_DELAY         "USC_LOOP_DELAY"
+
+/*
+ * The following prototypes are needed to remove compile errors
+ * on IRIX systems when compiled with -n32 and -64.
+ */
+extern void tst_res(int ttype, char *fname, char *arg_fmt, ...);
+extern void tst_resm(int ttype, char *arg_fmt, ...);
+extern void tst_brk(int ttype, char *fname, void (*func)(), 
+                                                       char *arg_fmt, ...);
+extern void tst_brkloop(int ttype, char *fname, void (*func)(), 
+                                                       char *arg_fmt, ...);
+extern void tst_brkm(int ttype, void (*func)(), char *arg_fmt, ...);
+extern void tst_brkloopm(int ttype, void (*func)(), char *arg_fmt, ...);
+
+extern int  tst_environ();
+extern void tst_exit();
+extern void tst_flush();
+
+/* prototypes for the t_res.c functions */
+extern void t_result(char *tcid, int tnum, int ttype, char *tmesg);
+extern void tt_exit();
+extern int  t_environ();
+extern void t_breakum(char *tcid, int total, int typ, char *msg, void (*fnc)());
+
+extern void tst_sig(int fork_flag, void (*handler)(), void (*cleanup)());
+extern void tst_tmpdir();
+extern void tst_rmdir();
+
+extern char * get_high_address(void);
+
+extern void get_kver(int*, int*, int*);
+extern int tst_kvercmp(int, int, int);
+
+#endif /* end of __TEST_H__ */
diff --git a/include/tlibio.h b/include/tlibio.h
new file mode 100644 (file)
index 0000000..ac0d570
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+
+#define LIO_IO_SYNC             00001   /* read/write */
+#define LIO_IO_ASYNC            00002   /* reada/writea/aio_write/aio_read */
+#define LIO_IO_SLISTIO          00004   /* single stride sync listio */
+#define LIO_IO_ALISTIO          00010   /* single stride async listio */
+#define LIO_IO_SYNCV            00020   /* single-buffer readv/writev */
+#define LIO_IO_SYNCP            00040   /* pread/pwrite */
+
+#ifdef sgi
+#define LIO_IO_ATYPES           00077   /* all io types */
+#define LIO_IO_TYPES            00061   /* all io types, non-async */
+#endif /* sgi */
+#ifdef linux
+#define LIO_IO_TYPES            00021   /* all io types */
+#endif /* linux */
+#ifdef CRAY
+#define LIO_IO_TYPES            00017   /* all io types */
+#endif /* CRAY */
+
+#define LIO_WAIT_NONE           00010000 /* return asap -- use with care */
+#define LIO_WAIT_ACTIVE         00020000 /* spin looking at iosw fields, or EINPROGRESS */
+#define LIO_WAIT_RECALL         00040000 /* call recall(2)/aio_suspend(3) */
+#define LIO_WAIT_SIGPAUSE       00100000 /* call pause */
+#define LIO_WAIT_SIGACTIVE      00200000 /* spin waiting for signal */
+#ifdef sgi
+#define LIO_WAIT_CBSUSPEND      00400000 /* aio_suspend waiting for callback */
+#define LIO_WAIT_SIGSUSPEND     01000000 /* aio_suspend waiting for signal */
+#define LIO_WAIT_ATYPES         01760000 /* all async wait types, except nowait */
+#define LIO_WAIT_TYPES          00020000 /* all sync wait types (sorta) */
+#endif /* sgi */
+#ifdef linux
+#define LIO_WAIT_TYPES          00300000 /* all wait types, except nowait */
+#endif /* linux */
+#ifdef CRAY
+#define LIO_WAIT_TYPES          00360000 /* all wait types, except nowait */
+#endif /* CRAY */
+
+/* meta wait io  */
+/*  00  000 0000 */
+
+#ifdef sgi
+/* all callback wait types */
+#define LIO_WAIT_CBTYPES       (LIO_WAIT_CBSUSPEND)
+/* all signal wait types */
+#define LIO_WAIT_SIGTYPES      (LIO_WAIT_SIGPAUSE|LIO_WAIT_SIGACTIVE|LIO_WAIT_SIGSUSPEND)
+/* all aio_{read,write} or lio_listio */
+#define LIO_IO_ASYNC_TYPES     (LIO_IO_ASYNC|LIO_IO_SLISTIO|LIO_IO_ALISTIO)
+#endif /* sgi */
+#ifdef linux
+/* all signal wait types */
+#define LIO_WAIT_SIGTYPES      (LIO_WAIT_SIGPAUSE)
+#endif /* linux */
+#ifdef CRAY
+/* all signal wait types */
+#define LIO_WAIT_SIGTYPES      (LIO_WAIT_SIGPAUSE|LIO_WAIT_SIGACTIVE)
+#endif /* CRAY */
+
+/*
+ * This bit provides a way to randomly pick an io type and wait method.
+ * lio_read_buffer() and lio_write_buffer() functions will call
+ * lio_random_methods() with the given method.
+ */
+#define LIO_RANDOM              010000000
+
+/*
+ * This bit provides a way for the programmer to use async i/o with
+ * signals and to use their own signal handler.  By default,
+ * the signal will only be given to the system call if the wait
+ * method is LIO_WAIT_SIGPAUSE or LIO_WAIT_SIGACTIVE.
+ * Whenever these wait methods are used, libio signal handler
+ * will be used.
+ */
+#define LIO_USE_SIGNAL          020000000
+
+/*
+ * prototypes/structures for functions in the libio.c module.  See comments
+ * in that module, or man page entries for information on the individual
+ * functions.
+ */
+
+int  stride_bounds(int offset, int stride, int nstrides,
+                     int bytes_per_stride, int *min_byte, int *max_byte);
+
+int  lio_set_debug(int level);
+int  lio_parse_io_arg1(char *string);
+void lio_help1(char *prefex);
+int  lio_parse_io_arg2(char *string, char **badtoken);
+void lio_help2(char *prefex);
+int  lio_write_buffer(int fd, int method, char *buffer, int size,
+                     int sig, char **errmsg, long wrd);
+
+int  lio_read_buffer(int fd, int method, char *buffer, int size,
+                    int sig, char **errmsg, long wrd);
+int  lio_random_methods(long mask);
+
+#if CRAY
+#include <sys/iosw.h>
+int  lio_wait4asyncio(int method, int fd, struct iosw **statptr);
+int  lio_check_asyncio(char *io_type, int size, struct iosw *status);
+#endif /* CRAY */
+#ifdef sgi
+#include <aio.h>
+int  lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp);
+int  lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method);
+#endif /* sgi */
+
+/*
+ * Define the structure that contains the infomation that is used
+ * by the parsing and help functions.
+ */
+struct lio_info_type {
+    char *token;
+    int  bits;
+    char *desc;
+};
+
+
diff --git a/include/usctest.h b/include/usctest.h
new file mode 100644 (file)
index 0000000..3655023
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+
+/* $Id: usctest.h,v 1.1 2003/07/07 06:36:46 nathans Exp $ */
+
+/**********************************************************
+ * 
+ *    IRIX/Linux Feature Test and Evaluation - Silicon Graphics, Inc.
+ * 
+ *    FUNCTION NAME    : usctest.h
+ * 
+ *    FUNCTION TITLE   : System Call Test Macros
+ * 
+ *    SYNOPSIS:
+ *     See DESCRIPTION below.
+ * 
+ *    AUTHOR           : William Roske
+ * 
+ *    INITIAL RELEASE  : UNICOS 7.0
+ * 
+ *    DESCRIPTION
+ *     TEST(SCALL) - calls a system call
+ *     TEST_VOID(SCALL) - same as TEST() but for syscalls with no return value.
+ *     TEST_CLEANUP - print the log of errno return counts if STD_ERRNO_LOG 
+ *                    is set.
+ *     TEST_PAUSEF(HAND) - Pause for SIGUSR1 if the pause flag is set.
+ *                   Use "hand" as the interrupt handling function
+ *     TEST_PAUSE -  Pause for SIGUSR1 if the pause flag is set.
+ *                   Use internal function to do nothing on signal and go on.
+ *     TEST_LOOPING(COUNTER) - Conditional to check if test should
+ *                   loop.  Evaluates to TRUE (1) or FALSE (0).
+ *     TEST_ERROR_LOG(eno) - log that this errno was received,
+ *                   if STD_ERRNO_LOG is set.
+ *     TEST_EXP_ENOS(array) - set the bits in TEST_VALID_ENO array at
+ *                   positions specified in integer "array"
+ *
+ *    RETURN VALUE
+ *     TEST(SCALL) - Global Variables set:
+ *                     int TEST_RETURN=return code from SCALL
+ *                     int TEST_ERRNO=value of errno at return from SCALL
+ *     TEST_VOID(SCALL) - Global Variables set:
+ *                     int TEST_ERRNO=value of errno at return from SCALL
+ *     TEST_CLEANUP - None.
+ *     TEST_PAUSEF(HAND) -  None.
+ *     TEST_PAUSE -  None.
+ *     TEST_LOOPING(COUNTER) - True if COUNTER < STD_LOOP_COUNT or
+ *                     STD_INFINITE is set.
+ *     TEST_ERROR_LOG(eno) - None
+ *     TEST_EXP_ENOS(array) - None
+ *
+ *    KNOWN BUGS
+ *      If you use the TEST_PAUSE or TEST_LOOPING macros, you must
+ *     link in parse_opts.o, which contains the code for those functions.
+ *
+ *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
+
+#ifndef  __USCTEST_H__
+#define __USCTEST_H__ 1
+
+#ifndef _SC_CLK_TCK
+#include <unistd.h>
+#endif
+
+#include <sys/param.h>
+
+/* 
+ * Ensure that PATH_MAX is defined 
+ */
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX  MAXPATHLEN
+#else
+#define PATH_MAX  1024
+#endif
+#endif
+
+#ifndef CRAY
+#ifndef BSIZE 
+#define BSIZE BBSIZE
+#endif
+#endif
+
+/***********************************************************************
+ * Define option_t structure type.
+ * Entries in this struct are used by the parse_opts routine
+ * to indicate valid options and return option arguments
+ ***********************************************************************/
+typedef struct {               
+  char *option;        /* Valid option string (one option only) like "a:" */
+  int  *flag;          /* pointer to location to set true if option given */
+  char **arg;          /* pointer to location to place argument, if needed */
+} option_t;
+
+/***********************************************************************
+ * The following globals are defined in parse_opts.c but must be 
+ * externed here because they are used in the macros defined below.
+ ***********************************************************************/
+extern int STD_FUNCTIONAL_TEST,        /* turned off by -f to not do functional test */
+           STD_TIMING_ON,      /* turned on by -t to print timing stats */
+           STD_PAUSE,          /* turned on by -p to pause before loop */
+           STD_INFINITE,       /* turned on by -i0 to loop forever */
+           STD_LOOP_COUNT,     /* changed by -in to set loop count to n */
+           STD_ERRNO_LOG,      /* turned on by -e to log errnos returned */
+           STD_ERRNO_LIST[],   /* counts of errnos returned.  indexed by errno */
+          STD_COPIES,
+          STD_argind;
+
+extern float STD_LOOP_DURATION, /* wall clock time to iterate */
+            STD_LOOP_DELAY;    /* delay time after each iteration */
+
+#define USC_MAX_ERRNO  2000
+    
+/**********************************************************************
+ * Prototype for parse_opts routine
+ **********************************************************************/
+extern char *parse_opts(int ac, char **av, option_t *user_optarr, void (*uhf)());
+
+
+/*
+ * define a structure 
+ */
+struct usc_errno_t {
+    int flag;
+};
+
+/***********************************************************************
+ ****
+ **** 
+ ****
+ **********************************************************************/
+#ifdef  _USC_LIB_
+
+extern int TEST_RETURN;
+extern int TEST_ERRNO;
+
+#else
+/***********************************************************************
+ * Global array of bit masks to indicate errnos that are expected.
+ * Bits set by TEST_EXP_ENOS() macro and used by TEST_CLEANUP() macro.
+ ***********************************************************************/
+struct usc_errno_t TEST_VALID_ENO[USC_MAX_ERRNO];
+
+/***********************************************************************
+ * Globals for returning the return code and errno from the system call
+ * test macros.
+ ***********************************************************************/
+int TEST_RETURN;
+int TEST_ERRNO;
+
+/***********************************************************************
+ * temporary variables for determining max and min times in TEST macro
+ ***********************************************************************/
+long btime, etime, tmptime;    
+
+#endif  /* _USC_LIB_ */
+
+/***********************************************************************
+ * structure for timing accumulator and counters 
+ ***********************************************************************/
+struct tblock {
+    long tb_max;
+    long tb_min;
+    long tb_total;
+    long tb_count;
+};
+
+/***********************************************************************
+ * The following globals are externed here so that they are accessable
+ * in the macros that follow.
+ ***********************************************************************/
+extern struct tblock tblock;
+extern void STD_go();
+extern int (*_TMP_FUNC)(void);
+extern void STD_opts_help();
+
+
+/***********************************************************************
+ * TEST: calls a system call 
+ * 
+ * parameters:
+ *     SCALL = system call and parameters to execute
+ *
+ ***********************************************************************/
+#define TEST(SCALL) errno=0; TEST_RETURN = (unsigned) SCALL;  TEST_ERRNO=errno;
+
+/***********************************************************************
+ * TEST_VOID: calls a system call
+ * 
+ * parameters:
+ *     SCALL = system call and parameters to execute
+ *
+ * Note: This is IDENTICAL to the TEST() macro except that it is intended
+ * for use with syscalls returning no values (void syscall()).  The 
+ * Typecasting nothing (void) into an unsigned integer causes compilation
+ * errors.
+ *
+ ***********************************************************************/
+#define TEST_VOID(SCALL)  errno=0; SCALL; TEST_ERRNO=errno;
+
+/***********************************************************************
+ * TEST_CLEANUP: print system call timing stats and errno log entries
+ * to stdout if STD_TIMING_ON and STD_ERRNO_LOG are set, respectively.
+ * Do NOT print ANY information if no system calls logged.
+ * 
+ * parameters:
+ *     none
+ *
+ ***********************************************************************/
+#define TEST_CLEANUP   \
+if ( STD_ERRNO_LOG ) {                                         \
+       for (tmptime=0; tmptime<USC_MAX_ERRNO; tmptime++) {             \
+            if ( STD_ERRNO_LIST[tmptime] )     {                       \
+                if ( TEST_VALID_ENO[tmptime].flag )                    \
+                    tst_resm(TINFO, "ERRNO %d:\tReceived %d Times",    \
+                             tmptime, STD_ERRNO_LIST[tmptime]);        \
+                else                                                   \
+                    tst_resm(TINFO,                                    \
+                             "ERRNO %d:\tReceived %d Times ** UNEXPECTED **",  \
+                             tmptime, STD_ERRNO_LIST[tmptime]);        \
+            }                                                          \
+       }                                                               \
+}
+
+/***********************************************************************
+ * TEST_PAUSEF: Pause for SIGUSR1 if the pause flag is set.
+ *              Set the user specified function as the interrupt
+ *              handler instead of "STD_go"
+ * 
+ * parameters:
+ *     none
+ *
+ ***********************************************************************/
+#define TEST_PAUSEF(HANDLER)                                   \
+if ( STD_PAUSE ) {                                     \
+    _TMP_FUNC = (int (*)())signal(SIGUSR1, HANDLER);   \
+    pause();                                           \
+    signal(SIGUSR1, (void (*)())_TMP_FUNC);            \
+}
+
+/***********************************************************************
+ * TEST_PAUSE: Pause for SIGUSR1 if the pause flag is set.
+ *            Just continue when signal comes in.
+ * 
+ * parameters:
+ *     none
+ *
+ ***********************************************************************/
+#define TEST_PAUSE usc_global_setup_hook();
+int usc_global_setup_hook();
+
+/***********************************************************************
+ * TEST_LOOPING now call the usc_test_looping function.
+ * The function will return 1 if the test should continue
+ * iterating.
+ *
+ ***********************************************************************/
+#define TEST_LOOPING usc_test_looping
+int usc_test_looping(int counter);
+
+/***********************************************************************
+ * TEST_ERROR_LOG(eno): log this errno if STD_ERRNO_LOG flag set
+ * 
+ * parameters:
+ *     int eno: the errno location in STD_ERRNO_LIST to log.
+ *
+ ***********************************************************************/
+#define TEST_ERROR_LOG(eno)            \
+    if ( STD_ERRNO_LOG )               \
+        if ( eno < USC_MAX_ERRNO )             \
+            STD_ERRNO_LIST[eno]++;     \
+
+
+/***********************************************************************
+ * TEST_EXP_ENOS(array): set the bits associated with the nput errnos
+ *     in the TEST_VALID_ENO array.
+ * 
+ * parameters:
+ *     int array[]: a zero terminated array of errnos expected.
+ *
+ ***********************************************************************/
+#define TEST_EXP_ENOS(array)                           \
+    tmptime=0;                                         \
+    while (array[tmptime] != 0) {                      \
+       if (array[tmptime] < USC_MAX_ERRNO)             \
+           TEST_VALID_ENO[array[tmptime]].flag=1;      \
+       tmptime++;                                      \
+    }
+                                       
+
+#endif  /* end of __USCTEST_H__ */
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644 (file)
index 0000000..5e37855
--- /dev/null
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2003 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., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, 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/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+LTLIBRARY = libtest.la
+LT_CURRENT = 0
+LT_REVISION = 0
+LT_AGE = 0
+
+# 
+# Everything (except for random.c) copied directly from LTP.
+# Refer to http://ltp.sourceforge.net/ for complete source.
+# 
+CFILES = dataascii.c databin.c datapid.c file_lock.c forker.c \
+       pattern.c open_flags.c random_range.c string_to_tokens.c \
+       str_to_bytes.c tlibio.c write_log.c \
+       random.c
+
+default: $(LTLIBRARY)
+
+include $(BUILDRULES)
+
+install install-dev: default
diff --git a/lib/dataascii.c b/lib/dataascii.c
new file mode 100644 (file)
index 0000000..4b18e38
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#include <stdio.h>
+#include <string.h>
+#include "dataascii.h"
+
+#define CHARS          "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjiklmnopqrstuvwxyz\n"
+#define CHARS_SIZE     sizeof(CHARS)
+
+#ifdef UNIT_TEST
+#include <stdlib.h> /* malloc */
+#endif
+
+static char Errmsg[80];
+
+int
+dataasciigen(listofchars, buffer, bsize, offset)
+char *listofchars;     /* a null terminated list of characters */
+char *buffer;
+int bsize;
+int offset;
+{
+   int cnt;
+   int total;
+   int ind;    /* index into CHARS array */
+   char *chr;
+   int chars_size;
+   char *charlist;
+
+       chr=buffer;
+       total=offset+bsize;
+
+       if ( listofchars == NULL ) {
+           charlist=CHARS;
+           chars_size=CHARS_SIZE;
+       }
+       else {
+           charlist=listofchars;
+           chars_size=strlen(listofchars);
+       }
+
+       for(cnt=offset; cnt<total;  cnt++) {
+               ind=cnt%chars_size;
+               *chr++=charlist[ind];
+       }
+
+       return bsize;
+
+}      /* end of dataasciigen */
+
+int
+dataasciichk(listofchars, buffer, bsize, offset, errmsg)
+char *listofchars;     /* a null terminated list of characters */
+char *buffer;
+int bsize;
+int offset;
+char **errmsg;
+{
+   int cnt;
+   int total;
+   int ind;    /* index into CHARS array */
+   char *chr;
+   int chars_size;
+   char *charlist;
+
+       chr=buffer;
+       total=offset+bsize;
+
+       if ( listofchars == NULL ) {
+           charlist=CHARS;
+           chars_size=CHARS_SIZE;
+       }
+       else {
+           charlist=listofchars;
+           chars_size=strlen(listofchars);
+       }
+
+       if ( errmsg != NULL ) {
+           *errmsg = Errmsg;
+       }
+
+       for(cnt=offset; cnt<total;  chr++, cnt++) {
+           ind=cnt%chars_size;
+           if ( *chr != charlist[ind] ) {
+               sprintf(Errmsg,
+                   "data mismatch at offset %d, exp:%#o, act:%#o", cnt,
+                   charlist[ind], *chr);
+               return cnt;
+           }
+       }
+
+       sprintf(Errmsg, "all %d bytes match desired pattern", bsize);
+       return -1;      /* buffer is ok */
+
+}      /* end of dataasciichk */
+
+
+#if UNIT_TEST
+
+/***********************************************************************
+ * main for doing unit testing
+ ***********************************************************************/
+int
+main(ac, ag)
+int ac;
+char **ag;
+{
+
+int size=1023;
+char *buffer;
+int ret;
+char *errmsg;
+
+    if ((buffer=(char *)malloc(size)) == NULL ) {
+        perror("malloc");
+        exit(2);
+    }
+
+    dataasciigen(NULL, buffer, size, 0);
+    printf("dataasciigen(NULL, buffer, %d, 0)\n", size);
+
+    ret=dataasciichk(NULL, buffer, size, 0, &errmsg);
+    printf("dataasciichk(NULL, buffer, %d, 0, &errmsg) returned %d %s\n",
+        size, ret, errmsg);
+
+    if ( ret == -1 )
+        printf("\tPASS return value is -1 as expected\n");
+    else
+        printf("\tFAIL return value is %d, expected -1\n", ret);
+
+    ret=dataasciichk(NULL, &buffer[1], size-1, 1, &errmsg);
+    printf("dataasciichk(NULL, &buffer[1], %d, 1, &errmsg) returned %d %s\n",
+        size-1, ret, errmsg);
+
+    if ( ret == -1 )
+        printf("\tPASS return value is -1 as expected\n");
+    else
+        printf("\tFAIL return value is %d, expected -1\n", ret);
+
+    buffer[25]= 0x0;
+    printf("changing char 25\n");
+
+    ret=dataasciichk(NULL, &buffer[1], size-1, 1, &errmsg);
+    printf("dataasciichk(NULL, &buffer[1], %d, 1, &errmsg) returned %d %s\n",
+        size-1, ret, errmsg);
+
+    if ( ret == 25 )
+       printf("\tPASS return value is 25 as expected\n");
+    else
+       printf("\tFAIL return value is %d, expected 25\n", ret);
+
+    dataasciigen("this is a test of the my string" , buffer, size, 0);
+    printf("dataasciigen(\"this is a test of the my string\", buffer, %d, 0)\n", size);
+
+    ret=dataasciichk("this is a test of the my string", buffer, size, 0, &errmsg);
+    printf("dataasciichk(\"this is a test of the my string\", buffer, %d, 0, &errmsg) returned %d %s\n",
+        size, ret, errmsg);
+
+    if ( ret == -1 )
+        printf("\tPASS return value is -1 as expected\n");
+    else
+        printf("\tFAIL return value is %d, expected -1\n", ret);
+
+    ret=dataasciichk("this is a test of the my string", &buffer[1], size-1, 1, &errmsg);
+    printf("dataasciichk(\"this is a test of the my string\", &buffer[1], %d, 1, &errmsg) returned %d %s\n",
+        size-1, ret, errmsg);
+
+    if ( ret == -1 )
+        printf("\tPASS return value is -1 as expected\n");
+    else
+        printf("\tFAIL return value is %d, expected -1\n", ret);
+
+    buffer[25]= 0x0;
+    printf("changing char 25\n");
+
+    ret=dataasciichk("this is a test of the my string", &buffer[1], size-1, 1, &errmsg);
+    printf("dataasciichk(\"this is a test of the my string\", &buffer[1], %d, 1, &errmsg) returned %d %s\n",
+        size-1, ret, errmsg);
+
+    if ( ret == 25 )
+       printf("\tPASS return value is 25 as expected\n");
+    else
+       printf("\tFAIL return value is %d, expected 25\n", ret);
+
+    exit(0);
+}
+
+#endif
+
diff --git a/lib/databin.c b/lib/databin.c
new file mode 100644 (file)
index 0000000..f09c2c8
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#include <stdio.h>
+#include <sys/param.h>
+#include <string.h> /* memset */
+#include <stdlib.h> /* rand */
+#include "databin.h"
+
+#if UNIT_TEST
+#include <malloc.h>
+#endif
+
+static char Errmsg[80];
+
+void
+databingen (mode, buffer, bsize, offset)
+int mode;      /* either a, c, r, o, z or C */
+unsigned char *buffer; /* buffer pointer */
+int bsize;     /* size of buffer */
+int offset;    /* offset into the file where buffer starts */
+{
+int ind;
+
+        switch (mode)
+        {
+        default:
+        case 'a':      /* alternating bit pattern */
+                memset(buffer,0x55,bsize);
+                break;
+
+        case 'c':      /* checkerboard pattern */
+                memset(buffer,0xf0,bsize);
+                break;
+
+       case 'C':       /* */
+                for (ind=0;ind< bsize;ind++) {
+                   buffer[ind] = ((offset+ind)%8 & 0177);
+               }
+               break;
+
+       case 'o':
+               memset(buffer,0xff,bsize);
+               break;
+
+       case 'z':
+               memset(buffer,0x0,bsize);
+               break;
+
+        case 'r':      /* random */
+                for (ind=0;ind< bsize;ind++) {
+                   buffer[ind] = (rand () & 0177) | 0100;
+               }
+        }
+}
+
+/***********************************************************************
+ *
+ * return values:
+ *      >= 0 : error at byte offset into the file, offset+buffer[0-(bsize-1)]
+ *      < 0  : no error
+ ***********************************************************************/
+int
+databinchk(mode, buffer, bsize, offset, errmsg)
+int mode;      /* either a, c, r, z, o, or C */
+unsigned char *buffer; /* buffer pointer */
+int bsize;     /* size of buffer */
+int offset;    /* offset into the file where buffer starts */
+char **errmsg;
+{
+    int cnt;
+    unsigned char *chr;
+    int total;
+    long expbits;
+    long actbits;
+
+       chr=buffer;
+       total=bsize;
+
+       if ( errmsg != NULL ) {
+           *errmsg = Errmsg;
+       }
+       
+        switch (mode)
+        {
+        default:
+        case 'a':      /* alternating bit pattern */
+               expbits=0x55;
+                break;
+
+        case 'c':      /* checkerboard pattern */
+               expbits=0xf0;
+                break;
+
+       case 'C':       /* counting pattern */
+                for (cnt=0;cnt< bsize;cnt++) {
+                   expbits = ((offset+cnt)%8 & 0177);
+
+                   if ( buffer[cnt] != expbits ) {
+                       sprintf(Errmsg,
+                           "data mismatch at offset %d, exp:%#lo, act:%#o",
+                           offset+cnt, expbits, buffer[cnt]);
+                       return offset+cnt;
+                   }
+               }
+               sprintf(Errmsg, "all %d bytes match desired pattern", bsize);
+               return -1;
+
+       case 'o':
+               expbits=0xff;
+               break;
+
+       case 'z':
+               expbits=0;
+               break;
+
+        case 'r':
+               return -1;      /* no check can be done for random */
+        }
+
+       for (cnt=0; cnt<bsize; chr++, cnt++) {
+           actbits = (long)*chr;
+
+           if ( actbits != expbits ) {
+               sprintf(Errmsg, "data mismatch at offset %d, exp:%#lo, act:%#lo",
+                   offset+cnt, expbits, actbits);
+               return offset+cnt;
+           }
+       }
+
+       sprintf(Errmsg, "all %d bytes match desired pattern", bsize);
+       return -1; /* all ok */
+}
+
+#if UNIT_TEST
+
+/***********************************************************************
+ * main for doing unit testing
+ ***********************************************************************/
+int
+main(ac, ag)
+int ac;
+char **ag;
+{
+
+    int size=1023;
+    int offset;
+    int number;
+    unsigned char *buffer;
+    int ret;
+    char *errmsg;
+
+    if ((buffer=(unsigned char *)malloc(size)) == NULL ) {
+       perror("malloc");
+       exit(2);
+    }
+
+
+printf("***** for a ****************************\n");
+    databingen('a', buffer, size, 0);
+    printf("databingen('a', buffer, %d, 0)\n", size);
+
+    ret=databinchk('a', buffer, size, 0, &errmsg);
+    printf("databinchk('a', buffer, %d, 0, &errmsg) returned %d: %s\n",
+       size, ret, errmsg);
+    if ( ret == -1 )
+       printf("\tPASS return value of -1 as expected\n");
+    else
+       printf("\tFAIL return value %d, expected -1\n", ret);
+
+    offset=232400;
+    ret=databinchk('a', &buffer[1], size-1, offset, &errmsg);
+    printf("databinchk('a', &buffer[1], %d, %d, &errmsg) returned %d: %s\n",
+       size, offset, ret, errmsg);
+    if ( ret == -1 )
+       printf("\tPASS return value of -1 as expected\n");
+    else
+       printf("\tFAIL return value %d, expected -1\n", ret);
+
+    buffer[15]= 0x0;
+    printf("changing char 15 (offset (%d+15) = %d) to 0x0\n", offset, offset+15);
+    number=offset+15;
+
+    ret=databinchk('a', &buffer[1], size-1, offset+1, &errmsg);
+    printf("databinchk('a', &buffer[1], %d, %d, &errmsg) returned %d: %s\n",
+       size-1, offset+1, ret, errmsg);
+    if ( ret == number )
+       printf("\tPASS return value of %d as expected\n", number);
+    else
+       printf("\tFAIL return value %d, expected %d\n", ret, number);
+
+
+
+printf("***** for c ****************************\n");
+    databingen('c', buffer, size, 0);
+    printf("databingen('c', buffer, %d, 0)\n", size);
+
+    ret=databinchk('c', buffer, size, 0, &errmsg);
+    printf("databinchk('c', buffer, %d, 0, &errmsg) returned %d: %s\n",
+       size, ret, errmsg);
+    if ( ret == -1 )
+       printf("\tPASS return value of -1 as expected\n");
+    else
+       printf("\tFAIL return value %d, expected -1\n", ret);
+
+    offset=232400;
+    ret=databinchk('c', &buffer[1], size-1, offset, &errmsg);
+    printf("databinchk('c', &buffer[1], %d, %d, &errmsg) returned %d: %s\n",
+       size, offset, ret, errmsg);
+    if ( ret == -1 )
+       printf("\tPASS return value of -1 as expected\n");
+    else
+       printf("\tFAIL return value %d, expected -1\n", ret);
+
+    buffer[15]= 0x0;
+    printf("changing char 15 (offset (%d+15) = %d) to 0x0\n", offset, offset+15);
+    number=offset+15;
+
+    ret=databinchk('c', &buffer[1], size-1, offset+1, &errmsg);
+    printf("databinchk('c', &buffer[1], %d, %d, &errmsg) returned %d: %s\n",
+       size-1, offset+1, ret, errmsg);
+    if ( ret == number )
+       printf("\tPASS return value of %d as expected\n", number);
+    else
+       printf("\tFAIL return value %d, expected %d\n", ret, number);
+
+printf("***** for C ****************************\n");
+
+    databingen('C', buffer, size, 0);
+    printf("databingen('C', buffer, %d, 0)\n", size);
+
+    ret=databinchk('C', buffer, size, 0, &errmsg);
+    printf("databinchk('C', buffer, %d, 0, &errmsg) returned %d: %s\n",
+       size, ret, errmsg);
+    if ( ret == -1 )
+       printf("\tPASS return value of -1 as expected\n");
+    else
+       printf("\tFAIL return value %d, expected -1\n", ret);
+
+    offset=18;
+    ret=databinchk('C', &buffer[18], size-18, 18, &errmsg);
+    printf("databinchk('C', &buffer[18], %d, 18, &errmsg) returned %d: %s\n",
+       size-18, ret, errmsg);
+    if ( ret == -1 )
+       printf("\tPASS return value of -1 as expected\n");
+    else
+       printf("\tFAIL return value %d, expected -1\n", ret);
+
+    buffer[20]= 0x0;
+    buffer[21]= 0x0;
+    printf("changing char 20 and 21 to 0x0 (offset %d and %d)\n", 20,
+       21);
+
+    ret=databinchk('C', &buffer[18], size-18, 18, &errmsg);
+    printf("databinchk('C', &buffer[18], %d, 18, &errmsg) returned %d: %s\n",
+       size-18, ret, errmsg);
+
+    if ( ret == 20 || ret == 21 )
+       printf("\tPASS return value of %d or %d as expected\n",
+           20, 21);
+    else
+       printf("\tFAIL return value %d, expected %d or %d\n", ret,
+           20, 21 );
+
+    exit(0);
+
+}
+
+#endif
+
diff --git a/lib/datapid.c b/lib/datapid.c
new file mode 100644 (file)
index 0000000..9414eae
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+/************
+
+64 bits in a Cray word
+
+                               12345678901234567890123456789012
+1234567890123456789012345678901234567890123456789012345678901234
+________________________________________________________________
+<    pid       >< word-offset in file (same #) ><    pid       >
+
+1234567890123456789012345678901234567890123456789012345678901234
+________________________________________________________________
+<    pid       >< offset in file of this word  ><    pid       >
+
+
+8 bits to a bytes == character
+ NBPW            8 
+************/
+
+#include <stdio.h>
+#include <sys/param.h>
+#ifdef UNIT_TEST
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+
+static char Errmsg[80];
+
+#define LOWER16BITS(X) (X & 0177777)
+#define LOWER32BITS(X) (X & 0xffffffff)
+
+/***
+#define HIGHBITS(WRD, bits) ( (-1 << (64-bits)) & WRD)
+#define LOWBITS(WRD, bits) ( (-1 >> (64-bits)) & WRD)
+****/
+
+#define NBPBYTE                8               /* number bits per byte */
+
+#ifndef DEBUG
+#define DEBUG  0
+#endif
+
+/***********************************************************************
+ *
+ * 
+ * 1   2   3   4   5   6   7   8   9   10  11  12  13  14  14  15      bytes
+ * 1234567890123456789012345678901234567890123456789012345678901234    bits
+ * ________________________________________________________________    1 word
+ * <    pid       >< offset in file of this word  ><    pid       >
+ * 
+ * the words are put together where offset zero is the start.
+ * thus, offset 16 is the start of  the second full word
+ * Thus, offset 8 is in middle of word 1
+ ***********************************************************************/
+int
+datapidgen(pid, buffer, bsize, offset)
+int pid;
+char *buffer;
+int bsize;
+int offset;
+{
+#if CRAY
+       
+   int cnt;
+   int tmp;
+   char *chr;
+   long *wptr;
+   long word;
+   int woff;   /* file offset for the word */
+   int boff;   /* buffer offset or index */
+   int num_full_words;
+
+    num_full_words = bsize/NBPW;
+    boff = 0;
+
+    if ( cnt=(offset % NBPW) ) {       /* partial word */
+
+       woff = offset - cnt;
+#if DEBUG
+printf("partial at beginning, cnt = %d, woff = %d\n", cnt, woff);
+#endif
+
+       word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+       chr = (char *)&word;
+
+       for (tmp=0; tmp<cnt; tmp++) {   /* skip unused bytes */
+           chr++;
+        }
+
+       for (; boff<(NBPW-cnt) && boff<bsize; boff++, chr++) {
+           buffer[boff] = *chr;
+       }
+    }
+
+    /*
+     * full words 
+     */
+
+    num_full_words = (bsize-boff)/NBPW;
+       
+    woff = offset+boff;
+       
+    for (cnt=0; cnt<num_full_words; woff += NBPW, cnt++ ) {
+
+       word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+       chr = (char *)&word;
+       for(tmp=0; tmp<NBPW; tmp++, chr++) {
+           buffer[boff++] = *chr;
+       }
+/****** Only if wptr is a word ellined
+       wptr = (long *)&buffer[boff];
+       *wptr = word;
+       boff += NBPW;
+*****/
+
+    }
+
+    /*
+     * partial word at end of buffer
+     */
+
+    if ( cnt=((bsize-boff) % NBPW) ) {
+#if DEBUG
+printf("partial at end\n");
+#endif
+       word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+       chr = (char *)&word;
+
+       for (tmp=0; tmp<cnt && boff<bsize; tmp++, chr++) {
+           buffer[boff++] = *chr;
+       }
+    }
+
+    return bsize;
+
+#else
+       return -1;      /* not support on non-64 bits word machines  */
+
+#endif
+
+} 
+
+/***********************************************************************
+ *
+ *
+ ***********************************************************************/
+int
+datapidchk(pid, buffer, bsize, offset, errmsg)
+int pid;
+char *buffer;
+int bsize;
+int offset;
+char **errmsg;
+{
+#if CRAY
+       
+   int cnt;
+   int tmp;
+   char *chr;
+   long *wptr;
+   long word;
+   int woff;   /* file offset for the word */
+   int boff;   /* buffer offset or index */
+   int num_full_words;
+
+
+    if ( errmsg != NULL ) {
+        *errmsg = Errmsg;
+    }
+
+
+    num_full_words = bsize/NBPW;
+    boff = 0;
+
+    if ( cnt=(offset % NBPW) ) {       /* partial word */
+       woff = offset - cnt;
+       word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+       chr = (char *)&word;
+
+       for (tmp=0; tmp<cnt; tmp++) {   /* skip unused bytes */
+           chr++;
+        }
+
+       for (; boff<(NBPW-cnt) && boff<bsize; boff++, chr++) {
+           if (buffer[boff] != *chr) {
+               sprintf(Errmsg, "Data mismatch at offset %d, exp:%#o, act:%#o",
+                   offset+boff, *chr, buffer[boff]);
+               return offset+boff;
+           }
+       }
+    }
+
+    /*
+     * full words 
+     */
+
+    num_full_words = (bsize-boff)/NBPW;
+       
+    woff = offset+boff;
+       
+    for (cnt=0; cnt<num_full_words; woff += NBPW, cnt++ ) {
+       word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+       chr = (char *)&word;
+       for(tmp=0; tmp<NBPW; tmp++, boff++, chr++) {
+           if ( buffer[boff] != *chr ) {
+               sprintf(Errmsg, "Data mismatch at offset %d, exp:%#o, act:%#o",
+                   woff, *chr, buffer[boff]);
+               return woff;
+           }
+       }
+
+/****** only if a word elined
+       wptr = (long *)&buffer[boff];
+       if ( *wptr != word ) {
+           sprintf(Errmsg, "Data mismatch at offset %d, exp:%#o, act:%#o",
+               woff, word, *wptr);
+           return woff;
+       }
+       boff += NBPW;
+******/
+    }
+
+    /*
+     * partial word at end of buffer
+     */
+
+    if ( cnt=((bsize-boff) % NBPW) ) {
+#if DEBUG
+printf("partial at end\n");
+#endif
+       word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+       chr = (char *)&word;
+
+
+       for (tmp=0; tmp<cnt && boff<bsize; boff++, tmp++, chr++) {
+           if ( buffer[boff] != *chr ) {
+               sprintf(Errmsg, "Data mismatch at offset %d, exp:%#o, act:%#o",
+                   offset+boff, *chr, buffer[boff]);
+               return offset+boff;
+           }
+       }
+    }
+
+    sprintf(Errmsg, "all %d bytes match desired pattern", bsize);
+    return -1;      /* buffer is ok */
+
+#else
+       
+    if ( errmsg != NULL ) {
+        *errmsg = Errmsg;
+    }
+    sprintf(Errmsg, "Not supported on this OS.");
+    return 0;
+
+#endif
+
+
+}       /* end of datapidchk */
+
+#if UNIT_TEST
+
+/***********************************************************************
+ * main for doing unit testing
+ ***********************************************************************/
+int
+main(ac, ag)
+int ac;
+char **ag;
+{
+
+int size=1234;
+char *buffer;
+int ret;
+char *errmsg;
+
+    if ((buffer=(char *)malloc(size)) == NULL ) {
+        perror("malloc");
+        exit(2);
+    }
+
+
+    datapidgen(-1, buffer, size, 3);
+
+/***
+fwrite(buffer, size, 1, stdout);
+fwrite("\n", 1, 1, stdout);
+****/
+
+    printf("datapidgen(-1, buffer, size, 3)\n");
+
+    ret=datapidchk(-1, buffer, size, 3, &errmsg);
+    printf("datapidchk(-1, buffer, %d, 3, &errmsg) returned %d %s\n",
+        size, ret, errmsg);
+    ret=datapidchk(-1, &buffer[1], size-1, 4, &errmsg);
+    printf("datapidchk(-1, &buffer[1], %d, 4, &errmsg) returned %d %s\n",
+        size-1, ret, errmsg);
+
+    buffer[25]= 0x0;
+    buffer[26]= 0x0;
+    buffer[27]= 0x0;
+    buffer[28]= 0x0;
+    printf("changing char 25-28\n");
+
+    ret=datapidchk(-1, &buffer[1], size-1, 4, &errmsg);
+    printf("datapidchk(-1, &buffer[1], %d, 4, &errmsg) returned %d %s\n",
+        size-1, ret, errmsg);
+
+printf("------------------------------------------\n");
+
+    datapidgen(getpid(), buffer, size, 5);
+
+/*******
+fwrite(buffer, size, 1, stdout);
+fwrite("\n", 1, 1, stdout);
+******/
+
+    printf("\ndatapidgen(getpid(), buffer, size, 5)\n");
+
+    ret=datapidchk(getpid(), buffer, size, 5, &errmsg);
+    printf("datapidchk(getpid(), buffer, %d, 5, &errmsg) returned %d %s\n",
+        size, ret, errmsg);
+
+    ret=datapidchk(getpid(), &buffer[1], size-1, 6, &errmsg);
+    printf("datapidchk(getpid(), &buffer[1], %d, 6, &errmsg) returned %d %s\n",
+        size-1, ret, errmsg);
+
+    buffer[25]= 0x0;
+    printf("changing char 25\n");
+
+    ret=datapidchk(getpid(), &buffer[1], size-1, 6, &errmsg);
+    printf("datapidchk(getpid(), &buffer[1], %d, 6, &errmsg) returned %d %s\n",
+        size-1, ret, errmsg);
+
+    exit(0);
+}
+
+#endif
+
diff --git a/lib/file_lock.c b/lib/file_lock.c
new file mode 100644 (file)
index 0000000..e6823a2
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/sysmacros.h>
+#include <string.h> /* memset, strerror */
+#include "file_lock.h"
+
+
+#ifndef EFSEXCLWR
+#define EFSEXCLWR      503
+#endif
+
+/*
+ * String containing the last system call.
+ *
+ */
+char Fl_syscall_str[128];
+
+static char errmsg[256];
+
+/***********************************************************************
+ *
+ * Test interface to the fcntl system call.
+ * It will loop if the LOCK_NB flags is NOT set.
+ ***********************************************************************/
+int
+file_lock(fd, flags, errormsg)
+int fd;
+int flags;
+char **errormsg;
+{
+        register int cmd, ret;
+        struct flock flocks;
+
+        memset(&flocks, 0, sizeof(struct flock));
+
+        if (flags&LOCK_NB)
+                cmd = F_SETLK;
+        else
+                cmd = F_SETLKW;
+
+        flocks.l_whence = 0;
+        flocks.l_start = 0;
+        flocks.l_len = 0;
+
+        if (flags&LOCK_UN)
+                flocks.l_type = F_UNLCK;
+        else if (flags&LOCK_EX)
+                flocks.l_type = F_WRLCK;
+        else if (flags&LOCK_SH)
+                flocks.l_type = F_RDLCK;
+        else {
+                errno = EINVAL;
+           if ( errormsg != NULL ) {
+               sprintf(errmsg,
+                   "Programmer error, called file_lock with in valid flags\n");
+               *errormsg = errmsg;
+            }
+            return -1;
+        }
+
+       sprintf(Fl_syscall_str,
+           "fcntl(%d, %d, &flocks): type:%d whence:%d, start:%lld len:%lld\n",
+                fd, cmd, flocks.l_type, flocks.l_whence,
+               (long long)flocks.l_start, (long long)flocks.l_len);
+
+       while (1) {
+            ret = fcntl(fd, cmd, &flocks);
+
+           if ( ret < 0 ) {
+               if ( cmd == F_SETLK )
+                   switch (errno) {
+                      /* these errors are okay */
+                       case EACCES:    /* Permission denied */
+                       case EINTR:             /* interrupted system call */
+#ifdef EFILESH
+                       case EFILESH:   /* file shared */
+#endif
+                       case EFSEXCLWR: /* File is write protected */
+                           continue;   /* retry getting lock */
+               }
+               if ( errormsg != NULL ) {
+                   sprintf(errmsg, "fcntl(%d, %d, &flocks): errno:%d %s\n",
+                       fd, cmd, errno, strerror(errno));
+                   *errormsg = errmsg;
+               }
+               return -1;
+           }
+           break;
+       }
+
+        return ret;
+
+}      /* end of file_lock */
+
+/***********************************************************************
+ *
+ * Test interface to the fcntl system call.
+ * It will loop if the LOCK_NB flags is NOT set.
+ ***********************************************************************/
+int
+record_lock(fd, flags, start, len, errormsg)
+int fd;
+int flags;
+int start;
+int len;
+char **errormsg;
+{
+        register int cmd, ret;
+        struct flock flocks;
+
+        memset(&flocks, 0, sizeof(struct flock));
+
+        if (flags&LOCK_NB)
+                cmd = F_SETLK;
+        else
+                cmd = F_SETLKW;
+
+        flocks.l_whence = 0;
+        flocks.l_start = start;
+        flocks.l_len = len;
+
+        if (flags&LOCK_UN)
+                flocks.l_type = F_UNLCK;
+        else if (flags&LOCK_EX)
+                flocks.l_type = F_WRLCK;
+        else if (flags&LOCK_SH)
+                flocks.l_type = F_RDLCK;
+        else {
+                errno = EINVAL;
+           if ( errormsg != NULL ) {
+               sprintf(errmsg,
+                   "Programmer error, called record_lock with in valid flags\n");
+               *errormsg = errmsg;
+            }
+            return -1;
+        }
+
+       sprintf(Fl_syscall_str,
+           "fcntl(%d, %d, &flocks): type:%d whence:%d, start:%lld len:%lld\n",
+                fd, cmd, flocks.l_type, flocks.l_whence,
+               (long long)flocks.l_start, (long long)flocks.l_len);
+
+       while (1) {
+            ret = fcntl(fd, cmd, &flocks);
+
+           if ( ret < 0 ) {
+               if ( cmd == F_SETLK )
+                   switch (errno) {
+                      /* these errors are okay */
+                       case EACCES:    /* Permission denied */
+                       case EINTR:             /* interrupted system call */
+#ifdef EFILESH
+                       case EFILESH:   /* file shared */
+#endif
+                       case EFSEXCLWR: /* File is write protected */
+                           continue;   /* retry getting lock */
+               }
+               if ( errormsg != NULL ) {
+                   sprintf(errmsg, "fcntl(%d, %d, &flocks): errno:%d %s\n",
+                       fd, cmd, errno, strerror(errno));
+                   *errormsg = errmsg;
+               }
+               return -1;
+           }
+           break;
+       }
+
+        return ret;
+
+}      /* end of record_lock */
+
+
diff --git a/lib/forker.c b/lib/forker.c
new file mode 100644 (file)
index 0000000..ca2c033
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+/**************************************************************
+ *
+ *    OS Testing - Silicon Graphics, Inc.
+ *
+ *    FUNCTION NAME     : forker
+ *                       background
+ *
+ *    FUNCTION TITLE    : fork desired number of copies of the current process
+ *                       fork a process and return control to caller
+ *
+ *    SYNOPSIS:
+ *      int forker(ncopies, mode, prefix)
+ *      int ncopies;
+ *     int mode;
+ *     char *prefix;
+ *
+ *     int background(prefix);
+ *     char *prefix;
+ *
+ *     extern int Forker_pids[];
+ *     extern int Forker_npids;
+ *
+ *    AUTHOR            : Richard Logan
+ *
+ *    CO-PILOT(s)       : Dean Roehrich
+ *
+ *    INITIAL RELEASE   : UNICOS 8.0
+ *
+ *    DESIGN DESCRIPTION
+ *     The background function will do a fork of the current process.
+ *     The parent process will then exit, thus orphaning the
+ *     child process.  Doing this will not nice the child process
+ *     like executing a cmd in the background using "&" from the shell.
+ *     If the fork fails and prefix is not NULL, a error message is printed
+ *      to stderr and the process will exit with a value of errno.
+ *
+ *     The forker function will fork <ncopies> minus one copies
+ *     of the current process.  There are two modes in how the forks
+ *     will be done.  Mode 0 (default) will have all new processes
+ *     be childern of the parent process.    Using Mode 1,
+ *     the parent process will have one child and that child will
+ *     fork the next process, if necessary, and on and on.
+ *     The forker function will return the number of successful
+ *     forks.  This value will be different for the parent and each child.
+ *     Using mode 0, the parent will get the total number of successful
+ *     forks.  Using mode 1, the newest child will get the total number
+ *     of forks.  The parent will get a return value of 1.
+ *
+ *     The forker function also updates the global variables
+ *     Forker_pids[] and Forker_npids.  The Forker_pids array will
+ *      be updated to contain the pid of each new process.  The
+ *     Forker_npids variable contains the number of entries
+ *     in Forker_pids.  Note, not all processes will have
+ *     access to all pids via Forker_pids.  If using mode 0, only the
+ *     parent process and the last process will have all information.
+ *      If using mode 1, only the last child process will have all information.
+ *
+ *     If the prefix parameter is not NULL and the fork system call fails,
+ *      a error message will be printed to stderr.  The error message
+ *      the be preceeded with prefix string.  If prefix is NULL,
+ *      no error message is printed.
+ *
+ *    SPECIAL REQUIREMENTS
+ *     None.
+ *
+ *    UPDATE HISTORY
+ *      This should contain the description, author, and date of any
+ *      "interesting" modifications (i.e. info should helpful in
+ *      maintaining/enhancing this module).
+ *      username     description
+ *      ----------------------------------------------------------------
+ *     rrl         This functions will first written during
+ *             the SFS testing days, 1993.
+ *
+ *    BUGS/LIMITATIONS
+ *     The child pids are stored in the fixed array, Forker_pids.
+ *     The array only has space for 4098 pids.  Only the first
+ *     4098 pids will be stored in the array.
+ *
+ **************************************************************/
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h> /* fork, getpid, sleep */
+#include <string.h>
+#include <stdlib.h> /* exit */
+#include "forker.h"
+
+int Forker_pids[FORKER_MAX_PIDS];      /* holds pids of forked processes */
+int Forker_npids=0;             /* number of entries in Forker_pids */
+
+/***********************************************************************
+ *
+ * This function will fork and the parent will exit zero and
+ * the child will return.  This will orphan the returning process
+ * putting it in the background.
+ *
+ * Return Value
+ *   0 : if fork did not fail
+ *  !0 : if fork failed, the return value will be the errno.
+ ***********************************************************************/
+int
+background(prefix)
+char *prefix;
+{
+  switch (fork()) {
+  case -1:
+    if ( prefix != NULL )
+        fprintf(stderr, "%s: In %s background(), fork() failed, errno:%d %s\n",
+           prefix, __FILE__, errno, strerror(errno));
+    exit(errno);
+
+  case 0:      /* child process */
+    break;
+
+  default:     
+    exit(0);
+  }
+
+  return 0;
+
+}      /* end of background */
+
+/***********************************************************************
+ * Forker will fork ncopies-1 copies of self. 
+ * 
+ ***********************************************************************/
+int
+forker(ncopies, mode, prefix)
+int ncopies;
+int mode;      /* 0 - all childern of parent, 1 - only 1 direct child */
+char *prefix;   /* if ! NULL, an message will be printed to stderr */
+               /* if fork fails.  The prefix (program name) will */
+               /* preceed the message */
+{
+    int cnt;
+    int pid;
+    static int ind = 0;
+
+    Forker_pids[ind]=0;
+
+    for ( cnt=1; cnt < ncopies; cnt++ ) {
+
+       switch ( mode ) {
+        case 1  :      /* only 1 direct child */
+           if ( (pid = fork()) == -1 ) {
+               if ( prefix != NULL ) 
+                   fprintf(stderr, "%s: %s,forker(): fork() failed, errno:%d %s\n",
+                       prefix, __FILE__, errno, strerror(errno));
+               return 0;
+           }
+           Forker_npids++;
+           
+           switch (pid ) {
+            case 0:     /* child - continues the forking */
+               
+               if ( Forker_npids < FORKER_MAX_PIDS )
+                    Forker_pids[Forker_npids-1]=getpid();
+                break;
+
+            default:    /* parent - stop the forking */
+               if ( Forker_npids < FORKER_MAX_PIDS )
+                    Forker_pids[Forker_npids-1]=pid;
+                return cnt-1;      
+            }
+
+           break;
+
+       default :       /* all new processes are childern of parent */
+           if ( (pid = fork()) == -1 ) {
+               if ( prefix != NULL ) 
+                   fprintf(stderr, "%s: %s,forker(): fork() failed, errno:%d %s\n",
+                       prefix, __FILE__, errno, strerror(errno));
+               return cnt-1;
+           }
+           Forker_npids++;
+           
+           switch (pid ) {
+           case 0:     /* child - stops the forking */
+               if ( Forker_npids < FORKER_MAX_PIDS )
+                    Forker_pids[Forker_npids-1]=getpid();
+               return cnt;     
+
+           default:    /* parent - continues the forking */
+               if ( Forker_npids < FORKER_MAX_PIDS )
+                    Forker_pids[Forker_npids-1]=pid;
+                break;
+            }
+           break;
+       }
+    }
+
+    if ( Forker_npids < FORKER_MAX_PIDS )
+        Forker_pids[Forker_npids]=0;
+    return cnt-1;
+
+}      /* end of forker */
+
+
+#if UNIT_TEST
+
+/*
+ * The following is a unit test main for the background and forker
+ * functions.
+ */
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+    int ncopies=1;
+    int mode=0;
+    int ret;
+    int ind;
+
+    if ( argc == 1 ) {
+       printf("Usage: %s ncopies [mode]\n", argv[0]);
+       exit(1);
+    }
+
+    if ( sscanf(argv[1], "%i", &ncopies) != 1 ) {
+       printf("%s: ncopies argument must be integer\n", argv[0]);
+       exit(1);
+    }
+
+    if ( argc == 3 )
+       if ( sscanf(argv[2], "%i", &mode) != 1 ) {
+        printf("%s: mode argument must be integer\n", argv[0]);
+        exit(1);
+    }
+
+    printf("Starting Pid = %d\n", getpid());
+    ret=background(argv[0]);
+    printf("After background() ret:%d, pid = %d\n", ret, getpid());
+
+    ret=forker(ncopies, mode, argv[0]);
+
+    printf("forker(%d, %d, %s) ret:%d, pid = %d, sleeping 30 seconds.\n", 
+       ncopies, mode, argv[0], ret, getpid());
+
+    printf("%d My version of Forker_pids[],  Forker_npids = %d\n", 
+       getpid(), Forker_npids);
+
+    for (ind=0; ind<Forker_npids; ind++){
+       printf("%d ind:%-2d pid:%d\n", getpid(), ind, Forker_pids[ind]);
+    }
+    
+    sleep(30);
+    exit(0);
+}
+
+#endif  /* UNIT_TEST */
diff --git a/lib/open_flags.c b/lib/open_flags.c
new file mode 100644 (file)
index 0000000..eed39ee
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+/**************************************************************
+ *
+ *    OS Testing - Silicon Graphics, Inc.
+ *
+ *    FUNCTION NAME     : parse_open_flags
+ *                       openflags2symbols
+ *
+ *    FUNCTION TITLE    : converts open flag symbols into bitmask
+ *                       converts open flag bitmask into symbols
+ *
+ *    SYNOPSIS:
+ *      int parse_open_flags(symbols, badname)
+ *     char *symbols;
+ *     char **badname;
+ *
+ *      char *openflags2symbols(openflags, sep, mode)
+ *     int openflags;
+ *     char *sep;
+ *     int mode;
+ *
+ *    AUTHOR            : Richard Logan
+ *
+ *    CO-PILOT(s)       : Dean Roehrich
+ *
+ *    INITIAL RELEASE   : UNICOS 8.0
+ *
+ *    DESIGN DESCRIPTION
+ *     The parse_open_flags function can be used to convert
+ *     a list of comma separated open(2) flag symbols (i.e. O_TRUNC)
+ *     into the bitmask that can be used by open(2).
+ *     If a symbol is unknown and <badname> is not NULL, <badname>
+ *     will updated to point that symbol in <string>.
+ *     Parse_open_flags will return -1 on this error.
+ *      Otherwise parse_open_flags will return the open flag bitmask.
+ *     If parse_open_flags returns, <string> will left unchanged.
+ *
+ *     The openflags2symbols function attempts to convert open flag
+ *     bits into human readable  symbols (i.e. O_TRUNC).  If there 
+ *     are more than one symbol, the <sep> string will be placed as
+ *     a separator between symbols.  Commonly used separators would
+ *     be a comma "," or pipe "|".  If <mode> is one and not all 
+ *     <openflags> bits can be converted to symbols, the "UNKNOWN"
+ *     symbol will be added to return string.
+ *     Openflags2symbols will return the indentified symbols.
+ *     If no symbols are recognized the return value will be a empty
+ *     string or the "UNKNOWN" symbol.
+ *
+ *    SPECIAL REQUIREMENTS
+ *     None.
+ *
+ *    UPDATE HISTORY
+ *      This should contain the description, author, and date of any
+ *      "interesting" modifications (i.e. info should helpful in
+ *      maintaining/enhancing this module).
+ *      username     description
+ *      ----------------------------------------------------------------
+ *     rrl    This code was first created during the beginning
+ *             of the SFS testing days.  I think that was in 1993.
+ *            This code was updated in 05/96.
+ *             (05/96)  openflags2symbols was written.
+ *
+ *    BUGS/LIMITATIONS
+ *     Currently (05/96) all known symbols are coded into openflags2symbols.
+ *     If new open flags are added this code will have to updated
+ *     to know about them or they will not be recognized.
+ *
+ **************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <string.h> /* strcat */
+#include "open_flags.h"
+
+#define UNKNOWN_SYMBOL "UNKNOWN"
+
+static char Open_symbols[512];   /* space for openflags2symbols return value */
+
+struct open_flag_t {
+    char *symbol;
+    int  flag;
+};
+
+static struct open_flag_t Open_flags[] = {
+    { "O_RDONLY",      O_RDONLY },
+    { "O_WRONLY",      O_WRONLY },
+    { "O_RDWR",                O_RDWR },
+    { "O_SYNC",                O_SYNC },
+    { "O_CREAT",       O_CREAT },
+    { "O_TRUNC",       O_TRUNC },
+    { "O_EXCL",                O_EXCL },
+    { "O_APPEND",      O_APPEND },
+    { "O_NONBLOCK",    O_NONBLOCK },
+#if O_NOCTTY
+    { "O_NOCTTY",      O_NOCTTY },
+#endif
+#if O_DSYNC
+    { "O_DSYNC",       O_DSYNC },
+#endif
+#if O_RSYNC
+    { "O_RSYNC",       O_RSYNC },
+#endif
+#if O_ASYNC
+    { "O_ASYNC",       O_ASYNC },
+#endif
+#if O_PTYIGN
+    { "O_PTYIGN",      O_PTYIGN },
+#endif
+#if O_NDELAY
+    { "O_NDELAY",      O_NDELAY },
+#endif
+#if O_RAW
+    { "O_RAW",         O_RAW },
+#endif
+#ifdef O_SSD
+    { "O_SSD",         O_SSD },
+#endif
+#if O_BIG
+    { "O_BIG",         O_BIG },
+#endif
+#if O_PLACE
+    { "O_PLACE",       O_PLACE },
+#endif
+#if O_RESTART
+    { "O_RESTART",     O_RESTART },
+#endif
+#if O_SFSXOP
+    { "O_SFSXOP",      O_SFSXOP },
+#endif
+#if O_SFS_DEFER_TM
+    { "O_SFS_DEFER_TM",        O_SFS_DEFER_TM },
+#endif
+#if O_WELLFORMED
+    { "O_WELLFORMED",  O_WELLFORMED },
+#endif
+#if O_LDRAW
+    { "O_LDRAW",       O_LDRAW },
+#endif
+#if O_T3D
+    { "O_T3D", O_T3D },
+#endif /* O_T3D */
+#if O_PARALLEL
+    { "O_PARALLEL",    O_PARALLEL },
+    { "O_FSA", O_PARALLEL|O_WELLFORMED|O_RAW },        /* short cut */
+#endif /* O_PARALLEL */
+#ifdef O_LARGEFILE
+    { "O_LARGEFILE",   O_LARGEFILE },
+#endif
+#ifdef O_DIRECT
+    { "O_DIRECT",      O_DIRECT },
+#endif
+#ifdef O_PRIV
+    { "O_PRIV",                O_PRIV },
+#endif
+
+};
+
+int 
+parse_open_flags(char *string, char **badname)
+{
+   int  bits = 0;
+   char *name;
+   char *cc;
+   char savecc;
+   int  found;
+   int  ind;
+
+   name=string;
+   cc=name;
+
+   while ( 1 ) {
+
+      for(; ((*cc != ',') && (*cc != '\0')); cc++);
+      savecc = *cc;
+      *cc = '\0';
+
+      found = 0;
+
+      for(ind=0; ind < sizeof(Open_flags)/sizeof(struct open_flag_t); ind++) {
+          if ( strcmp(name, Open_flags[ind].symbol) == 0 ) {
+              bits |= Open_flags[ind].flag;
+             found=1;
+             break;
+         }
+      }
+
+      *cc = savecc;    /* restore string */
+
+      if ( found == 0 ) {      /* invalid name */
+         if ( badname != NULL )
+           *badname = name;
+         return -1;
+      }
+
+      if ( savecc == '\0' )
+       break;
+
+      name = ++cc;
+
+   }   /* end while */
+
+   return bits;
+
+}      /* end of parse_open_flags */
+
+
+char *
+openflags2symbols(int openflags, char *sep, int mode)
+{
+    int ind;
+    int size;
+    int bits = openflags;
+    int havesome=0;
+
+    Open_symbols[0]='\0';
+
+    size=sizeof(Open_flags)/sizeof(struct open_flag_t);
+
+    /*
+     * Deal with special case of O_RDONLY.  If O_WRONLY nor O_RDWR
+     * bits are not set, assume O_RDONLY.
+     */
+
+    if ( (bits & (O_WRONLY | O_RDWR)) == 0 ) {
+       strcat(Open_symbols, "O_RDONLY");
+       havesome=1;
+    }
+
+    /*
+     *  Loop through all but O_RDONLY elments of Open_flags
+     */
+    for(ind=1; ind < size; ind++) {
+         
+       if ( (bits & Open_flags[ind].flag) == Open_flags[ind].flag ) {
+           if ( havesome ) 
+               strcat(Open_symbols, sep);
+
+           strcat(Open_symbols, Open_flags[ind].symbol);
+           havesome++;
+
+           /* remove flag bits from bits */
+           bits = bits & (~Open_flags[ind].flag);
+       }
+    }
+
+    /*
+     * If not all bits were identified and mode was equal to 1,
+     * added UNKNOWN_SYMBOL to return string
+     */
+    if ( bits && mode == 1 )  {    /* not all bits were identified */
+        if ( havesome )
+            strcat(Open_symbols, sep);
+       strcat(Open_symbols,  UNKNOWN_SYMBOL);
+    }
+
+    return Open_symbols;
+
+}   /* end of openflags2symbols */
+
+
+#ifdef UNIT_TEST
+
+/*
+ * The following code provides a UNIT test main for
+ * parse_open_flags and openflags2symbols functions.
+ */
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+    int bits;
+    int ret;
+    char *err;
+
+    if (argc == 1 ) {
+       printf("Usage: %s openflagsbits\n\t%s symbols\n", argv[0], argv[0]);
+       exit(1);
+    }
+
+    if ( sscanf(argv[1], "%i", &bits) == 1 ) {
+       printf("openflags2symbols(%#o, \",\", 1) returned %s\n",
+           bits, openflags2symbols(bits, ",", 1));
+       
+    } else {
+       ret=parse_open_flags(argv[1], &err);
+       if ( ret == -1 )
+           printf("parse_open_flags(%s, &err) returned -1, err = %s\n", 
+               argv[0], err);
+        else
+           printf("parse_open_flags(%s, &err) returned %#o\n", argv[0], ret);
+    }
+
+    exit(0);
+}
+
+#endif /* end of UNIT_TEST */
diff --git a/lib/pattern.c b/lib/pattern.c
new file mode 100644 (file)
index 0000000..7f4d587
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#include <string.h>
+#include "pattern.h"
+
+/*
+ * The routines in this module are used to fill/check a data buffer
+ * with/against a known pattern.
+ */
+
+int
+pattern_check(buf, buflen, pat, patlen, patshift)
+char   *buf;
+int    buflen;
+char   *pat;
+int    patlen;
+int    patshift;
+{
+    int                nb, ncmp, nleft;
+    char       *cp;
+
+    if (patlen)
+       patshift = patshift % patlen;
+
+    cp = buf;
+    nleft = buflen;
+
+    /*
+     * The following 2 blocks of code are to compare the first patlen
+     * bytes of buf.  We need 2 checks if patshift is > 0 since we
+     * must check the last (patlen - patshift) bytes, and then the
+     * first (patshift) bytes.
+     */
+
+    nb = patlen - patshift;
+    if (nleft < nb) {
+       return (memcmp(cp, pat + patshift, nleft) ? -1 : 0);
+    } else {
+        if (memcmp(cp, pat + patshift, nb))
+           return -1;
+
+       nleft -= nb;
+       cp += nb;
+    }
+
+    if (patshift > 0) {
+       nb = patshift;
+       if (nleft < nb) {
+           return (memcmp(cp, pat, nleft) ? -1 : 0);
+       } else {
+           if (memcmp(cp, pat, nb))
+               return -1;
+
+           nleft -= nb;
+           cp += nb;
+       }
+    }
+
+    /*
+     * Now, verify the rest of the buffer using the algorithm described
+     * in the function header.
+     */
+
+    ncmp = cp - buf;
+    while (ncmp < buflen) {
+       nb = (ncmp < nleft) ? ncmp : nleft;
+       if (memcmp(buf, cp, nb))
+           return -1;
+
+       cp += nb;
+       ncmp += nb;
+       nleft -= nb;
+    }
+
+    return 0;
+}
+
+int
+pattern_fill(buf, buflen, pat, patlen, patshift)
+char   *buf;
+int    buflen;
+char   *pat;
+int    patlen;
+int    patshift;
+{
+    int                trans, ncopied, nleft;
+    char       *cp;
+
+    if (patlen)
+       patshift = patshift % patlen;
+
+    cp = buf;
+    nleft = buflen;
+
+    /*
+     * The following 2 blocks of code are to fill the first patlen
+     * bytes of buf.  We need 2 sections if patshift is > 0 since we
+     * must first copy the last (patlen - patshift) bytes into buf[0]...,
+     * and then the first (patshift) bytes of pattern following them.
+     */
+
+    trans = patlen - patshift;
+    if (nleft < trans) {
+       memcpy(cp, pat + patshift, nleft);
+       return 0;
+    } else {
+       memcpy(cp, pat + patshift, trans);
+       nleft -= trans;
+       cp += trans;
+    }
+
+    if (patshift > 0) {
+        trans = patshift;
+       if (nleft < trans) {
+           memcpy(cp, pat, nleft);
+           return 0;
+       } else {
+           memcpy(cp, pat, trans);
+           nleft -= trans;
+           cp += trans;
+       }
+    }
+
+    /*
+     * Now, fill the rest of the buffer using the algorithm described
+     * in the function header comment.
+     */
+
+    ncopied = cp - buf;
+    while (ncopied < buflen) {
+       trans = (ncopied < nleft) ? ncopied : nleft;
+       memcpy(cp, buf, trans);
+       cp += trans;
+       ncopied += trans;
+       nleft -= trans;
+    }
+
+    return(0);
+}
similarity index 100%
rename from src/random.c
rename to lib/random.c
diff --git a/lib/random_range.c b/lib/random_range.c
new file mode 100644 (file)
index 0000000..124cd79
--- /dev/null
@@ -0,0 +1,917 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include "random_range.h"
+
+/*
+ * Internal format of the range array set up by parse_range()
+ */
+
+struct range {
+       int     min;
+       int     max;
+       int     mult;
+};
+
+/*
+ * parse_ranges() is a function to parse a comma-separated list of range
+ * tokens each having the following form:
+ *
+ *             num
+ *     or
+ *             min:max[:mult]
+ *
+ * any of the values may be blank (ie. min::mult, :max, etc.) and default
+ * values for missing arguments may be supplied by the caller.
+ *
+ * The special first form is short hand for 'num:num'.
+ *
+ * After parsing the string, the ranges are put into an array of integers,
+ * which is malloc'd by the routine.  The min, max, and mult entries of each
+ * range can be extracted from the array using the range_min(), range_max(),
+ * and range_mult() functions.
+ *
+ * It is the responsibility of the caller to free the space allocated by
+ * parse_ranges() - a single call to free() will free the space.
+ *
+ *     str             The string to parse - assumed to be a comma-separated
+ *                     list of tokens having the above format.
+ *     defmin          default value to plug in for min, if it is missing
+ *     defmax          default value to plug in for max, if it is missing     
+ *     defmult         default value to plug in for mult, if missing
+ *     parse_func      A user-supplied function pointer, which parse_ranges()
+ *                     can call to parse the min, max, and mult strings.  This
+ *                     allows for customized number formats.  The function
+ *                     MUST have the following prototype:
+ *                             parse_func(char *str, int *val)
+ *                     The function should return -1 if str cannot be parsed
+ *                     into an integer, or >= 0 if it was successfully 
+ *                     parsed.  The resulting integer will be stored in
+ *                     *val.  If parse_func is NULL, parse_ranges will parse
+ *                     the tokens in a manner consistent with the the sscanf
+ *                     %i format.
+ *     range_ptr       A user-supplied char **, which will be set to point
+ *                     at malloc'd space which holds the parsed range
+ *                     values.   If range_ptr is NULL, parse_ranges() just
+ *                     parses the string.  The data returned in range_ptr
+ *                     should not be processed directly - use the functions
+ *                     range_min(), range_max(), and range_mult() to access
+ *                     data for a given range.
+ *     errptr          user-supplied char ** which can be set to point to a
+ *                     static error string.  If errptr is NULL, it is ignored.
+ *
+ * parse_range() returns -1 on error, or the number of ranges parsed.
+ */
+
+static int       str_to_int();
+static long long divider(long long, long long, long long, long long);
+
+int
+parse_ranges(str, defmin, defmax, defmult, parse_func, rangeptr, errptr)
+char   *str;
+int    defmin;
+int    defmax;
+int    defmult;
+int    (*parse_func)();
+char   **rangeptr;
+char   **errptr;
+{
+       int             ncommas;
+       char            *tmpstr, *cp, *tok, *n1str, *n2str, *multstr;
+       struct range    *rp, *ranges;
+       static char     errmsg[256];
+
+       if (errptr != NULL) {
+               *errptr = errmsg;
+       }
+
+       for (ncommas = 0, cp = str; *cp != '\0'; cp++) {
+               if (*cp == ',') {
+                       ncommas++;
+               }
+       }
+
+       if (parse_func == NULL) {
+               parse_func = str_to_int;
+       }
+
+       tmpstr = strdup(str);
+       ranges = (struct range *)malloc((ncommas+1) * sizeof(struct range));
+       rp = ranges;
+
+       tok = strtok(tmpstr, ",");
+       while (tok != NULL) {
+               n1str = tok;
+               n2str = NULL;
+               multstr = NULL;
+
+               rp->min = defmin;
+               rp->max = defmax;
+               rp->mult = defmult;
+
+               if ((cp = strchr(n1str, ':')) != NULL) {
+                       *cp = '\0';
+                       n2str = cp+1;
+
+                       if ((cp = strchr(n2str, ':')) != NULL) {
+                               *cp = '\0';
+                               multstr = cp+1;
+                       }
+               }
+
+               /*
+                * Parse the 'min' field - if it is zero length (:n2[:mult]
+                * format), retain the default value, otherwise, pass the
+                * string to the parse function.
+                */
+
+               if ((int)strlen(n1str) > 0) {
+                       if ((*parse_func)(n1str, &rp->min) < 0) {
+                               sprintf(errmsg, "error parsing string %s into an integer", n1str);
+                               free(tmpstr);
+                               free(ranges);
+                               return -1;
+                       }
+               }
+
+               /*
+                * Process the 'max' field - if one was not present (n1 format)
+                * set max equal to min.  If the field was present, but 
+                * zero length (n1: format), retain the default.  Otherwise
+                * pass the string to the parse function.
+                */
+
+               if (n2str == NULL) {
+                       rp->max = rp->min;
+               } else if ((int)strlen(n2str) > 0) {
+                       if ((*parse_func)(n2str, &rp->max) < 0) {
+                               sprintf(errmsg, "error parsing string %s into an integer", n2str);
+                               free(tmpstr);
+                               free(ranges);
+                               return -1;
+                       }
+               }
+
+               /*
+                * Process the 'mult' field - if one was not present 
+                * (n1:n2 format), or the field was zero length (n1:n2: format)
+                * then set the mult field to defmult - otherwise pass then
+                * mult field to the parse function.
+                */
+
+               if (multstr != NULL && (int)strlen(multstr) > 0) {
+                       if ((*parse_func)(multstr, &rp->mult) < 0) {
+                               sprintf(errmsg, "error parsing string %s into an integer", multstr);
+                               free(tmpstr);
+                               free(ranges);
+                               return -1;
+                       }
+               }
+
+               rp++;
+               tok = strtok(NULL, ",");
+       }
+
+       free(tmpstr);
+
+       if (rangeptr != NULL) {
+               *rangeptr = (char *)ranges;
+       } else {
+               free(ranges);           /* just running in parse mode */
+       }
+
+       return (rp - ranges);
+}
+
+/*
+ * The default integer-parsing function
+ */
+
+static int
+str_to_int(str, ip)
+char   *str;
+int    *ip;
+{
+       char    c;
+
+       if (sscanf(str, "%i%c", ip, &c) != 1) {
+               return -1;
+       } else {
+               return 0;
+       }
+}
+
+/*
+ * Three simple functions to return the min, max, and mult values for a given
+ * range.  It is assumed that rbuf is a range buffer set up by parse_ranges(),
+ * and that r is a valid range within that buffer.
+ */
+
+int
+range_min(rbuf, r)
+char   *rbuf;
+int    r;
+{
+       return ((struct range *)rbuf)[r].min;
+}
+
+int
+range_max(rbuf, r)
+char   *rbuf;
+int    r;
+{
+       return ((struct range *)rbuf)[r].max;
+}
+
+int
+range_mult(rbuf, r)
+char   *rbuf;
+int    r;
+{
+       return ((struct range *)rbuf)[r].mult;
+}
+
+/*****************************************************************************
+ * random_range(int start, int end, int mult, char **errp)
+ *
+ * Returns a psuedo-random number which is >= 'start', <= 'end', and a multiple
+ * of 'mult'.  Start and end may be any valid integer, but mult must be an
+ * integer > 0.  errp is a char ** which will be set to point to a static
+ * error message buffer if it is not NULL, and an error occurs.
+ *
+ * The errp is the only way to check if the routine fails - currently the only
+ * failure conditions are:
+ *
+ *             mult < 1
+ *             no numbers in the start-end range that are a multiple of 'mult'
+ *
+ * If random_range_fails, and errp is a valid pointer, it will point to an
+ * internal error buffer.  If errp is a vaild pointer, and random_range
+ * is successful, errp will be set to NULL.
+ *
+ * Note - if mult is 1 (the most common case), there are error conditions
+ * possible, and errp need not be used.
+ *
+ * Note:    Uses lrand48(), assuming that set_random_seed() uses srand48() when
+ *          setting the seed.
+ *****************************************************************************/
+
+long
+random_range(min, max, mult, errp)
+int    min;
+int    max;
+int    mult;
+char   **errp;
+{
+       int             r, nmults, orig_min, orig_max, orig_mult, tmp;
+       extern long     lrand48();
+       static char     errbuf[128];
+
+       /*
+        * Sanity check
+        */
+
+       if (mult < 1) {
+               if (errp != NULL) {
+                       sprintf(errbuf, "mult arg must be greater than 0");
+                       *errp = errbuf;
+               }
+               return -1;
+       }
+
+       /*
+        * Save original parameter values for use in error message
+        */
+
+       orig_min = min;
+       orig_max = max;
+       orig_mult = mult;
+
+       /*
+        * switch min/max if max < min
+        */
+
+       if (max < min) {
+               tmp = max;
+               max = min;
+               min = tmp;
+       }
+
+       /*
+        * select the random number
+        */
+
+       if ((r = min % mult))     /* bump to the next higher 'mult' multiple */
+               min += mult - r;
+
+       if ((r = max % mult))     /* reduce to the next lower 'mult' multiple */
+               max -= r;
+
+       if (min > max) {         /* no 'mult' multiples between min & max */
+               if (errp != NULL) {
+                       sprintf(errbuf, "no numbers in the range %d:%d that are a multiple of %d", orig_min, orig_max, orig_mult);
+                       *errp = errbuf;
+               }
+               return -1;
+       }
+
+       if (errp != NULL) {
+               *errp = NULL;
+       }
+
+       nmults = ((max - min) / mult) + 1;
+#if CRAY 
+        /*
+         * If max is less than 2gb, then the value can fit in 32 bits
+         * and the standard lrand48() routine can be used.
+         */
+        if ( max <= (long)2147483647 ) {
+            return (long) (min + (((long)lrand48() % nmults) * mult));
+        } else {
+            /*
+             * max is greater than 2gb - meeds more than 32 bits.
+             * Since lrand48 only will get a number up to 32bits.
+             */
+           long randnum;
+            randnum=divider(min, max, 0, -1);
+            return (long) (min + ((randnum % nmults) * mult));
+        }
+
+#else
+        return (min + ((lrand48() % nmults) * mult));
+#endif
+
+}
+
+/*
+ * Just like random_range, but all values are longs.
+ */
+long
+random_rangel(min, max, mult, errp)
+long   min;
+long   max;
+long   mult;
+char   **errp;
+{
+       long            r, nmults, orig_min, orig_max, orig_mult, tmp;
+       extern long     lrand48();
+       static char     errbuf[128];
+
+       /*
+        * Sanity check
+        */
+
+       if (mult < 1) {
+               if (errp != NULL) {
+                       sprintf(errbuf, "mult arg must be greater than 0");
+                       *errp = errbuf;
+               }
+               return -1;
+       }
+
+       /*
+        * Save original parameter values for use in error message
+        */
+
+       orig_min = min;
+       orig_max = max;
+       orig_mult = mult;
+
+       /*
+        * switch min/max if max < min
+        */
+
+       if (max < min) {
+               tmp = max;
+               max = min;
+               min = tmp;
+       }
+
+       /*
+        * select the random number
+        */
+
+       if ((r = min % mult))     /* bump to the next higher 'mult' multiple */
+               min += mult - r;
+
+       if ((r = max % mult))     /* reduce to the next lower 'mult' multiple */
+               max -= r;
+
+       if (min > max) {         /* no 'mult' multiples between min & max */
+               if (errp != NULL) {
+                   sprintf(errbuf,
+                       "no numbers in the range %ld:%ld that are a multiple of %ld",
+                       orig_min, orig_max, orig_mult);
+                   *errp = errbuf;
+               }
+               return -1;
+       }
+
+       if (errp != NULL) {
+               *errp = NULL;
+       }
+
+       nmults = ((max - min) / mult) + 1;
+#if CRAY || (_MIPS_SZLONG == 64)
+        /*
+         * If max is less than 2gb, then the value can fit in 32 bits
+         * and the standard lrand48() routine can be used.
+         */
+        if ( max <= (long)2147483647 ) {
+            return (long) (min + (((long)lrand48() % nmults) * mult));
+        } else {
+            /*
+             * max is greater than 2gb - meeds more than 32 bits.
+             * Since lrand48 only will get a number up to 32bits.
+             */
+           long randnum;
+            randnum=divider(min, max, 0, -1);
+            return (long) (min + ((randnum % nmults) * mult));
+        }
+
+#else
+       return (min + ((lrand48() % nmults) * mult));
+#endif
+}
+
+/*
+ *  Attempts to be just like random_range, but everything is long long (64 bit)
+ */
+long long
+random_rangell(min, max, mult, errp)
+long long      min;
+long long      max;
+long long      mult;
+char           **errp;
+{
+       long long       r, nmults, orig_min, orig_max, orig_mult, tmp;
+        long long      randnum;
+       extern long     lrand48();
+       static char     errbuf[128];
+
+       /*
+        * Sanity check
+        */
+
+       if (mult < 1) {
+               if (errp != NULL) {
+                       sprintf(errbuf, "mult arg must be greater than 0");
+                       *errp = errbuf;
+               }
+               return -1;
+       }
+
+       /*
+        * Save original parameter values for use in error message
+        */
+
+       orig_min = min;
+       orig_max = max;
+       orig_mult = mult;
+
+       /*
+        * switch min/max if max < min
+        */
+
+       if (max < min) {
+               tmp = max;
+               max = min;
+               min = tmp;
+       }
+
+       /*
+        * select the random number
+        */
+
+       if ((r = min % mult))     /* bump to the next higher 'mult' multiple */
+               min += mult - r;
+
+       if ((r = max % mult))     /* reduce to the next lower 'mult' multiple */
+               max -= r;
+
+       if (min > max) {         /* no 'mult' multiples between min & max */
+               if (errp != NULL) {
+                   sprintf(errbuf,
+                       "no numbers in the range %lld:%lld that are a multiple of %lld",
+                       orig_min, orig_max, orig_mult);
+                   *errp = errbuf;
+               }
+               return -1;
+       }
+
+       if (errp != NULL) {
+               *errp = NULL;
+       }
+
+       nmults = ((max - min) / mult) + 1;
+        /*
+        * If max is less than 2gb, then the value can fit in 32 bits
+        * and the standard lrand48() routine can be used.
+        */
+       if ( max <= (long)2147483647 ) {  
+           return (long long) (min + (((long long)lrand48() % nmults) * mult));
+       } else {
+           /*
+            * max is greater than 2gb - meeds more than 32 bits.
+            * Since lrand48 only will get a number up to 32bits.
+            */
+           randnum=divider(min, max, 0, -1);
+           return (long long) (min + ((randnum % nmults) * mult));
+        }
+
+}
+
+/*
+ * This functional will recusively call itself to return a random
+ * number min and max.   It was designed to work the 64bit numbers
+ * even when compiled as 32 bit process.
+ * algorithm:  to use the official lrand48() routine - limited to 32 bits.
+ *   find the difference between min and max (max-min).
+ *   if the difference is 2g or less, use the random number gotton from lrand48().
+ *   Determine the midway point between min and max.
+ *   if the midway point is less than 2g from min or max,
+ *      randomly add the random number gotton from lrand48() to
+ *      either min or the midpoint.
+ *   Otherwise, call outself with min and max being min and midway value or
+ *   midway value and max.  This will reduce the range in half.
+ */
+static long long
+divider(long long min, long long max, long long cnt, long long rand)
+{
+    long long med, half, diff;
+
+    /*
+     * prevent run away code.  We are dividing by two each count.
+     * if we get to a count of more than 32, we should have gotten
+     * to 2gb.
+     */
+    if ( cnt > 32 )
+       return -1;
+
+    /*
+     * Only get a random number the first time.
+     */
+    if ( cnt == 0 || rand < -1 ) { 
+        rand = (long long)lrand48();  /* 32 bit random number */
+    }
+
+    diff = max - min;
+
+    if ( diff <= 2147483647 )
+       return min + rand;
+
+    half = diff/(long long)2;   /* half the distance between min and max */
+    med = min + half;          /* med way point between min and max */
+
+#if DEBUG
+printf("divider: min=%lld, max=%lld, cnt=%lld, rand=%lld\n", min, max, cnt, rand);
+printf("   diff = %lld, half = %lld,   med = %lld\n", diff, half, med);
+#endif
+
+    if ( half <= 2147483647 ) {
+        /*
+         * If half is smaller than 2gb, we can use the random number
+         * to pick the number within the min to med or med to max
+         * if the cnt bit of rand is zero or one, respectively.
+         */
+        if ( rand & (1<<cnt) )
+           return med + rand;
+        else
+           return min + rand;
+    } else {
+        /*
+        * recursively call ourself to reduce the value to the bottom half
+        * or top half (bit cnt is set).
+         */
+        if ( rand & (1<<cnt) ) {
+           return divider(med, max, cnt+1, rand);
+       } else {
+           return divider(min, med, cnt+1, rand);
+       }
+       
+    }
+
+}
+
+
+/*****************************************************************************
+ * random_range_seed(s)
+ *
+ * Sets the random seed to s.  Uses srand48(), assuming that lrand48() will
+ * be used in random_range().
+ *****************************************************************************/
+
+void
+random_range_seed(s)
+long    s;
+{
+    extern void srand48();
+
+    srand48(s);
+}
+
+/****************************************************************************
+ * random_bit(mask)
+ *
+ * This function randomly returns a single bit from the bits
+ * set in mask.  If mask is zero, zero is returned.
+ *
+ ****************************************************************************/
+long
+random_bit(long mask)
+{
+    int nbits = 0;      /* number of set bits in mask */
+    long bit;           /* used to count bits and num of set bits choosen */
+    int nshift;         /* used to count bit shifts */
+
+    if ( mask == 0 )
+        return 0;
+
+    /*
+     * get the number of bits set in mask
+     */
+#ifndef CRAY
+
+        bit=1L;
+        for ( nshift=0; nshift<sizeof(long)*8; nshift++) {
+                if ( mask & bit )
+                        nbits++;
+                bit=bit<<1;
+        }
+
+#else
+        nbits=_popcnt(mask);
+#endif  /* if CRAY */
+
+    /*
+     * randomly choose a bit.
+     */
+    bit=random_range(1, nbits, 1, NULL);
+
+    /*
+     * shift bits until you determine which bit was randomly choosen.
+     * nshift will hold the number of shifts to make.
+     */
+
+    nshift=0;
+    while (bit) {
+        /* check if the current one's bit is set */
+        if ( mask & 1L ) {
+            bit--;
+        }
+        mask = mask >> 1;
+        nshift++;
+    }
+
+    return 01L << (nshift-1);
+
+}
+
+
+#if RANDOM_BIT_UNITTEST
+/*
+ *  The following is a unit test main function for random_bit().
+ */
+main(argc, argv)
+int argc;
+char **argv;
+{
+    int ind;
+    int cnt, iter;
+    long mask, ret;
+
+    printf("test for first and last bit set\n");
+    mask=1L;
+    ret=random_bit(mask);
+    printf("random_bit(%#o) returned %#o\n", mask, ret);
+
+    mask=1L<<(sizeof(long)*8-1);
+    ret=random_bit(mask);
+    printf("random_bit(%#o) returned %#o\n", mask, ret);
+
+    if ( argc >= 3 ) {
+        iter=atoi(argv[1]);
+        for (ind=2; ind<argc; ind++) {
+            printf("Calling random_bit %d times for mask %#o\n", iter, mask);
+            sscanf(argv[ind], "%i", &mask);
+            for (cnt=0; cnt<iter; cnt++) {
+                ret=random_bit(mask);
+                printf("random_bit(%#o) returned %#o\n", mask, ret);
+            }
+        }
+    }
+    exit(0);
+}
+
+#endif /* end if RANDOM_BIT_UNITTEST */
+
+
+#if UNIT_TEST
+/*
+ *  The following is a unit test main function for random_range*().
+ */
+
+#define PARTNUM        10      /* used to determine even distribution of random numbers */
+#define MEG  1024*1024*1024
+#define GIG 1073741824
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+    int ind;
+    int cnt, iter=10;
+    int imin=0, imult=1, itmin, itmax=0;
+#if CRAY
+    int imax=6*GIG;    /* higher than 32 bits */
+#else
+    int imax=1048576;
+#endif
+
+    long lret, lmin=0, lmult=1, ltmin, ltmax=0; 
+#if CRAY || (_MIPS_SZLONG == 64)
+    long lmax=6*(long)GIG;     /* higher than 32 bits */
+#else
+    long lmax=1048576;
+#endif
+    long long llret, llmin=0, llmult=1, lltmin, lltmax=0;
+    long long llmax=(long long)80*(long long)GIG;
+
+    long part;
+    long long lpart;
+    long cntarr[PARTNUM];
+    long valbound[PARTNUM];
+    long long lvalbound[PARTNUM];
+
+    for (ind=0; ind<PARTNUM; ind++ )
+       cntarr[ind]=0;
+    
+    if ( argc < 2 ) {
+        printf("Usage: %s func [iterations] \n", argv[0]);
+       printf("func can be random_range, random_rangel, random_rangell\n");
+       exit(1);
+    }
+
+    if ( argc >= 3 ) {
+        if ( sscanf(argv[2], "%i", &iter) != 1 ) {
+            printf("Usage: %s [func iterations] \n", argv[0]);
+           printf("argv[2] is not a number\n");
+           exit(1);
+        }
+    }
+
+
+    /*
+     * random_rangel ()
+     */
+    if ( strcmp(argv[1], "random_rangel") == 0 ) {
+       ltmin=lmax;
+        part = lmax/PARTNUM;
+        for(ind=0; ind<PARTNUM; ind++) {
+           valbound[ind]=part*ind;
+        }
+
+       for(cnt=0; cnt<iter; cnt++) {
+           lret=random_rangel(lmin, lmax, lmult, NULL);
+           if ( iter < 100 )
+               printf("%ld\n", lret);
+           if ( lret < ltmin )
+               ltmin = lret;
+           if ( lret > ltmax )
+               ltmax = lret;
+           for(ind=0; ind<PARTNUM-1; ind++) {
+               if ( valbound[ind]  < lret && lret <= valbound[ind+1] ) {
+                   cntarr[ind]++;
+                   break;
+               }
+           }
+           if ( lret > valbound[PARTNUM-1] ) {
+               cntarr[PARTNUM-1]++;
+           }
+        }
+        for(ind=0; ind<PARTNUM-1; ind++) {
+           printf("%2d %-13ld to  %-13ld   %5ld %4.4f\n", ind+1,
+               valbound[ind], valbound[ind+1], cntarr[ind],
+               (float)(cntarr[ind]/(float)iter));
+        }
+        printf("%2d %-13ld to  %-13ld   %5ld %4.4f\n", PARTNUM, 
+           valbound[PARTNUM-1], lmax, cntarr[PARTNUM-1],
+           (float)(cntarr[PARTNUM-1]/(float)iter));
+       printf("  min=%ld,  max=%ld\n", ltmin, ltmax);
+
+    } else if ( strcmp(argv[1], "random_rangell") == 0 ) {
+       /*
+       * random_rangell() unit test
+        */
+        lltmin=llmax;
+        lpart = llmax/PARTNUM;
+        for(ind=0; ind<PARTNUM; ind++) {
+           lvalbound[ind]=(long long)(lpart*ind);
+        }
+
+       for(cnt=0; cnt<iter; cnt++) {
+           llret=random_rangell(llmin, llmax, llmult, NULL);
+           if ( iter < 100 )
+               printf("random_rangell returned %lld\n", llret);
+            if ( llret < lltmin )
+                lltmin = llret;
+            if ( llret > lltmax )
+                lltmax = llret;
+
+           for(ind=0; ind<PARTNUM-1; ind++) {
+               if ( lvalbound[ind]  < llret && llret <= lvalbound[ind+1] ) {
+                   cntarr[ind]++;
+                   break;
+               }
+           }
+           if ( llret > lvalbound[PARTNUM-1] ) {
+               cntarr[PARTNUM-1]++;
+           }
+        }
+        for(ind=0; ind<PARTNUM-1; ind++) {
+            printf("%2d %-13lld to  %-13lld   %5ld %4.4f\n", ind+1,
+                lvalbound[ind], lvalbound[ind+1], cntarr[ind],
+                (float)(cntarr[ind]/(float)iter));
+        }
+        printf("%2d %-13lld to  %-13lld   %5ld %4.4f\n", PARTNUM,
+            lvalbound[PARTNUM-1], llmax, cntarr[PARTNUM-1],
+            (float)(cntarr[PARTNUM-1]/(float)iter));
+       printf("  min=%lld,  max=%lld\n", lltmin, lltmax);
+
+    } else {
+       /*
+        * random_range() unit test
+         */
+       itmin=imax;
+        part = imax/PARTNUM;
+        for(ind=0; ind<PARTNUM; ind++) {
+           valbound[ind]=part*ind;
+        }
+
+       for(cnt=0; cnt<iter; cnt++) {
+           lret=random_range(imin, imax, imult, NULL);
+           if ( iter < 100 )
+               printf("%ld\n", lret);
+            if ( lret < itmin )
+                itmin = lret;
+            if ( lret > itmax )
+                itmax = lret;
+
+           for(ind=0; ind<PARTNUM-1; ind++) {
+               if ( valbound[ind]  < lret && lret <= valbound[ind+1] ) {
+                   cntarr[ind]++;
+                   break;
+               }
+           }
+           if ( lret > valbound[PARTNUM-1] ) {
+               cntarr[PARTNUM-1]++;
+           }
+        }
+        for(ind=0; ind<PARTNUM-1; ind++) {
+           printf("%2d %-13ld to  %-13ld   %5ld %4.4f\n", ind+1,
+               valbound[ind], valbound[ind+1], cntarr[ind],
+               (float)(cntarr[ind]/(float)iter));
+        }
+        printf("%2d %-13ld to  %-13ld   %5ld %4.4f\n", PARTNUM, 
+           valbound[PARTNUM-1], (long)imax, cntarr[PARTNUM-1],
+           (float)(cntarr[PARTNUM-1]/(float)iter));
+       printf("  min=%d,  max=%d\n", itmin, itmax);
+
+    }
+
+    exit(0);
+}
+
+#endif
diff --git a/lib/str_to_bytes.c b/lib/str_to_bytes.c
new file mode 100644 (file)
index 0000000..af63a1b
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+#include <stdio.h>
+#include <sys/param.h>
+#include "str_to_bytes.h"
+
+/****************************************************************************
+ * str_to_bytes(s)
+ *
+ * Computes the number of bytes described by string s.  s is assumed to be
+ * a base 10 positive (ie. >= 0) number followed by an optional single
+ * character multiplier.  The following multipliers are supported:
+ *
+ *              char    mult
+ *              -----------------
+ *              b       BSIZE  or BBSIZE
+ *              k       1024 bytes
+ *              K       1024 * sizeof(long)
+ *              m       2^20 (1048576)
+ *              M       2^20 (1048576 * sizeof(long)
+ *              g       2^30 (1073741824)
+ *              G       2^30 (1073741824) * sizeof(long)
+ *
+ * for instance, "1k" and "1024" would both cause str_to_bytes to return 1024.
+ *
+ * Returns -1 if mult is an invalid character, or if the integer portion of
+ * s is not a positive integer.
+ *
+ ****************************************************************************/
+
+#if CRAY
+#define B_MULT BSIZE           /* block size */
+#elif sgi
+#define B_MULT BBSIZE          /* block size */
+#elif linux
+#define B_MULT DEV_BSIZE       /* block size */
+#endif
+
+
+#define K_MULT 1024            /* Kilo or 2^10 */
+#define M_MULT 1048576         /* Mega or 2^20 */
+#define G_MULT 1073741824      /* Giga or 2^30 */
+#define T_MULT 1099511627776   /* tera or 2^40 */
+
+int
+str_to_bytes(s)
+char    *s;
+{
+    char    mult, junk;
+    int            nconv;
+    float   num;
+
+    nconv = sscanf(s, "%f%c%c", &num, &mult, &junk);
+    if (nconv == 0 || nconv == 3 )
+       return -1;
+
+    if (nconv == 1)
+       return num;
+
+    switch (mult) {
+    case 'b':
+               return (int)(num * (float)B_MULT);
+    case 'k':
+               return (int)(num * (float)K_MULT);
+    case 'K':
+               return (int)((num * (float)K_MULT) * sizeof(long));
+    case 'm':
+               return (int)(num * (float)M_MULT);
+    case 'M':
+               return (int)((num * (float)M_MULT) * sizeof(long));
+    case 'g':
+               return (int)(num * (float)G_MULT);
+    case 'G':  
+               return (int)((num * (float)G_MULT) * sizeof(long));
+    default:
+       return -1;
+    }
+}
+
+long
+str_to_lbytes(s)
+char    *s;
+{
+    char    mult, junk;
+    long    nconv;
+    float   num;
+
+    nconv = sscanf(s, "%f%c%c", &num, &mult, &junk);
+    if (nconv == 0 || nconv == 3 )
+       return -1;
+
+    if (nconv == 1)
+       return (long)num;
+
+    switch (mult) {
+    case 'b':
+               return (long)(num * (float)B_MULT);
+    case 'k':
+               return (long)(num * (float)K_MULT);
+    case 'K':
+               return (long)((num * (float)K_MULT) * sizeof(long));
+    case 'm':
+               return (long)(num * (float)M_MULT);
+    case 'M':
+               return (long)((num * (float)M_MULT) * sizeof(long));
+    case 'g':
+               return (long)(num * (float)G_MULT);
+    case 'G':  
+               return (long)((num * (float)G_MULT) * sizeof(long));
+    default:
+       return -1;
+    }
+}
+
+/*
+ * Force 64 bits number when compiled as 32 IRIX binary.
+ * This allows for a number bigger than 2G.
+ */
+
+long long
+str_to_llbytes(s)
+char    *s;
+{
+    char    mult, junk;
+    long    nconv;
+    double  num;
+
+    nconv = sscanf(s, "%lf%c%c", &num, &mult, &junk);
+    if (nconv == 0 || nconv == 3 )
+       return -1;
+
+    if (nconv == 1)
+       return (long long)num;
+
+    switch (mult) {
+    case 'b':
+               return (long long)(num * (float)B_MULT);
+    case 'k':
+               return (long long)(num * (float)K_MULT);
+    case 'K':
+               return (long long)((num * (float)K_MULT) * sizeof(long long));
+    case 'm':
+               return (long long)(num * (float)M_MULT);
+    case 'M':
+               return (long long)((num * (float)M_MULT) * sizeof(long long));
+    case 'g':
+               return (long long)(num * (float)G_MULT);
+    case 'G':  
+               return (long long)((num * (float)G_MULT) * sizeof(long long));
+    default:
+       return -1;
+    }
+}
+
+#ifdef UNIT_TEST
+
+main(int argc, char **argv)
+{
+    int ind;
+
+    if (argc == 1 ) {
+       fprintf(stderr, "missing str_to_bytes() parameteres\n");
+       exit(1);
+    }
+   
+    for (ind=1; ind<argc; ind++) {
+
+       printf("str_to_bytes(%s) returned %d\n", 
+           argv[ind], str_to_bytes(argv[ind]));
+
+       printf("str_to_lbytes(%s) returned %ld\n", 
+           argv[ind], str_to_lbytes(argv[ind]));
+
+       printf("str_to_llbytes(%s) returned %lld\n", 
+           argv[ind], str_to_llbytes(argv[ind]));
+    }
+}
+
+#endif
diff --git a/lib/string_to_tokens.c b/lib/string_to_tokens.c
new file mode 100644 (file)
index 0000000..6f0d775
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+/**********************************************************
+ * 
+ *    OS Testing - Silicon Graphics, Inc.
+ * 
+ *    FUNCTION NAME     : string_to_tokens
+ * 
+ *    FUNCTION TITLE    : Break a string into its tokens
+ * 
+ *    SYNOPSIS:
+ *
+ * int string_to_tokens(arg_string, arg_array, array_size, separator)
+ *    char *arg_string;
+ *    char *arg_array[];
+ *    int array_size;
+ *    char *separator;
+ * 
+ *    AUTHOR            : Richard Logan
+ *
+ *    DATE             : 10/94
+ *
+ *    INITIAL RELEASE   : UNICOS 7.0
+ * 
+ *    DESCRIPTION
+ * This function parses the string 'arg_string', placing pointers to
+ * the 'separator' separated tokens into the elements of 'arg_array'.
+ * The array is terminated with a null pointer.
+ * 'arg_array' must contains at least 'array_size' elements.
+ * Only the first 'array_size' minus one tokens will be placed into
+ * 'arg_array'.  If there are more than 'array_size'-1 tokens, the rest are
+ * ignored by this routine.
+ *
+ *    RETURN VALUE
+ * This function returns the number of 'separator' separated tokens that
+ * were found in 'arg_string'.
+ * If 'arg_array' or 'separator' is NULL or 'array_size' is less than 2, -1 is returned.
+ * 
+ *    WARNING
+ * This function uses strtok() to parse 'arg_string', and thus
+ * physically alters 'arg_string' by placing null characters where the
+ * separators originally were.
+ *
+ *
+ *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
+#include <stdio.h>         
+#include <string.h>        /* for string functions */
+#include "string_to_tokens.h"
+
+int
+string_to_tokens(char *arg_string, char *arg_array[], int array_size, char *separator)
+{
+   int num_toks = 0;  /* number of tokens found */
+   char *strtok();
+       
+   if ( arg_array == NULL || array_size <= 1 || separator == NULL )
+       return -1;
+
+   /*
+    * Use strtok() to parse 'arg_string', placing pointers to the
+    * individual tokens into the elements of 'arg_array'.
+    */
+   if ( (arg_array[num_toks] = strtok(arg_string, separator)) == NULL ) {
+       return 0;
+   }
+
+   for (num_toks=1;num_toks<array_size; num_toks++) {
+       if ( (arg_array[num_toks] = strtok(NULL, separator)) == NULL )
+           break;
+   }
+
+   if ( num_toks == array_size )
+       arg_array[num_toks] = NULL;
+
+   /*
+    * Return the number of tokens that were found in 'arg_string'.
+    */
+   return(num_toks);
+
+} /* end of string_to_tokens */
diff --git a/lib/tlibio.c b/lib/tlibio.c
new file mode 100644 (file)
index 0000000..82fe08b
--- /dev/null
@@ -0,0 +1,1992 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+/*
+ *
+ * Lib i/o
+ *
+ * This file contains several functions to doing reads and writes.
+ * It was written so that a single function could be called in a test
+ * program and only a io type field value would have to change to
+ * do different types of io.  There is even a couple of functions that
+ * will allow you to parse a string to determine the iotype.
+ *
+ * This file contains functions for writing/reading to/from open files
+ * Prototypes:
+ *
+ * Functions declared in this module - see individual function code for
+ * usage comments:
+ *
+ *  int         stride_bounds(int offset, int stride, int nstrides,
+ *                   int bytes_per_stride, int *min, int *max);
+
+ *  int  lio_write_buffer(int fd, int method, char *buffer, int size,
+ *                                             char **errmsg, long wrd);
+ *  int  lio_read_buffer(int fd, int method, char *buffer, int size,
+ *                                             char **errmsg, long wrd);
+ *
+ *  #ifdef CRAY
+ *  int  lio_wait4asyncio(int method, int fd, struct iosw **statptr)
+ *  int  lio_check_asyncio(char *io_type, int size, struct iosw *status)
+ *  #endif
+ *  #ifdef sgi
+ *  int  lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
+ *  int  lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
+ *  #endif
+ *
+ *  int  lio_parse_io_arg1(char *string)
+ *  void lio_help1(char *prefix);
+ *
+ *  int  lio_parse_io_arg2(char *string, char **badtoken)
+ *  void lio_help2(char *prefix);
+ *
+ *  int  lio_set_debug(int level);
+ *
+ *  char Lio_SysCall[];
+ *  struct lio_info_type Lio_info1[];
+ *  struct lio_info_type Lio_info2[];
+ *
+ *  Author : Richard Logan
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>          
+#include <sys/param.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <signal.h>
+#ifdef CRAY
+#include <sys/secparm.h>
+#include <sys/iosw.h>
+#include <sys/listio.h>
+#else
+/* for linux or sgi */
+#include <sys/uio.h> /* readv(2)/writev(2) */
+#include <string.h>  /* bzero */
+#endif
+#ifdef sgi
+#include <aio.h>
+#endif
+#include <stdlib.h> /* atoi, abs */
+
+#include "tlibio.h"            /* defines LIO* marcos */
+
+#ifndef PATH_MAX
+#define PATH_MAX       MAXPATHLEN
+#endif
+
+#if 0 /* disabled until it's needed -- roehrich 6/11/97 */
+#define BUG1_workaround        1 /* Work around a condition where aio_return gives
+                          * a value of zero but there is no errno followup
+                          * and the read/write operation actually did its
+                          * job.   spr/pv 705244
+                          */
+#endif
+
+
+#ifndef linux
+static void lio_async_signal_handler();
+#endif
+#ifdef sgi
+static void lio_async_callback_handler();
+#endif
+
+/*
+ * Define the structure as used in lio_parse_arg1 and lio_help1
+ */
+struct lio_info_type  Lio_info1[] = {
+    { "s", LIO_IO_SYNC, "sync i/o" },
+    { "p", LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, "async i/o using a loop to wait for a signal" },
+    { "b", LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, "async i/o using pause" },
+    { "a", LIO_IO_ASYNC|LIO_WAIT_RECALL, "async i/o using recall/aio_suspend" },
+#ifdef sgi
+    { "r", 
+       LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random sync i/o types and wait methods" },
+    { "R", 
+       LIO_RANDOM|LIO_IO_ATYPES|LIO_WAIT_ATYPES, "random i/o types and wait methods" },
+#else
+    { "r", 
+       LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
+    { "R", 
+       LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
+#endif
+    { "l", LIO_IO_SLISTIO|LIO_WAIT_RECALL, "single stride sync listio" },
+    { "L", LIO_IO_ALISTIO|LIO_WAIT_RECALL, "single stride async listio using recall" },
+    { "X", LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, "single stride async listio using pause" },
+    { "v", LIO_IO_SYNCV, "single buffer sync readv/writev" },
+    { "P", LIO_IO_SYNCP, "sync pread/pwrite" },
+};
+
+/*
+ * Define the structure used by lio_parse_arg2 and lio_help2
+ */
+struct lio_info_type  Lio_info2[] = {
+    { "sync",      LIO_IO_SYNC,                "sync i/o (read/write)"},
+    { "async",     LIO_IO_ASYNC,       "async i/o (reada/writea/aio_read/aio_write)" },
+    { "slistio",   LIO_IO_SLISTIO,     "single stride sync listio" },
+    { "alistio",   LIO_IO_ALISTIO,     "single stride async listio" },
+    { "syncv",     LIO_IO_SYNCV,       "single buffer sync readv/writev"},
+    { "syncp",     LIO_IO_SYNCP,       "pread/pwrite"},
+    { "active",    LIO_WAIT_ACTIVE,    "spin on status/control values" },
+    { "recall",    LIO_WAIT_RECALL,    "use recall(2)/aio_suspend(3) to wait for i/o to complete" },
+    { "sigactive", LIO_WAIT_SIGACTIVE,  "spin waiting for signal" },
+    { "sigpause",  LIO_WAIT_SIGPAUSE,  "call pause(2) to wait for signal" },
+/* nowait is a touchy thing, it's an accident that this implementation worked at all.  6/27/97 roehrich */
+/*    { "nowait",    LIO_WAIT_NONE,    "do not wait for async io to complete" },*/
+    { "random",    LIO_RANDOM,         "set random bit" },
+    { "randomall", 
+       LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, 
+       "all random i/o types and wait methods (except nowait)" },
+};
+
+char Lio_SysCall[PATH_MAX];    /* string containing last i/o system call */
+
+static volatile int Received_signal = 0;       /* number of signals received */
+static volatile int Rec_signal;
+#ifdef sgi
+static volatile int Received_callback = 0;     /* number of callbacks received */
+static volatile int Rec_callback;
+#endif
+static char Errormsg[500];
+static int Debug_level = 0;
+
+
+
+/***********************************************************************
+ * stride_bounds()
+ *
+ * Determine the bounds of a strided request, normalized to offset.  Returns
+ * the number of bytes needed to satisfy the request, and optionally sets
+ * *min and *max to the mininum and maximum bytes referenced, normalized 
+ * around offset.
+ *
+ * Returns -1 on error - the only possible error conditions are illegal values
+ * for nstrides and/or bytes_per_stride - both parameters must be >= 0.
+ *
+ * (maule, 11/16/95)
+ ***********************************************************************/
+
+int
+stride_bounds(offset, stride, nstrides, bytes_per_stride, min, max)
+int    offset;
+int    stride;
+int    nstrides;
+int    bytes_per_stride;
+int    *min;
+int    *max;
+{
+       int     nbytes, min_byte, max_byte;
+
+       /*
+        * sanity checks ...
+        */
+
+       if (nstrides < 0 || bytes_per_stride < 0) {
+               return -1;
+       }
+
+       if (stride == 0) {
+               stride = bytes_per_stride;
+       }
+
+       /*
+        * Determine the # of bytes needed to satisfy the request.  This
+        * value, along with the offset argument, determines the min and max
+        * bytes referenced.
+        */
+
+
+       nbytes = abs(stride) * (nstrides-1) + bytes_per_stride;
+
+       if (stride < 0) {
+               max_byte = offset + bytes_per_stride - 1;
+               min_byte = max_byte - nbytes + 1;
+       } else {
+               min_byte = offset;
+               max_byte = min_byte + nbytes - 1;
+       }
+       
+       if (min != NULL) {
+               *min = min_byte;
+       }
+       
+       if (max != NULL) {
+               *max = max_byte;
+       }
+
+       return nbytes;
+}
+
+/***********************************************************************
+ * This function will allow someone to set the debug level.
+ ***********************************************************************/
+int
+lio_set_debug(level)
+{
+    int old;
+
+    old = Debug_level;
+    Debug_level = level;
+    return old;
+}
+
+/***********************************************************************
+ * This function will parse a string and return desired io-method.
+ * Only the first character of the string is used.
+ *
+ * This function does not provide for meaningful option arguments,
+ * but it supports current growfiles/btlk interface.
+ *
+ *  (rrl 04/96)
+ ***********************************************************************/
+int
+lio_parse_io_arg1(char *string)
+{
+    int ind;
+    int found=0;
+    int mask=0;
+
+    /*
+     * Determine if token is a valid string.
+     */
+    for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
+        if ( strcmp(string, Lio_info1[ind].token) == 0 ) {
+            mask |= Lio_info1[ind].bits;
+            found = 1;
+            break;
+        }
+    }
+
+    if ( found == 0 ) {
+       return -1;
+    }
+
+    return mask;
+
+}
+
+/***********************************************************************
+ * This function will print a help message describing the characters
+ * that can be parsed by lio_parse_io_arg1().
+ * They will be printed one per line.
+ *  (rrl 04/96)
+ ***********************************************************************/
+void
+lio_help1(char *prefix)
+{
+    int ind;
+
+    for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
+        printf("%s %s : %s\n", prefix,
+            Lio_info1[ind].token, Lio_info1[ind].desc);
+    }
+
+    return;
+}
+
+/***********************************************************************
+ * This function will parse a string and return the desired io-method.
+ * This function will take a comma separated list of io type and wait
+ * method tokens as defined in Lio_info2[].  If a token does not match
+ * any of the tokens in Lio_info2[], it will be coverted to a number.
+ * If it was a number, those bits are also set.
+ * 
+ *  (rrl 04/96)
+ ***********************************************************************/
+int
+lio_parse_io_arg2(char *string, char **badtoken)
+{
+   char *token = string;
+   char *cc = token;
+   char savecc;
+   int found;
+   int mask=0;
+
+   int tmp;
+   int ind;
+   char chr;
+
+   if ( token == NULL )
+        return -1;
+
+   for (;;) {
+        for (; ((*cc != ',') && (*cc != '\0')); cc++);
+        savecc = *cc;
+        *cc = '\0';
+
+        found = 0; 
+
+        /*
+        * Determine if token is a valid string or number and if
+        * so, add the bits to the mask.
+          */
+        for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
+           if ( strcmp(token, Lio_info2[ind].token) == 0 ) {
+               mask |= Lio_info2[ind].bits;
+               found = 1;
+               break;
+           }
+        }
+
+       /*
+        * If token does not match one of the defined tokens, determine
+         * if it is a number, if so, add the bits.
+        */
+       if ( !found ) {
+           if (sscanf(token, "%i%c", &tmp, &chr) == 1 ) {
+                mask |= tmp;
+               found=1;
+           }
+        }
+
+        *cc = savecc;
+
+        if (!found) {  /* token is not valid */
+            if ( badtoken != NULL)
+                *badtoken = token;
+            return(-1);
+        }
+
+        if (savecc == '\0')
+            break;
+
+        token = ++cc;
+    }
+
+    return mask;
+}
+
+/***********************************************************************
+ * This function will print a help message describing the tokens
+ * that can be parsed by lio_parse_io_arg2().
+ * It will print them one per line.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+void
+lio_help2(char *prefix)
+{
+    int ind;
+
+    for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
+       printf("%s %s : %s\n", prefix,
+           Lio_info2[ind].token, Lio_info2[ind].desc);
+    }
+    return;
+}
+
+#ifndef linux
+/***********************************************************************
+ * This is an internal signal handler.
+ * If the handler is called, it will increment the Received_signal
+ * global variable.
+ ***********************************************************************/
+static void
+lio_async_signal_handler(int sig)
+{
+       if ( Debug_level )
+           printf("DEBUG %s/%d: received signal %d, a signal caught %d times\n",
+               __FILE__, __LINE__, sig, Received_signal+1);
+
+       Received_signal++;
+
+       return;
+}
+#endif
+
+#ifdef sgi
+/***********************************************************************
+ * This is an internal callback handler.
+ * If the handler is called, it will increment the Received_callback
+ * global variable.
+ ***********************************************************************/
+static void
+lio_async_callback_handler(sigval_t sigval)
+{
+       if ( Debug_level )
+           printf("DEBUG %s/%d: received callback, nbytes=%ld, a callback called %d times\n",
+               __FILE__, __LINE__, sigval.sival_int, Received_callback+1);
+
+       Received_callback++;
+
+       return;
+}
+#endif /* sgi */
+
+/***********************************************************************
+ * lio_random_methods
+ * This function will randomly choose an io type and wait method
+ * from set of io types and wait methods.  Since this information
+ * is stored in a bitmask, it randomly chooses an io type from
+ * the io type bits specified and does the same for wait methods.
+ *
+ * Return Value
+ * This function will return a value with all non choosen io type
+ * and wait method bits cleared.  The LIO_RANDOM bit is also 
+ * cleared.  All other bits are left unchanged.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+lio_random_methods(long curr_mask)
+{
+    int mask=0;
+    long random_bit();
+
+    /* remove random select, io type, and wait method bits from curr_mask */
+    mask = curr_mask & (~(LIO_IO_TYPES | LIO_WAIT_TYPES | LIO_RANDOM));
+
+    /* randomly select io type from specified io types */
+    mask = mask | random_bit(curr_mask & LIO_IO_TYPES);
+
+    /* randomly select wait methods  from specified wait methods */
+    mask = mask | random_bit(curr_mask & LIO_WAIT_TYPES);
+
+    return mask;
+}
+
+/***********************************************************************
+ * Generic write function 
+ * This function can be used to do a write using write(2), writea(2),
+ * aio_write(3), writev(2), pwrite(2),
+ * or single stride listio(2)/lio_listio(3).
+ * By setting the desired bits in the method
+ * bitmask, the caller can control the type of write and the wait method
+ * that will be used.  If no io type bits are set, write will be used.
+ *
+ * If async io was attempted and no wait method bits are set then the
+ * wait method is: recall(2) for writea(2) and listio(2); aio_suspend(3) for
+ * aio_write(3) and lio_listio(3).
+ *
+ * If multiple wait methods are specified, 
+ * only one wait method will be used. The order is predetermined.
+ *
+ * If the call specifies a signal and one of the two signal wait methods,
+ * a signal handler for the signal is set.  This will reset an already
+ * set handler for this signal. 
+ *
+ * If the LIO_RANDOM method bit is set, this function will randomly
+ * choose a io type and wait method from bits in the method argument.
+ *
+ * If an error is encountered, an error message will be generated
+ * in a internal static buffer.  If errmsg is not NULL, it will
+ * be updated to point to the static buffer, allowing the caller
+ * to print the error message.
+ *
+ * Return Value
+ *   If a system call fails, -errno is returned.
+ *   If LIO_WAIT_NONE bit is set, the return value is the return value
+ *   of the system call.
+ *   If the io did not fail, the amount of data written is returned.
+ *     If the size the system call say was written is different
+ *     then what was asked to be written, errmsg is updated for
+ *     this error condition.  The return value is still the amount
+ *     the system call says was written.  
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+lio_write_buffer(fd, method, buffer, size, sig, errmsg, wrd)
+int fd;                /* open file descriptor */
+int method;    /* contains io type and wait method bitmask */
+char *buffer;  /* pointer to buffer */
+int size;      /* the size of the io */
+int sig;       /* signal to use if async io */
+char **errmsg; /* char pointer that will be updated to point to err message */
+long wrd;      /* to allow future features, use zero for now */
+{
+    int ret = 0;       /* syscall return or used to get random method */
+    char *io_type;             /* Holds string of type of io */
+#ifndef linux
+    int omethod = method;
+    int listio_cmd;            /* Holds the listio/lio_listio cmd */
+#endif
+#ifdef  CRAY
+    struct listreq request;    /* Used when a listio is wanted */
+    struct iosw status, *statptr[1];  
+#else
+    /* for linux or sgi */
+    struct iovec iov;  /* iovec for writev(2) */
+#endif
+#ifdef sgi
+    aiocb_t aiocbp;    /* POSIX aio control block */
+    aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
+    off64_t poffset;   /* pwrite(2) offset */
+#endif
+
+    /*
+     * If LIO_RANDOM bit specified, get new method randomly.
+     */
+    if ( method & LIO_RANDOM ) {
+       if( Debug_level > 3 )
+               printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
+       method = lio_random_methods(method);
+       if ( Debug_level > 2 )
+           printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
+    }
+
+    if ( errmsg != NULL )
+       *errmsg = Errormsg;
+
+    Rec_signal=Received_signal;        /* get the current number of signals received */
+#ifdef sgi
+    Rec_callback=Received_callback;    /* get the current number of callbacks received */
+#endif
+
+#ifdef  CRAY
+    bzero(&status, sizeof(struct iosw));
+    bzero(&request, sizeof(struct listreq));
+    statptr[0] = &status;
+#else
+    /* for linux or sgi */
+    bzero(&iov, sizeof(struct iovec));
+    iov.iov_base = buffer;
+    iov.iov_len = size;
+#endif
+#ifdef sgi
+    bzero(&aiocbp, sizeof(aiocb_t));
+    aiocbp.aio_fildes = fd;
+    aiocbp.aio_nbytes = size;
+    aiocbp.aio_buf = buffer;
+/*    aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
+    aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
+    aiocbp.aio_sigevent.sigev_signo = 0;
+    aiocbp.aio_sigevent.sigev_func = NULL;
+    aiocbp.aio_sigevent.sigev_value.sival_int = 0;
+    aiolist[0] = &aiocbp;
+
+    if( (ret = lseek( fd, 0, SEEK_CUR )) == -1 ){
+       ret = 0;
+       /* If there is an error and it is not ESPIPE then kick out the error.
+        * If the fd is a fifo then we have to make sure that
+        * lio_random_methods() didn't select pwrite/pread; if it did then
+        * switch to write/read.
+        */
+       if( errno == ESPIPE ){
+               if( method & LIO_IO_SYNCP ){
+                       if( omethod & LIO_RANDOM ){
+                               method &= ~LIO_IO_SYNCP;
+                               method |= LIO_IO_SYNC;
+                               if( Debug_level > 2 )
+                                       printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method );
+                       }
+                       else if( Debug_level ){
+                               printf("DEBUG %s/%d: pwrite will fail when it writes to a fifo\n",
+                                      __FILE__, __LINE__ );
+                       }
+               }
+               /* else: let it ride */
+       }
+       else{
+               sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d  %s",
+                       __FILE__, __LINE__, fd, errno, strerror(errno));
+               return -errno;
+       }
+    }
+    poffset = (off64_t)ret;
+    aiocbp.aio_offset = ret;
+
+#endif
+
+    /*
+     * If the LIO_USE_SIGNAL bit is not set, only use the signal
+     * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit.
+     * Otherwise there is not necessary a signal handler to trap
+     * the signal.
+     */
+    if ( sig && !(method & LIO_USE_SIGNAL) && 
+       ! (method & LIO_WAIT_SIGTYPES) ){
+
+       sig=0;  /* ignore signal parameter */
+    }
+
+#ifdef sgi
+    if ( sig && (method & LIO_WAIT_CBTYPES) )
+       sig=0; /* ignore signal parameter */
+#endif
+
+    /*
+     * only setup signal hander if sig was specified and
+     * a sig wait method was specified.
+     * Doing this will change the handler for this signal.  The
+     * old signal handler will not be restored.
+     *** restoring the signal handler could be added ***
+     */
+
+    if ( sig &&  (method & LIO_WAIT_SIGTYPES) ){
+#ifdef CRAY
+        sigctl(SCTL_REG, sig, lio_async_signal_handler);
+#endif
+#ifdef sgi
+        aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+       aiocbp.aio_sigevent.sigev_signo = sig;
+        sigset(sig, lio_async_signal_handler);
+#endif /* sgi */
+    }
+#ifdef sgi
+    else if( method & LIO_WAIT_CBTYPES ){
+       /* sival_int just has to be something that I can use
+        * to identify the callback, and "size" happens to be handy...
+        */
+       aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
+       aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
+       aiocbp.aio_sigevent.sigev_value.sival_int = size;
+    }
+#endif
+
+    /*
+     * Determine the system call that will be called and produce
+     * the string of the system call and place it in Lio_SysCall.
+     * Also update the io_type char pointer to give brief description
+     * of system call.  Execute the system call and check for
+     * system call failure.  If sync i/o, return the number of
+     * bytes written/read.
+     */
+     
+    if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
+       /*
+        * write(2) is used if LIO_IO_SYNC bit is set or not none
+         * of the LIO_IO_TYPES bits are set (default).
+         */
+
+       sprintf(Lio_SysCall,
+           "write(%d, buf, %d)", fd, size);
+       io_type="write";
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       if ((ret = write(fd, buffer, size)) == -1) {
+           sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
+               __FILE__, __LINE__,
+               fd, size, errno, strerror(errno));
+           return -errno;
+       }
+
+       if ( ret != size ) {
+            sprintf(Errormsg,
+               "%s/%d write(%d, buf, %d) returned=%d",
+                   __FILE__, __LINE__,
+                   fd, size, ret);
+        }
+        else if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: write completed without error (ret %d)\n",
+                __FILE__, __LINE__, ret);
+
+        return ret;
+
+    }
+
+    else if ( method & LIO_IO_ASYNC ) {
+#ifdef CRAY
+       sprintf(Lio_SysCall,
+           "writea(%d, buf, %d, &status, %d)", fd, size, sig);
+       io_type="writea";
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       sigoff();
+       if ((ret = writea(fd, buffer, size, &status, sig)) == -1) {
+           sprintf(Errormsg,
+               "%s/%d writea(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
+                   __FILE__, __LINE__,
+               fd, size, sig, errno, strerror(errno));
+           sigon();
+           return -errno;
+       }
+#endif
+#ifdef sgi
+       sprintf(Lio_SysCall,
+           "aio_write(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig);
+       io_type="aio_write";
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       if( sig )
+               sighold( sig );
+       if ((ret = aio_write(&aiocbp)) == -1) {
+           sprintf(Errormsg,
+               "%s/%d aio_write(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
+                   __FILE__, __LINE__,
+               fd, size, sig, errno, strerror(errno));
+           if( sig )
+               sigrelse( sig );
+           return -errno;
+       }
+#endif
+    } /* LIO_IO_ASYNC */
+
+    else if ( method & LIO_IO_SLISTIO ) {
+#ifdef CRAY
+       request.li_opcode = LO_WRITE;
+       request.li_fildes = fd;
+        request.li_buf = buffer;
+        request.li_nbyte = size;
+        request.li_status = &status;
+        request.li_signo = sig;
+        request.li_nstride = 0;
+        request.li_filstride = 0;
+        request.li_memstride = 0;
+
+       listio_cmd=LC_WAIT;
+       io_type="listio(2) sync write";
+
+       sprintf(Lio_SysCall, 
+               "listio(LC_WAIT, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
+                fd, size);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       sigoff();
+       if ( listio(listio_cmd, &request, 1) == -1 ) {
+            sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+                   __FILE__, __LINE__,
+               Lio_SysCall, fd, size, errno, strerror(errno));
+           sigon();
+            return -errno;
+        }
+
+       if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: %s did not return -1\n",
+               __FILE__, __LINE__, Lio_SysCall);
+
+       ret=lio_check_asyncio(io_type, size,  &status);
+       return ret;
+
+#endif
+#ifdef sgi
+
+       aiocbp.aio_lio_opcode = LIO_WRITE;
+       listio_cmd=LIO_WAIT;
+       io_type="lio_listio(3) sync write";
+
+       sprintf(Lio_SysCall,
+               "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d, sig:%d",
+                fd, size, sig );
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       if( sig )
+           sighold( sig );
+       if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
+            sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+                   __FILE__, __LINE__,
+               Lio_SysCall, fd, size, errno, strerror(errno));
+           if( sig )
+               sigrelse( sig );
+            return -errno;
+        }
+
+       if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: %s did not return -1\n",
+               __FILE__, __LINE__, Lio_SysCall);
+
+       ret=lio_check_asyncio(io_type, size,  &aiocbp, method);
+       return ret;
+#endif
+    } /* LIO_IO_SLISTIO */
+
+    else if ( method & LIO_IO_ALISTIO ) {
+#ifdef CRAY
+       request.li_opcode = LO_WRITE;
+       request.li_fildes = fd;
+        request.li_buf = buffer;
+        request.li_nbyte = size;
+        request.li_status = &status;
+        request.li_signo = sig;
+        request.li_nstride = 0;
+        request.li_filstride = 0;
+        request.li_memstride = 0;
+
+       listio_cmd=LC_START;
+       io_type="listio(2) async write";
+
+       sprintf(Lio_SysCall, 
+               "listio(LC_START, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
+                fd, size);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       sigoff();
+       if ( listio(listio_cmd, &request, 1) == -1 ) {
+            sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+                   __FILE__, __LINE__,
+               Lio_SysCall, fd, size, errno, strerror(errno));
+           sigon();
+            return -errno;
+        }
+#endif
+#ifdef sgi
+       aiocbp.aio_lio_opcode = LIO_WRITE;
+       listio_cmd=LIO_NOWAIT;
+       io_type="lio_listio(3) async write";
+
+       sprintf(Lio_SysCall,
+               "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d",
+                fd, size);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       if( sig )
+               sighold( sig );
+       if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
+            sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+                   __FILE__, __LINE__,
+               Lio_SysCall, fd, size, errno, strerror(errno));
+           if( sig )
+               sigrelse( sig );
+            return -errno;
+        }
+#endif
+    }/* LIO_IO_ALISTIO */
+
+#ifndef CRAY
+    else if ( method & LIO_IO_SYNCV ) {
+       io_type="writev(2)";
+
+       sprintf(Lio_SysCall, 
+               "writev(%d, &iov, 1) nbyte:%d", fd, size);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+       if ((ret = writev(fd, &iov, 1)) == -1) {
+           sprintf(Errormsg, "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
+                   __FILE__, __LINE__,
+               fd, size, errno, strerror(errno));
+           return -errno;
+       }
+
+       if ( ret != size ) {
+            sprintf(Errormsg,
+               "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d",
+                   __FILE__, __LINE__,
+                   fd, size, ret);
+        }
+        else if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: writev completed without error (ret %d)\n",
+                __FILE__, __LINE__, ret);
+
+        return ret;
+    } /* LIO_IO_SYNCV */
+#endif
+
+#ifdef sgi
+    else if ( method & LIO_IO_SYNCP ) {
+       io_type="pwrite(2)";
+
+       sprintf(Lio_SysCall, 
+               "pwrite(%d, buf, %d, %lld)", fd, size, poffset);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+       if ((ret = pwrite(fd, buffer, size, poffset)) == -1) {
+           sprintf(Errormsg, "%s/%d pwrite(%d, buf, %d, %lld) ret:-1, errno=%d %s",
+                   __FILE__, __LINE__,
+               fd, size, poffset, errno, strerror(errno));
+           return -errno;
+       }
+
+       if ( ret != size ) {
+            sprintf(Errormsg,
+               "%s/%d pwrite(%d, buf, %d, %lld) returned=%d",
+                   __FILE__, __LINE__,
+                   fd, size, poffset, ret);
+        }
+        else if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: pwrite completed without error (ret %d)\n",
+                __FILE__, __LINE__, ret);
+
+        return ret;
+    } /* LIO_IO_SYNCP */
+#endif
+
+    else {
+       printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
+       return -1;
+    }
+
+    /*
+     * wait for async io to complete.
+     */
+#ifdef CRAY
+    ret=lio_wait4asyncio(method, fd, statptr);
+#endif
+#ifdef sgi
+    ret=lio_wait4asyncio(method, fd, &aiocbp);
+#endif
+
+    /*
+     * If there was an error waiting for async i/o to complete,
+     * return the error value (errno) to the caller.
+     * Note: Errormsg should already have been updated.
+     */
+    if ( ret < 0 ) {
+       return ret;
+    }
+
+    /*
+     * If i/o was not waited for (may not have been completed at this time),
+     * return the size that was requested.
+     */
+    if ( ret == 1 )
+       return size;
+
+    /*
+     * check that async io was successful.
+     * Note:  if the there was an system call failure, -errno
+     * was returned and Errormsg should already have been updated.
+     * If amount i/o was different than size, Errormsg should already 
+     * have been updated but the actual i/o size if returned.
+     */
+    
+#ifdef CRAY
+    ret=lio_check_asyncio(io_type, size, &status);
+#endif
+#ifdef sgi
+    ret=lio_check_asyncio(io_type, size, &aiocbp, method);
+#endif
+
+    return ret;
+}      /* end of lio_write_buffer */
+
+/***********************************************************************
+ * Generic read function 
+ * This function can be used to do a read using read(2), reada(2),
+ * aio_read(3), readv(2), pread(2),
+ * or single stride listio(2)/lio_listio(3).
+ * By setting the desired bits in the method
+ * bitmask, the caller can control the type of read and the wait method
+ * that will be used.  If no io type bits are set, read will be used.
+ *
+ * If async io was attempted and no wait method bits are set then the
+ * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for
+ * aio_read(3) and lio_listio(3).
+ *
+ * If multiple wait methods are specified, 
+ * only one wait method will be used. The order is predetermined.
+ *
+ * If the call specifies a signal and one of the two signal wait methods,
+ * a signal handler for the signal is set.  This will reset an already
+ * set handler for this signal. 
+ *
+ * If the LIO_RANDOM method bit is set, this function will randomly
+ * choose a io type and wait method from bits in the method argument.
+ *
+ * If an error is encountered, an error message will be generated
+ * in a internal static buffer.  If errmsg is not NULL, it will
+ * be updated to point to the static buffer, allowing the caller
+ * to print the error message.
+ *
+ * Return Value
+ *   If a system call fails, -errno is returned.
+ *   If LIO_WAIT_NONE bit is set, the return value is the return value
+ *   of the system call.
+ *   If the io did not fail, the amount of data written is returned.
+ *     If the size the system call say was written is different
+ *     then what was asked to be written, errmsg is updated for
+ *     this error condition.  The return value is still the amount
+ *     the system call says was written.  
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+lio_read_buffer(fd, method, buffer, size, sig, errmsg, wrd)
+int fd;                /* open file descriptor */
+int method;    /* contains io type and wait method bitmask */
+char *buffer;  /* pointer to buffer */
+int size;      /* the size of the io */
+int sig;       /* signal to use if async io */
+char **errmsg; /* char pointer that will be updated to point to err message */
+long wrd;      /* to allow future features, use zero for now */
+{
+    int ret = 0;       /* syscall return or used to get random method */
+    char *io_type;             /* Holds string of type of io */
+#ifndef linux
+    int listio_cmd;            /* Holds the listio/lio_listio cmd */
+    int omethod = method;
+#endif
+#ifdef  CRAY
+    struct listreq request;    /* Used when a listio is wanted */
+    struct iosw status, *statptr[1];  
+#else
+    /* for linux or sgi */
+    struct iovec iov; /* iovec for readv(2) */
+#endif
+#ifdef sgi
+    aiocb_t aiocbp;    /* POSIX aio control block */
+    aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
+    off64_t poffset;   /* pread(2) offset */
+#endif
+
+    /*
+     * If LIO_RANDOM bit specified, get new method randomly.
+     */
+    if ( method & LIO_RANDOM ) {
+       if( Debug_level > 3 )
+               printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
+       method = lio_random_methods(method);
+       if ( Debug_level > 2 )
+           printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
+    }
+
+    if ( errmsg != NULL )
+       *errmsg = Errormsg;
+
+    Rec_signal=Received_signal;        /* get the current number of signals received */
+#ifdef sgi
+    Rec_callback=Received_callback;    /* get the current number of callbacks received */
+#endif
+
+#ifdef  CRAY
+    bzero(&status, sizeof(struct iosw));
+    bzero(&request, sizeof(struct listreq));
+    statptr[0] = &status;
+#else
+    /* for linux or sgi */
+    bzero(&iov, sizeof(struct iovec));
+    iov.iov_base = buffer;
+    iov.iov_len = size;
+#endif
+#ifdef sgi
+    bzero(&aiocbp, sizeof(aiocb_t));
+    aiocbp.aio_fildes = fd;
+    aiocbp.aio_nbytes = size;
+    aiocbp.aio_buf = buffer;
+/*    aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
+    aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
+    aiocbp.aio_sigevent.sigev_signo = 0;
+    aiocbp.aio_sigevent.sigev_func = NULL;
+    aiocbp.aio_sigevent.sigev_value.sival_int = 0;
+    aiolist[0] = &aiocbp;
+
+    if( (ret = lseek( fd, 0, SEEK_CUR )) == -1 ){
+       ret = 0;
+       /* If there is an error and it is not ESPIPE then kick out the error.
+        * If the fd is a fifo then we have to make sure that
+        * lio_random_methods() didn't select pwrite/pread; if it did then
+        * switch to write/read.
+        */
+       if( errno == ESPIPE ){
+               if( method & LIO_IO_SYNCP ){
+                       if( omethod & LIO_RANDOM ){
+                               method &= ~LIO_IO_SYNCP;
+                               method |= LIO_IO_SYNC;
+                               if( Debug_level > 2 )
+                                       printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method );
+                       }
+                       else if( Debug_level ){
+                               printf("DEBUG %s/%d: pread will fail when it reads from a fifo\n",
+                                      __FILE__, __LINE__ );
+                       }
+               }
+               /* else: let it ride */
+       }
+       else{
+               sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d  %s",
+                       __FILE__, __LINE__, fd, errno, strerror(errno));
+               return -errno;
+       }
+    }
+    poffset = (off64_t)ret;
+    aiocbp.aio_offset = ret;
+
+#endif
+
+    /*
+     * If the LIO_USE_SIGNAL bit is not set, only use the signal
+     * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set.
+     * Otherwise there is not necessarily a signal handler to trap
+     * the signal.
+     */
+    if ( sig && !(method & LIO_USE_SIGNAL) &&
+        ! (method & LIO_WAIT_SIGTYPES) ){
+
+        sig=0;  /* ignore signal parameter */
+    }
+
+#ifdef sgi
+    if ( sig && (method & LIO_WAIT_CBTYPES) )
+       sig=0; /* ignore signal parameter */
+#endif
+
+    /*
+     * only setup signal hander if sig was specified and
+     * a sig wait method was specified.
+     * Doing this will change the handler for this signal.  The
+     * old signal handler will not be restored.
+     *** restoring the signal handler could be added ***
+     */
+
+    if ( sig &&  (method & LIO_WAIT_SIGTYPES) ){
+#ifdef CRAY
+           sigctl(SCTL_REG, sig, lio_async_signal_handler);
+#endif
+#ifdef sgi
+           aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+           aiocbp.aio_sigevent.sigev_signo = sig;
+           sigset(sig, lio_async_signal_handler);
+#endif /* CRAY */
+    }
+#ifdef sgi
+    else if( method & LIO_WAIT_CBTYPES ){
+           aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
+           aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
+           /* sival_int just has to be something that I can use
+            * to identify the callback, and "size" happens to be handy...
+            */
+           aiocbp.aio_sigevent.sigev_value.sival_int = size;
+    }
+#endif
+
+    /*
+     * Determine the system call that will be called and produce
+     * the string of the system call and place it in Lio_SysCall.
+     * Also update the io_type char pointer to give brief description
+     * of system call.  Execute the system call and check for
+     * system call failure.  If sync i/o, return the number of
+     * bytes written/read.
+     */
+     
+    if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
+       /*
+        * read(2) is used if LIO_IO_SYNC bit is set or not none
+         * of the LIO_IO_TYPES bits are set (default).
+         */
+
+       sprintf(Lio_SysCall,
+           "read(%d, buf, %d)", fd, size);
+       io_type="read";
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       if ((ret = read(fd, buffer, size)) == -1) {
+           sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
+                   __FILE__, __LINE__,
+               fd, size, errno, strerror(errno));
+           return -errno;
+       }
+
+       if ( ret != size ) {
+            sprintf(Errormsg,
+               "%s/%d read(%d, buf, %d) returned=%d",
+                   __FILE__, __LINE__,
+                   fd, size, ret);
+        }
+        else if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: read completed without error (ret %d)\n",
+                __FILE__, __LINE__, ret);
+
+        return ret;
+
+    }
+
+    else if ( method & LIO_IO_ASYNC ) {
+#ifdef CRAY
+       sprintf(Lio_SysCall,
+           "reada(%d, buf, %d, &status, %d)", fd, size, sig);
+       io_type="reada";
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       sigoff();
+       if ((ret = reada(fd, buffer, size, &status, sig)) == -1) {
+           sprintf(Errormsg,
+               "%s/%d reada(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
+                   __FILE__, __LINE__,
+               fd, size, sig, errno, strerror(errno));
+           sigon();
+           return -errno;
+       }
+#endif
+#ifdef sgi
+       sprintf(Lio_SysCall,
+           "aio_read(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig);
+       io_type="aio_read";
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       if( sig )
+               sighold( sig );
+       if ((ret = aio_read(&aiocbp)) == -1) {
+           sprintf(Errormsg,
+               "%s/%d aio_read(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
+                   __FILE__, __LINE__,
+               fd, size, sig, errno, strerror(errno));
+           if( sig )
+               sigrelse( sig );
+           return -errno;
+       }
+#endif
+    } /* LIO_IO_ASYNC */
+
+    else if ( method & LIO_IO_SLISTIO ) {
+#ifdef CRAY
+       request.li_opcode = LO_READ;
+       request.li_fildes = fd;
+        request.li_buf = buffer;
+        request.li_nbyte = size;
+        request.li_status = &status;
+        request.li_signo = sig;
+        request.li_nstride = 0;
+        request.li_filstride = 0;
+        request.li_memstride = 0;
+
+       listio_cmd=LC_WAIT;
+       io_type="listio(2) sync read";
+
+       sprintf(Lio_SysCall, 
+               "listio(LC_WAIT, &req, 1) LO_READ, fd:%d, nbyte:%d",
+                fd, size);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       sigoff();
+       if ( listio(listio_cmd, &request, 1) == -1 ) {
+            sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+                   __FILE__, __LINE__,
+               Lio_SysCall, fd, size, errno, strerror(errno));
+           sigon();
+            return -errno;
+        }
+
+       if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: %s did not return -1\n",
+               __FILE__, __LINE__, Lio_SysCall);
+
+       ret=lio_check_asyncio(io_type, size,  &status);
+       return ret;
+#endif
+#ifdef sgi
+       aiocbp.aio_lio_opcode = LIO_READ;
+       listio_cmd=LIO_WAIT;
+       io_type="lio_listio(3) sync read";
+
+       sprintf(Lio_SysCall, 
+               "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
+                fd, size);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       if( sig )
+               sighold( sig );
+       if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
+            sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+                   __FILE__, __LINE__,
+               Lio_SysCall, fd, size, errno, strerror(errno));
+           if( sig )
+               sigrelse( sig );
+            return -errno;
+        }
+
+       if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: %s did not return -1\n",
+               __FILE__, __LINE__, Lio_SysCall);
+
+       ret=lio_check_asyncio(io_type, size,  &aiocbp, method);
+       return ret;
+#endif
+    }/* LIO_IO_SLISTIO */
+
+    else if ( method & LIO_IO_ALISTIO ) {
+#ifdef CRAY
+       request.li_opcode = LO_READ;
+       request.li_fildes = fd;
+        request.li_buf = buffer;
+        request.li_nbyte = size;
+        request.li_status = &status;
+        request.li_signo = sig;
+        request.li_nstride = 0;
+        request.li_filstride = 0;
+        request.li_memstride = 0;
+
+       listio_cmd=LC_START;
+       io_type="listio(2) async read";
+
+       sprintf(Lio_SysCall, 
+               "listio(LC_START, &req, 1) LO_READ, fd:%d, nbyte:%d",
+                fd, size);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       sigoff();
+       if ( listio(listio_cmd, &request, 1) == -1 ) {
+            sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+                   __FILE__, __LINE__,
+               Lio_SysCall, fd, size, errno, strerror(errno));
+           sigon();
+            return -errno;
+        }
+#endif
+#ifdef sgi
+       aiocbp.aio_lio_opcode = LIO_READ;
+       listio_cmd=LIO_NOWAIT;
+       io_type="lio_listio(3) async read";
+
+       sprintf(Lio_SysCall, 
+               "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
+                fd, size);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+
+       if( sig )
+               sighold( sig );
+       if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
+            sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+                   __FILE__, __LINE__,
+               Lio_SysCall, fd, size, errno, strerror(errno));
+           if( sig )
+               sigrelse( sig );
+            return -errno;
+        }
+#endif
+    } /* LIO_IO_ALISTIO */
+
+#ifndef CRAY
+    else if ( method & LIO_IO_SYNCV ) {
+       io_type="readv(2)";
+
+       sprintf(Lio_SysCall, 
+               "readv(%d, &iov, 1) nbyte:%d", fd, size);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+       if ((ret = readv(fd, &iov, 1)) == -1) {
+           sprintf(Errormsg, "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
+                   __FILE__, __LINE__,
+               fd, size, errno, strerror(errno));
+           return -errno;
+       }
+
+       if ( ret != size ) {
+            sprintf(Errormsg,
+               "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d",
+                   __FILE__, __LINE__,
+                   fd, size, ret);
+        }
+        else if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: readv completed without error (ret %d)\n",
+                __FILE__, __LINE__, ret);
+
+        return ret;
+    } /* LIO_IO_SYNCV */
+#endif
+
+#ifdef sgi
+    else if ( method & LIO_IO_SYNCP ) {
+       io_type="pread(2)";
+
+       sprintf(Lio_SysCall, 
+               "pread(%d, buf, %d, %lld)", fd, size, poffset);
+
+        if ( Debug_level ) {
+           printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+        }
+       if ((ret = pread(fd, buffer, size, poffset)) == -1) {
+           sprintf(Errormsg, "%s/%d pread(%d, buf, %d, %lld) ret:-1, errno=%d %s",
+                   __FILE__, __LINE__,
+               fd, size, poffset, errno, strerror(errno));
+           return -errno;
+       }
+
+       if ( ret != size ) {
+            sprintf(Errormsg,
+               "%s/%d pread(%d, buf, %d, %lld) returned=%d",
+                   __FILE__, __LINE__,
+                   fd, size, poffset, ret);
+        }
+        else if ( Debug_level > 1 )
+            printf("DEBUG %s/%d: pread completed without error (ret %d)\n",
+                __FILE__, __LINE__, ret);
+
+        return ret;
+    } /* LIO_IO_SYNCP */
+#endif
+
+    else {
+       printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
+       return -1;
+    }
+
+    /*
+     * wait for async io to complete.
+     * Note: Sync io should have returned prior to getting here.
+     */
+#ifdef CRAY
+    ret=lio_wait4asyncio(method, fd, statptr);
+#endif
+#ifdef sgi
+    ret=lio_wait4asyncio(method, fd, &aiocbp);
+#endif
+
+    /*
+     * If there was an error waiting for async i/o to complete,
+     * return the error value (errno) to the caller.
+     * Note: Errormsg should already have been updated.
+     */
+    if ( ret < 0 ) {
+       return ret;
+    }
+
+    /*
+     * If i/o was not waited for (may not have been completed at this time),
+     * return the size that was requested.
+     */
+    if ( ret == 1 )
+       return size;
+
+    /*
+     * check that async io was successful.
+     * Note:  if the there was an system call failure, -errno
+     * was returned and Errormsg should already have been updated.
+     * If amount i/o was different than size, Errormsg should already 
+     * have been updated but the actual i/o size if returned.
+     */
+    
+#ifdef CRAY
+    ret=lio_check_asyncio(io_type, size, &status);
+#endif
+#ifdef sgi
+    ret=lio_check_asyncio(io_type, size, &aiocbp, method);
+#endif
+
+    return ret;
+}      /* end of lio_read_buffer */
+
+
+#ifndef linux
+/***********************************************************************
+ * This function will check that async io was successful.
+ * It can also be used to check sync listio since it uses the
+ * same method.
+ *
+ * Return Values
+ *  If status.sw_error is set, -status.sw_error is returned.
+ *  Otherwise sw_count's field value is returned.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+#ifdef CRAY
+lio_check_asyncio(char *io_type, int size, struct iosw *status)
+#else
+lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
+#endif
+{
+    int ret;
+
+#ifdef CRAY
+    if ( status->sw_error ) {
+        sprintf(Errormsg,
+            "%s/%d %s, sw_error set = %d %s, sw_count = %d",
+               __FILE__, __LINE__, io_type,
+            status->sw_error, strerror(status->sw_error), status->sw_count);
+        return -status->sw_error;
+    }
+    else if ( status->sw_count != size ) {
+        sprintf(Errormsg,
+            "%s/%d %s, sw_count not as expected(%d), but actual:%d",
+               __FILE__, __LINE__, io_type,
+            size, status->sw_count);
+    }
+    else if ( Debug_level > 1 ) {
+        printf("DEBUG %s/%d: %s completed without error (sw_error == 0, sw_count == %d)\n",
+            __FILE__, __LINE__, io_type, status->sw_count);
+    }
+
+    return status->sw_count;
+
+#else
+
+    int cnt = 1;
+
+    /* The I/O may have been synchronous with signal completion.  It doesn't
+     * make sense, but the combination could be generated.  Release the
+     * completion signal here otherwise it'll hang around and bite us
+     * later.
+     */
+    if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
+       sigrelse( aiocbp->aio_sigevent.sigev_signo );
+
+    ret = aio_error( aiocbp );
+
+    while( ret == EINPROGRESS ){
+       ret = aio_error( aiocbp );
+       ++cnt;
+    }
+    if( cnt > 1 ){
+       sprintf(Errormsg,
+               "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s",
+               __FILE__, __LINE__, io_type, cnt, method,
+               (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
+                aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
+                aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
+                "unknown") );
+       return -ret;
+    }
+
+    if( ret != 0 ){
+       sprintf(Errormsg,
+               "%s/%d %s, aio_error = %d %s; random method %#o",
+               __FILE__, __LINE__, io_type,
+               ret, strerror(ret),
+               method );
+       return -ret;
+    }
+    ret = aio_return( aiocbp );
+    if( ret != size ){
+       sprintf(Errormsg,
+               "%s/%d %s, aio_return not as expected(%d), but actual:%d",
+               __FILE__, __LINE__, io_type,
+               size, ret);
+
+#ifdef BUG1_workaround
+       if( ret == 0 ){
+               ret = size;
+               if( Debug_level > 1 ){
+                       printf("WARN %s/%d: %s completed with bug1_workaround (aio_error == 0, aio_return now == %d)\n",
+                              __FILE__, __LINE__, io_type, ret);
+               }
+       }
+#endif /* BUG1_workaround */
+
+    }
+    else if( Debug_level > 1 ){
+        printf("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n",
+            __FILE__, __LINE__, io_type, ret);
+    }
+
+    return ret;
+
+#endif
+
+} /* end of lio_check_asyncio */
+
+
+/***********************************************************************
+ *
+ * This function will wait for async io to complete.
+ * If multiple wait methods are specified, the order is predetermined
+ * to LIO_WAIT_RECALL,
+ * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE,
+ * then LIO_WAIT_NONE.
+ *
+ * If no wait method was specified the default wait method is: recall(2)
+ * or aio_suspend(3), as appropriate.
+ *
+ * Return Values
+ *     <0: errno of failed recall
+ *     0 : async io was completed
+ *     1 : async was not waited for, io may not have completed.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+#ifdef CRAY
+lio_wait4asyncio(int method, int fd, struct iosw **statptr)
+#else
+lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
+#endif
+{
+    int cnt;
+#ifdef sgi
+    int ret;
+    const aiocb_t *aioary[1]; 
+#endif
+
+    if ( (method & LIO_WAIT_RECALL)
+#ifdef sgi
+       || (method & LIO_WAIT_CBSUSPEND) 
+       || (method & LIO_WAIT_SIGSUSPEND) 
+#endif
+       || ((method & LIO_WAIT_TYPES) == 0) ){
+       /*
+        * If method has LIO_WAIT_RECALL bit set or method does
+        * not have any wait method bits set (default), use recall/aio_suspend.
+         */
+#ifdef CRAY
+        if ( Debug_level > 2 )
+            printf("DEBUG %s/%d: wait method : recall\n", __FILE__, __LINE__);
+        sigon();
+        if ( recall(fd, 1, statptr) ) {
+           sprintf(Errormsg, "%s/%d recall(%d, 1, stat) failed, errno:%d %s",
+                   __FILE__, __LINE__,
+               fd, errno, strerror(errno));
+           return -errno;
+       }
+#else
+        if ( Debug_level > 2 )
+            printf("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n", __FILE__, __LINE__,
+               (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
+                aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
+                aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
+                "unknown") );
+
+       aioary[0] = aiocbp;
+       ret = aio_suspend( aioary, 1, NULL );
+       if( (ret == -1) && (errno == EINTR) ){
+               if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ){
+                       if( Debug_level > 2 ){
+                               printf("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n",
+                                      __FILE__, __LINE__ );
+                       }
+               }
+               else {
+                       sprintf(Errormsg, "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n",
+                               __FILE__, __LINE__,
+                               (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
+                                aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
+                                aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
+                                "unknown") );
+                       return -errno;
+               }
+       }
+       else if ( ret ) {
+           sprintf(Errormsg, "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s",
+                   __FILE__, __LINE__,
+               fd, errno, strerror(errno));
+           return -errno;
+       }
+#endif
+
+    } else if ( method & LIO_WAIT_ACTIVE ) {
+        if ( Debug_level > 2 )
+            printf("DEBUG %s/%d: wait method : active\n", __FILE__, __LINE__);
+#ifdef CRAY
+        sigon();
+       /* 
+         * loop until sw_flag, sw_count or sw_error field elements
+        * change to non-zero.
+        */
+        cnt=0;
+        while ( (*statptr)->sw_flag == 0 && 
+               (*statptr)->sw_count == 0 &&
+               (*statptr)->sw_error == 0 ) {
+          cnt++;
+       }
+#else
+       /* loop while aio_error() returns EINPROGRESS */
+       cnt=0;
+       while(1){
+               ret = aio_error( aiocbp );
+               if( (ret == 0) || (ret != EINPROGRESS) ){
+                       break;
+               }
+               ++cnt;
+       }
+
+#endif
+       if ( Debug_level > 5 && cnt && (cnt % 50) == 0 )
+               printf("DEBUG %s/%d: wait active cnt = %d\n",
+                   __FILE__, __LINE__, cnt);
+
+    } else if ( method & LIO_WAIT_SIGPAUSE ) {
+        if ( Debug_level > 2 )
+            printf("DEBUG %s/%d: wait method : sigpause\n", __FILE__, __LINE__);
+#ifdef sgi
+       /* note: don't do the sigon() for CRAY in this case.  why? -- roehrich 6/11/97 */
+       if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
+               sigrelse( aiocbp->aio_sigevent.sigev_signo );
+       else {
+               printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
+               return -1;
+       }
+#endif
+        pause();
+
+    } else if ( method & LIO_WAIT_SIGACTIVE ) {
+        if ( Debug_level > 2 )
+            printf("DEBUG %s/%d: wait method : sigactive\n", __FILE__, __LINE__);
+#ifdef CRAY
+        sigon();
+#else
+       if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
+               sigrelse( aiocbp->aio_sigevent.sigev_signo );
+       else {
+               printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
+               return -1;
+       }
+#endif
+       /* loop waiting for signal */
+        while ( Received_signal == Rec_signal ){
+#ifdef CRAY
+                sigon();
+#else
+               sigrelse( aiocbp->aio_sigevent.sigev_signo );
+#endif
+       }
+
+    } else if ( method & LIO_WAIT_NONE ) {
+        if ( Debug_level > 2 )
+            printf("DEBUG %s/%d: wait method : none\n", __FILE__, __LINE__);
+       /* It's broken because the aiocb/iosw is an automatic variable in
+        * lio_{read,write}_buffer, so when the function returns and the
+        * I/O completes there will be nowhere to write the I/O status.
+        * It doesn't cause a problem on unicos--probably because of some
+        * compiler quirk, or an accident.  It causes POSIX async I/O
+        * to core dump some threads.   spr/pv 705909.  6/27/97 roehrich
+        */
+       sprintf(Errormsg, "%s/%d LIO_WAIT_NONE was selected (this is broken)\n",
+               __FILE__, __LINE__ );
+#ifdef CRAY
+        sigon();
+#endif
+/*        return 1;*/
+        return -1;
+    }
+    else {
+       if( Debug_level > 2 )
+           printf("DEBUG %s/%d: no wait method was chosen\n", __FILE__, __LINE__ );
+       return -1;
+    }
+
+    return 0;
+
+} /* end of lio_wait4asyncio */
+
+#endif /* ifndef linux */
+
+#if UNIT_TEST
+/***********************************************************************
+ * The following code is provided as unit test.
+ * Just define add "-DUNIT_TEST=1" to the cc line.
+ * 
+ * (rrl 04/96)
+ ***********************************************************************/
+struct unit_info_t {
+    int method;
+    int sig;
+    char *str;
+}  Unit_info[] = {
+    { LIO_IO_SYNC, 0, "sync io" },
+    { LIO_IO_SYNCV, 0, "sync readv/writev" },
+    { LIO_IO_SYNCP, 0, "sync pread/pwrite" },
+    { LIO_IO_ASYNC, 0, "async io, def wait" },
+    { LIO_IO_SLISTIO,     0, "sync listio" },
+    { LIO_IO_ALISTIO,     0, "async listio, def wait" },
+    { LIO_IO_ASYNC|LIO_WAIT_ACTIVE,    0, "async active" },
+    { LIO_IO_ASYNC|LIO_WAIT_RECALL,    0, "async recall/suspend" },
+    { LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE,  SIGUSR1, "async sigpause" },
+    { LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE,         SIGUSR1, "async sigactive" },
+    { LIO_IO_ALISTIO|LIO_WAIT_ACTIVE,     0, "async listio active" },
+    { LIO_IO_ALISTIO|LIO_WAIT_RECALL,     0, "async listio recall" },
+    { LIO_IO_ALISTIO|LIO_WAIT_SIGACTIVE,  SIGUSR1, "async listio sigactive" },
+    { LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE,  SIGUSR1, "async listio sigpause" },
+    { LIO_IO_ASYNC,    SIGUSR2, "async io, def wait, sigusr2" },
+    { LIO_IO_ALISTIO,   SIGUSR2, "async listio, def wait, sigusr2" },
+};
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+    extern char *optarg;
+    extern int optind;
+
+    int fd;
+    char *err;
+    char buffer[4096];
+    int size=4096;
+    int ret;
+    int ind;
+    int iter=3;
+    int method;
+    int exit_status = 0;
+    int c;
+    int i;
+    char *symbols = NULL;
+    int die_on_err = 0;
+
+    while( (c = getopt(argc,argv,"s:di:")) != -1 ){
+       switch(c){
+       case 's': symbols = optarg; break;
+       case 'd': ++die_on_err; break;
+       case 'i': iter = atoi(optarg); break;
+       }
+    }
+
+    if ((fd=open("unit_test_file", O_CREAT|O_RDWR|O_TRUNC, 0777)) == -1 ) {
+       perror("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed");
+       exit(1);
+    }
+
+    Debug_level=9;
+
+    if ( symbols != NULL ) {
+        if ( (method=lio_parse_io_arg2(symbols,  &err)) == -1 ){
+           printf("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n",
+           symbols, err);
+           if( die_on_err )
+               exit(1);
+       }
+       else
+           printf("lio_parse_io_arg2(%s, &err) returned %#o\n", symbols, method);
+
+       exit_status = 0;
+        for(ind=0; ind < iter; ind++ ) {
+         memset( buffer, 'A', 4096 );
+         if( lseek(fd, 0, 0) == -1 ){
+               printf("lseek(fd,0,0), %d, failed, errno %d\n",
+                      __LINE__, errno );
+               ++exit_status;
+         }
+          if ((ret=lio_write_buffer(fd, method, buffer,
+                        size, SIGUSR1, &err, 0)) != size ) {
+            printf("lio_write_buffer returned -1, err = %s\n", err);
+          } else
+            printf("lio_write_buffer returned %d\n", ret);
+
+         memset( buffer, 'B', 4096 );
+          if( lseek(fd, 0, 0) == -1 ){
+               printf("lseek(fd,0,0), %d, failed, errno %d\n",
+                      __LINE__, errno );
+               ++exit_status;
+         }
+          if ((ret=lio_read_buffer(fd, method, buffer,
+                        size, SIGUSR2, &err, 0)) != size ) {
+            printf("lio_read_buffer returned -1, err = %s\n", err);
+          } else
+            printf("lio_read_buffer returned %d\n", ret);
+
+         for( i = 0; i < 4096; ++i ){
+               if( buffer[i] != 'A' ){
+                       printf("  buffer[%d] = %d\n", i, buffer[i] );
+                       ++exit_status;
+                       break;
+               }
+         }
+
+         if( exit_status )
+               exit(exit_status);
+
+       }
+
+        unlink("unit_test_file");
+       exit(0);
+    }
+
+    for(ind=0; ind < sizeof(Unit_info)/sizeof(struct unit_info_t); ind++ ) {
+
+       printf("\n********* write %s ***************\n", Unit_info[ind].str);
+       if( lseek(fd, 0, 0) == -1 ){
+               printf("lseek(fd,0,0), %d, failed, errno %d\n",
+                      __LINE__, errno );
+               ++exit_status;
+       }
+
+       memset( buffer, 'A', 4096 );
+        if ((ret=lio_write_buffer(fd, Unit_info[ind].method, buffer,
+                       size, Unit_info[ind].sig, &err, 0)) != size ) {
+           printf(">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
+                  Unit_info[ind].method, size, Unit_info[ind].sig, err);
+           ++exit_status;
+           if( die_on_err )
+               exit(exit_status);
+        } else{
+           printf("lio_write_buffer returned %d\n", ret);
+       }
+
+       printf("\n********* read %s ***************\n", Unit_info[ind].str);
+       if( lseek(fd, 0, 0) == -1 ){
+               printf("lseek(fd,0,0), %d, failed, errno %d\n",
+                      __LINE__, errno );
+               ++exit_status;
+       }
+       memset( buffer, 'B', 4096 );
+        if ((ret=lio_read_buffer(fd, Unit_info[ind].method, buffer,
+                       size, Unit_info[ind].sig, &err, 0)) != size ) {
+           printf(">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
+                  Unit_info[ind].method, size, Unit_info[ind].sig, err);
+           ++exit_status;
+           if( die_on_err )
+               exit(exit_status);
+        } else {
+           printf("lio_read_buffer returned %d\n", ret);
+       }
+
+         for( i = 0; i < 4096; ++i ){
+               if( buffer[i] != 'A' ){
+                       printf("  buffer[%d] = %d\n", i, buffer[i] );
+                       ++exit_status;
+                       if( die_on_err )
+                               exit(exit_status);
+                       break;
+               }
+         }
+
+       fflush(stdout);
+       fflush(stderr);
+       sleep(1);
+
+    }
+
+    unlink("unit_test_file");
+
+    exit(exit_status);
+}
+#endif
diff --git a/lib/write_log.c b/lib/write_log.c
new file mode 100644 (file)
index 0000000..851ab65
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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 module contains code for logging writes to files, and for
+ * perusing the resultant logfile.  The main intent of all this is
+ * to provide a 'write history' of a file which can be examined to
+ * judge the state of a file (ie. whether it is corrupted or not) based
+ * on the write activity.
+ *
+ * The main abstractions available to the user are the wlog_file, and
+ * the wlog_rec.  A wlog_file is a handle encapsulating a write logfile.
+ * It is initialized with the wlog_open() function.  This handle is
+ * then passed to the various wlog_xxx() functions to provide transparent
+ * access to the write logfile.
+ *
+ * The wlog_rec datatype is a structure which contains all the information
+ * about a file write.  Examples include the file name, offset, length,
+ * pattern, etc.  In addition there is a bit which is cleared/set based
+ * on whether or not the write has been confirmed as complete.  This 
+ * allows the write logfile to contain information on writes which have
+ * been initiated, but not yet completed (as in async io).
+ *
+ * There is also a function to scan a write logfile in reverse order.
+ *
+ * NOTE:       For target file analysis based on a write logfile, the
+ *             assumption is made that the file being written to is
+ *             locked from simultaneous access, so that the order of
+ *             write completion is predictable.  This is an issue when
+ *             more than 1 process is trying to write data to the same
+ *             target file simultaneously.
+ *
+ * The history file created is a collection of variable length records
+ * described by scruct wlog_rec_disk in write_log.h.  See that module for
+ * the layout of the data on disk.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "write_log.h"
+
+#ifndef BSIZE
+#ifdef linux
+#define BSIZE DEV_BSIZE
+#else
+#define BSIZE BBSIZE
+#endif
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX          255
+/*#define PATH_MAX pathconf("/", _PC_PATH_MAX)*/
+#endif
+
+char   Wlog_Error_String[256];
+
+#if __STDC__
+static int     wlog_rec_pack(struct wlog_rec *wrec, char *buf, int flag);
+static int     wlog_rec_unpack(struct wlog_rec *wrec, char *buf);
+#else
+static int     wlog_rec_pack();
+static int     wlog_rec_unpack();
+#endif
+
+/*
+ * Initialize a write logfile.  wfile is a wlog_file structure that has
+ * the w_file field filled in.  The rest of the information in the
+ * structure is initialized by the routine.
+ *
+ * The trunc flag is used to indicate whether or not the logfile should
+ * be truncated if it currently exists.  If it is non-zero, the file will
+ * be truncated, otherwise it will be appended to.
+ *
+ * The mode argument is the [absolute] mode which the file will be
+ * given if it does not exist.  This mode is not affected by your process
+ * umask.
+ */
+
+int
+wlog_open(wfile, trunc, mode)
+struct wlog_file       *wfile;
+int                    trunc;
+int                    mode;
+{
+       int     omask, oflags;
+
+       if (trunc)
+               trunc = O_TRUNC;
+
+       omask = umask(0);
+
+       /*
+        * Open 1 file descriptor as O_APPEND
+        */
+
+       oflags = O_WRONLY | O_APPEND | O_CREAT | trunc;
+       wfile->w_afd =
+               open(wfile->w_file, oflags, mode);
+       umask(omask);
+
+       if (wfile->w_afd == -1) {
+               sprintf(Wlog_Error_String,
+                       "Could not open write_log - open(%s, %#o, %#o) failed:  %s\n",
+                       wfile->w_file, oflags, mode, strerror(errno));
+               return -1;
+       }
+
+       /*
+        * Open the next fd as a random access descriptor
+        */
+
+       oflags = O_RDWR;
+       if ((wfile->w_rfd = open(wfile->w_file, oflags)) == -1) {
+               sprintf(Wlog_Error_String,
+                       "Could not open write log - open(%s, %#o) failed:  %s\n",
+                       wfile->w_file, oflags, strerror(errno));
+               close(wfile->w_afd);
+               wfile->w_afd = -1;
+               return -1;
+       }
+    
+       return 0;
+}
+
+/*
+ * Release all resources associated with a wlog_file structure allocated
+ * with the wlog_open() call.
+ */
+
+int
+wlog_close(wfile)
+struct wlog_file       *wfile;
+{
+       close(wfile->w_afd);
+       close(wfile->w_rfd);
+       return 0;
+}
+
+/*
+ * Write a wlog_rec structure to a write logfile.  Offset is used to
+ * control where the record will be written.  If offset is < 0, the
+ * record will be appended to the end of the logfile.  Otherwise, the
+ * record which exists at the indicated offset will be overlayed.  This
+ * is so that we can record writes which are outstanding (with the w_done
+ * bit in wrec cleared), but not completed, and then later update the
+ * logfile when the write request completes (as with async io).  When
+ * offset is >= 0, only the fixed length portion of the record is 
+ * rewritten.  See text in write_log.h for details on the format of an
+ * on-disk record.
+ * 
+ * The return value of the function is the byte offset in the logfile
+ * where the record begins.
+ *
+ * Note:  It is the callers responsibility to make sure that the offset
+ * parameter 'points' to a valid record location when a record is to be
+ * overlayed.  This is guarenteed by saving the return value of a previous
+ * call to wlog_record_write() which wrote the record to be overlayed.
+ *
+ * Note2:  The on-disk version of the wlog_rec is MUCH different than
+ * the user version.  Don't expect to od the logfile and see data formatted
+ * as it is in the wlog_rec structure.  Considerable data packing takes
+ * place before the record is written.
+ */
+
+int
+wlog_record_write(wfile, wrec, offset)
+struct wlog_file       *wfile;
+struct wlog_rec                *wrec;
+long                   offset;
+{
+    int                reclen;
+    char       wbuf[WLOG_REC_MAX_SIZE + 2];
+
+    /*
+     * If offset is -1, we append the record at the end of file
+     *
+     * Otherwise, we overlay wrec at the file offset indicated and assume
+     * that the caller passed us the correct offset.  We do not record the
+     * fname in this case.
+     */
+
+    reclen = wlog_rec_pack(wrec, wbuf, (offset < 0));
+
+    if (offset < 0) {
+       /*
+        * Since we're writing a complete new record, we must also tack
+        * its length onto the end so that wlog_scan_backward() will work.
+        * Length is asumed to fit into 2 bytes.
+        */
+           
+           wbuf[reclen] = reclen / 256;
+           wbuf[reclen+1] = reclen % 256;
+           reclen += 2;
+
+           write(wfile->w_afd, wbuf, reclen);
+           offset = lseek(wfile->w_afd, 0, SEEK_CUR) - reclen;
+    } else {
+           lseek(wfile->w_rfd, offset, SEEK_SET);
+           write(wfile->w_rfd, wbuf, reclen);
+    }
+    
+    return offset;
+}
+
+/*
+ * Function to scan a logfile in reverse order.  Wfile is a valid
+ * wlog_file structure initialized by wlog_open().  nrecs is the number
+ * of records to scan (all records are scanned if nrecs is 0).  func is
+ * a user-supplied function to call for each record found.  The function
+ * will be passed a single parameter - a wlog_rec structure .
+ */
+
+int
+wlog_scan_backward(wfile, nrecs, func, data)
+struct wlog_file       *wfile;
+int                    nrecs;
+int                    (*func)();
+long                   data;
+{
+       int                     fd, leftover, nbytes, offset, recnum, reclen, rval;
+       char                    buf[BSIZE*32], *bufend, *cp, *bufstart;
+       char            albuf[WLOG_REC_MAX_SIZE];
+       struct wlog_rec wrec;
+
+       fd = wfile->w_rfd;
+
+       /*
+        * Move to EOF.  offset will always hold the current file offset
+        */
+
+       lseek(fd, 0, SEEK_END);
+       offset = lseek(fd, 0, SEEK_CUR);
+
+       bufend = buf + sizeof(buf);
+       bufstart = buf;
+
+       recnum = 0;
+       leftover = 0;
+       while ((!nrecs || recnum < nrecs) && offset > 0) {
+               /*
+                * Check for beginning of file - if there aren't enough bytes
+                * remaining to fill buf, adjust bufstart.
+                */
+
+               if (offset + leftover < sizeof(buf)) {
+                       bufstart = bufend - (offset + leftover);
+                       offset = 0;
+               } else {
+                       offset -= sizeof(buf) - leftover;
+               }
+
+               /* 
+                * Move to the proper file offset, and read into buf
+                */
+
+               lseek(fd, offset, SEEK_SET);
+               nbytes = read(fd, bufstart, bufend - bufstart - leftover);
+
+               if (nbytes == -1) {
+                       sprintf(Wlog_Error_String,
+                               "Could not read history file at offset %d - read(%d, %p, %d) failed:  %s\n",
+                               offset, fd, bufstart,
+                               (int)(bufend - bufstart - leftover), strerror(errno));
+                       return -1;
+               }
+
+               cp = bufend;
+               leftover = 0;
+
+               while (cp >= bufstart) {
+
+                       /*
+                        * If cp-bufstart is not large enough to hold a piece
+                        * of record length information, copy remainder to end
+                        * of buf and continue reading the file.
+                        */
+
+                       if (cp - bufstart < 2) {
+                               leftover = cp - bufstart;
+                               memcpy(bufend - leftover, bufstart, leftover);
+                               break;
+                       }
+
+                       /*
+                        * Extract the record length.  We must do it this way
+                        * instead of casting cp to an int because cp might
+                        * not be word aligned.
+                        */
+
+                       reclen = (*(cp-2) * 256) + *(cp -1);
+
+                       /*
+                        * If cp-bufstart isn't large enough to hold a
+                        * complete record, plus the length information, copy
+                        * the leftover bytes to the end of buf and continue
+                        * reading.
+                        */
+
+                       if (cp - bufstart < reclen + 2) {
+                               leftover = cp - bufstart;
+                               memcpy(bufend - leftover, bufstart, leftover);
+                               break;
+                       }
+
+                       /*
+                        * Adjust cp to point at the start of the record.
+                        * Copy the record into wbuf so that it is word
+                        * aligned and pass the record to the user supplied
+                        * function.
+                        */
+
+                       cp -= reclen + 2;
+                       memcpy(albuf, cp, reclen);
+
+                       wlog_rec_unpack(&wrec, albuf);
+
+                       /*
+                        * Call the user supplied function -
+                        * stop if instructed to.
+                        */
+
+                       if ((rval = (*func)(&wrec, data)) == WLOG_STOP_SCAN) {
+                               break;
+                       }
+
+                       recnum++;
+
+                       if (nrecs && recnum >= nrecs)
+                               break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * The following 2 routines are used to pack and unpack the user
+ * visible wlog_rec structure to/from a character buffer which is
+ * stored or read from the write logfile.  Any changes to either of
+ * these routines must be reflected in the other.
+ */
+
+static int
+wlog_rec_pack(wrec, buf, flag)
+struct wlog_rec        *wrec;
+char           *buf;
+int             flag;
+{
+       char                    *file, *host, *pattern;
+       struct wlog_rec_disk    *wrecd;
+
+       wrecd = (struct wlog_rec_disk *)buf;
+
+       wrecd->w_pid = (uint)wrec->w_pid;
+       wrecd->w_offset = (uint)wrec->w_offset;
+       wrecd->w_nbytes = (uint)wrec->w_nbytes;
+       wrecd->w_oflags = (uint)wrec->w_oflags;
+       wrecd->w_done = (uint)wrec->w_done;
+       wrecd->w_async = (uint)wrec->w_async;
+
+       wrecd->w_pathlen = (wrec->w_pathlen > 0) ? (uint)wrec->w_pathlen : 0;
+       wrecd->w_hostlen = (wrec->w_hostlen > 0) ? (uint)wrec->w_hostlen : 0;
+       wrecd->w_patternlen = (wrec->w_patternlen > 0) ? (uint)wrec->w_patternlen : 0;
+
+       /*
+        * If flag is true, we should also pack the variable length parts
+        * of the wlog_rec.  By default, we only pack the fixed length
+        * parts.
+        */
+
+       if (flag) {
+               file = buf + sizeof(struct wlog_rec_disk);
+               host = file + wrecd->w_pathlen;
+               pattern = host + wrecd->w_hostlen;
+       
+               if (wrecd->w_pathlen > 0)
+                       memcpy(file, wrec->w_path, wrecd->w_pathlen);
+       
+               if (wrecd->w_hostlen > 0)
+                       memcpy(host, wrec->w_host, wrecd->w_hostlen);
+       
+               if (wrecd->w_patternlen > 0)
+                       memcpy(pattern, wrec->w_pattern, wrecd->w_patternlen);
+
+               return (sizeof(struct wlog_rec_disk) +
+                       wrecd->w_pathlen + wrecd->w_hostlen + wrecd->w_patternlen);
+       } else {
+               return sizeof(struct wlog_rec_disk);
+       }
+}
+
+static int
+wlog_rec_unpack(wrec, buf)
+struct wlog_rec        *wrec;
+char           *buf;
+{
+       char                    *file, *host, *pattern;
+       struct wlog_rec_disk    *wrecd;
+
+       bzero((char *)wrec, sizeof(struct wlog_rec));
+       wrecd = (struct wlog_rec_disk *)buf;
+
+       wrec->w_pid = wrecd->w_pid;
+       wrec->w_offset = wrecd->w_offset;
+       wrec->w_nbytes = wrecd->w_nbytes;
+       wrec->w_oflags = wrecd->w_oflags;
+       wrec->w_hostlen = wrecd->w_hostlen;
+       wrec->w_pathlen = wrecd->w_pathlen;
+       wrec->w_patternlen = wrecd->w_patternlen;
+       wrec->w_done = wrecd->w_done;
+       wrec->w_async = wrecd->w_async;
+
+       if (wrec->w_pathlen > 0) {
+               file = buf + sizeof(struct wlog_rec_disk);
+               memcpy(wrec->w_path, file, wrec->w_pathlen);
+       }
+
+       if (wrec->w_hostlen > 0) {
+               host = buf + sizeof(struct wlog_rec_disk) + wrec->w_pathlen;
+               memcpy(wrec->w_host, host, wrec->w_hostlen);
+       }
+
+       if (wrec->w_patternlen > 0) {
+               pattern = buf + sizeof(struct wlog_rec_disk) +
+                       wrec->w_pathlen + wrec->w_hostlen;
+               memcpy(wrec->w_pattern, pattern, wrec->w_patternlen);
+       }
+
+       return 0;
+}
diff --git a/ltp/Makefile b/ltp/Makefile
new file mode 100644 (file)
index 0000000..bc186a9
--- /dev/null
@@ -0,0 +1,60 @@
+# 
+# Copyright (c) 2003 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., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, 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/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+TARGETS = doio fsstress fsx growfiles iogen
+CFILES = $(TARGETS:=.c)
+HFILES = doio.h
+LDIRT = $(TARGETS)
+LCFLAGS =
+
+default: $(TARGETS)
+
+include $(BUILDRULES)
+LINKTEST = $(LTLINK) $@.c -o $@ $(CFLAGS) $(LDFLAGS)
+
+doio: doio.c $(LIBTEST)
+       $(LINKTEST) $(LIBTEST) $(LDLIBS)
+
+fsstress: fsstress.c $(LIBATTR) $(LIBTEST)
+       $(LINKTEST) $(LIBATTR) $(LIBTEST) $(LDLIBS)
+
+fsx: fsx.c
+       $(LINKTEST) $(LDLIBS)
+
+growfiles: growfiles.c $(LIBTEST)
+       $(LINKTEST) $(LIBTEST) $(LDLIBS)
+
+iogen: iogen.c $(LIBTEST)
+       $(LINKTEST) $(LIBTEST) $(LDLIBS)
diff --git a/ltp/doio.c b/ltp/doio.c
new file mode 100644 (file)
index 0000000..731798e
--- /dev/null
@@ -0,0 +1,5423 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+/*
+ * doio -      a general purpose io initiator with system call and
+ *             write logging.  See doio.h for the structure which defines
+ *             what doio requests should look like.
+ *
+ * programming
+ * notes:
+ * -----------
+ *     messages should generally be printed using doio_fprintf().
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#ifdef CRAY
+#include <sys/iosw.h>
+#endif
+#ifdef sgi
+#include <aio.h>       /* for aio_read,write */
+#include <inttypes.h>  /* for uint64_t type */
+#include <siginfo.h>   /* signal handlers & SA_SIGINFO */
+#endif
+#ifndef CRAY
+#include <sys/uio.h>   /* for struct iovec (readv)*/
+#include <sys/mman.h>  /* for mmap(2) */
+#include <sys/ipc.h>   /* for i/o buffer in shared memory */
+#include <sys/shm.h>   /* for i/o buffer in shared memory */
+#endif
+#include <sys/wait.h>
+#ifdef CRAY
+#include <sys/listio.h>
+#include <sys/panic.h>
+#endif
+#include <sys/time.h>  /* for delays */
+
+#ifndef NO_XFS
+#include <xfs/libxfs.h>
+struct io_req;
+int do_xfsctl(struct io_req *);
+#endif
+
+#include "doio.h"
+#include "pattern.h"
+#include "write_log.h"
+#include "random_range.h"
+#include "string_to_tokens.h"
+
+#ifndef O_SSD
+#define O_SSD 0                /* so code compiles on a CRAY2 */
+#endif
+
+#define UINT64_T unsigned long long
+
+#ifndef O_PARALLEL
+#define O_PARALLEL 0   /* so O_PARALLEL may be used in expressions */
+#endif
+
+#define PPID_CHECK_INTERVAL 5          /* check ppid every <-- iterations */
+#define        MAX_AIO         256             /* maximum number of async I/O ops */
+#ifdef _CRAYMPP
+#define        MPP_BUMP        16              /* page un-alignment for MPP */
+#else
+#define        MPP_BUMP        0
+#endif
+
+
+#define        SYSERR strerror(errno)
+
+/*
+ * getopt() string of supported cmdline arguments.
+ */
+
+#define OPTS   "aC:d:ehm:n:kr:w:vU:V:M:N:"
+
+#define DEF_RELEASE_INTERVAL   0
+
+/*
+ * Flags set in parse_cmdline() to indicate which options were selected
+ * on the cmdline.
+ */
+
+int    a_opt = 0;          /* abort on data compare errors     */
+int    e_opt = 0;          /* exec() after fork()'ing          */
+int    C_opt = 0;          /* Data Check Type                  */
+int    d_opt = 0;          /* delay between operations         */
+int    k_opt = 0;          /* lock file regions during writes  */
+int    m_opt = 0;          /* generate periodic messages       */
+int    n_opt = 0;          /* nprocs                           */
+int    r_opt = 0;          /* resource release interval        */
+int    w_opt = 0;          /* file write log file              */
+int    v_opt = 0;          /* verify writes if set             */
+int    U_opt = 0;          /* upanic() on varios conditions    */
+int    V_opt = 0;          /* over-ride default validation fd type */
+int    M_opt = 0;          /* data buffer allocation types     */
+char   TagName[40];        /* name of this doio (see Monster)  */
+
+
+/*
+ * Misc globals initialized in parse_cmdline()
+ */
+
+char   *Prog = NULL;       /* set up in parse_cmdline()                */
+int    Upanic_Conditions;  /* set by args to -U                        */
+int    Release_Interval;   /* arg to -r                                */
+int    Nprocs;             /* arg to -n                                */
+char   *Write_Log;         /* arg to -w                                */
+char   *Infile;            /* input file (defaults to stdin)           */
+int    *Children;          /* pids of child procs                      */
+int    Nchildren = 0;
+int    Nsiblings = 0;      /* tfork'ed siblings                        */
+int    Execd = 0;
+int    Message_Interval = 0;
+int    Npes = 0;           /* non-zero if built as an mpp multi-pe app */
+int    Vpe = -1;           /* Virtual pe number if Npes >= 0           */
+int    Reqno = 1;          /* request # - used in some error messages  */
+int    Reqskipcnt = 0;     /* count of I/O requests that are skipped   */
+int    Validation_Flags;
+char   *(*Data_Check)();   /* function to call for data checking       */
+int    (*Data_Fill)();     /* function to call for data filling        */
+int    Nmemalloc = 0;      /* number of memory allocation strategies   */
+int    delayop = 0;        /* delay between operations - type of delay */
+int    delaytime = 0;      /* delay between operations - how long      */
+
+struct wlog_file       Wlog;
+
+int    active_mmap_rw = 0; /* Indicates that mmapped I/O is occurring. */
+                           /* Used by sigbus_action() in the child doio. */
+int    havesigint = 0;
+
+#define SKIP_REQ       -2      /* skip I/O request */
+
+#define        NMEMALLOC       32
+#define        MEM_DATA        1       /* data space                           */
+#define        MEM_SHMEM       2       /* System V shared memory               */
+#define        MEM_T3ESHMEM    3       /* T3E Shared Memory                    */
+#define        MEM_MMAP        4       /* mmap(2)                              */
+
+#define        MEMF_PRIVATE    0001
+#define        MEMF_AUTORESRV  0002
+#define        MEMF_LOCAL      0004
+#define        MEMF_SHARED     0010
+
+#define        MEMF_FIXADDR    0100
+#define        MEMF_ADDR       0200
+#define        MEMF_AUTOGROW   0400
+#define        MEMF_FILE       01000   /* regular file -- unlink on close      */
+#define MEMF_MPIN      010000  /* use mpin(2) to lock pages in memory */
+
+struct memalloc {
+       int     memtype;
+       int     flags;
+       int     nblks;
+       char    *name;
+       void    *space;         /* memory address of allocated space */
+       int     fd;             /* FD open for mmaping */
+       int     size;
+}      Memalloc[NMEMALLOC];
+
+/*
+ * Global file descriptors
+ */
+
+int    Wfd_Append;         /* for appending to the write-log       */
+int    Wfd_Random;         /* for overlaying write-log entries     */
+
+/*
+ * Structure for maintaining open file test descriptors.  Used by
+ * alloc_fd().
+ */
+
+struct fd_cache {
+       char    c_file[MAX_FNAME_LENGTH+1];
+       int     c_oflags;
+       int     c_fd;
+       long    c_rtc;
+#ifndef NO_XFS
+       int     c_memalign;     /* from xfsctl(XFS_IOC_DIOINFO) */
+       int     c_miniosz;
+       int     c_maxiosz;
+#endif
+#ifndef CRAY
+       void    *c_memaddr;     /* mmapped address */
+       int     c_memlen;       /* length of above region */
+#endif
+};
+
+#define FD_ALLOC_INCR  32      /* allocate this many fd_map structs    */
+                               /* at a time */
+
+/*
+ * Globals for tracking Sds and Core usage
+ */
+
+char   *Memptr;                /* ptr to core buffer space             */
+int    Memsize;                /* # bytes pointed to by Memptr         */
+                               /* maintained by alloc_mem()            */
+
+int    Sdsptr;                 /* sds offset (always 0)                */
+int    Sdssize;                /* # bytes of allocated sds space       */
+                               /* Maintained by alloc_sds()            */
+char   Host[16];
+char   Pattern[128];
+int    Pattern_Length;
+
+/*
+ * Signal handlers, and related globals
+ */
+
+void   sigint_handler();       /* Catch SIGINT in parent doio, propagate
+                                * to children, does not die. */
+
+void   die_handler();          /* Bad sig in child doios, exit 1. */
+void   cleanup_handler();      /* Normal kill, exit 0. */
+
+#ifndef CRAY
+void   sigbus_handler();       /* Handle sigbus--check active_mmap_rw to
+                                  decide if this should be a normal exit. */
+#endif
+
+void   cb_handler();           /* Posix aio callback handler. */
+void   noop_handler();         /* Delayop alarm, does nothing. */
+char   *hms();
+char   *format_rw();
+char   *format_sds();
+char   *format_listio();
+char   *check_file();
+int    doio_fprintf(FILE *stream, char *format, ...);
+void   doio_upanic();
+void   doio();
+void   help();
+void   doio_delay();
+int     alloc_fd( char *, int );
+int     alloc_mem( int );
+int     do_read( struct io_req * );
+int     do_write( struct io_req * );
+int     do_rw( struct io_req * );
+int     do_sync( struct io_req * );
+int     usage( FILE * );
+int     aio_unregister( int );
+int     parse_cmdline( int, char **, char * );
+int     lock_file_region( char *, int, int, int, int );
+struct fd_cache *alloc_fdcache(char *, int);
+
+/*
+ * Upanic conditions, and a map from symbolics to values
+ */
+
+#define U_CORRUPTION   0001        /* upanic on data corruption    */
+#define U_IOSW         0002        /* upanic on bad iosw           */
+#define U_RVAL         0004        /* upanic on bad rval           */
+
+#define U_ALL          (U_CORRUPTION | U_IOSW | U_RVAL)
+
+/*
+ * Name-To-Value map
+ * Used to map cmdline arguments to values
+ */
+struct smap {
+       char    *string;
+       int     value;
+};
+
+struct smap Upanic_Args[] = {
+       { "corruption", U_CORRUPTION    },
+       { "iosw",       U_IOSW          },
+       { "rval",       U_RVAL          },
+       { "all",        U_ALL           },
+       { NULL,         0               }
+};
+
+struct aio_info {
+       int                     busy;
+       int                     id;
+       int                     fd;
+       int                     strategy;
+       volatile int            done;
+#ifdef CRAY
+       struct iosw             iosw;
+#endif
+#ifdef sgi
+       aiocb_t                 aiocb;
+       int                     aio_ret;        /* from aio_return */
+       int                     aio_errno;      /* from aio_error */
+#endif
+       int                     sig;
+       int                     signalled;
+       struct sigaction        osa;
+};
+
+struct aio_info        Aio_Info[MAX_AIO];
+
+struct aio_info        *aio_slot();
+int     aio_done( struct aio_info * );
+
+/* -C data-fill/check type */
+#define        C_DEFAULT       1
+struct smap checkmap[] = {
+       { "default",    C_DEFAULT },
+       { NULL,         0 },
+};
+
+/* -d option delay types */
+#define        DELAY_SELECT    1
+#define        DELAY_SLEEP     2
+#define        DELAY_SGINAP    3
+#define        DELAY_ALARM     4
+#define        DELAY_ITIMER    5       /* POSIX timer                          */
+
+struct smap delaymap[] = {
+       { "select",     DELAY_SELECT },
+       { "sleep",      DELAY_SLEEP },
+#ifdef sgi
+       { "sginap",     DELAY_SGINAP },
+#endif
+       { "alarm",      DELAY_ALARM },
+       { NULL, 0 },
+};
+
+/******
+*
+* strerror() does similar actions.
+
+char *
+syserrno(int err)
+{
+    static char sys_errno[10];
+    sprintf(sys_errno, "%d", errno);
+    return(sys_errno);
+}
+
+******/
+
+int
+main(argc, argv)
+int    argc;
+char   **argv;
+{
+       int                     i, pid, stat, ex_stat;
+#ifdef CRAY
+       sigset_t                omask;
+#else
+       int                     omask;
+#endif
+       struct sigaction        sa;
+
+       umask(0);               /* force new file modes to known values */
+#if _CRAYMPP
+       Npes = sysconf(_SC_CRAY_NPES);  /* must do this before parse_cmdline */
+       Vpe = sysconf(_SC_CRAY_VPE);
+#endif
+
+       TagName[0] = '\0';
+       parse_cmdline(argc, argv, OPTS);
+
+       random_range_seed(getpid());       /* initialize random number generator */
+
+       /*      
+        * If this is a re-exec of doio, jump directly into the doio function.
+        */
+
+       if (Execd) {
+               doio();
+               exit(E_SETUP);
+       }
+
+       /*
+        * Stop on all but a few signals...
+        */
+       sigemptyset(&sa.sa_mask);
+       sa.sa_handler = sigint_handler;
+       sa.sa_flags = SA_RESETHAND;     /* sigint is ignored after the */
+                                       /* first time */
+       for (i = 1; i <= NSIG; i++) {
+               switch(i) {
+#ifdef SIGRECOVERY
+               case SIGRECOVERY:
+                       break;
+#endif
+#ifdef SIGCKPT
+               case SIGCKPT:
+#endif
+#ifdef SIGRESTART
+               case SIGRESTART:
+#endif
+               case SIGTSTP:
+               case SIGSTOP:
+               case SIGCONT:
+               case SIGCLD:
+               case SIGBUS:
+               case SIGSEGV:
+               case SIGQUIT:
+                       break;
+               default:
+                       sigaction(i, &sa, NULL);
+               }
+       }
+
+       /*
+        * If we're logging write operations, make a dummy call to wlog_open
+        * to initialize the write history file.  This call must be done in
+        * the parent, to ensure that the history file exists and/or has
+        * been truncated before any children attempt to open it, as the doio
+        * children are not allowed to truncate the file.
+        */
+
+       if (w_opt) {
+               strcpy(Wlog.w_file, Write_Log);
+
+               if (wlog_open(&Wlog, 1, 0666) < 0) {
+                       doio_fprintf(stderr,
+                                    "Could not create/truncate write log %s\n",
+                                    Write_Log);
+                       exit(2);
+               }
+
+               wlog_close(&Wlog);
+       }
+
+       /*
+        * Malloc space for the children pid array.  Initialize all entries
+        * to -1.
+        */
+
+       Children = (int *)malloc(sizeof(int) * Nprocs);
+       for (i = 0; i < Nprocs; i++) {
+               Children[i] = -1;
+       }
+
+       omask = sigblock(sigmask(SIGCLD));
+
+       /*
+        * Fork Nprocs.  This [parent] process is a watchdog, to notify the
+        * invoker of procs which exit abnormally, and to make sure that all
+        * child procs get cleaned up.  If the -e option was used, we will also
+        * re-exec.  This is mostly for unicos/mk on mpp's, to ensure that not
+        * all of the doio's don't end up in the same pe.
+        *
+        * Note - if Nprocs is 1, or this doio is a multi-pe app (Npes > 1),
+        * jump directly to doio().  multi-pe apps can't fork(), and there is
+        * no reason to fork() for 1 proc.
+        */
+
+       if (Nprocs == 1 || Npes > 1) {
+               doio();
+               exit(0);
+       } else {
+               for (i = 0; i < Nprocs; i++) {
+                       if ((pid = fork()) == -1) {
+                               doio_fprintf(stderr,
+                                            "(parent) Could not fork %d children:  %s (%d)\n",
+                                            i+1, SYSERR, errno);
+                               exit(E_SETUP);
+                       }
+                       
+                       Children[Nchildren] = pid;
+                       Nchildren++;
+                       
+                       if (pid == 0) {
+                               if (e_opt) {
+                                       char *exec_path;
+
+                                       exec_path = argv[0];
+                                       argv[0] = (char *)malloc(strlen(exec_path + 1));
+                                       sprintf(argv[0], "-%s", exec_path);
+
+                                       execvp(exec_path, argv);
+                                       doio_fprintf(stderr,
+                                                    "(parent) Could not execvp %s:  %s (%d)\n",
+                                                    exec_path, SYSERR, errno);
+                                       exit(E_SETUP);
+                               } else {
+                                       doio();
+                                       exit(E_SETUP);
+                               }
+                       }
+               }
+
+               /*
+                * Parent spins on wait(), until all children exit.
+                */
+               
+               ex_stat = E_NORMAL;
+               
+               while (Nprocs) {
+                       if ((pid = wait(&stat)) == -1) {
+                               if (errno == EINTR)
+                                       continue;
+                       }
+                       
+                       for (i = 0; i < Nchildren; i++)
+                               if (Children[i] == pid)
+                                       Children[i] = -1;
+                       
+                       Nprocs--;
+                       
+                       if (WIFEXITED(stat)) {
+                               switch (WEXITSTATUS(stat)) {
+                               case E_NORMAL:
+                                       /* noop */
+                                       break;
+
+                               case E_INTERNAL:
+                                       doio_fprintf(stderr,
+                                                    "(parent) pid %d exited because of an internal error\n",
+                                                    pid);
+                                       ex_stat |= E_INTERNAL;
+                                       break;
+
+                               case E_SETUP:
+                                       doio_fprintf(stderr,
+                                                    "(parent) pid %d exited because of a setup error\n",
+                                                    pid);
+                                       ex_stat |= E_SETUP;
+                                       break;
+
+                               case E_COMPARE:
+                                       doio_fprintf(stderr,
+                                                    "(parent) pid %d exited because of data compare errors\n",
+                                                    pid);
+
+                                       ex_stat |= E_COMPARE;
+
+                                       if (a_opt)
+                                               kill(0, SIGINT);
+
+                                       break;
+
+                               case E_USAGE:
+                                       doio_fprintf(stderr,
+                                                    "(parent) pid %d exited because of a usage error\n",
+                                                    pid);
+
+                                       ex_stat |= E_USAGE;
+                                       break;
+
+                               default:
+                                       doio_fprintf(stderr,
+                                                    "(parent) pid %d exited with unknown status %d\n",
+                                                    pid, WEXITSTATUS(stat));
+                                       ex_stat |= E_INTERNAL;
+                                       break;
+                               }
+                       } else if (WIFSIGNALED(stat) && WTERMSIG(stat) != SIGINT) {
+                               doio_fprintf(stderr,
+                                            "(parent) pid %d terminated by signal %d\n",
+                                            pid, WTERMSIG(stat));
+                               
+                               ex_stat |= E_SIGNAL;
+                       }
+                       
+                       fflush(NULL);
+               }
+       }
+
+       exit(ex_stat);
+
+}  /* main */
+
+/*
+ * main doio function.  Each doio child starts here, and never returns.
+ */
+
+void
+doio()
+{
+       int                     rval, i, infd, nbytes;
+       char                    *cp;
+       struct io_req           ioreq;
+       struct sigaction        sa, def_action, ignore_action, exit_action;
+#ifndef CRAY
+       struct sigaction        sigbus_action;
+#endif
+
+       Memsize = Sdssize = 0;
+
+       /*
+        * Initialize the Pattern - write-type syscalls will replace Pattern[1]
+        * with the pattern passed in the request.  Make sure that
+        * strlen(Pattern) is not mod 16 so that out of order words will be
+        * detected.
+        */
+
+       gethostname(Host, sizeof(Host));
+       if ((cp = strchr(Host, '.')) != NULL)
+               *cp = '\0';
+
+       Pattern_Length = sprintf(Pattern, "-:%d:%s:%s*", getpid(), Host, Prog);
+
+       if (!(Pattern_Length % 16)) {
+               Pattern_Length = sprintf(Pattern, "-:%d:%s:%s**",
+                                        getpid(), Host, Prog);
+       }
+
+       /*
+        * Open a couple of descriptors for the write-log file.  One descriptor
+        * is for appending, one for random access.  Write logging is done for
+        * file corruption detection.  The program doio_check is capable of
+        * doing corruption detection based on a doio write-log.
+        */
+
+       if (w_opt) {
+
+               strcpy(Wlog.w_file, Write_Log);
+       
+               if (wlog_open(&Wlog, 0, 0666) == -1) {
+                       doio_fprintf(stderr,
+                                    "Could not open write log file (%s): wlog_open() failed\n",
+                                    Write_Log);
+                       exit(E_SETUP);
+               }
+       }
+
+       /*
+        * Open the input stream - either a file or stdin
+        */
+
+       if (Infile == NULL) {
+               infd = 0;
+       } else {
+               if ((infd = open(Infile, O_RDWR)) == -1) {
+                       doio_fprintf(stderr,
+                                    "Could not open input file (%s):  %s (%d)\n",
+                                    Infile, SYSERR, errno);
+                       exit(E_SETUP);
+               }
+       }
+
+       /*
+        * Define a set of signals that should never be masked.  Receipt of
+        * these signals generally indicates a programming error, and we want
+        * a corefile at the point of error.  We put SIGQUIT in this list so
+        * that ^\ will force a user core dump.
+        *
+        * Note:  the handler for these should be SIG_DFL, all of them 
+        * produce a corefile as the default action.
+        */
+
+       ignore_action.sa_handler = SIG_IGN;
+       ignore_action.sa_flags = 0;
+       sigemptyset(&ignore_action.sa_mask);
+
+       def_action.sa_handler = SIG_DFL;
+       def_action.sa_flags = 0;
+       sigemptyset(&def_action.sa_mask);
+
+#ifdef sgi
+       exit_action.sa_sigaction = cleanup_handler;
+       exit_action.sa_flags = SA_SIGINFO;
+       sigemptyset(&exit_action.sa_mask);
+
+       sa.sa_sigaction = die_handler;
+       sa.sa_flags = SA_SIGINFO;
+       sigemptyset(&sa.sa_mask);
+
+       sigbus_action.sa_sigaction = sigbus_handler;
+       sigbus_action.sa_flags = SA_SIGINFO;
+       sigemptyset(&sigbus_action.sa_mask);
+#else
+       exit_action.sa_handler = cleanup_handler;
+       exit_action.sa_flags = 0;
+       sigemptyset(&exit_action.sa_mask);
+
+       sa.sa_handler = die_handler;
+       sa.sa_flags = 0;
+       sigemptyset(&sa.sa_mask);
+
+#ifndef CRAY
+       sigbus_action.sa_handler = sigbus_handler;
+       sigbus_action.sa_flags = 0;
+       sigemptyset(&sigbus_action.sa_mask);
+#endif
+#endif
+
+       for (i = 1; i <= NSIG; i++) {
+               switch(i) {
+                       /* Signals to terminate program on */
+               case SIGINT:
+                       sigaction(i, &exit_action, NULL);
+                       break;
+
+#ifndef CRAY
+                       /* This depends on active_mmap_rw */
+               case SIGBUS:
+                       sigaction(i, &sigbus_action, NULL);
+                       break;
+#endif
+
+                   /* Signals to Ignore... */
+               case SIGSTOP:
+               case SIGCONT:
+#ifdef SIGRECOVERY
+               case SIGRECOVERY:
+#endif
+                       sigaction(i, &ignore_action, NULL);
+                       break;
+
+                   /* Signals to trap & report & die */
+               /*case SIGTRAP:*/
+               /*case SIGABRT:*/
+#ifdef SIGERR  /* cray only signals */
+               case SIGERR:
+               case SIGBUFIO:
+               case SIGINFO:
+#endif
+               /*case SIGFPE:*/
+               case SIGURG:
+               case SIGHUP:
+               case SIGTERM:
+               case SIGPIPE:
+               case SIGIO:
+               case SIGUSR1:
+               case SIGUSR2:
+                       sigaction(i, &sa, NULL);
+                       break;
+
+
+                   /* Default Action for all other signals */
+               default:
+                       sigaction(i, &def_action, NULL);
+                       break;
+               }
+       }
+
+       /*
+        * Main loop - each doio proc does this until the read returns eof (0).
+        * Call the appropriate io function based on the request type.
+        */
+
+       while ((nbytes = read(infd, (char *)&ioreq, sizeof(ioreq)))) {
+
+               /*
+                * Periodically check our ppid.  If it is 1, the child exits to
+                * help clean up in the case that the main doio process was
+                * killed.
+                */
+
+               if (Reqno && ((Reqno % PPID_CHECK_INTERVAL) == 0)) {
+                       if (getppid() == 1) {
+                               doio_fprintf(stderr,
+                                            "Parent doio process has exited\n");
+                               alloc_mem(-1);
+                               exit(E_SETUP);
+                       }
+               }
+
+               if (nbytes == -1) {
+                       doio_fprintf(stderr,
+                                    "read of %d bytes from input failed:  %s (%d)\n",
+                                    sizeof(ioreq), SYSERR, errno);
+                       alloc_mem(-1);
+                       exit(E_SETUP);
+               }
+
+               if (nbytes != sizeof(ioreq)) {
+                       doio_fprintf(stderr,
+                                    "read wrong # bytes from input stream, expected %d, got %d\n",
+                                    sizeof(ioreq), nbytes);
+                       alloc_mem(-1);
+                       exit(E_SETUP);
+               }
+
+               if (ioreq.r_magic != DOIO_MAGIC) {
+                       doio_fprintf(stderr,
+                                    "got a bad magic # from input stream.  Expected 0%o, got 0%o\n",
+                                    DOIO_MAGIC, ioreq.r_magic);
+                       alloc_mem(-1);
+                       exit(E_SETUP);
+               }
+
+               /*
+                * If we're on a Release_Interval multiple, relase all ssd and
+                * core space, and close all fd's in Fd_Map[].
+                */
+
+               if (Reqno && Release_Interval && ! (Reqno%Release_Interval)) {
+                       if (Memsize) {
+#ifdef NOTDEF
+                               sbrk(-1 * Memsize);
+#else
+                               alloc_mem(-1);
+#endif
+                       }
+
+#ifdef _CRAY1
+                       if (Sdssize) {
+                               ssbreak(-1 * btoc(Sdssize));
+                               Sdsptr = 0;
+                               Sdssize = 0;
+                       }
+#endif /* _CRAY1 */
+
+                       alloc_fd(NULL, 0);
+               }
+
+               switch (ioreq.r_type) {
+               case READ:
+               case READA:
+                       rval = do_read(&ioreq);
+                       break;
+
+               case WRITE:
+               case WRITEA:
+                       rval = do_write(&ioreq);
+                       break;
+
+               case READV:
+               case AREAD:
+               case PREAD:
+               case LREAD:
+               case LREADA:
+               case LSREAD:
+               case LSREADA:
+               case WRITEV:
+               case AWRITE:
+               case PWRITE:
+               case MMAPR:
+               case MMAPW:
+               case LWRITE:
+               case LWRITEA:
+               case LSWRITE:
+               case LSWRITEA:
+               case LEREAD:
+               case LEREADA:
+               case LEWRITE:
+               case LEWRITEA:
+                       rval = do_rw(&ioreq);
+                       break;
+
+#ifdef CRAY
+               case SSREAD:
+               case SSWRITE:
+                       rval = do_ssdio(&ioreq);
+                       break;
+
+               case LISTIO:
+                       rval = do_listio(&ioreq);
+                       break;
+#endif
+
+#ifndef NO_XFS
+               case RESVSP:
+               case UNRESVSP:
+                       rval = do_xfsctl(&ioreq);
+                       break;
+#endif
+
+#ifndef CRAY
+               case FSYNC2:
+               case FDATASYNC:
+                       rval = do_sync(&ioreq);
+                       break;
+#endif
+               default:
+                       doio_fprintf(stderr,
+                                    "Don't know how to handle io request type %d\n",
+                                    ioreq.r_type);
+                       alloc_mem(-1);
+                       exit(E_SETUP);
+               }
+
+               if (rval == SKIP_REQ){
+                       Reqskipcnt++;
+               }
+               else if (rval != 0) {
+                       alloc_mem(-1);
+                       doio_fprintf(stderr,
+                                    "doio(): operation %d returned != 0\n",
+                                    ioreq.r_type);
+                       exit(E_SETUP);
+               }
+
+               if (Message_Interval && Reqno % Message_Interval == 0) {
+                       doio_fprintf(stderr, "Info:  %d requests done (%d skipped) by this process\n", Reqno, Reqskipcnt);
+               }
+
+               Reqno++;
+
+               if(delayop != 0)
+                       doio_delay();
+       }
+
+       /*
+        * Child exits normally
+        */
+       alloc_mem(-1);
+       exit(E_NORMAL);
+
+}  /* doio */
+
+void
+doio_delay()
+{
+       struct timeval tv_delay;
+       struct sigaction sa_al, sa_old;
+       sigset_t al_mask;
+
+       switch(delayop) {
+       case DELAY_SELECT:
+               tv_delay.tv_sec = delaytime / 1000000;
+               tv_delay.tv_usec = delaytime % 1000000;
+               /*doio_fprintf(stdout, "delay_select: %d %d\n", 
+                           tv_delay.tv_sec, tv_delay.tv_usec);*/
+               select(0, NULL, NULL, NULL, &tv_delay);
+               break;
+
+       case DELAY_SLEEP:
+               sleep(delaytime);
+               break;
+
+#ifdef sgi
+       case DELAY_SGINAP:
+               sginap(delaytime);
+               break;
+#endif
+
+       case DELAY_ALARM:
+               sa_al.sa_flags = 0;
+               sa_al.sa_handler = noop_handler;
+               sigemptyset(&sa_al.sa_mask);
+               sigaction(SIGALRM, &sa_al, &sa_old);
+               sigemptyset(&al_mask);
+               alarm(delaytime);
+               sigsuspend(&al_mask);
+               sigaction(SIGALRM, &sa_old, 0);
+               break;
+       }
+}
+
+
+/*
+ * Format IO requests, returning a pointer to the formatted text.
+ *
+ * format_strat        - formats the async i/o completion strategy
+ * format_rw   - formats a read[a]/write[a] request
+ * format_sds  - formats a ssread/sswrite request
+ * format_listio- formats a listio request
+ *
+ * ioreq is the doio io request structure.
+ */
+
+struct smap sysnames[] = {
+       { "READ",       READ            },
+       { "WRITE",      WRITE           },
+       { "READA",      READA           },
+       { "WRITEA",     WRITEA          },
+       { "SSREAD",     SSREAD          },
+       { "SSWRITE",    SSWRITE         },
+       { "LISTIO",     LISTIO          },
+       { "LREAD",      LREAD           },
+       { "LREADA",     LREADA          },
+       { "LWRITE",     LWRITE          },
+       { "LWRITEA",    LWRITEA         },
+       { "LSREAD",     LSREAD          },
+       { "LSREADA",    LSREADA         },
+       { "LSWRITE",    LSWRITE         },
+       { "LSWRITEA",   LSWRITEA        },
+
+       /* Irix System Calls */
+       { "PREAD",      PREAD           },
+       { "PWRITE",     PWRITE          },
+       { "AREAD",      AREAD           },
+       { "AWRITE",     AWRITE          },
+       { "LLREAD",     LLREAD          },
+       { "LLAREAD",    LLAREAD         },
+       { "LLWRITE",    LLWRITE         },
+       { "LLAWRITE",   LLAWRITE        },
+       { "RESVSP",     RESVSP          },
+       { "UNRESVSP",   UNRESVSP        },
+
+       /* Irix and Linux System Calls */
+       { "READV",      READV           },
+       { "WRITEV",     WRITEV          },
+       { "MMAPR",      MMAPR           },
+       { "MMAPW",      MMAPW           },
+       { "FSYNC2",     FSYNC2          },
+       { "FDATASYNC",  FDATASYNC       },
+
+       { "unknown",    -1              },
+};     
+
+struct smap aionames[] = {
+       { "poll",       A_POLL          },
+       { "signal",     A_SIGNAL        },
+       { "recall",     A_RECALL        },
+       { "recalla",    A_RECALLA       },
+       { "recalls",    A_RECALLS       },
+       { "suspend",    A_SUSPEND       },
+       { "callback",   A_CALLBACK      },
+       { "synch",      0               },
+       { "unknown",    -1              },
+};
+
+char *
+format_oflags(int oflags)
+{
+       char flags[255];
+
+
+       flags[0]='\0';
+       switch(oflags & 03) {
+       case O_RDONLY:          strcat(flags,"O_RDONLY,");      break;
+       case O_WRONLY:          strcat(flags,"O_WRONLY,");      break;
+       case O_RDWR:            strcat(flags,"O_RDWR,");        break;
+       default:                strcat(flags,"O_weird");        break;
+       }
+
+       if(oflags & O_EXCL)
+               strcat(flags,"O_EXCL,");
+
+       if(oflags & O_SYNC)
+               strcat(flags,"O_SYNC,");
+#ifdef CRAY
+       if(oflags & O_RAW)
+               strcat(flags,"O_RAW,");
+       if(oflags & O_WELLFORMED)
+               strcat(flags,"O_WELLFORMED,");
+#ifdef O_SSD
+       if(oflags & O_SSD)
+               strcat(flags,"O_SSD,");
+#endif
+       if(oflags & O_LDRAW)
+               strcat(flags,"O_LDRAW,");
+       if(oflags & O_PARALLEL)
+               strcat(flags,"O_PARALLEL,");
+       if(oflags & O_BIG)
+               strcat(flags,"O_BIG,");
+       if(oflags & O_PLACE)
+               strcat(flags,"O_PLACE,");
+       if(oflags & O_ASYNC)
+               strcat(flags,"O_ASYNC,");
+#endif
+
+       if(oflags & O_DIRECT)
+               strcat(flags,"O_DIRECT,");
+#ifdef sgi
+       if(oflags & O_DSYNC)
+               strcat(flags,"O_DSYNC,");
+       if(oflags & O_RSYNC)
+               strcat(flags,"O_RSYNC,");
+#endif
+
+       return(strdup(flags));
+}
+
+char *
+format_strat(int strategy)
+{
+       char msg[64];
+       char *aio_strat;
+
+       switch (strategy) {
+       case A_POLL:            aio_strat = "POLL";     break;
+       case A_SIGNAL:          aio_strat = "SIGNAL";   break;
+       case A_RECALL:          aio_strat = "RECALL";   break;
+       case A_RECALLA:         aio_strat = "RECALLA";  break;
+       case A_RECALLS:         aio_strat = "RECALLS";  break;
+       case A_SUSPEND:         aio_strat = "SUSPEND";  break;
+       case A_CALLBACK:        aio_strat = "CALLBACK"; break;
+       case 0:                 aio_strat = "<zero>";   break;
+       default:
+               sprintf(msg, "<error:%#o>", strategy);
+               aio_strat = strdup(msg);
+               break;
+       }
+
+       return(aio_strat);
+}
+
+char *
+format_rw(
+       struct  io_req  *ioreq,
+       int             fd,
+       void            *buffer,
+       int             signo,
+       char            *pattern,
+#ifdef CRAY
+       struct  iosw    *iosw
+#else
+       void            *iosw
+#endif
+       )
+{
+       static char             *errbuf=NULL;
+       char                    *aio_strat, *cp;
+       struct read_req         *readp = &ioreq->r_data.read;
+       struct write_req        *writep = &ioreq->r_data.write;
+       struct read_req         *readap = &ioreq->r_data.read;
+       struct write_req        *writeap = &ioreq->r_data.write;
+
+       if(errbuf == NULL)
+               errbuf = (char *)malloc(32768);
+
+       cp = errbuf;
+       cp += sprintf(cp, "Request number %d\n", Reqno);
+
+       switch (ioreq->r_type) {
+       case READ:
+               cp += sprintf(cp, "syscall:  read(%d, %#lo, %d)\n",
+                             fd, (unsigned long) buffer, readp->r_nbytes);
+               cp += sprintf(cp, "          fd %d is file %s - open flags are %#o\n",
+                             fd, readp->r_file, readp->r_oflags);
+               cp += sprintf(cp, "          read done at file offset %d\n",
+                             readp->r_offset);
+               break;
+
+       case WRITE:
+               cp += sprintf(cp, "syscall:  write(%d, %#lo, %d)\n",
+                             fd, (unsigned long) buffer, writep->r_nbytes);
+               cp += sprintf(cp, "          fd %d is file %s - open flags are %#o\n",
+                             fd, writep->r_file, writep->r_oflags);
+               cp += sprintf(cp, "          write done at file offset %d - pattern is %s\n",
+                             writep->r_offset, pattern);
+               break;
+
+       case READA:
+               aio_strat = format_strat(readap->r_aio_strat);
+
+               cp += sprintf(cp, "syscall:  reada(%d, %#lo, %d, %#lo, %d)\n",
+                             fd, (unsigned long) buffer, readap->r_nbytes,
+                             (unsigned long) iosw, signo);
+               cp += sprintf(cp, "          fd %d is file %s - open flags are %#o\n",
+                             fd, readap->r_file, readp->r_oflags);
+               cp += sprintf(cp, "          reada done at file offset %d\n",
+                             readap->r_offset);
+               cp += sprintf(cp, "          async io completion strategy is %s\n",
+                             aio_strat);
+               break;
+
+       case WRITEA:
+               aio_strat = format_strat(writeap->r_aio_strat);
+
+               cp += sprintf(cp, "syscall:  writea(%d, %#lo, %d, %#lo, %d)\n",
+                             fd, (unsigned long) buffer, writeap->r_nbytes,
+                             (unsigned long) iosw, signo);
+               cp += sprintf(cp, "          fd %d is file %s - open flags are %#o\n",
+                             fd, writeap->r_file, writeap->r_oflags);
+               cp += sprintf(cp, "          writea done at file offset %d - pattern is %s\n",
+                             writeap->r_offset, pattern);
+               cp += sprintf(cp, "          async io completion strategy is %s\n",
+                             aio_strat);
+               break;
+
+       }
+
+       return errbuf;
+}
+
+#ifdef CRAY
+char *
+format_sds(
+       struct  io_req  *ioreq,
+       void            *buffer,
+       int             sds,
+       char            *pattern
+       )
+{
+       int                     i;
+       static char             *errbuf=NULL;
+       char                    *cp;
+
+       struct ssread_req       *ssreadp = &ioreq->r_data.ssread;
+       struct sswrite_req      *sswritep = &ioreq->r_data.sswrite;
+
+       if(errbuf == NULL)
+               errbuf = (char *)malloc(32768);
+
+       cp = errbuf;
+       cp += sprintf(cp, "Request number %d\n", Reqno);
+
+
+       switch (ioreq->r_type) {
+       case SSREAD:
+               cp += sprintf(cp, "syscall:  ssread(%#o, %#o, %d)\n",
+                             buffer, sds, ssreadp->r_nbytes);
+               break;
+
+       case SSWRITE:
+               cp += sprintf(cp, "syscall:  sswrite(%#o, %#o, %d) - pattern was %s\n",
+                             buffer, sds, sswritep->r_nbytes, pattern);
+               break;
+       }
+       return errbuf;
+}
+#endif /* CRAY */
+
+/*
+ * Perform the various sorts of disk reads
+ */
+
+int
+do_read(req)
+struct io_req  *req;
+{
+       int                     fd, offset, nbytes, oflags, rval;
+       char                    *addr, *file;
+#ifdef CRAY
+       struct aio_info         *aiop;
+       int                     aio_id, aio_strat, signo;
+#endif
+#ifndef NO_XFS
+       struct fd_cache         *fdc;
+#endif
+
+       /*
+        * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+        * r_nbytes are at the same offset in the read_req and reada_req
+        * structures.
+        */
+
+       file = req->r_data.read.r_file;
+       oflags = req->r_data.read.r_oflags;
+       offset = req->r_data.read.r_offset;
+       nbytes = req->r_data.read.r_nbytes;
+
+       /*printf("read: %s, %#o, %d %d\n", file, oflags, offset, nbytes);*/
+
+       /*
+        * Grab an open file descriptor
+        * Note: must be done before memory allocation so that the direct i/o
+        *      information is available in mem. allocate
+        */
+
+       if ((fd = alloc_fd(file, oflags)) == -1)
+               return -1;
+
+       /*
+        * Allocate core or sds - based on the O_SSD flag
+        */
+
+#ifndef wtob
+#define wtob(x)        (x * sizeof(UINT64_T))
+#endif
+
+#ifdef CRAY
+       if (oflags & O_SSD) {
+               if (alloc_sds(nbytes) == -1)
+                       return -1;
+
+               addr = (char *)Sdsptr;
+       } else {
+               if ((rval = alloc_mem(nbytes + wtob(1) * 2 + MPP_BUMP * sizeof(UINT64_T))) < 0) {
+                       return rval;
+               }
+
+               addr = Memptr;
+
+               /*
+                * if io is not raw, bump the offset by a random amount
+                * to generate non-word-aligned io.
+                */
+               if (! (req->r_data.read.r_uflags & F_WORD_ALIGNED)) {
+                       addr += random_range(0, wtob(1) - 1, 1, NULL);
+               }
+       }
+#else
+#ifndef NO_XFS
+       /* get memory alignment for using DIRECT I/O */
+       fdc = alloc_fdcache(file, oflags);
+
+       if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) {
+               return rval;
+       }
+
+       addr = Memptr;
+
+
+       if( (req->r_data.read.r_uflags & F_WORD_ALIGNED) ) {
+               /*
+                * Force memory alignment for Direct I/O
+                */
+               if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
+                       addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
+               }
+       } else {
+               addr += random_range(0, wtob(1) - 1, 1, NULL);
+       }
+#else
+       if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) {
+               return rval;
+       }
+
+       addr = Memptr;
+#endif /* !CRAY && sgi */
+#endif /* CRAY */
+
+
+       switch (req->r_type) {
+       case READ:
+               /* move to the desired file position. */
+               if (lseek(fd, offset, SEEK_SET) == -1) {
+                       doio_fprintf(stderr,
+                                    "lseek(%d, %d, SEEK_SET) failed:  %s (%d)\n",
+                                    fd, offset, SYSERR, errno);
+                       return -1;
+               }
+
+               if ((rval = read(fd, addr, nbytes)) == -1) {
+                       doio_fprintf(stderr,
+                                    "read() request failed:  %s (%d)\n%s\n",
+                                    SYSERR, errno,
+                                    format_rw(req, fd, addr, -1, NULL, NULL));
+                       doio_upanic(U_RVAL);
+                       return -1;
+               } else if (rval != nbytes) {
+                       doio_fprintf(stderr,
+                                    "read() request returned wrong # of bytes - expected %d, got %d\n%s\n",
+                                    nbytes, rval, 
+                                    format_rw(req, fd, addr, -1, NULL, NULL));
+                       doio_upanic(U_RVAL);
+                       return -1;
+               }
+               break;
+
+#ifdef CRAY
+       case READA:
+               /*
+                * Async read
+                */
+
+               /* move to the desired file position. */
+               if (lseek(fd, offset, SEEK_SET) == -1) {
+                       doio_fprintf(stderr,
+                                    "lseek(%d, %d, SEEK_SET) failed:  %s (%d)\n",
+                                    fd, offset, SYSERR, errno);
+                       return -1;
+               }
+
+               aio_strat = req->r_data.read.r_aio_strat;
+               signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+               aio_id = aio_register(fd, aio_strat, signo);
+               aiop = aio_slot(aio_id);
+
+               if (reada(fd, addr, nbytes, &aiop->iosw, signo) == -1) {
+                       doio_fprintf(stderr, "reada() failed: %s (%d)\n%s\n",
+                                    SYSERR, errno,
+                                    format_rw(req, fd, addr, signo, NULL, &aiop->iosw));
+                       aio_unregister(aio_id);
+                       doio_upanic(U_RVAL);
+                       rval = -1;
+               } else {
+                       /*
+                        * Wait for io to complete
+                        */
+
+                       aio_wait(aio_id);
+
+                       /*
+                        * make sure the io completed without error
+                        */
+
+                       if (aiop->iosw.sw_count != nbytes) {
+                               doio_fprintf(stderr,
+                                            "Bad iosw from reada()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
+                                            1, 0, nbytes,
+                                            aiop->iosw.sw_flag,
+                                            aiop->iosw.sw_error,
+                                            aiop->iosw.sw_count,
+                                    format_rw(req, fd, addr, signo, NULL, &aiop->iosw));
+                               aio_unregister(aio_id);
+                               doio_upanic(U_IOSW);
+                               rval = -1;
+                       } else {
+                               aio_unregister(aio_id);
+                               rval = 0;
+                       }
+               }
+
+               if (rval == -1)
+                       return rval;
+               break;
+#endif /* CRAY */
+       }
+
+       return 0;               /* if we get here, everything went ok */
+}
+
+/*
+ * Perform the verious types of disk writes.
+ */
+
+int
+do_write(req)
+struct io_req  *req;
+{
+       static int              pid = -1;
+       int                     fd, nbytes, oflags, signo;
+       int                     logged_write, rval, got_lock;
+       long                    offset, woffset = 0;
+       char                    *addr, pattern, *file, *msg;
+       struct wlog_rec         wrec;
+#ifdef CRAY
+       int                     aio_strat, aio_id;
+       struct aio_info         *aiop;
+#endif
+#ifndef NO_XFS
+       struct fd_cache         *fdc;
+#endif
+
+       /*
+        * Misc variable setup
+        */
+
+       signo   = 0;
+       nbytes  = req->r_data.write.r_nbytes;
+       offset  = req->r_data.write.r_offset;
+       pattern = req->r_data.write.r_pattern;
+       file    = req->r_data.write.r_file;
+       oflags  = req->r_data.write.r_oflags;
+
+       /*printf("pwrite: %s, %#o, %d %d\n", file, oflags, offset, nbytes);*/
+
+       /*
+        * Allocate core memory and possibly sds space.  Initialize the data
+        * to be written.
+        */
+
+       Pattern[0] = pattern;
+
+
+       /*
+        * Get a descriptor to do the io on
+        */
+
+       if ((fd = alloc_fd(file, oflags)) == -1)
+               return -1;
+
+       /*printf("write: %d, %s, %#o, %d %d\n",
+              fd, file, oflags, offset, nbytes);*/
+
+       /*
+        * Allocate SDS space for backdoor write if desired
+        */
+
+#ifdef CRAY
+       if (oflags & O_SSD) {
+#ifndef _CRAYMPP
+               if ((rval = alloc_mem(nbytes + wtob(1))) < 0) {
+                       return rval;
+               }
+
+               (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+               /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0);*/
+
+               if (alloc_sds(nbytes) == -1)
+                       return -1;
+
+               if (sswrite((long)Memptr, Sdsptr, btoc(nbytes)) == -1) {
+                       doio_fprintf(stderr, "sswrite(%d, %d, %d) failed:  %s (%d)\n",
+                                    (long)Memptr, Sdsptr, btoc(nbytes), 
+                                    SYSERR, errno);
+                       fflush(stderr);
+                       return -1;
+               }
+
+               addr = (char *)Sdsptr;
+#else
+               doio_fprintf(stderr, "Invalid O_SSD flag was generated for MPP system\n");
+               fflush(stderr);
+               return -1;
+#endif /* !CRAYMPP */
+       } else {
+               if ((rval = alloc_mem(nbytes + wtob(1)) < 0)) {
+                       return rval;
+               }
+
+               addr = Memptr;
+
+               /*
+                * if io is not raw, bump the offset by a random amount
+                * to generate non-word-aligned io.
+                */
+
+               if (! (req->r_data.write.r_uflags & F_WORD_ALIGNED)) {
+                       addr += random_range(0, wtob(1) - 1, 1, NULL);
+               }
+
+               (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+               if( addr != Memptr )
+                       memmove( addr, Memptr, nbytes);
+       }
+#else /* CRAY */
+#ifndef NO_XFS
+       /* get memory alignment for using DIRECT I/O */
+       fdc = alloc_fdcache(file, oflags);
+
+       if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) {
+               return rval;
+       }
+
+       addr = Memptr;
+
+       if( (req->r_data.write.r_uflags & F_WORD_ALIGNED) ) {
+               /*
+                * Force memory alignment for Direct I/O
+                */
+               if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
+                       addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
+               }
+       } else {
+               addr += random_range(0, wtob(1) - 1, 1, NULL);
+       }
+
+       (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+       if( addr != Memptr )
+               memmove( addr, Memptr, nbytes);
+
+#else /* sgi */
+       if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) {
+               return rval;
+       }
+
+       addr = Memptr;
+
+       (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+       if( addr != Memptr )
+               memmove( addr, Memptr, nbytes);
+#endif /* sgi */
+#endif /* CRAY */
+
+       rval = -1;
+       got_lock = 0;
+       logged_write = 0;
+
+       if (k_opt) {
+               if (lock_file_region(file, fd, F_WRLCK, offset, nbytes) < 0) {
+                       alloc_mem(-1);
+                       exit(E_INTERNAL);
+               }
+
+               got_lock = 1;
+       }
+
+       /*
+        * Write a preliminary write-log entry.  This is done so that
+        * doio_check can do corruption detection across an interrupt/crash.
+        * Note that w_done is set to 0.  If doio_check sees this, it
+        * re-creates the file extents as if the write completed, but does not
+        * do any checking - see comments in doio_check for more details.
+        */
+
+       if (w_opt) {
+               if (pid == -1) {
+                       pid = getpid();
+               }
+               wrec.w_async = (req->r_type == WRITEA) ? 1 : 0;
+               wrec.w_oflags = oflags;
+               wrec.w_pid = pid;
+               wrec.w_offset = offset;
+               wrec.w_nbytes = nbytes;
+
+               wrec.w_pathlen = strlen(file);
+               memcpy(wrec.w_path, file, wrec.w_pathlen);
+               wrec.w_hostlen = strlen(Host);
+               memcpy(wrec.w_host, Host, wrec.w_hostlen);
+               wrec.w_patternlen = Pattern_Length;
+               memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen);
+
+               wrec.w_done = 0;
+
+               if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) {
+                       doio_fprintf(stderr,
+                                    "Could not append to write-log:  %s (%d)\n",
+                                    SYSERR, errno);
+               } else {
+                       logged_write = 1;
+               }
+       }
+
+       switch (req->r_type ) {
+       case WRITE:
+               /*
+                * sync write
+                */
+
+               if (lseek(fd, offset, SEEK_SET) == -1) {
+                       doio_fprintf(stderr,
+                                    "lseek(%d, %d, SEEK_SET) failed:  %s (%d)\n",
+                                    fd, offset, SYSERR, errno);
+                       return -1;
+               }
+
+               rval = write(fd, addr, nbytes);
+
+               if (rval == -1) {
+                       doio_fprintf(stderr,
+                                    "write() failed:  %s (%d)\n%s\n",
+                                    SYSERR, errno,
+                                    format_rw(req, fd, addr, -1, Pattern, NULL));
+#ifndef NO_XFS
+                       doio_fprintf(stderr,
+                                    "write() failed:  %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%miniou(%d)=%d, oflags=%#o memalign=%d, addr%%memalign=%d\n",
+                                    strerror(errno),
+                                    fd, addr, nbytes,
+                                    offset,
+                                    fdc->c_miniosz, nbytes%fdc->c_miniosz,
+                                    oflags, fdc->c_memalign, (long)addr%fdc->c_memalign);
+#else
+                       doio_fprintf(stderr,
+                                    "write() failed:  %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%1B=%d, oflags=%#o\n",
+                                    strerror(errno),
+                                    fd, addr, nbytes,
+                                    offset, nbytes%4096, oflags);
+#endif
+                       doio_upanic(U_RVAL);
+               } else if (rval != nbytes) {
+                       doio_fprintf(stderr,
+                                    "write() returned wrong # bytes - expected %d, got %d\n%s\n",
+                                    nbytes, rval,
+                                    format_rw(req, fd, addr, -1, Pattern, NULL));
+                       doio_upanic(U_RVAL);
+                       rval = -1;
+               }
+
+               break;
+
+#ifdef CRAY
+       case WRITEA:
+               /*
+                * async write
+                */
+               if (lseek(fd, offset, SEEK_SET) == -1) {
+                       doio_fprintf(stderr,
+                                    "lseek(%d, %d, SEEK_SET) failed:  %s (%d)\n",
+                                    fd, offset, SYSERR, errno);
+                       return -1;
+               }
+
+               aio_strat = req->r_data.write.r_aio_strat;
+               signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+               aio_id = aio_register(fd, aio_strat, signo);
+               aiop = aio_slot(aio_id);
+
+               /*
+                * init iosw and do the async write
+                */
+
+               if (writea(fd, addr, nbytes, &aiop->iosw, signo) == -1) {
+                       doio_fprintf(stderr,
+                                    "writea() failed: %s (%d)\n%s\n",
+                                    SYSERR, errno,
+                                    format_rw(req, fd, addr, -1, Pattern, NULL));
+                       doio_upanic(U_RVAL);
+                       aio_unregister(aio_id);
+                       rval = -1;
+               } else {
+
+                       /*
+                        * Wait for io to complete
+                        */
+
+                       aio_wait(aio_id);
+
+                       /*
+                        * check that iosw is ok
+                        */
+
+                       if (aiop->iosw.sw_count != nbytes) {
+                               doio_fprintf(stderr,
+                                            "Bad iosw from writea()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
+                                            1, 0, nbytes,
+                                            aiop->iosw.sw_flag,
+                                            aiop->iosw.sw_error,
+                                            aiop->iosw.sw_count,
+                                            format_rw(req, fd, addr, -1, Pattern, &aiop->iosw));
+                               aio_unregister(aio_id);
+                               doio_upanic(U_IOSW);
+                               rval = -1;
+                       } else {
+                               aio_unregister(aio_id);
+                               rval = 0;
+                       }
+               }
+               break;
+
+#endif /* CRAY */
+       }
+
+       /*
+        * Verify that the data was written correctly - check_file() returns
+        * a non-null pointer which contains an error message if there are
+        * problems.
+        */
+
+       if (v_opt) {
+               msg = check_file(file, offset, nbytes, Pattern, Pattern_Length,
+                                0, oflags & O_PARALLEL);
+               if (msg != NULL) {
+                       doio_fprintf(stderr, "%s%s\n",
+                                    msg,
+#ifdef CRAY
+                                    format_rw(req, fd, addr, -1, Pattern, &aiop->iosw)
+#else
+                                    format_rw(req, fd, addr, -1, Pattern, NULL)
+#endif
+                               );
+                       doio_upanic(U_CORRUPTION);
+                       exit(E_COMPARE);
+
+               }
+       }
+
+       /*
+        * General cleanup ...
+        *
+        * Write extent information to the write-log, so that doio_check can do
+        * corruption detection.  Note that w_done is set to 1, indicating that
+        * the write has been verified as complete.  We don't need to write the
+        * filename on the second logging.
+        */
+
+       if (w_opt && logged_write) {
+               wrec.w_done = 1;
+               wlog_record_write(&Wlog, &wrec, woffset);
+       }
+
+       /*
+        * Unlock file region if necessary
+        */
+
+       if (got_lock) {
+               if (lock_file_region(file, fd, F_UNLCK, offset, nbytes) < 0) {
+                       alloc_mem(-1);
+                       exit(E_INTERNAL);
+               }
+       }
+
+       return( (rval == -1) ? -1 : 0);
+}
+
+
+/*
+ * Simple routine to lock/unlock a file using fcntl()
+ */
+
+int
+lock_file_region(fname, fd, type, start, nbytes)
+char   *fname;
+int    fd;
+int    type;
+int    start;
+int    nbytes;
+{
+       struct flock    flk;
+
+       flk.l_type = type;
+       flk.l_whence = 0;
+       flk.l_start = start;
+       flk.l_len = nbytes;
+
+       if (fcntl(fd, F_SETLKW, &flk) < 0) {
+               doio_fprintf(stderr,
+                            "fcntl(%d, %d, %#o) failed for file %s, lock type %d, offset %d, length %d:  %s (%d), open flags: %#o\n",
+                            fd, F_SETLKW, &flk, fname, type,
+                            start, nbytes, SYSERR, errno,
+                            fcntl(fd, F_GETFL, 0));
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Perform a listio request.
+ */
+
+#ifdef CRAY
+char *
+format_listio(
+       struct  io_req  *ioreq,
+       int             lcmd,
+       struct listreq  *list,
+       int             nent,
+       int             fd,
+       char            *pattern
+       )
+{
+       static  char            *errbuf=NULL;
+       struct  listio_req      *liop = &ioreq->r_data.listio;
+       struct  listreq         *listreq;
+       char                    *cp, *cmd, *opcode, *aio_strat;
+       int                     i;
+
+       switch (lcmd) {
+       case LC_START:  cmd = "LC_START";       break;
+       case LC_WAIT:   cmd = "LC_WAIT";        break;
+       default:        cmd = "???";            break;
+       }
+
+       if(errbuf == NULL)
+               errbuf = (char *)malloc(32768);
+
+       cp = errbuf;
+       cp += sprintf(cp, "Request number %d\n", Reqno);
+
+       cp += sprintf(cp, "syscall:  listio(%s, %#o, %d)\n\n",
+                     cmd, list, nent);
+
+       aio_strat = format_strat(liop->r_aio_strat);
+
+       for (i = 0; i < nent; i++) {
+               cp += sprintf(cp, "struct lioreq for request element %d\n", i);
+               cp += sprintf(cp, "----------------------------------------\n");
+
+               listreq = list + i;
+
+               switch (listreq->li_opcode) {
+               case LO_READ:   opcode = "LO_READ";     break;
+               case LO_WRITE:  opcode = "LO_WRITE";    break;
+               default:        opcode = "???";         break;
+               }
+                       
+               cp += sprintf(cp, "          li_opcode =    %s\n", opcode);
+               cp += sprintf(cp, "          li_drvr =      %#o\n", listreq->li_drvr);
+               cp += sprintf(cp, "          li_flags =     %#o\n", listreq->li_flags);
+               cp += sprintf(cp, "          li_offset =    %d\n", listreq->li_offset);
+               cp += sprintf(cp, "          li_fildes =    %d\n", listreq->li_fildes);
+               cp += sprintf(cp, "          li_buf =       %#o\n", listreq->li_buf);
+               cp += sprintf(cp, "          li_nbyte =     %d\n", listreq->li_nbyte);
+               cp += sprintf(cp, "          li_status =    %#o (%d, %d, %d)\n", listreq->li_status, listreq->li_status->sw_flag, listreq->li_status->sw_error, listreq->li_status->sw_count);
+               cp += sprintf(cp, "          li_signo =     %d\n", listreq->li_signo);
+               cp += sprintf(cp, "          li_nstride =   %d\n", listreq->li_nstride);
+               cp += sprintf(cp, "          li_filstride = %d\n", listreq->li_filstride);
+               cp += sprintf(cp, "          li_memstride = %d\n", listreq->li_memstride);
+               cp += sprintf(cp, "          io completion strategy is %s\n", aio_strat);
+       }
+       return errbuf;
+}
+#endif /* CRAY */
+
+int
+do_listio(req)
+struct io_req  *req;
+{
+#ifdef CRAY
+       struct listio_req       *lio;
+       int                     fd, oflags, signo, nb, i;
+       int                     logged_write, rval, got_lock;
+       int                     aio_strat, aio_id;
+       int                     min_byte, max_byte;
+       int                     mem_needed;
+       int                     foffset, fstride, mstride, nstrides;
+       char                    *moffset;
+       long                    offset, woffset;
+       char                    *addr, *msg;
+       sigset_t                block_mask, omask;
+       struct wlog_rec         wrec;
+       struct aio_info         *aiop;
+       struct listreq          lio_req;
+
+       lio = &req->r_data.listio;
+
+       /*
+        * If bytes per stride is less than the stride size, drop the request
+        * since it will cause overlapping strides, and we cannot predict
+        * the order they will complete in.
+        */
+
+       if (lio->r_filestride && abs(lio->r_filestride) < lio->r_nbytes) {
+               doio_fprintf(stderr, "do_listio():  Bogus listio request - abs(filestride) [%d] < nbytes [%d]\n",
+                            abs(lio->r_filestride), lio->r_nbytes);
+               return -1;
+       }
+
+       /*
+        * Allocate core memory.  Initialize the data to be written.  Make
+        * sure we get enough, based on the memstride.
+        */
+
+       mem_needed = 
+               stride_bounds(0, lio->r_memstride, lio->r_nstrides,
+                             lio->r_nbytes, NULL, NULL);
+
+       if ((rval = alloc_mem(mem_needed + wtob(1))) < 0) {
+               return rval;
+       }
+
+       /*
+        * Set the memory address pointer.  If the io is not raw, adjust
+        * addr by a random amount, so that non-raw io is not necessarily
+        * word aligned.
+        */
+
+       addr = Memptr;
+
+       if (! (lio->r_uflags & F_WORD_ALIGNED)) {
+               addr += random_range(0, wtob(1) - 1, 1, NULL);
+       }
+
+       if (lio->r_opcode == LO_WRITE) {
+               Pattern[0] = lio->r_pattern;
+               (*Data_Fill)(Memptr, mem_needed, Pattern, Pattern_Length, 0);
+               if( addr != Memptr )
+                       memmove( addr, Memptr, mem_needed);
+       }
+
+       /*
+        * Get a descriptor to do the io on.  No need to do an lseek, as this
+        * is encoded in the listio request.
+        */
+
+       if ((fd = alloc_fd(lio->r_file, lio->r_oflags)) == -1) {
+               return -1;
+       }
+
+       rval = -1;
+       got_lock = 0;
+       logged_write = 0;
+
+       /*
+        * If the opcode is LO_WRITE, lock all regions of the file that
+        * are touched by this listio request.  Currently, we use
+        * stride_bounds() to figure out the min and max bytes affected, and
+        * lock the entire region, regardless of the file stride.
+        */
+
+       if (lio->r_opcode == LO_WRITE && k_opt) {
+               stride_bounds(lio->r_offset,
+                             lio->r_filestride, lio->r_nstrides,
+                             lio->r_nbytes, &min_byte, &max_byte);
+
+               if (lock_file_region(lio->r_file, fd, F_WRLCK,
+                                    min_byte, (max_byte-min_byte+1)) < 0) {
+                       doio_fprintf(stderr, "stride_bounds(%d, %d, %d, %d, ..., ...) set min_byte to %d, max_byte to %d\n",
+                                    lio->r_offset, lio->r_filestride,
+                                    lio->r_nstrides, lio->r_nbytes, min_byte,
+                                    max_byte);
+                       return -1;
+               } else {
+                       got_lock = 1;
+               }
+       }
+
+       /*
+        * async write
+        */
+
+       aio_strat = lio->r_aio_strat;
+       signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+       aio_id = aio_register(fd, aio_strat, signo);
+       aiop = aio_slot(aio_id);
+
+       /*
+        * Form the listio request, and make the call.
+        */
+
+       lio_req.li_opcode = lio->r_opcode;
+       lio_req.li_drvr = 0;
+       lio_req.li_flags = LF_LSEEK;
+       lio_req.li_offset = lio->r_offset;
+       lio_req.li_fildes = fd;
+
+       if (lio->r_memstride >= 0 || lio->r_nstrides <= 1) {
+               lio_req.li_buf = addr;
+       } else {
+               lio_req.li_buf = addr + mem_needed - lio->r_nbytes;
+       }
+
+       lio_req.li_nbyte = lio->r_nbytes;
+       lio_req.li_status = &aiop->iosw;
+       lio_req.li_signo = signo;
+       lio_req.li_nstride = lio->r_nstrides;
+       lio_req.li_filstride = lio->r_filestride;
+       lio_req.li_memstride = lio->r_memstride;
+
+       /*
+        * If signo != 0, block signo while we're in the system call, so that
+        * we don't get interrupted syscall failures.
+        */
+
+       if (signo) {
+               sigemptyset(&block_mask);
+               sigaddset(&block_mask, signo);
+               sigprocmask(SIG_BLOCK, &block_mask, &omask);
+       }
+
+       if (listio(lio->r_cmd, &lio_req, 1) < 0) {
+               doio_fprintf(stderr,
+                            "listio() failed: %s (%d)\n%s\n",
+                            SYSERR, errno,
+                            format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
+               aio_unregister(aio_id);
+               doio_upanic(U_RVAL);
+               goto lio_done;
+       }
+
+       if (signo) {
+               sigprocmask(SIG_SETMASK, &omask, NULL);
+       }
+
+       /*
+        * Wait for io to complete
+        */
+
+       aio_wait(aio_id);
+
+       nstrides = lio->r_nstrides ? lio->r_nstrides : 1;
+       if (aiop->iosw.sw_count != lio->r_nbytes * nstrides) {
+               doio_fprintf(stderr,
+                            "Bad iosw from listio()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
+                            1, 0, lio->r_nbytes * lio->r_nstrides,
+                            aiop->iosw.sw_flag,
+                            aiop->iosw.sw_error, aiop->iosw.sw_count,
+                            format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
+               aio_unregister(aio_id);
+               doio_upanic(U_IOSW);
+               goto lio_done;
+       } 
+
+       aio_unregister(aio_id);
+
+       /*
+        * Verify that the data was written correctly - check_file() returns
+        * a non-null pointer which contains an error message if there are
+        * problems.
+        *
+        * For listio, we basically have to make 1 call to check_file for each
+        * stride.
+        */
+
+       if (v_opt && lio_req.li_opcode == LO_WRITE) {
+               fstride = lio->r_filestride ? lio->r_filestride : lio->r_nbytes;
+               mstride = lio->r_memstride ? lio->r_memstride : lio->r_nbytes;
+               foffset = lio->r_offset;
+
+               if (mstride> 0 || lio->r_nstrides <= 1) {
+                       moffset = addr;
+               } else {
+                       moffset = addr + mem_needed - lio->r_nbytes;
+               }
+
+               for (i = 0; i < lio_req.li_nstride; i++) {
+                       msg = check_file(lio->r_file,
+                                        foffset, lio->r_nbytes,
+                                        Pattern, Pattern_Length,
+                                        moffset - addr,
+                                        lio->r_oflags & O_PARALLEL);
+
+                       if (msg != NULL) {
+                               doio_fprintf(stderr, "%s\n%s\n",
+                                            msg,
+                            format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
+                               doio_upanic(U_CORRUPTION);
+                               exit(E_COMPARE);
+                       }
+
+                       moffset += mstride;
+                       foffset += fstride;
+               }
+
+       }
+
+       rval = 0;
+
+ lio_done:
+
+       /*
+        * General cleanup ...
+        *
+        */
+
+       /*
+        * Release file locks if necessary
+        */
+
+       if (got_lock) {
+               if (lock_file_region(lio->r_file, fd, F_UNLCK,
+                                    min_byte, (max_byte-min_byte+1)) < 0) {
+                       return -1;
+               }
+       }
+
+       return rval;
+#else
+       return -1;
+#endif
+}
+
+/*
+ * perform ssread/sswrite operations
+ */
+
+#ifdef _CRAY1
+
+int
+do_ssdio(req)
+struct io_req  *req;
+{
+       int         nbytes, nb;
+       char    errbuf[BSIZE];
+
+       nbytes = req->r_data.ssread.r_nbytes;
+
+       /*
+        * Grab core and sds space
+        */
+
+       if ((nb = alloc_mem(nbytes)) < 0)
+               return nb;
+
+       if (alloc_sds(nbytes) == -1)
+               return -1;
+
+       if (req->r_type == SSWRITE) {
+
+               /*
+                * Init data and ship it to the ssd
+                */
+
+               Pattern[0] = req->r_data.sswrite.r_pattern;
+               /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0);*/
+               (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+
+               if (sswrite((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) {
+                       doio_fprintf(stderr, "sswrite() failed:  %s (%d)\n%s\n",
+                                    SYSERR, errno,
+                                    format_sds(req, Memptr, Sdsptr, Pattern));
+                       doio_upanic(U_RVAL);
+                       return -1;
+               }
+       } else {
+               /*
+                * read from sds
+                */
+
+               if (ssread((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) {
+                       doio_fprintf(stderr, "ssread() failed: %s (%d)\n%s\n",
+                                    SYSERR, errno,
+                                    format_sds(req, Memptr, Sdsptr, Pattern));
+
+                       doio_upanic(U_RVAL);
+                       return -1;
+               }
+       }
+
+       /*
+        * Verify data if SSWRITE and v_opt
+        */
+
+       if (v_opt && req->r_type == SSWRITE) {
+               ssread((long)Memptr, (long)Sdsptr, btoc(nbytes));
+
+               if (pattern_check(Memptr, nbytes, Pattern, Pattern_Length, 0) == -1) {
+                       doio_fprintf(stderr,
+                                    "sds DATA COMPARE ERROR - ABORTING\n%s\n",
+                                    format_sds(req, Memptr, Sdsptr, Pattern));
+
+                       doio_upanic(U_CORRUPTION);
+                       exit(E_COMPARE);
+               }
+       }
+}
+
+#else
+
+#ifdef CRAY
+
+int
+do_ssdio(req)
+struct io_req  *req;
+{
+       doio_fprintf(stderr,
+                    "Internal Error - do_ssdio() called on a non-cray1 system\n");
+       alloc_mem(-1);
+       exit(E_INTERNAL);
+}
+
+#endif
+
+#endif /* _CRAY1 */
+
+\f
+/* ---------------------------------------------------------------------------
+ * 
+ * A new paradigm of doing the r/w system call where there is a "stub"
+ * function that builds the info for the system call, then does the system
+ * call; this is called by code that is common to all system calls and does
+ * the syscall return checking, async I/O wait, iosw check, etc.
+ *
+ * Flags:
+ *     WRITE, ASYNC, SSD/SDS, 
+ *     FILE_LOCK, WRITE_LOG, VERIFY_DATA,
+ */
+
+struct status {
+       int     rval;           /* syscall return */
+       int     err;            /* errno */
+       int     *aioid;         /* list of async I/O structures */
+};
+
+struct syscall_info {
+       char            *sy_name;
+       int             sy_type;
+       struct status   *(*sy_syscall)();
+       int             (*sy_buffer)();
+       char            *(*sy_format)();
+       int             sy_flags;
+       int             sy_bits;
+};
+
+#define        SY_WRITE                00001
+#define        SY_ASYNC                00010
+#define        SY_IOSW                 00020
+#define        SY_SDS                  00100
+
+char *
+fmt_ioreq(struct io_req *ioreq, struct syscall_info *sy, int fd)
+{
+       static char             *errbuf=NULL;
+       char                    *cp;
+       struct rw_req           *io;
+       struct smap             *aname;
+#ifdef CRAY
+       struct stat             sbuf;
+#endif
+
+       if(errbuf == NULL)
+               errbuf = (char *)malloc(32768);
+
+       io = &ioreq->r_data.io;
+
+       /*
+        * Look up async I/O completion strategy
+        */
+       for(aname=aionames;
+           aname->value != -1 && aname->value != io->r_aio_strat;
+           aname++)
+               ;
+
+       cp = errbuf;
+       cp += sprintf(cp, "Request number %d\n", Reqno);
+
+       cp += sprintf(cp, "          fd %d is file %s - open flags are %#o %s\n",
+                     fd, io->r_file, io->r_oflags, format_oflags(io->r_oflags));
+
+       if(sy->sy_flags & SY_WRITE) {
+               cp += sprintf(cp, "          write done at file offset %d - pattern is %c (%#o)\n",
+                             io->r_offset,
+                             (io->r_pattern == '\0') ? '?' : io->r_pattern, 
+                             io->r_pattern);
+       } else {
+               cp += sprintf(cp, "          read done at file offset %d\n",
+                     io->r_offset);
+       }
+
+       if(sy->sy_flags & SY_ASYNC) {
+               cp += sprintf(cp, "          async io completion strategy is %s\n",
+                             aname->string);
+       }
+
+       cp += sprintf(cp, "          number of requests is %d, strides per request is %d\n",
+                     io->r_nent, io->r_nstrides);
+
+       cp += sprintf(cp, "          i/o byte count = %d\n",
+                     io->r_nbytes);
+
+       cp += sprintf(cp, "          memory alignment is %s\n",
+                     (io->r_uflags & F_WORD_ALIGNED) ? "aligned" : "unaligned");
+
+#ifdef CRAY
+       if(io->r_oflags & O_RAW) {
+               cp += sprintf(cp, "          RAW I/O: offset %% 4096 = %d length %% 4096 = %d\n",
+                             io->r_offset % 4096, io->r_nbytes % 4096);
+               fstat(fd, &sbuf);
+               cp += sprintf(cp, "          optimal file xfer size: small: %d large: %d\n",
+                             sbuf.st_blksize, sbuf.st_oblksize);
+               cp += sprintf(cp, "          cblks %d cbits %#o\n",
+                             sbuf.st_cblks, sbuf.st_cbits);
+       }
+#endif
+#ifndef NO_XFS
+       if(io->r_oflags & O_DIRECT) {
+               struct dioattr  finfo;
+               
+               if(xfsctl(io->r_file, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
+                       cp += sprintf(cp, "          Error %s (%d) getting direct I/O info\n",
+                                     strerror(errno), errno);
+                       finfo.d_mem = 1;
+                       finfo.d_miniosz = 1;
+                       finfo.d_maxiosz = 1;
+               }
+
+               cp += sprintf(cp, "          DIRECT I/O: offset %% %d = %d length %% %d = %d\n",
+                             finfo.d_miniosz,
+                             io->r_offset % finfo.d_miniosz,
+                             io->r_nbytes,
+                             io->r_nbytes % finfo.d_miniosz);
+               cp += sprintf(cp, "          mem alignment 0x%x xfer size: small: %d large: %d\n",
+                             finfo.d_mem, finfo.d_miniosz, finfo.d_maxiosz);
+       }
+#endif
+
+       return(errbuf);
+}
+
+/*
+ * Issue listio requests
+ */
+#ifdef CRAY
+struct status *
+sy_listio(req, sysc, fd, addr)
+struct io_req  *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+       int             offset, nbytes, nstrides, nents, aio_strat;
+       int             aio_id, signo, o, i, lc;
+       char            *a;
+       struct listreq  *lio_req, *l;
+       struct aio_info *aiop;
+       struct status   *status;
+
+       /*
+        * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+        * r_nbytes are at the same offset in the read_req and reada_req
+        * structures.
+        */
+       offset    = req->r_data.io.r_offset;
+       nbytes    = req->r_data.io.r_nbytes;
+       nstrides  = req->r_data.io.r_nstrides;
+       nents     = req->r_data.io.r_nent;
+       aio_strat = req->r_data.io.r_aio_strat;
+
+       lc = (sysc->sy_flags & SY_ASYNC) ? LC_START : LC_WAIT;
+
+       status = (struct status *)malloc(sizeof(struct status));
+       if( status == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+               return NULL;
+       }
+       status->aioid = (int *)malloc( (nents+1) * sizeof(int) );
+       if( status->aioid == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+               return NULL;
+       }
+
+       signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+       lio_req = (struct listreq *)malloc(nents * sizeof(struct listreq));
+       if( lio_req == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+               return NULL;
+       }
+       for(l=lio_req,a=addr,o=offset,i=0;
+           i < nents;
+           l++, a+=nbytes, o+=nbytes, i++) {
+
+               aio_id = aio_register(fd, aio_strat, signo);
+               aiop = aio_slot(aio_id);
+               status->aioid[i] = aio_id;
+
+               l->li_opcode    = (sysc->sy_flags & SY_WRITE) ? LO_WRITE : LO_READ;
+               l->li_offset    = o;
+               l->li_fildes    = fd;
+               l->li_buf       = a;
+               l->li_nbyte     = nbytes;
+               l->li_status    = &aiop->iosw;
+               l->li_signo     = signo;
+               l->li_nstride   = nstrides;
+               l->li_filstride = 0;
+               l->li_memstride = 0;
+               l->li_drvr      = 0;
+               l->li_flags     = LF_LSEEK;
+       }
+
+       status->aioid[nents] = -1;              /* end sentinel */
+
+       if( (status->rval = listio(lc, lio_req, nents)) == -1) {
+               status->err = errno;
+       }
+
+       free(lio_req);
+       return(status);
+}
+
+/*
+ * Calculate the size of a request in bytes and min/max boundaries
+ *
+ * This assumes filestride & memstride = 0.
+ */
+int
+listio_mem(struct io_req *req, int offset, int fmstride,
+          int *min, int *max)
+{
+       int     i, size;
+
+       size = stride_bounds(offset, fmstride,
+                            req->r_data.io.r_nstrides*req->r_data.io.r_nent,
+                            req->r_data.io.r_nbytes, min, max);
+       return(size);
+}
+
+char *
+fmt_listio(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+       static char     *errbuf = NULL;
+       char            *cp;
+       char            *c, *opcode;
+       int             i;
+
+       if(errbuf == NULL){
+               errbuf = (char *)malloc(32768);
+               if( errbuf == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+                       return NULL;
+               }
+       }
+
+       c = (sy->sy_flags & SY_ASYNC) ? "lc_wait" : "lc_start";
+
+       cp = errbuf;
+       cp += sprintf(cp, "syscall:  listio(%s, (?), %d)\n",
+                     c, req->r_data.io.r_nent);
+
+       cp += sprintf(cp, "          data buffer at %#o\n", addr);
+
+       return(errbuf);
+}
+#endif /* CRAY */
+
+struct status *
+sy_pread(req, sysc, fd, addr)
+struct io_req  *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+       int rc;
+       struct status   *status;
+
+       rc = pread(fd, addr, req->r_data.io.r_nbytes,
+                  req->r_data.io.r_offset);
+
+       status = (struct status *)malloc(sizeof(struct status));
+       if( status == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+               return NULL;
+       }
+       status->aioid = NULL;
+       status->rval = rc;
+       status->err = errno;
+
+       return(status);
+}
+
+struct status *
+sy_pwrite(req, sysc, fd, addr)
+struct io_req  *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+       int rc;
+       struct status   *status;
+
+       rc = pwrite(fd, addr, req->r_data.io.r_nbytes,
+                   req->r_data.io.r_offset);
+
+       status = (struct status *)malloc(sizeof(struct status));
+       if( status == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+               return NULL;
+       }
+       status->aioid = NULL;
+       status->rval = rc;
+       status->err = errno;
+
+       return(status);
+}
+
+char *
+fmt_pread(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+       static char     *errbuf = NULL;
+       char            *cp;
+
+       if(errbuf == NULL){
+               errbuf = (char *)malloc(32768);
+               if( errbuf == NULL ){
+                       doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                               __FILE__, __LINE__);
+                       return NULL;
+               }
+       }
+
+       cp = errbuf;
+       cp += sprintf(cp, "syscall:  %s(%d, 0x%p, %d)\n",
+                     sy->sy_name, fd, addr, req->r_data.io.r_nbytes);
+       return(errbuf);
+}
+
+#ifndef CRAY
+struct status *
+sy_readv(req, sysc, fd, addr)
+struct io_req  *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+       struct status *sy_rwv();
+       return sy_rwv(req, sysc, fd, addr, 0);
+}
+
+struct status *
+sy_writev(req, sysc, fd, addr)
+struct io_req  *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+       struct status *sy_rwv();
+       return sy_rwv(req, sysc, fd, addr, 1);
+}
+
+struct status *
+sy_rwv(req, sysc, fd, addr, rw)
+struct io_req  *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+int rw;
+{
+       int rc;
+       struct status   *status;
+       struct iovec    iov[2];
+
+       status = (struct status *)malloc(sizeof(struct status));
+       if( status == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+               return NULL;
+       }
+       status->aioid = NULL;
+
+       /* move to the desired file position. */
+       if ((rc=lseek(fd, req->r_data.io.r_offset, SEEK_SET)) == -1) {
+               status->rval = rc;
+               status->err = errno;
+               return(status);
+       }
+
+       iov[0].iov_base = addr;
+       iov[0].iov_len = req->r_data.io.r_nbytes;
+
+       if(rw)
+               rc = writev(fd, iov, 1);
+       else
+               rc = readv(fd, iov, 1);
+       status->aioid = NULL;
+       status->rval = rc;
+       status->err = errno;
+       return(status);
+}
+
+char *
+fmt_readv(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+       static char     errbuf[32768];
+       char            *cp;
+
+       cp = errbuf;
+       cp += sprintf(cp, "syscall:  %s(%d, (iov on stack), 1)\n",
+                     sy->sy_name, fd);
+       return(errbuf);
+}
+#endif /* !CRAY */
+
+#ifdef sgi
+struct status *
+sy_aread(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+       struct status *sy_arw();
+       return sy_arw(req, sysc, fd, addr, 0);
+}
+
+struct status *
+sy_awrite(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+       struct status *sy_arw();
+       return sy_arw(req, sysc, fd, addr, 1);
+}
+
+/*
+  #define sy_aread(A, B, C, D) sy_arw(A, B, C, D, 0)
+  #define sy_awrite(A, B, C, D)        sy_arw(A, B, C, D, 1)
+ */
+
+struct status *
+sy_arw(req, sysc, fd, addr, rw)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+int rw;
+{
+       /* POSIX 1003.1b-1993 Async read */
+       struct status           *status;
+       int                     rc;
+       int                     aio_id, aio_strat, signo;
+       struct aio_info         *aiop;
+
+       status = (struct status *)malloc(sizeof(struct status));
+       if( status == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+               return NULL;
+       }
+       aio_strat = req->r_data.io.r_aio_strat;
+       signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+       aio_id = aio_register(fd, aio_strat, signo);
+       aiop = aio_slot(aio_id);
+
+       memset( (void *)&aiop->aiocb, 0, sizeof(aiocb_t));
+
+       aiop->aiocb.aio_fildes = fd;
+       aiop->aiocb.aio_nbytes = req->r_data.io.r_nbytes;
+       aiop->aiocb.aio_offset = req->r_data.io.r_offset;
+       aiop->aiocb.aio_buf = addr;
+       aiop->aiocb.aio_reqprio = 0;    /* must be 0 */
+       aiop->aiocb.aio_lio_opcode = 0;
+
+       if(aio_strat == A_SIGNAL) {     /* siginfo(2) stuff */
+               aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+               aiop->aiocb.aio_sigevent.sigev_signo = signo;
+       } else if(aio_strat == A_CALLBACK) {
+               aiop->aiocb.aio_sigevent.sigev_signo = 0;
+               aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
+               aiop->aiocb.aio_sigevent.sigev_func = cb_handler;
+               aiop->aiocb.aio_sigevent.sigev_value.sival_int = aio_id;
+       } else {
+               aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_NONE;
+               aiop->aiocb.aio_sigevent.sigev_signo = 0;
+       }
+
+       if(rw)
+               rc = aio_write(&aiop->aiocb);
+       else
+               rc = aio_read(&aiop->aiocb);
+
+       status->aioid = (int *)malloc( 2 * sizeof(int) );
+       if( status->aioid == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+               return NULL;
+       }
+       status->aioid[0] = aio_id;
+       status->aioid[1] = -1;
+       status->rval = rc;
+       status->err = errno;
+       return(status);
+}
+
+char *
+fmt_aread(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+       static char     errbuf[32768];
+       char            *cp;
+
+       cp = errbuf;
+       cp += sprintf(cp, "syscall:  %s(&aiop->aiocb)\n",
+                     sy->sy_name);
+       return(errbuf);
+}
+#endif /* sgi */
+
+#ifndef CRAY
+
+struct status *
+sy_mmread(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+       struct status *sy_mmrw();
+       return sy_mmrw(req, sysc, fd, addr, 0);
+}
+
+struct status *
+sy_mmwrite(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+       struct status *sy_mmrw();
+       return sy_mmrw(req, sysc, fd, addr, 1);
+}
+
+struct status *
+sy_mmrw(req, sysc, fd, addr, rw)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+int rw;
+{
+       /*
+        * mmap read/write
+        * This version is oriented towards mmaping the file to memory
+        * ONCE and keeping it mapped.
+        */
+       struct status           *status;
+       void                    *mrc, *memaddr;
+       struct fd_cache         *fdc;
+       struct stat             sbuf;
+
+       status = (struct status *)malloc(sizeof(struct status));
+       if( status == NULL ){
+               doio_fprintf(stderr, "malloc failed, %s/%d\n",
+                       __FILE__, __LINE__);
+               return NULL;
+       }
+       status->aioid = NULL;
+       status->rval = -1;
+
+       fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags);
+
+       if( fdc->c_memaddr == NULL ) {
+               if( fstat(fd, &sbuf) < 0 ){
+                       doio_fprintf(stderr, "fstat failed, errno=%d\n",
+                                    errno);
+                       status->err = errno;
+                       return(status);
+               }
+
+               fdc->c_memlen = (int)sbuf.st_size;
+               mrc = mmap(NULL, (int)sbuf.st_size,
+                    rw ? PROT_WRITE|PROT_READ : PROT_READ,
+                    MAP_SHARED, fd, 0);
+
+               if( mrc == MAP_FAILED ) {
+                       doio_fprintf(stderr, "mmap() failed - 0x%lx %d\n",
+                               mrc, errno);
+                       status->err = errno;
+                       return(status);
+               }
+
+               fdc->c_memaddr = mrc;
+       }
+
+       memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset);
+
+       active_mmap_rw = 1;
+       if(rw)
+               memcpy(memaddr, addr, req->r_data.io.r_nbytes);
+       else
+               memcpy(addr, memaddr, req->r_data.io.r_nbytes);
+       active_mmap_rw = 0;
+
+       status->rval = req->r_data.io.r_nbytes;
+       status->err = 0;
+       return(status);
+}
+
+char *
+fmt_mmrw(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+       static char     errbuf[32768];
+       char            *cp;
+       struct fd_cache *fdc;
+       void            *memaddr;
+
+       fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags);
+
+       cp = errbuf;
+       cp += sprintf(cp, "syscall:  %s(NULL, %d, %s, MAP_SHARED, %d, 0)\n",
+                     sy->sy_name,
+                     fdc->c_memlen,
+                     (sy->sy_flags & SY_WRITE) ? "PROT_WRITE" : "PROT_READ",
+                     fd);
+
+       cp += sprintf(cp, "\tfile is mmaped to: 0x%lx\n",
+                     (unsigned long) fdc->c_memaddr);
+
+       memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset);
+
+       cp += sprintf(cp, "\tfile-mem=0x%lx, length=%d, buffer=0x%lx\n",
+                     (unsigned long) memaddr, req->r_data.io.r_nbytes,
+                     (unsigned long) addr);
+                     
+       return(errbuf);
+}
+#endif /* !CRAY */
+
+struct syscall_info syscalls[] = {
+#ifdef CRAY
+       { "listio-read-sync",           LREAD,
+         sy_listio,    NULL,           fmt_listio,
+         SY_IOSW
+       },
+       { "listio-read-strides-sync",   LSREAD,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW
+       },
+       { "listio-read-reqs-sync",      LEREAD,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW
+       },
+       { "listio-read-async",          LREADA,
+         sy_listio,    NULL,           fmt_listio,
+         SY_IOSW | SY_ASYNC
+       },
+       { "listio-read-strides-async",  LSREADA,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW | SY_ASYNC
+       },
+       { "listio-read-reqs-async",     LEREADA,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW | SY_ASYNC
+       },
+       { "listio-write-sync",          LWRITE,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW | SY_WRITE
+       },
+       { "listio-write-strides-sync",  LSWRITE,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW | SY_WRITE
+       },
+       { "listio-write-reqs-sync",     LEWRITE,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW | SY_WRITE
+       },
+       { "listio-write-async",         LWRITEA,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW | SY_WRITE | SY_ASYNC
+       },
+       { "listio-write-strides-async", LSWRITEA,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW | SY_WRITE | SY_ASYNC
+       },
+       { "listio-write-reqs-async",    LEWRITEA,
+         sy_listio,    listio_mem,     fmt_listio,
+         SY_IOSW | SY_WRITE | SY_ASYNC
+       },
+#endif
+
+#ifdef sgi
+       { "aread",                      AREAD,
+         sy_aread,     NULL,           fmt_aread,
+         SY_IOSW | SY_ASYNC
+       },
+       { "awrite",                     AWRITE,
+         sy_awrite,    NULL,           fmt_aread,
+         SY_IOSW | SY_WRITE | SY_ASYNC
+       },
+#endif
+       { "pread",                      PREAD,
+         sy_pread,     NULL,           fmt_pread,
+         0
+       },
+       { "pwrite",                     PWRITE,
+         sy_pwrite,    NULL,           fmt_pread,
+         SY_WRITE
+       },
+
+#ifndef CRAY
+       { "readv",                      READV,
+         sy_readv,     NULL,           fmt_readv,
+         0
+       },
+       { "writev",                     WRITEV,
+         sy_writev,    NULL,           fmt_readv,
+         SY_WRITE
+       },
+       { "mmap-read",                  MMAPR,
+         sy_mmread,    NULL,           fmt_mmrw,
+         0
+       },
+       { "mmap-write",                 MMAPW,
+         sy_mmwrite,   NULL,           fmt_mmrw,
+         SY_WRITE
+       },
+#endif
+
+       { NULL,                         0,
+         0,            0,              0,
+         0
+       },
+};
+
+int
+do_rw(req)
+       struct io_req   *req;
+{
+       static int              pid = -1;
+       int                     fd, offset, nbytes, nstrides, nents, oflags;
+       int                     rval, mem_needed, i;
+       int                     logged_write, got_lock, woffset = 0, pattern;
+       int                     min_byte, max_byte;
+       char                    *addr, *file, *msg;
+       struct status           *s;
+       struct wlog_rec         wrec;
+       struct syscall_info     *sy;
+#if defined(CRAY) || defined(sgi)
+       struct aio_info         *aiop;
+       struct iosw             *iosw;
+#endif
+#ifndef NO_XFS
+       struct fd_cache         *fdc;
+#endif
+
+       /*
+        * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+        * r_nbytes are at the same offset in the read_req and reada_req
+        * structures.
+        */
+       file    = req->r_data.io.r_file;
+       oflags  = req->r_data.io.r_oflags;
+       offset  = req->r_data.io.r_offset;
+       nbytes  = req->r_data.io.r_nbytes;
+       nstrides= req->r_data.io.r_nstrides;
+       nents   = req->r_data.io.r_nent;
+       pattern = req->r_data.io.r_pattern;
+
+       if( nents >= MAX_AIO ) {
+               doio_fprintf(stderr, "do_rw: too many list requests, %d.  Maximum is %d\n",
+                            nents, MAX_AIO);
+               return(-1);
+       }
+
+       /*
+        * look up system call info
+        */
+       for(sy=syscalls; sy->sy_name != NULL && sy->sy_type != req->r_type; sy++)
+               ;
+
+       if(sy->sy_name == NULL) {
+               doio_fprintf(stderr, "do_rw: unknown r_type %d.\n",
+                            req->r_type);
+               return(-1);
+       }
+
+       /*
+        * Get an open file descriptor
+        * Note: must be done before memory allocation so that the direct i/o
+        *      information is available in mem. allocate
+        */
+
+       if ((fd = alloc_fd(file, oflags)) == -1)
+               return -1;
+
+       /*
+        * Allocate core memory and possibly sds space.  Initialize the
+        * data to be written.  Make sure we get enough, based on the
+        * memstride.
+        *
+        * need:
+        *      1 extra word for possible partial-word address "bump"
+        *      1 extra word for dynamic pattern overrun
+        *      MPP_BUMP extra words for T3E non-hw-aligned memory address.
+        */
+
+       if( sy->sy_buffer != NULL ) {
+               mem_needed = (*sy->sy_buffer)(req, 0, 0, NULL, NULL);
+       } else {
+               mem_needed = nbytes;
+       }
+
+#ifdef CRAY
+       if ((rval = alloc_mem(mem_needed + wtob(1) * 2 + MPP_BUMP * sizeof(UINT64_T))) < 0) {
+               return rval;
+       }
+#else
+#ifndef NO_XFS
+       /* get memory alignment for using DIRECT I/O */
+       fdc = alloc_fdcache(file, oflags);
+
+       if ((rval = alloc_mem(mem_needed + wtob(1) * 2 + fdc->c_memalign)) < 0) {
+               return rval;
+       }
+#else
+       if ((rval = alloc_mem(mem_needed + wtob(1) * 2)) < 0) {
+               return rval;
+       }
+#endif
+#endif /* CRAY */
+
+       Pattern[0] = pattern;
+
+       /*
+        * Allocate SDS space for backdoor write if desired
+        */
+
+       if (oflags & O_SSD) {
+#ifdef CRAY
+#ifndef _CRAYMPP
+               if (alloc_sds(nbytes) == -1)
+                       return -1;
+
+               if( sy->sy_flags & SY_WRITE ) {
+                       /*pattern_fill(Memptr, mem_needed, Pattern, Pattern_Length, 0);*/
+                       (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+
+                       if (sswrite((long)Memptr, Sdsptr, btoc(mem_needed)) == -1) {
+                               doio_fprintf(stderr, "sswrite(%d, %d, %d) failed:  %s (%d)\n",
+                                            (long)Memptr, Sdsptr, 
+                                            btoc(mem_needed), SYSERR, errno);
+                               fflush(stderr);
+                               return -1;
+                       }
+               }
+
+               addr = (char *)Sdsptr;
+#else
+               doio_fprintf(stderr, "Invalid O_SSD flag was generated for MPP system\n");
+               fflush(stderr);
+               return -1;
+#endif /* _CRAYMPP */
+#else  /* CRAY */
+               doio_fprintf(stderr, "Invalid O_SSD flag was generated for non-Cray system\n");
+               fflush(stderr);
+               return -1;
+#endif /* CRAY */
+       } else {
+               addr = Memptr;
+
+               /*
+                * if io is not raw, bump the offset by a random amount
+                * to generate non-word-aligned io.
+                *
+                * On MPP systems, raw I/O must start on an 0x80 byte boundary.
+                * For non-aligned I/O, bump the address from 1 to 8 words.
+                */
+
+               if (! (req->r_data.io.r_uflags & F_WORD_ALIGNED)) {
+#ifdef _CRAYMPP
+                       addr += random_range(0, MPP_BUMP, 1, NULL) * sizeof(int);
+#endif
+                       addr += random_range(0, wtob(1) - 1, 1, NULL);
+               }
+
+#ifndef NO_XFS
+               /*
+                * Force memory alignment for Direct I/O
+                */
+               if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
+                       addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
+               }
+#endif
+
+               /*
+                * FILL must be done on a word-aligned buffer.
+                * Call the fill function with Memptr which is aligned,
+                * then memmove it to the right place.
+                */
+               if (sy->sy_flags & SY_WRITE) {
+                       (*Data_Fill)(Memptr, mem_needed, Pattern, Pattern_Length, 0);
+                       if( addr != Memptr )
+                           memmove( addr, Memptr, mem_needed);
+               }
+       }
+
+       rval = 0;
+       got_lock = 0;
+       logged_write = 0;
+
+       /*
+        * Lock data if this is a write and locking option is set
+        */
+       if (sy->sy_flags & SY_WRITE && k_opt) {
+               if( sy->sy_buffer != NULL ) {
+                       (*sy->sy_buffer)(req, offset, 0, &min_byte, &max_byte);
+               } else {
+                       min_byte = offset;
+                       max_byte = offset + (nbytes * nstrides * nents);
+               }
+
+               if (lock_file_region(file, fd, F_WRLCK,
+                                    min_byte, (max_byte-min_byte+1)) < 0) {
+                   doio_fprintf(stderr, 
+                               "file lock failed:\n%s\n",
+                               fmt_ioreq(req, sy, fd));
+                   doio_fprintf(stderr, 
+                               "          buffer(req, %d, 0, 0x%x, 0x%x)\n",
+                               offset, min_byte, max_byte);
+                   alloc_mem(-1);
+                   exit(E_INTERNAL);
+               }
+
+               got_lock = 1;
+       }
+
+       /*
+        * Write a preliminary write-log entry.  This is done so that
+        * doio_check can do corruption detection across an interrupt/crash.
+        * Note that w_done is set to 0.  If doio_check sees this, it
+        * re-creates the file extents as if the write completed, but does not
+        * do any checking - see comments in doio_check for more details.
+        */
+
+       if (sy->sy_flags & SY_WRITE && w_opt) {
+               if (pid == -1) {
+                       pid = getpid();
+               }
+
+               wrec.w_async = (sy->sy_flags & SY_ASYNC) ? 1 : 0;
+               wrec.w_oflags = oflags;
+               wrec.w_pid = pid;
+               wrec.w_offset = offset;
+               wrec.w_nbytes = nbytes; /* mem_needed -- total length */
+
+               wrec.w_pathlen = strlen(file);
+               memcpy(wrec.w_path, file, wrec.w_pathlen);
+               wrec.w_hostlen = strlen(Host);
+               memcpy(wrec.w_host, Host, wrec.w_hostlen);
+               wrec.w_patternlen = Pattern_Length;
+               memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen);
+
+               wrec.w_done = 0;
+
+               if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) {
+                       doio_fprintf(stderr,
+                                    "Could not append to write-log:  %s (%d)\n",
+                                    SYSERR, errno);
+               } else {
+                       logged_write = 1;
+               }
+       }
+
+       s = (*sy->sy_syscall)(req, sy, fd, addr);
+
+       if( s->rval == -1 ) {
+               doio_fprintf(stderr,
+                            "%s() request failed:  %s (%d)\n%s\n%s\n",
+                            sy->sy_name, SYSERR, errno,
+                            fmt_ioreq(req, sy, fd),
+                            (*sy->sy_format)(req, sy, fd, addr));
+
+               doio_upanic(U_RVAL);
+
+               for(i=0; i < nents; i++) {
+                       if(s->aioid == NULL)
+                               break;
+                       aio_unregister(s->aioid[i]);
+               }
+               rval = -1;
+       } else {
+               /*
+                * If the syscall was async, wait for I/O to complete
+                */
+#ifndef linux
+               if(sy->sy_flags & SY_ASYNC) {
+                       for(i=0; i < nents; i++) {
+                               aio_wait(s->aioid[i]);
+                       }
+               }
+#endif
+
+               /*
+                * Check the syscall how-much-data-written return.  Look
+                * for this in either the return value or the 'iosw'
+                * structure.
+                */
+
+               if( sy->sy_flags & SY_IOSW ) {
+#ifdef CRAY
+                       for( i=0; i < nents; i++ ) {
+                               if(s->aioid == NULL)
+                                       break; /* >>> error condition? */
+                               aiop = aio_slot(s->aioid[i]);
+                               iosw = &aiop->iosw;
+                               if(iosw->sw_error != 0) {
+                                       doio_fprintf(stderr,
+                                                    "%s() iosw error set: %s\n%s\n%s\n",
+                                                    sy->sy_name,
+                                                    strerror(iosw->sw_error),
+                                                    fmt_ioreq(req, sy, fd),
+                                                    (*sy->sy_format)(req, sy, fd, addr));
+                                       doio_upanic(U_IOSW);
+                                       rval = -1;
+                               } else if(iosw->sw_count != nbytes*nstrides) {
+                                       doio_fprintf(stderr,
+                                                    "Bad iosw from %s() #%d\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n%s\n",
+                                                    sy->sy_name, i,
+                                                    1, 0, nbytes*nstrides,
+                                                    iosw->sw_flag,
+                                                    iosw->sw_error,
+                                                    iosw->sw_count,
+                                                    fmt_ioreq(req, sy, fd),
+                                                    (*sy->sy_format)(req, sy, fd, addr));
+                                       doio_upanic(U_IOSW);
+                                       rval = -1;
+                               }
+
+                               aio_unregister(s->aioid[i]);
+                       }
+#endif /* CRAY */
+#ifdef sgi
+                       for( i=0; s->aioid[i] != -1; i++ ) {
+                               if(s->aioid == NULL) {
+                                       doio_fprintf(stderr,
+                                                    "aioid == NULL!\n");
+                                       break;
+                               }
+                               aiop = aio_slot(s->aioid[i]);
+
+                               /*
+                                * make sure the io completed without error
+                                */
+                               if (aiop->aio_errno != 0) {
+                                       doio_fprintf(stderr,
+                                                    "%s() aio error set: %s (%d)\n%s\n%s\n",
+                                                    sy->sy_name,
+                                                    strerror(aiop->aio_errno),
+                                                    aiop->aio_errno,
+                                                    fmt_ioreq(req, sy, fd),
+                                                    (*sy->sy_format)(req, sy, fd, addr));
+                                       doio_upanic(U_IOSW);
+                                       rval = -1;
+                               } else if (aiop->aio_ret != nbytes) {
+                                       doio_fprintf(stderr,
+                                                    "Bad aio return from %s() #%d\nExpected (%d,%d), got (%d,%d)\n%s\n%s\n",
+                                                    sy->sy_name, i,
+                                                    0, nbytes,
+                                                    aiop->aio_errno,
+                                                    aiop->aio_ret,
+                                                    fmt_ioreq(req, sy, fd),
+                                                    (*sy->sy_format)(req, sy, fd, addr));
+                                       aio_unregister(s->aioid[i]);
+                                       doio_upanic(U_IOSW);
+                                       return -1;
+                               } else {
+                                       aio_unregister(s->aioid[i]);
+                                       rval = 0;
+                               }
+                       }
+#endif /* sgi */
+               } else {
+
+                       if(s->rval != mem_needed) {
+                               doio_fprintf(stderr,
+                                            "%s() request returned wrong # of bytes - expected %d, got %d\n%s\n%s\n",
+                                            sy->sy_name, nbytes, s->rval,
+                                            fmt_ioreq(req, sy, fd),
+                                            (*sy->sy_format)(req, sy, fd, addr));
+                               rval = -1;
+                               doio_upanic(U_RVAL);
+                       }
+               }
+       }
+
+
+       /*
+        * Verify that the data was written correctly - check_file() returns
+        * a non-null pointer which contains an error message if there are
+        * problems.
+        */
+
+       if ( rval == 0 && sy->sy_flags & SY_WRITE && v_opt) {
+               msg = check_file(file, offset, nbytes*nstrides*nents,
+                                Pattern, Pattern_Length, 0,
+                                oflags & O_PARALLEL);
+               if (msg != NULL) {
+                       doio_fprintf(stderr, "%s\n%s\n%s\n",
+                                    msg,
+                                    fmt_ioreq(req, sy, fd),
+                                    (*sy->sy_format)(req, sy, fd, addr));
+                       doio_upanic(U_CORRUPTION);
+                       exit(E_COMPARE);
+               }
+       }
+
+       /*
+        * General cleanup ...
+        *
+        * Write extent information to the write-log, so that doio_check can do
+        * corruption detection.  Note that w_done is set to 1, indicating that
+        * the write has been verified as complete.  We don't need to write the
+        * filename on the second logging.
+        */
+
+       if (w_opt && logged_write) {
+               wrec.w_done = 1;
+               wlog_record_write(&Wlog, &wrec, woffset);
+       }
+
+       /*
+        * Unlock file region if necessary
+        */
+
+       if (got_lock) {
+               if (lock_file_region(file, fd, F_UNLCK,
+                                    min_byte, (max_byte-min_byte+1)) < 0) {
+                       alloc_mem(-1);
+                       exit(E_INTERNAL);
+               }
+       }
+
+       if(s->aioid != NULL)
+               free(s->aioid);
+       free(s);
+       return (rval == -1) ? -1 : 0;
+}
+
+
+/*
+ * xfsctl-based requests
+ *   - XFS_IOC_RESVSP
+ *   - XFS_IOC_UNRESVSP
+ */
+#ifndef NO_XFS
+int
+do_xfsctl(req)
+       struct io_req   *req;
+{
+       int                     fd, oflags, offset, nbytes;
+       int                     rval, op = 0;
+       int                     got_lock;
+       int                     min_byte = 0, max_byte = 0;
+       char                    *file, *msg = NULL;
+       struct xfs_flock64      flk;
+
+       /*
+        * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+        * r_nbytes are at the same offset in the read_req and reada_req
+        * structures.
+        */
+       file    = req->r_data.io.r_file;
+       oflags  = req->r_data.io.r_oflags;
+       offset  = req->r_data.io.r_offset;
+       nbytes  = req->r_data.io.r_nbytes;
+
+       flk.l_type=0;
+       flk.l_whence=SEEK_SET;
+       flk.l_start=offset;
+       flk.l_len=nbytes;
+
+       /*
+        * Get an open file descriptor
+        */
+
+       if ((fd = alloc_fd(file, oflags)) == -1)
+               return -1;
+
+       rval = 0;
+       got_lock = 0;
+
+       /*
+        * Lock data if this is locking option is set
+        */
+       if (k_opt) {
+               min_byte = offset;
+               max_byte = offset + nbytes;
+
+               if (lock_file_region(file, fd, F_WRLCK,
+                                    min_byte, (nbytes+1)) < 0) {
+                   doio_fprintf(stderr, 
+                               "file lock failed:\n");
+                   doio_fprintf(stderr, 
+                               "          buffer(req, %d, 0, 0x%x, 0x%x)\n",
+                               offset, min_byte, max_byte);
+                   alloc_mem(-1);
+                   exit(E_INTERNAL);
+               }
+
+               got_lock = 1;
+       }
+
+       switch (req->r_type) {
+       case RESVSP:    op=XFS_IOC_RESVSP;      msg="resvsp";   break;
+       case UNRESVSP:  op=XFS_IOC_UNRESVSP;    msg="unresvsp"; break;
+       }
+
+       rval = xfsctl(file, fd, op, &flk);
+
+       if( rval == -1 ) {
+               doio_fprintf(stderr,
+"xfsctl %s request failed: %s (%d)\n\txfsctl(%d, %s %d, {%d %lld ==> %lld}\n",
+                            msg, SYSERR, errno,
+                            fd, msg, op, flk.l_whence, 
+                            (long long)flk.l_start, 
+                            (long long)flk.l_len);
+
+               doio_upanic(U_RVAL);
+               rval = -1;
+       }
+
+       /*
+        * Unlock file region if necessary
+        */
+
+       if (got_lock) {
+               if (lock_file_region(file, fd, F_UNLCK,
+                                    min_byte, (max_byte-min_byte+1)) < 0) {
+                       alloc_mem(-1);
+                       exit(E_INTERNAL);
+               }
+       }
+
+       return (rval == -1) ? -1 : 0;
+}
+#endif
+
+/*
+ *  fsync(2) and fdatasync(2)
+ */
+#ifndef CRAY
+int
+do_sync(req)
+       struct io_req   *req;
+{
+       int                     fd, oflags;
+       int                     rval;
+       char                    *file;
+
+       /*
+        * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+        * r_nbytes are at the same offset in the read_req and reada_req
+        * structures.
+        */
+       file    = req->r_data.io.r_file;
+       oflags  = req->r_data.io.r_oflags;
+
+       /*
+        * Get an open file descriptor
+        */
+
+       if ((fd = alloc_fd(file, oflags)) == -1)
+               return -1;
+
+       rval = 0;
+       switch(req->r_type) {
+       case FSYNC2:
+               rval = fsync(fd);
+               break;
+       case FDATASYNC:
+               rval = fdatasync(fd);
+               break;
+       default:
+               rval = -1;
+       }
+       return (rval == -1) ? -1 : 0;
+}
+#endif
+
+
+int
+doio_pat_fill(char *addr, int mem_needed, char *Pattern, int Pattern_Length,
+             int shift)
+{
+       return pattern_fill(addr, mem_needed, Pattern, Pattern_Length, 0);
+}
+
+char *
+doio_pat_check(buf, offset, length, pattern, pattern_length, patshift)
+char   *buf;
+int    offset;
+int    length;
+char   *pattern;
+int    pattern_length;
+int    patshift;
+{
+       static char     errbuf[4096];
+       int             nb, i, pattern_index;
+       char            *cp, *bufend, *ep;
+       char            actual[33], expected[33];
+
+       if (pattern_check(buf, length, pattern, pattern_length, patshift) != 0) {
+               ep = errbuf;
+               ep += sprintf(ep, "Corrupt regions follow - unprintable chars are represented as '.'\n");
+               ep += sprintf(ep, "-----------------------------------------------------------------\n");
+
+               pattern_index = patshift % pattern_length;;
+               cp = buf;
+               bufend = buf + length;
+
+               while (cp < bufend) {
+                       if (*cp != pattern[pattern_index]) {
+                               nb = bufend - cp;
+                               if (nb > sizeof(expected)-1) {
+                                       nb = sizeof(expected)-1;
+                               }
+                           
+                               ep += sprintf(ep, "corrupt bytes starting at file offset %d\n", offset + (int)(cp-buf));
+
+                               /*
+                                * Fill in the expected and actual patterns
+                                */
+                               bzero(expected, sizeof(expected));
+                               bzero(actual, sizeof(actual));
+
+                               for (i = 0; i < nb; i++) {
+                                       expected[i] = pattern[(pattern_index + i) % pattern_length];
+                                       if (! isprint(expected[i])) {
+                                               expected[i] = '.';
+                                       }
+
+                                       actual[i] = cp[i];
+                                       if (! isprint(actual[i])) {
+                                               actual[i] = '.';
+                                       }
+                               }
+
+                               ep += sprintf(ep, "    1st %2d expected bytes:  %s\n", nb, expected);
+                               ep += sprintf(ep, "    1st %2d actual bytes:    %s\n", nb, actual);
+                               fflush(stderr);
+                               return errbuf;
+                       } else {
+                               cp++;
+                               pattern_index++;
+
+                               if (pattern_index == pattern_length) {
+                                       pattern_index = 0;
+                               }
+                       }
+               }
+               return errbuf;
+       }
+
+       return(NULL);
+}
+
+
+/*
+ * Check the contents of a file beginning at offset, for length bytes.  It
+ * is assumed that there is a string of pattern bytes in this area of the
+ * file.  Use normal buffered reads to do the verification.
+ *
+ * If there is a data mismatch, write a detailed message into a static buffer
+ * suitable for the caller to print.  Otherwise print NULL.
+ *
+ * The fsa flag is set to non-zero if the buffer should be read back through
+ * the FSA (unicos/mk).  This implies the file will be opened
+ * O_PARALLEL|O_RAW|O_WELLFORMED to do the validation.  We must do this because
+ * FSA will not allow the file to be opened for buffered io if it was
+ * previously opened for O_PARALLEL io.
+ */
+
+char *
+check_file(file, offset, length, pattern, pattern_length, patshift, fsa)
+char   *file;
+int    offset;
+int    length;
+char   *pattern;
+int    pattern_length;
+int    patshift;
+int    fsa;
+{
+       static char     errbuf[4096];
+       int             fd, nb, flags;
+       char            *buf, *em, *ep;
+#ifndef NO_XFS
+       struct fd_cache *fdc;
+#endif
+
+       buf = Memptr;
+
+       if (V_opt) {
+               flags = Validation_Flags | O_RDONLY;
+       } else {
+               flags = O_RDONLY;
+               if (fsa) {
+#ifdef CRAY
+                       flags |= O_PARALLEL | O_RAW | O_WELLFORMED;
+#endif
+               }
+       }
+
+       if ((fd = alloc_fd(file, flags)) == -1) {
+               sprintf(errbuf,
+                       "Could not open file %s with flags %#o (%s) for data comparison:  %s (%d)\n",
+                       file, flags, format_oflags(flags),
+                       SYSERR, errno);
+               return errbuf;
+       }
+
+       if (lseek(fd, offset, SEEK_SET) == -1) {
+               sprintf(errbuf, 
+                       "Could not lseek to offset %d in %s for verification:  %s (%d)\n",
+                       offset, file, SYSERR, errno);
+               return errbuf;
+       }
+
+#ifndef NO_XFS
+       /* Guarantee a properly aligned address on Direct I/O */
+       fdc = alloc_fdcache(file, flags);
+       if( (flags & O_DIRECT) && ((long)buf % fdc->c_memalign != 0) ) {
+               buf += fdc->c_memalign - ((long)buf % fdc->c_memalign);
+       }
+#endif
+
+       if ((nb = read(fd, buf, length)) == -1) {
+#ifndef NO_XFS
+               sprintf(errbuf,
+                       "Could not read %d bytes from %s for verification:  %s (%d)\n\tread(%d, 0x%p, %d)\n\tbuf %% alignment(%d) = %ld\n",
+                       length, file, SYSERR, errno,
+                       fd, buf, length,
+                       fdc->c_memalign, (long)buf % fdc->c_memalign);
+#else
+               sprintf(errbuf,
+                       "Could not read %d bytes from %s for verification:  %s (%d)\n",
+                       length, file, SYSERR, errno);
+
+#endif
+               return errbuf;
+       }
+
+       if (nb != length) {
+               sprintf(errbuf,
+                       "Read wrong # bytes from %s.  Expected %d, got %d\n",
+                       file, length, nb);
+               return errbuf;
+       }
+    
+       if( (em = (*Data_Check)(buf, offset, length, pattern, pattern_length, patshift)) != NULL ) {
+               ep = errbuf;
+               ep += sprintf(ep, "*** DATA COMPARISON ERROR ***\n");
+               ep += sprintf(ep, "check_file(%s, %d, %d, %s, %d, %d) failed\n\n",
+                             file, offset, length, pattern, pattern_length, patshift);
+               ep += sprintf(ep, "Comparison fd is %d, with open flags %#o\n",
+                             fd, flags);
+               strcpy(ep, em);
+               return(errbuf);
+       }
+       return NULL;
+}
+
+/*
+ * Function to single-thread stdio output.
+ */
+
+int
+doio_fprintf(FILE *stream, char *format, ...)
+{
+       static int      pid = -1;
+       char            *date;
+       int             rval;
+       struct flock    flk;
+       va_list         arglist;
+
+       date = hms(time(0));
+
+       if (pid == -1) {
+               pid = getpid();
+       }
+
+       flk.l_whence = flk.l_start = flk.l_len = 0;
+       flk.l_type = F_WRLCK;
+       fcntl(fileno(stream), F_SETLKW, &flk);
+
+       va_start(arglist, format);
+       rval = fprintf(stream, "\n%s%s (%5d) %s\n", Prog, TagName, pid, date);
+       rval += fprintf(stream, "---------------------\n");
+       vfprintf(stream, format, arglist);
+       va_end(arglist);
+
+       fflush(stream);
+
+       flk.l_type = F_UNLCK;
+       fcntl(fileno(stream), F_SETLKW, &flk);
+       return rval;
+}
+
+/*
+ * Simple function for allocating core memory.  Uses Memsize and Memptr to
+ * keep track of the current amount allocated.
+ */
+#ifndef CRAY
+int
+alloc_mem(nbytes)
+int nbytes;
+{
+       char            *cp;
+       void            *addr;
+       int             me = 0, flags, key, shmid;
+       static int      mturn = 0;      /* which memory type to use */
+       struct memalloc *M;
+       char            filename[255];
+#ifdef linux
+       struct shmid_ds shm_ds;
+#endif
+
+#ifdef linux
+       bzero( &shm_ds, sizeof(struct shmid_ds) );
+#endif
+
+       /* nbytes = -1 means "free all allocated memory" */
+       if( nbytes == -1 ) {
+
+               for(me=0; me < Nmemalloc; me++) {
+                       if(Memalloc[me].space == NULL)
+                               continue;
+
+                       switch(Memalloc[me].memtype) {
+                       case MEM_DATA:
+#ifdef sgi
+                               if(Memalloc[me].flags & MEMF_MPIN)
+                                       munpin(Memalloc[me].space,
+                                              Memalloc[me].size);
+#endif
+                               free(Memalloc[me].space);
+                               Memalloc[me].space = NULL;
+                               Memptr = NULL;
+                               Memsize = 0;
+                               break;
+                       case MEM_SHMEM:
+#ifdef sgi
+                               if(Memalloc[me].flags & MEMF_MPIN)
+                                       munpin(Memalloc[me].space,
+                                              Memalloc[me].size);
+#endif
+                               shmdt(Memalloc[me].space);
+                               Memalloc[me].space = NULL;
+#ifdef sgi
+                               shmctl(Memalloc[me].fd, IPC_RMID);
+#else
+                               shmctl(Memalloc[me].fd, IPC_RMID, &shm_ds);
+#endif
+                               break;
+                       case MEM_MMAP:
+#ifdef sgi
+                               if(Memalloc[me].flags & MEMF_MPIN)
+                                       munpin(Memalloc[me].space,
+                                              Memalloc[me].size);
+#endif
+                               munmap(Memalloc[me].space, 
+                                      Memalloc[me].size);
+                               close(Memalloc[me].fd);
+                               if(Memalloc[me].flags & MEMF_FILE) {
+                                       unlink(Memalloc[me].name);
+                               }
+                               Memalloc[me].space = NULL;
+                               break;
+                       default:
+                               doio_fprintf(stderr, "alloc_mem: HELP! Unknown memory space type %d index %d\n",
+                                            Memalloc[me].memtype, me);
+                               break;
+                       }
+               }
+               return 0;
+       }
+
+       /*
+        * Select a memory area (currently round-robbin)
+        */
+
+       if(mturn >= Nmemalloc)
+               mturn=0;
+
+       M = &Memalloc[mturn];
+
+       switch(M->memtype) {
+       case MEM_DATA:
+               if( nbytes > M->size ) {
+                       if( M->space != NULL ){
+#ifdef sgi
+                               if( M->flags & MEMF_MPIN )
+                                       munpin( M->space, M->size );
+#endif
+                               free(M->space);
+                       }
+                       M->space = NULL;
+                       M->size = 0;
+               }
+
+               if( M->space == NULL ) {
+                       if( (cp = malloc( nbytes )) == NULL ) {
+                               doio_fprintf(stderr, "malloc(%d) failed:  %s (%d)\n",
+                                            nbytes, SYSERR, errno);
+                               return -1;
+                       }
+#ifdef sgi
+                       if(M->flags & MEMF_MPIN) {
+                               if( mpin(cp, nbytes) == -1 ) {
+                                       doio_fprintf(stderr, "mpin(0x%lx, %d) failed:  %s (%d)\n",
+                                            cp, nbytes, SYSERR, errno);
+                               }
+                       }
+#endif
+                       M->space = (void *)cp;
+                       M->size = nbytes;
+               }
+               break;
+
+       case MEM_MMAP:
+               if( nbytes > M->size ) {
+                       if( M->space != NULL ) {
+#ifdef sgi
+                               if( M->flags & MEMF_MPIN )
+                                       munpin(M->space, M->size);
+#endif
+                               munmap(M->space, M->size);
+                               close(M->fd);
+                               if( M->flags & MEMF_FILE )
+                                       unlink( M->name );
+                       }
+                       M->space = NULL;
+                       M->size = 0;
+               }
+
+               if( M->space == NULL ) {
+                       if(strchr(M->name, '%')) {
+                               sprintf(filename, M->name, getpid());
+                               M->name = strdup(filename);
+                       }
+
+                       if( (M->fd = open(M->name, O_CREAT|O_RDWR, 0666)) == -1) {
+                               doio_fprintf(stderr, "alloc_mmap: error %d (%s) opening '%s'\n",
+                                            errno, SYSERR, 
+                                            M->name);
+                               return(-1);
+                       }
+
+                       addr = NULL;
+                       flags = 0;
+                       M->size = nbytes * 4;
+
+                       /* bias addr if MEMF_ADDR | MEMF_FIXADDR */
+                       /* >>> how to pick a memory address? */
+
+                       /* bias flags on MEMF_PRIVATE etc */
+                       if(M->flags & MEMF_PRIVATE)
+                               flags |= MAP_PRIVATE;
+#ifdef sgi
+                       if(M->flags & MEMF_LOCAL)
+                               flags |= MAP_LOCAL;
+                       if(M->flags & MEMF_AUTORESRV)
+                               flags |= MAP_AUTORESRV;
+                       if(M->flags & MEMF_AUTOGROW)
+                               flags |= MAP_AUTOGROW;
+#endif
+                       if(M->flags & MEMF_SHARED)
+                               flags |= MAP_SHARED;
+
+/*printf("alloc_mem, about to mmap, fd=%d, name=(%s)\n", M->fd, M->name);*/
+                       if( (M->space = mmap(addr, M->size,
+                                            PROT_READ|PROT_WRITE,
+                                            flags, M->fd, 0))
+                           == MAP_FAILED) {
+                               doio_fprintf(stderr, "alloc_mem: mmap error. errno %d (%s)\n\tmmap(addr 0x%x, size %d, read|write 0x%x, mmap flags 0x%x [%#o], fd %d, 0)\n\tfile %s\n",
+                                            errno, SYSERR,
+                                            addr, M->size,
+                                            PROT_READ|PROT_WRITE,
+                                            flags, M->flags, M->fd,
+                                            M->name);
+                               doio_fprintf(stderr, "\t%s%s%s%s%s",
+                                            (flags & MAP_PRIVATE) ? "private " : "",
+#ifdef sgi
+                                            (flags & MAP_LOCAL) ? "local " : "",
+                                            (flags & MAP_AUTORESRV) ? "autoresrv " : "",
+                                            (flags & MAP_AUTOGROW) ? "autogrow " : "",
+#endif
+                                            (flags & MAP_SHARED) ? "shared" : "");
+                               return(-1);
+                       }
+               }
+               break;
+               
+       case MEM_SHMEM:
+               if( nbytes > M->size ) {
+                       if( M->space != NULL ) {
+#ifdef sgi
+                               if( M->flags & MEMF_MPIN )
+                                       munpin(M->space, M->size);
+#endif
+                               shmdt( M->space );
+#ifdef sgi
+                               shmctl( M->fd, IPC_RMID );
+#else
+                               shmctl( M->fd, IPC_RMID, &shm_ds );
+#endif
+                       }
+                       M->space = NULL;
+                       M->size = 0;
+               }
+
+               if(M->space == NULL) {
+                       if(!strcmp(M->name, "private")) {
+                               key = IPC_PRIVATE;
+                       } else {
+                               sscanf(M->name, "%i", &key);
+                       }
+
+                       M->size = M->nblks ? M->nblks * 512 : nbytes;
+
+                       if( nbytes > M->size ){
+#ifdef DEBUG
+                               doio_fprintf(stderr, "MEM_SHMEM: nblks(%d) too small:  nbytes=%d  Msize=%d, skipping this req.\n",
+                                            M->nblks, nbytes, M->size );
+#endif
+                               return SKIP_REQ;
+                       }
+
+                       shmid = shmget(key, M->size, IPC_CREAT|0666);
+                       if( shmid == -1 ) {
+                               doio_fprintf(stderr, "shmget(0x%x, %d, CREAT) failed: %s (%d)\n",
+                                            key, M->size, SYSERR, errno);
+                               return(-1);
+                       }
+                       M->fd = shmid;
+                       M->space = shmat(shmid, NULL, SHM_RND);
+                       if( M->space == (void *)-1 ) {
+                               doio_fprintf(stderr, "shmat(0x%x, NULL, SHM_RND) failed: %s (%d)\n", 
+                                            shmid, SYSERR, errno);
+                               return(-1);
+                       }
+#ifdef sgi
+                       if(M->flags & MEMF_MPIN) {
+                               if( mpin(M->space, M->size) == -1 ) {
+                                       doio_fprintf(stderr, "mpin(0x%lx, %d) failed:  %s (%d)\n",
+                                                    M->space, M->size, SYSERR, errno);
+                           }
+                       }
+#endif
+               }
+               break;
+
+       default:
+               doio_fprintf(stderr, "alloc_mem: HELP! Unknown memory space type %d index %d\n",
+                            Memalloc[me].memtype, mturn);
+               break;
+       }
+
+       Memptr = M->space;
+       Memsize = M->size;
+
+       mturn++;
+       return 0;
+}
+#endif /* !CRAY */
+
+#ifdef CRAY
+int
+alloc_mem(nbytes)
+int nbytes;
+{
+       char    *cp;
+       int     ip;
+       static  char    *malloc_space;
+
+       /*
+        * The "unicos" version of this did some stuff with sbrk;
+        * this caused problems with async I/O on irix, and now appears
+        * to be causing problems with FSA I/O on unicos/mk.
+        */
+#ifdef NOTDEF
+       if (nbytes > Memsize) {
+               if ((cp = (char *)sbrk(nbytes - Memsize)) == (char *)-1) {
+                       doio_fprintf(stderr, "sbrk(%d) failed:  %s (%d)\n",
+                                    nbytes - Memsize, SYSERR, errno);
+                       return -1;
+               }
+
+               if (Memsize == 0)
+                       Memptr = cp;
+               Memsize += nbytes - Memsize;
+       }
+#else
+
+       /* nbytes = -1 means "free all allocated memory" */
+       if( nbytes == -1 ) {
+               free( malloc_space );
+               Memptr = NULL;
+               Memsize = 0;
+               return 0;
+       }
+
+       if( nbytes > Memsize ) {
+           if( Memsize != 0 )
+               free( malloc_space );
+
+           if( (cp = malloc_space = malloc( nbytes )) == NULL ) {
+               doio_fprintf(stderr, "malloc(%d) failed:  %s (%d)\n",
+                            nbytes, SYSERR, errno);
+               return -1;
+           }
+
+#ifdef _CRAYT3E
+           /* T3E requires memory to be aligned on 0x40 word boundaries */
+           ip = (int)cp;
+           if( ip & 0x3F != 0 ) {
+               doio_fprintf(stderr, "malloc(%d) = 0x%x(0x%x) not aligned by 0x%x\n",
+                            nbytes, cp, ip, ip & 0x3f);
+
+               free(cp);
+               if( (cp = malloc_space = malloc( nbytes + 0x40 )) == NULL ) {
+                   doio_fprintf(stderr, "malloc(%d) failed:  %s (%d)\n",
+                                nbytes, SYSERR, errno);
+                   return -1;
+               }
+               ip = (int)cp;
+               cp += (0x40 - (ip & 0x3F));
+           }
+#endif /* _CRAYT3E */
+           Memptr = cp;
+           Memsize = nbytes;
+       }
+#endif /* NOTDEF */
+       return 0;
+}
+#endif /* CRAY */
+
+/*
+ * Simple function for allocating sds space.  Uses Sdssize and Sdsptr to
+ * keep track of location and size of currently allocated chunk.
+ */
+
+#ifdef _CRAY1
+
+int
+alloc_sds(nbytes)
+int nbytes;
+{
+       int nblks;
+
+       if (nbytes > Sdssize) {
+               if ((nblks = ssbreak(btoc(nbytes - Sdssize))) == -1) {
+                       doio_fprintf(stderr, "ssbreak(%d) failed:  %s (%d)\n",
+                                    btoc(nbytes - Sdssize), SYSERR, errno);
+                       return -1;
+               }
+
+               Sdssize = ctob(nblks);
+               Sdsptr = 0;
+       }
+
+       return 0;
+}
+
+#else
+
+#ifdef CRAY
+
+int
+alloc_sds(nbytes)
+int    nbytes;
+{
+       doio_fprintf(stderr,
+                    "Internal Error - alloc_sds() called on a CRAY2 system\n");
+       alloc_mem(-1);
+       exit(E_INTERNAL);
+}
+
+#endif
+
+#endif /* _CRAY1 */
+
+/*
+ * Function to maintain a file descriptor cache, so that doio does not have
+ * to do so many open() and close() calls.  Descriptors are stored in the
+ * cache by file name, and open flags.  Each entry also has a _rtc value
+ * associated with it which is used in aging.  If doio cannot open a file
+ * because it already has too many open (ie. system limit hit) it will close
+ * the one in the cache that has the oldest _rtc value.
+ *
+ * If alloc_fd() is called with a file of NULL, it will close all descriptors
+ * in the cache, and free the memory in the cache.
+ */
+
+int
+alloc_fd(file, oflags)
+char   *file;
+int    oflags;
+{
+       struct fd_cache *fdc;
+       struct fd_cache *alloc_fdcache(char *file, int oflags);
+
+       fdc = alloc_fdcache(file, oflags);
+       if(fdc != NULL)
+               return(fdc->c_fd);
+       else
+               return(-1);
+}
+
+struct fd_cache *
+alloc_fdcache(file, oflags)
+char   *file;
+int    oflags;
+{
+       int                     fd;
+       struct fd_cache         *free_slot, *oldest_slot, *cp;
+       static int              cache_size = 0;
+       static struct fd_cache  *cache = NULL;
+#ifndef NO_XFS
+       struct dioattr  finfo;
+#endif
+
+       /*
+        * If file is NULL, it means to free up the fd cache.
+        */
+
+       if (file == NULL && cache != NULL) {
+               for (cp = cache; cp < &cache[cache_size]; cp++) {
+                       if (cp->c_fd != -1) {
+                               close(cp->c_fd);
+                       }
+#ifndef CRAY
+                       if (cp->c_memaddr != NULL) {
+                               munmap(cp->c_memaddr, cp->c_memlen);
+                       }
+#endif
+               }
+
+               free(cache);
+               cache = NULL;
+               cache_size = 0;
+                return 0;
+       }
+
+       free_slot = NULL;
+       oldest_slot = NULL;
+
+       /*
+        * Look for a fd in the cache.  If one is found, return it directly.
+        * Otherwise, when this loop exits, oldest_slot will point to the
+        * oldest fd slot in the cache, and free_slot will point to an
+        * unoccupied slot if there are any.
+        */
+
+       for (cp = cache; cp != NULL && cp < &cache[cache_size]; cp++) {
+               if (cp->c_fd != -1 &&
+                   cp->c_oflags == oflags &&
+                   strcmp(cp->c_file, file) == 0) {
+#ifdef CRAY
+                       cp->c_rtc = _rtc();
+#else
+                       cp->c_rtc = Reqno;
+#endif
+                       return cp;
+               }
+
+               if (cp->c_fd == -1) {
+                       if (free_slot == NULL) {
+                               free_slot = cp;
+                       }
+               } else {
+                       if (oldest_slot == NULL || 
+                           cp->c_rtc < oldest_slot->c_rtc) {
+                               oldest_slot = cp;
+                       }
+               }
+       }
+
+       /*
+        * No matching file/oflags pair was found in the cache.  Attempt to
+        * open a new fd.
+        */
+
+       if ((fd = open(file, oflags, 0666)) < 0) {
+               if (errno != EMFILE) {
+                       doio_fprintf(stderr,
+                                    "Could not open file %s with flags %#o (%s): %s (%d)\n",
+                                    file, oflags, format_oflags(oflags),
+                                    SYSERR, errno);
+                       alloc_mem(-1);
+                       exit(E_SETUP);
+               }
+
+               /*
+                * If we get here, we have as many open fd's as we can have.
+                * Close the oldest one in the cache (pointed to by
+                * oldest_slot), and attempt to re-open.
+                */
+
+               close(oldest_slot->c_fd);
+               oldest_slot->c_fd = -1;
+               free_slot = oldest_slot;
+
+               if ((fd = open(file, oflags, 0666)) < 0) {
+                       doio_fprintf(stderr,
+                                    "Could not open file %s with flags %#o (%s):  %s (%d)\n",
+                                    file, oflags, format_oflags(oflags),
+                                    SYSERR, errno);
+                       alloc_mem(-1);
+                       exit(E_SETUP);
+               }
+       }
+
+/*printf("alloc_fd: new file %s flags %#o fd %d\n", file, oflags, fd);*/
+
+       /*
+        * If we get here, fd is our open descriptor.  If free_slot is NULL,
+        * we need to grow the cache, otherwise free_slot is the slot that
+        * should hold the fd info.
+        */
+
+       if (free_slot == NULL) {
+               cache = (struct fd_cache *)realloc(cache, sizeof(struct fd_cache) * (FD_ALLOC_INCR + cache_size));
+               if (cache == NULL) {
+                       doio_fprintf(stderr, "Could not malloc() space for fd chace");
+                       alloc_mem(-1);
+                       exit(E_SETUP);
+               }
+
+               cache_size += FD_ALLOC_INCR;
+
+               for (cp = &cache[cache_size-FD_ALLOC_INCR];
+                    cp < &cache[cache_size]; cp++) {
+                       cp->c_fd = -1;
+               }
+
+               free_slot = &cache[cache_size - FD_ALLOC_INCR];
+       }
+
+       /*
+        * finally, fill in the cache slot info
+        */
+
+       free_slot->c_fd = fd;
+       free_slot->c_oflags = oflags;
+       strcpy(free_slot->c_file, file);
+#ifdef CRAY
+       free_slot->c_rtc = _rtc();
+#else
+       free_slot->c_rtc = Reqno;
+#endif
+
+#ifndef NO_XFS
+       if (oflags & O_DIRECT) {
+               if (xfsctl(file, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
+                       finfo.d_mem = 1;
+                       finfo.d_miniosz = 1;
+                       finfo.d_maxiosz = 1;
+               }
+       } else {
+               finfo.d_mem = 1;
+               finfo.d_miniosz = 1;
+               finfo.d_maxiosz = 1;
+       }
+
+       free_slot->c_memalign = finfo.d_mem;
+       free_slot->c_miniosz = finfo.d_miniosz;
+       free_slot->c_maxiosz = finfo.d_maxiosz;
+#endif
+#ifndef CRAY
+       free_slot->c_memaddr = NULL;
+       free_slot->c_memlen = 0;
+#endif
+
+       return free_slot;
+}
+
+/*
+ *
+ *                     Signal Handling Section
+ *
+ *
+ */
+
+#ifdef sgi
+/*
+ * "caller-id" for signals
+ */
+void
+signal_info(int sig, siginfo_t *info, void *v)
+{
+       int haveit = 0;
+
+       if(info != NULL) {
+               switch(info->si_code) {
+               case SI_USER:
+                       doio_fprintf(stderr,
+                                    "signal_info: si_signo %d si_errno %d si_code SI_USER pid %d uid %d\n",
+                                    info->si_signo, info->si_errno, 
+                                    info->si_pid, info->si_uid);
+                       haveit = 1;
+                       break;
+
+               case SI_QUEUE:
+                       doio_fprintf(stderr, "signal_info  si_signo %d si_code = SI_QUEUE\n",
+                                    info->si_signo);
+                       haveit = 1;
+                       break;
+               }
+
+               if( ! haveit ){
+                       if( (info->si_signo == SIGSEGV) ||
+                          (info->si_signo == SIGBUS) ){
+                               doio_fprintf(stderr, "signal_info  si_signo %d si_errno %d si_code = %d  si_addr=%p  active_mmap_rw=%d havesigint=%d\n",
+                                            info->si_signo, info->si_errno,
+                                            info->si_code, info->si_addr,
+                                            active_mmap_rw,
+                                            havesigint);
+                               haveit = 1;
+                          }
+               }
+
+               if( !haveit ){
+                       doio_fprintf(stderr, "signal_info: si_signo %d si_errno %d unknown code %d\n",
+                                    info->si_signo, info->si_errno,
+                                    info->si_code);
+               }
+       } else {
+               doio_fprintf(stderr, "signal_info: sig %d\n", sig);
+       }
+}
+#endif
+
+#ifdef sgi
+void
+cleanup_handler(int sig, siginfo_t *info, void *v)
+{
+       havesigint=1; /* in case there's a followup signal */
+       /*signal_info(sig, info, v);*/  /* be quiet on "normal" kill */
+       alloc_mem(-1);
+       exit(0);
+}
+
+
+void
+die_handler(int sig, siginfo_t *info, void *v)
+{
+       doio_fprintf(stderr, "terminating on signal %d\n", sig);
+       signal_info(sig, info, v);
+       alloc_mem(-1);
+       exit(1);
+}
+
+void
+sigbus_handler(int sig, siginfo_t *info, void *v)
+{
+       /* While we are doing a memcpy to/from an mmapped region we can
+          get a SIGBUS for a variety of reasons--and not all of them
+          should be considered failures.
+
+          Under normal conditions if we get a SIGINT it means we've been
+          told to shutdown.  However, if we're currently doing the above-
+          mentioned memcopy then the kernel will follow that SIGINT with
+          a SIGBUS.  We can guess that we're in this situation by seeing
+          that the si_errno field in the siginfo structure has EINTR as
+          an errno.  (We might make the guess stronger by looking at the
+          si_addr field to see that it's not faulting off the end of the
+          mmapped region, but it seems that in such a case havesigint
+          would not have been set so maybe that doesn't make the guess
+          stronger.)
+        */
+
+       
+       if( active_mmap_rw && havesigint && (info->si_errno == EINTR) ){
+               cleanup_handler( sig, info, v );
+       }
+       else{
+               die_handler( sig, info, v );
+       }
+}
+#else
+
+void
+cleanup_handler()
+{
+       havesigint=1; /* in case there's a followup signal */
+       alloc_mem(-1);
+       exit(0);
+}
+
+void
+die_handler(sig)
+int sig;
+{
+       doio_fprintf(stderr, "terminating on signal %d\n", sig);
+       alloc_mem(-1);
+       exit(1);
+}
+
+#ifndef CRAY
+void
+sigbus_handler(sig)
+int sig;
+{
+       /* See sigbus_handler() in the 'ifdef sgi' case for details.  Here,
+          we don't have the siginfo stuff so the guess is weaker but we'll
+          do it anyway.
+       */
+
+       if( active_mmap_rw && havesigint )
+               cleanup_handler();
+       else
+               die_handler(sig);
+}
+#endif /* !CRAY */
+#endif /* sgi */
+
+
+void
+noop_handler(sig)
+int sig;
+{
+       return;
+}
+
+
+/*
+ * SIGINT handler for the parent (original doio) process.  It simply sends
+ * a SIGINT to all of the doio children.  Since they're all in the same
+ * pgrp, this can be done with a single kill().
+ */
+
+void
+sigint_handler()
+{
+       int     i;
+
+       for (i = 0; i < Nchildren; i++) {
+               if (Children[i] != -1) {
+                       kill(Children[i], SIGINT);
+               }
+       }
+}
+
+/*
+ * Signal handler used to inform a process when async io completes.  Referenced
+ * in do_read() and do_write().  Note that the signal handler is not
+ * re-registered.
+ */
+
+void
+aio_handler(sig)
+int    sig;
+{
+       int             i;
+       struct aio_info *aiop;
+
+       for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
+               aiop = &Aio_Info[i];
+
+               if (aiop->strategy == A_SIGNAL && aiop->sig == sig) {
+                       aiop->signalled++;
+
+                       if (aio_done(aiop)) {
+                               aiop->done++;
+                       }
+               }
+       }
+}
+
+/*
+ * dump info on all open aio slots
+ */
+void
+dump_aio()
+{
+       int             i, count;
+
+       count=0;
+       for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
+               if (Aio_Info[i].busy) {
+                       count++;
+                       fprintf(stderr,
+                               "Aio_Info[%03d] id=%d fd=%d signal=%d signaled=%d\n",
+                               i, Aio_Info[i].id,
+                               Aio_Info[i].fd,
+                               Aio_Info[i].sig,
+                               Aio_Info[i].signalled);
+                       fprintf(stderr, "\tstrategy=%s\n",
+                               format_strat(Aio_Info[i].strategy));
+               }
+       }
+       fprintf(stderr, "%d active async i/os\n", count);
+}
+
+
+#ifdef sgi
+/*
+ * Signal handler called as a callback, not as a signal.
+ * 'val' is the value from sigev_value and is assumed to be the
+ * Aio_Info[] index.
+ */
+void
+cb_handler(val)
+sigval_t val;
+{
+       struct aio_info *aiop;
+
+/*printf("cb_handler requesting slot %d\n", val.sival_int);*/
+       aiop = aio_slot( val.sival_int );
+/*printf("cb_handler, aiop=%p\n", aiop);*/
+
+/*printf("%d in cb_handler\n", getpid() );*/
+       if (aiop->strategy == A_CALLBACK) {
+               aiop->signalled++;
+
+               if (aio_done(aiop)) {
+                       aiop->done++;
+               }
+       }
+}
+#endif
+
+struct aio_info *
+aio_slot(aio_id)
+int    aio_id;
+{
+       int             i;
+       static int      id = 1;
+       struct aio_info *aiop;
+
+       aiop = NULL;
+
+       for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
+               if (aio_id == -1) {
+                       if (! Aio_Info[i].busy) {
+                               aiop = &Aio_Info[i];
+                               aiop->busy = 1;
+                               aiop->id = id++;
+                               break;
+                       }
+               } else {
+                       if (Aio_Info[i].busy && Aio_Info[i].id == aio_id) {
+                               aiop = &Aio_Info[i];
+                               break;
+                       }
+               }
+       }
+
+       if( aiop == NULL ){
+               doio_fprintf(stderr,"aio_slot(%d) not found.  Request %d\n", 
+                            aio_id, Reqno);
+               dump_aio();
+               alloc_mem(-1);
+               exit(E_INTERNAL);
+       }
+
+       return aiop;
+}
+
+int
+aio_register(fd, strategy, sig)
+int            fd;
+int            strategy;
+int            sig;
+{
+       struct aio_info         *aiop;
+       void                    aio_handler();
+       struct sigaction        sa;
+
+       aiop = aio_slot(-1);
+
+       aiop->fd = fd;
+       aiop->strategy = strategy;
+       aiop->done = 0;
+#ifdef CRAY
+       bzero((char *)&aiop->iosw, sizeof(aiop->iosw));
+#endif
+
+       if (strategy == A_SIGNAL) {
+               aiop->sig = sig;
+               aiop->signalled = 0;
+
+               sa.sa_handler = aio_handler;
+               sa.sa_flags = 0;
+               sigemptyset(&sa.sa_mask);
+
+               sigaction(sig, &sa, &aiop->osa);
+       } else {
+               aiop->sig = -1;
+               aiop->signalled = 0;
+       }
+
+       return aiop->id;
+}
+
+int
+aio_unregister(aio_id)
+int    aio_id;
+{
+       struct aio_info *aiop;
+
+       aiop = aio_slot(aio_id);
+
+       if (aiop->strategy == A_SIGNAL) {
+               sigaction(aiop->sig, &aiop->osa, NULL);
+       }
+
+       aiop->busy = 0;
+       return 0;
+}
+
+#ifndef linux
+int
+aio_wait(aio_id)
+int    aio_id;
+{
+#ifdef RECALL_SIZEOF
+       long            mask[RECALL_SIZEOF];
+#endif
+       sigset_t        sigset;
+       struct aio_info *aiop;
+#ifdef CRAY
+       struct iosw     *ioswlist[1];
+#endif
+#ifdef sgi
+       const aiocb_t   *aioary[1];
+#endif
+       int r, cnt;
+
+
+       aiop = aio_slot(aio_id);
+/*printf("%d aiop B =%p\n", getpid(), aiop);*/
+
+       switch (aiop->strategy) {
+       case A_POLL:
+               while (! aio_done(aiop))
+                       ;
+               break;
+
+       case A_SIGNAL:
+               sigemptyset(&sigset);
+               sighold( aiop->sig );
+
+               while ( !aiop->signalled || !aiop->done ) {
+                       sigsuspend(&sigset);
+                       sighold( aiop->sig );
+               }
+               break;
+
+#ifdef CRAY
+       case A_RECALL:
+               ioswlist[0] = &aiop->iosw;
+               if (recall(aiop->fd, 1, ioswlist) < 0) {
+                       doio_fprintf(stderr, "recall() failed:  %s (%d)\n",
+                                    SYSERR, errno);
+                       exit(E_SETUP);
+               }
+               break;
+
+#ifdef RECALL_SIZEOF
+
+       case A_RECALLA:
+               RECALL_INIT(mask);
+               RECALL_SET(mask, aiop->fd);
+               if (recalla(mask) < 0) {
+                       doio_fprintf(stderr, "recalla() failed:  %s (%d)\n",
+                                    SYSERR, errno);
+                       exit(E_SETUP);
+               }
+
+               RECALL_CLR(mask, aiop->fd);
+               break;
+#endif
+
+       case A_RECALLS:
+               ioswlist[0] = &aiop->iosw;
+               if (recalls(1, ioswlist) < 0) {
+                       doio_fprintf(stderr, "recalls failed:  %s (%d)\n",
+                               SYSERR, errno);
+                       exit(E_SETUP);
+               }
+               break;
+#endif /* CRAY */
+
+#ifdef sgi
+       case A_CALLBACK:
+               aioary[0] = &aiop->aiocb;
+               cnt=0;
+               do {
+                       r = aio_suspend(aioary, 1, NULL);
+                       if( r == -1 ){
+                               doio_fprintf(stderr, "aio_suspend failed: %s (%d)\n",
+                                            SYSERR, errno );
+                               exit(E_SETUP);
+                       }
+                       cnt++;
+               } while(aiop->done == 0);
+
+#if 0
+               /*
+                * after having this set for a while, I've decided that
+                * it's too noisy
+                */
+               if(cnt > 1)
+                       doio_fprintf(stderr, "aio_wait: callback wait took %d tries\n", cnt);
+#endif
+
+               /* 
+                * Note: cb_handler already calls aio_done
+                */
+               break;
+
+
+       case A_SUSPEND:
+               aioary[0] = &aiop->aiocb;
+               r = aio_suspend(aioary, 1, NULL);
+               if( r == -1 ){
+                       doio_fprintf(stderr, "aio_suspend failed: %s (%d)\n",
+                                    SYSERR, errno );
+                       exit(E_SETUP);
+               }
+
+               aio_done(aiop);
+               break;
+#endif
+       }
+
+/*printf("aio_wait: errno %d return %d\n", aiop->aio_errno, aiop->aio_ret);*/
+
+       return 0;
+}
+#endif /* !linux */
+
+/*
+ * Format specified time into HH:MM:SS format.  t is the time to format
+ * in seconds (as returned from time(2)).
+ */
+
+char *
+hms(t)
+time_t t;
+{
+       static char     ascii_time[9];
+       struct tm       *ltime;
+
+       ltime = localtime(&t);
+       strftime(ascii_time, sizeof(ascii_time), "%H:%M:%S", ltime);
+
+       return ascii_time;
+}
+
+/*
+ * Simple routine to check if an async io request has completed.
+ */
+
+int
+aio_done(struct aio_info *ainfo)
+{
+#ifdef CRAY
+       return ainfo->iosw.sw_flag;
+#endif
+
+#ifdef sgi
+       if( (ainfo->aio_errno = aio_error(&ainfo->aiocb)) == -1 ){
+               doio_fprintf(stderr, "aio_done: aio_error failed: %s (%d)\n",
+                            SYSERR, errno );
+               exit(E_SETUP);
+       }
+       /*printf("%d aio_done aio_errno=%d\n", getpid(), ainfo->aio_errno);*/
+       if( ainfo->aio_errno != EINPROGRESS ){
+               if( (ainfo->aio_ret = aio_return(&ainfo->aiocb)) == -1 ){
+                       doio_fprintf(stderr, "aio_done: aio_return failed: %s (%d)\n",
+                                    SYSERR, errno );
+                       exit(E_SETUP);
+               }
+       }
+
+       return (ainfo->aio_errno != EINPROGRESS);
+#else
+        return -1;   /* invalid */
+#endif
+}
+
+/*
+ * Routine to handle upanic() - it first attempts to set the panic flag.  If
+ * the flag cannot be set, an error message is issued.  A call to upanic
+ * with PA_PANIC is then done unconditionally, in case the panic flag was set
+ * from outside the program (as with the panic(8) program).
+ *
+ * Note - we only execute the upanic code if -U was used, and the passed in
+ * mask is set in the Upanic_Conditions bitmask.
+ */
+
+void
+doio_upanic(mask)
+int    mask;
+{
+       if (U_opt == 0 || (mask & Upanic_Conditions) == 0) {
+               return;
+       }
+
+#ifdef CRAY
+       if (upanic(PA_SET) < 0) {
+               doio_fprintf(stderr, "WARNING - Could not set the panic flag - upanic(PA_SET) failed:  %s (%d)\n",
+                            SYSERR, errno);
+       }
+
+       upanic(PA_PANIC);
+#endif
+#ifdef sgi
+       syssgi(1005);   /* syssgi test panic - DEBUG kernels only */
+#endif
+       doio_fprintf(stderr, "WARNING - upanic() failed\n");
+}
+
+/*
+ * Parse cmdline options/arguments and set appropriate global variables.
+ * If the cmdline is valid, return 0 to caller.  Otherwise exit with a status
+ * of 1.
+ */
+
+int
+parse_cmdline(argc, argv, opts)
+int    argc;
+char   **argv;
+char   *opts;
+{
+       int             c;
+       char            cc, *cp, *tok = NULL;
+       extern int      opterr;
+       extern int      optind;
+       extern char     *optarg;
+       struct smap     *s;
+       char            *memargs[NMEMALLOC];
+       int             nmemargs, ma;
+       void            parse_memalloc(char *arg);
+       void            parse_delay(char *arg);
+       void            dump_memalloc();
+
+       if (*argv[0] == '-') {
+               argv[0]++;
+               Execd = 1;
+       }
+       
+       if ((Prog = strrchr(argv[0], '/')) == NULL) {
+               Prog = argv[0];
+       } else {
+               Prog++;
+       }
+       
+       opterr = 0;
+       while ((c = getopt(argc, argv, opts)) != EOF) {
+               switch ((char)c) {
+               case 'a':
+                       a_opt++;
+                       break;
+
+               case 'C':
+                       C_opt++;
+                       for(s=checkmap; s->string != NULL; s++)
+                               if(!strcmp(s->string, optarg))
+                                       break;
+                       if (s->string == NULL) {
+                               fprintf(stderr,
+                                       "%s%s:  Illegal -C arg (%s).  Must be one of: ", 
+                                       Prog, TagName, tok);
+
+                               for (s = checkmap; s->string != NULL; s++)
+                                       fprintf(stderr, "%s ", s->string);
+                               fprintf(stderr, "\n");
+                               exit(1);
+                       }
+
+                       switch(s->value) {
+                       case C_DEFAULT:
+                               Data_Fill = doio_pat_fill;
+                               Data_Check = doio_pat_check;
+                               break;
+                       default:
+                               fprintf(stderr,
+                                       "%s%s:  Unrecognised -C arg '%s' %d", 
+                                       Prog, TagName, s->string, s->value);
+                               exit(1);
+                       }
+                       break;
+
+               case 'd':       /* delay between i/o ops */
+                       parse_delay(optarg);
+                       break;
+
+               case 'e':
+                       if (Npes > 1 && Nprocs > 1) {
+                               fprintf(stderr, "%s%s:  Warning - Program is a multi-pe application - exec option is ignored.\n", Prog, TagName);
+                       }
+                       e_opt++;
+                       break;
+
+               case 'h':
+                       help(stdout);
+                       exit(0);
+                       break;
+
+               case 'k':
+                       k_opt++;
+                       break;
+
+               case 'm':
+                       Message_Interval = strtol(optarg, &cp, 10);
+                       if (*cp != '\0' || Message_Interval < 0) {
+                               fprintf(stderr, "%s%s:  Illegal -m arg (%s):  Must be an integer >= 0\n", Prog, TagName, optarg);
+                               exit(1);
+                       }
+                       m_opt++;
+                       break;
+
+               case 'M':       /* memory allocation types */
+#ifndef CRAY
+                       nmemargs = string_to_tokens(optarg, memargs, 32, ",");
+                       for(ma=0; ma < nmemargs; ma++) {
+                               parse_memalloc(memargs[ma]);
+                       }
+                       /*dump_memalloc();*/
+#else
+                       fprintf(stderr, "%s%s: Error: -M isn't supported on this platform\n", Prog, TagName);
+                       exit(1);
+#endif
+                       M_opt++;
+                       break;
+
+               case 'N':
+                       sprintf( TagName, "(%.39s)", optarg );
+                       break;
+
+               case 'n':
+                       Nprocs = strtol(optarg, &cp, 10);
+                       if (*cp != '\0' || Nprocs < 1) {
+                               fprintf(stderr,
+                                       "%s%s:  Illegal -n arg (%s):  Must be integer > 0\n",
+                                       Prog, TagName, optarg);
+                               exit(E_USAGE);
+                       }
+
+                       if (Npes > 1 && Nprocs > 1) {
+                               fprintf(stderr, "%s%s:  Program has been built as a multi-pe app.  -n1 is the only nprocs value allowed\n", Prog, TagName);
+                               exit(E_SETUP);
+                       }
+                       n_opt++;
+                       break;
+
+               case 'r':
+                       Release_Interval = strtol(optarg, &cp, 10);
+                       if (*cp != '\0' || Release_Interval < 0) {
+                               fprintf(stderr,
+                                       "%s%s:  Illegal -r arg (%s):  Must be integer >= 0\n",
+                                       Prog, TagName, optarg);
+                               exit(E_USAGE);
+                       }
+
+                       r_opt++;
+                       break;
+
+               case 'w':
+                       Write_Log = optarg;
+                       w_opt++;
+                       break;
+
+               case 'v':
+                       v_opt++;
+                       break;
+
+               case 'V':
+                       if (strcasecmp(optarg, "sync") == 0) {
+                               Validation_Flags = O_SYNC;
+                       } else if (strcasecmp(optarg, "buffered") == 0) {
+                               Validation_Flags = 0;
+#ifdef CRAY
+                       } else if (strcasecmp(optarg, "parallel") == 0) {
+                               Validation_Flags = O_PARALLEL;
+                       } else if (strcasecmp(optarg, "ldraw") == 0) {
+                               Validation_Flags = O_LDRAW;
+                       } else if (strcasecmp(optarg, "raw") == 0) {
+                               Validation_Flags = O_RAW;
+#endif
+                       } else if (strcasecmp(optarg, "direct") == 0) {
+                               Validation_Flags = O_DIRECT;
+                       } else {
+                               if (sscanf(optarg, "%i%c", &Validation_Flags, &cc) != 1) {
+                                       fprintf(stderr, "%s:  Invalid -V argument (%s) - must be a decimal, hex, or octal\n", Prog, optarg);
+                                       fprintf(stderr, "    number, or one of the following strings:  'sync',\n");
+                                       fprintf(stderr, "    'buffered', 'parallel', 'ldraw', or 'raw'\n");
+                                       exit(E_USAGE);
+                               }
+                       }
+                       V_opt++;
+                       break;
+               case 'U':
+                       tok = strtok(optarg, ",");
+                       while (tok != NULL) {
+                               for (s = Upanic_Args; s->string != NULL; s++)
+                                       if (strcmp(s->string, tok) == 0)
+                                               break;
+
+                               if (s->string == NULL) {
+                                       fprintf(stderr,
+                                               "%s%s:  Illegal -U arg (%s).  Must be one of: ", 
+                                               Prog, TagName, tok);
+
+                                       for (s = Upanic_Args; s->string != NULL; s++)
+                                               fprintf(stderr, "%s ", s->string);
+
+                                       fprintf(stderr, "\n");
+
+                                       exit(1);
+                               }
+
+                               Upanic_Conditions |= s->value;
+                               tok = strtok(NULL, ",");
+                       }
+
+                       U_opt++;
+                       break;
+
+               case '?':
+                       usage(stderr);
+                       exit(E_USAGE);
+                       break;
+               }
+       }
+       
+       /*
+        * Supply defaults
+        */
+       
+       if (! C_opt) {
+               Data_Fill = doio_pat_fill;
+               Data_Check = doio_pat_check;
+       }
+
+       if (! U_opt)
+               Upanic_Conditions = 0;
+
+       if (! n_opt)
+               Nprocs = 1;
+       
+       if (! r_opt)
+               Release_Interval = DEF_RELEASE_INTERVAL;
+
+       if (! M_opt) {
+               Memalloc[Nmemalloc].memtype = MEM_DATA;
+               Memalloc[Nmemalloc].flags = 0;
+               Memalloc[Nmemalloc].name = NULL;
+               Memalloc[Nmemalloc].space = NULL;
+               Nmemalloc++;
+       }
+
+       /*
+        * Initialize input stream
+        */
+
+       if (argc == optind) {
+               Infile = NULL;
+       } else {
+               Infile = argv[optind++];
+       }
+
+       if (argc != optind) {
+               usage(stderr);
+               exit(E_USAGE);
+       }
+
+       return 0;
+}      
+
+
+
+/*
+ * Parse memory allocation types
+ *
+ * Types are:
+ *  Data
+ *  T3E-shmem:blksize[:nblks]
+ *  SysV-shmem:shmid:blksize:nblks
+ *     if shmid is "private", use IPC_PRIVATE
+ *     and nblks is not required
+ *
+ *  mmap:flags:filename:blksize[:nblks]
+ *   flags are one of:
+ *     p - private (MAP_PRIVATE)
+ *     a - private, MAP_AUTORESRV
+ *     l - local (MAP_LOCAL)
+ *     s - shared (nblks required)
+ *
+ *   plus any of:
+ *     f - fixed address (MAP_FIXED)
+ *     A - use an address without MAP_FIXED
+ *     a - autogrow (map once at startup)
+ *
+ *  mmap:flags:devzero
+ *     mmap /dev/zero  (shared not allowd)
+ *     maps the first 4096 bytes of /dev/zero
+ *
+ * - put a directory at the beginning of the shared
+ *   regions saying what pid has what region.
+ *     DIRMAGIC
+ *     BLKSIZE
+ *     NBLKS
+ *     nblks worth of directories - 1 int pids
+ */
+#ifndef CRAY
+void
+parse_memalloc(char *arg)
+{
+       char            *allocargs[NMEMALLOC];
+       int             nalloc;
+       struct memalloc *M;
+
+       if(Nmemalloc >= NMEMALLOC) {
+               doio_fprintf(stderr, "Error - too many memory types (%d).\n", 
+                       Nmemalloc);
+               return;
+       }
+
+       M = &Memalloc[Nmemalloc];
+
+       nalloc = string_to_tokens(arg, allocargs, 32, ":");
+       if(!strcmp(allocargs[0], "data")) {
+               M->memtype = MEM_DATA;
+               M->flags = 0;
+               M->name = NULL;
+               M->space = NULL;
+               Nmemalloc++;
+               if(nalloc >= 2) {
+                       if(strchr(allocargs[1], 'p'))
+                               M->flags |= MEMF_MPIN;
+               }
+       } else if(!strcmp(allocargs[0], "mmap")) {
+               /* mmap:flags:filename[:size] */
+               M->memtype = MEM_MMAP;
+               M->flags = 0;
+               M->space = NULL;
+               if(nalloc >= 1) {
+                       if(strchr(allocargs[1], 'p'))
+                               M->flags |= MEMF_PRIVATE;
+                       if(strchr(allocargs[1], 'a'))
+                               M->flags |= MEMF_AUTORESRV;
+                       if(strchr(allocargs[1], 'l'))
+                               M->flags |= MEMF_LOCAL;
+                       if(strchr(allocargs[1], 's'))
+                               M->flags |= MEMF_SHARED;
+
+                       if(strchr(allocargs[1], 'f'))
+                               M->flags |= MEMF_FIXADDR;
+                       if(strchr(allocargs[1], 'A'))
+                               M->flags |= MEMF_ADDR;
+                       if(strchr(allocargs[1], 'G'))
+                               M->flags |= MEMF_AUTOGROW;
+
+                       if(strchr(allocargs[1], 'U'))
+                               M->flags |= MEMF_FILE;
+               } else {
+                       M->flags |= MEMF_PRIVATE;
+               }
+
+               if(nalloc > 2) {
+                       if(!strcmp(allocargs[2], "devzero")) {
+                               M->name = "/dev/zero";
+                               if(M->flags & 
+                                  ((MEMF_PRIVATE|MEMF_LOCAL) == 0))
+                                       M->flags |= MEMF_PRIVATE;
+                       } else {
+                               M->name = allocargs[2];
+                       }
+               } else {
+                       M->name = "/dev/zero";
+                       if(M->flags & 
+                          ((MEMF_PRIVATE|MEMF_LOCAL) == 0))
+                               M->flags |= MEMF_PRIVATE;
+               }
+               Nmemalloc++;
+
+       } else if(!strcmp(allocargs[0], "shmem")) {
+               /* shmem:shmid:size */
+               M->memtype = MEM_SHMEM;
+               M->flags = 0;
+               M->space = NULL;
+               if(nalloc >= 2) {
+                       M->name = allocargs[1];
+               } else {
+                       M->name = NULL;
+               }
+               if(nalloc >= 3) {
+                       sscanf(allocargs[2], "%i", &M->nblks);
+               } else {
+                       M->nblks = 0;
+               }
+               if(nalloc >= 4) {
+                       if(strchr(allocargs[3], 'p'))
+                               M->flags |= MEMF_MPIN;
+               }
+
+               Nmemalloc++;
+       } else {
+               doio_fprintf(stderr, "Error - unknown memory type '%s'.\n",
+                       allocargs[0]);
+               exit(1);
+       }
+}
+
+void
+dump_memalloc()
+{
+       int     ma;
+       char    *mt;
+
+       if(Nmemalloc == 0) {
+               printf("No memory allocation strategies devined\n");
+               return;
+       }
+
+       for(ma=0; ma < Nmemalloc; ma++) {
+               switch(Memalloc[ma].memtype) {
+               case MEM_DATA:  mt = "data";    break;
+               case MEM_SHMEM: mt = "shmem";   break;
+               case MEM_MMAP:  mt = "mmap";    break;
+               default:        mt = "unknown"; break;
+               }
+               printf("mstrat[%d] = %d %s\n", ma, Memalloc[ma].memtype, mt);
+               printf("\tflags=%#o name='%s' nblks=%d\n",
+                      Memalloc[ma].flags,
+                      Memalloc[ma].name,
+                      Memalloc[ma].nblks);
+       }
+}
+
+#endif /* !CRAY */
+
+/*
+ * -d <op>:<time> - doio inter-operation delay
+ *     currently this permits ONE type of delay between operations.
+ */
+
+void
+parse_delay(char *arg)
+{
+       char            *delayargs[NMEMALLOC];
+       int             ndelay;
+       struct smap     *s;
+
+       ndelay = string_to_tokens(arg, delayargs, 32, ":");
+       if(ndelay < 2) {
+               doio_fprintf(stderr,
+                       "Illegal delay arg (%s). Must be operation:time\n", arg);
+               exit(1);
+       }
+       for(s=delaymap; s->string != NULL; s++)
+               if(!strcmp(s->string, delayargs[0]))
+                       break;
+       if (s->string == NULL) {
+               fprintf(stderr,
+                       "Illegal Delay arg (%s).  Must be one of: ", arg);
+
+               for (s = delaymap; s->string != NULL; s++)
+                       fprintf(stderr, "%s ", s->string);
+               fprintf(stderr, "\n");
+               exit(1);
+       }
+
+       delayop = s->value;
+
+       sscanf(delayargs[1], "%i", &delaytime);
+
+       if(ndelay > 2) {
+               fprintf(stderr,
+                       "Warning: extra delay arguments ignored.\n");
+       }
+}
+
+
+/*
+ * Usage clause - obvious
+ */
+
+int
+usage(stream)
+FILE   *stream;
+{
+       /*
+        * Only do this if we are on vpe 0, to avoid seeing it from every
+        * process in the application.
+        */
+
+       if (Npes > 1 && Vpe != 0) {
+               return 0;
+       }
+
+       fprintf(stream, "usage%s:  %s [-aekv] [-m message_interval] [-n nprocs] [-r release_interval] [-w write_log] [-V validation_ftype] [-U upanic_cond] [infile]\n", TagName, Prog);
+       return 0;
+}
+
+void
+help(stream)
+FILE   *stream;
+{
+       /*
+        * Only the app running on vpe 0 gets to issue help - this prevents
+        * everybody in the application from doing this.
+        */
+
+       if (Npes > 1 && Vpe != 0) {
+               return;
+       }
+
+       usage(stream);
+       fprintf(stream, "\n");
+       fprintf(stream, "\t-a                   abort - kill all doio processes on data compare\n");
+       fprintf(stream, "\t                     errors.  Normally only the erroring process exits\n");
+       fprintf(stream, "\t-C data-pattern-type \n");
+       fprintf(stream, "\t                     Available data patterns are:\n");
+       fprintf(stream, "\t                     default - repeating pattern\n");
+       fprintf(stream, "\t-d Operation:Time    Inter-operation delay.\n");
+       fprintf(stream, "\t                     Operations are:\n");
+       fprintf(stream, "\t                         select:time (1 second=1000000)\n");
+       fprintf(stream, "\t                         sleep:time (1 second=1)\n");
+#ifdef sgi
+       fprintf(stream, "\t                         sginap:time (1 second=CLK_TCK=100)\n");
+#endif
+       fprintf(stream, "\t                         alarm:time (1 second=1)\n");
+       fprintf(stream, "\t-e                   Re-exec children before entering the main\n");
+       fprintf(stream, "\t                     loop.  This is useful for spreading\n");
+       fprintf(stream, "\t                     procs around on multi-pe systems.\n");
+       fprintf(stream, "\t-k                   Lock file regions during writes using fcntl()\n");
+       fprintf(stream, "\t-v                   Verify writes - this is done by doing a buffered\n");
+       fprintf(stream, "\t                     read() of the data if file io was done, or\n");
+       fprintf(stream, "\t                     an ssread()of the data if sds io was done\n");
+#ifndef CRAY
+       fprintf(stream, "\t-M                   Data buffer allocation method\n");
+       fprintf(stream, "\t                     alloc-type[,type]\n");
+#ifdef sgi
+       fprintf(stream, "\t                         data:flags\n");
+       fprintf(stream, "\t                             p - mpin buffer\n");
+       fprintf(stream, "\t                         shmem:shmid:size:flags\n");
+       fprintf(stream, "\t                             p - mpin buffer\n");
+#else
+       fprintf(stream, "\t                         data\n");
+       fprintf(stream, "\t                         shmem:shmid:size\n");
+#endif /* sgi */
+       fprintf(stream, "\t                         mmap:flags:filename\n");
+       fprintf(stream, "\t                             p - private\n");
+#ifdef sgi
+       fprintf(stream, "\t                             s - shared\n");
+       fprintf(stream, "\t                             l - local\n");
+       fprintf(stream, "\t                             a - autoresrv\n");
+       fprintf(stream, "\t                             G - autogrow\n");
+#else
+       fprintf(stream, "\t                             s - shared (shared file must exist\n"),
+       fprintf(stream, "\t                                 and have needed length)\n");
+#endif
+       fprintf(stream, "\t                             f - fixed address (not used)\n");
+       fprintf(stream, "\t                             a - specify address (not used)\n");
+       fprintf(stream, "\t                             U - Unlink file when done\n");
+       fprintf(stream, "\t                             The default flag is private\n");
+       fprintf(stream, "\n");
+#endif /* !CRAY */
+       fprintf(stream, "\t-m message_interval  Generate a message every 'message_interval'\n");
+       fprintf(stream, "\t                     requests.  An interval of 0 suppresses\n");
+       fprintf(stream, "\t                     messages.  The default is 0.\n");
+       fprintf(stream, "\t-N tagname           Tag name, for Monster.\n");
+       fprintf(stream, "\t-n nprocs            # of processes to start up\n");
+       fprintf(stream, "\t-r release_interval  Release all memory and close\n");
+       fprintf(stream, "\t                     files every release_interval operations.\n");
+       fprintf(stream, "\t                     By default procs never release memory\n");
+       fprintf(stream, "\t                     or close fds unless they have to.\n");
+       fprintf(stream, "\t-V validation_ftype  The type of file descriptor to use for doing data\n");
+       fprintf(stream, "\t                     validation.  validation_ftype may be an octal,\n");
+       fprintf(stream, "\t                     hex, or decimal number representing the open()\n");
+       fprintf(stream, "\t                     flags, or may be one of the following strings:\n");
+       fprintf(stream, "\t                     'buffered' - validate using bufferd read\n");
+       fprintf(stream, "\t                     'sync'     - validate using O_SYNC read\n");
+       fprintf(stream, "\t                     'direct    - validate using O_DIRECT read'\n");
+#ifdef CRAY
+       fprintf(stream, "\t                     'ldraw'    - validate using O_LDRAW read\n");
+       fprintf(stream, "\t                     'parallel' - validate using O_PARALLEL read\n");
+       fprintf(stream, "\t                     'raw'      - validate using O_RAW read\n");
+#endif
+       fprintf(stream, "\t                     By default, 'parallel'\n");
+       fprintf(stream, "\t                     is used if the write was done with O_PARALLEL\n");
+       fprintf(stream, "\t                     or 'buffered' for all other writes.\n");
+       fprintf(stream, "\t-w write_log         File to log file writes to.  The doio_check\n");
+       fprintf(stream, "\t                     program can reconstruct datafiles using the\n");
+       fprintf(stream, "\t                     write_log, and detect if a file is corrupt\n");
+       fprintf(stream, "\t                     after all procs have exited.\n");
+       fprintf(stream, "\t-U upanic_cond       Comma separated list of conditions that will\n");
+       fprintf(stream, "\t                     cause a call to upanic(PA_PANIC).\n");
+       fprintf(stream, "\t                     'corruption' -> upanic on bad data comparisons\n");
+       fprintf(stream, "\t                     'iosw'     ---> upanic on unexpected async iosw\n");
+       fprintf(stream, "\t                     'rval'     ---> upanic on unexpected syscall rvals\n");
+       fprintf(stream, "\t                     'all'      ---> all of the above\n");
+       fprintf(stream, "\n");
+       fprintf(stream, "\tinfile               Input stream - default is stdin - must be a list\n");
+       fprintf(stream, "\t                     of io_req structures (see doio.h).  Currently\n");
+       fprintf(stream, "\t                     only the iogen program generates the proper\n");
+       fprintf(stream, "\t                     format\n");
+}      
+
diff --git a/ltp/doio.h b/ltp/doio.h
new file mode 100644 (file)
index 0000000..3aae833
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+/*
+ * Define io syscalls supported by doio
+ */
+
+#define        READ    1
+#define        WRITE   2
+#define        READA   3
+#define        WRITEA  4
+#define        SSREAD  5
+#define        SSWRITE 6
+#define        LISTIO  7
+#define        LREAD   10              /* listio - single stride, single entry */
+#define        LREADA  11
+#define        LWRITE  12
+#define        LWRITEA 13
+#define        LSREAD  14              /* listio - multi-stride, single entry */
+#define        LSREADA 15
+#define        LSWRITE 16
+#define        LSWRITEA 17
+#define        LEREAD  18              /* listio - single stride, multiple entry */
+#define        LEREADA 19
+#define        LEWRITE 20
+#define        LEWRITEA 21
+
+/* System Calls */
+#define        PREAD   100
+#define        PWRITE  101
+#define        READV   102
+#define        WRITEV  103
+#define        AREAD   104
+#define        AWRITE  105
+#define        LLREAD  110
+#define        LLAREAD 111
+#define        LLWRITE 112
+#define        LLAWRITE 113
+#define        MMAPR   120
+#define        MMAPW   121
+#define RESVSP 122             /* xfsctl(XFS_IOC_RESVSP) */
+#define UNRESVSP 123           /* xfsctl(XFS_IOC_UNRESVSP) */
+#define        FSYNC2  125             /* fsync(2) */
+#define        FDATASYNC 126           /* fdatasync(2) */
+
+#ifdef CRAY
+/* used: <<doio>> 1.? <<DOIO>> 1.5 <-DOIO-> 1.7*/
+#define DOIO_MAGIC  '<[DOIO]>'
+#else
+#define DOIO_MAGIC  07116601
+#endif
+
+/*
+ * Define various user flags (r_uflag field) that io requests can have
+ * specified.
+ */
+
+#define F_WORD_ALIGNED         0001    /* force request to be word aligned */
+
+/*
+ * define various doio exit status's
+ */
+
+#define E_NORMAL    000                /* normal completion                    */
+#define E_USAGE            001         /* cmdline usage error                  */
+#define E_SETUP            002         /* any of a million setup conditions    */
+#define E_COMPARE   004                /* data compare error from doio child   */
+#define E_INTERNAL  010                /* various internal errors              */
+#define E_LOCKD            020         /* lockd startup/timeout errors         */
+#define E_SIGNAL    040                /* killed by signal                     */
+
+/*
+ * Define async io completion strategies supported by doio.
+ */
+
+#define        A_POLL          1               /* poll iosw for completion     */
+#define A_SIGNAL       2               /* get signal for completion    */
+#define A_RECALL       3               /* use recall(2) to wait        */
+#define A_RECALLA      4               /* use recalla(2) to wait       */
+#define A_RECALLS      5               /* use recalls(2) to wait       */
+#define        A_SUSPEND       6               /* use aio_suspend(2) to wait   */
+#define A_CALLBACK     7               /* use a callback signal op.    */
+
+/*
+ * Define individual structures for each syscall type.  These will all be
+ * unionized into a single io_req structure which io generators fill in and
+ * pass to doio.
+ *
+ * Note:       It is VERY important that the r_file, r_oflags, r_offset, and
+ *             r_nbytes fields occupy the same record positions in the
+ *             read_req, reada_req, write_req, and writea_req structures and
+ *             that they have the same type.  It is also that r_pattern
+ *             has the same type/offset in the write_req and writea_req
+ *             structures.
+ *
+ *             Since doio.c accesses all information through the r_data
+ *             union in io_req, if the above assumptions hold, the above
+ *             fields can be accessed without regard to structure type.
+ *             This is an allowed assumption in C.
+ */
+
+#define MAX_FNAME_LENGTH    128
+
+struct read_req {
+    char    r_file[MAX_FNAME_LENGTH];
+    int            r_oflags;                   /* open flags */
+    int            r_offset;
+    int            r_nbytes;
+    int            r_uflags;                   /* user flags: mem alignment */
+    int            r_aio_strat;                /* asynch read completion strategy */
+    int            r_nstrides;                 /* listio: multiple strides */
+    int            r_nent;                     /* listio: multiple list entries */
+};
+
+struct write_req {
+    char    r_file[MAX_FNAME_LENGTH];
+    int            r_oflags;
+    int            r_offset;
+    int            r_nbytes;
+    char    r_pattern;
+    int            r_uflags;                   /* user flags: mem alignment */
+    int            r_aio_strat;                /* asynch write completion strategy */
+    int            r_nstrides;                 /* listio: multiple strides */
+    int            r_nent;                     /* listio: multiple list entries */
+};
+
+struct ssread_req {
+    int            r_nbytes;
+};
+
+struct sswrite_req {
+    int            r_nbytes;
+    char    r_pattern;
+};
+
+struct listio_req {
+       char    r_file[MAX_FNAME_LENGTH];
+       int     r_cmd;                  /* LC_START or LC_WAIT */
+       int     r_offset;               /* file offset */
+       int     r_opcode;               /* LO_READ, or LO_WRITE */
+       int     r_nbytes;               /* bytes per stride */
+       int     r_nstrides;             /* how many strides to make */
+       int     r_nent;                 /* how many listreq entries to make */
+       int     r_filestride;           /* always 0 for now */
+       int     r_memstride;            /* always 0 for now */
+       char    r_pattern;              /* for LO_WRITE operations */
+       int     r_oflags;               /* open(2) flags */
+       int     r_aio_strat;            /* async I/O completion strategy */
+       int     r_uflags;               /* user flags: memory alignment */
+};
+
+#define rw_req listio_req      /* listio is superset of everything */
+
+/*
+ * Main structure for sending a request to doio.  Any tools which form IO
+ * for doio must present it using one of these structures.
+ */
+
+struct io_req {
+    int            r_type;             /* must be one of the #defines above        */
+    int            r_magic;            /* must be set to DOIO_MAGIC by requestor   */
+    union {
+       struct read_req         read;
+       struct write_req        write;
+       struct ssread_req       ssread;
+       struct sswrite_req      sswrite;
+       struct listio_req       listio;
+       struct rw_req           io;
+    } r_data;
+};
similarity index 95%
rename from src/fsstress.c
rename to ltp/fsstress.c
index 104c6af36bd89f2500c906b3c6319333f1f28145..4d5a14b461848c2fc7e7c34f18196490f5bcff85 100644 (file)
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
 
-#include "global.h"
+#include <xfs/libxfs.h>
 #include <attr/xattr.h>
+#include <attr/attributes.h>
+#include <sys/statvfs.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <dirent.h>
 
 #define XFS_ERRTAG_MAX         17
 
@@ -355,7 +360,7 @@ int main(int argc, char **argv)
                seed = (int)t.tv_sec ^ (int)t.tv_usec;
                printf("seed = %ld\n", seed);
        }
-       i = ioctl(fd, XFS_IOC_FSGEOMETRY, &geom);
+       i = xfsctl(buf, fd, XFS_IOC_FSGEOMETRY, &geom);
        if (i >= 0 && geom.rtblocks)
                rtpct = MIN(MAX(geom.rtblocks * 100 /
                                (geom.rtblocks + geom.datablocks), 1), 99);
@@ -384,7 +389,7 @@ int main(int argc, char **argv)
                printf("Injecting failure on tag #%d\n", errtag);
                err_inj.errtag = errtag;
                err_inj.fd = fd;
-               srval = ioctl(fd, XFS_IOC_ERROR_INJECTION, &err_inj);
+               srval = xfsctl(buf, fd, XFS_IOC_ERROR_INJECTION, &err_inj);
                if (srval < -1) {
                        perror("fsstress - XFS_SYSSGI error injection call");
                        close(fd);
@@ -393,7 +398,6 @@ int main(int argc, char **argv)
                }
        } else
                close(fd);
-       unlink(buf);
        for (i = 0; i < nproc; i++) {
                if (fork() == 0) {
                        procid = i;
@@ -406,15 +410,18 @@ int main(int argc, char **argv)
        if (errtag != 0) {
                err_inj.errtag = 0;
                err_inj.fd = fd;
-               if((srval = ioctl(fd, XFS_IOC_ERROR_CLEARALL, &err_inj)) != 0) {
-                       fprintf(stderr, "Bad ej clear on %d (%d).\n", fd, errno);
-                       perror("fsstress - XFS_SYSSGI clear error injection call");
+               srval = xfsctl(buf, fd, XFS_IOC_ERROR_CLEARALL, &err_inj);
+               if (srval != 0) {
+                       fprintf(stderr, "Bad ej clear on %s fd=%d (%d).\n",
+                               buf, fd, errno);
+                       perror("xfsctl(XFS_IOC_ERROR_CLEARALL)");
                        close(fd);
                        exit(1);
                }
                close(fd);
        }
 
+       unlink(buf);
        return 0;
 }
 
@@ -1340,10 +1347,10 @@ allocsp_f(int opno, long r)
        fl.l_whence = SEEK_SET;
        fl.l_start = off;
        fl.l_len = 0;
-       e = ioctl(fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0;
+       e = xfsctl(f.path, fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0;
        if (v)
-               printf("%d/%d: ioctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n",
-                       procid, opno, f.path, off, e);
+               printf("%d/%d: xfsctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n",
+                       procid, opno, f.path, (long long)off, e);
        free_pathname(&f);
        close(fd);
 }
@@ -1463,12 +1470,12 @@ bulkstat_f(int opno, long r)
         bsr.ubuffer=t;
         bsr.ocount=&count;
             
-       while (ioctl(fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
+       while (xfsctl(".", fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
                total += count;
        free(t);
        if (verbose)
-               printf("%d/%d: bulkstat nent %d total %lld\n",
-                       procid, opno, nent, total);
+               printf("%d/%d: bulkstat nent %d total %llu\n",
+                       procid, opno, nent, (long long)total);
        close(fd);
 }
 
@@ -1520,10 +1527,10 @@ bulkstat1_f(int opno, long r)
         bsr.ubuffer=&t;
         bsr.ocount=NULL;
         
-       e = ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
+       e = xfsctl(".", fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
        if (v)
                printf("%d/%d: bulkstat1 %s ino %lld %d\n", 
-                    procid, opno, good?"real":"random", (int64_t)ino, e);
+                    procid, opno, good?"real":"random", (long long)ino, e);
        close(fd);
 }
 
@@ -1591,11 +1598,12 @@ creat_f(int opno, long r)
        e1 = 0;
        check_cwd();
        if (fd >= 0) {
-               if (extsize && ioctl(fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
+               if (extsize &&
+                   xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
                        a.fsx_xflags |= XFS_XFLAG_REALTIME;
                        a.fsx_extsize =
                                geom.rtextsize * geom.blocksize * extsize;
-                       if (ioctl(fd, XFS_IOC_FSSETXATTR, &a) < 0)
+                       if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0)
                                e1 = errno;
                }
                add_to_flist(type, id, parid);
@@ -1655,10 +1663,10 @@ dread_f(int opno, long r)
                close(fd);
                return;
        }
-       if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) {
+       if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
                if (v)
                        printf(
-                       "%d/%d: dread - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n",
+                       "%d/%d: dread - xfsctl(XFS_IOC_DIOINFO) %s failed %d\n",
                                procid, opno, f.path, errno);
                free_pathname(&f);
                close(fd);
@@ -1680,7 +1688,7 @@ dread_f(int opno, long r)
        free(buf);
        if (v)
                printf("%d/%d: dread %s [%lld,%d] %d\n",
-                       procid, opno, f.path, off, len, e);
+                       procid, opno, f.path, (long long)off, (int)len, e);
        free_pathname(&f);
        close(fd);
 }
@@ -1725,10 +1733,10 @@ dwrite_f(int opno, long r)
                close(fd);
                return;
        }
-       if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) {
+       if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
                if (v)
-                       printf(
-                       "%d/%d: dwrite - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n",
+                       printf("%d/%d: dwrite - xfsctl(XFS_IOC_DIOINFO)"
+                               " %s failed %d\n",
                                procid, opno, f.path, errno);
                free_pathname(&f);
                close(fd);
@@ -1753,7 +1761,7 @@ dwrite_f(int opno, long r)
        free(buf);
        if (v)
                printf("%d/%d: dwrite %s [%lld,%d] %d\n",
-                       procid, opno, f.path, off, len, e);
+                       procid, opno, f.path, (long long)off, (int)len, e);
        free_pathname(&f);
        close(fd);
 }
@@ -1834,10 +1842,10 @@ freesp_f(int opno, long r)
        fl.l_whence = SEEK_SET;
        fl.l_start = off;
        fl.l_len = 0;
-       e = ioctl(fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
+       e = xfsctl(f.path, fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
        if (v)
-               printf("%d/%d: ioctl(XFS_IOC_FREESP64) %s %lld 0 %d\n",
-                       procid, opno, f.path, off, e);
+               printf("%d/%d: xfsctl(XFS_IOC_FREESP64) %s %lld 0 %d\n",
+                       procid, opno, f.path, (long long)off, e);
        free_pathname(&f);
        close(fd);
 }
@@ -2077,7 +2085,7 @@ read_f(int opno, long r)
        free(buf);
        if (v)
                printf("%d/%d: read %s [%lld,%d] %d\n",
-                       procid, opno, f.path, off, len, e);
+                       procid, opno, f.path, (long long)off, (int)len, e);
        free_pathname(&f);
        close(fd);
 }
@@ -2204,10 +2212,11 @@ resvsp_f(int opno, long r)
        fl.l_whence = SEEK_SET;
        fl.l_start = off;
        fl.l_len = (off64_t)(random() % (1024 * 1024));
-       e = ioctl(fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
+       e = xfsctl(f.path, fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
        if (v)
-               printf("%d/%d: ioctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n",
-                       procid, opno, f.path, off, fl.l_len, e);
+               printf("%d/%d: xfsctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n",
+                       procid, opno, f.path,
+                       (long long)off, (long long)fl.l_len, e);
        free_pathname(&f);
        close(fd);
 }
@@ -2347,7 +2356,7 @@ truncate_f(int opno, long r)
        check_cwd();
        if (v)
                printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path,
-                       off, e);
+                       (long long)off, e);
        free_pathname(&f);
 }
 
@@ -2419,10 +2428,11 @@ unresvsp_f(int opno, long r)
        fl.l_whence = SEEK_SET;
        fl.l_start = off;
        fl.l_len = (off64_t)(random() % (1 << 20));
-       e = ioctl(fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
+       e = xfsctl(f.path, fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
        if (v)
-               printf("%d/%d: ioctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n",
-                       procid, opno, f.path, off, fl.l_len, e);
+               printf("%d/%d: xfsctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n",
+                       procid, opno, f.path,
+                       (long long)off, (long long)fl.l_len, e);
        free_pathname(&f);
        close(fd);
 }
@@ -2476,7 +2486,7 @@ write_f(int opno, long r)
        free(buf);
        if (v)
                printf("%d/%d: write %s [%lld,%d] %d\n",
-                       procid, opno, f.path, off, len, e);
+                       procid, opno, f.path, (long long)off, (int)len, e);
        free_pathname(&f);
        close(fd);
 }
diff --git a/ltp/fsx.c b/ltp/fsx.c
new file mode 100644 (file)
index 0000000..25a0e96
--- /dev/null
+++ b/ltp/fsx.c
@@ -0,0 +1,1076 @@
+/*
+ * Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ *
+ *     File:   fsx.c
+ *     Author: Avadis Tevanian, Jr.
+ *
+ *     File system exerciser. 
+ *
+ *     Rewritten 8/98 by Conrad Minshall.
+ *
+ *     Small changes to work under Linux -- davej.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <limits.h>
+#include <time.h>
+#include <strings.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <limits.h>
+#include <err.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#ifndef MAP_FILE
+# define MAP_FILE 0
+#endif
+
+#define NUMPRINTCOLUMNS 32     /* # columns of data to print on each line */
+
+/*
+ *     A log entry is an operation and a bunch of arguments.
+ */
+
+struct log_entry {
+       int     operation;
+       int     args[3];
+};
+
+#define        LOGSIZE 1000
+
+struct log_entry       oplog[LOGSIZE]; /* the log */
+int                    logptr = 0;     /* current position in log */
+int                    logcount = 0;   /* total ops */
+
+/*
+ *     Define operations
+ */
+
+#define        OP_READ         1
+#define OP_WRITE       2
+#define OP_TRUNCATE    3
+#define OP_CLOSEOPEN   4
+#define OP_MAPREAD     5
+#define OP_MAPWRITE    6
+#define OP_SKIPPED     7
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE       getpagesize()
+#endif
+#define PAGE_MASK       (PAGE_SIZE - 1)
+
+char   *original_buf;                  /* a pointer to the original data */
+char   *good_buf;                      /* a pointer to the correct data */
+char   *temp_buf;                      /* a pointer to the current data */
+char   *fname;                         /* name of our test file */
+int    fd;                             /* fd for our test file */
+
+off_t          file_size = 0;
+off_t          biggest = 0;
+char           state[256];
+unsigned long  testcalls = 0;          /* calls to function "test" */
+
+unsigned long  simulatedopcount = 0;   /* -b flag */
+int    closeprob = 0;                  /* -c flag */
+int    debug = 0;                      /* -d flag */
+unsigned long  debugstart = 0;         /* -D flag */
+unsigned long  maxfilelen = 256 * 1024;        /* -l flag */
+int    sizechecks = 1;                 /* -n flag disables them */
+int    maxoplen = 64 * 1024;           /* -o flag */
+int    quiet = 0;                      /* -q flag */
+unsigned long progressinterval = 0;    /* -p flag */
+int    readbdy = 1;                    /* -r flag */
+int    style = 0;                      /* -s flag */
+int    truncbdy = 1;                   /* -t flag */
+int    writebdy = 1;                   /* -w flag */
+long   monitorstart = -1;              /* -m flag */
+long   monitorend = -1;                /* -m flag */
+int    lite = 0;                       /* -L flag */
+long   numops = -1;                    /* -N flag */
+int    randomoplen = 1;                /* -O flag disables it */
+int    seed = 1;                       /* -S flag */
+int     mapped_writes = 1;              /* -W flag disables */
+int    mapped_reads = 1;               /* -R flag disables it */
+int    fsxgoodfd = 0;
+FILE * fsxlogf = NULL;
+int badoff = -1;
+int closeopen = 0;
+
+
+void
+prt(char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       vfprintf(stdout, fmt, args);
+       if (fsxlogf)
+               vfprintf(fsxlogf, fmt, args);
+       va_end(args);
+}
+
+void
+prterr(char *prefix)
+{
+       prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
+}
+
+
+void
+log4(int operation, int arg0, int arg1, int arg2)
+{
+       struct log_entry *le;
+
+       le = &oplog[logptr];
+       le->operation = operation;
+       if (closeopen)
+               le->operation = ~ le->operation;
+       le->args[0] = arg0;
+       le->args[1] = arg1;
+       le->args[2] = arg2;
+       logptr++;
+       logcount++;
+       if (logptr >= LOGSIZE)
+               logptr = 0;
+}
+
+
+void
+logdump(void)
+{
+       int     i, count, down;
+       struct log_entry        *lp;
+
+       prt("LOG DUMP (%d total operations):\n", logcount);
+       if (logcount < LOGSIZE) {
+               i = 0;
+               count = logcount;
+       } else {
+               i = logptr;
+               count = LOGSIZE;
+       }
+       for ( ; count > 0; count--) {
+               int opnum;
+
+               opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
+               prt("%d(%d mod 256): ", opnum, opnum%256);
+               lp = &oplog[i];
+               if ((closeopen = lp->operation < 0))
+                       lp->operation = ~ lp->operation;
+                       
+               switch (lp->operation) {
+               case OP_MAPREAD:
+                       prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)",
+                           lp->args[0], lp->args[0] + lp->args[1] - 1,
+                           lp->args[1]);
+                       if (badoff >= lp->args[0] && badoff <
+                                                    lp->args[0] + lp->args[1])
+                               prt("\t***RRRR***");
+                       break;
+               case OP_MAPWRITE:
+                       prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)",
+                           lp->args[0], lp->args[0] + lp->args[1] - 1,
+                           lp->args[1]);
+                       if (badoff >= lp->args[0] && badoff <
+                                                    lp->args[0] + lp->args[1])
+                               prt("\t******WWWW");
+                       break;
+               case OP_READ:
+                       prt("READ\t0x%x thru 0x%x\t(0x%x bytes)",
+                           lp->args[0], lp->args[0] + lp->args[1] - 1,
+                           lp->args[1]);
+                       if (badoff >= lp->args[0] &&
+                           badoff < lp->args[0] + lp->args[1])
+                               prt("\t***RRRR***");
+                       break;
+               case OP_WRITE:
+                       prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)",
+                           lp->args[0], lp->args[0] + lp->args[1] - 1,
+                           lp->args[1]);
+                       if (lp->args[0] > lp->args[2])
+                               prt(" HOLE");
+                       else if (lp->args[0] + lp->args[1] > lp->args[2])
+                               prt(" EXTEND");
+                       if ((badoff >= lp->args[0] || badoff >=lp->args[2]) &&
+                           badoff < lp->args[0] + lp->args[1])
+                               prt("\t***WWWW");
+                       break;
+               case OP_TRUNCATE:
+                       down = lp->args[0] < lp->args[1];
+                       prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
+                           down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
+                       if (badoff >= lp->args[!down] &&
+                           badoff < lp->args[!!down])
+                               prt("\t******WWWW");
+                       break;
+               case OP_SKIPPED:
+                       prt("SKIPPED (no operation)");
+                       break;
+               default:
+                       prt("BOGUS LOG ENTRY (operation code = %d)!",
+                           lp->operation);
+               }
+               if (closeopen)
+                       prt("\n\t\tCLOSE/OPEN");
+               prt("\n");
+               i++;
+               if (i == LOGSIZE)
+                       i = 0;
+       }
+}
+
+
+void
+save_buffer(char *buffer, off_t bufferlength, int fd)
+{
+       off_t ret;
+       ssize_t byteswritten;
+
+       if (fd <= 0 || bufferlength == 0)
+               return;
+
+       if (bufferlength > SSIZE_MAX) {
+               prt("fsx flaw: overflow in save_buffer\n");
+               exit(67);
+       }
+       if (lite) {
+               off_t size_by_seek = lseek(fd, (off_t)0, L_XTND);
+               if (size_by_seek == (off_t)-1)
+                       prterr("save_buffer: lseek eof");
+               else if (bufferlength > size_by_seek) {
+                                                fprintf(stderr, "save_buffer: .fsxgood file too short... will save 0x%qx bytes instead of 0x%qx\n", (unsigned long long)size_by_seek,
+                            (unsigned long long)bufferlength);
+                       bufferlength = size_by_seek;
+               }
+       }
+
+       ret = lseek(fd, (off_t)0, SEEK_SET);
+       if (ret == (off_t)-1)
+               prterr("save_buffer: lseek 0");
+       
+       byteswritten = write(fd, buffer, (size_t)bufferlength);
+       if (byteswritten != bufferlength) {
+               if (byteswritten == -1)
+                       prterr("save_buffer write");
+               else
+                                                fprintf(stderr, "save_buffer: short write, 0x%x bytes instead of 0x%qx\n",
+                            (unsigned)byteswritten,
+                            (unsigned long long)bufferlength);
+       }
+}
+
+
+void
+report_failure(int status)
+{
+       logdump();
+       
+       if (fsxgoodfd) {
+               if (good_buf) {
+                       save_buffer(good_buf, file_size, fsxgoodfd);
+                       prt("Correct content saved for comparison\n");
+                       prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n",
+                           fname, fname);
+               }
+               close(fsxgoodfd);
+       }
+       exit(status);
+}
+
+
+#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
+                                       *(((unsigned char *)(cp)) + 1)))
+
+void
+check_buffers(unsigned offset, unsigned size)
+{
+       unsigned char c, t;
+       unsigned i = 0;
+       unsigned n = 0;
+       unsigned op = 0;
+       unsigned bad = 0;
+
+       if (bcmp(good_buf + offset, temp_buf, size) != 0) {
+               prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n",
+                   offset, size);
+               prt("OFFSET\tGOOD\tBAD\tRANGE\n");
+               while (size > 0) {
+                       c = good_buf[offset];
+                       t = temp_buf[i];
+                       if (c != t) {
+                               if (n == 0) {
+                                       bad = short_at(&temp_buf[i]);
+                                       prt("0x%5x\t0x%04x\t0x%04x", offset,
+                                           short_at(&good_buf[offset]), bad);
+                                       op = temp_buf[offset & 1 ? i+1 : i];
+                               }
+                               n++;
+                               badoff = offset;
+                       }
+                       offset++;
+                       i++;
+                       size--;
+               }
+               if (n) {
+                       prt("\t0x%5x\n", n);
+                       if (bad)
+                               prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff));
+                       else
+                               prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n");
+               } else
+                       prt("????????????????\n");
+               report_failure(110);
+       }
+}
+
+
+void
+check_size(void)
+{
+       struct stat     statbuf;
+       off_t   size_by_seek;
+
+       if (fstat(fd, &statbuf)) {
+               prterr("check_size: fstat");
+               statbuf.st_size = -1;
+       }
+       size_by_seek = lseek(fd, (off_t)0, L_XTND);
+       if (file_size != statbuf.st_size || file_size != size_by_seek) {
+               prt("Size error: expected 0x%qx stat 0x%qx seek 0x%qx\n",
+                   (unsigned long long)file_size,
+                   (unsigned long long)statbuf.st_size,
+                   (unsigned long long)size_by_seek);
+               report_failure(120);
+       }
+}
+
+
+void
+check_trunc_hack(void)
+{
+       struct stat statbuf;
+
+       ftruncate(fd, (off_t)0);
+       ftruncate(fd, (off_t)100000);
+       fstat(fd, &statbuf);
+       if (statbuf.st_size != (off_t)100000) {
+               prt("no extend on truncate! not posix!\n");
+               exit(130);
+       }
+       ftruncate(fd, 0);
+}
+
+
+void
+doread(unsigned offset, unsigned size)
+{
+       off_t ret;
+       unsigned iret;
+
+       offset -= offset % readbdy;
+       if (size == 0) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping zero size read\n");
+               log4(OP_SKIPPED, OP_READ, offset, size);
+               return;
+       }
+       if (size + offset > file_size) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping seek/read past end of file\n");
+               log4(OP_SKIPPED, OP_READ, offset, size);
+               return;
+       }
+
+       log4(OP_READ, offset, size, 0);
+
+       if (testcalls <= simulatedopcount)
+               return;
+
+       if (!quiet && ((progressinterval && !(testcalls % progressinterval)) ||
+                      (debug &&
+                       (monitorstart == -1 ||
+                        (offset + size > monitorstart &&
+                         (monitorend == -1 || offset <= monitorend))))))
+               prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+                   offset, offset + size - 1, size);
+       ret = lseek(fd, (off_t)offset, SEEK_SET);
+       if (ret == (off_t)-1) {
+               prterr("doread: lseek");
+               report_failure(140);
+       }
+       iret = read(fd, temp_buf, size);
+       if (iret != size) {
+               if (iret == -1)
+                       prterr("doread: read");
+               else
+                       prt("short read: 0x%x bytes instead of 0x%x\n",
+                           iret, size);
+               report_failure(141);
+       }
+       check_buffers(offset, size);
+}
+
+
+void
+domapread(unsigned offset, unsigned size)
+{
+       unsigned pg_offset;
+       unsigned map_size;
+       char    *p;
+
+       offset -= offset % readbdy;
+       if (size == 0) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping zero size read\n");
+               log4(OP_SKIPPED, OP_MAPREAD, offset, size);
+               return;
+       }
+       if (size + offset > file_size) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping seek/read past end of file\n");
+               log4(OP_SKIPPED, OP_MAPREAD, offset, size);
+               return;
+       }
+
+       log4(OP_MAPREAD, offset, size, 0);
+
+       if (testcalls <= simulatedopcount)
+               return;
+
+       if (!quiet && ((progressinterval && !(testcalls % progressinterval)) ||
+                      (debug &&
+                       (monitorstart == -1 ||
+                        (offset + size > monitorstart &&
+                         ((monitorend == -1 || offset <= monitorend)))))))
+               prt("%lu mapread\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+                   offset, offset + size - 1, size);
+
+       pg_offset = offset & PAGE_MASK;
+       map_size  = pg_offset + size;
+
+       if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_SHARED, fd,
+                             (off_t)(offset - pg_offset))) == (char *)-1) {
+               prterr("domapread: mmap");
+               report_failure(190);
+       }
+       memcpy(temp_buf, p + pg_offset, size);
+       if (munmap(p, map_size) != 0) {
+               prterr("domapread: munmap");
+               report_failure(191);
+       }
+
+       check_buffers(offset, size);
+}
+
+
+void
+gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
+{
+       while (size--) {
+               good_buf[offset] = testcalls % 256; 
+               if (offset % 2)
+                       good_buf[offset] += original_buf[offset];
+               offset++;
+       }
+}
+
+
+void
+dowrite(unsigned offset, unsigned size)
+{
+       off_t ret;
+       unsigned iret;
+
+       offset -= offset % writebdy;
+       if (size == 0) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping zero size write\n");
+               log4(OP_SKIPPED, OP_WRITE, offset, size);
+               return;
+       }
+
+       log4(OP_WRITE, offset, size, file_size);
+
+       gendata(original_buf, good_buf, offset, size);
+       if (file_size < offset + size) {
+               if (file_size < offset)
+                       bzero(good_buf + file_size, offset - file_size);
+               file_size = offset + size;
+               if (lite) {
+                                                fprintf(stderr, "Lite file size bug in fsx!");
+                       report_failure(149);
+               }
+       }
+
+       if (testcalls <= simulatedopcount)
+               return;
+       if (!quiet && ((progressinterval && !(testcalls % progressinterval)) ||
+                      (debug &&
+                       (monitorstart == -1 ||
+                        (offset + size > monitorstart &&
+                         ((monitorend == -1 || offset <= monitorend)))))))
+               prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+                   offset, offset + size - 1, size);
+       ret = lseek(fd, (off_t)offset, SEEK_SET);
+       if (ret == (off_t)-1) {
+               prterr("dowrite: lseek");
+               report_failure(150);
+       }
+       iret = write(fd, good_buf + offset, size);
+       if (iret != size) {
+               if (iret == -1)
+                       prterr("dowrite: write");
+               else
+                       prt("short write: 0x%x bytes instead of 0x%x\n",
+                           iret, size);
+               report_failure(151);
+       }
+}
+
+
+void
+domapwrite(unsigned offset, unsigned size)
+{
+       unsigned pg_offset;
+       unsigned map_size;
+       off_t    cur_filesize;
+       char    *p;
+
+       offset -= offset % writebdy;
+       if (size == 0) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping zero size write\n");
+               log4(OP_SKIPPED, OP_MAPWRITE, offset, size);
+               return;
+       }
+       cur_filesize = file_size;
+
+       log4(OP_MAPWRITE, offset, size, 0);
+
+       gendata(original_buf, good_buf, offset, size);
+       if (file_size < offset + size) {
+               if (file_size < offset)
+                       bzero(good_buf + file_size, offset - file_size);
+               file_size = offset + size;
+               if (lite) {
+                                                fprintf(stderr, "Lite file size bug in fsx!");
+                       report_failure(200);
+               }
+       }
+
+       if (testcalls <= simulatedopcount)
+               return;
+
+       if (!quiet && ((progressinterval && !(testcalls % progressinterval)) ||
+                      (debug &&
+                       (monitorstart == -1 ||
+                        (offset + size > monitorstart &&
+                         (monitorend == -1 || offset <= monitorend))))))
+               prt("%lu mapwrite\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+                   offset, offset + size - 1, size);
+
+       if (file_size > cur_filesize) {
+               if (ftruncate(fd, file_size) == -1) {
+                       prterr("domapwrite: ftruncate");
+                       exit(201);
+               }
+       }
+       pg_offset = offset & PAGE_MASK;
+       map_size  = pg_offset + size;
+
+       if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
+                             MAP_FILE | MAP_SHARED, fd,
+                             (off_t)(offset - pg_offset))) == (char *)-1) {
+               prterr("domapwrite: mmap");
+               report_failure(202);
+       }
+       memcpy(p + pg_offset, good_buf + offset, size);
+       if (msync(p, map_size, 0) != 0) {
+               prterr("domapwrite: msync");
+               report_failure(203);
+       }
+       if (munmap(p, map_size) != 0) {
+               prterr("domapwrite: munmap");
+               report_failure(204);
+       }
+}
+
+
+void
+dotruncate(unsigned size)
+{
+       int oldsize = file_size;
+
+       size -= size % truncbdy;
+       if (size > biggest) {
+               biggest = size;
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("truncating to largest ever: 0x%x\n", size);
+       }
+
+       log4(OP_TRUNCATE, size, (unsigned)file_size, 0);
+
+       if (size > file_size)
+               bzero(good_buf + file_size, size - file_size);
+       file_size = size;
+
+       if (testcalls <= simulatedopcount)
+               return;
+       
+       if ((progressinterval && !(testcalls % progressinterval)) ||
+           (debug && (monitorstart == -1 || monitorend == -1 ||
+                     size <= monitorend)))
+               prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size);
+       if (ftruncate(fd, (off_t)size) == -1) {
+               prt("ftruncate1: %x\n", size);
+               prterr("dotruncate: ftruncate");
+               report_failure(160);
+       }
+}
+
+
+void
+writefileimage()
+{
+       ssize_t iret;
+
+       if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
+               prterr("writefileimage: lseek");
+               report_failure(171);
+       }
+       iret = write(fd, good_buf, file_size);
+       if ((off_t)iret != file_size) {
+               if (iret == -1)
+                       prterr("writefileimage: write");
+               else
+                       prt("short write: 0x%x bytes instead of 0x%qx\n",
+                           iret, (unsigned long long)file_size);
+               report_failure(172);
+       }
+       if (lite ? 0 : ftruncate(fd, file_size) == -1) {
+               prt("ftruncate2: %qx\n", (unsigned long long)file_size);
+               prterr("writefileimage: ftruncate");
+               report_failure(173);
+       }
+}
+
+
+void
+docloseopen(void)
+{ 
+       if (testcalls <= simulatedopcount)
+               return;
+
+       if (debug)
+               prt("%lu close/open\n", testcalls);
+       if (close(fd)) {
+               prterr("docloseopen: close");
+               report_failure(180);
+       }
+       fd = open(fname, O_RDWR, 0);
+       if (fd < 0) {
+               prterr("docloseopen: open");
+               report_failure(181);
+       }
+}
+
+
+void
+test(void)
+{
+       unsigned long   offset;
+       unsigned long   size = maxoplen;
+       unsigned long   rv = random();
+       unsigned long   op = rv % (3 + !lite + mapped_writes);
+
+        /* turn off the map read if necessary */
+
+        if (op == 2 && !mapped_reads)
+            op = 0;
+
+       if (simulatedopcount > 0 && testcalls == simulatedopcount)
+               writefileimage();
+
+       testcalls++;
+
+       if (closeprob)
+               closeopen = (rv >> 3) < (1 << 28) / closeprob;
+
+       if (debugstart > 0 && testcalls >= debugstart)
+               debug = 1;
+
+       if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
+               prt("%lu...\n", testcalls);
+
+       /*
+        * READ:        op = 0
+        * WRITE:       op = 1
+        * MAPREAD:     op = 2
+        * TRUNCATE:    op = 3
+        * MAPWRITE:    op = 3 or 4
+        */
+       if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */
+               dotruncate(random() % maxfilelen);
+       else {
+               if (randomoplen)
+                       size = random() % (maxoplen+1);
+               if (lite ? 0 : op == 3)
+                       dotruncate(size);
+               else {
+                       offset = random();
+                       if (op == 1 || op == (lite ? 3 : 4)) {
+                               offset %= maxfilelen;
+                               if (offset + size > maxfilelen)
+                                       size = maxfilelen - offset;
+                               if (op != 1)
+                                       domapwrite(offset, size);
+                               else
+                                       dowrite(offset, size);
+                       } else {
+                               if (file_size)
+                                       offset %= file_size;
+                               else
+                                       offset = 0;
+                               if (offset + size > file_size)
+                                       size = file_size - offset;
+                               if (op != 0)
+                                       domapread(offset, size);
+                               else
+                                       doread(offset, size);
+                       }
+               }
+       }
+       if (sizechecks && testcalls > simulatedopcount)
+               check_size();
+       if (closeopen)
+               docloseopen();
+}
+
+
+void
+cleanup(sig)
+       int     sig;
+{
+       if (sig)
+               prt("signal %d\n", sig);
+       prt("testcalls = %lu\n", testcalls);
+       exit(sig);
+}
+
+
+void
+usage(void)
+{
+       fprintf(stdout, "usage: %s",
+               "fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\
+       -b opnum: beginning operation number (default 1)\n\
+       -c P: 1 in P chance of file close+open at each op (default infinity)\n\
+       -d: debug output for all operations\n\
+       -l flen: the upper bound on file size (default 262144)\n\
+       -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
+       -n: no verifications of file size\n\
+       -o oplen: the upper bound on operation size (default 65536)\n\
+       -p progressinterval: debug output at specified operation interval\n\
+       -q: quieter operation\n\
+       -r readbdy: 4096 would make reads page aligned (default 1)\n\
+       -s style: 1 gives smaller truncates (default 0)\n\
+       -t truncbdy: 4096 would make truncates page aligned (default 1)\n\
+       -w writebdy: 4096 would make writes page aligned (default 1)\n\
+       -D startingop: debug output starting at specified operation\n\
+       -L: fsxLite - no file creations & no file size changes\n\
+       -N numops: total # operations to do (default infinity)\n\
+       -O: use oplen (see -o flag) for every op (default random)\n\
+       -P: save .fsxlog and .fsxgood files in dirpath (default ./)\n\
+       -S seed: for random # generator (default 1) 0 gets timestamp\n\
+       -W: mapped write operations DISabled\n\
+        -R: read() system calls only (mapped reads disabled)\n\
+       fname: this filename is REQUIRED (no default)\n");
+       exit(90);
+}
+
+
+int
+getnum(char *s, char **e)
+{
+       int ret = -1;
+
+       *e = (char *) 0;
+       ret = strtol(s, e, 0);
+       if (*e)
+               switch (**e) {
+               case 'b':
+               case 'B':
+                       ret *= 512;
+                       *e = *e + 1;
+                       break;
+               case 'k':
+               case 'K':
+                       ret *= 1024;
+                       *e = *e + 1;
+                       break;
+               case 'm':
+               case 'M':
+                       ret *= 1024*1024;
+                       *e = *e + 1;
+                       break;
+               case 'w':
+               case 'W':
+                       ret *= 4;
+                       *e = *e + 1;
+                       break;
+               }
+       return (ret);
+}
+
+
+int
+main(int argc, char **argv)
+{
+       int     i, style, ch;
+       char    *endp;
+       char goodfile[1024];
+       char logfile[1024];
+
+       goodfile[0] = 0;
+       logfile[0] = 0;
+
+       setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
+
+       while ((ch = getopt(argc, argv, "b:c:dl:m:no:p:qr:s:t:w:D:LN:OP:RS:W"))
+              != EOF)
+               switch (ch) {
+               case 'b':
+                       simulatedopcount = getnum(optarg, &endp);
+                       if (!quiet)
+                               fprintf(stdout, "Will begin at operation %ld\n",
+                                       simulatedopcount);
+                       if (simulatedopcount == 0)
+                               usage();
+                       simulatedopcount -= 1;
+                       break;
+               case 'c':
+                       closeprob = getnum(optarg, &endp);
+                       if (!quiet)
+                               fprintf(stdout,
+                                       "Chance of close/open is 1 in %d\n",
+                                       closeprob);
+                       if (closeprob <= 0)
+                               usage();
+                       break;
+               case 'd':
+                       debug = 1;
+                       break;
+               case 'l':
+                       maxfilelen = getnum(optarg, &endp);
+                       if (maxfilelen <= 0)
+                               usage();
+                       break;
+               case 'm':
+                       monitorstart = getnum(optarg, &endp);
+                       if (monitorstart < 0)
+                               usage();
+                       if (!endp || *endp++ != ':')
+                               usage();
+                       monitorend = getnum(endp, &endp);
+                       if (monitorend < 0)
+                               usage();
+                       if (monitorend == 0)
+                               monitorend = -1; /* aka infinity */
+                       debug = 1;
+               case 'n':
+                       sizechecks = 0;
+                       break;
+               case 'o':
+                       maxoplen = getnum(optarg, &endp);
+                       if (maxoplen <= 0)
+                               usage();
+                       break;
+               case 'p':
+                       progressinterval = getnum(optarg, &endp);
+                       if (progressinterval < 0)
+                               usage();
+                       break;
+               case 'q':
+                       quiet = 1;
+                       break;
+               case 'r':
+                       readbdy = getnum(optarg, &endp);
+                       if (readbdy <= 0)
+                               usage();
+                       break;
+               case 's':
+                       style = getnum(optarg, &endp);
+                       if (style < 0 || style > 1)
+                               usage();
+                       break;
+               case 't':
+                       truncbdy = getnum(optarg, &endp);
+                       if (truncbdy <= 0)
+                               usage();
+                       break;
+               case 'w':
+                       writebdy = getnum(optarg, &endp);
+                       if (writebdy <= 0)
+                               usage();
+                       break;
+               case 'D':
+                       debugstart = getnum(optarg, &endp);
+                       if (debugstart < 1)
+                               usage();
+                       break;
+               case 'L':
+                       lite = 1;
+                       break;
+               case 'N':
+                       numops = getnum(optarg, &endp);
+                       if (numops < 0)
+                               usage();
+                       break;
+               case 'O':
+                       randomoplen = 0;
+                       break;
+               case 'P':
+                       strncpy(goodfile, optarg, sizeof(goodfile));
+                       strcat(goodfile, "/");
+                       strncpy(logfile, optarg, sizeof(logfile));
+                       strcat(logfile, "/");
+                       break;
+                case 'R':
+                        mapped_reads = 0;
+                        break;
+               case 'S':
+                        seed = getnum(optarg, &endp);
+                       if (seed == 0)
+                               seed = time(0) % 10000;
+                       if (!quiet)
+                               fprintf(stdout, "Seed set to %d\n", seed);
+                       if (seed < 0)
+                               usage();
+                       break;
+               case 'W':
+                       mapped_writes = 0;
+                       if (!quiet)
+                               fprintf(stdout, "mapped writes DISABLED\n");
+                       break;
+              
+               default:
+                       usage();
+                       /* NOTREACHED */
+               }
+       argc -= optind;
+       argv += optind;
+       if (argc != 1)
+               usage();
+       fname = argv[0];
+
+
+       signal(SIGHUP,  cleanup);
+       signal(SIGINT,  cleanup);
+       signal(SIGPIPE, cleanup);
+       signal(SIGALRM, cleanup);
+       signal(SIGTERM, cleanup);
+       signal(SIGXCPU, cleanup);
+       signal(SIGXFSZ, cleanup);
+       signal(SIGVTALRM,       cleanup);
+       signal(SIGUSR1, cleanup);
+       signal(SIGUSR2, cleanup);
+
+       initstate(seed, state, 256);
+       setstate(state);
+       fd = open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666);
+       if (fd < 0) {
+               prterr(fname);
+               exit(91);
+       }
+       strncat(goodfile, fname, 256);
+       strcat (goodfile, ".fsxgood");
+       fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
+       if (fsxgoodfd < 0) {
+               prterr(goodfile);
+               exit(92);
+       }
+       strncat(logfile, fname, 256);
+       strcat (logfile, ".fsxlog");
+       fsxlogf = fopen(logfile, "w");
+       if (fsxlogf == NULL) {
+               prterr(logfile);
+               exit(93);
+       }
+       if (lite) {
+               off_t ret;
+               file_size = maxfilelen = lseek(fd, (off_t)0, L_XTND);
+               if (file_size == (off_t)-1) {
+                       prterr(fname);
+                                                fprintf(stderr, "main: lseek eof");
+                       exit(94);
+               }
+               ret = lseek(fd, (off_t)0, SEEK_SET);
+               if (ret == (off_t)-1) {
+                       prterr(fname);
+                                                fprintf(stderr, "main: lseek 0");
+                       exit(95);
+               }
+       }
+       original_buf = (char *) malloc(maxfilelen);
+       for (i = 0; i < maxfilelen; i++)
+               original_buf[i] = random() % 256;
+       good_buf = (char *) malloc(maxfilelen);
+       bzero(good_buf, maxfilelen);
+       temp_buf = (char *) malloc(maxoplen);
+       bzero(temp_buf, maxoplen);
+       if (lite) {     /* zero entire existing file */
+               ssize_t written;
+
+               written = write(fd, good_buf, (size_t)maxfilelen);
+               if (written != maxfilelen) {
+                       if (written == -1) {
+                               prterr(fname);
+                               fprintf(stderr, "main: error on write");
+                       } else
+                               fprintf(stderr, "main: short write, 0x%x bytes instead of 0x%lx\n",
+                                    (unsigned)written, maxfilelen);
+                       exit(98);
+               }
+       } else 
+               check_trunc_hack();
+
+       while (numops == -1 || numops--)
+               test();
+
+       if (close(fd)) {
+               prterr("close");
+               report_failure(99);
+       }
+       prt("All operations completed A-OK!\n");
+
+       exit(0);
+       return 0;
+}
diff --git a/ltp/growfiles.c b/ltp/growfiles.c
new file mode 100644 (file)
index 0000000..21de853
--- /dev/null
@@ -0,0 +1,2819 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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 is a fifo
+ *     prealloc file space (if wanted)
+ *      growfile
+ *     check last write
+ *     check whole file
+ *     shrink file
+ *     close file
+ *     delay (if wanted)
+ *    End loop
+ *  End loop
+ *  remove all files (if wanted)
+ *
+ * Author: Richard Logan
+ *
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <errno.h>
+#include <string.h>
+#include "dataascii.h"
+#include "random_range.h"
+#include "databin.h"
+
+#ifndef NO_XFS
+#include <xfs/libxfs.h>
+#endif
+
+#ifdef CRAY
+#include <sys/panic.h>
+#include <sys/category.h>
+#endif
+
+extern char *openflags2symbols();
+
+extern int parse_open_flags();
+extern int background();
+extern int forker();
+extern int datapidgen();
+extern void databingen();
+extern int datapidchk();
+extern int databinchk();
+extern int file_lock();
+
+int file_size();
+int check_write();
+int shrinkfile();
+int check_file();
+int growfile();
+int cleanup();
+int handle_error();
+int lkfile();
+void usage();
+void help();
+void prt_examples();
+int set_sig();
+void sig_handler();
+static void notify_others();
+#ifndef NO_XFS
+int pre_alloc();
+#endif
+
+
+#define NEWIO  1       /* Use the tlibio.c functions */
+
+#ifndef NEWIO
+#define NEWIO  0       /* specifies to use original iowrite.c */
+                       /* functions instead of tlibio.c functions */
+                       /* Once it is proven tlibio.c functions work properly, */
+                       /* only tlibio.c functions will be used */
+#else
+#include "tlibio.h"
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX       1023
+#endif
+
+
+#define DEF_DIR                "."
+#define DEF_FILE       "gf"
+
+char *Progname;
+int Debug  = 1;
+
+int Pid=0;
+
+int io_type = 0;                       /* I/O type -sync */
+int open_flags = O_RDWR|O_CREAT;       /* open flags */
+
+#define MAX_FC_READ    196608          /* 4096 * 48 - 48 blocks */
+
+#define PATTERN_ASCII  1       /* repeating alphabet letter pattern */
+                               /* allows multiple writers and to be checked */
+#define PATTERN_PID    2       /* <pid><words byte offset><pid> */
+                               /* Assumes 64 bit word. Only allows single */
+                               /* process to write and check */
+/*
+ *     1234567890123456789012345678901234567890123456789012345678901234
+ *     ________________________________________________________________
+ *     <    pid       >< offset in file of this word  ><    pid       >
+ */
+       
+#define PATTERN_OFFSET 3       /* Like PATTERN_PID but has a fixed number */
+                               /* (STATIC_NUM) instead of pid. */
+                               /* Allows multiple processes to write/read */
+#define PATTERN_ALT    4       /* alternating bit pattern (i.e. 0x5555555...) */
+#define PATTERN_CHKER  5       /* checkerboard pattern (i.e. 0xff00ff00ff00...) */
+#define PATTERN_CNTING  6      /* counting pattern (i.e. 0 - 07, 0 - 07, ...) */
+#define PATTERN_ONES   7       /* all bits set (i.e. 0xffffffffffffff...) */
+#define PATTERN_ZEROS  8       /* all bits cleared (i.e. 0x000000000...) */
+#define PATTERN_RANDOM 9       /* random integers - can not be checked */
+#define STATIC_NUM     221849  /* used instead of pid when PATTERN_OFFSET */
+
+#define MODE_RAND_SIZE 1       /* random write and trunc */
+#define MODE_RAND_LSEEK        2       /* random lseek before write */
+#define MODE_GROW_BY_LSEEK 4   /* lseek beyond end of file then write a byte */
+#define RANDOM_OPEN    999876  /* if Open_flags set to this value, open flags */
+                               /* will be randomly choosen from Open_flags[] */
+#define MODE_FIFO      S_IFIFO /* defined in stat.h  0010000 */
+
+int num_files = 0;             /* num_auto_files + cmd line files */
+char *filenames;               /* pointer to space containing filenames */
+int remove_files = 0;          /* if set, cleanup default is not to cleanup */
+int bytes_consumed = 0;                /* total bytes consumed, all files */
+int bytes_to_consume = 0;      /* non-zero if -B was specified, total bytes */
+int Maxerrs = 100;             /* Max number errors before forced exit */
+int Errors = 0;                        /* number of encountered errors */
+int Upanic_on_error = 0;       /* call upanic if error and this variable set */
+
+/* The *_size variables are only used when random iosize option (-r) is used */
+int max_size=5000;
+int min_size=1;                        /* also set in option parsing */
+int mult_size=1;               /* when random iosz, iosz must be mult of mult_size */
+/* the *_lseek variables are only used when radon lseek option (-R) is used */
+int min_lseek=0;               /* also set in option parsing */
+int max_lseek=-1;              /* -1 means size of file */
+#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 */
+
+int Woffset=0;                 /* offset before last write */
+int Grow_incr=4096;            /* sz of last write */
+int Mode=0;                    /* bitmask of write/trunc mode */
+                               /* also knows if dealing with fifo */
+char *Buffer = NULL;           /* buffer used by write and write check */
+int Alignment=0;               /* if non word multiple, io will not be word aligned */
+int Opid=0;                    /* original pid */
+
+int Sync_with_others = 0;      /* Flag indicating to stop other if we stop before DONE */
+int Iter_cnt = 0;              /* contains current iteration count value */
+char   TagName[40];            /* name of this growfiles (see Monster)     */
+
+struct fileinfo_t {
+    char *filename;
+    int fd;
+    int openflags;
+    int mode;
+}  Fileinfo;
+
+/*
+ * Define open flags that will be used when '-o random' option is used.
+ * Note: If there is more than one growfiles doing its thing to the same
+ * file, O_TRUNC will cause data mismatches.  How you ask?
+ * timing of events, example:
+ *   Process one               Process two
+ *   ---------------           -------------
+ *   get write lock
+ *   fstat file
+ *   lseek
+ *   generate pattern
+ *                             open with O_TRUNC 
+ *   write with wrong pattern
+ *     because offset is wrong
+ *
+ *  The second process truncated the file after the pattern was
+ *  determined, thus the pattern is wrong for the file location.
+ *
+ * There can also be a timing problem with open flag O_APPEND if
+ * file locks are not being used (-l option).  Things could happen
+ * between the fstat and the write. Thus, writing the wrong pattern.
+ * If all processes observe the file locks, O_APPEND should be ok
+ * to use.
+ */
+int Open_flags[] = { 
+#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(argc, argv)
+int argc;
+char **argv;
+{
+extern char *optarg;            /* used by getopt */
+extern int optind;
+extern int opterr;
+
+int ind;
+int first_file_ind = 0;
+int num_auto_files = 0;                /* files created by tool */
+int seq_auto_files = 0;                /* auto files created by tool created by tool */
+char *auto_dir = DEF_DIR;
+char *auto_file = DEF_FILE;
+int grow_incr = 4096;
+int trunc_incr = 4096;
+int trunc_inter = 0;           /* 0 means none, */
+int unlink_inter = 0;          /* 0 means none, 1 means always unlink */
+int unlink_inter_ran = -1;     /* -1 -use unlink_inter, otherwise randomly choose */
+                               /* between unlink_inter and unlink_inter_ran */
+int file_check_inter = 0;      /* 0 means never, 1 means always */
+int write_check_inter = 1;     /* 0 means never, 1 means always */
+int iterations = 1;            /* number of increments to be added */
+int no_file_check = 0;         /* if set, no whole file checking will be done */
+int num;
+int fd;                                /* file descriptor */
+int stop = 0;                  /* loop stopper if set */
+int tmp;
+char chr;
+int ret;
+int pre_alloc_space = 0;
+#ifndef NO_XFS
+int total_grow_value = 0;      /* 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[40];               /* reason for loop termination */
+int num_procs=1;
+int forker_mode=0;
+int reexec=REXEC_INIT;         /* reexec info */
+char *exec_path=NULL;
+
+char *strrchr();
+
+char *filename;                 /* name of file specified by user */
+char *cptr;                    /* temp char pointer */
+extern int Forker_npids;       /* num of forked pid, defined in forker.c */
+
+
+       if ( argv[0][0] == '-' )
+          reexec=REXEC_DONE;
+       /*
+        * Determine name of file used to invoke this program
+        */
+       if ((Progname=strrchr(argv[0], '/')) != NULL)
+               Progname++;
+       else
+               Progname=argv[0];
+
+       TagName[0] = '\0';
+
+       /*
+        * Process options
+        */
+       while ((ind=getopt(argc, argv, 
+           "hB:C:c:bd:D:e:Ef:g:H:I:i:lL:n:N:O:o:pP:q:wt:r:R:s:S:T:uU:W:xy")) != EOF) {
+               switch(ind) {
+
+               case 'h' :
+                       help();
+                       exit(0);
+
+               case 'B':
+                       switch (sscanf(optarg, "%i%c",
+                                  &bytes_to_consume, &chr)) {
+                       case 1: /* noop */
+                               break;
+
+                       case 2:
+                               if (chr == 'b') {
+                                   bytes_to_consume *= BSIZE;
+                               } else {
+                                   fprintf(stderr,
+                                       "%s%s:  --B option arg invalid\n",
+                                       Progname, TagName);
+                                   usage();
+                                   exit(1);
+                               }
+                               break;
+
+                       default:
+                               fprintf(stderr, "%s%s: --B option arg invalid\n",
+                                       Progname, TagName);
+                               usage();
+                               exit(1);
+                               break;
+                       }
+
+                       break;
+
+               case 'E' :
+                       prt_examples(stdout);
+                       exit(0);
+
+               case 'b' :      /* batch */
+                       backgrnd=0;
+                       break;
+
+               case 'C':
+                       if (sscanf(optarg, "%i", &write_check_inter) != 1 ) {
+                               fprintf(stderr, "%s%s: --c option arg invalid\n",
+                                       Progname, TagName);
+                               usage();
+                               exit(1);
+                       }
+                      break;
+
+               case 'c':
+                       if (sscanf(optarg, "%i", &file_check_inter) != 1 ) {
+                               fprintf(stderr, "%s%s: --c option arg invalid\n",
+                                       Progname, TagName);
+                               usage();
+                               exit(1);
+                       }
+                       break;
+
+
+               case 'd':
+                       auto_dir=optarg;
+#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 ||
+                               num_auto_files < 0 ) {
+
+                               fprintf(stderr, "%s%s: --O option arg invalid\n",
+                                       Progname, TagName);
+                               usage();
+                               exit(1);
+                       }
+                       break;
+
+               case 'o':
+                       if ( strcmp(optarg, "random") == 0 ){
+                           open_flags=RANDOM_OPEN;
+                           using_random++;
+
+                       } else if ((open_flags=parse_open_flags(optarg, NULL)) == -1 ) {
+                           fprintf(stderr, "%s%s: --o arg contains invalid flag\n",
+                               Progname, TagName);
+                           exit(1);
+                       }
+                       break;
+
+
+               case 'p' :      /* pre allocate space */
+#ifdef NO_XFS
+                       printf("%s%s: --p is illegal option on this 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: Will call upanic after writes\n");
+#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=(int *)malloc(Nseeds*sizeof(int));
+
+                       /*
+                        * check that each seed is valid and put them in 
+                        * the newly malloc'ed Seeds arrary.
+                        */
+                       filename=cptr=optarg;
+                       for(Nseeds=0; *cptr; Nseeds++) {
+                           if ( (filename=strchr(cptr, ',')) == NULL ) {
+                               if ( sscanf(cptr, "%i", &Seeds[Nseeds]) < 1 ) {
+                                    fprintf(stderr, "%s%s: --s option arg %s invalid\n",
+                                        Progname, TagName, cptr);
+                                    usage();
+                                    exit(1);
+                               }
+                               Nseeds++;
+                                break;
+                           }
+
+                           *filename='\0';
+                           if ( sscanf(cptr, "%i", &Seeds[Nseeds]) < 1 ) {
+                               fprintf(stderr, "%s%s: --s option arg %s invalid\n",
+                                        Progname, TagName, cptr);
+                                usage();
+                                exit(1);
+                           }
+                           *filename=',';   /* restore string */
+                            cptr=filename;
+                           cptr++;
+                       }
+                       break;
+
+               case 't':
+                       if ((ret=sscanf(optarg, "%i%c", &trunc_incr, &chr)) < 1 ||
+                               trunc_incr < 0 ) {
+
+                               fprintf(stderr, "%s%s: --t option arg invalid\n",
+                                       Progname, TagName);
+                               usage();
+                               exit(1);
+                       }
+                       if ( ret == 2 ) {
+                               if ( chr == 'b' || chr == 'B' )
+                                       trunc_incr *= 4096;
+                               else {
+                                       fprintf(stderr,
+                                               "%s%s: --t option arg invalid\n",
+                                               Progname, TagName);
+                                       usage();
+                                       exit(1);
+                               }
+                       }
+                       break;
+
+               case 'T':       /* truncate interval */
+                       if (sscanf(optarg, "%i%c", &trunc_inter, &chr) != 1 ||
+                               trunc_inter < 0 ) {
+
+                               fprintf(stderr, "%s%s: --T option arg invalid\n",
+                                       Progname, TagName);
+                               usage();
+                               exit(1);
+                       }
+                       break;
+
+               case 'u':
+                       remove_files++;
+                       break;
+
+               case 'U':   /* how often to unlink file */
+                      /* 
+                       * formats:   
+                       *      A-B  - randomly pick interval between A and B 
+                       *      X    - unlink file every X iteration
+                       */
+                       if (sscanf(optarg, "%i-%i", &unlink_inter, 
+                                               &unlink_inter_ran) == 2 ) {
+
+                          if ( unlink_inter < 0 || unlink_inter_ran < 0 ) {
+                                fprintf(stderr, "%s%s: --U option arg invalid\n",
+                                        Progname, TagName);
+                                usage();
+                                exit(1);
+                          }
+                          /* ensure unlink_inter contains smaller value */
+                          if ( unlink_inter > unlink_inter_ran ) {
+                               tmp=unlink_inter_ran;
+                               unlink_inter_ran=unlink_inter;
+                               unlink_inter=tmp;
+                          }
+                          using_random++;
+
+                       } else if (sscanf(optarg, "%i%c", &unlink_inter, &chr) != 1 ||
+                                unlink_inter < 0 ) {
+
+                            fprintf(stderr, "%s%s: --U option arg invalid\n",
+                                 Progname, TagName);
+                            usage();
+                            exit(1);
+                        }
+                       break;
+
+               case 'x':
+                       if ( reexec != REXEC_DONE )
+                           reexec=REXEC_DOIT;
+                       break;
+
+               case 'w':
+                       Mode |= MODE_GROW_BY_LSEEK;
+                       break;
+
+               case 'W':
+                       sprintf( TagName, "(%.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 ) 
+                   Seed=time(0) + Pid;  /* default random seed */
+               else {
+                   Seed=Seeds[Forker_npids];
+               }
+           }
+       } else {
+           /* 
+            * Generate a random seed based on time and pid.
+            * It has a good chance of being unique for each pid.
+            */
+           Seed=time(0) + Pid;  /* default random seed */
+       }
+
+       random_range_seed(Seed);
+
+        if ( using_random && Debug > 0 )
+           printf("%s%s: %d DEBUG1 Using random seed of %d\n",
+               Progname, TagName, Pid, Seed);
+
+       if ( unlink_inter_ran > 0 ) {
+           /*
+            * Find unlinking file interval.  This must be done after
+            * the seed was set.   This allows multiple copies to
+            * get different intervals.
+            */
+           tmp=unlink_inter;
+           unlink_inter=random_range(tmp, unlink_inter_ran, 1, NULL);
+
+           if ( Debug > 2 )
+               printf("%s: %d DEBUG3 Unlink interval is %d (random %d - %d)\n",
+                   Progname, Pid, unlink_inter, tmp, unlink_inter_ran);
+       }
+
+       /*
+        * re-exec all childern if reexec is set to REXEC_DOIT.
+        * This is useful on MPP systems to get the
+        * child process on another PE.
+        */
+       if ( reexec == REXEC_DOIT && Opid != Pid ) {
+           if ( exec_path == NULL ) {
+               exec_path = argv[0];
+               /* Get space for cmd (2 extra, 1 for - and 1 fro NULL */
+               argv[0] = (char *)malloc(strlen(exec_path) + 2);
+               sprintf(argv[0], "-%s", exec_path);
+           }
+         
+           if ( Debug > 2 )
+               printf("%s: %d DEBUG3 %s/%d: execvp(%s, argv)\n",
+                   Progname, Pid, __FILE__, __LINE__, argv[0]);
+
+           execvp(argv[0], argv);
+        }
+
+       /*** begin filename stuff here *****/
+       /*
+        * Determine the number of files to be dealt with
+        */
+       if ( optind == argc ) {
+               /*
+                * no cmd line files, therfore, set
+                * the default number of auto created files
+                */
+               if ( ! num_auto_files && ! seq_auto_files )
+                       num_auto_files=1;
+       }
+       else {
+               first_file_ind=optind;
+               num_files += argc-optind;
+       }
+
+       if ( num_auto_files ) {
+               num_files += num_auto_files;
+       }
+
+       if ( seq_auto_files ) {
+               num_files += seq_auto_files;
+       }
+
+       /*
+        * get space for file names
+        */
+       if ((filenames=(char *)malloc(num_files*PATH_MAX)) == NULL) {
+               fprintf(stderr, "%s%s: %d %s/%d: malloc(%d) failed: %s\n",
+                       Progname, TagName, Pid, __FILE__, __LINE__, num_files*PATH_MAX,
+                       strerror(errno));
+               exit(1);
+       }
+
+       /*
+        * fill in filename cmd files then auto files.
+        */
+
+       num=0;
+       if ( first_file_ind ) {
+               for(ind=first_file_ind; ind<argc; ind++, num++) {
+                       strcpy((char *)filenames+(num*PATH_MAX), argv[ind]);
+               }
+       }
+
+       /*
+        * construct auto filename and insert them into filenames space
+        */
+               
+       for(ind=0;ind<num_auto_files; ind++, num++) {
+               sprintf((char *)filenames+(num*PATH_MAX), "%s.%d",
+                       tempnam(auto_dir, auto_file), ind );
+       }
+
+       /*
+        * construct auto seq filenames
+        */
+       for(ind=1; ind<=seq_auto_files; ind++, num++) {
+               sprintf((char *)filenames+(num*PATH_MAX), "%s/%s%d",
+                       auto_dir, auto_file, ind);
+       }
+
+/**** end filename stuff ****/
+
+       if ( time_iterval > 0 )
+               start_time=time(0);
+
+       /*
+        * get space for I/O buffer
+        */
+       if ( grow_incr ) {
+               if ((Buffer=(char *)malloc(grow_incr+Alignment)) == NULL) {
+                       fprintf(stderr, "%s%s: %d %s/%d: malloc(%d) failed: %s\n",
+                               Progname, TagName, Pid, __FILE__, __LINE__, grow_incr, strerror(errno));
+                       exit(1);
+               }
+               if ( Alignment )
+               Buffer = Buffer + Alignment;
+
+       }
+
+       if ( Debug > 2 ) {
+               printf("%s: %d DEBUG3 num_files = %d\n",
+                       Progname, Pid, num_files);
+       }
+
+#ifndef NO_XFS
+       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++) {
+
+           if ( iterations && Iter_cnt >= iterations+1 ) {
+               strcpy(reason, "Hit iteration value");
+               stop=1;
+               continue;
+           }
+
+           if (  (time_iterval > 0) && (start_time + time_iterval < time(0)) ) {
+               sprintf(reason, "Hit time value of %d", time_iterval);
+               stop=1;
+               continue;
+           }
+
+           if ( bytes_to_consume && bytes_consumed >= bytes_to_consume) {
+               sprintf(reason, "Hit bytes consumed value of %d", bytes_to_consume);
+               stop=1;
+                continue;
+            }
+
+           /*
+            * This loop will loop through all files.
+            * Each iteration, a single file can  be opened, written to,
+            * read to check the write, check the whole file, 
+            * truncated, and closed.   
+            */
+           for(ind=0; ind<num_files; ind++) {
+
+               fflush(stdout);
+               fflush(stderr);
+
+               filename=(char *)filenames+(ind*PATH_MAX);
+               Fileinfo.filename=(char *)filenames+(ind*PATH_MAX);
+
+
+               if ( open_flags ==  RANDOM_OPEN ) {
+                  ret=Open_flags[random_range(0, sizeof(Open_flags)/sizeof(int)-1, 1, NULL)];
+               }
+
+               else
+                  ret=open_flags;
+
+               Fileinfo.openflags=ret;
+
+               if ( Debug > 3 ) {
+                   printf("%s: %d DEBUG3 %s/%d: %d Open filename = %s, open flags = %#o %s\n",
+                       Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, ret, 
+                       openflags2symbols(ret, ",", NULL));
+               } 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 NO_XFS
+               /*
+                * preallocation is only done once, if specified.
+                */
+               if ( pre_alloc_space ) {
+                       if (pre_alloc(filename, fd, total_grow_value) != 0 ) {
+                               cleanup();
+                               exit(2);
+                       }
+                       if ( Debug > 1 ) {
+                               printf("%s: %d DEBUG2 %s/%d: pre_allocated %d for file %s\n",
+                                   Progname, Pid, __FILE__, __LINE__, total_grow_value, filename);
+                       }
+                       lkfile(fd, LOCK_UN, LKLVL1);   /* release lock */
+                       close(fd);
+                       Iter_cnt=0;     /* reset outside loop to restart from one */
+                       continue;
+               }
+#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.
+                */
+
+               if (growfile(fd, filename, grow_incr, Buffer) != 0 ) {
+                       handle_error();
+                       lkfile(fd, LOCK_UN, LKLVL1);   /* release lock */
+                       close(fd);
+                       continue;
+               }
+
+               /*
+                * check if last write is not corrupted
+                */
+               if ( check_write(fd, write_check_inter, filename,
+                                                       Mode) != 0 ) {
+                   handle_error();
+                }
+
+               /*
+                * Check that whole file is not corrupted.
+                */
+               if ( check_file(fd, file_check_inter, filename,
+                                               no_file_check) != 0 ) {
+                   handle_error();
+               }
+
+               /*
+                * shrink file by desired amount if it is time 
+                */
+
+               if ( shrinkfile(fd, filename, trunc_incr, trunc_inter, Mode) != 0 ) {
+                   handle_error();
+               }
+
+               lkfile(fd, LOCK_UN, LKLVL1);   /* release lock */
+
+               if ( Debug > 4 )
+                   printf("%s: %d DEBUG5 %s/%d: %d Closing file %s fd:%d \n", 
+                       Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, fd);
+               close(fd);
+
+               /*
+                * Unlink the file if that is desired
+                */
+               if ( unlink_inter && (Iter_cnt % unlink_inter == 0) ) {
+               
+                   if ( Debug > 4 )
+                       printf("%s: %d DEBUG5 %s/%d: %d Unlinking file %s\n", 
+                           Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename);
+
+                   unlink(filename);
+               }
+
+               /*
+                * delay while staying active for "delaysecs" seconds.
+                */
+               if ( delaytime ) {
+               
+                   int ct, end;
+#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 NO_XFS
+           /*
+            * 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);
+}
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+set_sig()
+{
+   int sig;
+
+       
+        /*
+         * now loop through all signals and set the handlers
+         */
+
+        for (sig = 1; sig < NSIG; sig++) {
+            switch (sig) {
+                case SIGKILL:
+                case SIGSTOP:
+                case SIGCONT:
+#ifdef CRAY
+                case SIGINFO:
+                case SIGRECOVERY:
+#endif /* CRAY */
+#ifdef SIGCKPT
+               case SIGCKPT:
+#endif /* SIGCKPT */
+#ifdef SIGRESTART
+               case SIGRESTART:
+#endif /* SIGRESTART */
+                case SIGCLD:
+                    break;
+
+                default:
+#ifdef sgi
+                   sigset( sig, sig_handler );
+#else
+/* linux and cray */
+                    signal(sig, sig_handler);
+#endif
+                break;
+            }
+        } /* endfor */
+
+
+        return 0;
+}
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+void
+sig_handler(sig)
+int sig;
+{
+    int exit_stat = 2;
+
+    if ( sig == SIGUSR2 ) {
+       fprintf(stdout, "%s%s: %d %s/%d: received SIGUSR2 (%d) - stopping.\n",
+           Progname, TagName, Pid, __FILE__, __LINE__, sig);
+#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()
+{
+    static int send_signals = 0;
+    int ind;
+    extern int Forker_pids[];
+    extern int Forker_npids;
+
+    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()
+{
+    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()
+{
+    int ind;
+
+       if ( remove_files ) {
+           if ( Debug > 2 )
+               printf("%s: %d DEBUG3 Removing all %d files\n", 
+                   Progname, Pid, num_files);
+           for(ind=0; ind<=num_files; ind++) {
+               unlink(filenames+(ind*PATH_MAX));
+           }
+       }
+       if ( using_random && Debug > 1 )
+           printf("%s%s: %d DEBUG2 Used random seed: %d\n",
+               Progname, TagName, Pid, Seed);
+       return 0;
+}
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+void
+usage()
+{
+       fprintf(stderr,
+       "Usage: %s%s [-bhEluy][[-g grow_incr][-i num][-t trunc_incr][-T trunc_inter]\n",
+       Progname, TagName );
+       fprintf(stderr,
+       "[-d auto_dir][-e maxerrs][-f auto_file][-N num_files][-w][-c chk_inter][-D debug]\n");
+       fprintf(stderr,
+       "[-s seed][-S seq_auto_files][-p][-P PANIC][-I io_type][-o open_flags][-B maxbytes]\n");
+       fprintf(stderr,
+       "[-r iosizes][-R lseeks][-U unlk_inter][-W tagname] [files]\n");
+
+       return;
+
+}      /* end of usage */
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+void
+help()
+{
+       usage();
+
+fprintf(stdout, "\
+  -h             Specfied to print this help and exit.\n\
+  -b             Specfied to execute in sync mode.(def async mode)\n\
+  -B maxbytes    Max bytes to consume by all files.  growfiles exits when more\n\
+                 than maxbytes have been consumed. (def no chk)  If maxbytes ends\n\
+                 with the letter 'b', maxbytes is multiplied by BSIZE\n\
+  -C write_chk   Specifies how often to check the last write (default 1)\n\
+  -c file_chk    Specifies how often to check whole file (default 0)\n\
+  -d auto_dir    Specifies the directory to auto created files. (default .)\n\
+  -D debug_lvl   Specifies the debug level (default 1)\n\
+  -E             Print examples and exit\n\
+  -e errs        The number errors that will terminate this program (def 100)\n\
+  -f auto_file   Specifies the base filename files created. (default \"gf\")\n\
+  -g grow_incr   Specfied to grow by incr for each num. (default 4096)\n\
+                 grow_incr may end in b for blocks\n\
+                If -r option is used, this option is ignored and size is random\n\
+  -H delay       Amount of time to delay between each file (default 0.0)\n\
+  -I io_type Specifies io type: s - sync, p - polled async, a - async (def s)\n\
+                l - listio sync, L - listio async, r - random\n\
+  -i iteration   Specfied to grow each file num times. 0 means forever (default 1)\n\
+  -l             Specfied to do file locking around write/read/trunc\n\
+                If specified twice, file locking after open to just before close\n\
+  -L time        Specfied to exit after time secs, must be used with -i.\n\
+  -N num_files   Specifies the number of files to be created.\n\
+                 The default is zero if cmd line files.\n\
+                 The default is one if no cmd line files.\n\
+  -n num_procs   Specifies the number of copies of this cmd.\n\
+  -o op_type     Specifies open flages: (def O_RDWR,O_CREAT) op_type can be 'random'\n\
+  -O offset      adjust i/o buffer alignment by offset bytes\n\
+  -P PANIC       Specifies to call upanic on error.\n\
+  -p             Specifies to pre-allocate space\n\
+  -q pattern     pattern can be a - ascii, p - pid with boff, o boff (def)\n\
+                A - Alternating bits, r - random, O - all ones, z - all zeros,\n\
+                c - checkboard, C - counting\n\
+  -R [min-]max   random lseek before write and trunc, max of -1 means filesz,\n\
+                -2 means filesz+grow, -3 filesz-grow. (min def is 0)\n\
+  -r [min-]max   random io write size (min def is 1)\n\
+  -S seq_auto_files Specifies the number of seqental auto files (default 0)\n\
+  -s seed[,seed...] Specifies the random number seed (default time(0)+pid)\n\
+  -t trunc_incr  Specfied the amount to shrink file. (default 4096)\n\
+                 trunc_inter may end in b for blocks\n\
+                If -R option is used, this option is ignored and trunc is random\n\
+  -T trunc_inter Specfied the how many grows happen before shrink. (default 0)\n\
+  -u             unlink files before exit\n\
+  -U ui[-ui2]    Unlink files each ui iteration (def 0)\n\
+  -w             Specfied to grow via lseek instead of writes.\n\
+  -W tag-name   Who-am-i.  My Monster tag name.  (used by Monster).\n\
+  -x            Re-exec children before continuing - useful on MPP systems\n\
+  -y             Attempt to sync copies - if one fails it will send sigusr2 to others\n\
+  Action to each file every iteration is open, write, write check\n\
+  file check, trunc and closed.\n");
+
+       return;
+}
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+void
+prt_examples(FILE *stream)
+{
+       /* This example creates 200 files in directory dir1.  It writes */
+       /* 4090 bytes 100 times then truncates 408990 bytes off the file */
+       /* The file contents are checked every 1000 grow. */
+    fprintf(stream,
+        "# run forever: writes of 4090 bytes then on every 100 iterval\n\
+# truncate file by 408990 bytes.  Done to 200 files in dir1.\n\
+%s -i 0 -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -d dir1 -S 200\n\n", Progname);
+
+       /* same as above with 5000 byte grow and a 499990 byte tuncate */
+    fprintf(stream,
+        "# same as above with writes of 5000 bytes and truncs of 499990\n\
+%s -i 0 -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -d dir2 -S 200\n\n", Progname);
+
+       /* This example beats on opens and closes */
+    fprintf(stream,
+        "# runs forever: beats on opens and closes of file ocfile - no io\n\
+%s -i 0 -g 0 -c 0 -C 0 ocfile\n\n", Progname);
+
+    fprintf(stream,
+        "# writes 4096 to files until 50 blocks are written\n\
+%s -i 0 -g 4096 -B 50b file1 file2\n\n", Progname);
+       
+    fprintf(stream,
+        "# write one byte to 750 files in gdir then unlinks them\n\
+%s -g 1 -C 0 -d gdir -u -S 750\n\n", Progname);
+
+    fprintf(stream,
+       "# run 30 secs: random iosize, random lseek up to eof\n\
+%s -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 g_rand1 g_rand2\n\n", Progname);
+
+    fprintf(stream,
+       "# run 30 secs: grow by lseek then write single byte, trunc every 10 itervals\n\
+%s -g 5000 -wlu -i 0 -L 30 -C 1 -T 10  g_sleek1 g_lseek2\n\n", Progname);
+
+    fprintf(stream, 
+       "# run forever: 5 copies of random iosize, random lseek to beyond eof,\n\
+# rand io types doing a trunc every 5 iterations, with unlinks.\n\
+%s -i0 -r 1-50000 -R 0--2 -I r -C1 -l -n5 -u -U 100-200 gf_rana gf_ranb\n\n", 
+           Progname);
+
+    fprintf(stream, 
+       "# run forever: 5 copies of random iosize, random lseek to beyond eof,\n\
+# random open flags, rand io types doing a trunc every 10 iterations.\n\
+%s -i0 -r 1-50000 -R 0--2 -o random -I r -C0 -l -T 20 -uU100-200 -n 5 gf_rand1 gf_rand2\n", 
+           Progname);
+
+
+       return;
+}
+
+/***********************************************************************
+ *
+ * The file descriptor current offset is assumed to be the end of the
+ * file.  
+ * Woffset will be set to the offset before the write.
+ * Grow_incr will be set to the size of the write or lseek write.
+ ***********************************************************************/
+int
+growfile(fd, file, grow_incr, buf)
+int fd;
+char *file;
+int grow_incr;
+char *buf;
+{
+   int noffset;
+   int ret;
+   int cur_offset;
+   char *errmsg;
+   int fsize;          /* current size of file */
+   int size_grew;      /* size the file grew */
+   struct stat stbuf;
+   int tmp = 0;
+
+        /*
+         * Do a stat on the open file.
+         * If the file is a fifo, set the bit in Mode variable.
+         * This fifo check must be done prior to growfile() returning.
+        * Also get the current size of the file.
+         */
+        if ( fstat(fd, &stbuf) != -1 ) {
+            if ( S_ISFIFO(stbuf.st_mode) ) {
+               Fileinfo.mode |= MODE_FIFO;
+                Mode |= MODE_FIFO;
+                if ( Debug > 3 )
+                    printf("%s: %d DEBUG4 %s/%d: file is a fifo - no lseek or truncs,\n",
+                        Progname, Pid, __FILE__, __LINE__);
+            }
+           fsize = stbuf.st_size;
+
+        } else {
+           fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
+               Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
+
+           return -1;
+       }
+
+
+        if ( grow_incr <= 0 ) {   /* don't attempt i/o if grow_incr <= 0 */ 
+
+           Grow_incr=grow_incr;
+           if ( Debug > 2 )
+               printf("%s: %d DEBUG3 %s/%d: Not attempting to grow, growsize == %d\n",
+                   Progname, Pid, __FILE__, __LINE__, grow_incr);
+           return grow_incr;
+       }
+
+       if ( Mode & MODE_RAND_SIZE ) {
+           grow_incr=random_range(min_size, max_size, mult_size, &errmsg);
+           if (errmsg != NULL) {
+               fprintf(stderr, "%s%s: %d %s/%d: random_range() failed - %s\n", Progname, TagName, Pid, __FILE__, __LINE__, errmsg);
+               return -1;
+           }
+           Grow_incr=grow_incr;
+       }
+       else
+           Grow_incr=grow_incr;
+
+       if ( ! (Mode & MODE_FIFO) ) {
+           if ((cur_offset=lseek(fd,0,SEEK_CUR)) == -1 ) {
+               fprintf(stderr, "%s%s: %d %s/%d: tell failed: %s\n",
+                   Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
+               return -1;
+           }
+        }
+
+       if ( Mode & MODE_GROW_BY_LSEEK ) {
+                Woffset=fsize;
+               if ( Debug > 2 ) {
+                   printf("%s: %d DEBUG3 %s/%d: Current size of file is %d\n", Progname,
+                       Pid, __FILE__, __LINE__, Woffset);
+                   printf("%s: %d DEBUG3 %s/%d: lseeking to %d byte with SEEK_END\n", Progname,
+                       Pid, __FILE__, __LINE__, grow_incr-1);
+               }
+
+               if ((noffset=lseek(fd, grow_incr-1, SEEK_END)) == -1 ) {
+                       fprintf(stderr, "%s%s: %s/%d: lseek(fd, %d, SEEK_END) failed: %s\n",
+                               Progname, TagName, __FILE__, __LINE__, grow_incr-1, strerror(errno));
+                       return -1;
+               }
+
+               lkfile(fd, LOCK_EX, LKLVL0);     /* get exclusive lock */
+               
+#if NEWIO
+               ret=lio_write_buffer(fd, io_type, "w", 1, SIGUSR1, &errmsg,0);
+#else
+               ret=write_buffer(fd, io_type, "w", 1, 0, &errmsg); 
+#endif
+
+               if ( ret != 1 ) {
+                       fprintf(stderr, "%s%s: %d %s/%d: %d %s\n", 
+                           Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+                       if ( ret == -ENOSPC ) {
+                               cleanup();
+                               exit(2);
+                       }
+               }
+/***
+               write(fd, "w", 1);
+****/
+
+               lkfile(fd, LOCK_UN, LKLVL0);
+
+                if ( Debug > 2 )
+                    printf("%s: %d DEBUG3 %s/%d: %d wrote 1 byte to file\n",
+                            Progname, Pid, __FILE__, __LINE__, Iter_cnt);
+
+       } else {  /* end of grow by lseek */
+
+               if ( Fileinfo.openflags & O_APPEND ) {
+                  /*
+                   * Deal with special case of the open flag containing O_APPEND.
+                   * If it does, the current offset does not matter since the write
+                   * will be done end of the file.
+                   */
+                   if ( Debug > 4 )
+                       printf("%s: %d DEBUG5 %s/%d: dealing with O_APPEND condition\n",
+                           Progname, Pid, __FILE__, __LINE__ );
+                   lkfile(fd, LOCK_EX, LKLVL0);         /* get exclusive lock */
+
+                   /*
+                    * do fstat again to get size of the file.
+                    * This is done inside a file lock (if locks are being used).
+                    */
+                   if ( fstat(fd, &stbuf) != -1 ) {
+                       Woffset = stbuf.st_size;
+                   } else {
+                       fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
+                       Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
+       
+                       lkfile(fd, LOCK_UN, LKLVL0);     /* release lock */
+                       return -1;
+                   }
+                   if ( Debug > 2 )
+                       printf("%s: %d DEBUG3 %s/%d: dealing with O_APPEND condition (offset:fsz:%d)\n",
+                           Progname, Pid, __FILE__, __LINE__, (int)stbuf.st_size);
+
+
+               } else if ( Mode & MODE_RAND_LSEEK ) {
+                   if ( max_lseek == LSK_EOF ) {       /* within file size */
+                        noffset=random_range(min_lseek, fsize, 1, NULL);
+                   }           
+                  else if ( max_lseek == LSK_EOFPLUSGROW ) {   
+                       /* max to beyond file size */
+                       noffset=random_range(min_lseek, fsize+grow_incr, 1, NULL);
+                  }
+                  else if ( max_lseek == LSK_EOFMINUSGROW ) {  
+                       /* 
+                        * Attempt to not grow the file.
+                        * If the i/o will fit from min_lseek to EOF,
+                        * pick offset to allow it to fit.
+                        * Otherwise, pick the min_lseek offset and grow
+                        * file by smallest amount.
+                        * If min_lseek is != 0, there will be a problem
+                        * with whole file checking if file is ever smaller
+                        * than min_lseek.
+                        */
+                       if ( fsize <= min_lseek + grow_incr )
+                           noffset=min_lseek;  /* file will still grow */
+                       else
+                           noffset=random_range(min_lseek, fsize-grow_incr, 1, NULL);
+                  }
+                   else {
+                        noffset=random_range(min_lseek, max_lseek, 1, NULL);
+                   }
+
+                  if ((Woffset=lseek(fd, noffset, SEEK_SET)) == -1 ) {
+                        fprintf(stderr, "%s%s: %d %s/%d: lseek(%d, %d, SEEK_SET) l2 failed: %s\n",
+                                Progname, TagName, Pid, __FILE__, __LINE__, fd, noffset, strerror(errno));
+                        return -1;
+                  }
+                   else if ( Debug > 2 )
+                        printf("%s: %d DEBUG3 %s/%d: lseeked to random offset %d (fsz:%d)\n",
+                            Progname, Pid, __FILE__, __LINE__, Woffset,
+                           (int)stbuf.st_size);
+
+                }
+
+               /*
+                * lseek to end of file only if not fifo
+                */
+               else if ( ! (Mode & MODE_FIFO) ) {
+                   if ((Woffset=lseek(fd, 0, SEEK_END)) == -1 ) {
+                       fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, 0, SEEK_END) failed: %s\n",
+                               Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
+                       return -1;
+                   }
+                    else if ( Debug > 2 )
+                        printf("%s: %d DEBUG3 %s/%d: lseeked to end of file, offset %d\n",
+                            Progname, Pid, __FILE__, __LINE__, Woffset);
+               }
+
+               if ( Pattern == PATTERN_OFFSET )
+                   datapidgen(STATIC_NUM, buf, grow_incr, Woffset);
+               else if ( Pattern == PATTERN_PID )
+                   datapidgen(Pid, buf, grow_incr, Woffset);
+               else if ( Pattern == PATTERN_ASCII )
+                   dataasciigen(NULL, 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);
+
+               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.
+                        */
+                       tmp = Woffset + grow_incr;
+               }
+               else{
+                       if( (tmp=lseek(fd,0,SEEK_CUR)) < 0 ){ /* get offset after the write */
+                               fprintf(stderr, "%s%s: %s/%d: tell(2) failed: %d  %s\n",
+                                       Progname, TagName, __FILE__, __LINE__, errno, strerror(errno) );
+                               return -1;
+                       }
+#if NEWIO
+#ifdef sgi
+                       /* 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( tmp != Woffset + grow_incr ){
+                                       if( Debug > 5 ){
+                                               printf("%s: %d DEBUG6 %s/%d: posix fudge, forcing tmp (%d) to match Woffset+grow_incr (%d)\n",
+                                                      Progname, Pid, __FILE__, __LINE__, tmp, Woffset+grow_incr);
+                                       }
+                                       tmp = Woffset + grow_incr;
+                               }
+                       }
+#endif
+#endif
+               }
+
+               lkfile(fd, LOCK_UN, LKLVL0);    
+
+               if ( ret != grow_incr ) {
+                       fprintf(stderr, "%s%s: %d %s/%d: %d %s\n", 
+                           Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+                       if ( ret == -ENOSPC ) {
+                               cleanup();
+                               exit(2);
+                       }
+                       return -1;
+               }
+
+               /*
+                * Check for a condition where the file was truncated just before
+                * the write. 
+                */
+               if ( tmp != Woffset + grow_incr) {
+                   /*
+                    * The offset after the write was not as expected.
+                    * This could be caused by the following:
+                    *  - file truncated after the lseek and before the write.
+                    *  - the file was written to after fstat and before the write
+                    *    and the file was opened with O_APPEND.
+                    *
+                    * The pattern written to the file will be considered corrupted.
+                    */
+                   if ( Debug > 0 && lockfile ) {
+                       printf("%s%s: %d DEBUG1 %s/%d: offset after write(%d) not as exp(%d+%d=%d)\n",  
+                           Progname, TagName, Pid, __FILE__, __LINE__, tmp, Woffset, grow_incr, Woffset+grow_incr);
+                       printf("%s%s: %d DEBUG1 %s/%d: %d Assuming file changed by another process, resetting offset:%d (expect pattern mismatch)\n",
+                               Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, tmp-grow_incr);
+                   }
+                   if( Debug > 4 ){
+                       printf("%s: %d DEBUG5 %s/%d: about to chop Woffset.  tmp=%d, grow_incr=%d, Woffset was %d\n",
+                              Progname, Pid, __FILE__, __LINE__, tmp, grow_incr, Woffset);
+                   }
+                   Woffset=tmp-grow_incr;
+                   if( Woffset < 0 )
+                       Woffset = 0;
+               }
+
+       }  /* end of grow by write */
+
+
+       /*
+        * Woffset - holds start of grow (start of write expect in grow by lseek)
+        * Grow_incr - holds size of grow (write).
+        * fsize - holds size of file before write
+        */
+       size_grew=(Woffset + Grow_incr) - fsize;
+       if ( Debug > 1) {
+            if ( Mode & MODE_FIFO ) {
+               printf("%s: %d DEBUG2 %s/%d: file is fifo, %d wrote %d bytes\n",
+                   Progname, Pid, __FILE__, __LINE__, Grow_incr, Iter_cnt);
+            }
+
+            else if ( size_grew > 0 )
+               printf("%s: %d DEBUG2 %s/%d: %d wrote %d bytes(off:%d), grew file by %d bytes\n",
+                        Progname, Pid, __FILE__, __LINE__, Iter_cnt, Grow_incr, Woffset, size_grew);
+            else
+               printf("%s: %d DEBUG2 %s/%d: %d wrote %d bytes(off:%d), did not grow file\n",
+                        Progname, Pid, __FILE__, __LINE__, Iter_cnt, Grow_incr, Woffset);
+       }
+
+       bytes_consumed += size_grew;
+       return 0;
+
+}      /* end of growfile */
+
+/***********************************************************************
+ * shrinkfile file by trunc_incr.  file can not be made smaller than
+ * size zero.  Therefore, if trunc_incr is larger than file size,
+ * file will be truncated to zero.
+ * The file descriptor current offset is assumed to be the end of the
+ * file.
+ *
+ ***********************************************************************/
+int
+shrinkfile(fd, filename, trunc_incr, trunc_inter, just_trunc)
+int fd;
+char *filename;
+int trunc_incr;
+int trunc_inter;       /* interval */
+int just_trunc;                /* lseek has already been done for you */
+{
+    static int shrink_cnt = 0;
+    int cur_offset;
+    int new_offset;
+    int ret;
+#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(fd, cf_inter, filename, mode)
+int fd;
+int cf_inter;   /* check file interval */
+char *filename; /* needed for error messages */
+int mode;       /* write mode */
+{
+    int fsize;
+    static int cf_count = 0;
+    int ret = 0;
+    int tmp;
+    char *errmsg;
+    char *ptr;
+
+    cf_count++;
+
+    if ( cf_inter == 0 || (cf_count % cf_inter != 0)) {
+       if ( Debug > 4 )
+           printf("%s: %d DEBUG5 %s/%d: no write check, not time iter=%d, cnt=%d\n",
+               Progname, Pid, __FILE__, __LINE__, cf_inter, cf_count);
+       return 0;        /* no check done */
+    }
+
+    if ( Grow_incr <= 0 ) {
+        if ( Debug > 3 )
+           printf("%s: %d DEBUG4 %s/%d: No write validation,  Grow_incr = %d, offset = %d\n",
+               Progname, Pid, __FILE__, __LINE__, Grow_incr, Woffset);
+        return 0;      /* no check */
+    }
+
+
+    
+    /* 
+     * Get the shared file lock.  We need to hold the lock from before
+     * we do the stat until after the read.
+     */
+    lkfile(fd, LOCK_SH, LKLVL0);
+
+    if ((fsize=file_size(fd)) == -1 )  {
+        lkfile(fd, LOCK_UN, LKLVL0);
+        return -1;
+
+    } else if ( fsize <= Woffset ) {
+       /*
+        * The file was truncated between write and now.
+        * The contents of our last write is totally gone, no check.
+        */
+       if ( Debug > 1 )
+           printf("%s%s: %d DEBUG2 %s/%d: %d File size (%d) smaller than where last wrote (%d)- no write validation\n",
+               Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, fsize, Woffset);
+        lkfile(fd, LOCK_UN, LKLVL0);
+        return 0;      /* no validation, but not an error */
+    } else if ( fsize < (Woffset + Grow_incr)) {
+       /*
+        * The file was truncated between write and now.
+        * Part of our last write has been truncated, adjust our Grow_incr
+        * to reflect this.
+        */
+
+       tmp=Grow_incr;
+       Grow_incr=fsize-Woffset;
+
+       if ( Debug > 1 )  {
+
+           printf("%s%s: %d DEBUG2 %s/%d: %d fsz:%d, lost(%d)of wrt(off:%d, sz:%d), adj=%d\n",
+           Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, fsize, tmp-Grow_incr, Woffset, tmp, Grow_incr);
+       }
+
+    }
+
+    if ( Debug > 2 )
+        printf("%s: %d DEBUG3 %s/%d: about to do write validation, offset = %d, size = %d\n",
+           Progname, Pid, __FILE__, __LINE__, Woffset, Grow_incr);
+
+    if ( ! (mode & MODE_FIFO)  ) {
+
+        if ( lseek(fd, Woffset, 0) == -1 ) {
+            fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, %d, 0) failed: %s\n",
+               Progname, TagName, Pid, __FILE__, __LINE__, Woffset, strerror(errno));
+        }
+        if ( Debug > 3 )
+           printf("%s: %d DEBUG4 %s/%d: lseeked to offset:%d\n",
+               Progname, Pid, __FILE__, __LINE__, Woffset);
+    }
+
+    /*
+     * Read last writes data
+     */
+#if NEWIO
+    ret=lio_read_buffer(fd, io_type, Buffer, Grow_incr, SIGUSR1, &errmsg,0);
+#else
+    ret=read_buffer(fd, io_type, Buffer, Grow_incr, 0, &errmsg);
+#endif
+
+    /*
+     * report the error and debug information before releasing
+     * the file lock
+     */
+    if ( ret != Grow_incr ) {
+        fprintf(stderr, "%s%s: %d %s/%d: %d CW %s\n", Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+        {
+           struct stat stbuf;
+           fstat(fd, &stbuf);
+           if ( Debug > 2 )
+               printf("%s%s: %d DEBUG3 %s/%d: fd:%d, offset:%d, fsize:%d, openflags:%#o\n",
+                   Progname, TagName, Pid, __FILE__, __LINE__, fd,
+                   (int)lseek(fd,SEEK_CUR,0),  /* FIXME: 64bit/LFS ? */
+                   (int)stbuf.st_size,
+                   Fileinfo.openflags);
+        }
+
+       lkfile(fd, LOCK_UN, LKLVL0);
+       return 1;
+    }
+
+
+    lkfile(fd, LOCK_UN, LKLVL0);
+
+    if ( Mode & MODE_GROW_BY_LSEEK ) {
+       /* check that all zeros upto last character */
+       for(ptr=Buffer; ptr < (Buffer+Grow_incr-1); ptr++) {
+           if ( *ptr != '\0' ) {
+               fprintf(stderr,
+                   "%s%s: %d %s/%d: data mismatch at offset %d, exp:%#o(zerofilled), act:%#o in file %s\n",
+                   Progname, TagName, Pid, __FILE__, __LINE__, 
+                   (int)(Woffset+(Grow_incr-(Buffer-ptr))),
+                   0, *ptr, filename);
+               fflush(stderr);
+               return 1;
+           }
+       }
+       /* check that the last char is a 'w' */
+       if ( *ptr != 'w' ) {
+           fprintf(stderr,
+         "%s%s: %d %s/%d: data mismatch at offset %d, exp:%#o(zerofilled), act:%#o in file %s\n",
+               Progname, TagName, Pid, __FILE__, __LINE__, 
+               (int)(Woffset+(Grow_incr-(Buffer-ptr))), 'w',
+               *ptr, filename);
+           fflush(stderr);
+           return 1;
+       }
+       return 0;   /* all is well */
+       
+    }
+    else if ( Pattern == PATTERN_OFFSET )
+       ret=datapidchk(STATIC_NUM, Buffer, Grow_incr, Woffset, &errmsg);
+    else if ( Pattern == PATTERN_PID )
+       ret=datapidchk(Pid, Buffer, Grow_incr, Woffset, &errmsg);
+    else if ( Pattern == PATTERN_ASCII )
+        ret=dataasciichk(NULL, Buffer, Grow_incr, Woffset, &errmsg);
+    else if ( Pattern == PATTERN_RANDOM )
+       ;       /* no check for random */
+    else if ( Pattern == PATTERN_ALT )
+        ret=databinchk('a', Buffer, Grow_incr, Woffset, &errmsg);
+    else if ( Pattern == PATTERN_CHKER )
+        ret=databinchk('c', Buffer, Grow_incr, Woffset, &errmsg);
+    else if ( Pattern == PATTERN_CNTING )
+       ret=databinchk('C', Buffer, Grow_incr, Woffset, &errmsg);
+    else if ( Pattern == PATTERN_ZEROS )
+       ret=databinchk('z', Buffer, Grow_incr, Woffset, &errmsg);
+    else if ( Pattern == PATTERN_ONES )
+       ret=databinchk('o', Buffer, Grow_incr, Woffset, &errmsg);
+    else
+       ret=dataasciichk(NULL, Buffer, Grow_incr, Woffset, &errmsg);
+
+    if ( ret >= 0 ) {
+       fprintf(stderr, "%s%s: %d %s/%d: %d CW %s in file %s\n",
+               Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
+
+       if ( Debug > 0 )
+           printf("%s%s: %d DEBUG1 %s/%d: **fd:%d, lk:%d, offset:%d, sz:%d open flags:%#o %s\n",
+               Progname, TagName, Pid, __FILE__, __LINE__, fd, lockfile, 
+               Woffset, Grow_incr, Fileinfo.openflags, openflags2symbols(Fileinfo.openflags, ",", NULL));
+
+       fflush(stderr);
+       return 1;
+    }
+
+    if ( Debug > 6 )
+        printf("%s: %d DEBUG7 %s/%d: No corruption detected on write validation , offset = %d, size = %d\n",
+            Progname, Pid, __FILE__, __LINE__, Woffset, Grow_incr);
+
+    return 0;  /* all is well */
+}
+
+
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+check_file(fd, cf_inter, filename, no_file_check)
+int fd;
+int cf_inter;  /* check file interval */
+char *filename;        /* needed for error messages */
+int no_file_check;     /* if set, do not do file content check */
+{
+    int fsize;
+    static int cf_count = 0;
+    char *buf;
+    int ret;
+    int ret_val = 0;
+    int rd_cnt;
+    int rd_size;
+    char *errmsg;
+
+       cf_count++;
+
+       if ( cf_inter == 0 || (cf_count % cf_inter != 0)) {
+               if ( Debug > 4 )
+                   printf("%s: %d DEBUG5 %s/%d: No file check - not time, iter=%d, cnt=%d\n",
+                       Progname, Pid, __FILE__, __LINE__, cf_inter, cf_count);
+               return 0;        /* no check done */
+       }
+
+       /*
+        * if we can't determine file content, don't bother checking
+        */
+        if ( no_file_check ) {
+               if ( Debug > 4 )
+                   printf("%s: %d DEBUG5 %s/%d: No file check, lseek grow or random lseeks\n",
+                       Progname, Pid, __FILE__, __LINE__);
+               return 0;
+       }
+
+       /*
+        * Lock the file.  We need to have the file lock before
+        * the stat and until after the last read to prevent
+        * a trunc/truncate from "corrupting" our data.
+        */
+       lkfile(fd, LOCK_SH, LKLVL0);
+       
+       if ((fsize=file_size(fd)) == -1 )  {
+           lkfile(fd, LOCK_UN, LKLVL0);
+           return -1;
+       }
+
+        if ( fsize == 0 ) {
+           if ( Debug > 2 )
+            printf("%s: %d DEBUG3 %s/%d: No file validation, file size == 0\n",
+                Progname, Pid, __FILE__, __LINE__);
+
+           lkfile(fd, LOCK_UN, LKLVL0);
+           return 0;
+       }
+
+       if ( Debug > 2 )
+            printf("%s: %d DEBUG3 %s/%d: about to do file validation\n",
+               Progname, Pid, __FILE__, __LINE__);
+
+        if ( fsize > MAX_FC_READ ) {
+           /*
+            * read the file in MAX_FC_READ chuncks.
+            */
+
+           if ((buf=(char *)malloc(MAX_FC_READ)) == NULL ) {
+               fprintf(stderr, "%s%s: %s/%d: malloc(%d) failed: %s\n", Progname, TagName,
+                   __FILE__, __LINE__, MAX_FC_READ, strerror(errno));
+              lkfile(fd, LOCK_UN, LKLVL0);
+              return -1;
+           }
+
+           lseek(fd, 0, SEEK_SET);
+
+           lkfile(fd, LOCK_SH, LKLVL0);  /* get lock on file before getting file size */
+
+           rd_cnt=0;
+           while (rd_cnt < fsize ) {
+               if ( fsize - rd_cnt > MAX_FC_READ )
+                   rd_size=MAX_FC_READ;
+               else
+                   rd_size=fsize - rd_cnt;
+                               
+#if NEWIO
+               ret=lio_read_buffer(fd, io_type, buf, rd_size,
+                   SIGUSR1, &errmsg,0);
+#else
+               ret=read_buffer(fd, io_type, buf, rd_size, 0, &errmsg);
+#endif
+
+               if (ret != rd_size ) {
+                   fprintf(stderr, "%s%s: %d %s/%d: %d CFa %s\n", 
+                       Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+                   free(buf);
+                   lkfile(fd, LOCK_UN, LKLVL0);
+                   return -1;
+               }
+/**
+               read(fd, buf, rd_size);
+***/
+
+               if ( Pattern == PATTERN_OFFSET )
+                   ret=datapidchk(STATIC_NUM, buf, rd_size, rd_cnt, &errmsg);
+               else if ( Pattern == PATTERN_PID )
+                   ret=datapidchk(Pid, buf, rd_size, rd_cnt, &errmsg);
+               else if ( Pattern == PATTERN_ASCII )
+                   ret=dataasciichk(NULL, buf, rd_size, rd_cnt, &errmsg);
+               else if ( Pattern == PATTERN_RANDOM )
+                       ;  /* no checks for random */
+               else if ( Pattern == PATTERN_ALT )
+                   ret=databinchk('a', buf, rd_size, rd_cnt, &errmsg);
+               else if ( Pattern == PATTERN_CHKER )
+                   ret=databinchk('c', buf, rd_size, rd_cnt, &errmsg);
+               else if ( Pattern == PATTERN_CNTING )
+                   ret=databinchk('C', buf, rd_size, rd_cnt, &errmsg);
+               else if ( Pattern == PATTERN_ZEROS )
+                   ret=databinchk('z', buf, rd_size, rd_cnt, &errmsg);
+               else if ( Pattern == PATTERN_ONES )
+                   ret=databinchk('o', buf, rd_size, rd_cnt, &errmsg);
+               else
+                   ret=dataasciichk(NULL, buf, rd_size, rd_cnt, &errmsg);
+               
+                   
+               if ( ret >= 0 ) {
+                   fprintf(stderr,
+                       "%s%s: %d %s/%d: %d CFp %s in file %s\n",
+                       Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
+                   fflush(stderr);
+                   ret_val=1;
+                   lkfile(fd, LOCK_UN, LKLVL0);
+                   break;
+               }
+               rd_cnt += rd_size;
+           }
+
+           lkfile(fd, LOCK_UN, LKLVL0);
+
+           free(buf);
+
+       }
+       else {
+           /*
+            * Read the whole file in a single read 
+            */
+           if((buf=(char *)malloc(fsize)) == NULL ) {
+                       fprintf(stderr, "%s%s: %s/%d: malloc(%d) failed: %s\n", Progname, TagName,
+                               __FILE__, __LINE__, fsize, strerror(errno));
+                       fflush(stderr);
+                       return -1;
+           }
+
+           lseek(fd, 0, SEEK_SET);
+
+/****
+           read(fd, buf, fsize);
+****/
+#if NEWIO
+           ret=lio_read_buffer(fd, io_type, buf, fsize, SIGUSR1, &errmsg,0);
+#else
+           ret=read_buffer(fd, io_type, buf, fsize, 0, &errmsg);
+#endif
+
+           /* unlock the file as soon as we can */
+           lkfile(fd, LOCK_UN, LKLVL0);
+
+
+           if ( ret != fsize ) {
+               fprintf(stderr, "%s%s: %d %s/%d: %d CFw %s\n", 
+                   Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+               ret_val=1;
+           }
+           else  {
+               if ( Pattern == PATTERN_OFFSET )
+                   ret=datapidchk(STATIC_NUM, buf, fsize, 0, &errmsg);
+               else if ( Pattern == PATTERN_PID )
+                   ret=datapidchk(Pid, buf, fsize, 0, &errmsg);
+               else if ( Pattern == PATTERN_ASCII )
+                   ret=dataasciichk(NULL, buf, fsize, 0, &errmsg);
+               else if ( Pattern == PATTERN_RANDOM )
+                   ;   /* no check for random */
+               else if ( Pattern == PATTERN_ALT )
+                   ret=databinchk('a', buf, fsize, 0, &errmsg);
+               else if ( Pattern == PATTERN_CHKER )
+                   ret=databinchk('c', buf, fsize, 0, &errmsg);
+               else if ( Pattern == PATTERN_CNTING )
+                   ret=databinchk('C', buf, fsize, 0, &errmsg);
+               else if ( Pattern == PATTERN_ZEROS )
+                   ret=databinchk('z', buf, fsize, 0, &errmsg);
+               else if ( Pattern == PATTERN_ONES )
+                   ret=databinchk('o', buf, fsize, 0, &errmsg);
+               else
+                   ret=dataasciichk(NULL, buf, fsize, 0, &errmsg);
+
+               if ( ret >= 0 ) {
+                   fprintf(stderr, "%s%s: %d %s/%d: %d CFw %s in file %s\n",
+                       Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
+                   fflush(stderr);
+                   ret_val=1;
+               }
+           }
+           free(buf);
+       }
+
+       return ret_val;
+
+}      /* end of check_file */
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+file_size(int fd)
+{
+    struct stat sb;
+
+        if (fstat(fd, &sb) < 0) {
+            fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
+                Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
+           return -1;
+       
+        }
+
+        return sb.st_size;
+}
+
+/***********************************************************************
+ *  do file lock/unlock action.
+ ***********************************************************************/
+int
+lkfile(int fd, int operation, int lklevel)
+{
+    char *errmsg;
+
+    
+    if ( lockfile == lklevel) {
+       
+        if ( Debug > 5 ) {
+           switch (operation) {
+           case LOCK_UN:
+               printf("%s: %d DEBUG6 %s/%d: Attempting to release lock on fd %d\n", 
+                   Progname, Pid, __FILE__, __LINE__, fd);
+               break;
+
+           case LOCK_SH:
+               printf("%s: %d DEBUG6 %s/%d: Attempting to get read/shared lock on fd %d\n", 
+                   Progname, Pid, __FILE__, __LINE__, fd);
+               break;
+
+           case LOCK_EX:
+               printf("%s: %d DEBUG6 %s/%d: Attempting to get write/exclusive lock on fd %d\n", 
+                   Progname, Pid, __FILE__, __LINE__, fd);
+               break;
+           }
+       }
+
+       /*
+        * Attempt to get/release desired lock.
+        * file_lock will attempt to do action over and over again until
+        * either an unretryable error or the action is completed.
+        */
+
+        if ( file_lock(fd, operation, &errmsg) != 0 ) {
+           printf("%s%s: %d %s/%d: Unable to perform lock operation. %s\n",
+               Progname, TagName, Pid, __FILE__, __LINE__, errmsg);
+
+           /* do we count this as an error? handle_error();  */
+           return -1;
+        }
+
+        if ( Debug > 2 ) {
+           switch (operation) {
+           case LOCK_UN:
+               printf("%s: %d DEBUG3 %s/%d: Released lock on fd %d\n", 
+                   Progname, Pid, __FILE__, __LINE__, fd);
+               break;
+
+           case LOCK_SH:
+               printf("%s: %d DEBUG3 %s/%d: Got read/shared lock on fd %d\n", 
+                   Progname, Pid, __FILE__, __LINE__, fd);
+               break;
+
+           case LOCK_EX:
+               printf("%s: %d DEBUG3 %s/%d: Got write/exclusive lock on fd %d\n", 
+                   Progname, Pid, __FILE__, __LINE__, fd);
+               break;
+       
+           default:
+               printf("%s: %d DEBUG3 %s/%d: Completed action %d on fd %d\n", 
+                   Progname, Pid, __FILE__, __LINE__, operation, fd);
+               break;
+           }
+       }
+   }
+
+   return 0;
+}
+
+#ifndef NO_XFS
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+pre_alloc(file, fd, size)
+char *file;
+int fd;
+int 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
+
+#ifndef NO_XFS
+    struct xfs_flock64 f;
+
+       f.l_whence = 0;
+       f.l_start = 0;
+       f.l_len = size;
+
+       /* non-zeroing reservation */
+       if( xfsctl( file, fd, XFS_IOC_RESVSP, &f ) == -1 ){
+                fprintf(stderr, "%s%s %s/%d: Unable to pre-alloc space: xfsctl(XFS_IOC_RESVSP) failed: %d  %s\n",
+                       Progname, TagName,
+                        __FILE__, __LINE__, errno, strerror(errno));
+               return -1;
+       }
+
+#endif
+
+       return 0;
+}
+#endif
diff --git a/ltp/iogen.c b/ltp/iogen.c
new file mode 100644 (file)
index 0000000..7a20092
--- /dev/null
@@ -0,0 +1,1973 @@
+/*
+ * 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., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, 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/
+ */
+/*
+ * iogen - a tool for generating file/sds io for a doio process
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#ifdef CRAY
+#include <sys/file.h>
+#include <sys/iosw.h>
+#include <sys/listio.h>
+#endif
+#ifdef sgi
+#include <sys/statvfs.h>
+#include <sys/fs/xfs_itable.h>
+#endif
+
+#ifndef NO_XFS
+#include <xfs/libxfs.h>
+#endif
+
+#ifdef CRAY
+#include "libkern.h"
+#endif
+
+#include "doio.h"
+#include "str_to_bytes.h"
+#include "string_to_tokens.h"
+#include "open_flags.h"
+#include "random_range.h"
+
+#ifndef BSIZE
+#define BSIZE 512
+#endif
+
+#define RAW_IO(_flags_)        ((_flags_) & (O_RAW | O_SSD))
+
+#define SYSERR strerror(errno)
+
+/*
+ * Structure for retaining test file information
+ */
+
+struct file_info {
+       char    f_path[MAX_FNAME_LENGTH+1]; /* file name (full path)    */
+       int     f_length;       /* length in bytes                      */
+       int     f_iou;          /* file iounit                          */
+       int     f_riou;         /* file raw iounit (for O_RAW/O_SSD)    */
+       int     f_dalign;       /* direct I/O alignment                 */
+       int     f_nextoff;      /* offset of end of last io operation   */
+       int     f_type;         /* file type S_IFREG, etc...            */
+       int     f_lastoffset;   /* offset of last io operation          */
+       int     f_lastlength;   /* length of last io operation          */
+};
+
+/*
+ * Simple structure for associating strings with values - useful for converting
+ * cmdline args to internal values, as well as printing internal values in
+ * a human readable form.
+ */
+
+struct strmap {
+       char    *m_string;
+       int     m_value;
+       int     m_flags;
+};
+
+/*
+ * Declare cmdline option flags/variables initialized in parse_cmdline()
+ */
+
+#define OPTS   "a:dhf:i:L:m:op:qr:s:t:T:O:N:"
+
+int    a_opt = 0;              /* async io comp. types supplied            */
+int    o_opt = 0;              /* form overlapping requests                */
+int    f_opt = 0;              /* test flags                               */
+int    i_opt = 0;              /* iterations - 0 implies infinite          */
+int    L_opt = 0;              /* listio min-max nstrides & nents          */
+int    m_opt = 0;              /* offset mode                              */
+int    O_opt = 0;              /* file creation Open flags                 */
+int    p_opt = 0;              /* output pipe - default is stdout          */
+int    r_opt = 0;              /* specify raw io multiple instead of       */
+                               /* getting it from the mounted on device.   */
+                               /* Only applies to regular files.           */
+int    s_opt = 0;              /* syscalls                                 */
+int    t_opt = 0;              /* min transfer size (bytes)                */
+int    T_opt = 0;              /* max transfer size (bytes)                */
+int    q_opt = 0;              /* quiet operation on startup               */
+char   TagName[40];            /* name of this iogen (see Monster)         */
+struct strmap *Offset_Mode;    /* M_SEQUENTIAL, M_RANDOM, etc.             */
+int    Iterations;             /* # requests to generate (0 --> infinite)  */
+int    Time_Mode = 0;          /* non-zero if Iterations is in seconds     */
+                               /* (ie. -i arg was suffixed with 's')       */
+char   *Outpipe;               /* Pipe to write output to if p_opt         */
+int    Mintrans;               /* min io transfer size                     */
+int    Maxtrans;               /* max io transfer size                     */
+int    Rawmult;                /* raw/ssd io multiple (from -r)            */
+int    Minstrides;             /* min # of listio strides per request      */
+int    Maxstrides;             /* max # of listio strides per request      */
+int    Oflags;                 /* open(2) flags for creating files         */
+int    Ocbits;                 /* open(2) cbits for creating files         */
+int    Ocblks;                 /* open(2) cblks for creating files         */
+int    Orealtime=0;            /* flag set for -O REALTIME                 */
+int    Oextsize=0;             /* real-time extent size                    */
+int    Oreserve=1;             /* flag for -O [no]reserve                  */
+int    Oallocate=0;            /* flag for -O allocate                     */
+int    Owrite=1;               /* flag for -O nowrite                      */
+
+int    Nfiles = 0;             /* # files on cmdline                       */
+struct file_info *File_List;   /* info about each file                     */
+int    Nflags = 0;             /* # flags on cmdline                       */
+struct strmap *Flag_List[128]; /* flags selected from cmdline              */
+int    Nsyscalls = 0;          /* # syscalls on cmdline                    */
+struct strmap *Syscall_List[128]; /* syscalls selected on cmdline          */
+int    Fileio = 0;             /* flag indicating that a file              */
+                               /* io syscall has been chosen.              */
+int    Naio_Strat_Types = 0;   /* # async io completion types              */
+struct strmap *Aio_Strat_List[128]; /* Async io completion types           */
+
+void   startup_info();
+
+/*
+ * Map async io completion modes (-a args) names to values.  Macros are
+ * defined in doio.h.
+ */
+
+struct strmap  Aio_Strat_Map[] = {
+#ifndef linux
+       { "poll",       A_POLL          },
+       { "signal",     A_SIGNAL        },
+#else
+       { "none",       0       },
+#endif /* !linux */
+#ifdef CRAY
+#if _UMK || RELEASE_LEVEL >= 8000
+       { "recall",     A_RECALL        },
+#endif
+
+#ifdef RECALL_SIZEOF
+       { "recalla",    A_RECALLA       },
+#endif
+       { "recalls",    A_RECALLS       },
+#endif /* CRAY */
+
+#ifdef sgi
+       { "suspend",    A_SUSPEND       },
+       { "callback",   A_CALLBACK      },
+#endif
+       { NULL,         -1              }
+};
+
+/*
+ * Offset_Mode #defines
+ */
+
+#define M_RANDOM       1
+#define M_SEQUENTIAL   2
+#define M_REVERSE      3
+
+/*
+ * Map offset mode (-m args) names to values
+ */
+
+struct strmap  Omode_Map[] = {
+       { "random",             M_RANDOM        },
+       { "sequential",         M_SEQUENTIAL    },
+       { "reverse",            M_REVERSE       },
+       { NULL,                 -1              }
+};
+
+/*
+ * Map syscall names (-s args) to values - macros are defined in doio.h.
+ */
+#define        SY_ASYNC        00001
+#define        SY_WRITE        00002
+#define        SY_SDS          00010
+#define        SY_LISTIO       00020
+#define        SY_NENT         00100   /* multi entry vs multi stride >>> */
+
+struct strmap  Syscall_Map[] = {
+       { "read",               READ,           0                       },
+       { "write",              WRITE,          SY_WRITE                },
+#ifdef CRAY
+       { "reada",              READA,          SY_ASYNC                },
+       { "writea",             WRITEA,         SY_WRITE|SY_ASYNC       },
+#ifndef _CRAYMPP
+       { "ssread",             SSREAD,         SY_SDS                  },
+       { "sswrite",            SSWRITE,        SY_WRITE|SY_SDS         },
+#endif
+       { "listio",             LISTIO,         SY_ASYNC                },
+
+       /* listio as 4 system calls */
+       { "lread",              LREAD,          0                       },
+       { "lreada",             LREADA,         SY_ASYNC                },
+       { "lwrite",             LWRITE,         SY_WRITE                },
+       { "lwritea",            LWRITEA,        SY_WRITE|SY_ASYNC       },
+
+       /* listio with nstrides > 1 */
+       { "lsread",             LSREAD,         0                       },
+       { "lsreada",            LSREADA,        SY_ASYNC                },
+       { "lswrite",            LSWRITE,        SY_WRITE                },
+       { "lswritea",           LSWRITEA,       SY_WRITE|SY_ASYNC       },
+
+       /* listio with nents > 1 */
+       { "leread",             LEREAD,         0|SY_NENT               },
+       { "lereada",            LEREADA,        SY_ASYNC|SY_NENT        },
+       { "lewrite",            LEWRITE,        SY_WRITE|SY_NENT        },
+       { "lewritea",           LEWRITEA,       SY_WRITE|SY_ASYNC|SY_NENT },
+
+       /* listio with nents > 1 & nstrides > 1 */
+
+       /* all listio system calls under one name */
+       { "listio+",            LREAD,          0                       },
+       { "listio+",            LREADA,         SY_ASYNC                },
+       { "listio+",            LWRITE,         SY_WRITE                },
+       { "listio+",            LWRITEA,        SY_WRITE|SY_ASYNC       },
+       { "listio+",            LSREAD,         0                       },
+       { "listio+",            LSREADA,        SY_ASYNC                },
+       { "listio+",            LSWRITE,        SY_WRITE                },
+       { "listio+",            LSWRITEA,       SY_WRITE|SY_ASYNC       },
+       { "listio+",            LEREAD,         0|SY_NENT               },
+       { "listio+",            LEREADA,        SY_ASYNC|SY_NENT        },
+       { "listio+",            LEWRITE,        SY_WRITE|SY_NENT        },
+       { "listio+",            LEWRITEA,       SY_WRITE|SY_ASYNC|SY_NENT },
+#endif
+
+       { "pread",              PREAD                                   },
+       { "pwrite",             PWRITE,         SY_WRITE                },
+#ifdef sgi
+       { "aread",              AREAD,          SY_ASYNC                },
+       { "awrite",             AWRITE,         SY_WRITE|SY_ASYNC       },
+#if 0
+       /* not written yet */
+       { "llread",             LLREAD,         0                       },
+       { "llaread",            LLAREAD,        SY_ASYNC                },
+       { "llwrite",            LLWRITE,        0                       },
+       { "llawrite",           LLAWRITE,       SY_ASYNC                },
+#endif
+       { "ffsync",             DFFSYNC,        SY_WRITE                },
+#endif /* SGI */
+#ifndef NO_XFS
+       { "resvsp",             RESVSP,         SY_WRITE                },
+       { "unresvsp",           UNRESVSP,       SY_WRITE                },
+       { "reserve",            RESVSP,         SY_WRITE                },
+       { "unreserve",          UNRESVSP,       SY_WRITE                },
+#endif
+
+#ifndef CRAY
+       { "readv",              READV                                   },
+       { "writev",             WRITEV,         SY_WRITE                },
+       { "mmread",             MMAPR                                   },
+       { "mmwrite",            MMAPW,          SY_WRITE                },
+       { "fsync2",             FSYNC2,         SY_WRITE                },
+       { "fdatasync",          FDATASYNC,      SY_WRITE                },
+#endif
+
+       { NULL,                 -1      }
+};
+
+/*
+ * Map open flags (-f args) to values
+ */
+#define        FLG_RAW         00001
+
+struct strmap  Flag_Map[] = {
+       { "buffered",           0,                      0       },
+       { "sync",               O_SYNC,                 0       },
+#ifdef CRAY
+       { "raw",                O_RAW,                  FLG_RAW },
+       { "raw+wf",             O_RAW | O_WELLFORMED,   FLG_RAW },
+       { "raw+wf+ldraw",       O_RAW | O_WELLFORMED | O_LDRAW, FLG_RAW },
+       { "raw+wf+ldraw+sync",  O_RAW | O_WELLFORMED | O_LDRAW | O_SYNC, FLG_RAW },
+#ifdef O_SSD
+       { "ssd",                O_SSD,                  FLG_RAW },
+#endif
+#ifdef O_LDRAW
+       { "ldraw",              O_LDRAW,                0       },
+#endif
+#ifdef O_PARALLEL
+       { "parallel",           O_PARALLEL | O_RAW | O_WELLFORMED,
+                 FLG_RAW },
+       { "parallel+sync",      O_PARALLEL | O_RAW | O_WELLFORMED | O_SYNC,
+                 FLG_RAW },
+       { "parallel+ldraw",     O_PARALLEL | O_RAW | O_WELLFORMED | O_LDRAW,
+                 FLG_RAW },
+       { "parallel+ldraw+sync",
+                 O_PARALLEL | O_RAW | O_WELLFORMED | O_LDRAW | O_SYNC,
+                 FLG_RAW },
+#endif
+#endif /* CRAY */
+
+       { "direct",             O_DIRECT,               FLG_RAW },
+#ifdef sgi
+       { "dsync",              O_DSYNC         },      /* affects writes */
+       { "rsync",              O_RSYNC         },      /* affects reads */
+       { "rsync+dsync",        O_RSYNC|O_DSYNC },
+#endif
+       { NULL,             -1          }
+};
+
+/*
+ * Map file types to strings
+ */
+
+struct strmap  Ftype_Map[] = {
+       { "regular",    S_IFREG },
+       { "blk-spec",   S_IFBLK },
+       { "chr-spec",   S_IFCHR },
+       { NULL,         0 }
+};
+
+/*
+ * Misc declarations
+ */
+
+int            Sds_Avail;
+
+char   Byte_Patterns[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+                             'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+                             'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+                             'Y', 'Z' };
+
+
+int form_iorequest(struct io_req *);
+int init_output();
+int parse_cmdline(int argc, char **argv, char *opts);
+int help(FILE *stream);
+int usage(FILE *stream);
+
+
+int
+main(argc, argv)
+int    argc;
+char   **argv;
+{
+    int                    rseed, outfd, infinite;
+    time_t         start_time;
+    struct io_req   req;
+    
+    umask(0);
+
+#ifdef CRAY
+    Sds_Avail = sysconf(_SC_CRAY_SDS);
+#else
+    Sds_Avail = 0;
+#endif
+
+    TagName[0] = '\0';
+    parse_cmdline(argc, argv, OPTS);
+
+    /*
+     * Initialize output descriptor.  
+     */
+    if (! p_opt) {
+       outfd = 1;
+    } else {
+       outfd = init_output();
+    }
+
+    rseed = getpid();
+    random_range_seed(rseed);       /* initialize random number generator */
+
+    /*
+     * Print out startup information, unless we're running in quiet mode
+     */
+    if (!q_opt)
+       startup_info(stderr, rseed);
+
+    start_time = time(0);
+
+    /*
+     * While iterations (or forever if Iterations == 0) - compute an
+     * io request, and write the structure to the output descriptor
+     */
+
+    infinite = !Iterations;
+
+    while (infinite ||
+          (! Time_Mode && Iterations--) ||
+          (Time_Mode && time(0) - start_time <= Iterations)) {
+
+       memset(&req, 0, sizeof(struct io_req));
+       if (form_iorequest(&req) == -1) {
+           fprintf(stderr, "iogen%s:  form_iorequest() failed\n", TagName);
+           continue;
+       }
+
+       req.r_magic = DOIO_MAGIC;
+       write(outfd, (char *)&req, sizeof(req));
+    }
+
+    exit(0);
+
+}   /* main */
+
+void
+startup_info(FILE *stream, int seed)
+{
+    char       *value_to_string(), *type;
+    int                i;
+
+    fprintf(stream, "\n");
+    fprintf(stream, "iogen%s starting up with the following:\n", TagName);
+    fprintf(stream, "\n");
+
+    fprintf(stream, "Out-pipe:              %s\n", 
+           p_opt ? Outpipe : "stdout");
+
+    if (Iterations) {
+       fprintf(stream, "Iterations:            %d", Iterations);
+       if (Time_Mode)
+           fprintf(stream, " seconds");
+
+       fprintf(stream, "\n");
+    } else {
+       fprintf(stream, "Iterations:            Infinite\n");
+    }
+
+    fprintf(stream,
+           "Seed:                  %d\n", seed);
+
+    fprintf(stream,
+           "Offset-Mode:           %s\n", Offset_Mode->m_string);
+
+    fprintf(stream, "Overlap Flag:          %s\n",
+           o_opt ? "on" : "off");
+
+    fprintf(stream,
+           "Mintrans:              %-11d (%d blocks)\n",
+           Mintrans, (Mintrans+BSIZE-1)/BSIZE);
+
+    fprintf(stream,
+           "Maxtrans:              %-11d (%d blocks)\n",
+           Maxtrans, (Maxtrans+BSIZE-1)/BSIZE);
+
+    if (! r_opt) 
+       fprintf(stream,
+               "O_RAW/O_SSD Multiple:  (Determined by device)\n");
+    else
+       fprintf(stream,
+               "O_RAW/O_SSD Multiple:  %-11d (%d blocks)\n",
+               Rawmult, (Rawmult+BSIZE-1)/BSIZE);
+
+    fprintf(stream, "Syscalls:              ");
+    for (i = 0; i < Nsyscalls; i++)
+       fprintf(stream,
+               "%s ", Syscall_List[i]->m_string);
+    fprintf(stream, "\n");
+
+    fprintf(stream, "Aio completion types:  ");
+    for (i = 0; i < Naio_Strat_Types; i++)
+       fprintf(stream,
+               "%s ", Aio_Strat_List[i]->m_string);
+    fprintf(stream, "\n");
+
+    if (Fileio) {
+       fprintf(stream, "Flags:                 ");
+       for (i = 0; i < Nflags; i++)
+           fprintf(stream,
+                   "%s ", Flag_List[i]->m_string);
+
+       fprintf(stream, "\n");
+       fprintf(stream, "\n");
+       fprintf(stream, "Test Files:  \n");
+       fprintf(stream, "\n");
+       fprintf(stream,
+               "Path                                          Length    iou   raw iou file\n");
+       fprintf(stream,
+               "                                              (bytes) (bytes) (bytes) type\n"); 
+       fprintf(stream,
+               "-----------------------------------------------------------------------------\n");
+
+       for (i = 0; i < Nfiles; i++) {
+           type = value_to_string(Ftype_Map, File_List[i].f_type);
+           fprintf(stream, "%-40s %12d %7d %7d %s\n",
+                   File_List[i].f_path, File_List[i].f_length,
+                   File_List[i].f_iou, File_List[i].f_riou, type);
+       }
+    }
+}
+
+/*
+ * Initialize output descriptor.  If going to stdout, its easy,
+ * otherwise, attempt to create a FIFO on path Outpipe.  Exit with an
+ * error code if this cannot be done.
+ */
+int
+init_output()
+{
+    int         outfd;
+    struct stat            sbuf;
+
+    if (stat(Outpipe, &sbuf) == -1) {
+       if (errno == ENOENT) {
+           if (mkfifo(Outpipe, 0666) == -1) {
+               fprintf(stderr, "iogen%s:  Could not mkfifo %s:  %s\n",
+                       TagName, Outpipe, SYSERR);
+               exit(2);
+           }
+       } else {
+           fprintf(stderr, "iogen%s:  Could not stat outpipe %s:  %s\n",
+                   TagName, Outpipe, SYSERR);
+           exit(2);
+       }
+    } else {
+       if (! S_ISFIFO(sbuf.st_mode)) {
+           fprintf(stderr,
+                   "iogen%s:  Output file %s exists, but is not a FIFO\n",
+                   TagName, Outpipe);
+           exit(2);
+       }
+    }
+
+    if ((outfd = open(Outpipe, O_RDWR)) == -1) {
+       fprintf(stderr,
+               "iogen%s:  Couldn't open outpipe %s with flags O_RDWR: %s\n",
+               TagName, Outpipe, SYSERR);
+       exit(2);
+    }
+
+    return(outfd);
+}
+
+
+/*
+ * Main io generation function.  form_iorequest() selects a system call to
+ * do based on cmdline arguments, and proceeds to select parameters for that
+ * system call.
+ *
+ * Returns 0 if req is filled in with a complete doio request, otherwise
+ * returns -1.
+ */
+
+int
+form_iorequest(req)
+struct io_req   *req;
+{
+    int                        mult, offset = 0, length = 0, slength;
+    int                        minlength, maxlength, laststart, lastend;
+    int                        minoffset, maxoffset;
+    int                        maxstride, nstrides;
+    char               pattern, *errp;
+    struct strmap      *flags, *sc, *aio_strat;
+    struct file_info   *fptr;
+#ifdef CRAY
+    int                 opcode, cmd;
+#endif
+
+    /*
+     * Choose system call, flags, and file
+     */
+
+    sc = Syscall_List[random_range(0, Nsyscalls-1, 1, NULL)];
+    req->r_type = sc->m_value;
+
+#ifdef CRAY
+    if (sc->m_value == LISTIO ) {
+           opcode = random_range(0, 1, 1, NULL) ? LO_READ : LO_WRITE;
+           cmd = random_range(0, 1, 1, NULL) ? LC_START : LC_WAIT;
+    }
+#endif
+
+    if( sc->m_flags & SY_WRITE )
+           pattern = Byte_Patterns[random_range(0, sizeof(Byte_Patterns) - 1, 1, NULL)];
+    else
+           pattern = 0;
+
+#if CRAY
+    /*
+     * If sds io, simply choose a length (possibly pattern) and return
+     */
+
+    if (sc->m_flags & SY_SDS ) {
+           req->r_data.ssread.r_nbytes = random_range(Mintrans, Maxtrans, BSIZE, NULL);
+           if (sc->m_flags & SY_WRITE)
+                   req->r_data.sswrite.r_pattern = pattern;
+
+           return 0;
+    }
+#endif
+
+    /*
+     * otherwise, we're doing file io.  Choose starting offset, length,
+     * open flags, and possibly a pattern (for write/writea).
+     */
+
+    fptr = &File_List[random_range(0, Nfiles-1, 1, NULL)];
+    flags = Flag_List[random_range(0, Nflags-1, 1, NULL)];
+
+    /*
+     * Choose offset/length multiple.  IO going to a device, or regular
+     * IO that is O_RAW or O_SSD must be aligned on the file r_iou.  Otherwise
+     * it must be aligned on the regular iou (normally 1).
+     */
+
+    if ( fptr->f_type == S_IFREG && (flags->m_flags & FLG_RAW) )
+           mult = fptr->f_riou;
+    else
+           mult = fptr->f_iou;
+
+    /*
+     * Choose offset and length.  Both must be a multiple of mult
+     */
+
+    /*
+     * Choose length first - it must be a multiple of mult
+     */
+
+    laststart = fptr->f_lastoffset;
+    lastend = fptr->f_lastoffset + fptr->f_lastlength - 1;
+
+    minlength = (Mintrans > mult) ? Mintrans : mult;
+
+    switch (Offset_Mode->m_value) {
+    case M_SEQUENTIAL:
+       if (o_opt && lastend > laststart)
+           offset = random_range(laststart, lastend, 1, NULL);
+       else
+           offset = lastend + 1;
+       if (offset && (offset%mult))
+           offset += mult - (offset % mult);
+
+       if (minlength > fptr->f_length - offset)
+           offset = 0;
+
+       maxlength = fptr->f_length - offset;
+       if (maxlength > Maxtrans)
+           maxlength = Maxtrans;
+
+       length = random_range(minlength, maxlength, mult, &errp);
+       if (errp != NULL) {
+           fprintf(stderr, "iogen%s:  random_range(%d, %d, %d) failed\n",
+                   TagName, minlength, maxlength, mult);
+           return -1;
+       }
+
+       break;
+
+    case M_REVERSE:
+       maxlength = laststart;
+
+       if (maxlength > Maxtrans)
+           maxlength = Maxtrans;
+
+       if (minlength > maxlength) {
+           laststart = fptr->f_length;
+           lastend = fptr->f_length;
+           maxlength = Maxtrans;
+       }
+
+       length = random_range(minlength, maxlength, mult, &errp);
+       if (errp != NULL) {
+           fprintf(stderr, "iogen%s:  random_range(%d, %d, %d) failed\n",
+                   TagName, minlength, maxlength, mult);
+           return -1;
+       }
+
+       offset = laststart - length;
+
+       if (o_opt && lastend > laststart)
+           offset += random_range(1, lastend - laststart, 1, NULL);
+
+       if (offset &&  (offset%mult))
+           offset -= offset % mult;
+
+       break;
+    
+    case M_RANDOM:
+       length = random_range(Mintrans, Maxtrans, mult, NULL);
+
+       if (o_opt && lastend > laststart) {
+               minoffset = laststart - length + 1;
+               if (minoffset < 0) {
+                       minoffset = 0;
+               }
+
+               if (lastend + length > fptr->f_length) {
+                       maxoffset = fptr->f_length - length;
+               } else {
+                       maxoffset = lastend;
+               }
+       } else {
+           minoffset = 0;
+           maxoffset = fptr->f_length - length;
+       }
+
+       if (minoffset < 0)
+           minoffset = 0;
+
+       offset = random_range(minoffset, maxoffset, mult, &errp);
+       if (errp != NULL) {
+           fprintf(stderr, "iogen%s:  random_range(%d, %d, %d) failed\n",
+                   TagName, minoffset, maxoffset, mult);
+           return -1;
+       }
+    }
+
+    fptr->f_lastoffset = offset;
+    fptr->f_lastlength = length;
+
+    /*
+     * Choose an async io completion strategy if necessary
+     */
+    if( sc->m_flags & SY_ASYNC )
+           aio_strat = Aio_Strat_List[random_range(0, Naio_Strat_Types - 1,
+                                                   1, NULL)];
+    else
+           aio_strat = NULL;
+
+    /*
+     * fill in specific syscall record data
+     */
+    switch (sc->m_value) {
+    case READ:
+    case READA:
+       strcpy(req->r_data.read.r_file, fptr->f_path);
+       req->r_data.read.r_oflags = O_RDONLY | flags->m_value;
+       req->r_data.read.r_offset = offset;
+       req->r_data.read.r_nbytes = length;
+       req->r_data.read.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+       req->r_data.read.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+       req->r_data.read.r_nstrides = 1;
+       req->r_data.read.r_nent = 1;
+       break;
+
+    case WRITE:
+    case WRITEA:
+       strcpy(req->r_data.write.r_file, fptr->f_path);
+       req->r_data.write.r_oflags = O_WRONLY | flags->m_value;
+       req->r_data.write.r_offset = offset;
+       req->r_data.write.r_nbytes = length;
+       req->r_data.write.r_pattern = pattern;
+       req->r_data.write.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+       req->r_data.write.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+       req->r_data.write.r_nstrides = 1;
+       req->r_data.write.r_nent = 1;
+       break;
+
+    case READV:
+    case AREAD:
+    case PREAD:
+    case WRITEV:
+    case AWRITE:
+    case PWRITE:
+
+    case LREAD:
+    case LREADA:
+    case LWRITE:
+    case LWRITEA:
+
+    case RESVSP:
+    case UNRESVSP:
+    case FSYNC2:
+    case FDATASYNC:
+
+       strcpy(req->r_data.io.r_file, fptr->f_path);
+       req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value;
+       req->r_data.io.r_offset = offset;
+       req->r_data.io.r_nbytes = length;
+       req->r_data.io.r_pattern = pattern;
+       req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+       req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+       req->r_data.io.r_nstrides = 1;
+       req->r_data.io.r_nent = 1;
+       break;
+
+    case MMAPR:
+    case MMAPW:
+       strcpy(req->r_data.io.r_file, fptr->f_path);
+       /* a subtle "feature" of mmap: a write-map requires
+           the file open read/write */
+       req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_RDWR : O_RDONLY) | flags->m_value;
+       req->r_data.io.r_offset = offset;
+       req->r_data.io.r_nbytes = length;
+       req->r_data.io.r_pattern = pattern;
+       req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+       req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+       req->r_data.io.r_nstrides = 1;
+       req->r_data.io.r_nent = 1;
+       break;
+
+    case LSREAD:
+    case LSREADA:
+    case LEREAD:
+    case LEREADA:
+    case LSWRITE:
+    case LSWRITEA:
+    case LEWRITE:
+    case LEWRITEA:
+       /* multi-strided */
+       strcpy(req->r_data.io.r_file, fptr->f_path);
+       req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value;
+       req->r_data.io.r_offset = offset;
+       req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+       req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+       req->r_data.io.r_pattern = pattern;
+
+       /* multi-strided request...
+        *  random number of strides (1...MaxStrides)
+        *  length of stride must be > minlength
+        *  length of stride must be % mult
+        *
+        * maxstrides = min(length / mult, overall.max#strides)
+        * nstrides = random #
+        * while( length / nstrides < minlength )
+        *      nstrides = new random #
+        */
+       maxstride = length / mult;
+       if(maxstride > Maxstrides)
+           maxstride = Maxstrides;
+
+       if(!Minstrides)
+               Minstrides=1;
+       nstrides = random_range(Minstrides, maxstride, 1, &errp);
+       if (errp != NULL) {
+           fprintf(stderr, "iogen%s:  random_range(%d, %d, %d) failed\n",
+                   TagName, Minstrides, maxstride, 1);
+           return -1;
+       }
+
+       slength = length / nstrides;
+       if(slength % mult != 0) {
+           if( mult > slength) {
+               slength = mult;
+           } else {
+               slength -= slength % mult;
+           }
+           nstrides = length / slength;
+           if(nstrides > Maxstrides)
+                   nstrides = Maxstrides;
+       }
+
+       req->r_data.io.r_nbytes = slength;
+       if( sc->m_flags & SY_NENT ) {
+               req->r_data.io.r_nstrides = 1;
+               req->r_data.io.r_nent = nstrides;
+       } else {
+               req->r_data.io.r_nstrides = nstrides;
+               req->r_data.io.r_nent = 1;
+       }
+       break;
+
+    case LISTIO:
+#ifdef CRAY
+       strcpy(req->r_data.listio.r_file, fptr->f_path);
+       req->r_data.listio.r_offset = offset;
+       req->r_data.listio.r_cmd = cmd;
+       req->r_data.listio.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+       req->r_data.listio.r_filestride = 0;
+       req->r_data.listio.r_memstride = 0;
+       req->r_data.listio.r_opcode = opcode;
+       req->r_data.listio.r_nstrides = 1;
+       req->r_data.listio.r_nbytes = length;
+       req->r_data.listio.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+
+       if (opcode == LO_WRITE) {
+               req->r_data.listio.r_pattern = pattern;
+               req->r_data.listio.r_oflags = O_WRONLY | flags->m_value;
+       } else {
+               req->r_data.listio.r_oflags = O_RDONLY | flags->m_value;
+       }
+#endif
+       break;
+    }
+
+    return 0;
+}
+
+/*
+ * Get information about a file that iogen uses to choose io length and
+ * offset.  Information gathered is file length, iounit, and raw iounit.
+ * For regurlar files, iounit is 1, and raw iounit is the iounit of the
+ * device on which the file resides.  For block/character special files
+ * the iounit and raw iounit are both the iounit of the device.
+ *
+ * Note:       buffered and osync io must be iounit aligned
+ *             raw and ossd io must be raw iounit aligned
+ */
+
+int
+get_file_info(rec)
+struct file_info    *rec;
+{
+    struct stat                        sbuf;
+#ifdef CRAY
+    struct lk_device_info      dinfo;
+#endif
+#ifndef NO_XFS
+    int                                fd;
+    struct dioattr             finfo;
+#endif
+
+    /*
+     * Figure out if the files is regular, block or character special.  Any
+     * other type is an error.
+     */
+
+    if (stat(rec->f_path, &sbuf) == -1) {
+       fprintf(stderr, "iogen%s: get_file_info():  Could not stat() %s:  %s\n",
+               TagName, rec->f_path, SYSERR);
+       return -1;
+    }
+
+#if _CRAY2
+    if ((! S_ISREG(sbuf.st_mode)) || strncmp(rec->f_path, "/dev/", 5) == 0) {
+       fprintf(stderr, "iogen%s:  device level io not supported on cray2\n", TagName);
+       return -1;
+    }
+#endif
+
+    rec->f_type = sbuf.st_mode & S_IFMT;
+
+    /*
+     * If regular, iou is 1, and we must figure out the device on
+     * which the file resides.  riou is the iou (logical sector size) of
+     * this device.
+     */
+
+    if (S_ISREG(sbuf.st_mode)) {
+       rec->f_iou = 1;
+       rec->f_length = sbuf.st_size;
+
+       /*
+        * If -r used, take Rawmult as the raw/ssd io multiple.  Otherwise
+        * attempt to determine it by looking at the device the file
+        * resides on.
+        */
+
+       if (r_opt) {
+           rec->f_riou = Rawmult;
+           return 0;
+       }
+
+       rec->f_riou = BSIZE;
+#ifdef CRAY
+       if (lk_rawdev(rec->f_path, dinfo.path, sizeof(dinfo.path), 0) == -1)
+           return -1;
+
+       if (lk_devinfo(&dinfo, 0) == -1) {
+           /* can't get raw I/O unit -- use stat to fudge it */
+           rec->f_riou = sbuf.st_blksize;
+       } else {
+           rec->f_riou = ctob(dinfo.iou);
+       }
+#endif
+#ifndef NO_XFS
+       if( (fd = open(rec->f_path, O_RDWR|O_DIRECT, 0)) != -1 ) {
+           if(xfsctl(rec->f_path, fd, XFS_IOC_DIOINFO, &finfo) != -1) {
+               rec->f_riou = finfo.d_miniosz;
+           } else {
+               fprintf(stderr,
+                       "iogen%s: Error %s (%d) getting direct I/O info of file %s\n",
+                       TagName, strerror(errno), errno, rec->f_path);
+           }
+           close(fd);
+       } else {
+           rec->f_riou = BBSIZE;
+       }
+#endif
+
+    } else {
+
+#ifdef CRAY
+       /*
+        * Otherwise, file is a device.  Use lk_devinfo() to get its logical
+        * sector size.  This is the iou and riou
+        */
+
+       strcpy(dinfo.path, rec->f_path);
+
+       if (lk_devinfo(&dinfo, 0) == -1) {
+           fprintf(stderr, "iogen%s: %s:  %s\n", TagName, Lk_err_func, Lk_err_mesg);
+           return -1;
+       }
+
+       rec->f_iou = ctob(dinfo.iou);
+       rec->f_riou = ctob(dinfo.iou);
+       rec->f_length = ctob(dinfo.length);
+#else
+#ifdef sgi
+       rec->f_riou = BBSIZE;
+       rec->f_length = BBSIZE;
+#else
+       rec->f_riou = BSIZE;
+       rec->f_length = BSIZE;
+#endif /* sgi */
+#endif /* CRAY */
+    }
+
+    return 0;
+}
+
+/*
+ * Create file path as nbytes long.  If path exists, the file will either be
+ * extended or truncated to be nbytes long.  Returns final size of file,
+ * or -1 if there was a failure.
+ */
+
+int
+create_file(path, nbytes)
+char   *path;
+int    nbytes;
+{
+    int                fd, rval;
+    char       c;
+    struct stat        sbuf;
+#ifndef NO_XFS
+    int                nb;
+    struct xfs_flock64 f;
+    struct fsxattr xattr;
+    struct dioattr finfo;
+    char       *b, *buf;
+#endif
+
+    errno = 0;
+    rval = stat(path, &sbuf);
+
+    if (rval == -1) {
+       if (errno == ENOENT) {
+           sbuf.st_size = 0;
+       } else {
+           fprintf(stderr, "iogen%s:  Could not stat file %s:  %s (%d)\n",
+                   TagName, path, SYSERR, errno);
+           return -1;
+       }
+    } else {
+       if (! S_ISREG(sbuf.st_mode)) {
+           fprintf(stderr,
+                   "iogen%s:  file %s exists, but is not a regular file - cannot modify length\n",
+                   TagName, path);
+           return -1;
+       }
+    }
+
+    if (sbuf.st_size == nbytes)
+       return nbytes;
+
+    Oflags |= O_CREAT | O_WRONLY;
+
+    if ((fd = open(path, Oflags, 0666, Ocbits, Ocblks)) == -1) {
+       fprintf(stderr, "iogen%s:  Could not create/open file %s: %s (%d)\n",
+               TagName, path, SYSERR, errno);
+       return -1;
+    }
+
+    /*
+     * Truncate file if it is longer than nbytes, otherwise attempt to
+     * pre-allocate file blocks.
+     */
+
+    if (sbuf.st_size > nbytes) {
+       if (ftruncate(fd, nbytes) == -1) {
+           fprintf(stderr,
+                   "iogen%s:  Could not ftruncate() %s to %d bytes:  %s (%d)\n",
+                   TagName, path, nbytes, SYSERR, errno);
+           close(fd);
+           return -1;
+       }
+    } else {
+
+#ifndef NO_XFS
+       /*
+        *  The file must be designated as Real-Time before any data
+        *  is allocated to it.
+        *
+        */
+       if(Orealtime != 0) {
+           bzero(&xattr, sizeof(xattr));
+           xattr.fsx_xflags = XFS_XFLAG_REALTIME;
+           /*fprintf(stderr, "set: fsx_xflags = 0x%x\n", xattr.fsx_xflags);*/
+           if( xfsctl(path, fd, XFS_IOC_FSSETXATTR, &xattr) == -1 ) {
+               fprintf(stderr, "iogen%s: Error %s (%d) setting XFS XATTR->Realtime on file %s\n",
+                       TagName, SYSERR, errno, path);
+               close(fd);
+               return -1;
+           }
+
+#ifdef DEBUG
+           if( xfsctl(path, fd, XFS_IOC_FSGETXATTR, &xattr) == -1 ) {
+               fprintf(stderr, "iogen%s: Error getting realtime flag %s (%d)\n",
+                       TagName, SYSERR, errno);
+               close(fd);
+               return -1;
+           } else {
+               fprintf(stderr, "get: fsx_xflags = 0x%x\n", 
+                       xattr.fsx_xflags);
+           }
+#endif
+       }
+
+       /*
+        * Reserve space
+        *
+        * Failure is ignored since XFS_IOC_RESVSP only works on XFS and the
+        * filesystem could be on some otehr filesystem.
+        */
+       if( Oreserve ) {
+           f.l_whence = SEEK_SET;
+           f.l_start = 0;
+           f.l_len = nbytes;
+           
+           /*fprintf(stderr,
+                   "create_file: xfsctl(%d, RESVSP, { %d, %lld, %lld })\n",
+                  fd, f.l_whence, (long long)f.l_start, (long long)f.l_len);*/
+
+           /* non-zeroing reservation */
+           if( xfsctl( path, fd, XFS_IOC_RESVSP, &f ) == -1) {
+               fprintf(stderr,
+                       "iogen%s:  Could not xfsctl(XFS_IOC_RESVSP) %d bytes in file %s: %s (%d)\n",
+                       TagName, nbytes, path, SYSERR, errno);
+               close(fd);
+               return -1;
+           }
+       }
+
+       if( Oallocate ) {
+           /* XFS_IOC_ALLOCSP allocates from the file start to l_start */
+           f.l_whence = SEEK_SET;
+           f.l_start = nbytes;
+           f.l_len = 0;
+           /*fprintf(stderr,
+                   "create_file: xfsctl(%d, XFS_IOC_ALLOCSP, { %d, %lld, %lld })\n",
+                   fd, f.l_whence, (long long)f.l_start,
+                   (long long)f.l_len);*/
+
+           /* zeroing reservation */
+           if( xfsctl( path, fd, XFS_IOC_ALLOCSP, &f ) == -1) {
+               fprintf(stderr,
+                       "iogen%s:  Could not xfsctl(XFS_IOC_ALLOCSP) %d bytes in file %s: %s (%d)\n",
+                       TagName, nbytes, path, SYSERR, errno);
+               close(fd);
+               return -1;
+           }
+       }
+#endif
+
+       /*
+        * Write a byte at the end of file so that stat() sets the right
+        * file size.
+        */
+
+#ifndef NO_XFS
+       if(Owrite == 2) {
+           close(fd);
+           if( (fd = open(path, O_CREAT|O_RDWR|O_DIRECT, 0)) != -1 ) {
+               if(xfsctl(path, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
+                   fprintf(stderr,
+                           "iogen%s: Error %s (%d) getting direct I/O info for file %s\n",
+                           TagName, SYSERR, errno, path);
+                   return -1;
+               } else {
+                   /*fprintf(stderr, "%s: miniosz=%d\n", 
+                           path, finfo.d_miniosz);*/
+               }
+           } else {
+               fprintf(stderr, "iogen%s: Error %s (%d) opening file %s with flags O_CREAT|O_RDWR|O_DIRECT\n",
+                       TagName, SYSERR, errno, path);
+               return -1;
+           }
+
+           /*
+            * nb is nbytes adjusted down by an even d_miniosz block
+            *
+            * Note: the first adjustment can cause iogen to print a warning 
+            *  about not being able to create a file of <nbytes> length, 
+            *  since the file will be shorter.
+            */
+           nb = nbytes-finfo.d_miniosz;
+           nb = nb-nb%finfo.d_miniosz;
+
+           /*fprintf(stderr,
+                   "create_file_ow2: lseek(%d, %d {%d %d}, SEEK_SET)\n",
+                   fd, nb, nbytes, finfo.d_miniosz);*/
+
+           if (lseek(fd, nb, SEEK_SET) == -1) {
+               fprintf(stderr,
+                       "iogen%s:  Could not lseek() to EOF of file %s: %s (%d)\n\tactual offset %d file size goal %d miniosz %lld\n",
+                       TagName, path, SYSERR, errno,
+                       nb, nbytes, (long long)finfo.d_miniosz);
+               close(fd);
+               return -1;
+           }
+
+           b = buf = (char *)malloc(finfo.d_miniosz+finfo.d_mem);
+
+           if( ((long)buf % finfo.d_mem != 0) ) {
+               buf += finfo.d_mem - ((long)buf % finfo.d_mem);
+           }
+           
+           memset(buf, 0, finfo.d_miniosz);
+
+           if ( (rval=write(fd, buf, finfo.d_miniosz)) != finfo.d_miniosz) {
+               fprintf(stderr,
+                       "iogen%s:  Could not write %d byte length file %s: %s (%d)\n",
+                       TagName, nb, path, SYSERR, errno);
+               fprintf(stderr,
+                       "\twrite(%d, 0x%lx, %d) = %d\n",
+                       fd, (long)buf, finfo.d_miniosz, rval);
+               fprintf(stderr,
+                       "\toffset %d file size goal %d, miniosz=%d\n",
+                       nb, nbytes, finfo.d_miniosz);
+               close(fd);
+               return -1;
+           }
+           free(b);
+       } else
+#endif
+           if(Owrite) {
+           /*fprintf(stderr,
+                   "create_file_Owrite: lseek(%d, %d {%d}, SEEK_SET)\n",
+                   fd, nbytes-1, nbytes);*/
+
+           if (lseek(fd, nbytes-1, SEEK_SET) == -1) {
+               fprintf(stderr,
+                       "iogen%s:  Could not lseek() to EOF in file %s:  %s (%d)\n\toffset goal %d\n",
+                       TagName, path, SYSERR, errno,
+                       nbytes-1);
+               close(fd);
+               return -1;
+           }
+
+           if ( (rval=write(fd, &c, 1)) != 1) {
+               fprintf(stderr,
+                       "iogen%s:  Could not create a %d byte length file %s: %s (%d)\n",
+                       TagName, nbytes, path, SYSERR, errno);
+               fprintf(stderr,
+                       "\twrite(%d, 0x%lx, %d) = %d\n",
+                       fd, (long)&c, 1, rval);
+               fprintf(stderr,
+                       "\toffset %d file size goal %d\n",
+                       nbytes-1, nbytes);
+               close(fd);
+               return -1;
+           }
+       }
+    }
+
+    fstat(fd, &sbuf);
+    close(fd);
+
+    return sbuf.st_size;
+}
+
+/*
+ * Function to convert a string to its corresponding value in a strmap array.
+ * If the string is not found in the array, the value corresponding to the
+ * NULL string (the last element in the array) is returned.
+ */
+
+int
+str_to_value(map, str)
+struct strmap  *map;
+char           *str;
+{
+    struct strmap   *mp;
+
+    for (mp = map; mp->m_string != NULL; mp++)
+       if (strcmp(mp->m_string, str) == 0)
+           break;
+
+    return mp->m_value;
+}
+    
+/*
+ * Function to convert a string to its corresponding entry in a strmap array.
+ * If the string is not found in the array, a NULL is returned.
+ */
+
+struct strmap *
+str_lookup(map, str)
+struct strmap  *map;
+char           *str;
+{
+    struct strmap   *mp;
+
+    for (mp = map; mp->m_string != NULL; mp++)
+       if (strcmp(mp->m_string, str) == 0)
+           break;
+
+    return((mp->m_string == NULL) ? NULL : mp);
+}
+    
+
+/*
+ * Function to convert a value to its corresponding string in a strmap array.
+ * If the value is not found in the array, NULL is returned.
+ */
+
+char *
+value_to_string(map, val)
+struct strmap   *map;
+int            val;
+{
+    struct strmap  *mp;
+
+    for (mp = map; mp->m_string != NULL; mp++)
+       if (mp->m_value == val)
+           break;
+
+    return mp->m_string;
+}
+
+/*
+ * Interpret cmdline options/arguments.  Exit with 1 if something on the
+ * cmdline isn't kosher.
+ */
+
+int
+parse_cmdline(argc, argv, opts)
+int    argc;
+char   **argv;
+char   *opts;
+{
+    int                        o, len, nb, format_error;
+    struct strmap      *flgs, *sc;
+    char               *file, *cp, ch;
+    struct strmap      *mp;
+    struct file_info   *fptr;
+    int                        nopenargs;
+    char               *openargs[5];   /* Flags, cbits, cblks */
+#ifdef CRAY
+    char               *errmsg;
+    char               *ranges;
+    struct strmap      *type;
+#endif
+
+    while ((o = getopt(argc, argv, opts)) != EOF) {
+        switch ((char)o) {
+
+       case 'a':
+#ifndef CRAY
+           fprintf(stderr, "iogen%s:  Unrecognized option -a on this platform\n", TagName);
+           exit(2);
+#else
+           cp = strtok(optarg, ",");
+           while (cp != NULL) {
+               if ((type = str_lookup(Aio_Strat_Map, cp)) == NULL) {
+                   fprintf(stderr, "iogen%s:  Unrecognized aio completion strategy:  %s\n", TagName, cp);
+                   exit(2);
+               }
+
+               Aio_Strat_List[Naio_Strat_Types++] = type;
+               cp = strtok(NULL, ",");
+           }
+           a_opt++;
+#endif
+           break;
+
+       case 'f':
+           cp = strtok(optarg, ",");
+           while (cp != NULL) {
+               if( (flgs = str_lookup(Flag_Map, cp)) == NULL ) {
+                   fprintf(stderr, "iogen%s:  Unrecognized flags:  %s\n", TagName, cp);
+                   exit(2);
+               }
+
+               cp = strtok(NULL, ",");
+
+#ifdef O_SSD
+               if (flgs->m_value & O_SSD && ! Sds_Avail) {
+                   fprintf(stderr, "iogen%s:  Warning - no sds available, ignoring ssd flag\n", TagName);
+                   continue;
+               }
+#endif
+
+               Flag_List[Nflags++] = flgs;
+           }
+           f_opt++;
+           break;
+
+       case 'h':
+           help(stdout);
+           exit(0);
+           break;
+
+       case 'i':
+           format_error = 0;
+
+           switch (sscanf(optarg, "%i%c", &Iterations, &ch)) {
+           case 1:
+               Time_Mode = 0;
+               break;
+
+           case 2:
+               if (ch == 's')
+                   Time_Mode = 1;
+               else
+                   format_error = 1;
+               break;
+
+           default:
+               format_error = 1;
+           }
+
+           if (Iterations < 0)
+               format_error = 1;
+
+           if (format_error) {
+               fprintf(stderr, "iogen%s:  Illegal -i arg (%s):  Must be of the format:  number[s]\n", TagName, optarg);
+               fprintf(stderr, "        where 'number' is >= 0\n");
+               exit(1);
+           }
+
+           i_opt++;
+           break;
+
+       case 'L':
+#ifndef CRAY
+           fprintf(stderr, "iogen%s:  Unrecognized option -L on this platform\n", TagName);
+           exit(2);
+#else
+           if( parse_ranges(optarg, 1, 255, 1, NULL, &ranges, 
+                            &errmsg ) == -1 ) {
+                   fprintf(stderr, "iogen%s: error parsing listio range '%s': %s\n",
+                           TagName, optarg, errmsg);
+                   exit(1);
+           }
+
+           Minstrides = range_min(ranges, 0);
+           Maxstrides = range_max(ranges, 0);
+
+           free(ranges);
+           L_opt++;
+#endif
+           break;
+
+       case 'm':
+           if ((Offset_Mode = str_lookup(Omode_Map, optarg)) == NULL) {
+               fprintf(stderr, "iogen%s:  Illegal -m arg (%s)\n", TagName, optarg);
+               exit(1);
+           }
+
+           m_opt++;
+           break;
+
+       case 'N':
+           sprintf( TagName, "(%.39s)", optarg );
+           break;
+
+       case 'o':
+           o_opt++;
+           break;
+
+       case 'O':
+
+           nopenargs = string_to_tokens(optarg, openargs, 4, ":/");
+
+#ifdef CRAY
+           if(nopenargs)
+               sscanf(openargs[1],"%i", &Ocbits);
+           if(nopenargs > 1)
+               sscanf(openargs[2],"%i", &Ocblks);
+
+           Oflags = parse_open_flags(openargs[0], &errmsg);
+           if(Oflags == -1) {
+               fprintf(stderr, "iogen%s: -O %s error: %s\n", TagName, optarg, errmsg);
+               exit(1);
+           }
+#endif
+#ifndef NO_XFS
+           if(!strcmp(openargs[0], "realtime")) {
+               /*
+                * -O realtime:extsize
+                */
+               Orealtime = 1;
+               if(nopenargs > 1)
+                   sscanf(openargs[1],"%i", &Oextsize);
+               else
+                   Oextsize=0;
+           } else if( !strcmp(openargs[0], "allocate") ||
+                      !strcmp(openargs[0], "allocsp")) {
+               /*
+                * -O allocate
+                */
+               Oreserve=0;
+               Oallocate=1;
+           } else if(!strcmp(openargs[0], "reserve")) {
+               /*
+                * -O [no]reserve
+                */
+               Oallocate=0;
+               Oreserve=1;
+           } else if(!strcmp(openargs[0], "noreserve")) {
+               /* Oreserve=1 by default; this clears that default */
+               Oreserve=0;
+           } else if(!strcmp(openargs[0], "nowrite")) {
+               /* Owrite=1 by default; this clears that default */
+               Owrite=0;
+           } else if(!strcmp(openargs[0], "direct")) {
+               /* this means "use direct i/o to preallocate file" */
+               Owrite=2;
+           } else {
+               fprintf(stderr, "iogen%s: Error: -O %s error: unrecognized option\n",
+                       TagName, openargs[0]);
+               exit(1);
+           }
+#else
+           Oflags = parse_open_flags(openargs[0], &errmsg);
+           if(Oflags == -1) {
+               fprintf(stderr, "iogen%s: -O %s error: %s\n", TagName, optarg, errmsg);
+               exit(1);
+           }
+#endif
+
+           O_opt++;
+           break;
+
+       case 'p':
+           Outpipe = optarg;
+           p_opt++;
+           break;
+
+       case 'r':
+           if ((Rawmult = str_to_bytes(optarg)) == -1 ||
+                         Rawmult < 11 || Rawmult % BSIZE) {
+               fprintf(stderr, "iogen%s:  Illegal -r arg (%s).  Must be > 0 and multipe of BSIZE (%d)\n",
+                       TagName, optarg, BSIZE);
+               exit(1);
+           }
+
+           r_opt++;
+           break;
+
+       case 's':
+           cp = strtok(optarg, ",");
+           while (cp != NULL) {
+               if ((sc = str_lookup(Syscall_Map, cp)) == NULL) {
+                   fprintf(stderr, "iogen%s:  Unrecognized syscall:  %s\n", TagName, cp);
+                   exit(2);
+               }
+
+               do {
+                   /* >>> sc->m_flags & FLG_SDS */
+                   if (sc->m_value != SSREAD && sc->m_value != SSWRITE)
+                       Fileio++;
+
+                   Syscall_List[Nsyscalls++] = sc;
+               } while ( (sc = str_lookup(++sc, cp)) != NULL);
+
+               cp = strtok(NULL, ",");
+           }
+           s_opt++;
+           break;
+
+       case 't':
+           if ((Mintrans = str_to_bytes(optarg)) == -1) {
+               fprintf(stderr, "iogen%s:  Illegal -t arg (%s):  Must have the form num[bkm]\n", TagName, optarg);
+               exit(1);
+           }
+           t_opt++;
+           break;
+
+       case 'T':
+           if ((Maxtrans = str_to_bytes(optarg)) == -1) {
+               fprintf(stderr, "iogen%s:  Illegal -T arg (%s):  Must have the form num[bkm]\n", TagName, optarg);
+               exit(1);
+           }
+           T_opt++;
+           break;
+
+       case 'q':
+           q_opt++;
+           break;
+
+       case '?':
+           usage(stderr);
+           exit(1);
+       }
+    }
+
+    /*
+     * Supply defaults
+     */
+
+    if( ! L_opt ) {
+           Minstrides = 1;
+           Maxstrides = 255;
+    }
+
+    if (! m_opt)
+       Offset_Mode = str_lookup(Omode_Map, "sequential");
+
+    if (! i_opt)
+       Iterations = 0;
+
+    if (! t_opt)
+       Mintrans = 1;
+
+    if (! T_opt)
+       Maxtrans = 256 * BSIZE;
+
+    if( ! O_opt) 
+       Oflags = Ocbits = Ocblks = 0;
+
+    /*
+     * Supply default async io completion strategy types.
+     */
+
+    if (! a_opt) {
+           for (mp = Aio_Strat_Map; mp->m_string != NULL; mp++) {
+                   Aio_Strat_List[Naio_Strat_Types++] = mp;
+           }
+    }
+
+    /*
+     * Supply default syscalls.  Default is read,write,reada,writea,listio.
+     */
+
+    if (! s_opt) {
+       Nsyscalls = 0;
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "read");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "write");
+#ifdef CRAY
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "reada");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writea");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lread");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lreada");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lwrite");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lwritea");
+#endif
+
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pread");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pwrite");
+#ifdef sgi
+       /*Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "aread");*/
+       /*Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "awrite");*/
+#endif
+
+#ifndef CRAY
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "readv");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writev");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmread");
+       Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmwrite");
+#endif
+
+        Fileio = 1;
+    }
+
+    if (Fileio && (argc - optind < 1)) {
+       fprintf(stderr, "iogen%s:  No files specified on the cmdline\n", TagName);
+       exit(1);
+    }
+
+    /*
+     * Supply default file io flags - defaut is 'buffered,raw,sync,ldraw'.
+     */
+
+    if (! f_opt && Fileio) {
+           Nflags = 0;
+           Flag_List[Nflags++] = str_lookup(Flag_Map, "buffered");
+           Flag_List[Nflags++] = str_lookup(Flag_Map, "sync");
+#ifdef CRAY
+           Flag_List[Nflags++] = str_lookup(Flag_Map, "raw+wf");
+           Flag_List[Nflags++] = str_lookup(Flag_Map, "ldraw");
+#endif
+
+#ifdef sgi
+           /* Warning: cannot mix direct i/o with others! */
+           Flag_List[Nflags++] = str_lookup(Flag_Map, "dsync");
+           Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync");
+           /* Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync+sync");*/
+           /* Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync+dsync");*/
+#endif
+    }
+
+    if (Fileio) {
+       if (optind >= argc) {
+           fprintf(stderr, "iogen%s:  No files listed on the cmdline\n", TagName);
+           exit(1);
+       }
+
+       /*
+        * Initialize File_List[] - only necessary if doing file io.  First 
+        * space for the File_List array, then fill it in.
+        */
+       
+       File_List = (struct file_info *)
+           malloc((argc-optind) * sizeof(struct file_info));
+       
+       if (File_List == NULL) {
+           fprintf(stderr, "iogen%s:  Could not malloc space for %d file_info structures\n", TagName, argc-optind);
+           exit(2);
+       }
+
+       memset(File_List, 0, (argc-optind) * sizeof(struct file_info));
+
+        Nfiles = 0;
+        while (optind < argc) {
+           len = -1;
+
+           /*
+            * Pick off leading len: if it's there and create/extend/trunc
+            * the file to the desired length.  Otherwise, just make sure
+            * the file is accessable.
+            */
+
+           if ((cp = strchr(argv[optind], ':')) != NULL) {
+               *cp = '\0';
+               if ((len = str_to_bytes(argv[optind])) == -1) {
+                   fprintf(stderr,
+                           "iogen%s:  illegal file length (%s) for file %s\n",
+                           TagName, argv[optind], cp+1);
+                   exit(2);
+               }
+               *cp = ':';
+               file = cp+1;
+
+               if (strlen(file) > MAX_FNAME_LENGTH) {
+                   fprintf(stderr, "iogen%s:  Max fname length is %d chars - ignoring file %s\n",
+                           TagName, MAX_FNAME_LENGTH, file);
+                   optind++;
+                   continue;
+               }
+
+               nb = create_file(file, len);
+
+               if (nb < len) {
+                   fprintf(stderr,
+                           "iogen%s warning:  Couldn't create file %s of %d bytes\n",
+                           TagName, file, len);
+
+                   if (nb <= 0) {
+                       optind++;
+                       continue;
+                   }
+               }
+           } else {
+               file = argv[optind];
+               if (access(file, R_OK | W_OK) == -1) {
+                   fprintf(stderr, "iogen%s:  file %s cannot be accessed for reading and/or writing:  %s (%d)\n",
+                           TagName, file, SYSERR, errno);
+                   exit(2);
+               }
+           }
+
+           /*
+            * get per-file information
+            */
+
+           fptr = &File_List[Nfiles];
+
+           if (file[0] == '/') {
+               strcpy(fptr->f_path, file);
+           } else {
+               getcwd(fptr->f_path,
+                      sizeof(fptr->f_path)-1);
+               strcat(fptr->f_path, "/");
+               strcat(fptr->f_path, file);
+           }
+
+           if (get_file_info(fptr) == -1) {
+               fprintf(stderr, "iogen%s warning:  Error getting file info for %s\n", TagName, file);
+           } else {
+
+               /*
+                * If the file length is smaller than our min transfer size,
+                * ignore it.
+                */
+
+               if (fptr->f_length < Mintrans) {
+                   fprintf(stderr, "iogen%s warning:  Ignoring file %s\n",
+                           TagName, fptr->f_path);
+                   fprintf(stderr, "                length (%d) is < min transfer size (%d)\n",
+                           fptr->f_length, Mintrans);
+                   optind++;
+                   continue;
+               }
+
+                /*
+                 * If the file length is smaller than our max transfer size,
+                 * ignore it.
+                 */
+
+                if (fptr->f_length < Maxtrans) {
+                    fprintf(stderr, "iogen%s warning:  Ignoring file %s\n",
+                            TagName, fptr->f_path);
+                    fprintf(stderr, "                length (%d) is < max transfer size (%d)\n",
+                            fptr->f_length, Maxtrans);
+                    optind++;
+                    continue;
+                }
+
+               if (fptr->f_length > 0) {
+                   switch (Offset_Mode->m_value) {
+                   case M_SEQUENTIAL:
+                       fptr->f_lastoffset = 0;
+                       fptr->f_lastlength = 0;
+                       break;
+                       
+                   case M_REVERSE:
+                       fptr->f_lastoffset = fptr->f_length;
+                       fptr->f_lastlength = 0;
+                       break;
+                       
+                   case M_RANDOM:
+                       fptr->f_lastoffset = fptr->f_length / 2;
+                       fptr->f_lastlength = 0;
+                       break;
+                   }
+                   
+                   Nfiles++;
+               }
+           }
+
+           optind++;
+       }
+
+        if (Nfiles == 0) {
+           fprintf(stderr, "iogen%s:  Could not create, or gather info for any test files\n", TagName);
+           exit(2);
+        }
+    }
+
+    return 0;
+}
+
+int
+help(stream)
+FILE   *stream;
+{
+    usage(stream);
+    fprintf(stream, "\n");
+#ifndef linux
+    fprintf(stream, "\t-a aio_type,...  Async io completion types to choose.  Supported types\n");
+#ifdef CRAY
+#if _UMK || RELEASE_LEVEL >= 8000
+    fprintf(stream, "\t                 are:  poll, signal, recall, recalla, and recalls.\n");
+#else
+    fprintf(stream, "\t                 are:  poll, signal, recalla, and recalls.\n");
+#endif
+#else
+    fprintf(stream, "\t                 are:  poll, signal, suspend, and callback.\n");
+#endif
+    fprintf(stream, "\t                 Default is all of the above.\n");
+#else /* !linux */
+    fprintf(stream, "\t-a               (Not used on Linux).\n");
+#endif /* !linux */
+    fprintf(stream, "\t-f flag,...      Flags to use for file IO.  Supported flags are\n");
+#ifdef CRAY
+    fprintf(stream, "\t                 raw, ssd, buffered, ldraw, sync,\n");
+    fprintf(stream, "\t                 raw+wf, raw+wf+ldraw, raw+wf+ldraw+sync,\n");
+    fprintf(stream, "\t                 and parallel (unicos/mk on MPP only).\n");
+    fprintf(stream, "\t                 Default is 'raw,ldraw,sync,buffered'.\n");
+#else
+#ifndef NO_XFS
+    fprintf(stream, "\t                 buffered, direct, sync.\n");
+    fprintf(stream, "\t                 Default is 'buffered,sync'.\n");
+#else
+    fprintf(stream, "\t                 buffered, sync.\n");
+    fprintf(stream, "\t                 Default is 'buffered,sync'.\n");
+#endif /* sgi */
+#endif /* CRAY */
+    fprintf(stream, "\t-h               This help.\n");
+    fprintf(stream, "\t-i iterations[s] # of requests to generate.  0 means causes iogen\n");
+    fprintf(stream, "\t                 to run until it's killed.  If iterations is suffixed\n");
+    fprintf(stream, "\t                 with 's', then iterations is the number of seconds\n");
+    fprintf(stream, "\t                 that iogen should run for.  Default is '0'.\n");
+#ifndef CRAY
+    fprintf(stream, "\t-L min:max       listio nstrides / nrequests range\n");
+#else
+    fprintf(stream, "\t-L               (Not used on this platform).\n");
+#endif /* !CRAY */
+    fprintf(stream, "\t-m offset-mode   The mode by which iogen chooses the offset for\n");
+    fprintf(stream, "\t                 consectutive transfers within a given file.\n");
+    fprintf(stream, "\t                 Allowed values are 'random', 'sequential',\n");
+    fprintf(stream, "\t                 and 'reverse'.\n");
+    fprintf(stream, "\t                 sequential is the default.\n");
+    fprintf(stream, "\t-N tagname       Tag name, for Monster.\n");
+    fprintf(stream, "\t-o               Form overlapping consecutive requests.\n");
+    fprintf(stream, "\t-O               Open flags for creating files\n");
+#ifdef CRAY
+    fprintf(stream, "\t                 {O_PLACE,O_BIG,etc}[:CBITS[:CBLKS]]\n");
+#endif
+#ifndef NO_XFS
+    fprintf(stream, "\t                 realtime:extsize - put file on real-time volume\n");
+    fprintf(stream, "\t                 allocate - allocate space with F_ALLOCSP\n");
+    fprintf(stream, "\t                 reserve - reserve space with F_RESVSP (default)\n");
+    fprintf(stream, "\t                 noreserve - do not reserve with F_RESVSP\n");
+    fprintf(stream, "\t                 direct - use O_DIRECT I/O to write to the file\n");
+#else
+    fprintf(stream, "\t                 {O_SYNC,etc}\n");
+#endif
+    fprintf(stream, "\t-p               Output pipe.  Default is stdout.\n");
+    fprintf(stream, "\t-q               Quiet mode.  Normally iogen spits out info\n");
+    fprintf(stream, "\t                 about test files, options, etc. before starting.\n");
+    fprintf(stream, "\t-s syscall,...   Syscalls to do.  Supported syscalls are\n");
+#ifdef sgi
+    fprintf(stream, "\t                 read, write, pread, pwrite, readv, writev\n");
+    fprintf(stream, "\t                 aread, awrite, resvsp, unresvsp, ffsync,\n");
+    fprintf(stream, "\t                 mmread, mmwrite, fsync2, fdatasync,\n");
+    fprintf(stream, "\t                 Default is 'read,write,pread,pwrite,readv,writev,mmread,mmwrite'.\n");
+#endif
+#ifdef CRAY
+    fprintf(stream, "\t                 read, write, reada, writea, listio,\n");
+    fprintf(stream, "\t                 ssread (PVP only), and sswrite (PVP only).\n");
+    fprintf(stream, "\t                 Default is 'read,write,reada,writea,listio'.\n");
+#endif
+#ifdef linux
+    fprintf(stream, "\t                 read, write, pread, pwrite, readv, writev,\n");
+    fprintf(stream, "\t                 mmread, mmwrite, fsync2, fdatasync,\n");
+    fprintf(stream, "\t                 Default is 'read,write,readv,writev,mmread,mmwrite'.\n");
+#endif
+    fprintf(stream, "\t-t mintrans      Min transfer length\n");
+    fprintf(stream, "\t-T maxtrans      Max transfer length\n");
+    fprintf(stream, "\n");
+    fprintf(stream, "\t[len:]file,...   Test files to do IO against (note ssread/sswrite\n");
+    fprintf(stream, "\t                 don't need a test file).  The len: syntax\n");
+    fprintf(stream, "\t                 informs iogen to first create/expand/truncate the\n");
+    fprintf(stream, "\t                 to the desired length.\n");
+    fprintf(stream, "\n");
+    fprintf(stream, "\tNote:  The ssd flag causes sds transfers to also be done.\n");
+    fprintf(stream, "\t       To totally eliminate sds transfers, you must eleminate sds\n");
+    fprintf(stream, "\t       from the flags (-f) and ssread,ssrite from the syscalls (-s)\n");
+    fprintf(stream, "\tThe mintrans, maxtrans, and len: parameters are numbers of the\n");
+    fprintf(stream, "\tform [0-9]+[bkm].  The optional trailing b, k, or m multiplies\n");
+    fprintf(stream, "\tthe number by blocks, kilobytes, or megabytes.  If no trailing\n");
+    fprintf(stream, "\tmultiplier is present, the number is interpreted as bytes\n");
+
+    return 0;
+}
+
+/*
+ * Obvious - usage clause
+ */
+
+int
+usage(stream)
+FILE   *stream;
+{
+    fprintf(stream, "usage%s:  iogen [-hoq] [-a aio_type,...] [-f flag[,flag...]] [-i iterations] [-p outpipe] [-m offset-mode] [-s syscall[,syscall...]] [-t mintrans] [-T maxtrans] [ -O file-create-flags ] [[len:]file ...]\n", TagName);
+    return 0;
+}
index 556a9936eec6dfdd2068ce924032cc886a2bf8ed..a16956eaf9671995873f67c393339a261cabde15 100644 (file)
@@ -41,6 +41,7 @@ LSRCFILES = \
        package_dmapidev.m4 \
        package_globals.m4 \
        package_ncurses.m4 \
+       package_pthread.m4 \
        package_types.m4 \
        package_utilies.m4 \
        package_uuiddev.m4 \
diff --git a/soak b/soak
index 79bf9795ff5f2ed5facbd3a6eb7e54f13ba388bf..6b6b62f6f188e5142bac27b7d6d9e350594a090d 100755 (executable)
--- a/soak
+++ b/soak
@@ -139,7 +139,7 @@ do
                         || _fail "            !!! couldn't delete old dir"
     
     _log "        *** stress"
-    src/fsstress -d $SCRATCH_MNT/soak_test -p $proc -n $stress $FSSTRESS_AVOID 2>&1 | \
+    ltp/fsstress -d $SCRATCH_MNT/soak_test -p $proc -n $stress $FSSTRESS_AVOID 2>&1 | \
         _fix_malloc >>$FULL
 
     _log "        *** unmounting scratch device"
index 63a5da31ee5680876ab6773e1810fefaee270aed..231456f8c4c1c2d0f93df96e98aa22ad4149496b 100644 (file)
@@ -1,5 +1,5 @@
 # 
-# Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (c) 2000-2003 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
@@ -34,53 +34,38 @@ TOPDIR = ..
 include $(TOPDIR)/include/builddefs
 
 TARGETS = alloc acl_get bstat devzero dirstress fault feature \
-         fsstress fill fill2 getpagesize holes xfsctl loggen lstat64 \
+         fill fill2 getpagesize holes xfsctl loggen lstat64 \
          nametest permname randholes runas truncfile usemem \
          fstest mmapcat append_reader append_writer
-ifeq ($(HAVE_DB), true)
+ifeq ($(ENABLE_DBM), yes)
 TARGETS += dbtest
 endif
 
-CFILES = $(TARGETS:=.c) random.c
-HFILES = global.h
+CFILES = $(TARGETS:=.c)
 LDIRT = $(TARGETS)
 
 default: $(TARGETS)
 
 include $(BUILDRULES)
+LINKTEST = $(LTLINK) $@.c -o $@ $(CFLAGS) $(LDFLAGS)
 
-install install-dev: default
+randholes: randholes.o $(LIBTEST)
+       $(LINKTEST) $(LIBTEST) $(LDLIBS)
 
-# binaries using non-default objects/libs need an entry below
-# 
-RANDHOLES_OBJECTS = randholes.o random.o
-randholes:     $(HFILES) $(RANDHOLES_OBJECTS)
-               $(CCF) -o $@ $(LDFLAGS) $(RANDHOLES_OBJECTS) $(LDLIBS)
-
-TRUNCFILE_OBJECTS = truncfile.o random.o
-truncfile:     $(HFILES) $(TRUNCFILE_OBJECTS)
-               $(CCF) -o $@ $(LDFLAGS) $(TRUNCFILE_OBJECTS) $(LDLIBS)
-
-FSSTRESS_OBJECTS = fsstress.o random.o $(LIBATTR)
-fsstress:      $(HFILES) $(FSSTRESS_OBJECTS)
-               $(CCF) -o $@ $(LDFLAGS) $(FSSTRESS_OBJECTS) $(LDLIBS)
+truncfile: truncfile.o $(LIBTEST)
+       $(LINKTEST) $(LIBTEST) $(LDLIBS)
 
-DBTEST_OBJECTS = dbtest.o random.o
-dbtest:                $(HFILES) $(DBTEST_OBJECTS)
-               $(CCF) -o $@ $(LDFLAGS) $(DBTEST_OBJECTS) $(LIBGDBM) $(LDLIBS)
+dbtest:        dbtest.o $(LIBTEST)
+       $(LINKTEST) $(LIBTEST) $(LIBGDBM) $(LDLIBS)
 
-NAMETEST_OBJECTS = nametest.o random.o
-nametest:      $(HFILES) $(NAMETEST_OBJECTS)
-               $(CCF) -o $@ $(LDFLAGS) $(NAMETEST_OBJECTS) $(LDLIBS)
+nametest: nametest.o $(LIBTEST)
+       $(LINKTEST) $(LIBTEST) $(LDLIBS)
 
-BSTAT_OBJECTS = bstat.o
-bstat:         $(HFILES) $(BSTAT_OBJECTS)
-               $(CCF) -o $@ $(LDFLAGS) $(BSTAT_OBJECTS) $(LIBHANDLE) $(LDLIBS)
+bstat: bstat.o $(LIBHANDLE)
+       $(LINKTEST) $(LIBHANDLE) $(LDLIBS)
 
-LOGGEN_OBJECTS = loggen.o $(LIBXFS)
-loggen:                $(HFILES) $(LOGGEN_OBJECTS)
-               $(CCF) -o $@ $(LDFLAGS) $(LOGGEN_OBJECTS) $(LDLIBS)
+loggen:        loggen.o $(LIBXFS)
+       $(LINKTEST) $(LIBXFS) $(LDLIBS)
 
-ACLGET_OBJECTS = acl_get.o $(LIBACL) $(LIBATTR)
-acl_get:       $(HFILES) $(ACLGET_OBJECTS)
-               $(CCF) -o $@ $(LDFLAGS) $(ACLGET_OBJECTS) $(LDLIBS)
+acl_get: acl_get.o $(LIBACL) $(LIBATTR)
+       $(LINKTEST) $(LIBACL) $(LIBATTR) $(LDLIBS)
index d366f4cb2a9d9386ba6396deb77b4f17443c28ef..1e4b569efa5d2be4a16db8d6d05e1a9750224e2c 100755 (executable)
@@ -43,7 +43,7 @@ if ($usage) {
     exit 1;
 }
 
-my @pkglist = qw( attr acl dmapi xfsdump xfsprogs );
+my @pkglist = qw( xfstests attr acl dmapi xfsdump xfsprogs );
 my @difflist = qw(
        xfs_ag.h  xfs_alloc.h  xfs_alloc_btree.h xfs_arch.h
        xfs_attr_leaf.h  xfs_attr_sf.h  xfs_bit.h  xfs_bmap.h