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)
54 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 [new file with mode: 0644]
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 [new file with mode: 0644]
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
src/fsstress.c [deleted file]
src/random.c [deleted file]
tools/srcdiff

diff --git a/013 b/013
index 68951f8..841b003 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 718f385..c997b9f 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 91668f6..95e1639 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 72a3fd4..a1ec2f6 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 5e2c6a8..aaa0edf 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 31d1950..8312ac4 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 405304c..fec586b 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 75d3e63..f2eb6e7 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 dea3f30..b4065dd 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 3ba9a7c..3202fff 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 c24bec8..eeb74cd 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 19966c5..b545b03 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 a7eea66..3b52f2d 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 d6ec04d..10648e4 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 0befc54..f808ffd 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 9522042..cecb4c9 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);
+}
diff --git a/lib/random.c b/lib/random.c
new file mode 100644 (file)
index 0000000..eb23cd9
--- /dev/null
@@ -0,0 +1,240 @@
+/**************************************************************************
+ *
+ * random.c -- pseudo random number generator
+ * Copyright (C) 1994  Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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 to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+
+#include <sys/types.h>
+
+/*
+ * modified by dxm@sgi.com so that this file acts as a drop in replacement
+ * for srandom and random.
+ */
+
+/*
+ *     A random number generator called as a function by
+ *     random (iseed)  or      irandm (iseed)
+ *     The parameter should be a pointer to a 2-element int32_t vector.
+ *     The first function returns a double uniform in 0 .. 1.
+ *     The second returns a int32_t integer uniform in 0 .. 2**31-1
+ *     Both update iseed[] in exactly the same way.
+ *     iseed[] must be a 2-element integer vector.
+ *     The initial value of the second element may be anything.
+ *
+ *     The period of the random sequence is 2**32 * (2**32-1)
+ *     The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+#define MASK ((int32_t) 593970775)
+/*     or in hex, 23674657     */
+
+#define SCALE ((double) 1.0 / (1024.0 * 1024.0 * 1024.0 * 2.0))
+/*     i.e. 2 to power -31     */
+
+static int32_t mt [128] =   {
+      902906369,
+     2030498053,
+     -473499623,
+     1640834941,
+      723406961,
+     1993558325,
+     -257162999,
+    -1627724755,
+      913952737,
+      278845029,
+     1327502073,
+    -1261253155,
+      981676113,
+    -1785280363,
+     1700077033,
+      366908557,
+    -1514479167,
+     -682799163,
+      141955545,
+     -830150595,
+      317871153,
+     1542036469,
+     -946413879,
+    -1950779155,
+      985397153,
+      626515237,
+      530871481,
+      783087261,
+    -1512358895,
+     1031357269,
+    -2007710807,
+    -1652747955,
+    -1867214463,
+      928251525,
+     1243003801,
+    -2132510467,
+     1874683889,
+     -717013323,
+      218254473,
+    -1628774995,
+    -2064896159,
+       69678053,
+      281568889,
+    -2104168611,
+     -165128239,
+     1536495125,
+      -39650967,
+      546594317,
+     -725987007,
+     1392966981,
+     1044706649,
+      687331773,
+    -2051306575,
+     1544302965,
+     -758494647,
+    -1243934099,
+      -75073759,
+      293132965,
+    -1935153095,
+      118929437,
+      807830417,
+    -1416222507,
+    -1550074071,
+      -84903219,
+     1355292929,
+     -380482555,
+    -1818444007,
+     -204797315,
+      170442609,
+    -1636797387,
+      868931593,
+     -623503571,
+     1711722209,
+      381210981,
+     -161547783,
+     -272740131,
+    -1450066095,
+     2116588437,
+     1100682473,
+      358442893,
+    -1529216831,
+     2116152005,
+     -776333095,
+     1265240893,
+     -482278607,
+     1067190005,
+      333444553,
+       86502381,
+      753481377,
+       39000101,
+     1779014585,
+      219658653,
+     -920253679,
+     2029538901,
+     1207761577,
+    -1515772851,
+     -236195711,
+      442620293,
+      423166617,
+    -1763648515,
+     -398436623,
+    -1749358155,
+     -538598519,
+     -652439379,
+      430550625,
+    -1481396507,
+     2093206905,
+    -1934691747,
+     -962631983,
+     1454463253,
+    -1877118871,
+     -291917555,
+    -1711673279,
+      201201733,
+     -474645415,
+      -96764739,
+    -1587365199,
+     1945705589,
+     1303896393,
+     1744831853,
+      381957665,
+     2135332261,
+      -55996615,
+    -1190135011,
+     1790562961,
+    -1493191723,
+      475559465,
+          69069
+               };
+
+double 
+_random (int32_t is [2])
+{
+       int32_t it, leh, nit;
+
+       it = is [0];
+       leh = is [1];
+       if (it <= 0)    
+               it = (it + it) ^ MASK;
+       else
+               it = it + it;
+       nit = it - 1;
+/*     to ensure all-ones pattern omitted    */
+       leh = leh * mt[nit & 127] + nit;
+       is [0] = it;    is [1] = leh;
+       if (leh < 0) leh = ~leh;
+       return (SCALE * ((int32_t) (leh | 1)));
+}
+
+
+
+int32_t 
+_irandm (int32_t is [2])
+{
+       int32_t it, leh, nit;
+
+       it = is [0];
+       leh = is [1];
+       if (it <= 0)    
+               it = (it + it) ^ MASK;
+       else
+               it = it + it;
+       nit = it - 1;
+/*     to ensure all-ones pattern omitted    */
+       leh = leh * mt[nit & 127] + nit;
+       is [0] = it;    is [1] = leh;
+       if (leh < 0) leh = ~leh;
+       return (leh);
+}
+
+/*
+ * make this a drop in replacement for random and srandom
+ *
+ * XXX not thread safe I guess.
+ */
+
+static int32_t saved_seed[2];
+
+long random(void)
+{
+    return _irandm(saved_seed);
+}
+
+void srandom(unsigned seed)
+{
+    saved_seed[0]=seed;
+    saved_seed[1]=0;
+    _irandm(saved_seed);
+}
+
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: