functionality-test-suite-20020114
authorDerrick Brashear <shadow@dementia.org>
Mon, 14 Jan 2002 07:49:15 +0000 (07:49 +0000)
committerDerrick Brashear <shadow@dementia.org>
Mon, 14 Jan 2002 07:49:15 +0000 (07:49 +0000)
Based on Arla test suite and AFSTools with some other additions;
intended to set up a standalone cell, perform operations

243 files changed:
Makefile.in
configure.in
src/tests/Auth-Heimdal.pm [new file with mode: 0644]
src/tests/CMU_copyright.pm [new file with mode: 0644]
src/tests/ConfigUtils.pm [new file with mode: 0644]
src/tests/Dirpath.pm.in [new file with mode: 0644]
src/tests/Makefile [new file with mode: 0644]
src/tests/Makefile.in [new file with mode: 0644]
src/tests/OS-LINUX.pm [new file with mode: 0644]
src/tests/OS-SOLARIS.pm [new file with mode: 0644]
src/tests/README [new file with mode: 0644]
src/tests/README.afstools [new file with mode: 0644]
src/tests/acladdgroup.pl [new file with mode: 0755]
src/tests/acladdnegrights.pl [new file with mode: 0755]
src/tests/acladdrights.pl [new file with mode: 0755]
src/tests/acladduser.pl [new file with mode: 0755]
src/tests/aclclearnegrights.pl [new file with mode: 0755]
src/tests/aclcopy.pl [new file with mode: 0755]
src/tests/aclremovegroup.pl [new file with mode: 0755]
src/tests/aclremoveuser.pl [new file with mode: 0755]
src/tests/afs-newcell.pl [new file with mode: 0755]
src/tests/afs-rmcell.sh [new file with mode: 0755]
src/tests/afsconf.pm [new file with mode: 0644]
src/tests/afscp.c [new file with mode: 0644]
src/tests/afscp_callback.c [new file with mode: 0644]
src/tests/append-over-page.c [new file with mode: 0644]
src/tests/append1 [new file with mode: 0644]
src/tests/apwd.c [new file with mode: 0644]
src/tests/asu.c [new file with mode: 0644]
src/tests/blocks-new-file.c [new file with mode: 0644]
src/tests/boot-strap-arla [new file with mode: 0644]
src/tests/bos.pm [new file with mode: 0644]
src/tests/bosaddhost.pl [new file with mode: 0755]
src/tests/bosaddkey.pl [new file with mode: 0755]
src/tests/bosadduser.pl [new file with mode: 0755]
src/tests/boscreate.pl [new file with mode: 0755]
src/tests/bosdelete.pl [new file with mode: 0755]
src/tests/bosdeleterunning.pl [new file with mode: 0755]
src/tests/bosexec.pl [new file with mode: 0755]
src/tests/bosinstall.pl [new file with mode: 0755]
src/tests/boslisthosts.pl [new file with mode: 0755]
src/tests/boslistkeys.pl [new file with mode: 0755]
src/tests/boslistusers.pl [new file with mode: 0755]
src/tests/bosremovehost.pl [new file with mode: 0755]
src/tests/bosremovekey.pl [new file with mode: 0755]
src/tests/bosremoveuser.pl [new file with mode: 0755]
src/tests/bosrestartstopped.pl [new file with mode: 0755]
src/tests/bossalvagepart.pl [new file with mode: 0755]
src/tests/bossalvageserver.pl [new file with mode: 0755]
src/tests/bossalvagevolume.pl [new file with mode: 0755]
src/tests/bosshutdown.pl [new file with mode: 0755]
src/tests/bosstart.pl [new file with mode: 0755]
src/tests/bosstatus.pl [new file with mode: 0755]
src/tests/bosstop.pl [new file with mode: 0755]
src/tests/build-and-run-rcs [new file with mode: 0755]
src/tests/build-emacs [new file with mode: 0755]
src/tests/build-emacs-j [new file with mode: 0644]
src/tests/build-gdb [new file with mode: 0755]
src/tests/build-openafs [new file with mode: 0755]
src/tests/checkpwd [new file with mode: 0755]
src/tests/compare-inum-mp [new file with mode: 0755]
src/tests/compare-inums [new file with mode: 0755]
src/tests/compare-with-local [new file with mode: 0755]
src/tests/config.pm [new file with mode: 0644]
src/tests/copy-and-diff-gnu-mirror [new file with mode: 0755]
src/tests/copy-file [new file with mode: 0755]
src/tests/creat1 [new file with mode: 0755]
src/tests/create-dirs.c [new file with mode: 0644]
src/tests/create-files.c [new file with mode: 0644]
src/tests/create-remove-dirs [new file with mode: 0644]
src/tests/create-remove-files [new file with mode: 0644]
src/tests/create-remove.c [new file with mode: 0644]
src/tests/create-stat.c [new file with mode: 0644]
src/tests/create-symlinks.c [new file with mode: 0644]
src/tests/dd [new file with mode: 0755]
src/tests/deep-tree [new file with mode: 0644]
src/tests/deep-tree2 [new file with mode: 0644]
src/tests/dir-size-mismatch [new file with mode: 0644]
src/tests/dir-tree [new file with mode: 0755]
src/tests/dup2-and-unlog.c [new file with mode: 0644]
src/tests/echo-n.c [new file with mode: 0644]
src/tests/err.c [new file with mode: 0644]
src/tests/err.h [new file with mode: 0644]
src/tests/errtrans.pm [new file with mode: 0644]
src/tests/errx.c [new file with mode: 0644]
src/tests/exec [new file with mode: 0755]
src/tests/exit-wo-close.c [new file with mode: 0644]
src/tests/extcopyin [new file with mode: 0755]
src/tests/extcopyout [new file with mode: 0755]
src/tests/fcachesize-dir [new file with mode: 0644]
src/tests/fcachesize-file-small [new file with mode: 0644]
src/tests/fcachesize-read-file [new file with mode: 0644]
src/tests/fcachesize-write-file [new file with mode: 0644]
src/tests/fchmod.c [new file with mode: 0644]
src/tests/fhbench.c [new file with mode: 0644]
src/tests/find-and-cat-netbsd [new file with mode: 0644]
src/tests/find-linux [new file with mode: 0644]
src/tests/fs-flush [new file with mode: 0644]
src/tests/fs-sa-la [new file with mode: 0755]
src/tests/fs.pm [new file with mode: 0644]
src/tests/fs_lib.c [new file with mode: 0644]
src/tests/fsx.c [new file with mode: 0644]
src/tests/ga-test.c [new file with mode: 0644]
src/tests/generic-build [new file with mode: 0755]
src/tests/getdents-and-unlink1 [new file with mode: 0755]
src/tests/getdents-and-unlink2 [new file with mode: 0755]
src/tests/getdents-and-unlink3 [new file with mode: 0755]
src/tests/grind-arla-with-cvs [new file with mode: 0755]
src/tests/hardlink1.c [new file with mode: 0644]
src/tests/hardlink2.c [new file with mode: 0644]
src/tests/hardlink3 [new file with mode: 0644]
src/tests/hardlink4.c [new file with mode: 0644]
src/tests/hardlink5 [new file with mode: 0644]
src/tests/hello-world.in [new file with mode: 0644]
src/tests/intr-read.c [new file with mode: 0644]
src/tests/intr-read1 [new file with mode: 0755]
src/tests/invalidate-file.c [new file with mode: 0644]
src/tests/kas.pm [new file with mode: 0644]
src/tests/kill-softer.c [new file with mode: 0644]
src/tests/kill-softly.c [new file with mode: 0644]
src/tests/kotest [new file with mode: 0755]
src/tests/large-dir-16384 [new file with mode: 0755]
src/tests/large-dir-extra [new file with mode: 0755]
src/tests/large-dir.c [new file with mode: 0644]
src/tests/large-dir2.c [new file with mode: 0644]
src/tests/large-dir3.c [new file with mode: 0644]
src/tests/large-filename [new file with mode: 0644]
src/tests/ls-afs [new file with mode: 0644]
src/tests/make-page.c [new file with mode: 0644]
src/tests/many-dirs [new file with mode: 0644]
src/tests/many-fetchs [new file with mode: 0644]
src/tests/many-files [new file with mode: 0644]
src/tests/many-files-with-content [new file with mode: 0644]
src/tests/many-stores [new file with mode: 0644]
src/tests/many-symlinks [new file with mode: 0644]
src/tests/mkdir [new file with mode: 0644]
src/tests/mkdir-lnk [new file with mode: 0755]
src/tests/mkdir1 [new file with mode: 0755]
src/tests/mkdir2.c [new file with mode: 0644]
src/tests/mkdir3.c [new file with mode: 0644]
src/tests/mkm-rmm [new file with mode: 0755]
src/tests/mmap-and-read.c [new file with mode: 0644]
src/tests/mmap-cat.c [new file with mode: 0644]
src/tests/mmap-shared-write.c [new file with mode: 0644]
src/tests/mmap-vs-read.c [new file with mode: 0644]
src/tests/mmap-vs-read2.c [new file with mode: 0644]
src/tests/mountpoint.in [new file with mode: 0644]
src/tests/parallel1 [new file with mode: 0644]
src/tests/pine.c [new file with mode: 0644]
src/tests/pts.pm [new file with mode: 0644]
src/tests/ptsadduser.pl [new file with mode: 0755]
src/tests/ptschown.pl [new file with mode: 0755]
src/tests/ptscreategroup.pl [new file with mode: 0755]
src/tests/ptscreateuser.pl [new file with mode: 0755]
src/tests/ptsdeletegroup.pl [new file with mode: 0755]
src/tests/ptsdeleteuser.pl [new file with mode: 0755]
src/tests/ptsexaminegroup.pl [new file with mode: 0755]
src/tests/ptsexamineuser.pl [new file with mode: 0755]
src/tests/ptslistmax.pl [new file with mode: 0755]
src/tests/ptslistown.pl [new file with mode: 0755]
src/tests/ptsmembersgroup.pl [new file with mode: 0755]
src/tests/ptsmembersuser.pl [new file with mode: 0755]
src/tests/ptsremove.pl [new file with mode: 0755]
src/tests/ptssetf.pl [new file with mode: 0755]
src/tests/ptssetmax.pl [new file with mode: 0755]
src/tests/read-vs-mmap.c [new file with mode: 0644]
src/tests/read-vs-mmap2.c [new file with mode: 0644]
src/tests/read-write.c [new file with mode: 0644]
src/tests/readdir-vs-lstat.c [new file with mode: 0644]
src/tests/readfile-wo-create [new file with mode: 0755]
src/tests/reauth.pl [new file with mode: 0755]
src/tests/rename-under-feet.c [new file with mode: 0644]
src/tests/rename1 [new file with mode: 0755]
src/tests/rename2 [new file with mode: 0644]
src/tests/rename3 [new file with mode: 0755]
src/tests/rename4 [new file with mode: 0755]
src/tests/rename5.c [new file with mode: 0644]
src/tests/rename6.c [new file with mode: 0644]
src/tests/rewrite-emacs [new file with mode: 0755]
src/tests/rm-rf.c [new file with mode: 0644]
src/tests/run-fsx [new file with mode: 0755]
src/tests/run-rcs [new file with mode: 0755]
src/tests/run-tests.in [new file with mode: 0755]
src/tests/setgroups [new file with mode: 0755]
src/tests/setpag [new file with mode: 0755]
src/tests/shallow-tree [new file with mode: 0644]
src/tests/still-there-p.c [new file with mode: 0644]
src/tests/strange-characters [new file with mode: 0755]
src/tests/strange-characters-c.c [new file with mode: 0644]
src/tests/strange-other-characters [new file with mode: 0644]
src/tests/symlink.c [new file with mode: 0644]
src/tests/t.uniq-bad [new file with mode: 0644]
src/tests/test-gunzip-gnu-mirror [new file with mode: 0755]
src/tests/test-parallel1.c [new file with mode: 0644]
src/tests/test-parallel2.c [new file with mode: 0644]
src/tests/test-setgroups.c [new file with mode: 0644]
src/tests/test-setpag.c [new file with mode: 0644]
src/tests/too-many-files [new file with mode: 0644]
src/tests/touch1 [new file with mode: 0755]
src/tests/truncate-files.c [new file with mode: 0644]
src/tests/truncate.c [new file with mode: 0644]
src/tests/untar-emacs [new file with mode: 0755]
src/tests/untar-openafs [new file with mode: 0755]
src/tests/util.pm [new file with mode: 0644]
src/tests/utime-dir.c [new file with mode: 0644]
src/tests/utime-file.c [new file with mode: 0644]
src/tests/visit-volumes [new file with mode: 0644]
src/tests/vos.pm [new file with mode: 0644]
src/tests/vosaddsite.pl [new file with mode: 0755]
src/tests/vosbackup.pl [new file with mode: 0755]
src/tests/voscreate.pl [new file with mode: 0755]
src/tests/vosdelentry.pl [new file with mode: 0755]
src/tests/vosdump.pl [new file with mode: 0755]
src/tests/vosexamine.pl [new file with mode: 0755]
src/tests/voslistpart.pl [new file with mode: 0755]
src/tests/voslistvldb.pl [new file with mode: 0755]
src/tests/voslistvol.pl [new file with mode: 0755]
src/tests/voslock.pl [new file with mode: 0755]
src/tests/vosmove.pl [new file with mode: 0755]
src/tests/vospartinfo.pl [new file with mode: 0755]
src/tests/vosrelease.pl [new file with mode: 0755]
src/tests/vosremove.pl [new file with mode: 0755]
src/tests/vosremsite.pl [new file with mode: 0755]
src/tests/vosrename.pl [new file with mode: 0755]
src/tests/vosrestore.pl [new file with mode: 0755]
src/tests/vossyncserv.pl [new file with mode: 0755]
src/tests/vossyncvldb.pl [new file with mode: 0755]
src/tests/vosunlock.pl [new file with mode: 0755]
src/tests/vosunlockall.pl [new file with mode: 0755]
src/tests/voszap.pl [new file with mode: 0755]
src/tests/warn.c [new file with mode: 0644]
src/tests/warnx.c [new file with mode: 0644]
src/tests/wrapper.pm [new file with mode: 0644]
src/tests/write-closed.c [new file with mode: 0644]
src/tests/write-closed2.c [new file with mode: 0644]
src/tests/write-large.c [new file with mode: 0644]
src/tests/write-rand.c [new file with mode: 0644]
src/tests/write-ro [new file with mode: 0755]
src/tests/write-ro-file.c [new file with mode: 0644]
src/tests/write-ucc.c [new file with mode: 0644]
src/tests/write1 [new file with mode: 0755]
src/tests/write2 [new file with mode: 0755]
src/tests/write3.c [new file with mode: 0644]

index 0d87d6b..364456e 100644 (file)
@@ -90,6 +90,9 @@ build_dirs_rx:
 
 project: cmd comerr 
 
+tests: all 
+       ${COMPILE_PART1} tests ${COMPILE_PART2}
+
 config: 
        ${COMPILE_PART1} config ${COMPILE_PART2}
 
index 1f4b000..10615e2 100644 (file)
@@ -105,6 +105,8 @@ src/sgistuff/Makefile \
 src/sia/Makefile \
 src/sys/Makefile \
 src/tbutc/Makefile \
+src/tests/Makefile \
+src/tests/Dirpath.pm \
 src/tools/Makefile \
 src/tsm41/Makefile \
 src/tviced/Makefile \
diff --git a/src/tests/Auth-Heimdal.pm b/src/tests/Auth-Heimdal.pm
new file mode 100644 (file)
index 0000000..f578c82
--- /dev/null
@@ -0,0 +1,44 @@
+# This is -*- perl -*-
+
+package OpenAFS::Auth;
+use OpenAFS::Dirpath;
+
+use strict;
+#use vars qw( @ISA @EXPORT );
+#@ISA = qw(Exporter);
+#require Exporter;
+#@EXPORT = qw($openafs-authadmin $openafs-authuser);
+
+sub getcell {
+    my($cell);
+    open(CELL, "$openafsdirpath->{'afsconfdir'}/ThisCell") 
+       or die "Cannot open $openafsdirpath->{'afsconfdir'}/ThisCell: $!\n";
+    $cell = <CELL>;
+    chomp $cell;
+    close CELL;
+    return $cell;
+}
+
+sub getrealm {
+    my($cell);
+    open(CELL, "$openafsdirpath->{'afsconfdir'}/ThisCell") 
+       or die "Cannot open $openafsdirpath->{'afsconfdir'}/ThisCell: $!\n";
+    $cell = <CELL>;
+    chomp $cell;
+    close CELL;
+    $cell =~ tr/a-z/A-Z/;
+    return $cell;
+}
+
+sub authadmin {
+    my $cell = &getrealm;
+    my $cmd = "kinit -k -t /usr/afs/etc/krb5.keytab admin\@${cell} ; afslog";
+    system($cmd);
+}
+sub authuser {
+    my $cell = &getrealm;
+    my $cmd = "kinit -k -t /usr/afs/etc/krb5.keytab user\@${cell} ; afslog";
+    system($cmd);
+}
+
+1;
diff --git a/src/tests/CMU_copyright.pm b/src/tests/CMU_copyright.pm
new file mode 100644 (file)
index 0000000..8b3b5a0
--- /dev/null
@@ -0,0 +1,33 @@
+## CMUCS AFStools
+## Copyright (c) 1996, 2001 Carnegie Mellon University
+## All Rights Reserved.
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+#  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+#  School of Computer Science
+#  Carnegie Mellon University
+#  Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie Mellon
+# the rights to redistribute these changes.
+#
+# CMU_copyright.pm - CMU copyright
+# This isn't a real package; it merely provides a central location to keep
+# information regarding redistribution of this set of modules, and to make
+# sure that no one can use the modules (at least, as shipped) without also
+# having a copy of these terms.
+
+package AFS::CMU_copyright;
+
+1;
diff --git a/src/tests/ConfigUtils.pm b/src/tests/ConfigUtils.pm
new file mode 100644 (file)
index 0000000..ca56d60
--- /dev/null
@@ -0,0 +1,26 @@
+# This is -*- perl -*-
+
+package OpenAFS::ConfigUtils;
+
+use strict;
+use vars qw( @ISA @EXPORT @unwinds);
+@ISA = qw(Exporter);
+require Exporter;
+@EXPORT = qw(@unwinds run unwind);
+
+sub run ($) {
+  print join(' ', @_);
+  print "\n";
+  system (@_)  == 0
+    or die "Failed: $?\n";
+}
+
+# This subroutine takes a command to run in case of failure.  After
+# each succesful step, this routine should be run with a command to
+# undo the successful step.
+
+        sub unwind($) {
+          push @unwinds, $_[0];
+        }
+
+1;
diff --git a/src/tests/Dirpath.pm.in b/src/tests/Dirpath.pm.in
new file mode 100644 (file)
index 0000000..32c001c
--- /dev/null
@@ -0,0 +1,25 @@
+# This is -*- perl -*-
+
+package OpenAFS::Dirpath;
+
+use strict;
+use vars qw( @ISA @EXPORT $openafsdirpath);
+@ISA = qw(Exporter);
+require Exporter;
+@EXPORT = qw($openafsdirpath);
+
+# Dirpath configuration
+$openafsdirpath = {
+        'afsconfdir'       => '@afsconfdir@',
+        'viceetcdir'       => '@viceetcdir@',
+       'afssrvbindir'     => '@afssrvbindir@',
+       'afssrvsbindir'    => '@afssrvsbindir@',
+       'afssrvlibexecdir' => '@afssrvlibexecdir@',
+       'afsdbdir'         => '@afsdbdir@',
+       'afslogsdir'       => '@afslogsdir@',
+       'afslocaldir'      => '@afslocaldir@',
+       'afsbackupdir'     => '@afsbackupdir@',
+       'afsbosconfigdir'  => '@afsbosconfigdir@'
+};
+
+1;
diff --git a/src/tests/Makefile b/src/tests/Makefile
new file mode 100644 (file)
index 0000000..0ab6df3
--- /dev/null
@@ -0,0 +1,284 @@
+# Generated automatically from Makefile.in by configure.
+srcdir         = .
+include /usr/src/openafs/openafs/src/config/Makefile.config
+
+SHELL          = /bin/sh
+
+CFLAGS         = -I. -I${srcdir} ${DBG} ${OPTMZ} -I${TOP_OBJDIR}/src/config -I${TOP_INCDIR} ${XCFLAGS}
+LDFLAGS=${DBG} ${OPTMZ} ${XLDFLAGS}
+
+SYS_LIBS       = ${TOP_LIBDIR}/libsys.a ${TOP_LIBDIR}/librx.a ${TOP_LIBDIR}/liblwp.a ${TOP_LIBDIR}/util.a
+
+AUTH_LIBS      = ${TOP_LIBDIR}/libauth.a ${SYS_LIBS}
+
+INT_LIBS       = ${TOP_LIBDIR}/libafsint.a ${TOP_LIBDIR}/libsys.a ${TOP_LIBDIR}/librxkad.a ${TOP_LIBDIR}/librx.a ${TOP_LIBDIR}/liblwp.a ${TOP_LIBDIR}/libcom_err.a ${TOP_LIBDIR}/util.a 
+
+TEST_PROGRAMS = write-ro-file hello-world read-vs-mmap read-vs-mmap2    \
+               mmap-and-read large-dir large-dir2 large-dir3 mountpoint \
+               test-setgroups test-setpag hardlink1 hardlink2 mkdir2    \
+               create-files create-symlinks create-dirs dup2-and-unlog  \
+               readdir-vs-lstat read-write create-remove mkdir3         \
+               symlink echo-n test-parallel1 test-parallel2 create-stat \
+               kill-softly kill-softer rm-rf exit-wo-close              \
+               mmap-vs-read mmap-vs-read2 strange-characters-c pine     \
+               append-over-page write-ucc utime-dir mmap-shared-write   \
+               rename5 rename-under-feet write-closed write-closed2     \
+               truncate fchmod make-page utime-file rename6             \
+               write3 still-there-p write-large afscp hardlink4         \
+               intr-read asu truncate-files mmap-cat blocks-new-file    \
+               fsx write-rand
+
+TEST_OBJS     = write-ro-file.o read-vs-mmap.o read-vs-mmap2.o            \
+               mmap-and-read.o large-dir.o large-dir2.o large-dir3.o      \
+               test-setgroups.o test-setpag.o hardlink1.o hardlink2.o     \
+               mkdir2.o create-files.o create-symlinks.o create-dirs.o    \
+               dup2-and-unlog.o readdir-vs-lstat.o read-write.o           \
+               create-remove.o symlink.o echo-n.o test-parallel1.o        \
+               test-parallel1.o mkdir3.o rename6.o                        \
+               create-stat.o kill-softly.o kill-softer.o rm-rf.o          \
+               exit-wo-close.o mmap-vs-read.o mmap-vs-read2.o             \
+               strange-characters-c.o pine.o append-over-page.o           \
+               write-ucc.o utime-dir.o mmap-shared-write.o rename5.o      \
+               rename-under-feet.o write-closed.o write-closed2.o         \
+               truncate.o fchmod.o make-page.o utime-file.o               \
+               write3.o still-there-p.o write-large.o hardlink4.o         \
+               intr-read.o asu.o truncate-files.o mmap-cat.o              \
+               blocks-new-file.o fsx.o afscp.o afscp_callback.o           \
+               write-rand.o
+
+TEST_SRCS     = write-ro-file.c read-vs-mmap.c read-vs-mmap2.c            \
+               mmap-and-read.c large-dir.c large-dir2.c large-dir3.c      \
+               test-setgroups.c test-setpag.c hardlink1.c hardlink2.c     \
+               mkdir2.c create-files.c create-symlinks.c create-dirs.c    \
+               dup2-and-unlog.c readdir-vs-lstat.c read-write.c           \
+               create-remove.c symlink.c echo-n.c test-parallel1.c        \
+               test-parallel2.c mkdir3.c rename6.c                        \
+               create-stat.c kill-softly.c kill-softer.c rm-rf.c          \
+               exit-wo-close.c mmap-vs-read.c mmap-vs-read2.c             \
+               strange-characters-c.c pine.c append-over-page.c           \
+               write-ucc.c utime-dir.c mmap-shared-write.c rename5.c      \
+               rename-under-feet.c write-closed.c write-closed2.c         \
+               truncate.c fchmod.c make-page.c utime-file.c               \
+               write3.c still-there-p.c write-large.c hardlink4.c         \
+               intr-read.c asu.c truncate-files.c mmap-cat.c              \
+               blocks-new-file.c fsx.c afscp.c afscp_callback.c           \
+               write-rand.c
+
+EXTRA_OBJS = err.o errx.o warn.o warnx.o
+
+all: run-tests $(TEST_PROGRAMS) OS.pm
+
+OS.pm: OS-$(MKAFS_OSTYPE).pm
+       $(CP) OS-$(MKAFS_OSTYPE).pm OS.pm
+
+write-rand: write-rand.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-rand.o $(EXTRA_OBJS) $(LIBS)
+
+write-ro-file: write-ro-file.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-ro-file.o $(EXTRA_OBJS) $(LIBS)
+
+write-large: write-large.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-large.o $(EXTRA_OBJS) $(LIBS)
+
+read-vs-mmap: read-vs-mmap.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ read-vs-mmap.o $(EXTRA_OBJS) $(LIBS)
+
+read-vs-mmap2: read-vs-mmap2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ read-vs-mmap2.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-vs-read: mmap-vs-read.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-vs-read.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-vs-read2: mmap-vs-read2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-vs-read2.o $(EXTRA_OBJS) $(LIBS)
+
+read-write: read-write.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ read-write.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-and-read: mmap-and-read.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-and-read.o $(EXTRA_OBJS) $(LIBS)
+
+large-dir: large-dir.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ large-dir.o $(EXTRA_OBJS) $(LIBS)
+
+large-dir2: large-dir2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ large-dir2.o $(EXTRA_OBJS) $(LIBS)
+
+large-dir3: large-dir3.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ large-dir3.o $(EXTRA_OBJS) $(LIBS)
+
+fchmod: fchmod.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ fchmod.o $(EXTRA_OBJS) $(LIBS)
+
+truncate: truncate.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ truncate.o $(EXTRA_OBJS) $(LIBS)
+
+make-page: make-page.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ make-page.o $(EXTRA_OBJS) $(LIBS)
+
+still-there-p: still-there-p.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ still-there-p.o $(EXTRA_OBJS) $(LIBS)
+
+intr-read: intr-read.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ intr-read.o $(EXTRA_OBJS) $(LIBS)
+
+blocks-new-file: blocks-new-file.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ blocks-new-file.o $(EXTRA_OBJS) $(LIBS)
+
+asu: asu.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ asu.o $(EXTRA_OBJS) $(LIBS)
+
+test-setgroups: test-setgroups.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ test-setgroups.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+test-setpag: test-setpag.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ test-setpag.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+hardlink1: hardlink1.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ hardlink1.o $(EXTRA_OBJS) $(LIBS)
+
+hardlink2: hardlink2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ hardlink2.o $(EXTRA_OBJS) $(LIBS)
+
+hardlink4: hardlink4.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ hardlink4.o $(EXTRA_OBJS) $(LIBS)
+
+mkdir2: mkdir2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mkdir2.o $(EXTRA_OBJS) $(LIBS)
+
+mkdir3: mkdir3.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mkdir3.o $(EXTRA_OBJS) $(LIBS)
+
+create-files: create-files.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-files.o $(EXTRA_OBJS) $(LIBS)
+
+create-symlinks: create-symlinks.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-symlinks.o $(EXTRA_OBJS) $(LIBS)
+
+create-dirs: create-dirs.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-dirs.o $(EXTRA_OBJS) $(LIBS)
+
+create-remove: create-remove.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-remove.o $(EXTRA_OBJS) $(LIBS)
+
+dup2-and-unlog: dup2-and-unlog.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ dup2-and-unlog.o  $(EXTRA_OBJS) $(AUTH_LIBS) $(LIBS)
+
+readdir-vs-lstat: readdir-vs-lstat.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ readdir-vs-lstat.o $(EXTRA_OBJS) $(LIBS)
+
+symlink: symlink.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ symlink.o $(EXTRA_OBJS) $(LIBS)
+
+echo-n: echo-n.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ echo-n.o $(EXTRA_OBJS)
+
+test-parallel1: test-parallel1.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ test-parallel1.o $(EXTRA_OBJS) $(LIBS)
+
+test-parallel2: test-parallel2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ test-parallel2.o $(EXTRA_OBJS) $(LIBS)
+
+create-stat: create-stat.o fs_lib.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-stat.o fs_lib.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+kill-softly: kill-softly.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ kill-softly.o $(EXTRA_OBJS) $(LIBS)
+
+kill-softer: kill-softer.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ kill-softer.o $(EXTRA_OBJS) $(LIBS)
+
+rm-rf: rm-rf.o fs_lib.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ rm-rf.o fs_lib.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+exit-wo-close: exit-wo-close.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ exit-wo-close.o $(EXTRA_OBJS) $(LIBS)
+
+strange-characters-c: strange-characters-c.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ strange-characters-c.o $(EXTRA_OBJS) $(LIBS)
+
+pine: pine.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ pine.o $(EXTRA_OBJS) $(LIBS)
+
+append-over-page: append-over-page.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ append-over-page.o $(EXTRA_OBJS) $(LIBS)
+
+write-ucc: write-ucc.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-ucc.o $(EXTRA_OBJS) $(LIBS)
+
+utime-dir: utime-dir.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ utime-dir.o $(EXTRA_OBJS) $(LIBS)
+
+utime-file: utime-file.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ utime-file.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-shared-write: mmap-shared-write.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-shared-write.o $(EXTRA_OBJS) $(LIBS)
+
+rename5: rename5.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ rename5.o $(EXTRA_OBJS) $(LIBS)
+
+rename6: rename6.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ rename6.o $(EXTRA_OBJS) $(LIBS)
+
+write3: write3.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write3.o $(EXTRA_OBJS) $(LIBS)
+
+rename-under-feet: rename-under-feet.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ rename-under-feet.o $(EXTRA_OBJS) $(LIBS)
+
+write-closed: write-closed.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-closed.o $(EXTRA_OBJS) $(LIBS)
+
+write-closed2: write-closed2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-closed2.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+truncate-files: truncate-files.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ truncate-files.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-cat: mmap-cat.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-cat.o $(EXTRA_OBJS) $(LIBS)
+
+run-tests: run-tests.in
+       (cd ..; CONFIG_FILES=tests/run-tests CONFIG_HEADERS= $(SHELL) /usr/src/openafs/openafs/config.status)
+       @chmod +x run-tests
+
+#.c.o:
+#      $(CC) -c $(CPPFLAGS) $(DEFS) -I$(srcdir) -I. $(REALCFLAGS) $<
+
+afscp: afscp.o afscp_callback.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ afscp.o afscp_callback.o $(EXTRA_OBJS) $(INT_LIBS)
+
+hello-world:   hello-world.in
+       sed -e "s!%CC%!$(CC)!" $(srcdir)/hello-world.in > $@
+       chmod +x hello-world
+
+mountpoint:   mountpoint.in
+       sed -e "s!%bindir%!$(bindir)!" $(srcdir)/mountpoint.in > $@
+       chmod +x mountpoint
+
+clean:
+       rm -f run-tests $(TEST_PROGRAMS) *.o *~
+
+realclean:
+
+distclean: clean
+       rm -f Makefile
+
+mostlyclean:
+
+install:
+
+uninstall:
+
+
+TAGS:  $(TEST_SRCS)
+       etags $(TEST_SRCS)
+
+check: run-tests $(TEST_PROGRAMS)
+       ./run-tests -all
+
+check-fast: run-tests $(TEST_PROGRAMS)
+       ./run-tests -all -fast
+
+.PHONY:                all install clean realclean distclean mostlyclean install uninstall check
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
new file mode 100644 (file)
index 0000000..b402189
--- /dev/null
@@ -0,0 +1,276 @@
+srcdir         = @srcdir@
+include @TOP_OBJDIR@/src/config/Makefile.config
+
+SHELL          = /bin/sh
+
+CFLAGS         = -I. -I${srcdir} ${DBG} ${OPTMZ} -I${TOP_OBJDIR}/src/config -I${TOP_INCDIR} ${XCFLAGS}
+LDFLAGS=${DBG} ${OPTMZ} ${XLDFLAGS}
+
+SYS_LIBS       = ${TOP_LIBDIR}/libsys.a ${TOP_LIBDIR}/librx.a ${TOP_LIBDIR}/liblwp.a ${TOP_LIBDIR}/util.a
+
+AUTH_LIBS      = ${TOP_LIBDIR}/libauth.a ${SYS_LIBS}
+
+INT_LIBS       = ${TOP_LIBDIR}/libafsint.a ${TOP_LIBDIR}/libsys.a ${TOP_LIBDIR}/librxkad.a ${TOP_LIBDIR}/librx.a ${TOP_LIBDIR}/liblwp.a ${TOP_LIBDIR}/libcom_err.a ${TOP_LIBDIR}/util.a 
+
+TEST_PROGRAMS = write-ro-file hello-world read-vs-mmap read-vs-mmap2    \
+               mmap-and-read large-dir large-dir2 large-dir3 mountpoint \
+               test-setgroups test-setpag hardlink1 hardlink2 mkdir2    \
+               create-files create-symlinks create-dirs dup2-and-unlog  \
+               readdir-vs-lstat read-write create-remove mkdir3         \
+               symlink echo-n test-parallel1 test-parallel2 create-stat \
+               kill-softly kill-softer rm-rf exit-wo-close              \
+               mmap-vs-read mmap-vs-read2 strange-characters-c pine     \
+               append-over-page write-ucc utime-dir mmap-shared-write   \
+               rename5 rename-under-feet write-closed write-closed2     \
+               truncate fchmod make-page utime-file rename6             \
+               write3 still-there-p write-large afscp hardlink4         \
+               intr-read asu truncate-files mmap-cat blocks-new-file    \
+               fsx write-rand
+
+TEST_OBJS     = write-ro-file.o read-vs-mmap.o read-vs-mmap2.o            \
+               mmap-and-read.o large-dir.o large-dir2.o large-dir3.o      \
+               test-setgroups.o test-setpag.o hardlink1.o hardlink2.o     \
+               mkdir2.o create-files.o create-symlinks.o create-dirs.o    \
+               dup2-and-unlog.o readdir-vs-lstat.o read-write.o           \
+               create-remove.o symlink.o echo-n.o test-parallel1.o        \
+               test-parallel1.o mkdir3.o rename6.o                        \
+               create-stat.o kill-softly.o kill-softer.o rm-rf.o          \
+               exit-wo-close.o mmap-vs-read.o mmap-vs-read2.o             \
+               strange-characters-c.o pine.o append-over-page.o           \
+               write-ucc.o utime-dir.o mmap-shared-write.o rename5.o      \
+               rename-under-feet.o write-closed.o write-closed2.o         \
+               truncate.o fchmod.o make-page.o utime-file.o               \
+               write3.o still-there-p.o write-large.o hardlink4.o         \
+               intr-read.o asu.o truncate-files.o mmap-cat.o              \
+               blocks-new-file.o fsx.o afscp.o afscp_callback.o           \
+               write-rand.o
+
+TEST_SRCS     = write-ro-file.c read-vs-mmap.c read-vs-mmap2.c            \
+               mmap-and-read.c large-dir.c large-dir2.c large-dir3.c      \
+               test-setgroups.c test-setpag.c hardlink1.c hardlink2.c     \
+               mkdir2.c create-files.c create-symlinks.c create-dirs.c    \
+               dup2-and-unlog.c readdir-vs-lstat.c read-write.c           \
+               create-remove.c symlink.c echo-n.c test-parallel1.c        \
+               test-parallel2.c mkdir3.c rename6.c                        \
+               create-stat.c kill-softly.c kill-softer.c rm-rf.c          \
+               exit-wo-close.c mmap-vs-read.c mmap-vs-read2.c             \
+               strange-characters-c.c pine.c append-over-page.c           \
+               write-ucc.c utime-dir.c mmap-shared-write.c rename5.c      \
+               rename-under-feet.c write-closed.c write-closed2.c         \
+               truncate.c fchmod.c make-page.c utime-file.c               \
+               write3.c still-there-p.c write-large.c hardlink4.c         \
+               intr-read.c asu.c truncate-files.c mmap-cat.c              \
+               blocks-new-file.c fsx.c afscp.c afscp_callback.c           \
+               write-rand.c
+
+EXTRA_OBJS = err.o errx.o warn.o warnx.o
+
+all: run-tests $(TEST_PROGRAMS) OS.pm
+
+OS.pm: OS-$(MKAFS_OSTYPE).pm
+       $(CP) OS-$(MKAFS_OSTYPE).pm OS.pm
+
+write-rand: write-rand.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-rand.o $(EXTRA_OBJS) $(LIBS)
+
+write-ro-file: write-ro-file.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-ro-file.o $(EXTRA_OBJS) $(LIBS)
+
+write-large: write-large.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-large.o $(EXTRA_OBJS) $(LIBS)
+
+read-vs-mmap: read-vs-mmap.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ read-vs-mmap.o $(EXTRA_OBJS) $(LIBS)
+
+read-vs-mmap2: read-vs-mmap2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ read-vs-mmap2.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-vs-read: mmap-vs-read.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-vs-read.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-vs-read2: mmap-vs-read2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-vs-read2.o $(EXTRA_OBJS) $(LIBS)
+
+read-write: read-write.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ read-write.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-and-read: mmap-and-read.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-and-read.o $(EXTRA_OBJS) $(LIBS)
+
+large-dir: large-dir.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ large-dir.o $(EXTRA_OBJS) $(LIBS)
+
+large-dir2: large-dir2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ large-dir2.o $(EXTRA_OBJS) $(LIBS)
+
+large-dir3: large-dir3.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ large-dir3.o $(EXTRA_OBJS) $(LIBS)
+
+fchmod: fchmod.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ fchmod.o $(EXTRA_OBJS) $(LIBS)
+
+truncate: truncate.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ truncate.o $(EXTRA_OBJS) $(LIBS)
+
+make-page: make-page.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ make-page.o $(EXTRA_OBJS) $(LIBS)
+
+still-there-p: still-there-p.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ still-there-p.o $(EXTRA_OBJS) $(LIBS)
+
+intr-read: intr-read.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ intr-read.o $(EXTRA_OBJS) $(LIBS)
+
+blocks-new-file: blocks-new-file.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ blocks-new-file.o $(EXTRA_OBJS) $(LIBS)
+
+asu: asu.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ asu.o $(EXTRA_OBJS) $(LIBS)
+
+test-setgroups: test-setgroups.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ test-setgroups.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+test-setpag: test-setpag.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ test-setpag.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+hardlink1: hardlink1.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ hardlink1.o $(EXTRA_OBJS) $(LIBS)
+
+hardlink2: hardlink2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ hardlink2.o $(EXTRA_OBJS) $(LIBS)
+
+hardlink4: hardlink4.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ hardlink4.o $(EXTRA_OBJS) $(LIBS)
+
+mkdir2: mkdir2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mkdir2.o $(EXTRA_OBJS) $(LIBS)
+
+mkdir3: mkdir3.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mkdir3.o $(EXTRA_OBJS) $(LIBS)
+
+create-files: create-files.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-files.o $(EXTRA_OBJS) $(LIBS)
+
+create-symlinks: create-symlinks.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-symlinks.o $(EXTRA_OBJS) $(LIBS)
+
+create-dirs: create-dirs.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-dirs.o $(EXTRA_OBJS) $(LIBS)
+
+create-remove: create-remove.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-remove.o $(EXTRA_OBJS) $(LIBS)
+
+dup2-and-unlog: dup2-and-unlog.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ dup2-and-unlog.o  $(EXTRA_OBJS) $(AUTH_LIBS) $(LIBS)
+
+readdir-vs-lstat: readdir-vs-lstat.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ readdir-vs-lstat.o $(EXTRA_OBJS) $(LIBS)
+
+symlink: symlink.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ symlink.o $(EXTRA_OBJS) $(LIBS)
+
+echo-n: echo-n.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ echo-n.o $(EXTRA_OBJS)
+
+test-parallel1: test-parallel1.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ test-parallel1.o $(EXTRA_OBJS) $(LIBS)
+
+test-parallel2: test-parallel2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ test-parallel2.o $(EXTRA_OBJS) $(LIBS)
+
+create-stat: create-stat.o fs_lib.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ create-stat.o fs_lib.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+kill-softly: kill-softly.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ kill-softly.o $(EXTRA_OBJS) $(LIBS)
+
+kill-softer: kill-softer.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ kill-softer.o $(EXTRA_OBJS) $(LIBS)
+
+rm-rf: rm-rf.o fs_lib.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ rm-rf.o fs_lib.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+exit-wo-close: exit-wo-close.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ exit-wo-close.o $(EXTRA_OBJS) $(LIBS)
+
+strange-characters-c: strange-characters-c.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ strange-characters-c.o $(EXTRA_OBJS) $(LIBS)
+
+pine: pine.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ pine.o $(EXTRA_OBJS) $(LIBS)
+
+append-over-page: append-over-page.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ append-over-page.o $(EXTRA_OBJS) $(LIBS)
+
+write-ucc: write-ucc.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-ucc.o $(EXTRA_OBJS) $(LIBS)
+
+utime-dir: utime-dir.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ utime-dir.o $(EXTRA_OBJS) $(LIBS)
+
+utime-file: utime-file.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ utime-file.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-shared-write: mmap-shared-write.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-shared-write.o $(EXTRA_OBJS) $(LIBS)
+
+rename5: rename5.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ rename5.o $(EXTRA_OBJS) $(LIBS)
+
+rename6: rename6.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ rename6.o $(EXTRA_OBJS) $(LIBS)
+
+write3: write3.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write3.o $(EXTRA_OBJS) $(LIBS)
+
+rename-under-feet: rename-under-feet.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ rename-under-feet.o $(EXTRA_OBJS) $(LIBS)
+
+write-closed: write-closed.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-closed.o $(EXTRA_OBJS) $(LIBS)
+
+write-closed2: write-closed2.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ write-closed2.o $(EXTRA_OBJS) $(SYS_LIBS) $(LIBS)
+
+truncate-files: truncate-files.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ truncate-files.o $(EXTRA_OBJS) $(LIBS)
+
+mmap-cat: mmap-cat.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ mmap-cat.o $(EXTRA_OBJS) $(LIBS)
+
+run-tests: run-tests.in
+       (cd ..; CONFIG_FILES=tests/run-tests CONFIG_HEADERS= $(SHELL) @TOP_OBJDIR@/config.status)
+       @chmod +x run-tests
+
+#.c.o:
+#      $(CC) -c $(CPPFLAGS) $(DEFS) -I$(srcdir) -I. $(REALCFLAGS) $<
+
+afscp: afscp.o afscp_callback.o $(EXTRA_OBJS)
+       $(CC) $(LDFLAGS) -o $@ afscp.o afscp_callback.o $(EXTRA_OBJS) $(INT_LIBS)
+
+hello-world:   hello-world.in
+       sed -e "s!%CC%!$(CC)!" $(srcdir)/hello-world.in > $@
+       chmod +x hello-world
+
+mountpoint:   mountpoint.in
+       sed -e "s!%bindir%!$(bindir)!" $(srcdir)/mountpoint.in > $@
+       chmod +x mountpoint
+
+clean:
+       rm -f run-tests $(TEST_PROGRAMS) *.o *~ OS.pm
+
+install:
+
+uninstall:
+
+
+TAGS:  $(TEST_SRCS)
+       etags $(TEST_SRCS)
+
+check: run-tests $(TEST_PROGRAMS)
+       ./run-tests -all
+
+check-fast: run-tests $(TEST_PROGRAMS)
+       ./run-tests -all -fast
+
+.PHONY:                all install clean realclean distclean mostlyclean install uninstall check
diff --git a/src/tests/OS-LINUX.pm b/src/tests/OS-LINUX.pm
new file mode 100644 (file)
index 0000000..70c7d38
--- /dev/null
@@ -0,0 +1,23 @@
+# This is -*- perl -*-
+
+package OpenAFS::OS;
+
+use strict;
+use vars qw( @ISA @EXPORT $openafsinitcmd);
+@ISA = qw(Exporter);
+require Exporter;
+@EXPORT = qw($openafsinitcmd);
+
+# OS-specific configuration
+$openafsinitcmd = {
+        'client-start'      => '/etc/init.d/openafs-client start',
+        'client-stop'       => '/etc/init.d/openafs-client stop',
+       'client-forcestart' => '/etc/init.d/openafs-client force-start',
+        'client-restart'    => '/etc/init.d/openafs-client restart',
+       'filesrv-start'     => '/etc/init.d/openafs-fileserver start',
+       'filesrv-stop'      => '/etc/init.d/openafs-fileserver stop',
+       'filesrv-forcestart'=> '/etc/init.d/openafs-fileserver force-start',
+       'filesrv-restart'   => '/etc/init.d/openafs-fileserver restart',
+};
+
+1;
diff --git a/src/tests/OS-SOLARIS.pm b/src/tests/OS-SOLARIS.pm
new file mode 100644 (file)
index 0000000..3ba2645
--- /dev/null
@@ -0,0 +1,23 @@
+# This is -*- perl -*-
+
+package OpenAFS::OS;
+
+use strict;
+use vars qw( @ISA @EXPORT $openafsinitcmd);
+@ISA = qw(Exporter);
+require Exporter;
+@EXPORT = qw($openafsinitcmd);
+
+# OS-specific configuration
+$openafsinitcmd = {
+        'client-start'      => 'modload /usr/vice/etc/modload/libafs.nonfs.o; /usr/vice/etc/afsd -nosettime',
+        'client-stop'       => 'echo Solaris client cannot be stopped',
+       'client-forcestart' => 'modload /usr/vice/etc/modload/libafs.nonfs.o; /usr/vice/etc/afsd -nosettime',
+        'client-restart'    => 'echo Solaris client cannot be restarted',
+       'filesrv-start'     => '/usr/afs/bin/bosserver',
+       'filesrv-stop'      => '/usr/afs/bin/bos shutdown localhost -local -wait; pkill /usr/afs/bin/bosserver',
+       'filesrv-forcestart'=> '/usr/afs/bin/bosserver',
+       'filesrv-restart'   => '/usr/afs/bin/bos shutdown localhost -local -wait; pkill /usr/afs/bin/bosserver; sleep 1; /usr/afs/bin/bosserver',
+};
+
+1;
diff --git a/src/tests/README b/src/tests/README
new file mode 100644 (file)
index 0000000..49d10ba
--- /dev/null
@@ -0,0 +1,239 @@
+AFS verification suite
+14 Jan 2002
+
+Prerequisites
+
+1) A Kerberos KDC should already be configured 
+2) An afs key should be in the KeyFile the AFS binaries will use
+   (/usr/afs/etc/KeyFile in an IBM-style installation; bos_util can be used
+    to set it up)
+3) 2 srvtabs or keytabs with user keys, one for the user "admin"
+   and one for the user "user" that can be used for authenticated testing 
+   of the AFS installation
+4) The necessary tools for getting an AFS token from the installed Kerberos
+   (typically aklog) should be available.
+5) Ability to run as root on the "test" node.
+6) If the AFS to be tested is not OpenAFS, pt_util from OpenAFS should be
+   built and installed.
+7) Volume dump test tools included in new versions of OpenAFS.
+8) The "test" node should have partitions mounted as /vicepa and /vicepb
+9) perl5
+10) wget (should be configurable to use curl; what else?)
+
+(*) This is not yet true but will be by the time the suite is delivered.
+
+Setup
+1) Scripts provided bootstrap and populate a "test cell". (afs-newcell)
+
+Tests
+
+A) Simple tests
+10) Create a file. (creat1)
+20) Create a directory. (mkdir1/mkdir2)
+30) Create a symlink. (symlink)
+40) Create a in-same-directory hardlink. (hardlink1)
+50) Create a hardlink to a different-directory-same-volume file. (hardlink4)
+60) Create a hardlink to a directory. (hardlink2)
+70) Create a cross-volume hardlink. (hardlink5)
+80) Touch a file. (touch1)
+90) Write a simple file. (write1)
+100) Rewrite a file. (write3)
+110) Rename a file. (rename1)
+
+B) Basic functionality
+10) Stat multiple hardlinked files. (hardlink3)
+20) Write, truncate, rewrite a file. (write2)
+30) Append to a file. (append1)
+40) Rename a file over another file. (rename2)
+50) Rename a file into a same-volume directory. (rename4)
+60) Rename a file into another-volume directory. (rename6)
+70) Rename an open directory. (rename-under-feet)
+80) Create a file with a large filename. (large-filename)
+90) Chmod a file by descriptor. (fchmod)
+100) Utimes a file. (utime-file)
+110) Utimes a directory. (utime-dir)
+120) Test directory "link count" increasing/decreasing appropriately. (mkdir3)
+
+C) Mountpoint tests
+10) Create and remove a good mountpoint. (mkm-rmm)
+20) Create a mountpoint to a nonexistant volume. (mountpoint)
+
+D) ACL tests
+10) Add a valid PTS user to an ACL. (acladduser)
+20) Add a valid PTS group to an ACL. (acladdgroup)
+30) Add ACL rights for a PTS user. (acladdrights)
+40) Add negative ACL rights for a PTS user. (acladdnegrights)
+50) Clear negative ACL rights for a PTS user. (aclclearnegrights)
+60) Remove a valid PTS user from an ACL. (aclremoveuser)
+70) Remove a valid PTS group from an ACL. (aclremovegroup)
+80) Copy an ACL. (aclcopy)
+
+E) Executable tests
+10) Write and execute a script in a directory. (exec)
+20) Download and build http://www.openafs.org/dl/openafs/1.2.2/openafs-1.2.2-src.tar.gz, then run something from it. (build-openafs)
+
+F) mmap tests
+10) Append over a mapped page. (append-over-page)
+20) Write via mmap to a shared-mapped file. (mmap-shared-write)
+30) Compare a file being read via mmap private and read (mmap-vs-read2)
+40) Compare a file being read via mmap shared and read (mmap-vs-read)
+50) Compare a file being read via read and mmap shared (read-vs-mmap2)
+60) Compare a file being read via read and mmap private (read-vs-mmap)
+
+G) Filesystem Semantics tests
+10) Create a file with 8 bit characters in its name. (strange-characters)
+20) Test pine lockfile semantics. (pine)
+30) Create and remove a single file in parallel. (parallel1)
+40) Create a >2gb file (write-large)
+
+H) AFS behavior tests
+10) Write a file in a readonly volume. (write-ro)
+20) Create 31707 entries in a directory. (too-many-files)
+30) Test setpag(). (setpag)
+40) Test setgroups(). (setgroups)
+
+I) Remote operation tests
+10) Write a file locally and read it in a foreign cache manager. (extcopyin)
+20) Write a file in a foreign cache manager and read it locally. (extcopyout)
+
+K) Client abuse tests
+10) Write a file, read, rewrite and reread a file with the same open descriptor. (read-write)
+20) Populate and clean up a directory tree. (create-remove-files)
+30) FSX file system stresser (fsx)
+
+L) Fileserver tests
+
+M) Ptserver tests
+10) Create a user (ptscreateuser)
+20) Create a group (ptscreategroup)
+30) Add a user to a group (ptsadduser)
+40) Chown a group (ptschown)
+50) Get user membership (ptsmembersuser)
+60) Get group membership (ptsmembersgroup)
+70) Examine a user (ptsexamineuser)
+80) Examine a group (ptsexaminegroup)
+90) Remove a user from a group (ptsremove)
+100) List groups a user owns (ptslistown)
+100) Set maxuser (ptssetmax)
+110) List maxuser (ptslistmax)
+130) Set fields on a user (ptssetf)
+140) Delete a group (ptsdeletegroup)
+150) Delete a user (ptsdeleteuser)
+160) pt_util exercising (?)
+
+N) Volserver/vlserver tests
+10) Create a volume (voscreate)
+20) Move a volume (vosmove)
+30) Add a replication site (vosaddsite)
+40) Release a volume (vosrelease)
+50) Remove a replication site (vosremsite)
+70) Remove a volume (vosremove)
+80) Delete a VLDB entry (vosdelentry)
+90) Synchronize vldb to volumes (vossyncvldb)
+100) Zap a volume (voszap)
+110) Synchronize volumes to vldb (vossyncserv)
+120) Lock a VLDB entry (voslock)
+130) Unlock a VLDB entry (vosunlock)
+140) Unlock all VLDB entries after locking one or more (vosunlockall)
+150) Rename a volume. (vosrename)
+160) List all volumes on a partition. (voslistvol)
+170) List vldb (voslistvldb)
+180) Get partition info. (vospartinfo)
+190) List partitions (voslistpart)
+200) Backup a volume (vosbackup)
+210) Examine a volume (vosexamine)
+220) Dump a volume (vosdump)
+230) Restore a volume (vosrestore)
+240) Verify a volume dump (?)
+
+O) Bosserver tests
+10) Add a bosserver host (bosaddhost)
+20) List server hosts (bostlisthosts)
+30) Remove a server host (bosremovehost)
+40) Add a superuser (bosadduser)
+50) List superusers (boslistusers)
+60) Remove a superuser (bosremoveuser)
+70) Install an executable shell script (bosinstall)
+80) Execute something via the bosserver (bosexec)
+80) Create a bos bnode (boscreate)
+90) Delete a running bnode (bosdeleterunning)
+100) Get a bnode status (bosstatus)
+110) Stop a bos bnode (bosstop)
+120) Restart a bos bnode (bosrestartstopped)
+130) Start a bos bnode (bosstart)
+140) Shutdown a bnode (bosshutdown)
+150) Delete a stopped bnode (bosdelete)
+160) Add a key (bosaddkey)
+170) List keys (boslistkeys)
+180) Remove a key (bosremovekey)
+180) Salvage a volume (bossalvagevolume)
+190) Salvage a partition (bossalvagepart)
+200) Salvage a server (bossalvageserver)
+
+P) Regression
+10) Restore volume with a bad uniquifier in it, salvage, check. (?)
+20) Check for bad dentry caching on Linux taking advantage of last test. (?)
+30) Write a file larger than the cache. (fcachesize-write-file)
+40) Read a file larger than the cache. (fcachesize-read-file)
+
+---
+Copyright information
+
+The AFStools perl modules are:
+
+## Copyright (c) 1996, 2001 Carnegie Mellon University
+## All Rights Reserved.
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+#  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+#  School of Computer Science
+#  Carnegie Mellon University
+#  Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie Mellon
+# the rights to redistribute these changes.
+
+Some tests as noted are:
+/*
+ * Copyright (c) 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
diff --git a/src/tests/README.afstools b/src/tests/README.afstools
new file mode 100644 (file)
index 0000000..d9f5c7f
--- /dev/null
@@ -0,0 +1,2 @@
+This is a (potentially) modified verion of the AFSTools perl suite. 
+You should visit grand.central.org for the official version.
diff --git a/src/tests/acladdgroup.pl b/src/tests/acladdgroup.pl
new file mode 100755 (executable)
index 0000000..8259c6f
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($wscell, $path, @pos1, @pos2, @neg1, @neg2, $ret, @tmp, @tmp2, @tmp3, $found);
+&AFS_Init();
+$wscell = &AFS_fs_wscell();
+$found = 0;
+
+eval { &AFS_pts_creategroup(group1,,,); };
+$path = "/afs/${wscell}/service/acltest";
+mkdir $path, 0777;
+($pos1, $neg1) = &AFS_fs_getacl($path);
+$ret = &AFS_fs_setacl([$path],[["group1", "rl"]],,);
+($pos2, $neg2) = &AFS_fs_getacl($path);
+while ($ret = pop(@$pos2)) {
+    @tmp2=@$ret;
+    if ($tmp2[0] eq "group1") { 
+       $found++; 
+    } else { 
+       unshift @tmp, @$ret;
+    }
+}
+
+@tmp2=();
+while ($ret = pop(@$pos1)) {
+    unshift @tmp2, @$ret;
+}
+
+if ($found != 1) {
+    exit(1);
+}
+exit(0);
+
+
+
diff --git a/src/tests/acladdnegrights.pl b/src/tests/acladdnegrights.pl
new file mode 100755 (executable)
index 0000000..d18db57
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($wscell, $path, @pos1, @pos2, @neg1, @neg2, $ret, @tmp, @tmp2, @tmp3, $found);
+&AFS_Init();
+$wscell = &AFS_fs_wscell();
+$found = 0;
+
+eval { &AFS_pts_createuser(user1,,); };
+$path = "/afs/${wscell}/service/acltest";
+mkdir $path, 0777;
+($pos1, $neg1) = &AFS_fs_getacl($path);
+$ret = &AFS_fs_setacl([$path],[],[["user1", "rl"]],);
+($pos2, $neg2) = &AFS_fs_getacl($path);
+while ($ret = pop(@$neg2)) {
+    @tmp2=@$ret;
+    if ($tmp2[0] eq "user1") { 
+       $found++;
+    } else {
+       unshift @tmp, @$ret;
+    }
+}
+
+if ($found != 1) {
+    exit(1);
+}
+
+@tmp2=();
+while ($ret = pop(@$neg1)) {
+    unshift @tmp2, @$ret;
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/acladdrights.pl b/src/tests/acladdrights.pl
new file mode 100755 (executable)
index 0000000..a37a210
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($wscell, $path, @pos1, @pos2, @neg1, @neg2, $ret, @tmp, @tmp2, @tmp3, $found);
+&AFS_Init();
+$wscell = &AFS_fs_wscell();
+$found = 0;
+
+eval { &AFS_pts_createuser(user1,,); };
+$path = "/afs/${wscell}/service/acltest";
+mkdir $path, 0777;
+($pos1, $neg1) = &AFS_fs_getacl($path);
+$ret = &AFS_fs_setacl([$path],[["user1", "rlidw"]],,);
+($pos2, $neg2) = &AFS_fs_getacl($path);
+while ($ret = pop(@$pos2)) {
+    @tmp2=@$ret;
+    if ($tmp2[0] eq "user1") { 
+       if ($tmp2[1] ne "rlidw") {
+           exit (1);
+       }
+       $tmp2[1] = "rl";
+       unshift @tmp, @tmp2;
+    } else {
+       unshift @tmp, @$ret;
+    }
+}
+
+@tmp2=();
+while ($ret = pop(@$pos1)) {
+    unshift @tmp2, @$ret;
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/acladduser.pl b/src/tests/acladduser.pl
new file mode 100755 (executable)
index 0000000..7e29fa4
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($wscell, $path, @pos1, @pos2, @neg1, @neg2, $ret, @tmp, @tmp2, @tmp3, $found);
+&AFS_Init();
+$wscell = &AFS_fs_wscell();
+$found = 0;
+
+eval { &AFS_pts_createuser(user1,,); };
+$path = "/afs/${wscell}/service/acltest";
+mkdir $path, 0777;
+($pos1, $neg1) = &AFS_fs_getacl($path);
+$ret = &AFS_fs_setacl([$path],[["user1", "rl"]],,);
+($pos2, $neg2) = &AFS_fs_getacl($path);
+while ($ret = pop(@$pos2)) {
+    @tmp2=@$ret;
+    if ($tmp2[0] eq "user1") { 
+       $found++; 
+    } else { 
+       unshift @tmp, @$ret;
+    }
+}
+
+@tmp2=();
+while ($ret = pop(@$pos1)) {
+    unshift @tmp2, @$ret;
+}
+
+if ($found != 1) {
+    exit(1);
+}
+exit(0);
+
+
+
diff --git a/src/tests/aclclearnegrights.pl b/src/tests/aclclearnegrights.pl
new file mode 100755 (executable)
index 0000000..738001f
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($wscell, $path, @pos1, @pos2, @neg1, @neg2, $ret, @tmp, @tmp2, @tmp3, $found);
+&AFS_Init();
+$wscell = &AFS_fs_wscell();
+$found = 0;
+
+eval { &AFS_pts_createuser(user1,,); };
+$path = "/afs/${wscell}/service/acltest";
+mkdir $path, 0777;
+($pos1, $neg1) = &AFS_fs_getacl($path);
+$ret = &AFS_fs_setacl([$path],[],[["user1", "r"]],);
+($pos2, $neg2) = &AFS_fs_getacl($path);
+while ($ret = pop(@$neg2)) {
+    @tmp2=@$ret;
+    if ($tmp2[0] eq "user1") { 
+       if ($tmp2[1] ne "r") {
+           exit 1;
+       }
+       $tmp2[1] = "rl";
+       unshift @tmp, @tmp2;
+    } else {
+       unshift @tmp, @$ret;
+    }
+}
+
+@tmp2=();
+while ($ret = pop(@$neg1)) {
+    unshift @tmp2, @$ret;
+}
+
+if (@tmp != @tmp2) {
+    exit(1);
+}
+if (@pos1 != @pos2) {
+    exit(1);
+}
+exit(0);
+
+
+
diff --git a/src/tests/aclcopy.pl b/src/tests/aclcopy.pl
new file mode 100755 (executable)
index 0000000..dce2f54
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($wscell, $path, @pos1, @pos2, @neg1, @neg2, $ret, @tmp, @tmp2, @tmp3, $found, $path2);
+&AFS_Init();
+$wscell = &AFS_fs_wscell();
+$found = 0;
+
+eval { &AFS_pts_createuser(user1,,); };
+$path = "/afs/${wscell}/service/acltest";
+$path2 = "/afs/${wscell}/service/acltest2";
+mkdir $path, 0777;
+mkdir $path2, 0777;
+($pos1, $neg1) = &AFS_fs_getacl($path);
+$ret = &AFS_fs_copyacl($path,[$path2],1);
+($pos2, $neg2) = &AFS_fs_getacl($path2);
+if (@pos1 != @pos2) {
+    exit(1);
+}
+if (@neg1 != @neg2) {
+    exit(1);
+}
+exit(0);
+
+
+
diff --git a/src/tests/aclremovegroup.pl b/src/tests/aclremovegroup.pl
new file mode 100755 (executable)
index 0000000..65cb0f4
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($wscell, $path, @pos1, @pos2, @neg1, @neg2, $ret, @tmp, @tmp2, @tmp3, $found, $listref, $first);
+&AFS_Init();
+$wscell = &AFS_fs_wscell();
+$found = 0;
+$first = 0;
+
+$path = "/afs/${wscell}/service/acltest";
+mkdir $path, 0777;
+($pos1, $neg1) = &AFS_fs_getacl($path);
+$listref = "[ ";
+while ($ret = pop(@$pos1)) {
+    $first++;
+    @tmp2=@$ret;
+    if ($tmp2[0] eq "group1") { 
+       $found++; 
+    } else { 
+       unshift @tmp, @$ret;
+       if ($first == 0 ) {
+           $listref = $listref . "[ @tmp2 ]";
+       } else {
+           $listref = $listref . ", [ @tmp2 ]";
+       }
+    }
+}
+$listref = $listref . " ]";
+
+if ($found != 1) {
+    print "WARNING: Can't remove user not on ACL. This shouldn't happen.\n";
+    exit(1);
+}
+
+$ret = &AFS_fs_setacl([$path],$listref,,);
+($pos2, $neg2) = &AFS_fs_getacl($path);
+
+@tmp2=();
+while ($ret = pop(@$pos1)) {
+    unshift @tmp2, @$ret;
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/aclremoveuser.pl b/src/tests/aclremoveuser.pl
new file mode 100755 (executable)
index 0000000..9124c6d
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($wscell, $path, @pos1, @pos2, @neg1, @neg2, $ret, @tmp, @tmp2, @tmp3, $found, $listref, $first);
+&AFS_Init();
+$wscell = &AFS_fs_wscell();
+$found = 0;
+$first = 0;
+
+$path = "/afs/${wscell}/service/acltest";
+mkdir $path, 0777;
+($pos1, $neg1) = &AFS_fs_getacl($path);
+$listref = "[ ";
+while ($ret = pop(@$pos1)) {
+    $first++;
+    @tmp2=@$ret;
+    if ($tmp2[0] eq "user1") { 
+       $found++; 
+    } else { 
+       unshift @tmp, @$ret;
+       if ($first == 0 ) {
+           $listref = $listref . "[ @tmp2 ]";
+       } else {
+           $listref = $listref . ", [ @tmp2 ]";
+       }
+    }
+}
+$listref = $listref . " ]";
+
+if ($found != 1) {
+    print "WARNING: Can't remove user not on ACL. This shouldn't happen.\n";
+    exit(1);
+}
+
+$ret = &AFS_fs_setacl([$path],$listref,,);
+($pos2, $neg2) = &AFS_fs_getacl($path);
+
+@tmp2=();
+while ($ret = pop(@$pos1)) {
+    unshift @tmp2, @$ret;
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/afs-newcell.pl b/src/tests/afs-newcell.pl
new file mode 100755 (executable)
index 0000000..91a2428
--- /dev/null
@@ -0,0 +1,294 @@
+#!/usr/bin/env perl -w
+# Copyright (C) 2000 by Sam Hartman
+# This file may be copied either under the terms of the GNU GPL or the IBM Public License
+# either version 2 or later of the GPL or version 1.0 or later of the IPL.
+
+use Term::ReadLine;
+use strict;
+use OpenAFS::ConfigUtils;
+use OpenAFS::Dirpath;
+use OpenAFS::OS;
+use OpenAFS::Auth;
+use Getopt::Long;
+use vars qw($admin $server $cellname $cachesize $part
+          $requirements_met  $shutdown_needed $csdb);
+my $rl = new Term::ReadLine('afs-newcell');
+
+=head1  NAME
+
+   afs-newcell - Set up initial database server for AFS cell.
+
+=head1 SYNOPSIS
+
+B<afs-newcell> [B<--requirements-met>] [B<--admin> admin_user] [B<--cellname> cellname] [B<--cachesize> size] [B<--partition> partition-letter]
+
+=head1 DESCRIPTION
+
+
+This script sets up the initial AFS database and configures the first
+database/file server. It also sets up an AFS cell's root volumes.  It 
+assumes that you already have a fileserver and database servers.  The 
+fileserver should have an empty root.afs. This script creates root.cell, 
+user, service and populates root.afs.  
+
+The B<requirements-met> option specifies that the initial requirements
+have been met and that the script can proceed without displaying the
+initial banner or asking for confirmation.
+
+The B<admin> option specifies the name of the administrative user.
+This user will be given system:administrators and susers permission in
+the cell.
+
+The B<cellname> option specifies the name of the cell.
+
+The B<cachesize> option specifies the size of the AFS cache.
+
+=head1 AUTHOR
+
+Sam Hartman <hartmans@debian.org>
+
+=cut
+
+# main script
+
+# mkvol(volume, mount)
+sub mkvol($$) {
+    my ($vol, $mnt) = @_;
+    run("$openafsdirpath->{'afssrvsbindir'}/vos create $server $part $vol -localauth");
+    unwind("$openafsdirpath->{'afssrvsbindir'}/vos remove $server $part $vol -localauth");
+    run("$openafsdirpath->{'afssrvbindir'}/fs mkm $mnt $vol ");
+    run("$openafsdirpath->{'afssrvbindir'}/fs sa $mnt system:anyuser rl");
+}
+
+GetOptions (
+           "requirements-met" => \$requirements_met, 
+           "cellname=s" => \$cellname, 
+          "cachesize=s" => \$cachesize,
+           "partition=s" => \$part,
+           "admin=s" => \$admin);
+
+unless ($requirements_met) {
+  print <<eoreqs;
+                           Prerequisites
+
+In order to set up a new AFS cell, you must meet the following:
+
+1) You need a working Kerberos realm with Kerberos4 support.  You
+   should install Heimdal with Kth-kerberos compatibility or MIT
+   Kerberos5.
+
+2) You need to create the single-DES AFS key and load it into
+   $openafsdirpath->{'afsconfdir'}/KeyFile.  If your cell's name is the same as
+   your Kerberos realm then create a principal called afs.  Otherwise,
+   create a principal called afs/cellname in your realm.  The cell
+   name should be all lower case, unlike Kerberos realms which are all
+   upper case.  You can use asetkey from the openafs-krb5 package, or
+   if you used AFS3 salt to create the key, the bos addkey command.
+
+3) This machine should have a filesystem mounted on /vicepa.  If you
+   do not have a free partition, on Linux you can create a large file by using
+   dd to extract bytes from /dev/zero.  Create a filesystem on this file
+   and mount it using -oloop.  
+
+4) You will need an administrative principal created in a Kerberos
+   realm.  This principal will be added to susers and
+   system:administrators and thus will be able to run administrative
+   commands.  Generally the user is a root instance of some administravie
+   user.  For example if jruser is an administrator then it would be
+   reasonable to create jruser/root and specify jruser/root as the user
+   to be added in this script.
+
+5) The AFS client must not be running on this workstation.  It will be
+   at the end of this script.
+
+eoreqs
+
+  $_ = $rl->readline("Do you meet these requirements? [y/n] ");
+  unless (/^y/i ) {
+    print "Run this script again when you meet the requirements\n";
+    exit(1);
+  }
+       
+  if ($> != 0) {
+    die "This script should almost always be run as root.  Use the --requirements-met option to run as non-root.\n";
+  }
+}
+open(MOUNT, "mount |") or die "Failed to run mount: $!\n";
+while(<MOUNT>) {
+  if(m:^AFS:) {
+    print "The AFS client is currently running on this workstation.\n";
+    print "Please restart this script after running $openafsinitcmd->{'client-stop'}\n";
+    exit(1);
+  }
+  if(m:^/afs on AFS:) {
+    print "The AFS client is currently running on this workstation.\n";
+    print "Please restart this script after running $openafsinitcmd->{'client-stop'}\n";
+    exit(1);
+  }
+}
+close MOUNT;
+
+unless ( -f "$openafsdirpath->{'afsconfdir'}/KeyFile") {
+  print "You do not have an AFS keyfile.  Please create this using asetkey from openafs-krb5 or 
+the bos addkey command";
+  exit(1);
+}
+
+print "If the fileserver is not running, this may hang for 30 seconds.\n";
+run("$openafsinitcmd->{'filesrv-stop'}");
+$server = `hostname`;
+chomp $server;
+$admin = $rl->readline("What administrative principal should be used? ") unless $admin;
+ die "Please specify an administrative user\n" unless $admin;
+$admin =~ s:/:.:g;
+if($admin =~ /@/) {
+die "The administrative user must be in the same realm as the cell and no realm may be specified.\n";
+}
+
+$cellname = $rl->readline("What cellname should be used? ") unless $cellname;
+die "Please specify a cellname\n" unless $cellname;
+
+if (! -f "$openafsdirpath->{'afsconfdir'}/ThisCell") {
+    open(CELL, "> $openafsdirpath->{'afsconfdir'}/ThisCell");
+    print CELL "${cellname}";
+    close CELL;
+}
+
+open(CELL, "$openafsdirpath->{'afsconfdir'}/ThisCell") or
+    die "Cannot open $openafsdirpath->{'afsconfdir'}/ThisCell: $!\n";
+
+my $lcell = <CELL>;
+chomp $lcell;
+close CELL;
+
+run( "echo \\>$lcell >$openafsdirpath->{'afsconfdir'}/CellServDB");
+$csdb = `host $server|awk '{print $4 " #" $1}'`;
+run( "echo $csdb >>$openafsdirpath->{'afsconfdir'}/CellServDB");
+run("$openafsinitcmd->{'filesrv-start'}");
+unwind("$openafsinitcmd->{'filesrv-stop'}");
+$shutdown_needed = 1;
+run ("$openafsdirpath->{'afssrvbindir'}/bos addhost $server $server -localauth ||true");
+run("$openafsdirpath->{'afssrvbindir'}/bos adduser $server $admin -localauth");
+unwind("$openafsdirpath->{'afssrvbindir'}/bos removeuser $server $admin -localauth");
+if ( -f "$openafsdirpath->{'afsdbdir'}/prdb.DB0" ) {
+  die "Protection database already exists; cell already partially created\n";
+ }
+open(PRDB, "|$openafsdirpath->{'afssrvsbindir'}/pt_util -p $openafsdirpath->{'afsdbdir'}/prdb.DB0 -w ")
+or die "Unable to start pt_util: $!\n";
+print PRDB "$admin 128/20 1 -204 -204\n";
+print PRDB "system:administrators 130/20 -204 -204 -204\n";
+print PRDB" $admin 1\n";
+close PRDB;
+unwind( "rm $openafsdirpath->{'afsdbdir'}/prdb* ");
+# Start up ptserver and vlserver
+run("$openafsdirpath->{'afssrvbindir'}/bos create $server ptserver simple $openafsdirpath->{'afssrvlibexecdir'}/ptserver -localauth");
+unwind("$openafsdirpath->{'afssrvbindir'}/bos delete $server ptserver -localauth");
+
+run("$openafsdirpath->{'afssrvbindir'}/bos create $server vlserver simple $openafsdirpath->{'afssrvlibexecdir'}/vlserver -localauth");
+unwind("$openafsdirpath->{'afssrvbindir'}/bos delete $server vlserver -localauth");
+
+run( "$openafsdirpath->{'afssrvbindir'}/bos create $server fs fs ".
+     "-cmd $openafsdirpath->{'afssrvlibexecdir'}/fileserver ".
+     "-cmd $openafsdirpath->{'afssrvlibexecdir'}/volserver ".
+     "-cmd $openafsdirpath->{'afssrvlibexecdir'}/salvager -localauth");
+unwind( "$openafsdirpath->{'afssrvbindir'}/bos delete $server fs -localauth ");
+
+print "Waiting for database elections: ";
+sleep(30);
+print "done.\n";
+# Past this point we want to control when bos shutdown happens
+$shutdown_needed = 0;
+unwind( "$openafsdirpath->{'afssrvbindir'}/bos shutdown $server -localauth ");
+run("$openafsdirpath->{'afssrvsbindir'}/vos create $server a root.afs -localauth");
+# bring up client
+
+$cachesize = $rl->readline("What size cache (in 1k blocks)? ") unless $cachesize;
+die "Please specify a cache size\n" unless $cachesize;
+
+run("echo $lcell >$openafsdirpath->{'viceetcdir'}/ThisCell");
+run("cp $openafsdirpath->{'afsconfdir'}/CellServDB $openafsdirpath->{'viceetcdir'}/CellServDB");
+run("echo /afs:/usr/vice/cache:${cachesize} >$openafsdirpath->{'viceetcdir'}/cacheinfo");
+run("$openafsinitcmd->{'client-forcestart'}");
+my $afs_running = 0;
+open(MOUNT, "mount |") or die "Failed to run mount: $!\n";
+while(<MOUNT>) {
+if(m:^AFS:) {
+       $afs_running = 1;
+}
+       }
+unless ($afs_running) {
+print "*** The AFS client failed to start.\n";
+print  "Please fix whatever problem kept it from running.\n";
+       exit(1);
+}
+unwind("$openafsinitcmd->{'client-stop'}");
+
+unless ($part) {
+    $part = $rl    ->readline("What partition? [a] ");
+    $part = "a" unless $part;
+}
+
+&OpenAFS::Auth::authadmin();
+
+run("$openafsdirpath->{'afssrvbindir'}/fs sa /afs system:anyuser rl");
+
+run("$openafsdirpath->{'afssrvsbindir'}/vos create $server $part root.cell -localauth");
+unwind("$openafsdirpath->{'afssrvsbindir'}/vos remove $server $part root.cell -localauth");
+# We make root.cell s:anyuser readable after we mount in the next
+# loop.
+open(CELLSERVDB, "$openafsdirpath->{'viceetcdir'}/CellServDB")
+    or die "Unable to open $openafsdirpath->{'viceetcdir'}/CellServDB: $!\n";
+while(<CELLSERVDB>) {
+    chomp;
+    if (/^>\s*([a-z0-9_\-.]+)/ ) {
+       run("$openafsdirpath->{'afssrvbindir'}/fs mkm /afs/$1 root.cell -cell $1 -fast");
+       unwind ("$openafsdirpath->{'afssrvbindir'}/fs rmm /afs/$1");
+   }
+}
+
+run("$openafsdirpath->{'afssrvbindir'}/fs sa /afs/$lcell system:anyuser rl");
+run ("$openafsdirpath->{'afssrvbindir'}/fs mkm /afs/.$lcell root.cell -cell $lcell -rw");
+unwind ("$openafsdirpath->{'afssrvbindir'}/fs rmm /afs/.$lcell");
+run("$openafsdirpath->{'afssrvbindir'}/fs mkm /afs/.root.afs root.afs -rw");
+unwind ("$openafsdirpath->{'afssrvbindir'}/fs rmm /afs/.root.afs");
+
+mkvol( "user", "/afs/$lcell/user" );
+unwind( "$openafsdirpath->{'afssrvsbindir'}/vos remove $server $part user -localauth ");
+
+mkvol( "service", "/afs/$lcell/service" );
+unwind( "$openafsdirpath->{'afssrvsbindir'}/vos remove $server $part service -localauth ");
+
+mkvol( "rep", "/afs/$lcell/.replicated" );
+unwind( "$openafsdirpath->{'afssrvsbindir'}/vos remove $server $part rep -localauth ");
+run( "$openafsdirpath->{'afssrvbindir'}/fs mkm /afs/$lcell/replicated rep.readonly " );
+
+run( "$openafsdirpath->{'afssrvsbindir'}/vos addsite $server $part rep -localauth" );
+run( "$openafsdirpath->{'afssrvsbindir'}/vos release rep -localauth" );
+unwind( "$openafsdirpath->{'afssrvsbindir'}/vos remove $server $part rep.readonly -localauth ");
+
+mkvol( "unrep", "/afs/$lcell/unreplicated" );
+unwind( "$openafsdirpath->{'afssrvsbindir'}/vos remove $server $part unrep -localauth ");
+
+$lcell =~ /^([^.]*)/;
+my $cellpart = $1;
+run("ln -s /afs/$lcell /afs/$cellpart");
+unwind ("rm /afs/$cellpart");
+run( "ln -s /afs/.$lcell /afs/.$cellpart" );
+unwind ("rm /afs/.$cellpart");
+
+run( "$openafsdirpath->{'afssrvsbindir'}/vos addsite $server $part root.afs -localauth" );
+run( "$openafsdirpath->{'afssrvsbindir'}/vos addsite $server $part root.cell -localauth" );
+run( "$openafsdirpath->{'afssrvsbindir'}/vos release root.afs -localauth" );
+run( "$openafsdirpath->{'afssrvsbindir'}/vos release root.cell -localauth" );
+unwind( "$openafsdirpath->{'afssrvsbindir'}/vos remove $server $part root.cell.readonly -localauth ");
+unwind( "$openafsdirpath->{'afssrvsbindir'}/vos remove $server $part root.afs.readonly -localauth ");
+
+
+
+@unwinds = ();
+END {
+# If we fail before all the instances are created, we need to perform 
+# our own bos shutdown
+    system("$openafsdirpath->{'afssrvbindir'}/bos shutdown $server -localauth") if $shutdown_needed;
+  run(pop @unwinds) while @unwinds;
+  }
diff --git a/src/tests/afs-rmcell.sh b/src/tests/afs-rmcell.sh
new file mode 100755 (executable)
index 0000000..53f5958
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+/bin/rm -rf /usr/afs/db/prdb.DB0 /usr/afs/db/prdb.DBSYS1 /usr/afs/db/vldb.DB0 /usr/afs/db/vldb.DBSYS1 /usr/afs/local/BosConfig /usr/afs/etc/UserList /usr/afs/etc/ThisCell /usr/afs/etc/CellServDB 
+/bin/rm -rf /vicepa/AFSIDat 
+/bin/rm -rf /vicepb/AFSIDat
+/bin/rm -rf /vicepa/V*.vol
+/bin/rm -rf /vicepb/V*.vol
+exit 0
diff --git a/src/tests/afsconf.pm b/src/tests/afsconf.pm
new file mode 100644 (file)
index 0000000..86db460
--- /dev/null
@@ -0,0 +1,234 @@
+# CMUCS AFStools
+# Copyright (c) 1996, Carnegie Mellon University
+# All rights reserved.
+#
+# See CMUCS/CMU_copyright.pm for use and distribution information
+
+package OpenAFS::afsconf;
+
+=head1 NAME
+
+OpenAFS::afsconf - Access to AFS config info
+
+=head1 SYNOPSIS
+
+  use OpenAFS::afsconf;
+
+  $cell = AFS_conf_localcell();
+  $cell = AFS_conf_canoncell($cellname);
+  @servers = AFS_conf_cellservers($cellname);
+  @cells = AFS_conf_listcells();
+  %info = AFS_conf_cacheinfo();
+
+=head1 DESCRIPTION
+
+This module provides access to information about the local workstation's
+AFS configuration.  This includes information like the name of the
+local cell, where AFS is mounted, and access to information in the
+F<CellServDB>.  All information returned by this module is based on the
+configuration files, and does not necessarily reflect changes made
+on the afsd command line or using B<fs> commands.
+
+=cut
+
+use OpenAFS::CMU_copyright;
+use OpenAFS::config;
+use OpenAFS::util qw(:DEFAULT :afs_internal);
+use Exporter;
+
+$VERSION   = '';
+$VERSION   = '1.00';
+@ISA       = qw(Exporter);
+@EXPORT    = qw(&AFS_conf_localcell
+                &AFS_conf_canoncell
+               &AFS_conf_listcells
+               &AFS_conf_cellservers
+               &AFS_conf_cacheinfo);
+
+
+# _confpath($file) - Return path to a configuration file
+sub _confpath {
+  my($file) = @_;
+
+  if ($conf_paths{$file}) {
+    $conf_paths{$file};
+  } elsif ($AFS_Parms{confdir} && -r "$AFS_Parms{confdir}/$file") {
+    $conf_paths{$file} = "$AFS_Parms{confdir}/$file";
+  } elsif (-r "$def_ConfDir/$file") {
+    $conf_paths{$file} = "$def_ConfDir/$file";
+  } else {
+    die "Unable to locate $file\n";
+  }
+}
+
+=head2 AFS_conf_localcell()
+
+Return the canonical name of the local cell.  This depends on the contents
+of the F<ThisCell> file in the AFS configuration directory.
+
+=cut
+
+$AFS_Help{conf_localcell} = '=> $lclcell';
+sub AFS_conf_localcell {
+  my($path) = _confpath(ThisCell);
+  my($result);
+
+  return '' if (!$path);
+  if (open(THISCELL, $path)) {
+    chomp($result = <THISCELL>);
+    close(THISCELL);
+    $result;
+  } else {
+    die "Unable to open $path: $!\n";
+  }
+}
+
+=head2 AFS_conf_canoncell($cellname)
+
+Return the canonical name of the specified cell, as found in F<CellServDB>.
+I<$cellname> may be any unique prefix of a cell name, as with various AFS
+commands that take cell names as arguments.
+
+=head2 AFS_conf_cellservers($cellname)
+
+Return a list of servers in the specified cell.  As with B<AFS_conf_canoncell>,
+I<$cellname> may be any unique prefix of a cell name.  The resulting list
+contains server hostnames, as found in F<CellServDB>.
+
+=cut
+
+$AFS_Help{conf_canoncell} = '$cellname => $canon';
+$AFS_Help{conf_cellservers} = '$cellname => @servers';
+
+sub AFS_conf_canoncell   { &_findcell($_[0], 0); }
+sub AFS_conf_cellservers { &_findcell($_[0], 1); }
+
+sub _findcell {
+  my($cellname, $doservers) = @_;
+  my($path, $found, @servers, $looking);
+
+  return $canon_name{$cellname} if (!$doservers && $canon_name{$cellname});
+  $path = _confpath(CellServDB) || die "Unable to locate CellServDB\n";
+
+  if (open(CELLSERVDB, $path)) {
+    my($cellpat) = $cellname;
+    $cellpat =~ s/(\W)/\\$1/g;
+    while (<CELLSERVDB>) {
+      $looking = 0 if (/^\>/);
+      if (/^\>$cellpat/) {
+       if ($found) {
+         close(CELLSERVDB);
+         die "Cell name $cellname is not unique\n";
+       } else {
+         chop($found = $_);
+         $found =~ s/^\>(\S+).*/$1/;
+         $looking = 1 if ($doservers);
+       }
+      } elsif ($looking && (/^[\.\d]+\s*\#\s*(.*\S+)/ || /^([\.\d]+)/)) {
+       push(@servers, $1);
+      }
+    }
+    close(CELLSERVDB);
+    if ($found) {
+      $canon_name{$cellname} = $found;
+      $doservers ? @servers : ($found);
+    } else {
+      die "Cell $cellname not in CellServDB\n";
+    }
+  } else {
+    die "Unable to open $path: $!\n";
+  }
+}
+
+=head2 AFS_conf_listcells()
+
+Return a list of canonical names (as found in F<CellServDB>) of all
+known AFS cells.
+
+=cut
+
+$AFS_Help{conf_listcells} = '=> @cells';
+sub AFS_conf_listcells {
+  my($path, @cells);
+
+  $path = _confpath(CellServDB) || die "Unable to locate CellServDB!\n";
+
+  if (open(CELLSERVDB, $path)) {
+    while (<CELLSERVDB>) {
+      if (/^\>(\S+)/) {
+       push(@cells, $1);
+      }
+    }
+    close(CELLSERVDB);
+    @cells;
+  } else {
+    die "Unable to open $path: $!\n";
+  }
+}
+
+=head2 AFS_conf_cacheinfo()
+
+Return a table of information about the local workstation's cache
+configuration.  This table may contain any or all of the following elements:
+
+=over 14
+
+=item afsroot
+
+Mount point for the AFS root volume
+
+=item cachedir
+
+Location of the AFS cache directory
+
+=item cachesize
+
+AFS cache size
+
+=item hardcachesize
+
+Hard limit on AFS cache size (if specified; probably Mach-specific)
+
+=item translator
+
+Name of AFS/NFS translator server (if set)
+
+=back
+
+=cut
+
+$AFS_Help{conf_cacheinfo} = '=> %info';
+sub AFS_conf_cacheinfo {
+  my($path) = _confpath('cacheinfo');
+  my(%result, $line, $hcs);
+
+  if ($path) {
+    if (open(CACHEINFO, $path)) {
+      chop($line = <CACHEINFO>);
+      close(CACHEINFO);
+      (@result{'afsroot', 'cachedir', 'cachesize'} , $hcs) = split(/:/, $line);
+      $result{'hardcachesize'} = $hcs if ($hcs);
+    } else {
+      die "Unable to open $path: $!\n";
+    }
+  }
+  if ($ENV{'AFSSERVER'}) {
+    $result{'translator'} = $ENV{'AFSSERVER'};
+  } elsif (open(SRVFILE, "$ENV{HOME}/.AFSSERVER")
+          || open(SRVFILE, "/.AFSSERVER")) {
+    $result{'translator'} = <SRVFILE>;
+    close(SRVFILE);
+  }
+  %result;
+}
+
+
+1;
+
+=head1 COPYRIGHT
+
+The CMUCS AFStools, including this module are
+Copyright (c) 1996, Carnegie Mellon University.  All rights reserved.
+For use and redistribution information, see CMUCS/CMU_copyright.pm
+
+=cut
diff --git a/src/tests/afscp.c b/src/tests/afscp.c
new file mode 100644 (file)
index 0000000..4bf5ce2
--- /dev/null
@@ -0,0 +1,500 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <sys/ioctl.h>
+#include <afs/venus.h>
+#include <afs/cellconfig.h>
+#include <afs/afs.h>
+
+/*#include <rx/rxkad.h>*/
+#include <rx/rx_null.h>
+
+/*#include <krb.h>*/
+#include <com_err.h>
+
+struct VenusFid {
+    afs_int32 Cell;
+    struct AFSFid Fid;
+};
+
+int statfile(char *path, char *cellname, afs_uint32 *server, 
+             struct AFSFid *f)
+{
+     
+     struct ViceIoctl v;
+     struct VenusFid vf;
+     afs_int32 srvbuf[MAXHOSTS];
+     int code;
+     
+     v.in=0;
+     v.in_size=0;
+     v.out=cellname;
+     v.out_size=MAXCELLCHARS;
+     if ((code=pioctl(path, VIOC_FILE_CELL_NAME, &v, 1)))
+          return code;
+     
+     v.out=(char *)&vf;
+     v.out_size=sizeof(struct VenusFid);
+     if ((code=pioctl(path, VIOCGETFID, &v, 1)))
+          return code;
+     memcpy(f,&vf.Fid, sizeof(struct AFSFid));
+     
+     v.out=(char *)srvbuf;
+     v.out_size=sizeof(srvbuf);
+     if ((code=pioctl(path, VIOCWHEREIS, &v, 1)))
+          return code;
+     if (v.out_size <= sizeof(afs_int32))
+          return EINVAL;
+     
+     memcpy(server, srvbuf, sizeof(afs_int32));
+     return 0;
+}
+
+
+extern int RXAFSCB_ExecuteRequest();
+struct rx_securityClass *sc;
+
+extern int start_cb_server() 
+{
+     struct rx_service *s;
+
+     sc=rxnull_NewServerSecurityObject();
+     s=rx_NewService(0,1,"afs", &sc, 1, RXAFSCB_ExecuteRequest);
+     if (!s)
+          return 1;
+     rx_StartServer(0);
+     return 0;
+}
+
+
+/*extern int rx_socket;*/
+extern unsigned short rx_port;
+int do_rx_Init(void)
+{
+     struct sockaddr_in s;
+     int len;
+
+     if (rx_Init(0)) {
+          fprintf(stderr, "Cannot initialize rx\n");
+          return 1;
+     }
+
+     len=sizeof(struct sockaddr_in);
+     if (getsockname(rx_socket, &s, &len)) {
+          perror("getsockname");
+          return 1;
+     }
+     rx_port=ntohs(s.sin_port);
+
+     return 0;
+}
+
+struct rx_securityClass *get_sc(char * cellname) 
+{
+#if 0
+     char realm[REALM_SZ];
+     CREDENTIALS c;
+#endif
+     
+     return rxnull_NewClientSecurityObject();
+#if 0     
+
+     ucstring(realm, cellname, REALM_SZ);
+     
+     if (krb_get_cred("afs", "", realm, &c)) {
+          if (get_ad_tkt("afs","",realm, DEFAULT_TKT_LIFE)) {
+               return NULL;
+          } else {
+               if (krb_get_cred("afs", "", realm, &c)) {
+                    return NULL;
+               }
+          }
+     }
+     
+     return rxkad_NewClientSecurityObject(rxkad_clear, c.session, c.kvno, 
+                                          c.ticket_st.length, c.ticket_st.dat);
+#endif
+}
+
+#define scindex_NULL 0
+#define scindex_RXKAD 2
+
+#define scindex scindex_RXKAD
+int main(int argc, char **argv) 
+{
+     char scell[MAXCELLCHARS], dcell[MAXCELLCHARS];
+     afs_uint32 ssrv, dsrv;
+     char *databuffer,*srcf,*destd,*destf,*destpath;
+     struct stat statbuf;
+     
+     struct AFSStoreStatus sst;
+     struct AFSFetchStatus fst,dfst;
+     struct AFSVolSync vs;
+     struct AFSCallBack scb,dcb;
+     struct AFSFid sf, dd, df;
+    
+     int filesz;
+     int ch, blksize, bytesremaining, bytes;
+     struct timeval start, finish;
+     struct timezone tz;
+     struct rx_securityClass *ssc = 0, *dsc = 0;
+     int sscindex, dscindex;
+     struct rx_connection *sconn,*dconn;
+     struct rx_call *scall, *dcall;
+     int code,fetchcode,storecode,printcallerrs;
+     int slcl = 0, dlcl = 0;
+     int sfd, dfd, unauth = 0;
+
+     struct AFSCBFids theFids;
+     struct AFSCBs theCBs;
+
+
+     blksize=8*1024;
+     
+     while ((ch=getopt(argc, argv, "ioub:")) != -1) {
+          switch(ch)
+          {
+          case 'b':
+               blksize=atoi(optarg);
+               break;
+          case 'i':
+               slcl=1;
+               break;
+          case 'o':
+               dlcl=1;
+               break;
+          case 'a':
+               unauth=1;
+               break;
+          default:
+               exit(1);
+          }
+     }
+     
+
+     if (argc - optind < 2) {
+          fprintf(stderr, "Usage: afscp [-i|-o]] [-b xfersz] [-u] source dest\n");
+          fprintf(stderr, "  -b   Set block size\n");
+          fprintf(stderr, "  -i   Source is local (copy into AFS)\n");
+          fprintf(stderr, "  -o   Dest is local (copy out of AFS)\n");
+          fprintf(stderr, "  -u   Run unauthenticated\n");
+          exit(1);
+     }
+     srcf=argv[optind++];
+     destpath=argv[optind++];
+     destd=strdup(destpath);
+     if (!destd) {
+          perror("strdup");
+          exit(1);
+     }
+     if ((destf=strrchr(destd, '/'))) {
+          *destf++=0;
+     } else {
+          destf=destd;
+          destd=".";
+     }
+     
+     
+     if (!slcl && statfile(srcf, scell, &ssrv, &sf)) {
+          fprintf(stderr, "Cannot get attributes of %s\n", srcf);
+          exit(1);
+     }
+     if (!dlcl && statfile(destd, dcell, &dsrv, &dd)) {
+          fprintf(stderr, "Cannot get attributes of %s\n", destd);
+          exit(1);
+     }
+    
+     if ((databuffer=malloc(blksize)) == NULL) {
+          perror("malloc");
+          exit(1);
+     }
+     
+     if (do_rx_Init())
+          exit(1);
+
+     if (start_cb_server()) {
+          printf("Cannot start callback service\n");
+          goto Fail_rx;
+     }
+     
+     if (!slcl) {
+          sscindex=scindex_RXKAD;
+          if (unauth || (ssc=get_sc(scell)) == NULL) {
+               ssc=rxnull_NewClientSecurityObject();
+               sscindex=scindex_NULL;
+               /*printf("Cannot get authentication for cell %s; running unauthenticated\n", scell);*/
+          }
+               sscindex=scindex_NULL;
+
+          if ((sconn=rx_NewConnection(ssrv, htons(AFSCONF_FILEPORT), 1, ssc, 
+                                      sscindex))
+                ==NULL) {
+               struct in_addr s;
+               s.s_addr=ssrv;
+               printf("Cannot initialize rx connection to source server (%s)\n",
+                      inet_ntoa(s));
+               goto Fail_sc;
+          }
+     }
+     
+     if (!dlcl) {
+          if (!slcl && ssrv == dsrv) {
+               dconn=sconn;
+               dsc=NULL;
+          } else {
+               if (slcl || strcmp(scell, dcell)){
+                    dscindex=scindex_RXKAD;
+                    if (unauth || (dsc=get_sc(dcell)) == NULL) {
+                         dsc=rxnull_NewClientSecurityObject();
+                         dscindex=scindex_NULL;
+                         /*printf("Cannot get authentication for cell %s; running unauthenticated\n", dcell);*/
+                    }
+               dscindex=scindex_NULL;
+               } else {
+                    dsc=ssc;
+                    dscindex=sscindex;
+               }
+          
+               if ((dconn=rx_NewConnection(dsrv, htons(AFSCONF_FILEPORT), 1, dsc,
+                                           dscindex))
+                   ==NULL) {
+                    struct in_addr s;
+                    s.s_addr=dsrv;
+                    printf("Cannot initialize rx connection to dest server (%s)\n",
+                           inet_ntoa(s));
+                    goto Fail_sconn;
+               }
+          }
+     }
+     
+     
+     memset(&sst, 0, sizeof(struct AFSStoreStatus));
+     
+     if (dlcl) {
+          dfd = open(destpath, O_RDWR|O_CREAT|O_EXCL, 0666);
+          if (dfd < 0 && errno == EEXIST) {
+               printf("%s already exists, overwriting\n", destpath);
+               dfd = open(destpath, O_RDWR|O_TRUNC, 0666);
+               if (dfd < 0) {
+                    fprintf(stderr, "Cannot open %s (%s)\n", destpath,
+                            error_message(errno));
+                    goto Fail_dconn;
+               }
+          } else if (dfd < 0) {
+               fprintf(stderr, "Cannot open %s (%s)\n", destpath,
+                       error_message(errno));
+               goto Fail_dconn;
+          }
+     } else {
+          if ((code=RXAFS_CreateFile(dconn, &dd, destf, &sst, &df, &fst,
+                                     &dfst, &dcb, &vs))) {
+               if (code == EEXIST) {
+                    printf("%s already exits, overwriting\n", destpath);
+                    if (statfile(destpath, dcell, &dsrv, &df))
+                         fprintf(stderr, "Cannot get attributes of %s\n",
+                                 destpath);
+                    else
+                         code=0;
+               } else {
+                    printf("Cannot create %s (%s)\n", destpath,
+                           error_message(code));
+               if (code)
+                    goto Fail_dconn;
+               }
+          }
+     }
+
+     if (slcl) {
+          sfd = open(srcf, O_RDONLY, 0);
+          if (sfd < 0) {
+               fprintf(stderr, "Cannot open %s (%s)\n", srcf,
+                       error_message(errno));
+               goto Fail_dconn;
+          }
+          if (fstat(sfd, &statbuf) < 0) {
+               fprintf(stderr, "Cannot stat %s (%s)\n", srcf,
+                       error_message(errno));
+               close(sfd);
+               goto Fail_dconn;
+          }
+     } else {
+          if ((code=RXAFS_FetchStatus(sconn, &sf, &fst, &scb, &vs))) {
+               printf("Cannot fetchstatus of %d.%d (%s)\n", sf.Volume, sf.Vnode, 
+                      error_message(code));
+               goto Fail_dconn;
+          }
+     }
+     
+     
+
+     if (slcl) {
+          filesz=statbuf.st_size;
+     } else {
+          filesz=fst.Length;
+     }
+     
+     printcallerrs=0;
+     fetchcode=0;
+     storecode=0;
+     if (!slcl) scall=rx_NewCall(sconn);
+     if (!dlcl) dcall=rx_NewCall(dconn);
+     gettimeofday(&start, &tz);
+     
+     if (!slcl) {
+          if ((code = StartRXAFS_FetchData(scall, &sf, 0, filesz))) {
+               printf("Unable to fetch data from %s (%s)\n", srcf, 
+                      error_message(code));
+               goto Fail_call;
+          }
+     }
+
+     if (!dlcl) {
+          if (slcl) {
+               sst.Mask=AFS_SETMODTIME|AFS_SETMODE;
+               sst.ClientModTime=statbuf.st_mtime;
+               sst.UnixModeBits=statbuf.st_mode & ~(S_IFMT|S_ISUID|S_ISGID);
+          } else {
+               sst.Mask=AFS_SETMODTIME|AFS_SETMODE;
+               sst.ClientModTime=fst.ClientModTime;
+               sst.UnixModeBits=fst.UnixModeBits & ~(S_IFMT|S_ISUID|S_ISGID);
+          }
+     
+          if ((code = StartRXAFS_StoreData(dcall, &df, &sst, 0, filesz, filesz))) {
+               printf("Unable to store data to %s (%s)\n", destpath, 
+                      error_message(code));
+               goto Fail_call;
+          }
+     }
+
+     if (slcl) {
+          bytesremaining=statbuf.st_size;
+     } else {
+          rx_Read(scall,&bytesremaining,sizeof(afs_int32));
+          bytesremaining=ntohl(bytesremaining);
+     }
+     
+     while (bytesremaining >0) {
+          /*printf("%d bytes remaining\n",bytesremaining);*/
+          if (slcl) {
+               if ((bytes=read(sfd, databuffer,
+                                  min(blksize,bytesremaining)))<= 0) {
+                    fetchcode=errno;
+                    break;
+               }
+          } else {
+               if ((bytes=rx_Read(scall, databuffer,
+                                  min(blksize,bytesremaining)))<= 0)
+                    break;
+          }
+          if (dlcl) {
+               if (write(dfd, databuffer, bytes) != bytes) {
+                    storecode=errno;
+                    break;
+               }
+          } else {
+               if (rx_Write(dcall, databuffer, bytes) != bytes)
+                    break;
+          }
+          bytesremaining -= bytes;
+          /*printf("%d bytes copied\n",bytes);*/
+     }
+          
+
+     if (bytesremaining > 0) {
+          printf("Some network error occured while copying data\n");
+          goto Fail_call;
+     }
+     
+     if (!slcl) fetchcode = EndRXAFS_FetchData(scall, &fst, &scb, &vs);
+     if (!dlcl) storecode = EndRXAFS_StoreData(dcall, &fst, &vs);
+     printcallerrs=1;
+ Fail_call:
+          
+     if (slcl) {
+          if (close(sfd) && !fetchcode) fetchcode = errno;
+     } else {
+          fetchcode = rx_EndCall(scall, fetchcode);
+     }
+     if (fetchcode && printcallerrs)
+          printf("Error returned from fetch: %s\n", error_message(fetchcode));
+
+     if (dlcl) {
+          if (close(dfd) && !storecode) storecode = errno;
+     } else {
+          storecode = rx_EndCall(dcall, storecode);
+     }
+     if (storecode && printcallerrs)
+          printf("Error returned from store: %s\n", error_message(storecode));
+     
+     gettimeofday(&finish, &tz);
+     
+     if (!slcl) {
+          theFids.AFSCBFids_len=1;
+          theFids.AFSCBFids_val=&sf;
+          theCBs.AFSCBs_len=1;
+          theCBs.AFSCBs_val=&scb;
+          scb.CallBackType = CB_DROPPED;
+          if ((code=RXAFS_GiveUpCallBacks(sconn, &theFids, &theCBs)))
+               printf("Could not give up source callback: %s\n",
+                      error_message(code));
+     }
+
+     if (!dlcl) {
+          theFids.AFSCBFids_len=1;
+          theFids.AFSCBFids_val=&df;
+          theCBs.AFSCBs_len=1;
+          theCBs.AFSCBs_val=&dcb;
+          dcb.CallBackType = CB_DROPPED;
+          if ((code=RXAFS_GiveUpCallBacks(dconn, &theFids, &theCBs)))
+               printf("Could not give up target callback: %s\n",
+                      error_message(code));
+     }
+
+     if (code==0)
+          code=storecode;
+     if (code==0)
+          code=fetchcode;
+     
+ Fail_dconn:
+     if (!dlcl && (slcl || dconn != sconn))
+          rx_DestroyConnection(dconn);
+ Fail_sconn:
+     if (!slcl) rx_DestroyConnection(sconn);
+ Fail_sc:
+     if (dsc && dsc != ssc)
+          RXS_Close(dsc);
+     if (ssc) RXS_Close(ssc);
+ Fail_rx:
+     rx_Finalize();
+     
+     free(databuffer);
+     if (printcallerrs) {
+          double rate,size,time;
+          if (finish.tv_sec == start.tv_sec) {
+               printf("Copied %d bytes in %d microseconds\n", filesz, finish.tv_usec
+                      -start.tv_usec);
+          } else {
+               printf("Copied %d bytes in %d seconds\n", filesz, finish.tv_sec
+                      -start.tv_sec);
+          }
+          
+          size=filesz/1024.0;
+          time=finish.tv_sec-start.tv_sec + (finish.tv_usec-start.tv_usec)/1e+06;
+          rate=size/time;
+          printf("Transfer rate %g Kbytes/sec\n", rate);
+     
+     }
+     
+     exit(code != 0);
+}
diff --git a/src/tests/afscp_callback.c b/src/tests/afscp_callback.c
new file mode 100644 (file)
index 0000000..6d2549d
--- /dev/null
@@ -0,0 +1,156 @@
+#include <afs/param.h>
+#include <afs/afscbint.h>               /*Callback interface defs*/
+int afs_cb_inited = 0;
+struct interfaceAddr afs_cb_interface;
+static int init_afs_cb() {
+    int count;
+
+    afs_uuid_create(&afs_cb_interface.uuid);
+    count = rx_getAllAddr(&afs_cb_interface.addr_in, AFS_MAX_INTERFACE_ADDR);
+    if ( count <= 0 )
+        afs_cb_interface.numberOfInterfaces = 0;
+    else
+        afs_cb_interface.numberOfInterfaces = count;
+    afs_cb_inited = 1;
+    return 0;
+}
+afs_int32 SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array)
+    struct rx_call *rxcall;
+    AFSCBFids *Fids_Array;
+    AFSCBs *CallBack_Array;
+
+{ /*SRXAFSCB_CallBack*/
+    return(0);
+
+} /*SRXAFSCB_CallBack*/
+
+
+afs_int32 SRXAFSCB_InitCallBackState(rxcall)
+    struct rx_call *rxcall;
+
+{ /*SRXAFSCB_InitCallBackState*/
+   return(0);
+
+} /*SRXAFSCB_InitCallBackState*/
+
+afs_int32 SRXAFSCB_Probe(rxcall)
+        struct rx_call *rxcall;
+
+{ /*SRXAFSCB_Probe*/
+    return(0);
+
+} /*SRXAFSCB_Probe*/
+
+
+afs_int32 SRXAFSCB_GetCE(rxcall)
+    struct rx_call *rxcall;
+
+{ /*SRXAFSCB_GetCE*/
+     return(0);
+} /*SRXAFSCB_GetCE*/
+
+
+afs_int32 SRXAFSCB_GetCE64(rxcall)
+    struct rx_call *rxcall;
+
+{ /*SRXAFSCB_GetCE64*/
+     return(0);
+} /*SRXAFSCB_GetCE64*/
+
+
+afs_int32 SRXAFSCB_GetLock(rxcall)
+    struct rx_call *rxcall;
+
+{ /*SRXAFSCB_GetLock*/
+    return(0);
+
+} /*SRXAFSCB_GetLock*/
+afs_int32 SRXAFSCB_XStatsVersion(rxcall)
+    struct rx_call *rxcall;
+
+{ /*SRXAFSCB_XStatsVersion*/
+    return(0);
+
+} /*SRXAFSCB_XStatsVersion*/
+
+afs_int32 SRXAFSCB_GetXStats(rxcall)
+    struct rx_call *rxcall;
+
+{ /*SRXAFSCB_GetXStats*/
+     return(0);
+} /*SRXAFSCB_GetXStats*/
+
+int SRXAFSCB_InitCallBackState2(rxcall, addr)
+struct rx_call *rxcall;
+struct interfaceAddr * addr;
+{
+    return RXGEN_OPCODE;
+}
+
+int SRXAFSCB_WhoAreYou(rxcall, addr)
+struct rx_call *rxcall;
+struct interfaceAddr *addr;
+{
+    if ( rxcall && addr )
+    {
+        if (!afs_cb_inited) init_afs_cb();
+        *addr = afs_cb_interface;
+    }
+    return(0);
+}
+
+int SRXAFSCB_InitCallBackState3(rxcall, uuidp)
+struct rx_call *rxcall;
+afsUUID *uuidp;
+{
+    return(0);
+}
+int SRXAFSCB_ProbeUuid(rxcall, uuidp)
+struct rx_call *rxcall;
+afsUUID *uuidp;
+{
+    int code = 0;
+    if (!afs_cb_inited) init_afs_cb();
+    if (!afs_uuid_equal(uuidp, &afs_cb_interface.uuid))
+        code = 1; /* failure */
+    return code;
+}
+
+afs_int32 SRXAFSCB_GetServerPrefs(rxcall, serverIndex, srvrAddr, srvrRank)
+struct rx_call *rxcall;
+afs_int32 serverIndex;
+afs_int32 *srvrAddr;
+afs_int32 *srvrRank;
+{
+    return RXGEN_OPCODE;
+}
+
+
+afs_int32 SRXAFSCB_GetCellServDB(rxcall, cellIndex, cellName, cellHosts)
+struct rx_call *rxcall;
+afs_int32 cellIndex;
+char *cellName;
+afs_int32 *cellHosts;
+{
+    return RXGEN_OPCODE;
+}
+
+
+afs_int32 SRXAFSCB_GetLocalCell(rxcall, cellName)
+struct rx_call *rxcall;
+char *cellName;
+{
+    return RXGEN_OPCODE;
+}
+
+
+afs_int32 SRXAFSCB_GetCacheConfig(rxcall, callerVersion, serverVersion,
+                                  configCount, config)
+struct rx_call *rxcall;
+afs_uint32 callerVersion;
+afs_uint32 *serverVersion;
+afs_uint32 *configCount;
+cacheConfig *config;
+{
+    return RXGEN_OPCODE;
+}
diff --git a/src/tests/append-over-page.c b/src/tests/append-over-page.c
new file mode 100644 (file)
index 0000000..6b875a9
--- /dev/null
@@ -0,0 +1,977 @@
+/*
+ * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+
+#include <err.h>
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+static char long_buf[] =
+"1000\n"
+"1001\n"
+"1002\n"
+"1003\n"
+"1004\n"
+"1005\n"
+"1006\n"
+"1007\n"
+"1008\n"
+"1009\n"
+"1010\n"
+"1011\n"
+"1012\n"
+"1013\n"
+"1014\n"
+"1015\n"
+"1016\n"
+"1017\n"
+"1018\n"
+"1019\n"
+"1020\n"
+"1021\n"
+"1022\n"
+"1023\n"
+"1024\n"
+"1025\n"
+"1026\n"
+"1027\n"
+"1028\n"
+"1029\n"
+"1030\n"
+"1031\n"
+"1032\n"
+"1033\n"
+"1034\n"
+"1035\n"
+"1036\n"
+"1037\n"
+"1038\n"
+"1039\n"
+"1040\n"
+"1041\n"
+"1042\n"
+"1043\n"
+"1044\n"
+"1045\n"
+"1046\n"
+"1047\n"
+"1048\n"
+"1049\n"
+"1050\n"
+"1051\n"
+"1052\n"
+"1053\n"
+"1054\n"
+"1055\n"
+"1056\n"
+"1057\n"
+"1058\n"
+"1059\n"
+"1060\n"
+"1061\n"
+"1062\n"
+"1063\n"
+"1064\n"
+"1065\n"
+"1066\n"
+"1067\n"
+"1068\n"
+"1069\n"
+"1070\n"
+"1071\n"
+"1072\n"
+"1073\n"
+"1074\n"
+"1075\n"
+"1076\n"
+"1077\n"
+"1078\n"
+"1079\n"
+"1080\n"
+"1081\n"
+"1082\n"
+"1083\n"
+"1084\n"
+"1085\n"
+"1086\n"
+"1087\n"
+"1088\n"
+"1089\n"
+"1090\n"
+"1091\n"
+"1092\n"
+"1093\n"
+"1094\n"
+"1095\n"
+"1096\n"
+"1097\n"
+"1098\n"
+"1099\n"
+"1100\n"
+"1101\n"
+"1102\n"
+"1103\n"
+"1104\n"
+"1105\n"
+"1106\n"
+"1107\n"
+"1108\n"
+"1109\n"
+"1110\n"
+"1111\n"
+"1112\n"
+"1113\n"
+"1114\n"
+"1115\n"
+"1116\n"
+"1117\n"
+"1118\n"
+"1119\n"
+"1120\n"
+"1121\n"
+"1122\n"
+"1123\n"
+"1124\n"
+"1125\n"
+"1126\n"
+"1127\n"
+"1128\n"
+"1129\n"
+"1130\n"
+"1131\n"
+"1132\n"
+"1133\n"
+"1134\n"
+"1135\n"
+"1136\n"
+"1137\n"
+"1138\n"
+"1139\n"
+"1140\n"
+"1141\n"
+"1142\n"
+"1143\n"
+"1144\n"
+"1145\n"
+"1146\n"
+"1147\n"
+"1148\n"
+"1149\n"
+"1150\n"
+"1151\n"
+"1152\n"
+"1153\n"
+"1154\n"
+"1155\n"
+"1156\n"
+"1157\n"
+"1158\n"
+"1159\n"
+"1160\n"
+"1161\n"
+"1162\n"
+"1163\n"
+"1164\n"
+"1165\n"
+"1166\n"
+"1167\n"
+"1168\n"
+"1169\n"
+"1170\n"
+"1171\n"
+"1172\n"
+"1173\n"
+"1174\n"
+"1175\n"
+"1176\n"
+"1177\n"
+"1178\n"
+"1179\n"
+"1180\n"
+"1181\n"
+"1182\n"
+"1183\n"
+"1184\n"
+"1185\n"
+"1186\n"
+"1187\n"
+"1188\n"
+"1189\n"
+"1190\n"
+"1191\n"
+"1192\n"
+"1193\n"
+"1194\n"
+"1195\n"
+"1196\n"
+"1197\n"
+"1198\n"
+"1199\n"
+"1200\n"
+"1201\n"
+"1202\n"
+"1203\n"
+"1204\n"
+"1205\n"
+"1206\n"
+"1207\n"
+"1208\n"
+"1209\n"
+"1210\n"
+"1211\n"
+"1212\n"
+"1213\n"
+"1214\n"
+"1215\n"
+"1216\n"
+"1217\n"
+"1218\n"
+"1219\n"
+"1220\n"
+"1221\n"
+"1222\n"
+"1223\n"
+"1224\n"
+"1225\n"
+"1226\n"
+"1227\n"
+"1228\n"
+"1229\n"
+"1230\n"
+"1231\n"
+"1232\n"
+"1233\n"
+"1234\n"
+"1235\n"
+"1236\n"
+"1237\n"
+"1238\n"
+"1239\n"
+"1240\n"
+"1241\n"
+"1242\n"
+"1243\n"
+"1244\n"
+"1245\n"
+"1246\n"
+"1247\n"
+"1248\n"
+"1249\n"
+"1250\n"
+"1251\n"
+"1252\n"
+"1253\n"
+"1254\n"
+"1255\n"
+"1256\n"
+"1257\n"
+"1258\n"
+"1259\n"
+"1260\n"
+"1261\n"
+"1262\n"
+"1263\n"
+"1264\n"
+"1265\n"
+"1266\n"
+"1267\n"
+"1268\n"
+"1269\n"
+"1270\n"
+"1271\n"
+"1272\n"
+"1273\n"
+"1274\n"
+"1275\n"
+"1276\n"
+"1277\n"
+"1278\n"
+"1279\n"
+"1280\n"
+"1281\n"
+"1282\n"
+"1283\n"
+"1284\n"
+"1285\n"
+"1286\n"
+"1287\n"
+"1288\n"
+"1289\n"
+"1290\n"
+"1291\n"
+"1292\n"
+"1293\n"
+"1294\n"
+"1295\n"
+"1296\n"
+"1297\n"
+"1298\n"
+"1299\n"
+"1300\n"
+"1301\n"
+"1302\n"
+"1303\n"
+"1304\n"
+"1305\n"
+"1306\n"
+"1307\n"
+"1308\n"
+"1309\n"
+"1310\n"
+"1311\n"
+"1312\n"
+"1313\n"
+"1314\n"
+"1315\n"
+"1316\n"
+"1317\n"
+"1318\n"
+"1319\n"
+"1320\n"
+"1321\n"
+"1322\n"
+"1323\n"
+"1324\n"
+"1325\n"
+"1326\n"
+"1327\n"
+"1328\n"
+"1329\n"
+"1330\n"
+"1331\n"
+"1332\n"
+"1333\n"
+"1334\n"
+"1335\n"
+"1336\n"
+"1337\n"
+"1338\n"
+"1339\n"
+"1340\n"
+"1341\n"
+"1342\n"
+"1343\n"
+"1344\n"
+"1345\n"
+"1346\n"
+"1347\n"
+"1348\n"
+"1349\n"
+"1350\n"
+"1351\n"
+"1352\n"
+"1353\n"
+"1354\n"
+"1355\n"
+"1356\n"
+"1357\n"
+"1358\n"
+"1359\n"
+"1360\n"
+"1361\n"
+"1362\n"
+"1363\n"
+"1364\n"
+"1365\n"
+"1366\n"
+"1367\n"
+"1368\n"
+"1369\n"
+"1370\n"
+"1371\n"
+"1372\n"
+"1373\n"
+"1374\n"
+"1375\n"
+"1376\n"
+"1377\n"
+"1378\n"
+"1379\n"
+"1380\n"
+"1381\n"
+"1382\n"
+"1383\n"
+"1384\n"
+"1385\n"
+"1386\n"
+"1387\n"
+"1388\n"
+"1389\n"
+"1390\n"
+"1391\n"
+"1392\n"
+"1393\n"
+"1394\n"
+"1395\n"
+"1396\n"
+"1397\n"
+"1398\n"
+"1399\n"
+"1400\n"
+"1401\n"
+"1402\n"
+"1403\n"
+"1404\n"
+"1405\n"
+"1406\n"
+"1407\n"
+"1408\n"
+"1409\n"
+"1410\n"
+"1411\n"
+"1412\n"
+"1413\n"
+"1414\n"
+"1415\n"
+"1416\n"
+"1417\n"
+"1418\n"
+"1419\n"
+"1420\n"
+"1421\n"
+"1422\n"
+"1423\n"
+"1424\n"
+"1425\n"
+"1426\n"
+"1427\n"
+"1428\n"
+"1429\n"
+"1430\n"
+"1431\n"
+"1432\n"
+"1433\n"
+"1434\n"
+"1435\n"
+"1436\n"
+"1437\n"
+"1438\n"
+"1439\n"
+"1440\n"
+"1441\n"
+"1442\n"
+"1443\n"
+"1444\n"
+"1445\n"
+"1446\n"
+"1447\n"
+"1448\n"
+"1449\n"
+"1450\n"
+"1451\n"
+"1452\n"
+"1453\n"
+"1454\n"
+"1455\n"
+"1456\n"
+"1457\n"
+"1458\n"
+"1459\n"
+"1460\n"
+"1461\n"
+"1462\n"
+"1463\n"
+"1464\n"
+"1465\n"
+"1466\n"
+"1467\n"
+"1468\n"
+"1469\n"
+"1470\n"
+"1471\n"
+"1472\n"
+"1473\n"
+"1474\n"
+"1475\n"
+"1476\n"
+"1477\n"
+"1478\n"
+"1479\n"
+"1480\n"
+"1481\n"
+"1482\n"
+"1483\n"
+"1484\n"
+"1485\n"
+"1486\n"
+"1487\n"
+"1488\n"
+"1489\n"
+"1490\n"
+"1491\n"
+"1492\n"
+"1493\n"
+"1494\n"
+"1495\n"
+"1496\n"
+"1497\n"
+"1498\n"
+"1499\n"
+"1500\n"
+"1501\n"
+"1502\n"
+"1503\n"
+"1504\n"
+"1505\n"
+"1506\n"
+"1507\n"
+"1508\n"
+"1509\n"
+"1510\n"
+"1511\n"
+"1512\n"
+"1513\n"
+"1514\n"
+"1515\n"
+"1516\n"
+"1517\n"
+"1518\n"
+"1519\n"
+"1520\n"
+"1521\n"
+"1522\n"
+"1523\n"
+"1524\n"
+"1525\n"
+"1526\n"
+"1527\n"
+"1528\n"
+"1529\n"
+"1530\n"
+"1531\n"
+"1532\n"
+"1533\n"
+"1534\n"
+"1535\n"
+"1536\n"
+"1537\n"
+"1538\n"
+"1539\n"
+"1540\n"
+"1541\n"
+"1542\n"
+"1543\n"
+"1544\n"
+"1545\n"
+"1546\n"
+"1547\n"
+"1548\n"
+"1549\n"
+"1550\n"
+"1551\n"
+"1552\n"
+"1553\n"
+"1554\n"
+"1555\n"
+"1556\n"
+"1557\n"
+"1558\n"
+"1559\n"
+"1560\n"
+"1561\n"
+"1562\n"
+"1563\n"
+"1564\n"
+"1565\n"
+"1566\n"
+"1567\n"
+"1568\n"
+"1569\n"
+"1570\n"
+"1571\n"
+"1572\n"
+"1573\n"
+"1574\n"
+"1575\n"
+"1576\n"
+"1577\n"
+"1578\n"
+"1579\n"
+"1580\n"
+"1581\n"
+"1582\n"
+"1583\n"
+"1584\n"
+"1585\n"
+"1586\n"
+"1587\n"
+"1588\n"
+"1589\n"
+"1590\n"
+"1591\n"
+"1592\n"
+"1593\n"
+"1594\n"
+"1595\n"
+"1596\n"
+"1597\n"
+"1598\n"
+"1599\n"
+"1600\n"
+"1601\n"
+"1602\n"
+"1603\n"
+"1604\n"
+"1605\n"
+"1606\n"
+"1607\n"
+"1608\n"
+"1609\n"
+"1610\n"
+"1611\n"
+"1612\n"
+"1613\n"
+"1614\n"
+"1615\n"
+"1616\n"
+"1617\n"
+"1618\n"
+"1619\n"
+"1620\n"
+"1621\n"
+"1622\n"
+"1623\n"
+"1624\n"
+"1625\n"
+"1626\n"
+"1627\n"
+"1628\n"
+"1629\n"
+"1630\n"
+"1631\n"
+"1632\n"
+"1633\n"
+"1634\n"
+"1635\n"
+"1636\n"
+"1637\n"
+"1638\n"
+"1639\n"
+"1640\n"
+"1641\n"
+"1642\n"
+"1643\n"
+"1644\n"
+"1645\n"
+"1646\n"
+"1647\n"
+"1648\n"
+"1649\n"
+"1650\n"
+"1651\n"
+"1652\n"
+"1653\n"
+"1654\n"
+"1655\n"
+"1656\n"
+"1657\n"
+"1658\n"
+"1659\n"
+"1660\n"
+"1661\n"
+"1662\n"
+"1663\n"
+"1664\n"
+"1665\n"
+"1666\n"
+"1667\n"
+"1668\n"
+"1669\n"
+"1670\n"
+"1671\n"
+"1672\n"
+"1673\n"
+"1674\n"
+"1675\n"
+"1676\n"
+"1677\n"
+"1678\n"
+"1679\n"
+"1680\n"
+"1681\n"
+"1682\n"
+"1683\n"
+"1684\n"
+"1685\n"
+"1686\n"
+"1687\n"
+"1688\n"
+"1689\n"
+"1690\n"
+"1691\n"
+"1692\n"
+"1693\n"
+"1694\n"
+"1695\n"
+"1696\n"
+"1697\n"
+"1698\n"
+"1699\n"
+"1700\n"
+"1701\n"
+"1702\n"
+"1703\n"
+"1704\n"
+"1705\n"
+"1706\n"
+"1707\n"
+"1708\n"
+"1709\n"
+"1710\n"
+"1711\n"
+"1712\n"
+"1713\n"
+"1714\n"
+"1715\n"
+"1716\n"
+"1717\n"
+"1718\n"
+"1719\n"
+"1720\n"
+"1721\n"
+"1722\n"
+"1723\n"
+"1724\n"
+"1725\n"
+"1726\n"
+"1727\n"
+"1728\n"
+"1729\n"
+"1730\n"
+"1731\n"
+"1732\n"
+"1733\n"
+"1734\n"
+"1735\n"
+"1736\n"
+"1737\n"
+"1738\n"
+"1739\n"
+"1740\n"
+"1741\n"
+"1742\n"
+"1743\n"
+"1744\n"
+"1745\n"
+"1746\n"
+"1747\n"
+"1748\n"
+"1749\n"
+"1750\n"
+"1751\n"
+"1752\n"
+"1753\n"
+"1754\n"
+"1755\n"
+"1756\n"
+"1757\n"
+"1758\n"
+"1759\n"
+"1760\n"
+"1761\n"
+"1762\n"
+"1763\n"
+"1764\n"
+"1765\n"
+"1766\n"
+"1767\n"
+"1768\n"
+"1769\n"
+"1770\n"
+"1771\n"
+"1772\n"
+"1773\n"
+"1774\n"
+"1775\n"
+"1776\n"
+"1777\n"
+"1778\n"
+"1779\n"
+"1780\n"
+"1781\n"
+"1782\n"
+"1783\n"
+"1784\n"
+"1785\n"
+"1786\n"
+"1787\n"
+"1788\n"
+"1789\n"
+"1790\n"
+"1791\n"
+"1792\n"
+"1793\n"
+"1794\n"
+"1795\n"
+"1796\n"
+"1797\n"
+"1798\n"
+"1799\n"
+"1800\n"
+"1801\n"
+"1802\n"
+"1803\n"
+"1804\n"
+"1805\n"
+"1806\n"
+"1807\n"
+"1808\n"
+"1809\n"
+"1810\n"
+"1811\n"
+"1812\n"
+"1813\n"
+"1814\n"
+"1815\n"
+"1816\n"
+"1817\n"
+"1818\n"
+"1819\n"
+"1820\n"
+"1821\n"
+"1822\n"
+"1823\n"
+"1824\n"
+"1825\n"
+"1826\n";
+
+/*
+ * compare this file with read and mmap.
+ * return 0 iff identical.
+ */
+
+static int
+compare_file (const char *filename)
+{
+    struct stat sb;
+    int fd;
+    int ret;
+    void *read_buf;
+    void *mmap_buf;
+
+    fd = open (filename, O_RDONLY);
+    if (fd < 0)
+       err(1, "open %s", filename);
+    ret = fstat (fd, &sb);
+    if (ret < 0)
+       err (1, "stat %s", filename);
+    read_buf = malloc (sb.st_size);
+    if (read_buf == NULL)
+       err (1, "malloc %u", (unsigned)sb.st_size);
+    ret = read (fd, read_buf, sb.st_size);
+    if (ret < 0)
+       err (1, "read %s", filename);
+    if (ret != sb.st_size)
+       errx (1, "short read from %s", filename);
+    mmap_buf = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (mmap_buf == (void *)MAP_FAILED)
+       err (1, "mmap %s", filename);
+    ret = memcmp (read_buf, mmap_buf, sb.st_size);
+    close (fd);
+    free (read_buf);
+    return ret;
+}
+
+static void
+doit (const char *filename)
+{
+    int fd;
+    int ret;
+
+    fd = open (filename, O_WRONLY | O_APPEND | O_CREAT | O_TRUNC, 0600);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    ret = close (fd);
+    if (ret < 0)
+       err (1, "close %s", filename);
+    fd = open (filename, O_WRONLY | O_APPEND);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    ret = write (fd, "foobar\n", 7);
+    if (ret < 0)
+       err (1, "write %s", filename);
+    if (ret != 7)
+       errx (1, "short write to %s", filename);
+    ret = close (fd);
+    if (ret < 0)
+       err(1, "close %s", filename);
+       
+    if(compare_file (filename))
+       errx (1, "compare 1 failed");
+
+    fd = open (filename, O_WRONLY | O_APPEND);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    ret = write (fd, long_buf, strlen(long_buf));
+    if (ret < 0)
+       err (1, "write %s", filename);
+    if (ret != strlen(long_buf))
+       errx (1, "short write to %s", filename);
+    ret = close (fd);
+    if (ret < 0)
+       err(1, "close %s", filename);
+    
+    if(compare_file (filename))
+       errx (1, "compare 2 failed");
+}
+
+int
+main(int argc, char **argv)
+{
+    const char *file = "blaha";
+
+    if (argc != 1 && argc != 2)
+       errx (1, "usage: %s [file]", argv[0]);
+    if (argc == 2)
+       file = argv[1];
+    doit (file);
+    return 0;
+}
diff --git a/src/tests/append1 b/src/tests/append1
new file mode 100644 (file)
index 0000000..c7dc373
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+$objdir/echo-n hej > foo || exit 1
+if test `cat foo` != "hej"; then exit 1; fi
+$objdir/echo-n hopp >> foo || exit 1
+if test `cat foo` != "hejhopp"; then exit 1; fi
+rm foo || exit 1
diff --git a/src/tests/apwd.c b/src/tests/apwd.c
new file mode 100644 (file)
index 0000000..82335ec
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+
+#ifndef MAXPATHLEN
+#ifdef PATH_MAX
+#define MAXPATHLEN PATH_MAX
+#else
+#define MAXPATHLEN 4096
+#endif
+#endif
+
+RCSID("$Id$");
+
+static int verbose_flag;
+static FILE *verbose_fp = NULL;
+
+static int
+initial_string (char **buf, size_t *size, size_t new_size)
+{
+    char *tmp = malloc (new_size);
+
+    if (tmp == NULL)
+       return -1;
+    *buf  = tmp;
+    *size = new_size;
+    return 0;
+}
+
+static int
+expand_string (char **buf, size_t *size, size_t new_size)
+{
+    char *tmp = realloc (*buf, new_size);
+
+    if (tmp == NULL)
+       return -1;
+    *buf  = tmp;
+    *size = new_size;
+    return 0;
+}
+
+/*
+ * Verify that the dynamically allocated string `buf' of length
+ * `size', has room for `len' bytes.  Returns -1 if realloc fails.
+ */
+
+static int
+guarantee_room (char **buf, size_t *size, size_t len)
+{
+    if (*size > len)
+       return 0;
+
+    return expand_string (buf, size, min(*size * 2, len));
+}
+
+static char *
+getcwd_classic (char *buf, size_t size)
+{
+    int dynamic_buf = 0;
+    struct stat root_sb, dot_sb, dotdot_sb;
+    char *work_string;
+    size_t work_length;
+    char slash_dot_dot[] = "/..";
+    char *curp;
+    char *endp;
+    DIR *dir = NULL;
+
+    if (initial_string (&work_string, &work_length, MAXPATHLEN) < 0)
+       return NULL;
+
+    if (buf == NULL) {
+       dynamic_buf = 1;
+       if (initial_string (&buf, &size, MAXPATHLEN) < 0) {
+           free (work_string);
+           return NULL;
+       }
+    }
+
+    endp = curp = buf + size - 1;
+
+    if (lstat (".", &dot_sb) < 0)
+       goto err_ret;
+    if (lstat ("/", &root_sb) < 0)
+       goto err_ret;
+    strcpy (work_string, "..");
+    fprintf (verbose_fp, "\".\" is (%u, %u), \"/\" is (%u, %u)\n",
+            (unsigned)dot_sb.st_dev, (unsigned)dot_sb.st_ino,
+            (unsigned)root_sb.st_dev, (unsigned)root_sb.st_ino);
+
+    while (dot_sb.st_dev != root_sb.st_dev
+          || dot_sb.st_ino != root_sb.st_ino) {
+       struct dirent *dp;
+       int found = 0;
+       int change_dev = 0;
+       int pattern_len = strlen (work_string);
+
+       if (lstat (work_string, &dotdot_sb) < 0)
+           goto err_ret;
+       fprintf (verbose_fp, "\"..\" is (%u, %u)\n",
+                (unsigned)dotdot_sb.st_dev, (unsigned)dotdot_sb.st_ino);
+       if (dot_sb.st_dev != dotdot_sb.st_dev)
+           change_dev = 1;
+       dir = opendir (work_string);
+       if (dir == NULL)
+           goto err_ret;
+       while ((dp = readdir (dir)) != NULL) {
+           size_t name_len = strlen (dp->d_name);
+
+           if (change_dev) {
+               struct stat sb;
+
+               if (guarantee_room (&work_string, &work_length,
+                                   pattern_len + name_len + 2) < 0) {
+                   goto err_ret;
+               }
+
+               strcat (work_string, "/");
+               strcat (work_string, dp->d_name);
+
+               if (lstat (work_string, &sb) < 0) {
+                   goto err_ret;
+               }
+               if (sb.st_dev == dot_sb.st_dev
+                   && sb.st_ino == dot_sb.st_ino) {
+                   fprintf (verbose_fp, "\"%s\" found\n", work_string);
+                   found = 1;
+               }
+               work_string[pattern_len] = '\0';
+           } else if (dp->d_ino == dot_sb.st_ino) {
+               fprintf (verbose_fp, "\"%s\" found\n", dp->d_name);
+               found = 1;
+           }
+
+           if (found) {
+               while (buf + name_len >= curp) {
+                   size_t old_len;
+
+                   if (!dynamic_buf) {
+                       errno = ERANGE;
+                       goto err_ret;
+                   }
+                   old_len = endp - curp + 1;
+                   if (expand_string (&buf, &size, size * 2) < 0)
+                       goto err_ret;
+                   memmove (buf + size - old_len,
+                            buf + size / 2 - old_len,
+                            old_len);
+                   endp = buf + size - 1;
+                   curp = endp - old_len + 1;
+               }
+               memcpy (curp - name_len, dp->d_name, name_len);
+               curp[-(name_len + 1)] = '/';
+               curp -= name_len + 1;
+               break;
+           }
+       }
+       closedir (dir);
+       dir = NULL;
+
+       if (!found)
+           goto err_ret;
+
+       dot_sb = dotdot_sb;
+       if (guarantee_room (&work_string, &work_length,
+                           pattern_len + strlen(slash_dot_dot) + 1) < 0)
+           goto err_ret;
+       strcat (work_string, slash_dot_dot);
+    }
+    if (curp == endp) {
+       while (buf >= curp) {
+           if (!dynamic_buf) {
+               errno = ERANGE;
+               goto err_ret;
+           }
+           if (expand_string (&buf, &size, size * 2) < 0)
+               goto err_ret;
+       }
+       *--curp = '/';
+    }
+    *endp = '\0';
+    memmove (buf, curp, endp - curp + 1);
+    free (work_string);
+    return buf;
+
+err_ret:
+    if (dir)
+       closedir (dir);
+    if (dynamic_buf)
+       free (buf);
+    free (work_string);
+    return NULL;
+}
+
+#if linux
+
+static char *
+getcwd_proc (char *buf, size_t size)
+{
+    int dynamic_buf = 0;
+
+    if (buf == NULL) {
+       dynamic_buf = 1;
+       if (initial_string (&buf, &size, MAXPATHLEN) < 0)
+           return NULL;
+    } else if (size <= 1) {
+       errno = ERANGE;
+       return NULL;
+    }
+
+    for (;;) {
+       int ret;
+
+       ret = readlink ("/proc/self/cwd", buf, size);
+       if (ret == -1)
+           goto err_ret;
+       if (buf[0] != '/') {
+           errno = EINVAL;
+           goto err_ret;
+       }
+       if (buf[ret-1] != '\0' && ret >= size) {
+           if (!dynamic_buf) {
+               errno = ERANGE;
+               goto err_ret;
+           }
+           if (expand_string (&buf, &size, size * 2) < 0)
+               goto err_ret;
+       } else {
+           if (buf[ret - 1] != '\0')
+               buf[ret] = '\0';
+           return buf;
+       }
+    }
+err_ret:
+    if (dynamic_buf)
+       free (buf);
+    return NULL;
+}
+
+#endif /* linux */
+
+static int
+test_1(char *(*func)(char *, size_t), const char *func_name, int init_size)
+{
+    char real_buf[2048];
+    char buf[2048], *buf2, buf3[4711];
+    int i;
+    int ret = 0;
+    int three_done = 1;
+
+    if (getcwd (real_buf, sizeof(real_buf)) == NULL) {
+       fprintf (verbose_fp, "getcwd(buf, %u) failed\n",
+                (unsigned)sizeof(real_buf));
+       ret = 1;
+    }
+    if (func (buf, sizeof(buf)) == NULL) {
+       fprintf (verbose_fp, "%s(buf, %u) failed\n", func_name, 
+                (unsigned)sizeof(buf));
+       ret = 1;
+    } else {
+       fprintf (verbose_fp, "first *%s*\n", buf);
+       if (strcmp (real_buf, buf) != 0) {
+           fprintf (verbose_fp, "first comparison failed: *%s* != *%s*\n",
+                    real_buf, buf);
+           ret = 1;
+       }
+    }
+
+    buf2 = func (NULL, 0);
+    if (buf2 == NULL) {
+       fprintf (verbose_fp, "%s(NULL, 0) failed\n", func_name);
+       ret = 1;
+    } else {
+       fprintf (verbose_fp, "second *%s*\n", buf2);
+       if (strcmp (real_buf, buf2) != 0) {
+           fprintf (verbose_fp, "second comparison failed: *%s* != *%s*\n",
+                    real_buf, buf2);
+           ret = 1;
+       }
+       free (buf2);
+    }
+
+    for (i = init_size; i < sizeof(buf3); ++i) {
+       memset (buf3, '\x01', sizeof(buf3));
+       if (func (buf3, i) == NULL) {
+           if (errno != ERANGE) {
+               fprintf (verbose_fp, "%s(buf,%u) call failed\n", func_name, i);
+               three_done = 0;
+               break;
+           }
+       } else {
+           int j;
+
+           for (j = i; j < sizeof(buf3); ++j)
+               if (buf3[j] != '\x01') {
+                   fprintf (verbose_fp, "buffer was overwritten at %d\n", j);
+                   three_done = 0;
+                   break;
+               }
+           break;
+       }
+    }
+
+    if (three_done) {
+       fprintf (verbose_fp, "third *%s*\n", buf3);
+       if (strcmp (real_buf, buf3) != 0) {
+           fprintf (verbose_fp, "third comparison failed: *%s* != *%s*\n",
+                    real_buf, buf3);
+           ret = 1;
+       } else if (strlen (buf3) + 1 != i
+                  && strlen (buf3) + 1 >= init_size) {
+           fprintf (verbose_fp, "wrong len in third call: %d != %d\n",
+                    (unsigned)strlen(buf3) + 1, i);
+           ret = 1;
+       }
+    } else {
+       ret = 1;
+    }
+
+    return ret;
+}
+
+static int
+test_it(char *(*func)(char *, size_t), const char *name, int init_size)
+{
+    int ret;
+
+    fprintf (verbose_fp, "testing %s (initial size %d)\n", name, init_size);
+    ret = test_1 (func, name, init_size);
+    if (ret)
+       fprintf (verbose_fp, "FAILED!\n");
+    else
+       fprintf (verbose_fp, "passed\n");
+    return ret;
+}
+
+#ifdef linux
+#include <linux/unistd.h>
+#endif
+
+#ifdef __NR_getcwd
+
+#define __NR_sys_getcwd __NR_getcwd
+
+static
+_syscall2(int, sys_getcwd, char *, buf, size_t, size)
+
+static char *
+getcwd_syscall (char *buf, size_t size)
+{
+    int dynamic_buf = 0;
+
+    if (buf == NULL) {
+       dynamic_buf = 1;
+       if (initial_string (&buf, &size, MAXPATHLEN) < 0)
+           return NULL;
+    }
+
+    for (;;) {
+       int ret;
+
+       ret = sys_getcwd (buf, size);
+       if (ret >= 0)
+           return buf;
+       else if (errno == ERANGE) {
+           if (!dynamic_buf)
+               return NULL;
+           if (expand_string (&buf, &size, size * 2) < 0)
+               return NULL;
+       } else
+           return NULL;
+    }
+}
+
+#endif
+
+static int help_flag;
+
+static struct agetargs args[] = {
+    {"verbose", 'v',   aarg_flag,      &verbose_flag,  "verbose",      NULL},
+    {"help",   0,      aarg_flag,      &help_flag,     NULL,           NULL},
+    {NULL,     0,      aarg_end,       NULL,           NULL,           NULL}
+};
+
+static void
+usage (int exit_val)
+{
+    aarg_printusage (args, NULL, "", AARG_GNUSTYLE);
+}
+
+int
+main(int argc, char **argv)
+{
+    int ret = 0;
+    int optind = 0;
+
+
+    verbose_flag = getenv ("VERBOSE") != NULL;
+
+    if (agetarg (args, argc, argv, &optind, AARG_GNUSTYLE))
+       usage (1);
+
+    argc -= optind;
+    argv += optind;
+
+    if (argc != 0)
+       usage (1);
+    if (help_flag)
+       usage (0);
+
+    verbose_fp = fdopen (4, "w");
+    if (verbose_fp == NULL) {
+       verbose_fp = fopen ("/dev/null", "w");
+       if (verbose_fp == NULL)
+           err (1, "fopen");
+    }
+
+    ret += test_it (getcwd, "getcwd", 3);
+#ifdef __NR_getcwd
+    ret += test_it (getcwd_syscall, "getcwd_syscall", 3);
+#endif
+    ret += test_it (getcwd_classic, "getcwd_classic", 0);
+#if linux
+    ret += test_it (getcwd_proc, "getcwd_proc", 0);
+#endif
+    return ret;
+}
diff --git a/src/tests/asu.c b/src/tests/asu.c
new file mode 100644 (file)
index 0000000..d69650d
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id$");
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <unistd.h>
+
+
+#include <err.h>
+
+static void
+usage(int exit_val)
+{
+    fprintf(stderr, "asu user program [arguments ...]\n");
+    exit(exit_val);
+}
+
+int
+main(int argc, char **argv)
+{
+    const char *user, *prog;
+
+
+    if (argc < 3)
+       usage(1);
+
+    user = argv[1];
+    prog = argv[2];
+
+    if (getuid() == 0) {
+       struct passwd *pw;
+       gid_t groups[1];
+       uid_t uid;
+       gid_t gid;
+
+       pw = getpwnam(user);
+       if(pw == NULL)
+           errx(1, "no such user %s", user);
+       
+       uid = pw->pw_uid;
+       gid = pw->pw_gid;
+       groups[0] = gid;
+       
+       if (setgroups(1, groups))
+           errx(1, "setgroups failed");
+
+       setgid(gid);
+       setuid(uid);
+       setegid(gid);
+       seteuid(uid);
+    }
+
+#if 0
+    if (k_hasafs()) {
+       int ret = k_setpag();
+       if (ret < 0)
+           warn("k_setpag");
+    }
+#endif
+    
+    execvp(prog, &argv[2]);
+
+    return 0;
+}
diff --git a/src/tests/blocks-new-file.c b/src/tests/blocks-new-file.c
new file mode 100644 (file)
index 0000000..d04a519
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <err.h>
+
+static void
+doit (const char *filename)
+{
+    int fd;
+    struct stat sb;
+
+    fd = open (filename, O_RDWR | O_TRUNC | O_CREAT, 0666);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    if (lseek (fd, (off_t)(1024*1024), SEEK_SET) != 1024*1024)
+       err (1, "lseek %s", filename);
+    if (write (fd, "hej", 3) != 3)
+       err (1, "write to %s", filename);
+    if (close (fd) < 0)
+       err (1, "close %s", filename);
+    if (stat (filename, &sb) < 0)
+       err (1, "stat %s", filename);
+    if (unlink (filename) < 0)
+       err (1, "unlink %s", filename);
+    if (sb.st_blocks == 0)
+       errx (1, "st_blocks == 0");
+}
+
+int
+main(int argc, char **argv)
+{
+
+    if (argc == 1)
+       doit ("foo");
+    else if (argc == 2)
+       doit (argv[1]);
+    else
+       errx (1, "usage: %s [filename]", argv[0]);
+    return 0;
+}
diff --git a/src/tests/boot-strap-arla b/src/tests/boot-strap-arla
new file mode 100644 (file)
index 0000000..beba197
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;exit 0; fi
+
+ARLA_RELEASE=${AFSROOT}/stacken.kth.se/ftp/pub/arla/arla-0.34.tar.gz
+
+mkdir src || exit 1
+mkdir obj || exit 1
+
+cd src || exit 1
+gzip -dc $ARLA_RELEASE | tar xf -
+cd ../obj || exit 1
+../src/*/configure || exit 1
+make || exit 1
+cd milko || exit 1
+make || exit 1
+exit 0
diff --git a/src/tests/bos.pm b/src/tests/bos.pm
new file mode 100644 (file)
index 0000000..9d85792
--- /dev/null
@@ -0,0 +1,679 @@
+# CMUCS AFStools
+# Copyright (c) 1996, Carnegie Mellon University
+# All rights reserved.
+#
+# See CMU_copyright.ph for use and distribution information
+#
+#: * bos.pm - Wrappers around BOS commands (basic overseer server)
+#: * This module provides wrappers around the various bosserver 
+#: * commands, giving them a nice perl-based interface.  Someday, they might
+#: * talk to the servers directly instead of using 'bos', but not anytime
+#: * soon.
+#:
+
+package OpenAFS::bos;
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT :afs_internal);
+use OpenAFS::wrapper;
+use Exporter;
+
+$VERSION   = '';
+$VERSION   = '1.00';
+@ISA       = qw(Exporter);
+@EXPORT    = qw(&AFS_bos_create        &AFS_bos_addhost
+               &AFS_bos_addkey        &AFS_bos_adduser
+               &AFS_bos_delete        &AFS_bos_exec
+               &AFS_bos_getdate       &AFS_bos_getlog
+               &AFS_bos_getrestart    &AFS_bos_install
+               &AFS_bos_listhosts     &AFS_bos_listkeys
+               &AFS_bos_listusers     &AFS_bos_prune
+               &AFS_bos_removehost    &AFS_bos_removekey
+               &AFS_bos_removeuser    &AFS_bos_restart
+               &AFS_bos_salvage       &AFS_bos_setauth
+               &AFS_bos_setcellname   &AFS_bos_setrestart
+               &AFS_bos_shutdown      &AFS_bos_start
+               &AFS_bos_startup       &AFS_bos_status
+               &AFS_bos_stop          &AFS_bos_uninstall);
+
+#: AFS_bos_addhost($server, $host, [$clone], [$cell])
+#: Add a new database server host named $host to the database
+#: on $server.
+#: If $clone is specified, create an entry for a clone server.
+#: On success, return 1.
+#:
+$AFS_Help{bos_addhost} = '$server, $host, [$clone], [$cell] => Success?';
+sub AFS_bos_addhost {
+  my($server, $host, $clone, $cell) = @_;
+  my(@args);
+
+  @args = ('addhost', '-server', $server, '-host', $host);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-clone') if ($clone);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_addkey($server, $key, $kvno, [$cell])
+#: Add a key $key with key version number $kvno on server $server
+#: On success, return 1.
+#:
+$AFS_Help{bos_addkey} = '$server, $key, $kvno, [$cell] => Success?';
+sub AFS_bos_addkey {
+  my($server, $key, $kvno, $cell) = @_;
+  my(@args);
+
+  @args = ('addkey', '-server', $server, '-key', $key, '-kvno', $kvno);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_adduser($server, \@user, [$cell])
+#: Add users specified in @users to bosserver superuser list on $server.
+#: On success, return 1.
+#:
+$AFS_Help{bos_adduser} = '$server, \@user, [$cell] => Success?';
+sub AFS_bos_adduser {
+  my($server, $user, $cell) = @_;
+  my(@args);
+
+  @args = ('adduser', '-server', $server, '-user', @$user);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_create($server, $instance, $type, \@cmd, [$cell])
+#: Create a bnode with name $instance
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_create} = '$server, $instance, $type, \@cmd, [$cell] => Success?';
+sub AFS_bos_create {
+  my($server, $instance, $type, $cmd, $cell) = @_;
+  my(@args);
+
+  @args = ('create', '-server', $server, '-instance', $instance, '-type', 
+          $type, '-cmd', @$cmd);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_delete($server, $instance, [$cell])
+#: Delete a bnode with name $instance
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_delete} = '$server, $instance, [$cell] => Success?';
+sub AFS_bos_delete {
+  my($server, $instance, $cell) = @_;
+  my(@args);
+
+  @args = ('delete', '-server', $server, '-instance', $instance);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_exec($server, $cmd, [$cell])
+#: Exec a process on server $server
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_exec} = '$server, $cmd, [$cell] => Success?';
+sub AFS_bos_exec {
+  my($server, $cmd, $cell) = @_;
+  my(@args);
+
+  @args = ('exec', '-server', $server, '-cmd', $cmd);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_getdate($server, $file, [$cell])
+#: Get the date for file $file from server $server 
+#: On success, return ($exedate, $bakdate, $olddate).
+#:
+$AFS_Help{bos_getdate} = '$server, $file, [$cell] => ($exedate, $bakdate, $olddate)';
+sub AFS_bos_getdate {
+  my($server, $file, $cell) = @_;
+  my(@args, $exedate, $bakdate, $olddate);
+
+  @args = ('getdate', '-server', $server, '-file', $file);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args,
+          [[ 'dated (.*), (no )?\.BAK', \$exedate],
+           [ '\.BAK file dated (.*), (no )?\.OLD', \$bakdate],
+           [ '\.OLD file dated (.*)\.', \$olddate]]);
+  ($exedate, $bakdate, $olddate);
+}
+
+#: AFS_bos_getlog($server, $file, [$cell])
+#: Get log named $file from server $server 
+#: On success, return 1.
+#:
+$AFS_Help{bos_getlog} = '$server, $file, [$cell] => Success?';
+sub AFS_bos_getlog {
+  my($server, $file, $cell) = @_;
+  my(@args);
+
+  @args = ('getlog', '-server', $server, '-file', $file);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args, 
+          [[ '^Fetching log file .*', '.']], { pass_stdout });
+  1;
+}
+
+#: AFS_bos_getrestart($server, [$cell])
+#: Get the restart time for server $server 
+#: On success, return ($genrestart, $binrestart).
+#:
+$AFS_Help{bos_getrestart} = '$server, [$cell] => ($genrestart, $binrestart)';
+sub AFS_bos_getrestart {
+  my($server, $cell) = @_;
+  my(@args, $genrestart, $binrestart);
+
+  @args = ('getrestart', '-server', $server);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args,
+          [[ '^Server .* restarts at\s*(.*\S+)', \$genrestart],
+           [ '^Server .* restarts for new binaries at\s*(.*\S+)', \$binrestart]]);
+  ($genrestart, $binrestart);
+}
+
+#: AFS_bos_install($server, \@files, [$dir], [$cell])
+#: Install files in \@files on server $server in directory $dir
+#: or the default directory.
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_install} = '$server, \@files, [$dir], [$cell] => Success?';
+sub AFS_bos_install {
+  my($server, $files, $dir, $cell) = @_;
+  my(@args, $file);
+
+  @args = ('install', '-server', $server, '-file', @$files);
+  push(@args, '-dir', $dir)        if ($dir);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args, [[ 'bos: installed file .*', '.' ]],
+          { 'errors_last' => 1 });
+  1;
+}
+
+#: AFS_bos_listhosts($server, [$cell])
+#: Get host list on server $server.
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, an array of hosts with the first entry being the cellname.
+#:
+$AFS_Help{bos_listhosts} = '$server, [$cell] => @ret';
+sub AFS_bos_listhosts {
+  my($server, $cell) = @_;
+  my(@args, @ret);
+
+  @args = ('listhosts', '-server', $server);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args, 
+          [[ '^Cell name is (.*)', sub { 
+              push(@ret, $_[0]);
+          } ],
+           [ 'Host \S+ is (\S+)', sub {
+               push(@ret, $_[0]);
+           } ]
+           ]);
+  @ret;
+}
+
+#: AFS_bos_listkeys($server, [$showkey], [$cell])
+#: Get key list on server $server.
+#: The server name ($server) may be a hostname or IP address
+#: If specified, $showkey indicates keys and not checksums should be shown.
+#: If specified, work in $cell instead of the default cell.
+#: On success, an array of hosts with the first entry being the cellname.
+#:
+$AFS_Help{bos_listkeys} = '$server, [$showkey], [$cell] => %ret';
+sub AFS_bos_listkeys {
+  my($server, $showkey, $cell) = @_;
+  my(@args, %ret);
+
+  @args = ('listkeys', '-server', $server);
+  push(@args, '-showkey')          if ($showkey);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  %ret = &wrapper('bos', \@args, 
+                 [[ '^key (\d+) has cksum (\d+)', sub {
+                     my(%ret) = %OpenAFS::wrapper::result;
+                     $ret{$_[0]} = $_[1];
+                     %OpenAFS::wrapper::result = %ret;
+                     } ],
+                  [ '^key (\d+) is \'(\S+)\'', sub {
+                     my(%ret) = %OpenAFS::wrapper::result;
+                      $ret{$_[0]} = $_[1];
+                     %OpenAFS::wrapper::result = %ret;
+                      } ],
+                  [ '^Keys last changed on\s*(.*\S+)', sub {
+                     my(%ret) = %OpenAFS::wrapper::result;
+                      $ret{'date'} = $_[0];
+                     %OpenAFS::wrapper::result = %ret;
+                     } ],
+                  [ 'All done.', '.']]);
+  %ret;
+}
+
+#: AFS_bos_listusers($server, [$cell])
+#: Get superuser list on server $server.
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, an array of users.
+#:
+$AFS_Help{bos_listusers} = '$server, [$cell] => @ret';
+sub AFS_bos_listusers {
+  my($server, $cell) = @_;
+  my(@args, @ret);
+
+  @args = ('listusers', '-server', $server);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args, [[ '^SUsers are: (\S+)', sub { 
+      push(@ret, split(' ',$_[0]));
+  } ]]);
+  @ret;
+}
+
+#: AFS_bos_prune($server, [$bak], [$old], [$core], [$all], [$cell])
+#: Prune files on server $server
+#: If $bak is specified, remove .BAK files
+#: If $old is specified, remove .OLD files
+#: If $core is specified, remove core files
+#: If $all is specified, remove all junk files
+#: On success, return 1.
+#:
+$AFS_Help{bos_prune} = '$server, [$bak], [$old], [$core], [$all], [$cell] => Success?';
+sub AFS_bos_prune {
+  my($server, $bak, $old, $core, $all, $cell) = @_;
+  my(@args);
+
+  @args = ('prune', '-server', $server, '-bak', $bak, '-old', $old, '-core', $core, '-all', $all);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-bak') if ($bak);
+  push(@args, '-old') if ($old);
+  push(@args, '-core') if ($core);
+  push(@args, '-all') if ($all);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_removehost($server, $host, [$cell])
+#: Remove a new database server host named $host from the database
+#: on $server.
+#: On success, return 1.
+#:
+$AFS_Help{bos_removehost} = '$server, $host, [$cell] => Success?';
+sub AFS_bos_removehost {
+  my($server, $host, $cell) = @_;
+  my(@args);
+
+  @args = ('removehost', '-server', $server, '-host', $host);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_removekey($server, $kvno, [$cell])
+#: Remove a key with key version number $kvno on server $server
+#: On success, return 1.
+#:
+$AFS_Help{bos_removekey} = '$server, $kvno, [$cell] => Success?';
+sub AFS_bos_removekey {
+  my($server, $kvno, $cell) = @_;
+  my(@args);
+
+  @args = ('removekey', '-server', $server, '-kvno', $kvno);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_removeuser($server, \@user, [$cell])
+#: Remove users specified in @users to bosserver superuser list on $server.
+#: On success, return 1.
+#:
+$AFS_Help{bos_removeuser} = '$server, \@user, [$cell] => Success?';
+sub AFS_bos_removeuser {
+  my($server, $user, $cell) = @_;
+  my(@args);
+
+  @args = ('removeuser', '-server', $server, '-user', @$user);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_restart($server, [\@inst], [$bosserver], [$all], [$cell])
+#: Restart bosserver instances specified in \@inst, or if $all is
+#: specified, all instances.
+#: If $bosserver is specified, restart the bosserver.
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_restart} = '$server, [\@inst], [$bosserver], [$all], [$cell] => Success?';
+sub AFS_bos_restart {
+  my($server, $inst, $bosserver, $all, $cell) = @_;
+  my(@args);
+
+  @args = ('restart', '-server', $server);
+  push(@args, '-instance', @$inst) if ($inst);
+  push(@args, '-bosserver')        if ($bosserver);
+  push(@args, '-all')              if ($all);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_salvage($server, [$partition], [$volume], [$file], [$all], [$showlog], [$parallel], [$tmpdir], [$orphans], [$cell])
+#: Invoke the salvager, providing a partition $partition if specified, and 
+#: further a volume id $volume if specified. 
+#: If specified, $file is a file to write the salvager output into.
+#: If specified, $all indicates all partitions should be salvaged.
+#: If specified, $showlog indicates the log should be displayed on completion.
+#: If specified, $parallel indicates the number salvagers that should be run
+#: in parallel.
+#: If specified, $tmpdir indicates a directory in which to store temporary 
+#: files.
+#: If specified, $orphans indicates how to handle orphans in a volume
+#: (valid options are ignore, remove and attach).
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_salvage} = '$server, [$partition], [$volume], [$file], [$all], [$showlog], [$parallel], [$tmpdir], [$orphans], [$cell] => Success?';
+sub AFS_bos_salvage {
+  my($server, $partition, $volume, $file, $all, $showlog, $parallel, $tmpdir, $orphans, $cell) = @_;
+  my(@args);
+
+  @args = ('salvage', '-server', $server);
+  push(@args, '-partition', $partition)if ($partition);
+  push(@args, '-volume', $volume)      if ($volume);
+  push(@args, '-file', $file)      if ($file);
+  push(@args, '-all')              if ($all);
+  push(@args, '-showlog')          if ($showlog);
+  push(@args, '-parallel', $parallel)  if ($parallel);
+  push(@args, '-tmpdir', $tmpdir)  if ($tmpdir);
+  push(@args, '-orphans', $orphans)if ($orphans);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args, [['bos: shutting down fs.', '.'],
+                          ['Starting salvage.', '.'],
+                          ['bos: waiting for salvage to complete.', '.'],
+                          ['bos: salvage completed', '.'],
+                          ['bos: restarting fs.', '.']],
+          { 'errors_last' => 1 });
+  1;
+}
+
+#: AFS_bos_setauth($server, $authrequired, [$cell])
+#: Set the authentication required flag for server $server to 
+#: $authrequired.
+#: On success, return 1.
+#:
+$AFS_Help{bos_setauth} = '$server, $authrequired, [$cell] => Success?';
+sub AFS_bos_setauth {
+  my($server, $authrequired, $cell) = @_;
+  my(@args);
+
+  @args = ('setauth', '-server', $server, '-authrequired', $authrequired);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_setcellname($server, $name, [$cell])
+#: Set the cellname for server $server to $name
+#: On success, return 1.
+#:
+$AFS_Help{bos_setcellname} = '$server, $name, [$cell] => Success?';
+sub AFS_bos_setcellname {
+  my($server, $name, $cell) = @_;
+  my(@args);
+
+  @args = ('setcellname', '-server', $server, '-name', $name);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_setrestart($server, $time, [$general], [$newbinary], [$cell])
+#: Set the restart time for server $server to $time
+#: If specified, $general indicates only the general restart time should be 
+#: set.
+#: If specified, $newbinary indicates only the binary restart time should be 
+#: set.
+#: On success, return 1.
+#:
+$AFS_Help{bos_setrestart} = '$server, $time, [$general], [$newbinary], [$cell] => Success?';
+sub AFS_bos_setrestart {
+  my($server, $time, $general, $newbinary, $cell) = @_;
+  my(@args);
+
+  @args = ('setrestart', '-server', $server, '-time', $time);
+  push(@args, '-general')          if ($general);
+  push(@args, '-newbinary')        if ($newbinary);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_shutdown($server, [\@inst], [$wait], [$cell])
+#: Stop all bosserver instances or if \@inst is specified,
+#: only those in \@inst on server $server 
+#: waiting for them to stop if $wait is specified.
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_shutdown} = '$server, [\@inst], [$wait], [$cell] => Success?';
+sub AFS_bos_shutdown {
+  my($server, $inst, $wait, $cell) = @_;
+  my(@args);
+
+  @args = ('shutdown', '-server', $server);
+  push(@args, '-instance', @$inst) if ($inst);
+  push(@args, '-wait')             if ($wait);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_start($server, \@inst, [$cell])
+#: Start bosserver instances in \@inst on server $server .
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_start} = '$server, \@inst, [$cell] => Success?';
+sub AFS_bos_start {
+  my($server, $inst, $cell) = @_;
+  my(@args);
+
+  @args = ('start', '-server', $server, '-instance', @$inst);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_startup($server, [\@inst], [$cell])
+#: Start all bosserver instances or if \@inst is specified, only
+#: those in \@inst on server $server .
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_startup} = '$server, [\@inst], [$cell] => Success?';
+sub AFS_bos_startup {
+  my($server, $inst, $cell) = @_;
+  my(@args);
+
+  @args = ('startup', '-server', $server);
+  push(@args, '-instance', @$inst) if ($inst);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_status($server, [\@bnodes], [$cell])
+#: Get status for the specified bnodes on $server, or for all bnodes
+#: if none are given.
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return an associative array whose keys are the names
+#: of bnodes on the specified server, and each of whose values is
+#: an associative array describing the status of the corresponding
+#: bnode, containing some or all of the following elements:
+#: - name         Name of this bnode (same as key)
+#: - type         Type of bnode (simple, cron, fs)
+#: - status       Basic status
+#: - aux_status   Auxillary status string, for bnode types that provide it
+#: - num_starts   Number of process starts
+#: - last_start   Time of last process start
+#: - last_exit    Time of last exit
+#: - last_error   Time of last error exit
+#: - error_code   Exit code from last error exit
+#: - error_signal Signal from last error exit
+#: - commands     Ref to list of commands
+#:
+$AFS_Help{bos_status} = '$server, [\@bnodes], [$cell] => %bnodes';
+sub AFS_bos_status {
+  my($server, $bnodes, $cell) = @_;
+  my(@args, %finres, %blist, @cmds);
+
+  @args = ('status', '-server', $server, '-long');
+  push(@args, '-instance', @$bnodes) if ($bnodes);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  %finres = &wrapper('bos', \@args,
+           [['^(Instance)', sub {
+              my(%binfo) = %OpenAFS::wrapper::result;
+
+              if ($binfo{name}) {
+                $binfo{commands} = [@cmds] if (@cmds);
+                $blist{$binfo{name}} = \%binfo;
+
+                @cmds = ();
+                %OpenAFS::wrapper::result = ();
+              }
+            }],
+            ['^Instance (.*), \(type is (\S+)\)\s*(.*)',            'name', 'type', 'status'   ],
+            ['Auxilliary status is: (.*)\.',                        'aux_status'               ],
+            ['Process last started at (.*) \((\d+) proc starts\)',  'last_start', 'num_starts' ],
+            ['Last exit at (.*\S+)',                                'last_exit'                ],
+            ['Last error exit at (.*),',                            'last_error'               ],
+            ['by exiting with code (\d+)',                          'error_code'               ],
+            ['due to signal (\d+)',                                 'error_signal'             ],
+            [q/Command \d+ is '(.*)'/, sub { push(@cmds, $_[0]) }],
+           ]);
+  if ($finres{name}) {
+    $finres{commands} = [@cmds] if (@cmds);
+    $blist{$finres{name}} = \%finres;
+  }
+  %blist;
+}
+
+#: AFS_bos_stop($server, \@inst, [$wait], [$cell])
+#: Stop bosserver instances in \@inst on server $server 
+#: waiting for them to stop if $wait is specified.
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_stop} = '$server, \@inst, [$wait], [$cell] => Success?';
+sub AFS_bos_stop {
+  my($server, $inst, $wait, $cell) = @_;
+  my(@args);
+
+  @args = ('stop', '-server', $server, '-instance', @$inst);
+  push(@args, '-wait')             if ($wait);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args);
+  1;
+}
+
+#: AFS_bos_uninstall($server, \@files, [$dir], [$cell])
+#: Uninstall files in \@files on server $server in directory $dir
+#: or the default directory.
+#: The server name ($server) may be a hostname or IP address
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{bos_uninstall} = '$server, \@files, [$dir], [$cell] => Success?';
+sub AFS_bos_uninstall {
+  my($server, $files, $dir, $cell) = @_;
+  my(@args);
+
+  @args = ('uninstall', '-server', $server, '-file', @$files);
+  push(@args, '-dir', $dir) if ($dir);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('bos', \@args, [[ '^bos: uninstalled file .*', '.' ]],
+          { 'errors_last' => 1 });
+  1;
+}
+
+1;
diff --git a/src/tests/bosaddhost.pl b/src/tests/bosaddhost.pl
new file mode 100755 (executable)
index 0000000..549ecb7
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_addhost(localhost,"128.2.1.2",,);
+
+exit(0);
+
+
+
diff --git a/src/tests/bosaddkey.pl b/src/tests/bosaddkey.pl
new file mode 100755 (executable)
index 0000000..6a5e596
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_addkey(localhost,"\000\001\002\003\004\005\006\007",250,);
+
+exit(0);
+
+
+
diff --git a/src/tests/bosadduser.pl b/src/tests/bosadduser.pl
new file mode 100755 (executable)
index 0000000..7495042
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_adduser(localhost,[testuser1],);
+
+exit(0);
+
+
+
diff --git a/src/tests/boscreate.pl b/src/tests/boscreate.pl
new file mode 100755 (executable)
index 0000000..9161e9d
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, $ret);
+$host = `hostname`;
+&AFS_Init();
+
+open(FOO, ">sleeper.sh"); 
+print FOO "#!/bin/sh\n";
+print FOO "while true; do sleep 60; done\n";
+print FOO "exit 0\n";
+close FOO;
+chmod 0755, "sleeper.sh";
+
+&AFS_bos_install(localhost,["sleeper.sh"],,);
+&AFS_bos_create(localhost,sleeper,simple,["/usr/afs/bin/sleeper.sh"],);
+
+exit(0);
+
+
+
diff --git a/src/tests/bosdelete.pl b/src/tests/bosdelete.pl
new file mode 100755 (executable)
index 0000000..6d0819b
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, $ret);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_delete(localhost,sleeper,);
+
+exit(0);
+
+
+
diff --git a/src/tests/bosdeleterunning.pl b/src/tests/bosdeleterunning.pl
new file mode 100755 (executable)
index 0000000..db96930
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, $ret);
+$host = `hostname`;
+&AFS_Init();
+
+eval { &AFS_bos_delete(localhost,sleeper,); };
+
+if (! $@) {
+    exit (1);
+}
+exit(0);
+
+
+
diff --git a/src/tests/bosexec.pl b/src/tests/bosexec.pl
new file mode 100755 (executable)
index 0000000..37a3487
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+use OpenAFS::ConfigUtils;
+use OpenAFS::Dirpath;
+use OpenAFS::OS;
+
+my ($host);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_exec(localhost,"$openafsdirpath->{'afssrvbindir'}/foo.sh",);
+if (-f "/usr/tmp/garbage") {
+} else {
+    exit(1);
+}
+unlink "/usr/tmp/garbage";
+exit(0);
+
+
+
diff --git a/src/tests/bosinstall.pl b/src/tests/bosinstall.pl
new file mode 100755 (executable)
index 0000000..ddaa7c2
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host);
+$host = `hostname`;
+&AFS_Init();
+
+open(FOO, ">foo.sh"); 
+print FOO "#!/bin/sh\n";
+print FOO "touch /usr/tmp/garbage\n";
+print FOO "exit 0\n";
+close FOO;
+chmod 0755, "foo.sh";
+
+&AFS_bos_install(localhost,["foo.sh"],,);
+
+exit(0);
+
+
+
diff --git a/src/tests/boslisthosts.pl b/src/tests/boslisthosts.pl
new file mode 100755 (executable)
index 0000000..dfab1ab
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, @hosts, $this, $cell, $cnt);
+$host = `hostname`;
+chomp $host;
+&AFS_Init();
+$cell = &AFS_fs_wscell();
+
+@hosts = &AFS_bos_listhosts(localhost,);
+$this = shift(@hosts);
+if ($this ne $cell) {
+    exit (1);
+}
+while ($this = shift(@hosts)) {
+    if ($this ne $host) {
+       if (($this ne "128.2.1.2")) {
+           exit (1);
+       }
+    }
+}
+exit(0);
+
+
+
diff --git a/src/tests/boslistkeys.pl b/src/tests/boslistkeys.pl
new file mode 100755 (executable)
index 0000000..77affa4
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, @hosts, $this, $cell, $cnt, %ret);
+$host = `hostname`;
+chomp $host;
+&AFS_Init();
+$cell = &AFS_fs_wscell();
+
+%ret = &AFS_bos_listkeys(localhost,,);
+foreach $this (keys %ret) {
+    if ($this == 250) {
+       if ($ret{250} ne 3288840443) {
+           exit(1);
+       }
+    }
+}
+exit(0);
+
+
+
diff --git a/src/tests/boslistusers.pl b/src/tests/boslistusers.pl
new file mode 100755 (executable)
index 0000000..b9fc7c9
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, @hosts, $this, $cell, $cnt);
+$host = `hostname`;
+chomp $host;
+&AFS_Init();
+
+@hosts = &AFS_bos_listusers(localhost,);
+while ($this = shift(@hosts)) {
+    if ($this ne "admin") {
+       if (($this ne "testuser1")) {
+           exit (1);
+       }
+    }
+}
+exit(0);
+
+
+
diff --git a/src/tests/bosremovehost.pl b/src/tests/bosremovehost.pl
new file mode 100755 (executable)
index 0000000..5a8133e
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, @hosts, $this, $cell, $cnt);
+$host = `hostname`;
+chomp $host;
+&AFS_Init();
+$cell = &AFS_fs_wscell();
+
+&AFS_bos_removehost(localhost,"128.2.1.2",);
+@hosts = &AFS_bos_listhosts(localhost,);
+$this = shift(@hosts);
+if ($this ne $cell) {
+    exit (1);
+}
+while ($this = shift(@hosts)) {
+    if ($this ne $host) {
+       exit (1);
+    }
+}
+exit(0);
+
+
+
diff --git a/src/tests/bosremovekey.pl b/src/tests/bosremovekey.pl
new file mode 100755 (executable)
index 0000000..3c1a923
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, @hosts, $this, $cell, $cnt, %ret);
+$host = `hostname`;
+chomp $host;
+&AFS_Init();
+$cell = &AFS_fs_wscell();
+
+&AFS_bos_removekey(localhost,250,);
+foreach $this (keys %ret) {
+    if ($this == 250) {
+       exit(1);
+    }
+}
+exit(0);
+
+
+
diff --git a/src/tests/bosremoveuser.pl b/src/tests/bosremoveuser.pl
new file mode 100755 (executable)
index 0000000..75cc014
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, @hosts, $this, $cell, $cnt);
+$host = `hostname`;
+chomp $host;
+&AFS_Init();
+$cell = &AFS_fs_wscell();
+
+&AFS_bos_removeuser(localhost,[testuser1],);
+@hosts = &AFS_bos_listusers(localhost,);
+while ($this = shift(@hosts)) {
+    if ($this ne "admin") {
+       exit (1);
+    }
+}
+exit(0);
+
+
+
diff --git a/src/tests/bosrestartstopped.pl b/src/tests/bosrestartstopped.pl
new file mode 100755 (executable)
index 0000000..7b5f59f
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, %info, %info2, $linfo);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_restart(localhost,[sleeper],,,);
+%info = &AFS_bos_status("localhost",[sleeper],);
+$linfo=$info{'sleeper'};
+%info2 = %$linfo;
+if ($info2{'num_starts'} != 2) {
+    exit 1;
+}
+if ($info2{'status'} ne "temporarily enabled, currently running normally.") {
+    exit 1;
+}
+exit(0);
+
+
+
diff --git a/src/tests/bossalvagepart.pl b/src/tests/bossalvagepart.pl
new file mode 100755 (executable)
index 0000000..87cdc53
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, $ret);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_salvage("localhost","a",,,,,,,);
+
+exit(0);
+
+
+
diff --git a/src/tests/bossalvageserver.pl b/src/tests/bossalvageserver.pl
new file mode 100755 (executable)
index 0000000..9b6fcd7
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, $ret);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_salvage("localhost",,,,1,,,,);
+
+exit(0);
+
+
+
diff --git a/src/tests/bossalvagevolume.pl b/src/tests/bossalvagevolume.pl
new file mode 100755 (executable)
index 0000000..f3bc1ed
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, $ret);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_salvage("localhost","a","unrep",,,,,,);
+
+exit(0);
+
+
+
diff --git a/src/tests/bosshutdown.pl b/src/tests/bosshutdown.pl
new file mode 100755 (executable)
index 0000000..a5cff46
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, %info, %info2, $linfo);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_shutdown(localhost,[sleeper],1,);
+%info = &AFS_bos_status("localhost",[sleeper],);
+$linfo=$info{'sleeper'};
+%info2 = %$linfo;
+if ($info2{'num_starts'} != 2) {
+    exit 1;
+}
+if ($info2{'status'} ne "temporarily disabled, currently shutdown.") {
+    exit 1;
+}
+exit(0);
+
+
+
diff --git a/src/tests/bosstart.pl b/src/tests/bosstart.pl
new file mode 100755 (executable)
index 0000000..2f8d9a5
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, %info, %info2, $linfo);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_start(localhost,[sleeper],);
+%info = &AFS_bos_status("localhost",[sleeper],);
+$linfo=$info{'sleeper'};
+%info2 = %$linfo;
+if ($info2{'num_starts'} != 2) {
+    exit 1;
+}
+if ($info2{'status'} ne "currently running normally.") {
+    exit 1;
+}
+exit(0);
+
+
+
diff --git a/src/tests/bosstatus.pl b/src/tests/bosstatus.pl
new file mode 100755 (executable)
index 0000000..37428b5
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, %info, %info2, $linfo);
+$host = `hostname`;
+&AFS_Init();
+
+%info = &AFS_bos_status("localhost",[sleeper],);
+$linfo=$info{'sleeper'};
+%info2 = %$linfo;
+if ($info2{'num_starts'} != 1) {
+    exit 1;
+}
+if ($info2{'status'} ne "currently running normally.") {
+    exit 1;
+}
+exit(0);
+
+
+
diff --git a/src/tests/bosstop.pl b/src/tests/bosstop.pl
new file mode 100755 (executable)
index 0000000..ff34697
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT %AFS_Help);
+use OpenAFS::afsconf;
+use OpenAFS::fs;
+use OpenAFS::pts;
+use OpenAFS::vos;
+use OpenAFS::bos;
+
+my ($host, %info, %info2, $linfo);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_bos_stop(localhost,[sleeper],1,);
+%info = &AFS_bos_status("localhost",[sleeper],);
+$linfo=$info{'sleeper'};
+%info2 = %$linfo;
+if ($info2{'num_starts'} != 1) {
+    exit 1;
+}
+if ($info2{'status'} ne "disabled, currently shutdown.") {
+    exit 1;
+}
+exit(0);
+
+
+
diff --git a/src/tests/build-and-run-rcs b/src/tests/build-and-run-rcs
new file mode 100755 (executable)
index 0000000..744281f
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+set -x
+# $Id$
+##if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+echo -n pwd before is ' '
+pwd
+#
+# copied from generic-build because rcs wants to put (hard)links into tar balls.
+#
+filename=$AFSROOT/stacken.kth.se/ftp/pub/gnu/rcs/rcs-5.7.tar.gz
+b=rcs-5.7
+obj=$b-obj
+gzip -dc $filename | tar xvf - >&4 2>&1
+mkdir $obj || exit 1
+cd $obj || exit 1
+../$b/configure >&4 || exit 1
+make $MAKEFLAGS || exit 1
+echo -n pwd after is ' '
+pwd
+echo row1 > testfile
+echo log1 | ./src/ci -u testfile
+./src/co -l testfile
+echo row2 >> testfile
+echo log2 | ./src/ci -u testfile
+./src/co -l testfile
+echo row3 >> testfile
+echo log3 | ./src/ci -u testfile
+wc -l testfile | grep '3 testfile' || exit 1
+
diff --git a/src/tests/build-emacs b/src/tests/build-emacs
new file mode 100755 (executable)
index 0000000..d5cfb5b
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+$SHELL $SHELLVERBOSE $srcdir/generic-build $AFSROOT/stacken.kth.se/ftp/pub/gnu/emacs/emacs-20.7.tar.gz emacs-20.7
diff --git a/src/tests/build-emacs-j b/src/tests/build-emacs-j
new file mode 100644 (file)
index 0000000..3cac279
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+env MAKEFLAGS="-j" $SHELL $SHELLVERBOSE $srcdir/generic-build $AFSROOT/stacken.kth.se/ftp/pub/gnu/emacs/emacs-20.7.tar.gz emacs-20.7
diff --git a/src/tests/build-gdb b/src/tests/build-gdb
new file mode 100755 (executable)
index 0000000..f030054
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+$SHELL $SHELLVERBOSE $srcdir/generic-build $AFSROOT/stacken.kth.se/ftp/pub/gnu/gdb/gdb-5.0.tar.gz
diff --git a/src/tests/build-openafs b/src/tests/build-openafs
new file mode 100755 (executable)
index 0000000..8a14add
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id$
+FS=${FS:-${objdir}/../appl/fs/fs}
+
+${FS} sq . 0
+wget http://www.openafs.org/dl/1.2.2/openafs-1.2.2-src.tar.gz >& 4
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+$SHELL $SHELLVERBOSE $srcdir/generic-build openafs-1.2.2-src.tar.gz openafs-1.2.2
+openafs-1.2.2/src/finale/translate_et 180480 >& /dev/null
diff --git a/src/tests/checkpwd b/src/tests/checkpwd
new file mode 100755 (executable)
index 0000000..502a3dd
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+# $Id$
+$objdir/apwd
diff --git a/src/tests/compare-inum-mp b/src/tests/compare-inum-mp
new file mode 100755 (executable)
index 0000000..ce92bcf
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+# $Id$
+FS=${FS:-${objdir}/../appl/fs/fs}
+${FS} sa . system:anyuser all || exit 1
+${FS} mkm root.cell root.cell || exit 1
+$objdir/readdir-vs-lstat . || exit 1
+$objdir/readdir-vs-lstat root.cell || exit 1
+${FS} rmm root.cell || exit 1
diff --git a/src/tests/compare-inums b/src/tests/compare-inums
new file mode 100755 (executable)
index 0000000..614560d
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id$
+$objdir/create-files 100 0 || exit 1
+$objdir/readdir-vs-lstat . || exit 1
diff --git a/src/tests/compare-with-local b/src/tests/compare-with-local
new file mode 100755 (executable)
index 0000000..8c7a495
--- /dev/null
@@ -0,0 +1,77 @@
+#!/bin/sh
+# $Id$
+#################################################################
+#
+# Copy file back and forth between $TMPDIR (defaults to /tmp)
+# which is hopefully on local disk or any other well tested
+# file system and the filesystem we want to test (in $PWD).
+#
+#################################################################
+
+test $SHELLVERBOSE && set $SHELLVERBOSE
+
+function compare () {
+    if cmp $1 $2; then
+       :
+    else
+       diff $1 $2
+       exit 1
+    fi
+}
+
+test $TMPDIR || TMPDIR=/tmp
+TMPDIR=$TMPDIR/compare-with-local-$$
+mkdir $TMPDIR || exit 1
+
+# Generate test file
+cat > $TMPDIR/bar << EOF
+This is an arla temporary test file.
+You may remove it any time.
+Kontrollen blinkar blå.
+EOF
+
+cp $TMPDIR/bar bar
+compare $TMPDIR/bar bar
+mv bar $TMPDIR/bas
+compare $TMPDIR/bar $TMPDIR/bas
+ # this is for later overwrite test
+ test -f bar && echo bar should not exist && exit 1
+ cp $TMPDIR/bar bar
+ compare $TMPDIR/bar bar
+cat $TMPDIR/bas > bat
+compare $TMPDIR/bar bat
+cat bat > $TMPDIR/bau
+compare $TMPDIR/bar $TMPDIR/bau
+mv $TMPDIR/bau bav
+compare $TMPDIR/bar bav
+ # this is for later overwrite test
+ test -f $TMPDIR/bau && echo $TMPDIR/bau should not exist && exit 1
+ cp $TMPDIR/bar $TMPDIR/bau 
+cp bav $TMPDIR/baw
+compare $TMPDIR/bar $TMPDIR/baw
+
+# If we get so far we can write new files. 
+# Now test overwrite.
+
+# Generate test file slightly different
+cat > $TMPDIR/bar << EOF
+This is an arla temporary test file.
+You may remove it any time.
+Mera jul.
+EOF
+
+cp $TMPDIR/bar bar
+compare $TMPDIR/bar bar
+mv bar $TMPDIR/bas
+compare $TMPDIR/bar $TMPDIR/bas
+cat $TMPDIR/bas > bat
+compare $TMPDIR/bar bat
+cat bat > $TMPDIR/bau
+compare $TMPDIR/bar $TMPDIR/bau
+mv $TMPDIR/bau bav
+compare $TMPDIR/bar bav
+cp bav $TMPDIR/baw
+compare $TMPDIR/bar $TMPDIR/baw
+
+${objdir}/rm-rf $TMPDIR
+exit 0
diff --git a/src/tests/config.pm b/src/tests/config.pm
new file mode 100644 (file)
index 0000000..0de0a54
--- /dev/null
@@ -0,0 +1,125 @@
+# CMUCS AFStools
+# Copyright (c) 1996, Carnegie Mellon University
+# All rights reserved.
+#
+# See CMU_copyright.pm for use and distribution information
+
+package OpenAFS::config;
+
+=head1 NAME
+
+OpenAFS::config - AFStools configuration
+
+=head1 SYNOPSIS
+
+  use OpenAFS::config;
+
+=head1 DESCRIPTION
+
+This module contains various AFStools configuration variables which are used
+by the other AFStools modules.  These describe how AFStools should act in a
+particular installation, and are mostly pretty mundane.  All of the defaults
+here are pretty reasonable, so you shouldn't have to change anything unless
+your site is particularly exotic.
+
+Note that this file only describes how a particular B<installation> of AFStools
+should act, not how it should act upon a particular B<cell>.  Since the cell
+AFStools is running in is not necessarily the same as the cell on which it
+is acting, most configuration that is really per-cell should be located in a
+cell-specific module.
+
+This module should only be used by other parts of AFStools.  As such, the
+variables described here are not normally visible to user programs, and this
+file is mostly of interest to administrators who are installing AFStools.
+
+=over 4
+
+=cut
+
+use OpenAFS::CMU_copyright;
+use OpenAFS::Dirpath;
+use Exporter;
+
+$VERSION   = '';
+$VERSION   = '1.00';
+@ISA       = qw(Exporter);
+@EXPORT    = qw($def_ConfDir
+                @CmdList
+                @CmdPath
+                $err_table_dir
+               );
+
+# The following configuration variables are defined here.  Mention them
+# all an extra time, to suppress annoying warnings.  Doesn't perl have
+# a way of doing this???
+@x = ();
+@x = ($def_ConfDir, @CmdList, @CmdPath);
+
+=item $def_ConfDir - Default configuration directory
+
+This is the default AFS configuration directory, where files like ThisCell,
+CellServDB, and so on are found.  If the AFStools parameter I<confdir> is
+set, it will generally be searched before this directory.  Normally, this
+should be set to F</usr/vice/etc> and not changed, as that path is hardwired
+into AFS.  However, it might be necessary to modify this if your site uses
+an exotic locally-compiled version of AFS.
+
+=cut
+
+$def_ConfDir = "$openafsdirpath->{'viceetcdir'}";
+#$def_ConfDir = "/usr/vice/etc";
+
+
+=item @CmdList - List of AFS commands
+
+This is a list of AFS commands that the AFStools package might want to invoke
+using B<OpenAFS::wrapper::wrapper>.  Don't remove anything from this list if you
+know what's good for you.  It's OK to add things, though, if you think you
+might use the wrapper features for something.
+
+=cut
+
+@CmdList = ('fs', 'pts', 'vos', 'bos', 'kas', 'krbkas', 'sys');
+
+
+=item @CmdPath - Path to search for AFS commands
+
+This is the list of directories where B<OpenAFS::wrapper::wrapper> will look for
+AFS commands.  For AFStools to work properly, every command listed in
+I<@OpenAFS::config::CmdList> must appear in one of these directories.  The default
+should be sufficient for most sites; we deal with Transarc's reccommendations
+as well as common practice.  Note that on machines for which /usr/afs/bin
+exists (typically, AFS fileservers), that directory is first.  This is probably
+what you want...
+
+=cut
+
+@CmdPath = (split(/:/, $ENV{PATH}),
+            "$openafsdirpath->{'afssrvbindir'}",        # For servers
+           '/usr/local/bin',      # Many sites put AFS in /usr/local
+           '/usr/local/etc',
+           '/usr/afsws/bin',      # For people who use Transarc's
+           '/usr/afsws/etc');     # silly reccommendations
+
+=item $err_table_dir - Error table directory
+
+This is the location of error tables used by the errcode and errstr
+routines in OpenAFS::errtrans.  Each file in this directory should be a
+com_err error table (in source form), and should be named the same
+as the com_err error package contained within.
+
+=cut
+
+$err_table_dir = '/usr/local/lib/errtbl';
+
+1;
+
+=back
+
+=head1 COPYRIGHT
+
+The CMUCS AFStools, including this module are
+Copyright (c) 1996, Carnegie Mellon University.  All rights reserved.
+For use and redistribution information, see CMUCS/CMU_copyright.pm
+
+=cut
diff --git a/src/tests/copy-and-diff-gnu-mirror b/src/tests/copy-and-diff-gnu-mirror
new file mode 100755 (executable)
index 0000000..3f608a8
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+if test "X$LARGE" = "X" ; then echo "Not running large test $0" ;  exit 0 ; fi
+original=${1-$AFSROOT/stacken.kth.se/ftp/pub}
+(cd $original; tar cvf - gnu) 2>&4 | tar xvf - >&4
+find gnu -type f -exec cmp '{}' $original/'{}' \;
diff --git a/src/tests/copy-file b/src/tests/copy-file
new file mode 100755 (executable)
index 0000000..ade0946
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/sh
+# $Id$
+cat > foo <<EOF
+hej love
+
+ska vi g|ra r{tt nu.
+EOF
+
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+cp foo foo2 || exit 1
+exit 0
diff --git a/src/tests/creat1 b/src/tests/creat1
new file mode 100755 (executable)
index 0000000..9bdf2b5
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+> foobar
+test -f foobar || exit 1
+test -s foobar && exit 1
+rm foobar || exit 1
diff --git a/src/tests/create-dirs.c b/src/tests/create-dirs.c
new file mode 100644 (file)
index 0000000..9864cdd
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id$");
+#endif
+
+static int
+creat_dirs (int count)
+{
+    int i;
+    
+    for (i = 0; i < count; ++i) {
+       char num[17];
+       int ret;
+
+       snprintf (num, sizeof(num), "%d", i);
+       
+       ret = mkdir (num, 0777);
+       if (ret < 0)
+           err (1, "mkdir %s", num);
+    }
+    return 0;
+}
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s number-of-dirs\n", __progname);
+    exit (ret);
+}
+
+int
+main(int argc, char **argv)
+{
+    char *ptr;
+    int count;
+
+
+    if (argc != 2)
+       usage (1);
+
+    count = strtol (argv[1], &ptr, 0);
+    if (count == 0 && ptr == argv[1])
+       errx (1, "'%s' not a number", argv[1]);
+
+    return creat_dirs (count);
+}
diff --git a/src/tests/create-files.c b/src/tests/create-files.c
new file mode 100644 (file)
index 0000000..50eca70
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+
+#undef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#undef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+#ifdef RCSID
+RCSID("$Id$");
+#endif
+
+static int
+creat_files (int count, long startsize)
+{
+    int i;
+    long size = 0;
+    
+    for (i = 0; i < count; ++i) {
+       char num[17];
+       int fd;
+
+       snprintf (num, sizeof(num), "%d", i);
+       
+       fd = open (num, O_WRONLY | O_CREAT | O_EXCL, 0777);
+       if (fd < 0)
+           err (1, "open %s", num);
+       size = startsize;
+       while (size > 0) {
+           char buf[8192];
+           size_t len;
+           ssize_t ret;
+
+           len = min(sizeof(buf), size);
+
+           ret = write (fd, buf, len);
+           if (ret < 0)
+               err (1, "write to %s", num);
+           if (ret != len)
+               errx (1, "short write to %s", num);
+           size -= ret;
+       }
+       if (close (fd) < 0)
+           err (1, "close %s", num);
+    }
+    return 0;
+}
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s number-of-files size-of-files\n", __progname);
+    exit (ret);
+}
+
+int
+main(int argc, char **argv)
+{
+    char *ptr;
+    int count;
+    long size;
+
+
+    if (argc != 3)
+       usage (1);
+
+    count = strtol (argv[1], &ptr, 0);
+    if (count == 0 && ptr == argv[1])
+       errx (1, "'%s' not a number", argv[1]);
+
+    size = strtol (argv[2], &ptr, 0);
+    if (size == 0 && ptr == argv[2])
+       errx (1, "`%s' not a number", argv[2]);
+
+    return creat_files (count, size);
+}
diff --git a/src/tests/create-remove-dirs b/src/tests/create-remove-dirs
new file mode 100644 (file)
index 0000000..58175ab
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+$objdir/create-remove dir 1000
diff --git a/src/tests/create-remove-files b/src/tests/create-remove-files
new file mode 100644 (file)
index 0000000..19cb161
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+$objdir/create-remove file 1000
diff --git a/src/tests/create-remove.c b/src/tests/create-remove.c
new file mode 100644 (file)
index 0000000..8debf07
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id$");
+#endif
+
+static int
+creat_dir (const char *name)
+{
+    int ret = mkdir (name, 0777);
+    if (ret < 0) err (1, "mkdir %s", name);
+    return 0;
+}
+
+static int
+remove_dir (const char *name)
+{
+    int ret = rmdir (name);
+    if (ret < 0) err (1, "rmdir %s", name);
+    return 0;
+}
+
+static int
+creat_file (const char *name)
+{
+    int ret = open (name, O_CREAT|O_RDWR, 0777);
+    if (ret < 0) err (1, "mkdir %s", name);
+    close (ret);
+    return 0;
+}
+
+static int
+unlink_file (const char *name)
+{
+    int ret = unlink (name);
+    if (ret < 0) err (1, "unlink %s", name);
+    return 0;
+}
+
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s [file|dir] number-of-dirs\n", __progname);
+    exit (ret);
+}
+
+#ifndef MAXPATHLEN
+#ifdef PATH_MAX
+#define MAXPATHLEN PATH_MAX
+#else
+#define MAXPATHLEN 4096
+#endif
+#endif
+
+static int
+creat_many (int num,
+           int (*c) (const char *name),
+           int (*d) (const char *name))
+{
+    char name[MAXPATHLEN];
+
+    if (num < 0)
+       errx (1, "not be negative");
+
+    snprintf (name, sizeof(name), "foo-%d-%d", num, getpid());
+
+    while (num-- > 0) {
+       (c) (name);
+       (d) (name);
+    }
+    return 0;
+}
+
+
+int
+main(int argc, char **argv)
+{
+    char *ptr;
+    int count;
+
+
+    if (argc != 3)
+       usage (1);
+
+    count = strtol (argv[2], &ptr, 0);
+    if (count == 0 && ptr == argv[2])
+       errx (1, "'%s' not a number", argv[2]);
+
+    if (strcmp ("file", argv[1]) == 0) 
+       return creat_many (count, creat_file, unlink_file);
+    else if (strcmp("dir", argv[1]) == 0)
+       return creat_many (count, creat_dir, remove_dir);
+    else
+       errx (1, "unknown type: %s", argv[1]);
+    return 0;
+}
diff --git a/src/tests/create-stat.c b/src/tests/create-stat.c
new file mode 100644 (file)
index 0000000..c9ef14c
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <afs/afsint.h>
+#include <afs/auth.h>
+#include <afs/cellconfig.h>
+#include <afs/cmd.h>
+
+#include <err.h>
+
+struct VenusFid {
+  afs_int32 Cell;
+  struct AFSFid Fid;
+};
+
+#ifdef RCSID
+RCSID("$Id$");
+#endif
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s file\n", __progname);
+    exit (ret);
+}
+
+int
+main(int argc, char **argv)
+{
+    char *file;
+    int ret;
+    struct stat sb;
+    struct stat sb_new;
+    struct stat sb_old;
+    struct VenusFid fid;
+    char *filename;
+    ino_t afsfileid;
+
+    if (argc != 2)
+       usage (1);
+
+    file = argv[1];
+
+    asprintf (&filename, "%s.new", file);
+
+    ret = open (file, O_RDWR, 0600);
+    if (ret < 0)
+       err (1, "open");
+    close (ret);
+
+    ret = open (filename, O_RDWR|O_CREAT|O_EXCL, 0600);
+    if (ret < 0) {
+       unlink(file);
+       err (1, "open");
+    }
+    close (ret);
+
+    ret = stat (file, &sb);
+    if (ret < 0) {
+       unlink(filename);
+       unlink(file);
+       err (1, "stat");
+    }
+
+    ret = lstat (filename, &sb_new);
+    if (ret < 0) {
+       unlink(filename);
+       unlink(file);
+       err (1, "stat");
+    }
+
+    if (sb.st_ino == sb_new.st_ino)
+       err (1, "sb.st_ino == sb_new.st_ino");
+
+    ret = lstat (file, &sb_old);
+    if (ret < 0) {
+       unlink(filename);
+       unlink(file);
+       err (1, "stat");
+    }
+
+    if (sb_old.st_ino == sb_new.st_ino)
+       err (1, "sb_old.st_ino == sb_new.st_ino");
+    if (sb.st_ino == sb_new.st_ino)
+       err (1, "sb.st_ino == sb_new.st_ino");
+    if (sb_old.st_ino != sb.st_ino)
+       err (1, "sb_old.st_ino != sb.st_ino");
+
+    ret = fs_getfid (file, &fid);
+    if (ret) {
+       unlink(file);
+       unlink(filename);
+       err (1, "fs_getfid: %d", ret);
+    }
+
+    afsfileid = ((fid.Fid.Volume & 0x7FFF) << 16 | (fid.Fid.Vnode & 0xFFFFFFFF));
+    if (sb.st_ino != afsfileid) {
+       unlink(file);
+       unlink(filename);
+       errx (1, "sb.st_ino(%ld) != afsfileid(%ld) (%d.%d.%d.%d)",
+             (long)sb.st_ino, (long)afsfileid,
+             fid.Cell, fid.Fid.Volume, fid.Fid.Vnode, fid.Fid.Unique);
+    }
+
+    unlink(filename);
+    unlink(file);
+
+    return 0;
+}
diff --git a/src/tests/create-symlinks.c b/src/tests/create-symlinks.c
new file mode 100644 (file)
index 0000000..4dc022c
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id$");
+#endif
+
+#define CONTENT_STRING "kaka"
+
+static FILE *verbose_fp = NULL;
+
+static int
+creat_symlinks (int count)
+{
+    int ret;
+    int i;
+    
+    fprintf (verbose_fp, "creating:");
+
+    for (i = 0; i < count; ++i) {
+       char num[17];
+
+       fprintf (verbose_fp, " c%d", i);
+       fflush (verbose_fp);
+
+       snprintf (num, sizeof(num), "%d", i);
+       
+       ret = symlink (CONTENT_STRING, num);
+       if (ret < 0)
+           err (1, "symlink %s", num);
+    }
+    fprintf (verbose_fp, "\n");
+    return 0;
+}
+
+#ifndef MAXPATHLEN
+#ifdef PATH_MAX
+#define MAXPATHLEN PATH_MAX
+#else
+#define MAXPATHLEN 4096
+#endif
+#endif
+
+static int
+verify_contents (int count)
+{
+    int ret, i;
+    char file[MAXPATHLEN];
+    char content[MAXPATHLEN];
+    
+    fprintf (verbose_fp, "reading:");
+    for (i = 0; i < count; i++) {
+       fprintf (verbose_fp, " r%d", i); 
+       fflush (verbose_fp);
+
+       snprintf (file, sizeof(file), "%d", i);
+       ret = readlink (file, content, sizeof(content) - 1);
+       if (ret < 0)
+           err (1, "readlink: %d", i);
+       content[ret] = '\0';
+       if (strcmp (CONTENT_STRING, content) != 0)
+           errx (1, "%s != %s", content, CONTENT_STRING);
+    }
+    fprintf (verbose_fp, "\n");
+    return 0;
+}
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s number-of-symlinks\n", __progname);
+    exit (ret);
+}
+
+int
+main(int argc, char **argv)
+{
+    char *ptr;
+    int count;
+
+
+    if (argc != 2)
+       usage (1);
+
+    verbose_fp = fdopen (4, "w");
+    if (verbose_fp == NULL) {
+       verbose_fp = fopen ("/dev/null", "w");
+       if (verbose_fp == NULL)
+           err (1, "fopen");
+    }
+
+    count = strtol (argv[1], &ptr, 0);
+    if (count == 0 && ptr == argv[1])
+       errx (1, "'%s' not a number", argv[1]);
+
+    return creat_symlinks (count) ||
+       verify_contents(count);
+}
diff --git a/src/tests/dd b/src/tests/dd
new file mode 100755 (executable)
index 0000000..9f51153
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+# $Id$
+if test -r /dev/zero; then
+  dd if=/dev/zero of=foo bs=1k count=20 >/dev/null 2>/dev/null || exit 1
+  rm foo || exit 1
+else
+  echo "not running dd (you have no /dev/zero)"
+fi
diff --git a/src/tests/deep-tree b/src/tests/deep-tree
new file mode 100644 (file)
index 0000000..cafecd6
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;exit 0; fi
+
+mkdir foo && ( cd foo && $SHELL $SHELLVERBOSE ${srcdir}/dir-tree 5 "0 1 2 3 4" )
+${objdir}/rm-rf foo
diff --git a/src/tests/deep-tree2 b/src/tests/deep-tree2
new file mode 100644 (file)
index 0000000..3252e42
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $Id$
+
+mkdir foo
+
+b=foo
+for a in 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z å ä ö; do
+    b=$b/$a
+    mkdir $b
+done
+
+rm -rf foo
\ No newline at end of file
diff --git a/src/tests/dir-size-mismatch b/src/tests/dir-size-mismatch
new file mode 100644 (file)
index 0000000..537de13
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;exit 0; fi
+
+for i in `awk 'BEGIN {for(i=0; i < 1000; ++i) printf "%d\n", i}' /dev/null`; do
+ ln -s hejsan qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq$i
+done
+find . -name 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq*' -print | xargs rm
+ln -s foo bar
+rm bar
diff --git a/src/tests/dir-tree b/src/tests/dir-tree
new file mode 100755 (executable)
index 0000000..bb68098
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $Id$
+
+#######################################################
+#
+# Make a directory tree of directories 
+# dir-tree <depth> <dirnames>+
+#
+#######################################################
+
+DEPTH=$1; shift
+DIRNUMS="$*"
+export DIRNUMS DEPTH
+
+# catch non numeric args and recurse cond
+expr $DEPTH '>' 0 > /dev/null 2>&1 || exit 0
+
+for a in $DIRNUMS; do
+    (mkdir $a && cd $a && \
+      $SHELL $SHELLVERBOSE ${srcdir}/dir-tree \
+            `expr $DEPTH - 1` "$DIRNUMS") || exit 1
+done
diff --git a/src/tests/dup2-and-unlog.c b/src/tests/dup2-and-unlog.c
new file mode 100644 (file)
index 0000000..c9c16b2
--- /dev/null
@@ -0,0 +1,32 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <err.h>
+
+int
+main(int argc, char **argv)
+{
+    int fd;
+
+
+    fd = open ("foo", O_RDWR|O_CREAT, 0666);
+    if (fd < 0)
+       err (1, "open");
+
+    dup2 (fd + 1, fd);
+    
+    if (write (fd, "foo\n", 4) != 4)
+       errx (1, "write");
+
+    ktc_ForgetAllTokens();
+
+    close (fd);
+    close (fd + 1);
+
+    exit (0);
+}
diff --git a/src/tests/echo-n.c b/src/tests/echo-n.c
new file mode 100644 (file)
index 0000000..7617a1f
--- /dev/null
@@ -0,0 +1,18 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+    int i;
+    for (i = 1; i < argc ; i++) {
+       printf ("%s", argv[i]);
+       if (argc > i + 1)
+           printf (" ");
+    }
+    fflush (stdout);
+    return 0;
+}
diff --git a/src/tests/err.c b/src/tests/err.c
new file mode 100644 (file)
index 0000000..cc1b031
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan 
+ * (Royal Institute of Technology, Stockholm, Sweden).  
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id$");
+#endif
+
+#include "err.h"
+
+void
+err(int eval, const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  verr(eval, fmt, ap);
+  va_end(ap);
+}
diff --git a/src/tests/err.h b/src/tests/err.h
new file mode 100644 (file)
index 0000000..e4dc06d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan 
+ * (Royal Institute of Technology, Stockholm, Sweden).  
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef __ERR_H__
+#define __ERR_H__
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+extern const char *__progname;
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(x)
+#endif
+
+void warnerr(int doerrno, const char *fmt, va_list ap)
+     __attribute__ ((format (printf, 2, 0)));
+
+void verr(int eval, const char *fmt, va_list ap)
+     __attribute__ ((noreturn, format (printf, 2, 0)));
+void err(int eval, const char *fmt, ...)
+     __attribute__ ((noreturn, format (printf, 2, 3)));
+void verrx(int eval, const char *fmt, va_list ap)
+     __attribute__ ((noreturn, format (printf, 2, 0)));
+void errx(int eval, const char *fmt, ...)
+     __attribute__ ((noreturn, format (printf, 2, 3)));
+void vwarn(const char *fmt, va_list ap)
+     __attribute__ ((format (printf, 1, 0)));
+void warn(const char *fmt, ...)
+     __attribute__ ((format (printf, 1, 2)));
+void vwarnx(const char *fmt, va_list ap)
+     __attribute__ ((format (printf, 1, 0)));
+void warnx(const char *fmt, ...)
+     __attribute__ ((format (printf, 1, 2)));
+
+#endif /* __ERR_H__ */
diff --git a/src/tests/errtrans.pm b/src/tests/errtrans.pm
new file mode 100644 (file)
index 0000000..48cf96a
--- /dev/null
@@ -0,0 +1,310 @@
+# CMUCS AFStools
+# Copyright (c) 1996, Carnegie Mellon University
+# All rights reserved.
+#
+# See CMUCS/CMU_copyright.pm for use and distribution information
+
+package OpenAFS::errtrans;
+
+=head1 NAME
+
+OpenAFS::errtrans - com_err error translation
+
+=head1 SYNOPSIS
+
+  use OpenAFS::errtrans
+  $code = errcode($name);
+  $code = errcode($pkg, $err);
+  $string = errstr($code, [$volerrs]);
+
+=head1 DESCRIPTION
+
+This module translates "common" error codes such as those produced
+by MIT's com_err package, and used extensively in AFS.  It also knows
+how to translate system error codes, negative error codes used by Rx,
+and a few "special" error codes used by AFS's volume package.
+
+In order to work, these routines depend on the existence of error
+table files in $err_table_dir, which is usually /usr/local/lib/errtbl.
+Each file should be named after a com_err error package, and contain
+the definition for that package.
+
+Note that the AFS version of com_err translates package names to uppercase
+before generating error codes, so a table which claims to define the 'pt'
+package actually defines the 'PT' package when compiled by AFS's compile_et.
+Tables that are normally fed to AFS's compile_et should be installed using
+the _uppercase_ version of the package name.
+
+The error tables used in AFS are part of copyrighted AFS source code, and
+are not included with this package.  However, I have included a utility
+(gen_et) which can generate error tables from the .h files normally
+produced by compile_et, and Transarc provides many of these header files
+with binary AFS distributions (in .../include/afs).  See the gen_et
+program for more details.
+
+=cut
+
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT :afs_internal);
+use OpenAFS::config qw($err_table_dir);
+use Symbol;
+use Exporter;
+use POSIX;
+
+$VERSION   = '';
+$VERSION   = '1.00';
+@ISA       = qw(Exporter);
+@EXPORT    = qw(&errcode &errstr);
+
+
+@NumToChar = ('', 'A'..'Z', 'a'..'z', '0'..'9', '_');
+%CharToNum = map(($NumToChar[$_], $_), (1 .. $#NumToChar));
+
+%Vol_Codes = ( VSALVAGE    => 101,
+               VNOVNODE    => 102,
+               VNOVOL      => 103,
+               VVOLEXISTS  => 104,
+               VNOSERVICE  => 105,
+               VOFFLINE    => 106,
+               VONLINE     => 107,
+               VDISKFULL   => 108,
+               VOVERQUOTA  => 109,
+               VBUSY       => 110,
+               VMOVED      => 111
+             );
+%Vol_Desc  = ( 101 => "volume needs to be salvaged",
+               102 => "no such entry (vnode)",
+               103 => "volume does not exist / did not salvage",
+               104 => "volume already exists",
+               105 => "volume out of service",
+               106 => "volume offline (utility running)",
+               107 => "volume already online",
+               108 => "unknown volume error 108",
+               109 => "unknown volume error 109",
+               110 => "volume temporarily busy",
+               111 => "volume moved"
+             );
+%Rx_Codes  = ( RX_CALL_DEAD           => -1,
+               RX_INVALID_OPERATION   => -2,
+               RX_CALL_TIMEOUT        => -3,
+               RX_EOF                 => -4,
+               RX_PROTOCOL_ERROR      => -5,
+               RX_USER_ABORT          => -6,
+               RX_ADDRINUSE           => -7,
+               RX_MSGSIZE             => -8,
+               RXGEN_CC_MARSHAL       => -450,
+               RXGEN_CC_UNMARSHAL     => -451,
+               RXGEN_SS_MARSHAL       => -452,
+               RXGEN_SS_UNMARSHAL     => -453,
+               RXGEN_DECODE           => -454,
+               RXGEN_OPCODE           => -455,
+               RXGEN_SS_XDRFREE       => -456,
+               RXGEN_CC_XDRFREE       => -457
+             );
+%Rx_Desc   = (   -1 => "server or network not responding",
+                 -2 => "invalid RPC (Rx) operation",
+                 -3 => "server not responding promptly",
+                 -4 => "Rx unexpected EOF",
+                 -5 => "Rx protocol error",
+                 -6 => "Rx user abort",
+                 -7 => "port address already in use",
+                 -8 => "Rx message size incorrect",
+               -450 => "Rx client: XDR marshall failed",
+               -451 => "Rx client: XDR unmarshall failed",
+               -452 => "Rx server: XDR marshall failed",
+               -453 => "Rx server: XDR unmarshall failed",
+               -454 => "Rx: Decode failed",
+               -455 => "Rx: Invalid RPC opcode",
+               -456 => "Rx server: XDR free failed",
+               -457 => "Rx client: XDR free failed",
+               map(($_ => "RPC interface mismatch ($_)"), (-499 .. -458)),
+               -999 => "Unknown error"
+             );
+
+
+sub _tbl_to_num {
+  my(@tbl) = split(//, $_[0]);
+  my($n);
+
+  @tbl = @tbl[0..3] if (@tbl > 4);
+  foreach (@tbl) { $n = ($n << 6) + $CharToNum{$_} }
+  $n << 8;
+}
+
+
+sub _num_to_tbl {
+  my($n) = $_[0] >> 8;
+  my($tbl);
+
+  while ($n) {
+    $tbl = @NumToChar[$n & 0x3f] . $tbl;
+    $n >>= 6;
+  }
+  $tbl;
+}
+
+
+sub _load_system_errors {
+  my($file) = @_;
+  my($fh) = &gensym();
+
+  return if ($did_include{$file});
+# print "Loading $file...\n";
+  $did_include{$file} = 'yes';
+  if (open($fh, "/usr/include/$file")) {
+    while (<$fh>) {
+      if (/^\#define\s*(E\w+)\s*(\d+)/) {
+        $Codes{$1} = $2;
+      } elsif (/^\#include\s*\"([^"]+)\"/
+           ||  /^\#include\s*\<([^>]+)\>/) {
+        &_load_system_errors($1);
+      }
+    }
+    close($fh);
+  }
+}
+
+
+# Load an error table into memory
+sub _load_error_table {
+  my($pkg) = @_;
+  my($fh, @words, $curval, $tval, $nval);
+  my($tid, $tfn, $code, $val, $desc);
+
+  return if ($Have_Table{$pkg});
+  # Read in the input file, and split it into words
+  $fh = &gensym();
+  return unless open($fh, "$err_table_dir/$pkg");
+# print "Loading $pkg...\n";
+  line: while (<$fh>) {
+    s/^\s*//;  # Strip leading whitespace
+    while ($_) {
+      next line if (/^#/);
+      if    (/^(error_table|et)\s*/) { push(@words, 'et');  $_ = $' }
+      elsif (/^(error_code|ec)\s*/)  { push(@words, 'ec');  $_ = $' }
+      elsif (/^end\s*/)              { push(@words, 'end'); $_ = $' }
+      elsif (/^(\w+)\s*/)            { push(@words, $1);    $_ = $' }
+      elsif (/^\"([^"]*)\"\s*/)      { push(@words, $1);    $_ = $' }
+      elsif (/^([,=])\s*/)           { push(@words, $1);    $_ = $' }
+      else { close($fh); return }
+    }
+  }
+  close($fh);
+
+  # Parse the table header
+  $_ = shift(@words); return unless ($_ eq 'et');
+  if ($words[1] eq 'ec')    { $tid = shift(@words) }
+  elsif ($words[2] eq 'ec') { ($tfn, $tid) = splice(@words, 0, 2) }
+  else { return; }
+  if ($tid ne $pkg) {
+    $Have_Table{$tid} = 'yes';
+    $_ = $tid;
+    $_ =~ tr/a-z/A-Z/;
+    $tid = $_ if ($_ eq $pkg);
+  }
+  $tval = &_tbl_to_num($tid);
+  $Have_Table{$pkg} = 'yes';
+# print "Package $pkg: table-id = $tid, table-fun = $tfn, base = $tval\n";
+
+  while (@words) {
+    $_ = shift(@words); return unless ($_ eq 'ec');
+    $code = shift(@words);
+    $_ = shift(@words);
+    if ($_ eq '=') {
+      $val = shift(@words);
+      $_ = shift(@words);
+    } else {
+      $val = $curval;
+    }
+    return unless ($_ eq ',');
+    $desc = shift(@words);
+    $nval = $tval + $val;
+    $curval = $val + 1;
+    $Desc{$nval} = $desc;
+    $Codes{$code} = $nval;
+#   print "  code $code: value = $nval ($tval + $val), desc = \"$desc\"\n";
+  }
+}
+
+=head2 errcode($name)
+
+Returns the numeric error code corresponding to the specified error
+name.  This routine knows about names of system errors, a few special
+Rx and volume-package errors, and any errors defined in installed
+error tables.  If the specified error code is not found, returns -999.
+
+=head2 errcode($pkg, $code)
+
+Shifts $code into the specified error package, and returns the
+resulting com_err code.  This can be used to generate error codes
+for _any_ valid com_err package.
+
+=cut
+
+sub errcode {
+  if (@_ > 1) {
+    my($pkg, $code) = @_;
+    &_tbl_to_num($pkg) + $code;
+  } else {
+    my($name) = @_;
+    my($dir, @tbls, $code);
+
+    &_load_system_errors("errno.h");
+    if ($Vol_Codes{$name})   { $Vol_Codes{$name} }
+    elsif ($Rx_Codes{$name}) { $Rx_Codes{$name} }
+    elsif ($Codes{$name})    { $Codes{$name} }
+    else {
+      if ($name =~ /^E/) {  # Might be a POSIX error constant
+        $! = 0;
+        $code = &POSIX::constant($name, 0);
+        if (!$!) { return $code; }
+      }
+      $dir = &gensym();
+      if (opendir($dir, $err_table_dir)) {
+        @tbls = grep(!/^\.?\.$/, readdir($dir));
+        close($dir);
+        foreach (@tbls) { &_load_error_table($_) }
+      }
+      $Codes{$name} ? $Codes{$name} : -999;
+    }
+  }
+}
+
+
+=head2 errstr($code, [$volerrs])
+
+Returns the error string corresponding to a specified com_err, Rx,
+or system error code.  If $volerrs is specified and non-zero, then
+volume-package errors are considered before system errors with the
+same values.
+
+=cut
+
+sub errstr {
+  my($code, $volerrs) = @_;
+  my($pkg, $sub);
+
+  if ($Rx_Desc{$code}) { return $Rx_Desc{$code} }
+  if ($volerrs && $Vol_Desc{$code}) { return $Vol_Desc{$code} }
+  $sub = $code & 0xff;
+  $pkg = &_num_to_tbl($code);
+  if ($pkg eq '') {
+    $! = $sub + 0;
+    $_ = $! . '';
+    if (/^(Error )?\d+$/) { $Vol_Desc{$sub} ? $Vol_Desc{$sub} : "Error $sub" }
+    else { $_ }
+  } else {
+    &_load_error_table($pkg);
+    $Desc{$code} ? $Desc{$code} : "Unknown code $pkg $sub ($code)";
+  }
+}
+
+1;
+
+=head1 COPYRIGHT
+
+The CMUCS AFStools, including this module are
+Copyright (c) 1996, Carnegie Mellon University.  All rights reserved.
+For use and redistribution information, see CMUCS/CMU_copyright.pm
+
+=cut
diff --git a/src/tests/errx.c b/src/tests/errx.c
new file mode 100644 (file)
index 0000000..da47e4d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan 
+ * (Royal Institute of Technology, Stockholm, Sweden).  
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id$");
+#endif
+
+#include "err.h"
+
+void
+errx(int eval, const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  verrx(eval, fmt, ap);
+  va_end(ap);
+}
diff --git a/src/tests/exec b/src/tests/exec
new file mode 100755 (executable)
index 0000000..f6535c0
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+echo '#!/bin/sh' > foo.sh
+export objdir
+echo '$objdir/echo-n "foo"' >> foo.sh
+test -f foo.sh || exit 1
+chmod +x foo.sh
+test -x foo.sh || exit 1
+FOO=`./foo.sh`
+test "X"$FOO = "Xfoo" || exit 1
diff --git a/src/tests/exit-wo-close.c b/src/tests/exit-wo-close.c
new file mode 100644 (file)
index 0000000..c2ff56f
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id$");
+#endif
+
+static int 
+child (const char *filename)
+{
+    int fd;
+    int ret;
+
+    fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    ret = write (fd, "hej", 3);
+    if (ret != 3)
+       err (1, "write %s", filename);
+    return 0;
+}
+
+static int 
+parent (const char *filename, pid_t child_pid)
+{
+    int stat;
+    int ret;
+    int fd;
+    struct stat sb;
+    char buf[3];
+
+    ret = waitpid (child_pid, &stat, 0);
+    if (ret < 0)
+       err (1, "waitpid %u", (unsigned)child_pid);
+    if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0)
+       errx (1, "weird child %u", (unsigned)child_pid);
+    fd = open (filename, O_RDONLY, 0);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    ret = fstat (fd, &sb);
+    if (ret < 0)
+       err (1, "fstat %s", filename);
+    if (sb.st_size != 3)
+       errx (1, "size of %s = %u != 3", filename, (unsigned)sb.st_size);
+    ret = read (fd, buf, sizeof(buf));
+    if (ret < 0)
+       err (1, "read %s", filename);
+    if (ret != 3)
+       errx (1, "short read from %s", filename);
+    if (memcmp (buf, "hej", 3) != 0)
+       errx (1, "bad contents of %s = `%.3s'\n", filename, buf);
+    close (fd);
+    return 0;
+}
+
+static int
+doit (const char *filename)
+{
+    pid_t pid;
+
+    pid = fork ();
+    if (pid < 0)
+       err (1, "fork");
+
+    if (pid == 0)
+       return child (filename);
+    else
+       return parent (filename, pid);
+}
+
+int
+main(int argc, char **argv)
+{
+    const char *file = "foo";
+
+
+    if (argc != 2 && argc != 1)
+       errx (1, "usage: %s [file]", argv[0]);
+    if (argc == 2)
+       file = argv[1];
+    return doit (file);
+}
diff --git a/src/tests/extcopyin b/src/tests/extcopyin
new file mode 100755 (executable)
index 0000000..a5f5790
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+FS=${FS:-${objdir}/../appl/fs/fs}
+${FS} sa . system:anyuser all || exit 1
+${objdir}/write-rand /usr/tmp/$$ 262144 || exit 1
+${objdir}/afscp -i -b 56k /usr/tmp/$$ `pwd`/$$ || exit 1
+diff /usr/tmp/$$ `pwd`/$$ || exit 1
+${objdir}/afscp -i -b 32k /usr/tmp/$$ `pwd`/$$ || exit 1
+diff /usr/tmp/$$ `pwd`/$$ || exit 1
+exit 0
+
+
diff --git a/src/tests/extcopyout b/src/tests/extcopyout
new file mode 100755 (executable)
index 0000000..0347dd8
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+FS=${FS:-${objdir}/../appl/fs/fs}
+${FS} sa . system:anyuser all || exit 1
+${objdir}/write-rand $$ 262144 || exit 1
+${objdir}/afscp -o -b 56k `pwd`/$$ /usr/tmp/$$ || exit 1
+diff /usr/tmp/$$ `pwd`/$$ || exit 1
+${objdir}/afscp -o -b 32k `pwd`/$$ /usr/tmp/$$ || exit 1
+diff /usr/tmp/$$ `pwd`/$$ || exit 1
+exit 0
+
+
diff --git a/src/tests/fcachesize-dir b/src/tests/fcachesize-dir
new file mode 100644 (file)
index 0000000..c9a9879
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# $Id$
+
+FS=${FS:-${objdir}/../appl/fs/fs}
+SIZE1=`$FS getcache -b | awk '{ print $4 ; exit }'`
+mkdir foo
+SIZE2=`$FS getcache -b | awk '{ print $4 ; exit }'`
+test $SIZE2 = `expr $SIZE1 + 2048` || exit 1
+rmdir foo
+#SIZE3=`$FS getcache -b | awk '{ print $4 ; exit }'`
+#test $SIZE3 = $SIZE1 || exit 1
+
+exit 0
diff --git a/src/tests/fcachesize-file-small b/src/tests/fcachesize-file-small
new file mode 100644 (file)
index 0000000..62800c1
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# $Id$
+
+FS=${FS:-${objdir}/../appl/fs/fs}
+SIZE1=`$FS getcache -b | awk '{ print $4 ; exit }'`
+echo foo > foo
+SIZE2=`$FS getcache -b | awk '{ print $4 ; exit }'`
+test $SIZE2 = `expr $SIZE1 + 4` || exit 1
+rm foo
+#SIZE3=`$FS getcache -b | awk '{ print $4 ; exit }'`
+#test $SIZE3 = $SIZE1 || exit 1
+
+exit 0
diff --git a/src/tests/fcachesize-read-file b/src/tests/fcachesize-read-file
new file mode 100644 (file)
index 0000000..6dd4b72
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# $Id$
+
+FS=${FS:-${objdir}/../appl/fs/fs}
+SIZE1=`$FS getcache | awk '{ print $8 ; exit }'`
+SIZE2=`expr $SIZE1 + 4`
+if test -w /dev/null; then
+  dd if=../foo of=/dev/null bs=1k count=$SIZE2 >/dev/null 2>/dev/null || exit 1
+  rm ../foo || exit 1
+else
+  echo "not running dd (you have no /dev/null)"
+fi
+
+exit 0
diff --git a/src/tests/fcachesize-write-file b/src/tests/fcachesize-write-file
new file mode 100644 (file)
index 0000000..8b60ad2
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# $Id$
+
+FS=${FS:-${objdir}/../appl/fs/fs}
+SIZE1=`$FS getcache | awk '{ print $8 ; exit }'`
+SIZE2=`expr $SIZE1 + 4`
+if test -r /dev/zero; then
+  dd if=/dev/zero of=../foo bs=1k count=$SIZE2 >/dev/null 2>/dev/null || exit 1
+else
+  echo "not running dd (you have no /dev/zero)"
+fi
+
+exit 0
diff --git a/src/tests/fchmod.c b/src/tests/fchmod.c
new file mode 100644 (file)
index 0000000..3dbee05
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+
+int
+main(int argc, char **argv)
+{
+    int fd, ret;
+    struct stat sb;
+
+
+    fd = open ("deps", O_WRONLY|O_CREAT|O_TRUNC, 0666);
+    if (fd < 0)
+       err (1, "open");
+    ret = fstat (fd, &sb);
+    if (ret < 0)
+       err (1, "fstat");
+    ret = write (fd, "# DO NOT DELETE\n", 16);
+    if (ret != 16)
+       err (1, "write");
+    ret = fchmod (fd, 0100644);
+    if (ret < 0)
+       errx (1, "fchmod");
+    ret = close (fd);
+    if (ret < 0)
+       errx (1, "close");
+
+    unlink("deps");
+    return 0;
+}
diff --git a/src/tests/fhbench.c b/src/tests/fhbench.c
new file mode 100644 (file)
index 0000000..98b2b4d
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/mount.h>
+
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
+
+#include <fcntl.h>
+
+#include <err.h>
+#include <agetarg.h>
+
+#include <atypes.h>
+#include <kafs.h>
+
+RCSID("$Id$");
+
+struct fhb_handle {
+    char data[512];
+};
+
+static int help_flag;
+static int num_files;
+static int write_file = 0;
+static int num_runs = 3;
+
+static struct agetargs args[] = {
+    {"num",    'n',    aarg_integer,   &num_files,     "number of files"},
+    {"write",  'w',    aarg_integer,   &write_file,    "write num kb"},
+    {"runs",   'r',    aarg_integer,   &num_runs,      "number of runs"},
+    {"help",   0,      aarg_flag,      &help_flag,     NULL,           NULL},
+    {NULL,     0,      aarg_end,       NULL,           NULL,           NULL}
+};
+
+
+static void
+fhb_fhget (char *filename, struct fhb_handle *handle)
+{
+    int ret = 0;
+#if defined(HAVE_GETFH) && defined(HAVE_FHOPEN)
+    {
+       fhandle_t fh;
+
+       ret = getfh (filename, &fh);
+       if (ret)
+           err (1, "getfh");
+       memcpy (handle, &fh, sizeof(fh));
+    }
+#endif
+    {
+       struct ViceIoctl vice_ioctl;
+       
+       vice_ioctl.in      = NULL;
+       vice_ioctl.in_size = 0;
+       
+       vice_ioctl.out      = (caddr_t)handle;
+       vice_ioctl.out_size = sizeof(*handle);
+       
+       ret = pioctl (filename, VIOC_FHGET, &vice_ioctl, 0);
+       if (ret)
+           errx (1, "k_pioctl");
+    }
+}
+
+
+static int
+fhb_fhopen (struct fhb_handle *handle, int flags)
+{
+    int ret;
+#if defined(HAVE_GETFH) && defined(HAVE_FHOPEN)
+    {
+       fhandle_t fh;
+
+       memcpy (&fh, handle, sizeof(fh));
+       ret = fhopen (&fh, flags);
+       if (ret >= 0)
+           return ret;
+    }
+#endif
+
+#ifdef KERBEROS                        /* really KAFS */
+    {
+       struct ViceIoctl vice_ioctl;
+       
+       vice_ioctl.in      = (caddr_t)handle;
+       vice_ioctl.in_size = sizeof(*handle);
+       
+       vice_ioctl.out      = NULL;
+       vice_ioctl.out_size = 0;
+       
+       ret = k_pioctl (NULL, VIOC_FHOPEN, &vice_ioctl, flags);
+       if (ret >= 0)
+           return ret;
+    }
+#endif
+    errx (1, "fhopen/k_pioctl");
+}
+
+static void
+nop_call (void)
+{
+#ifdef KERBEROS                        /* really KAFS */
+    {
+       struct ViceIoctl vice_ioctl;
+       char c[8];
+       int ret;
+       
+       vice_ioctl.in      = (caddr_t)&c;
+       vice_ioctl.in_size = sizeof(c);
+       
+       vice_ioctl.out      = NULL;
+       vice_ioctl.out_size = 0;
+       
+       ret = k_pioctl (NULL, VIOC_XFSDEBUG, &vice_ioctl, 0);
+       if (ret < 0)
+           err (1, "k_pioctl");
+    }
+#else
+    {
+       static first = 1;
+       if (first) {
+           warnx ("can't test this");
+           first = 0;
+       }
+    }
+#endif
+}
+
+static void
+create_file (int num, struct fhb_handle *handle)
+{
+    int fd;
+    char filename[1024];
+
+    snprintf (filename, sizeof(filename), "file-%d", num);
+
+    fd = open (filename, O_CREAT|O_EXCL|O_RDWR, 0666);
+    if (fd < 0)
+       err (1, "open");
+
+    close (fd);
+    
+    fhb_fhget(filename, handle);
+}
+
+char databuf[1024];
+
+static void
+write_to_file (int fd, int num)
+{
+    int ret;
+    while (num > 0) {
+       ret = write (fd, databuf, sizeof(databuf));
+       if (ret != sizeof(databuf))
+           err (1, "write");
+       num--;
+    }
+}
+
+static void
+fhopen_file (int num, struct fhb_handle *handle)
+{
+    int fd;
+
+    fd = fhb_fhopen(handle, O_RDWR);
+    if (fd < 0)
+       err (1, "open");
+
+    if (write_file)
+       write_to_file(fd, write_file);
+    close(fd);
+}
+
+static void
+open_file (int num)
+{
+    int fd;
+    char filename[1024];
+
+    snprintf (filename, sizeof(filename), "file-%d", num);
+
+    fd = open (filename, O_RDWR, 0666);
+    if (fd < 0)
+       err (1, "open");
+
+    if (write_file)
+       write_to_file(fd, write_file);
+
+    close (fd);
+}
+
+static void
+unlink_file (int num)
+{
+    int ret;
+    char filename[1024];
+
+    snprintf (filename, sizeof(filename), "file-%d", num);
+
+    ret = unlink(filename);
+    if (ret < 0)
+       err (1, "unlink");
+}
+
+struct timeval time1, time2;
+
+static void
+starttesting(char *msg)
+{
+    printf("testing %s...\n", msg);
+    fflush (stdout);
+    gettimeofday(&time1, NULL);
+}    
+
+static void
+endtesting(void)
+{
+    gettimeofday(&time2, NULL);
+    timevalsub(&time2, &time1);
+    printf("timing: %ld.%06ld\n", (long)time2.tv_sec, (long)time2.tv_usec);
+}
+
+static void
+usage (int exit_val)
+{
+    aarg_printusage (args, NULL, "number of files", AARG_GNUSTYLE);
+    exit (exit_val);
+}
+
+static void
+open_bench (int i, struct fhb_handle *handles)
+{
+    printf ("====== test run %d\n"
+           "==================\n",
+           i);
+
+    starttesting ("fhopening files");
+    for (i = 0; i < num_files; i++)
+       fhopen_file (i, &handles[i]);
+    endtesting ();
+   
+    starttesting ("opening files");
+    for (i = 0; i < num_files; i++)
+       open_file (i);
+    endtesting ();
+}
+
+int
+main (int argc, char **argv)
+{
+    int optind = 0;
+    int i;
+    struct fhb_handle *handles;
+
+
+    if (agetarg (args, argc, argv, &optind, AARG_GNUSTYLE))
+       usage (1);
+
+    if (help_flag)
+       usage (0);
+
+    if (num_files <= 0)
+       usage (1);
+
+    if (write_file < 0)
+       usage (1);
+
+#ifdef KERBEROS
+    if (!k_hasafs())
+#endif
+       errx (1, "no afs kernel module");
+
+    handles = emalloc (num_files * sizeof(*handles));
+
+    starttesting ("creating files");
+    for (i = 0; i < num_files; i++)
+       create_file (i, &handles[i]);
+    endtesting ();
+
+    for (i = 0 ; i < num_runs; i++)
+       open_bench (i, handles);
+   
+    printf ( "==================\n");
+    starttesting ("unlink files");
+    for (i = 0; i < num_files; i++)
+       unlink_file (i);
+    endtesting ();
+
+    printf ( "==================\n");
+    starttesting ("nop call");
+    for (i = 0; i < num_files; i++)
+       nop_call ();
+    endtesting ();
+
+    return 0;
+}
diff --git a/src/tests/find-and-cat-netbsd b/src/tests/find-and-cat-netbsd
new file mode 100644 (file)
index 0000000..9048ecc
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+netbsd_ftp_mirror=${1-$AFSROOT/stacken.kth.se/ftp/pub/NetBSD/NetBSD-1.4/}
+find ${netbsd_ftp_mirror} -type f -exec cat '{}' \; > /dev/null
diff --git a/src/tests/find-linux b/src/tests/find-linux
new file mode 100644 (file)
index 0000000..d347707
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id$
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+linux_src=${1-$AFSROOT/pdc.kth.se/src/OS/Linux/}
+(cd ${linux_src} ; find . ) >&4
diff --git a/src/tests/fs-flush b/src/tests/fs-flush
new file mode 100644 (file)
index 0000000..36fe37e
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id$
+FS=${FS:-${objdir}/../appl/fs/fs}
+> foobar
+${FS} flush
+test -f foobar || exit 1
\ No newline at end of file
diff --git a/src/tests/fs-sa-la b/src/tests/fs-sa-la
new file mode 100755 (executable)
index 0000000..20f0ccb
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id$
+FS=${FS:-${objdir}/../appl/fs/fs}
+${FS} sa . kalle-anka-nu rl 2>&4
+${FS} la >&4 2>&4
+exit 0
diff --git a/src/tests/fs.pm b/src/tests/fs.pm
new file mode 100644 (file)
index 0000000..4093237
--- /dev/null
@@ -0,0 +1,817 @@
+# CMUCS AFStools
+# Copyright (c) 1996, 2001 Carnegie Mellon University
+# All rights reserved.
+#
+# See CMU_copyright.ph for use and distribution information
+#
+#: * fs.pm - Wrappers around the FS commands (fileserver/cache manager)
+#: * This module provides wrappers around the various FS commands, which
+#: * perform fileserver and cache manager control operations.  Right now,
+#: * these are nothing more than wrappers around 'fs'; someday, we might
+#: * talk to the cache manager directly, but not anytime soon.
+#:
+
+package OpenAFS::fs;
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT :afs_internal);
+use OpenAFS::wrapper;
+use Exporter;
+
+$VERSION   = '';
+$VERSION   = '1.00';
+@ISA       = qw(Exporter);
+@EXPORT    = qw(&AFS_fs_getacl          &AFS_fs_setacl
+                &AFS_fs_cleanacl        &AFS_fs_getquota
+                &AFS_fs_setquota        &AFS_fs_whereis
+               &AFS_fs_examine         &AFS_fs_setvol
+                &AFS_fs_getmount        &AFS_fs_mkmount
+                &AFS_fs_rmmount         &AFS_fs_checkvolumes
+                &AFS_fs_flush           &AFS_fs_flushmount
+                &AFS_fs_flushvolume     &AFS_fs_messages
+                &AFS_fs_newcell         &AFS_fs_rxstatpeer
+                &AFS_fs_rxstatproc      &AFS_fs_setcachesize
+                &AFS_fs_setcell         &AFS_fs_setcrypt
+                &AFS_fs_setclientaddrs  &AFS_fs_copyacl
+                &AFS_fs_storebehind     &AFS_fs_setserverprefs
+                &AFS_fs_checkservers    &AFS_fs_checkservers_interval
+                &AFS_fs_exportafs       &AFS_fs_getcacheparms
+                &AFS_fs_getcellstatus   &AFS_fs_getclientaddrs
+                &AFS_fs_getcrypt        &AFS_fs_getserverprefs
+                &AFS_fs_listcells       &AFS_fs_setmonitor
+                &AFS_fs_getmonitor      &AFS_fs_getsysname
+                &AFS_fs_setsysname      &AFS_fs_whichcell
+                &AFS_fs_wscell);
+
+#: ACL-management functions:
+#: AFS access control lists are represented as a Perl list (or usually, a
+#: reference to such a list).  Each element in such a list corresponds to
+#: a single access control entry, and is a reference to a 2-element list
+#: consisting of a PTS entity (name or ID), and a set of rights.  The
+#: rights are expressed in the usual publically-visible AFS notation, as
+#: a string of characters drawn from the class [rlidwkaABCDEFGH].  No
+#: rights are denoted by the empty string; such an ACE will never returned
+#: by this library, but may be used as an argument to remove a particular
+#: ACE from a directory's ACL.
+#:
+#: One might be inclined to ask why we chose this representation, instead of
+#: using an associative array, as might seem obvious.  The answer is that
+#: doing so would have implied a nonambiguity that isn't there.  Suppose you
+#: have an ACL %x, and want to know if there is an entry for user $U on that
+#: list.  You might think you could do this by looking at $x{$U}.  The
+#: problem here is that two values for $U (one numeric and one not) refer to
+#: the same PTS entity, even though they would reference different elements
+#: in such an ACL.  So, we instead chose a representation that wasn't a hash,
+#: so people wouldn't try to do hash-like things to it.  If you really want
+#: to be able to do hash-like operations, you should turn the list-form ACL
+#: into a hash table, and be sure to do name-to-number translation on all the
+#: keys as you go.
+#:
+#: AFS_fs_getacl($path)
+#: Get the ACL on a specified path.
+#: On success, return a list of two references to ACLs; the first is the
+#: positive ACL for the specified path, and the second is the negative ACL.
+#:
+$AFS_Help{fs_getacl} = '$path => (\@posacl, \@negacl)';
+sub AFS_fs_getacl {
+  my($path) = @_;
+  my(@args, @posacl, @negacl, $neg);
+
+  @args = ('listacl', '-path', $path);
+  &wrapper('fs', \@args,
+          [
+           [ '^(Normal|Negative) rights\:', sub {
+             $neg = ($_[0] eq 'Negative');
+           }],
+           [ '^  (.*) (\S+)$', sub { #',{
+             if ($neg) {
+               push(@negacl, [@_]);
+             } else {
+               push(@posacl, [@_]);
+             }
+           }]]);
+  (\@posacl, \@negacl);
+}
+
+#: AFS_fs_setacl(\@paths, \@posacl, \@negacl, [$clear])
+#: Set the ACL on a specified path.  Like the 'fs setacl' command, this
+#: function normally only changes ACEs that are mentioned in one of the two
+#: argument lists.  If a given ACE already exists, it is changed; if not, it
+#: is added.  To delete a single ACE, specify the word 'none' or the empty
+#: string in the rights field.  ACEs that already exist but are not mentioned
+#: are left untouched, unless $clear is specified.  In that case, all
+#: existing ACE's (both positive and negative) are deleted.
+$AFS_Help{fs_setacl} = '\@paths, \@posacl, \@negacl, [$clear] => Success?';
+sub AFS_fs_setacl {
+  my($paths, $posacl, $negacl, $clear) = @_;
+  my($ace, $U, $access);
+
+  if (@$posacl) {
+    @args = ('setacl', '-dir', @$paths);
+    push(@args, '-clear') if ($clear);
+    push(@args, '-acl');
+    foreach $e (@$posacl) {
+      ($U, $access) = @$e;
+      $access = 'none' if ($access eq '');
+      push(@args, $U, $access);
+    }
+    &wrapper('fs', \@args);
+  }
+  if (@$negacl) {
+    @args = ('setacl', '-dir', @$paths, '-negative');
+    push(@args, '-clear') if ($clear && !@$posacl);
+    push(@args, '-acl');
+    foreach $e (@$negacl) {
+      ($U, $access) = @$e;
+      $access = 'none' if ($access eq '');
+      push(@args, $U, $access);
+    }
+    &wrapper('fs', \@args);
+  }
+  if ($clear && !@$posacl && !@$negacl) {
+    @args = ('setacl', '-dir', @$paths,
+            '-acl', 'system:anyuser', 'none', '-clear');
+    &wrapper('fs', \@args);
+  }
+  1;
+}
+
+#: AFS_fs_cleanacl(\@paths)
+#: Clean the ACL on the specified path, removing any ACEs which refer to PTS
+#: entities that no longer exist.  All the work is done by 'fs'.
+#:
+$AFS_Help{'fs_cleanacl'} = '\@paths => Success?';
+sub AFS_fs_cleanacl {
+  my($paths) = @_;
+  my(@args);
+
+  @args = ('cleanacl', '-path', @$paths);
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_getquota($path) [listquota]
+#: Get the quota on the specified path.
+#: On success, returns the quota.
+#:
+$AFS_Help{'fs_getquota'} = '$path => $quota';
+sub AFS_fs_getquota {
+  my($path) = @_;
+  my(@args, $quota);
+
+  @args = ('listquota', '-path', $path);
+  &wrapper('fs', \@args,
+          [[ '^\S+\s+(\d+)\s+\d+\s+\d+\%', \$quota ]]);
+  $quota;
+}
+
+#: AFS_fs_setquota($path, $quota) [setquota]
+#: Set the quota on the specified path to $quota.  If $quota is
+#: given as 0, there will be no limit to the volume's size.
+#: On success, return 1
+#:
+$AFS_Help{'fs_setquota'} = '$path, $quota => Success?';
+sub AFS_fs_setquota {
+  my($path, $quota) = @_;
+  my(@args);
+
+  @args = ('setquota', '-path', $path, '-max', $quota);
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_whereis($path)  [whereis, whichcell]
+#: Locate the fileserver housing the specified path, and the cell in which it
+#: is located.
+#: On success, returns a list of 2 or more elements.  The first element is the
+#: name of the cell in which the volume is located.  The remaining elements
+#: the names of servers housing the volume; for a replicated volume, there may
+#: (should) be more than one such server.
+#:
+$AFS_Help{'fs_whereis'} = '$path => ($cell, @servers)';
+sub AFS_fs_whereis {
+  my($path) = @_;
+  my(@args, $cell, @servers);
+
+  @args = ('whichcell', '-path', $path);
+  &wrapper('fs', \@args,
+          [[ "lives in cell \'(.*)\'", \$cell ]]);
+
+  @args = ('whereis', '-path', $path);
+  &wrapper('fs', \@args,
+          [[ 'is on host(s?)\s*(.*)', sub {
+            @servers = split(' ', $_[1]);
+          }]]);
+  ($cell, @servers);
+}
+
+#: AFS_fs_examine($path)
+#: Get information about the volume containing the specified path.
+#: On success, return an associative array containing some or all
+#: of the following elements:
+#: - vol_name
+#: - vol_id
+#: - quota_max
+#: - quota_used
+#: - quota_pctused
+#: - part_size
+#: - part_avail
+#: - part_used
+#: - part_pctused
+#:
+$AFS_Help{'fs_examine'} = '$path => %info';
+sub AFS_fs_examine {
+  my($path) = @_;
+  my(@args, %info);
+
+  @args = ('examine', '-path', $path);
+  %info = &wrapper('fs', \@args,
+                  [[ 'vid = (\d+) named (\S+)',       'vol_id', 'vol_name' ],
+                   [ 'disk quota is (\d+|unlimited)', 'quota_max' ],
+                   [ 'blocks used are (\d+)',         'quota_used' ],
+                   [ '(\d+) blocks available out of (\d+)',
+                    'part_avail', 'part_size']]);
+  if ($info{'quota_max'} eq 'unlimited') {
+    $info{'quota_max'} = 0;
+    $info{'quota_pctused'} = 0;
+  } else {
+    $info{'quota_pctused'} = ($info{'quota_used'} / $info{'quota_max'}) * 100;
+    $info{'quota_pctused'} =~ s/\..*//;
+  }
+  $info{'part_used'} = $info{'part_size'} - $info{'part_avail'};
+  $info{'part_pctused'} = ($info{'part_used'} / $info{'part_size'}) * 100;
+  $info{'part_pctused'} =~ s/\..*//;
+  %info;
+}
+
+#: AFS_fs_setvol($path, [$maxquota], [$motd])
+#: Set information about the volume containing the specified path.
+#: On success, return 1.
+$AFS_Help{'fs_setvol'} = '$path, [$maxquota], [$motd] => Success?';
+sub AFS_fs_setvol {
+  my($path, $maxquota, $motd) = @_;
+  my(@args);
+
+  @args = ('setvol', '-path', $path);
+  push(@args, '-max', $maxquota) if ($maxquota || $maxquota eq '0');
+  push(@args, '-motd', $motd) if ($motd);
+  &wrapper('fs', \@args);
+  1;
+}
+
+
+#: AFS_fs_getmount($path)
+#: Get the contents of the specified AFS mount point.
+#: On success, return the contents of the specified mount point.
+#: If the specified path is not a mount point, return the empty string.
+$AFS_Help{'fs_getmount'} = '$path => $vol';
+sub AFS_fs_getmount {
+  my($path) = @_;
+  my(@args, $vol);
+
+  @args = ('lsmount', '-dir', $path);
+  &wrapper('fs', \@args,
+          [[ "mount point for volume '(.+)'", \$vol ]]);
+  $vol;
+}
+
+
+#: AFS_fs_mkmount($path, $vol, [$cell], [$rwmount], [$fast])
+#: Create an AFS mount point at $path, leading to the volume $vol.
+#: If $cell is specified, create a cellular mount point to that cell.
+#: If $rwmount is specified and nonzero, create a read-write mount point.
+#: If $fast is specified and nonzero, don't check to see if the volume exists.
+#: On success, return 1.
+$AFS_Help{'fs_mkmount'} = '$path, $vol, [$cell], [$rwmount], [$fast] => Success?';
+sub AFS_fs_mkmount {
+  my($path, $vol, $cell, $rwmount, $fast) = @_;
+  my(@args);
+
+  @args = ('mkmount', '-dir', $path, '-vol', $vol);
+  push(@args, '-cell', $cell) if ($cell);
+  push(@args, '-rw') if ($rwmount);
+  push(@args, '-fast') if ($fast);
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_rmmount($path) [rmmount]
+#: Remove an AFS mount point at $path
+#: On success, return 1
+$AFS_Help{'fs_rmmount'} = '$path => Success?';
+sub AFS_fs_rmmount {
+  my($path) = @_;
+  my(@args);
+
+  @args = ('rmmount', '-dir', $path);
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_checkvolumes()
+#: Check/update volume ID cache
+#: On success, return 1
+$AFS_Help{'fs_checkvolumes'} = '=> Success?';
+sub AFS_fs_checkvolumes {
+  my(@args);
+
+  @args = ('checkvolumes');
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_flush(\@paths)
+#: Flush files named by @paths from the cache
+#: On success, return 1
+$AFS_Help{'fs_flush'} = '\@paths => Success?';
+sub AFS_fs_flush {
+  my($paths) = @_;
+  my(@args);
+
+  @args = ('flush');
+  push(@args, '-path', @$paths) if $paths;
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_flushmount(\@paths)
+#: Flush mount points named by @paths from the cache
+#: On success, return 1
+$AFS_Help{'fs_flushmount'} = '\@paths => Success?';
+sub AFS_fs_flushmount {
+  my($paths) = @_;
+  my(@args);
+
+  @args = ('flushmount');
+  push(@args, '-path', @$paths) if $paths;
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_flushvolume(\@paths)
+#: Flush volumes containing @paths from the cache
+#: On success, return 1
+$AFS_Help{'fs_flushvolume'} = '\@paths => Success?';
+sub AFS_fs_flushvolume {
+  my($paths) = @_;
+  my(@args);
+
+  @args = ('flushvolume');
+  push(@args, '-path', @$paths) if $paths;
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_messages($mode)
+#: Set cache manager message mode
+#: Valid modes are 'user', 'console', 'all', 'none'
+#: On success, return 1
+$AFS_Help{'fs_messages'} = '$mode => Success?';
+sub AFS_fs_messages {
+  my($mode) = @_;
+  my(@args);
+
+  @args = ('messages', '-show', $mode);
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_newcell($cell, \@dbservers, [$linkedcell])
+#: Add a new cell to the cache manager's list, or updating an existing cell
+#: On success, return 1
+$AFS_Help{'fs_newcell'} = '$cell, \@dbservers, [$linkedcell] => Success?';
+sub AFS_fs_newcell {
+  my($cell, $dbservers, $linkedcell) = @_;
+  my(@args);
+
+  @args = ('newcell', '-name', $cell, '-servers', @$dbservers);
+  push(@args, '-linkedcell', $linkedcell) if $linkedcell;
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_rxstatpeer($enable, [$clear])
+#: Control per-peer Rx statistics:
+#: - if $enable is 1, enable stats
+#: - if $enable is 0, disable stats
+#: - if $clear  is 1, clear stats
+#: On success, return 1
+$AFS_Help{'fs_rxstatpeer'} = '$enable, [$clear] => Success?';
+sub AFS_fs_rxstatpeer {
+  my($enable, $clear) = @_;
+  my(@args);
+
+  @args = ('rxstatpeer');
+  push(@args, '-enable')  if $enable;
+  push(@args, '-disable') if defined($enable) && !$enable;
+  push(@args, '-clear')   if $clear;
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_rxstatproc($enable, [$clear])
+#: Control per-process Rx statistics:
+#: - if $enable is 1, enable stats
+#: - if $enable is 0, disable stats
+#: - if $clear  is 1, clear stats
+#: On success, return 1
+$AFS_Help{'fs_rxstatproc'} = '$enable, [$clear] => Success?';
+sub AFS_fs_rxstatproc {
+  my($enable, $clear) = @_;
+  my(@args);
+
+  @args = ('rxstatproc');
+  push(@args, '-enable')  if $enable;
+  push(@args, '-disable') if defined($enable) && !$enable;
+  push(@args, '-clear')   if $clear;
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_setcachesize($size)
+#: Set the cache size to $size K
+#: On success, return 1
+$AFS_Help{'fs_setcachesize'} = '$size => Success?';
+sub AFS_fs_setcachesize {
+  my($size) = @_;
+  my(@args);
+
+  @args = ('setcachesize', '-blocks', $size);
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_setcell(\@cells, $suid)
+#: Set cell control bits for @cells
+#: - if $suid is 1, enable suid programs
+#: - if $suid is 0, disable suid programs
+#: On success, return 1
+$AFS_Help{'fs_setcell'} = '\@cells, [$suid] => Success?';
+sub AFS_fs_setcell {
+  my($cells, $suid) = @_;
+  my(@args);
+
+  @args = ('setcell', '-cell', @$cells);
+  push(@args, '-suid')   if $suid;
+  push(@args, '-nosuid') if defined($suid) && !$suid;
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_setcrypt($enable)
+#: Control cache manager encryption
+#: - if $enable is 1, enable encrypted connections
+#: - if $enable is 0, disable encrypted connections
+#: On success, return 1
+$AFS_Help{'fs_setcrypt'} = '$enable => Success?';
+sub AFS_fs_setcrypt {
+  my($enable) = @_;
+  my(@args);
+
+  @args = ('setcrypt', '-crypt', $enable ? 'on' : 'off');
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_setclientaddrs(\@addrs)
+#: Set client network interface addresses
+#: On success, return 1
+$AFS_Help{'fs_setclientaddrs'} = '\@addrs => Success?';
+sub AFS_fs_setclientaddrs {
+  my($addrs) = @_;
+  my(@args);
+
+  @args = ('setclientaddrs');
+  push(@args, '-address', @$addrs) if $addrs;
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_copyacl($from, \@to, [$clear])
+#: Copy the access control list on $from to each directory named in @to.
+#: If $clear is specified and nonzero, the target ACL's are cleared first
+#: On success, return 1
+$AFS_Help{'fs_copyacl'} = '$from, \@to, [$clear] => Success?';
+sub AFS_fs_copyacl {
+  my($from, $to, $clear) = @_;
+  my(@args);
+
+  @args = ('copyacl', '-fromdir', $from, '-todir', @$to);
+  push(@args, '-clear') if $clear;
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_storebehind(\@paths, [$size], [$def])
+#: Set amount of date to store after file close
+#: If $size is specified, the size for each file in @paths is set to $size.
+#: If $default is specified, the default size is set to $default.
+#: Returns the new or current default value, and a hash mapping filenames
+#: to their storebehind sizes.  A hash entry whose value is undef indicates
+#: that the corresponding file will use the default size.
+$AFS_Help{'fs_storebehind'} = '\@paths, [$size], [$def] => ($def, \%sizes)';
+sub AFS_fs_storebehind {
+  my($paths, $size, $def) = @_;
+  my(@args, %sizes, $ndef);
+
+  @args = ('storebehind', '-verbose');
+  push(@args, '-kbytes', $size) if defined($size);
+  push(@args, '-files', @$paths) if $paths && @$paths;
+  push(@args, '-allfiles', $def) if defined($def);
+  &wrapper('fs', \@args, [
+    ['^Will store up to (\d+) kbytes of (.*) asynchronously',
+     sub { $sizes{$_[1]} = $_[0] }],
+    ['^Will store (.*) according to default',
+     sub { $sizes{$_[0]} = undef }],
+    ['^Default store asynchrony is (\d+) kbytes', \$ndef],
+  ]);
+  ($ndef, \%sizes);
+}
+
+#: AFS_fs_setserverprefs(\%fsprefs, \%vlprefs)
+#: Set fileserver and/or VLDB server preference ranks
+#: Each of %fsprefs and %vlprefs maps server names to the rank to be
+#: assigned to the specified servers.
+#: On success, return 1.
+$AFS_Help{'fs_setserverprefs'} = '\%fsprefs, \%vlprefs => Success?';
+sub AFS_fs_setserverprefs {
+  my($fsprefs, $vlprefs) = @_;
+  my(@args, $srv);
+
+  @args = ('setserverprefs');
+  if ($fsprefs && %$fsprefs) {
+    push(@args, '-servers');
+    foreach $srv (keys %$fsprefs) {
+      push(@args, $srv, $$fsprefs{$srv});
+    }
+  }
+  if ($vlprefs && %$vlprefs) {
+    push(@args, '-vlservers');
+    foreach $srv (keys %$vlprefs) {
+      push(@args, $srv, $$vlprefs{$srv});
+    }
+  }
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_checkservers([$fast], [$allcells], [$cell])
+#: Check to see what fileservers are down
+#: If $cell is specified, fileservers in the specified cell are checked
+#: If $allcells is specified and nonzero, fileservers in all cells are checked
+#: If $fast is specified and nonzero, don't probe servers
+$AFS_Help{'fs_checkservers'} = '[$fast], [$allcells], [$cell] => @down';
+sub AFS_fs_checkservers {
+  my($fast, $allcells, $cell) = @_;
+  my(@args, @down);
+
+  @args = ('checkservers');
+  push(@args, '-all')         if $allcells;
+  push(@args, '-fast')        if $fast;
+  push(@args, '-cell', $cell) if $cell;
+  &wrapper('fs', \@args, [
+    ['^These servers unavailable due to network or server problems: (.*)\.',
+     sub { push(@down, split(' ', $_[0])) }],
+  ]);
+  @down;
+}
+
+#: AFS_fs_checkservers_interval([$interval])
+#: Get and/or set the down server check interval
+#: If $interval is specified and nonzero, it is set as the new interval
+#: On success, returns the old interval in seconds
+$AFS_Help{'fs_checkservers_interval'} = '$interval => $oldinterval';
+sub AFS_fs_checkservers_interval {
+  my($interval) = @_;
+  my(@args, $oldinterval);
+
+  @args = ('checkservers', '-interval', $interval);
+  &wrapper('fs', \@args, [
+    ['^The new down server probe interval \((\d+) secs\)',    \$oldinterval],
+    ['^The current down server probe interval is (\d+) secs', \$oldinterval],
+  ]);
+  $oldinterval;
+}
+
+#: AFS_fs_exportafs($type, \%options);
+#: Get and/or modify protocol translator settings
+#: $type is the translator type, which must be 'nfs'
+#: %options specifies the options to be set.  Each key is the name of an
+#: option, which is enabled if the value is 1, and disabled if the value
+#: is 0.  The following options are supported:
+#:   start       Enable exporting of AFS
+#:   convert     Copy AFS owner mode bits to UNIX group/other mode bits
+#:   uidcheck    Strict UID checking
+#:   submounts   Permit mounts of /afs subdirectories
+#: On success, returns an associative array %modes, which is of the same
+#: form, indicating which options are enabled.
+$AFS_Help{'fs_exportafs'} = '$type, \%options => %modes';
+sub AFS_fs_exportafs {
+  my($type, $options) = @_;
+  my(@args, %modes);
+
+  @args = ('exportafs', '-type', $type);
+  foreach (qw(start convert uidcheck submounts)) {
+    push(@args, "-$_", $$options{$_} ? 'on' : 'off') if exists($$options{$_});
+  }
+
+  &wrapper('fs', \@args, [
+    ['translator is disabled',  sub { $modes{'start'}     = 0 }],
+    ['translator is enabled',   sub { $modes{'start'}     = 1 }],
+    ['strict unix',             sub { $modes{'convert'}   = 0 }],
+    ['convert owner',           sub { $modes{'convert'}   = 1 }],
+    [q/no 'passwd sync'/,       sub { $modes{'uidcheck'}  = 0 }],
+    [q/strict 'passwd sync'/,   sub { $modes{'uidcheck'}  = 1 }],
+    ['Only mounts',             sub { $modes{'submounts'} = 0 }],
+    ['Allow mounts',            sub { $modes{'submounts'} = 1 }],
+  ]);
+  %modes;
+}
+
+
+#: AFS_fs_getcacheparms()
+#: Returns the size of the cache, and the amount of cache space used.
+#: Sizes are returned in 1K blocks.
+$AFS_Help{'fs_getcacheparms'} = 'void => ($size, $used)';
+sub AFS_fs_getcacheparms {
+  my(@args, $size, $used);
+
+  @args = ('getcacheparms');
+  &wrapper('fs', \@args, [
+    [q/AFS using (\d+) of the cache's available (\d+) 1K byte blocks/,
+     \$used, \$size],
+  ]);
+  ($size, $used);
+}
+
+#: AFS_fs_getcellstatus(\@cells)
+#: Get cell control bits for cells listed in @cells.
+#: On success, returns a hash mapping cells to their status; keys are
+#: cell names, and values are 1 if SUID programs are permitted for that
+#: cell, and 0 if not.
+$AFS_Help{'fs_getcellstatus'} = '\@cells => %status';
+sub AFS_fs_getcellstatus {
+  my($cells) = @_;
+  my(@args, %status);
+
+  @args = ('getcellstatus', '-cell', @$cells);
+  &wrapper('fs', \@args, [
+    ['Cell (.*) status: setuid allowed',    sub { $status{$_[0]} = 1 }],
+    ['Cell (.*) status: no setuid allowed', sub { $status{$_[0]} = 0 }],
+  ]);
+  %status;
+}
+
+#: AFS_fs_getclientaddrs
+#: Returns a list of the client interface addresses
+$AFS_Help{'fs_getclientaddrs'} = 'void => @addrs';
+sub AFS_fs_getclientaddrs {
+  my(@args, @addrs);
+
+  @args = ('getclientaddrs');
+  &wrapper('fs', \@args, [
+    ['^(\d+\.\d+\.\d+\.\d+)', \@addrs ]
+  ]);
+  @addrs;
+}
+
+#: AFS_fs_getcrypt
+#: Returns the cache manager encryption flag
+$AFS_Help{'fs_getcrypt'} = 'void => $crypt';
+sub AFS_fs_getcrypt {
+  my(@args, $crypt);
+
+  @args = ('getcrypt');
+  &wrapper('fs', \@args, [
+    ['^Security level is currently clear', sub { $crypt = 0 }],
+    ['^Security level is currently crypt', sub { $crypt = 1 }],
+  ]);
+  $crypt;
+}
+
+#: AFS_fs_getserverprefs([$vlservers], [$numeric])
+#: Get fileserver or vlserver preference ranks
+#: If $vlservers is specified and nonzero, VLDB server ranks
+#: are retrieved; otherwise fileserver ranks are retrieved.
+#: If $numeric is specified and nonzero, servers are identified
+#: by IP address instead of by hostname.
+#: Returns a hash whose keys are server names or IP addresses, and
+#: whose values are the ranks of those servers.
+$AFS_Help{'fs_getserverprefs'} = '[$vlservers], [$numeric] => %prefs';
+sub AFS_fs_getserverprefs {
+  my($vlservers, $numeric) = @_;
+  my(@args, %prefs);
+
+  @args = ('getserverprefs');
+  push(@args, '-numeric')   if $numeric;
+  push(@args, '-vlservers') if $vlservers;
+  &wrapper('fs', \@args, [
+    ['^(\S+)\s*(\d+)', \%prefs],
+  ]);
+  %prefs;
+}
+
+#: AFS_fs_listcells([$numeric')
+#: Get a list of cells known to the cache manager, and the VLDB
+#: servers for each cell.
+#: If $numeric is specified and nonzero, VLDB servers are identified
+#: by IP address instead of by hostname.
+#: Returns a hash where each key is a cell name, and each value is
+#: a list of VLDB servers for the corresponding cell.
+$AFS_Help{'fs_listcells'} = '[$numeric] => %cells';
+sub AFS_fs_listcells {
+  my($numeric) = @_;
+  my(@args, %cells);
+
+  @args = ('listcells');
+  push(@args, '-numeric') if $numeric;
+  &wrapper('fs', \@args, [
+    ['^Cell (\S+) on hosts (.*)\.',
+      sub { $cells{$_[0]} = [ split(' ', $_[1]) ] }],
+  ]);
+  %cells;
+}
+
+#: AFS_fs_setmonitor($server)
+#: Set the cache manager monitor host to $server.
+#: If $server is 'off' or undefined, monitoring is disabled.
+#: On success, return 1.
+$AFS_Help{'fs_setmonitor'} = '$server => Success?';
+sub AFS_fs_setmonitor {
+  my($server) = @_;
+  my(@args);
+
+  @args = ('monitor', '-server', defined($server) ? $server : 'off');
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_getmonitor
+#: Return the cache manager monitor host, or undef if monitoring is disabled.
+$AFS_Help{'fs_getmonitor'} = 'void => $server';
+sub AFS_fs_getmonitor {
+  my(@args, $server);
+
+  @args = ('monitor');
+  &wrapper('fs', \@args, [
+    ['Using host (.*) for monitor services\.', \$server],
+  ]);
+  $server;
+}
+
+#: AFS_fs_getsysname
+#: Returns the current list of system type names
+$AFS_Help{'fs_getsysname'} = 'void => @sys';
+sub AFS_fs_getsysname {
+  my(@args, @sys);
+
+  @args = ('sysname');
+  &wrapper('fs', \@args, [
+    [q/Current sysname is '(.*)'/, \@sys],
+    [q/Current sysname list is '(.*)'/,
+      sub { push(@sys, split(q/' '/, $_[0])) }],
+  ]);
+  @sys;
+}
+
+#: AFS_fs_setsysname(\@sys)
+#: Sets the system type list to @sys
+#: On success, return 1.
+$AFS_Help{'fs_setsysname'} = '$server => Success?';
+sub AFS_fs_setsysname {
+  my($sys) = @_;
+  my(@args);
+
+  @args = ('sysname', '-newsys', @$sys);
+  &wrapper('fs', \@args);
+  1;
+}
+
+#: AFS_fs_whichcell(\@paths)
+#: Get the cells containing the specified paths
+#: Returns a hash in which each key is a pathname, and each value
+#: is the name of the cell which contains the corresponding file.
+$AFS_Help{'fs_whichcell'} = '\@paths => %where';
+sub AFS_fs_whichcell {
+  my($paths) = @_;
+  my(@args, %where);
+
+  @args = ('whichcell', '-path', @$paths);
+  &wrapper('fs', \@args, [
+    [q/^File (.*) lives in cell '(.*)'/, \%where],
+  ]);
+  %where;
+}
+
+#: AFS_fs_wscell
+#: Returns the name of the workstation's home cell
+$AFS_Help{'fs_wscell'} = 'void => $cell';
+sub AFS_fs_wscell {
+  my(@args, $cell);
+
+  @args = ('wscell');
+  &wrapper('fs', \@args, [
+    [q/^This workstation belongs to cell '(.*)'/, \$cell],
+  ]);
+  $cell;
+}
+
diff --git a/src/tests/fs_lib.c b/src/tests/fs_lib.c
new file mode 100644 (file)
index 0000000..04a56b3
--- /dev/null
@@ -0,0 +1,848 @@
+/*
+ * Copyright (c) 1998 - 2001 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <afs/stds.h>
+#include <afs/vice.h>
+#include <afs/venus.h>
+#include <afs/afsint.h>
+#include <afs/auth.h>
+#include <afs/cellconfig.h>
+#include <afs/cmd.h>
+
+enum { PIOCTL_MAXSIZE = 2000 };
+
+struct VenusFid {
+  afs_int32 Cell;
+  struct AFSFid Fid;
+};
+
+/*
+ * fs_getfid, the the `fid' that `path' points on. 
+ */
+
+int
+fs_getfid(char *path, struct VenusFid *fid)
+{
+    struct ViceIoctl a_params;
+
+    if (path == NULL || fid == NULL)
+       return EINVAL;
+
+    a_params.in_size=0;
+    a_params.out_size=sizeof(struct VenusFid);
+    a_params.in=NULL;
+    a_params.out=(void*) fid;
+    
+    if(pioctl(path,VIOCGETFID,&a_params,1) == -1)
+       return errno;
+
+    return 0;
+}
+
+/*
+ * Do nothing
+ */
+
+int
+fs_nop(void)
+{
+    struct ViceIoctl a_params;
+
+    a_params.in_size=0;
+    a_params.out_size=0;
+    a_params.in=NULL;
+    a_params.out=NULL;
+    
+    if (pioctl(NULL,VIOCNOP,&a_params,1) == -1) 
+       return errno;
+
+    return 0;
+}
+
+/*
+ * Get the `cell' that the `path' ends up in
+ */
+
+int
+fs_getfilecellname(char *path, char *cell, size_t len)
+{
+    struct ViceIoctl a_params;
+
+    a_params.in_size=0;
+    a_params.out_size=len;
+    a_params.in=NULL;
+    a_params.out=cell;
+    
+    if (pioctl(path,VIOC_FILE_CELL_NAME,&a_params,1) == -1) 
+       return errno;
+
+    return 0;
+}
+
+/*
+ * set the level of crypt
+ */
+
+#ifdef VIOC_SETRXKCRYPT
+int
+fs_setcrypt (u_int32_t n)
+{
+    struct ViceIoctl   a_params;
+
+    a_params.in_size  = sizeof(n);
+    a_params.out_size = 0;
+    a_params.in              = (char *)&n;
+    a_params.out      = NULL;
+
+    if (pioctl (NULL, VIOC_SETRXKCRYPT, &a_params, 0) == -1)
+       return errno;
+
+    return 0;
+}
+#endif
+
+/*
+ * get currernt level of crypt
+ */
+
+#ifdef VIOC_GETRXKCRYPT
+int
+fs_getcrypt (u_int32_t *level)
+{
+    struct ViceIoctl   a_params;
+
+    a_params.in_size  = 0;
+    a_params.out_size = sizeof(*level);
+    a_params.in              = NULL;
+    a_params.out      = (char *) level;
+
+    if (pioctl (NULL, VIOC_GETRXKCRYPT, &a_params, 0) == -1) 
+       return errno;
+    
+    return 0;
+}
+#endif
+
+/*
+ * get and set the connect-mode
+ */
+
+#ifdef VIOCCONNECTMODE
+int
+fs_connect(int32_t type, int32_t *flags)
+{
+    struct ViceIoctl   a_params;
+
+    a_params.in_size = sizeof(type);
+    a_params.out_size = sizeof (int32_t);
+    a_params.in = (char *) &type;
+    a_params.out = (char *) flags;
+
+    if (pioctl (NULL, VIOCCONNECTMODE, &a_params, 0) == -1)
+       return errno;
+
+    return 0;
+}
+#endif
+
+/*
+ *
+ */
+
+#ifdef VIOC_FPRIOSTATUS
+int
+fs_setfprio(struct VenusFid fid, int16_t prio)
+{
+    struct ViceIoctl   a_params;
+    struct vioc_fprio  fprio;
+
+    fprio.cmd = FPRIO_SET;
+    fprio.Cell = fid.Cell;
+    fprio.Volume = fid.fid.Volume;
+    fprio.Vnode = fid.fid.Vnode;
+    fprio.Unique = fid.fid.Unique;
+    fprio.prio = prio;
+
+    a_params.in_size = sizeof(fprio);
+    a_params.out_size = 0;
+    a_params.in = (char *) &fprio;
+    a_params.out = NULL;
+
+    if (pioctl (NULL, VIOC_FPRIOSTATUS , &a_params, 0) == -1)
+       return errno;
+
+    return 0;
+}
+#endif
+
+#ifdef VIOC_FPRIOSTATUS
+int
+fs_getfprio(struct VenusFid fid, int16_t *prio)
+{
+    struct ViceIoctl   a_params;
+    struct vioc_fprio  fprio;
+
+    fprio.cmd = FPRIO_GET;
+    fprio.Cell = fid.Cell;
+    fprio.Volume = fid.fid.Volume;
+    fprio.Vnode = fid.fid.Vnode;
+    fprio.Unique = fid.fid.Unique;
+
+    a_params.in_size = sizeof(fprio);
+    a_params.out_size = sizeof(*prio);
+    a_params.in = (char *) &fprio;
+    a_params.out = (char *) prio;
+
+    if (pioctl (NULL, VIOC_FPRIOSTATUS , &a_params, 0) == -1)
+       return errno;
+
+    return 0;
+}
+#endif
+
+#ifdef VIOC_FPRIOSTATUS
+int
+fs_setmaxfprio(int16_t maxprio)
+{
+    struct ViceIoctl   a_params;
+    struct vioc_fprio  fprio;
+
+    fprio.cmd = FPRIO_SETMAX;
+    fprio.prio = maxprio;
+
+    a_params.in_size = sizeof(fprio);
+    a_params.out_size = 0;
+    a_params.in = (char *) &fprio;
+    a_params.out = NULL;
+
+    if (pioctl (NULL, VIOC_FPRIOSTATUS , &a_params, 0) == -1)
+       return errno;
+
+    return 0;
+}
+#endif
+
+#ifdef VIOC_FPRIOSTATUS
+int
+fs_getmaxfprio(int16_t *maxprio)
+{
+    struct ViceIoctl   a_params;
+    struct vioc_fprio  fprio;
+
+    fprio.cmd = FPRIO_GETMAX;
+
+    a_params.in_size = sizeof(fprio);
+    a_params.out_size = sizeof(*maxprio);
+    a_params.in = (char *) &fprio;
+    a_params.out = (char *) maxprio;
+
+    if (pioctl (NULL, VIOC_FPRIOSTATUS , &a_params, 0) == -1)
+       return errno;
+
+    return 0;
+}
+#endif
+
+/*
+ *
+ */
+
+#ifdef VIOCGETCACHEPARAMS
+int
+fs_getfilecachestats(u_int32_t *max_bytes,
+                    u_int32_t *used_bytes,
+                    u_int32_t *max_vnodes,
+                    u_int32_t *used_vnodes)
+{
+    u_int32_t parms[16];
+    struct ViceIoctl a_params;
+
+    a_params.in_size  = 0;
+    a_params.out_size = sizeof(parms);
+    a_params.in       = NULL;
+    a_params.out      = (char *) parms;
+
+    memset (parms, 0, sizeof(parms));
+
+    if (pioctl (NULL, VIOCGETCACHEPARAMS , &a_params, 0) == -1)
+       return errno;
+
+    /* param[0] and param[1] send maxbytes and usedbytes in kbytes */
+
+    if (max_vnodes)
+       *max_vnodes = parms[2];
+    if (used_vnodes)
+       *used_vnodes = parms[3];
+    if (max_bytes)
+       *max_bytes = parms[4];
+    if (used_bytes)
+       *used_bytes = parms[5];
+
+    return 0;
+}
+#endif
+
+/*
+ *
+ */
+
+#ifdef VIOC_AVIATOR
+int
+fs_getaviatorstats(u_int32_t *max_workers,
+                  u_int32_t *used_workers)
+{
+    u_int32_t parms[16];
+    struct ViceIoctl a_params;
+
+    a_params.in_size = 0;
+    a_params.out_size = sizeof(parms);
+    a_params.in = NULL;
+    a_params.out = (char *) parms;
+
+    if (pioctl (NULL, VIOC_AVIATOR , &a_params, 0) == -1)
+       return errno;
+
+    if (max_workers)
+       *max_workers = parms[0];
+    if (used_workers)
+       *used_workers = parms[1];
+
+    return 0;
+}
+#endif
+
+/*
+ *
+ */
+
+#ifdef VIOC_GCPAGS
+int
+fs_gcpags(void)
+{
+    struct ViceIoctl a_params;
+
+    a_params.in_size  = 0;
+    a_params.out_size = 0;
+    a_params.in       = NULL;
+    a_params.out      = NULL;
+
+
+    if (pioctl(NULL, VIOC_GCPAGS, &a_params, 0) != 0)
+       return errno;
+    
+    return 0;
+}
+#endif
+
+/*
+ *
+ */
+
+#ifdef VIOC_CALCULATE_CACHE
+int
+fs_calculate_cache(u_int32_t *calculated,
+                  u_int32_t *usedbytes)
+{
+    u_int32_t parms[16];
+    struct ViceIoctl a_params;
+
+    a_params.in_size = 0;
+    a_params.out_size = sizeof(parms);
+    a_params.in = NULL;
+    a_params.out = (char *) parms;
+
+    if (pioctl (NULL, VIOC_CALCULATE_CACHE , &a_params, 0) == -1)
+       return errno;
+
+    if (calculated)
+       *calculated = parms[0];
+    if (usedbytes)
+       *usedbytes = parms[1];
+
+    return 0;
+}
+#endif
+
+/*
+ *
+ */
+
+#ifdef VIOC_BREAKCALLBACK
+int
+fs_invalidate (const char *path)
+{
+    struct ViceIoctl   a_params;
+
+    a_params.in_size  = 0;
+    a_params.out_size = 0;
+    a_params.in       = NULL;
+    a_params.out      = NULL;
+    
+    if (pioctl ((char *)path, VIOC_BREAKCALLBACK, &a_params, 0) < 0)
+       return errno;
+    else
+       return 0;
+}
+#endif
+
+/*
+ * Get/set debug levels with pioctl_cmd.
+ *
+ * inflags == -1 -> don't change
+ * outflags == NULL -> don't return
+ */
+
+static int
+debug (int pioctl_cmd, int inflags, int *outflags, char *pathname)
+{
+    struct ViceIoctl   a_params;
+
+    int32_t rinflags = inflags;
+    int32_t routflags;
+
+    if (inflags != -1) {
+       a_params.in_size = sizeof(rinflags);
+       a_params.in = (char *) &rinflags;
+    } else {
+       a_params.in_size = 0;
+       a_params.in = NULL;
+    }
+       
+    if (outflags) {
+       a_params.out_size = sizeof(routflags);
+       a_params.out = (char *)  &routflags;
+    } else {
+       a_params.out_size = 0;
+       a_params.out = NULL;
+    }
+
+    if (pioctl (pathname, pioctl_cmd, &a_params, 0) == -1)
+       return errno;
+    
+    if (outflags)
+       *outflags = routflags;
+
+    return 0;
+}
+
+/*
+ * xfs_debug
+ */
+
+#ifdef VIOC_XFSDEBUG
+int
+xfs_debug(int inflags, int *outflags)
+{
+    return debug (VIOC_XFSDEBUG, inflags, outflags, NULL);
+}
+#endif
+
+/*
+ * xfs_debug_print
+ */
+
+#ifdef VIOC_XFSDEBUG_PRINT
+int
+xfs_debug_print(int inflags, char *pathname)
+{
+    return debug (VIOC_XFSDEBUG_PRINT, inflags, NULL, pathname);
+}
+#endif
+
+/*
+ * arla_debug
+ */
+
+#ifdef VIOC_ARLADEBUG
+int
+arla_debug (int inflags, int *outflags)
+{
+    return debug (VIOC_ARLADEBUG, inflags, outflags, NULL);
+}
+#endif
+
+/*
+ * checkservers
+ *
+ *   flags is the same flags as in CKSERV flags
+ *
+ */
+
+int
+fs_checkservers(char *cell, int32_t flags, u_int32_t *hosts, int numhosts)
+{
+    struct ViceIoctl a_params;
+    char *in = NULL;
+    int ret;
+    size_t insize;
+
+    if (cell != NULL) {
+       insize = strlen(cell) + sizeof(int32_t) + 1;
+       in = malloc (insize);
+       if (in == NULL)
+           errx (1, "malloc");
+
+       memcpy (in, &flags, sizeof(flags));
+
+       memcpy (in + sizeof(int32_t), cell, strlen(cell));
+       in[sizeof(int32_t) + strlen(cell)] = '\0';
+       
+       a_params.in_size = insize;
+       a_params.in = in;
+    } else {
+       a_params.in_size = sizeof(flags);
+       a_params.in = (caddr_t )&flags;
+    }
+
+    a_params.out_size = numhosts * sizeof(u_int32_t);
+    a_params.out = (caddr_t)hosts;
+
+    ret = 0;
+
+    if (pioctl (NULL, VIOCCKSERV, &a_params, 0) == -1)
+       ret = errno;
+    
+    if (in)
+       free(in);
+
+    return ret;
+}
+
+/*
+ * check validity of cached volume information
+ */
+
+int
+fs_checkvolumes (void)
+{
+    struct ViceIoctl a_params;
+
+    a_params.in       = NULL;
+    a_params.in_size  = 0;
+    a_params.out      = NULL;
+    a_params.out_size = 0;
+
+    if (pioctl (NULL, VIOCCKBACK, &a_params, 0) < 0)
+       return errno;
+    else
+       return 0;
+}
+
+/*
+ * set current sysname to `sys'
+ */
+
+int
+fs_set_sysname (const char *sys)
+{
+    struct ViceIoctl a_params;
+    int32_t set = 1;
+
+    a_params.in_size  = sizeof(set) + strlen(sys) + 1;
+    a_params.in       = malloc(a_params.in_size);
+    if (a_params.in == NULL)
+       return ENOMEM;
+    a_params.out      = NULL;
+    a_params.out_size = 0;
+    memcpy (a_params.in, &set, sizeof(set));
+    strcpy (a_params.in + sizeof(set), sys);
+
+    if(pioctl (NULL, VIOC_AFS_SYSNAME, &a_params, 1) < 0)
+       return errno;
+    else
+       return 0;
+}
+
+/*
+ *
+ */
+
+int
+fs_setcache(int lv, int hv, int lb, int hb)
+{
+    struct ViceIoctl a_params;
+    u_int32_t s[4];
+
+    s[0] = lv;
+    s[1] = hv;
+    s[2] = lb;
+    s[3] = hb;
+
+    a_params.in_size  = ((hv == 0) ? 1 : 4) * sizeof(u_int32_t);
+    a_params.out_size = 0;
+    a_params.in       = (void *)s;
+    a_params.out      = NULL;
+
+    if (pioctl(NULL, VIOCSETCACHESIZE, &a_params, 0) < 0)
+       return errno;
+    else
+       return 0;
+}
+
+/*
+ * return the local cell in `cell' (of size `cell_sz').
+ */
+
+int
+fs_wscell (char *cell, size_t cell_sz)
+{
+    struct ViceIoctl a_params;
+
+    a_params.in_size  = 0;
+    a_params.in       = NULL;
+    a_params.out_size = cell_sz;
+    a_params.out      = cell;
+
+    if (pioctl (NULL, VIOC_GET_WS_CELL, &a_params, 0) < 0)
+       return errno;
+    return 0;
+}
+
+/*
+ * Flush the contents of the volume pointed to by `path'.
+ */
+
+int
+fs_flushvolume (const char *path)
+{
+    struct ViceIoctl a_params;
+
+    a_params.in_size  = 0;
+    a_params.out_size = 0;
+    a_params.in       = NULL;
+    a_params.out      = NULL;
+
+    if (pioctl ((char *)path, VIOC_FLUSHVOLUME, &a_params, 0) < 0)
+       return errno;
+    else
+       return 0;
+}
+
+/*
+ * Flush the file `path' from the cache.
+ */
+
+int
+fs_flush (const char *path)
+{
+    struct ViceIoctl a_params;
+
+    a_params.in_size  = 0;
+    a_params.out_size = 0;
+    a_params.in       = NULL;
+    a_params.out      = NULL;
+
+    if (pioctl ((char *)path, VIOCFLUSH, &a_params, 0) < 0)
+       return errno;
+    else
+       return 0;
+}
+
+/*
+ *
+ */
+
+int
+fs_venuslog (void)
+{
+    struct ViceIoctl a_params;
+    int32_t status = 0;   /* XXX not really right, but anyway */
+
+    a_params.in_size  = sizeof(int32_t);
+    a_params.out_size = 0;
+    a_params.in       = (caddr_t) &status;
+    a_params.out      = NULL;
+
+    if (pioctl (NULL, VIOC_VENUSLOG, &a_params, 0) < 0)
+       return errno;
+    else
+       return 0;
+}
+
+/*
+ * Get status for `cell' and put the flags in `flags'.
+ */
+
+int
+fs_getcellstatus (char *cellname, u_int32_t *flags)
+{
+    struct ViceIoctl a_params;
+
+    a_params.in_size  = strlen (cellname) + 1;
+    a_params.out_size = sizeof (u_int32_t);
+    a_params.in       = cellname;
+    a_params.out      = (caddr_t) flags;
+
+    if (pioctl (NULL, VIOC_GETCELLSTATUS, &a_params, 0) < 0)
+       return errno;
+    else
+       return 0;
+}
+
+/*
+ * Separate `path' into directory and last component and call
+ * pioctl with `pioctl_cmd'.
+ */
+
+static int
+internal_mp (const char *path, int pioctl_cmd, char **res)
+{
+    struct ViceIoctl    a_params;
+    char               *last;
+    char               *path_bkp;
+    int                        error;
+
+    path_bkp = strdup (path);
+    if (path_bkp == NULL) {
+       printf ("fs: Out of memory\n");
+       return ENOMEM;
+    }
+
+    a_params.out = malloc (PIOCTL_MAXSIZE);
+    if (a_params.out == NULL) {
+       printf ("fs: Out of memory\n");
+       free (path_bkp);
+       return ENOMEM;
+    }
+
+    /* If path contains more than the filename alone - split it */
+
+    last = strrchr (path_bkp, '/');
+    if (last != NULL) {
+       *last = '\0';
+       a_params.in = last + 1;
+    } else
+       a_params.in = (char *)path;
+
+    a_params.in_size = strlen (a_params.in) + 1;
+    a_params.out_size = PIOCTL_MAXSIZE;
+
+    error = pioctl (last ? path_bkp : "." ,
+                     pioctl_cmd, &a_params, 1);
+    if (error < 0) {
+       error = errno;
+       free (path_bkp);
+       free (a_params.out);
+       return error;
+    }
+
+    if (res != NULL)
+       *res = a_params.out;
+    else
+       free (a_params.out);
+    free (path_bkp);
+    return 0;
+}
+
+int
+fs_lsmount (const char *path)
+{
+    char *res;
+    int error = internal_mp (path, VIOC_AFS_STAT_MT_PT, &res);
+
+    if (error == 0) {
+       printf ("'%s' is a mount point for volume '%s'\n", path, res);
+       free (res);
+    }
+    return error;
+}
+
+int
+fs_rmmount (const char *path)
+{
+    return internal_mp (path, VIOC_AFS_DELETE_MT_PT, NULL);
+}
+
+int
+fs_incompat_renumber (int *ret)
+{
+    struct ViceIoctl a_params;
+    unsigned char buf[1024];
+
+    a_params.in_size  = 0;
+    a_params.out_size = sizeof(buf);
+    a_params.in       = 0;
+    a_params.out      = (caddr_t) buf;
+
+    /* getcrypt or getinitparams */
+    if (pioctl (NULL, _VICEIOCTL(49), &a_params, 0) < 0) {
+       if (errno == EINVAL) {
+
+           /* not openafs or old openafs */
+
+           a_params.in_size  = 0;
+           a_params.out_size = 4;
+           a_params.in       = 0;
+           a_params.out      = (caddr_t) buf;
+           
+           if (pioctl (NULL, _VICEIOCTL(49), &a_params, 0) < 0) {
+               if (errno == EINVAL) {
+                   
+                   a_params.in_size  = 0;
+                   a_params.out_size = 4;
+                   a_params.in       = 0;
+                   a_params.out      = (caddr_t) buf;
+                   
+                   /* might be new interface */
+
+                   if (pioctl (NULL, _VICEIOCTL(55), &a_params, 0) < 0)
+                       return errno; /* dunno */
+                   
+                   *ret = 1;
+                   return 0;
+               } else {
+                   return errno;
+               }
+           }
+           *ret = 0;
+           return 0;
+       } else
+           return errno;
+    }
+    *ret = 1;
+    return 0;
+}
diff --git a/src/tests/fsx.c b/src/tests/fsx.c
new file mode 100644 (file)
index 0000000..0b67ae8
--- /dev/null
@@ -0,0 +1,1054 @@
+/*
+ *     Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
+ *
+ *     File:   fsx.c
+ *     Author: Avadis Tevanian, Jr.
+ *
+ *     File system exerciser. 
+ *
+ *     Rewritten 8/98 by Conrad Minshall.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(_UWIN) || defined(__linux)
+# include <sys/param.h>
+# include <limits.h>
+# include <time.h>
+# include <strings.h>
+# define MAP_FILE 0
+#else
+# include <sys/dirent.h>
+#endif
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <limits.h>
+#include <err.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#define NUMPRINTCOLUMNS 32     /* # columns of data to print on each line */
+
+/*
+ *     A log entry is an operation and a bunch of arguments.
+ */
+
+struct log_entry {
+       int     operation;
+       int     args[3];
+};
+
+#define        LOGSIZE 1000
+
+struct log_entry       oplog[LOGSIZE]; /* the log */
+int                    logptr = 0;     /* current position in log */
+int                    logcount = 0;   /* total ops */
+
+/*
+ *     Define operations
+ */
+
+#define        OP_READ         1
+#define OP_WRITE       2
+#define OP_TRUNCATE    3
+#define OP_CLOSEOPEN   4
+#define OP_MAPREAD     5
+#define OP_MAPWRITE    6
+#define OP_SKIPPED     7
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE       4096
+#endif
+#define PAGE_MASK       (PAGE_SIZE - 1)
+
+char   *original_buf;                  /* a pointer to the original data */
+char   *good_buf;                      /* a pointer to the correct data */
+char   *temp_buf;                      /* a pointer to the current data */
+char   *fname;                         /* name of our test file */
+int    fd;                             /* fd for our test file */
+
+off_t          file_size = 0;
+off_t          biggest = 0;
+char           state[256];
+unsigned long  testcalls = 0;          /* calls to function "test" */
+
+unsigned long  simulatedopcount = 0;   /* -b flag */
+int    closeprob = 0;                  /* -c flag */
+int    debug = 0;                      /* -d flag */
+unsigned long  debugstart = 0;         /* -D flag */
+unsigned long  maxfilelen = 256 * 1024;        /* -l flag */
+int    sizechecks = 1;                 /* -n flag disables them */
+int    maxoplen = 64 * 1024;           /* -o flag */
+int    quiet = 0;                      /* -q flag */
+unsigned long progressinterval = 0;    /* -p flag */
+int    readbdy = 1;                    /* -r flag */
+int    style = 0;                      /* -s flag */
+int    truncbdy = 1;                   /* -t flag */
+int    writebdy = 1;                   /* -w flag */
+long   monitorstart = -1;              /* -m flag */
+long   monitorend = -1;                /* -m flag */
+int    lite = 0;                       /* -L flag */
+long   numops = -1;                    /* -N flag */
+int    randomoplen = 1;                /* -O flag disables it */
+int    seed = 1;                       /* -S flag */
+int     mapped_writes = 1;              /* -W flag disables */
+int    mapped_reads = 1;               /* -R flag disables it */
+int    fsxgoodfd = 0;
+FILE * fsxlogf = NULL;
+int badoff = -1;
+int closeopen = 0;
+
+
+void
+prt(char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       vfprintf(stdout, fmt, args);
+       if (fsxlogf)
+               vfprintf(fsxlogf, fmt, args);
+       va_end(args);
+}
+
+void
+prterr(char *prefix)
+{
+       prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
+}
+
+
+void
+log4(int operation, int arg0, int arg1, int arg2)
+{
+       struct log_entry *le;
+
+       le = &oplog[logptr];
+       le->operation = operation;
+       if (closeopen)
+               le->operation = ~ le->operation;
+       le->args[0] = arg0;
+       le->args[1] = arg1;
+       le->args[2] = arg2;
+       logptr++;
+       logcount++;
+       if (logptr >= LOGSIZE)
+               logptr = 0;
+}
+
+
+void
+logdump(void)
+{
+       int     i, count, down;
+       struct log_entry        *lp;
+
+       prt("LOG DUMP (%d total operations):\n", logcount);
+       if (logcount < LOGSIZE) {
+               i = 0;
+               count = logcount;
+       } else {
+               i = logptr;
+               count = LOGSIZE;
+       }
+       for ( ; count > 0; count--) {
+               int opnum;
+
+               opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
+               prt("%d(%d mod 256): ", opnum, opnum%256);
+               lp = &oplog[i];
+               if ((closeopen = lp->operation < 0))
+                       lp->operation = ~ lp->operation;
+                       
+               switch (lp->operation) {
+               case OP_MAPREAD:
+                       prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)",
+                           lp->args[0], lp->args[0] + lp->args[1] - 1,
+                           lp->args[1]);
+                       if (badoff >= lp->args[0] && badoff <
+                                                    lp->args[0] + lp->args[1])
+                               prt("\t***RRRR***");
+                       break;
+               case OP_MAPWRITE:
+                       prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)",
+                           lp->args[0], lp->args[0] + lp->args[1] - 1,
+                           lp->args[1]);
+                       if (badoff >= lp->args[0] && badoff <
+                                                    lp->args[0] + lp->args[1])
+                               prt("\t******WWWW");
+                       break;
+               case OP_READ:
+                       prt("READ\t0x%x thru 0x%x\t(0x%x bytes)",
+                           lp->args[0], lp->args[0] + lp->args[1] - 1,
+                           lp->args[1]);
+                       if (badoff >= lp->args[0] &&
+                           badoff < lp->args[0] + lp->args[1])
+                               prt("\t***RRRR***");
+                       break;
+               case OP_WRITE:
+                       prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)",
+                           lp->args[0], lp->args[0] + lp->args[1] - 1,
+                           lp->args[1]);
+                       if (lp->args[0] > lp->args[2])
+                               prt(" HOLE");
+                       else if (lp->args[0] + lp->args[1] > lp->args[2])
+                               prt(" EXTEND");
+                       if ((badoff >= lp->args[0] || badoff >=lp->args[2]) &&
+                           badoff < lp->args[0] + lp->args[1])
+                               prt("\t***WWWW");