]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
Initial revision
authorSam Hartman <hartmans@debian.org>
Tue, 22 Jan 2002 19:52:31 +0000 (19:52 +0000)
committerSam Hartman <hartmans@debian.org>
Tue, 22 Jan 2002 19:52:31 +0000 (19:52 +0000)
298 files changed:
src/bozo/bos_util.c [new file with mode: 0644]
src/config/Makefile.ppc_darwin_14.in [new file with mode: 0644]
src/config/Makefile.sparc_linux24.in [new file with mode: 0644]
src/config/param.ppc_darwin_14.h [new file with mode: 0644]
src/config/param.ppc_darwin_14_usr.h [new file with mode: 0644]
src/config/param.sparc_linux24.h [new file with mode: 0644]
src/config/param.sparc_linux24_usr.h [new file with mode: 0644]
src/rx/rxperf.c [new file with mode: 0644]
src/tests/Makefile.in [new file with mode: 0644]
src/tests/OpenAFS/Auth-Heimdal.pm [new file with mode: 0644]
src/tests/OpenAFS/CMU_copyright.pm [new file with mode: 0644]
src/tests/OpenAFS/ConfigUtils.pm [new file with mode: 0644]
src/tests/OpenAFS/Dirpath.pm.in [new file with mode: 0644]
src/tests/OpenAFS/OS-LINUX.pm [new file with mode: 0644]
src/tests/OpenAFS/OS-SOLARIS.pm [new file with mode: 0644]
src/tests/OpenAFS/afsconf.pm [new file with mode: 0644]
src/tests/OpenAFS/bos.pm [new file with mode: 0644]
src/tests/OpenAFS/config.pm [new file with mode: 0644]
src/tests/OpenAFS/errtrans.pm [new file with mode: 0644]
src/tests/OpenAFS/fs.pm [new file with mode: 0644]
src/tests/OpenAFS/kas.pm [new file with mode: 0644]
src/tests/OpenAFS/pts.pm [new file with mode: 0644]
src/tests/OpenAFS/util.pm [new file with mode: 0644]
src/tests/OpenAFS/vos.pm [new file with mode: 0644]
src/tests/OpenAFS/wrapper.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/README.dumptool [new file with mode: 0644]
src/tests/TEMPLATE [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/afscp.c [new file with mode: 0644]
src/tests/afscp_callback.c [new file with mode: 0644]
src/tests/afsdump_dirlist.c [new file with mode: 0644]
src/tests/afsdump_extract.c [new file with mode: 0644]
src/tests/afsdump_scan.c [new file with mode: 0644]
src/tests/afsdump_xsed.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/backuphdr.c [new file with mode: 0644]
src/tests/baduniq.pl [new file with mode: 0755]
src/tests/blocks-new-file.c [new file with mode: 0644]
src/tests/boot-strap-arla [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/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/directory.c [new file with mode: 0644]
src/tests/dump.c [new file with mode: 0644]
src/tests/dumpfmt.h [new file with mode: 0644]
src/tests/dumpscan.h [new file with mode: 0644]
src/tests/dumpscan_errs.et [new file with mode: 0644]
src/tests/dumptool.c [new file with mode: 0644]
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/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_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/int64.c [new file with mode: 0644]
src/tests/intNN.h [new file with mode: 0644]
src/tests/internal.h [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/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/null-search.c [new file with mode: 0644]
src/tests/parallel1 [new file with mode: 0644]
src/tests/parsedump.c [new file with mode: 0644]
src/tests/parsetag.c [new file with mode: 0644]
src/tests/parsevnode.c [new file with mode: 0644]
src/tests/parsevol.c [new file with mode: 0644]
src/tests/pathname.c [new file with mode: 0644]
src/tests/pine.c [new file with mode: 0644]
src/tests/primitive.c [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/repair.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: 0644]
src/tests/run-suite.pl [new file with mode: 0755]
src/tests/run-tests.in [new file with mode: 0644]
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/stagehdr.c [new file with mode: 0644]
src/tests/stagehdr.h [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-front.sh [new file with mode: 0755]
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.c [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/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/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]
src/tests/xf_errs.et [new file with mode: 0644]
src/tests/xf_files.c [new file with mode: 0644]
src/tests/xf_printf.c [new file with mode: 0644]
src/tests/xf_profile.c [new file with mode: 0644]
src/tests/xf_rxcall.c [new file with mode: 0644]
src/tests/xfiles.c [new file with mode: 0644]
src/tests/xfiles.h [new file with mode: 0644]
src/tools/install/RPM.README [new file with mode: 0644]
src/tools/install/afs_uninstall [new file with mode: 0644]
src/tools/install/afsinit_both [new file with mode: 0644]
src/tools/install/afsinit_client [new file with mode: 0644]
src/tools/install/afsinit_server [new file with mode: 0644]
src/tools/install/check_udebug.pl [new file with mode: 0644]
src/tools/install/install_afs [new file with mode: 0644]
src/tools/install/make_rpm_source [new file with mode: 0644]
src/tools/install/openafs-tools-cmd-1.2.2-1.spec [new file with mode: 0644]
src/tools/install/unpack_cmd [new file with mode: 0644]
src/tools/install/write_fstab.pl [new file with mode: 0644]
src/tools/install/write_pam.pl [new file with mode: 0644]
src/tools/openafs-tools-cmd.README [new file with mode: 0644]

diff --git a/src/bozo/bos_util.c b/src/bozo/bos_util.c
new file mode 100644 (file)
index 0000000..63198c1
--- /dev/null
@@ -0,0 +1,201 @@
+/* 
+ *  Copyright (C) 1989 by the Massachusetts Institute of Technology
+ * 
+ *    Export of software employing encryption from the United States of
+ *    America is assumed to require a specific license from the United
+ *    States Government.  It is the responsibility of any person or
+ *    organization contemplating export to obtain such a license before
+ *    exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+RCSID("$Header: /tmp/cvstemp/openafs/src/bozo/bos_util.c,v 1.1 2002/01/22 19:52:32 hartmans Exp $");
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <afs/stds.h>
+#include <afs/afsutil.h>
+#include <rx/rxkad.h>
+#include <afs/keys.h>
+#include <afs/cellconfig.h>
+
+int 
+main(int argc, char **argv)
+{
+    struct afsconf_dir *tdir;
+    register afs_int32 code;
+
+    if (argc == 1) {
+       printf("bos_util: usage is 'bos_util <opcode> options, e.g.\n");
+       printf("    bos_util add <kvno>\n");
+       printf("    bos_util adddes <kvno>\n");
+#ifdef KERBEROS
+       printf("    bos_util srvtab2keyfile <kvno> <keyfile> <princ>\n");
+#endif
+       printf("    bos_util delete <kvno>\n");
+       printf("    bos_util list\n");
+       exit(1);
+    }
+
+    tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIR);
+    if (!tdir) {
+       printf("bos_util: can't initialize conf dir '%s'\n", AFSDIR_SERVER_ETC_DIR);
+       exit(1);
+    }
+    if (strcmp(argv[1], "add")==0) {
+       struct ktc_encryptionKey tkey;
+       int kvno;
+       char buf[BUFSIZ], ver[BUFSIZ];
+       char *tcell = (char *) 0;
+
+       if (argc != 3) {
+           printf("bos_util add: usage is 'bos_util add <kvno>\n");
+           exit(1);
+       }
+       kvno = atoi(argv[2]);
+       memset(&tkey, 0, sizeof(struct ktc_encryptionKey));
+
+       /* prompt for key */
+       code=des_read_pw_string(buf,sizeof(buf),"input key: ",0);
+       if(code || strlen(buf)==0) {
+           printf("Bad key: \n");
+           exit(1);
+       }
+       code=des_read_pw_string(ver,sizeof(ver),"Retype input key: ",0);
+       if(code || strlen(ver)==0) {
+           printf("Bad key: \n");
+           exit(1);
+       }
+       if (strcmp (ver, buf) != 0) {
+           printf ("\nInput key mismatch\n");
+           exit(1);
+       }
+       ka_StringToKey(buf,tcell,&tkey);
+       code = afsconf_AddKey(tdir, kvno, &tkey);
+       if (code) {
+           printf("bos_util: failed to set key, code %d.\n", code);
+           exit(1);
+       }
+    }
+    else if (strcmp(argv[1], "adddes")==0) {
+       struct ktc_encryptionKey tkey;
+       int kvno;
+       register afs_int32 code;
+       char buf[BUFSIZ], ver[BUFSIZ];
+       char *tcell = (char *) 0;
+
+       if (argc != 3) {
+           printf("bos_util adddes: usage is 'bos_util adddes <kvno>\n");
+           exit(1);
+       }
+       kvno = atoi(argv[2]);
+       memset(&tkey, 0, sizeof(struct ktc_encryptionKey));
+
+       /* prompt for key */
+       code=des_read_pw_string(buf,sizeof(buf),"input key: ",0);
+       if(code || strlen(buf)==0) {
+           printf("Bad key: \n");
+           exit(1);
+       }
+       code=des_read_pw_string(ver,sizeof(ver),"Retype input key: ",0);
+       if(code || strlen(ver)==0) {
+           printf("Bad key: \n");
+           exit(1);
+       }
+       if (strcmp (ver, buf) != 0) {
+           printf ("\nInput key mismatch\n");
+           exit(1);
+       }
+       des_string_to_key(buf,&tkey);
+       code = afsconf_AddKey(tdir, kvno, &tkey);
+       if (code) {
+           printf("bos_util: failed to set key, code %d.\n", code);
+           exit(1);
+       }
+    }
+#ifdef KERBEROS
+    else if (strcmp(argv[1], "srvtab2keyfile")==0) {
+       char tkey[8], name[255], inst[255], realm[255];
+       int kvno;
+       if (argc != 5) {
+           printf("bos_util add: usage is 'bos_util srvtab2keyfile <kvno> <keyfile> <princ>\n");
+           exit(1);
+       }
+       kvno = atoi(argv[2]);
+       bzero(tkey, sizeof(tkey));
+       code = kname_parse(name, inst, realm, argv[4]);
+       if (code != 0) {
+               printf("Invalid kerberos name\n");
+               exit(1);
+       }
+       code = read_service_key(name, inst, realm, kvno, argv[3], tkey);
+       if (code != 0) {
+               printf("Can't find key in %s\n", argv[3]);
+               exit(1);
+       }
+       code = afsconf_AddKey(tdir, kvno, tkey);
+       if (code) {
+           printf("bos_util: failed to set key, code %d.\n", code);
+           exit(1);
+       }
+    }
+#endif
+    else if (strcmp(argv[1], "delete")==0) {
+       long kvno;
+       if (argc != 3) {
+           printf("bos_util delete: usage is 'bos_util delete <kvno>\n");
+           exit(1);
+       }
+       kvno = atoi(argv[2]);
+       code = afsconf_DeleteKey(tdir, kvno);
+       if (code) {
+           printf("bos_util: failed to delete key %d, (code %d)\n", kvno, code);
+           exit(1);
+       }
+    }
+    else if (strcmp(argv[1], "list") == 0) {
+       struct afsconf_keys tkeys;
+       register int i;
+       unsigned char tbuffer[9];
+       
+       code = afsconf_GetKeys(tdir, &tkeys);
+       if (code) {
+           printf("bos_util: failed to get keys, code %d\n", code);
+           exit(1);
+       }
+       for(i=0;i<tkeys.nkeys;i++) {
+           if (tkeys.key[i].kvno != -1) {
+               int count;
+               unsigned char x[8];
+               memcpy(tbuffer, tkeys.key[i].key, 8);
+               tbuffer[8] = 0;
+               printf("kvno %4d: key is '%s' '", tkeys.key[i].kvno, tbuffer);
+               strcpy(x,(char *)tbuffer);
+               for(count=0;count<8;count++)
+                   printf("\\%03o",(unsigned char *)x[count]);
+               printf("'\n");
+           }
+       }
+       printf("All done.\n");
+    }
+    else {
+       printf("bos_util: unknown operation '%s', type 'bos_util' for assistance\n");
+       exit(1);
+    }
+    exit(0);
+}
diff --git a/src/config/Makefile.ppc_darwin_14.in b/src/config/Makefile.ppc_darwin_14.in
new file mode 100644 (file)
index 0000000..3dfaaaa
--- /dev/null
@@ -0,0 +1,43 @@
+# Keep macros within each section in sorted order for clean diff displays.
+#
+# AFS_OSTYPE used to indicate suffixes and os specific subdirectories.
+AFS_OSTYPE = DARWIN
+#
+#
+# compilation and link editor flags
+XCFLAGS=-no-cpp-precomp
+#MT_CFLAGS=-D_REENTRANT -DAFS_PTHREAD_ENV ${XCFLAGS}
+#MT_CC=cc
+KROOT=
+KINCLUDES=-I$(KROOT)/System/Library/Frameworks/Kernel.framework/Headers
+#SHARE_LDFLAGS =
+LWP_OPTMZ=-O2
+OPTMZ=-O2
+DBG=-g
+REGEX_OBJ=regex.o
+
+
+#
+# libraries
+XLIBS=@LIB_AFSDB@
+TXLIBS=
+#MTLIBS=
+#XLIBELFA=
+#XLIBKVM=
+#
+SHLIB_SUFFIX=
+SHLIB_CFLAGS=
+#
+# programs
+AR=ar
+AS=as
+CC=cc
+CP=cp
+INSTALL=${TOP_SRCDIR}/pinstall/pinstall
+LEX=lex -l
+LD= ld
+LORDER = lorder
+MV=mv
+RANLIB=ranlib
+RM=rm
+STRIP= strip
diff --git a/src/config/Makefile.sparc_linux24.in b/src/config/Makefile.sparc_linux24.in
new file mode 100644 (file)
index 0000000..b550bd7
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright 1998 Transarc Corporation 
+#
+# Keep macros within each section in sorted order for clean diff displays.
+#
+# AFS_OSTYPE used to indicate suffixes and os specific subdirectories.
+AFS_OSTYPE = LINUX
+
+# Base directory for linux kernel source. Actually a prefix which is complete
+# when LINUX_VERS is appended to it.
+LINUX_SRCDIR = /usr/src/linux-
+# Default list of Linux kernels to build. Build will run only if all
+# can be built. To build a different set, specify LINUX_VERS to make.
+LINUX_VERS = 2.2.14
+
+#
+# compilation and link editor flags
+DBG=-g
+OPTMZ=-O2
+PAM_CFLAGS = -O2 -Dlinux -DLINUX_PAM -fPIC
+# Put -O2 here to _ensure_ all Makefiles pick it up.
+XCFLAGS= -O2
+MT_CFLAGS=-DAFS_PTHREAD_ENV -pthread -D_REENTRANT ${XCFLAGS}
+XLDFLAGS=
+SHARE_LDFLAGS = -shared -Xlinker -x
+SHLIB_SUFFIX=so
+SHLIB_CFLAGS=
+#
+# libraries
+MTLIBS=-lpthread
+TXLIBS= /usr/lib/libncurses.so
+XLIBS=@LIB_AFSDB@
+#
+# programs
+AR=ar
+AS=as
+CP=cp
+LD=ld   
+MT_CC=cc
+MV=mv
+RANLIB=ranlib
+RM=rm
+INSTALL=${TOP_SRCDIR}/pinstall/pinstall
+#
+# Other OS specific requirements
+#
+YACC = bison -y
+LEX = flex -l
diff --git a/src/config/param.ppc_darwin_14.h b/src/config/param.ppc_darwin_14.h
new file mode 100644 (file)
index 0000000..aff9457
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef AFS_PARAM_H
+#define AFS_PARAM_H
+
+#define AFS_ENV                 1
+#define AFS_64BIT_ENV           1       /* Defines afs_int32 as int, not long. */
+#define AFS_PPC_ENV 1
+#define AFS_VFSINCL_ENV 1
+
+#include <afs/afs_sysnames.h>
+
+#define AFS_DARWIN_ENV
+#define AFS_DARWIN13_ENV
+#define AFS_DARWIN14_ENV
+#define AFS_NONFSTRANS
+#define AFS_SYSCALL             230
+
+/* File system entry (used if mount.h doesn't define MOUNT_AFS */
+#define AFS_MOUNT_AFS    "afs"
+
+/* Machine / Operating system information */
+#define sys_ppc_darwin_12   1
+#define sys_ppc_darwin_13   1
+#define sys_ppc_darwin_14   1
+#define SYS_NAME        "ppc_darwin_14"
+#define SYS_NAME_ID     SYS_NAME_ID_ppc_darwin_14
+#define AFSBIG_ENDIAN   1
+#define AFS_HAVE_FFS    1       /* Use system's ffs. */
+
+#define AFS_GCPAGS                1       /* if nonzero, garbage collect PAGs */
+#define RXK_LISTENER_ENV         1
+
+#ifdef KERNEL
+#undef MACRO_BEGIN
+#undef MACRO_END
+#include <kern/macro_help.h>
+#define AFS_GLOBAL_SUNLOCK        1
+#define AFS_VFS34       1       /* What is VFS34??? */
+#define afsio_iov       uio_iov
+#define afsio_iovcnt    uio_iovcnt
+#define afsio_offset    uio_offset
+#define afsio_seg       uio_segflg
+#define afsio_resid     uio_resid
+#define AFS_UIOSYS      UIO_SYSSPACE
+#define AFS_UIOUSER     UIO_USERSPACE
+#define AFS_CLBYTES     CLBYTES
+#define osi_GetTime(x)  microtime(x)
+#define AFS_KALLOC(x)   kalloc(x)
+#define AFS_KFREE(x,y)  kfree(x,y)
+#define v_count         v_usecount
+#define v_vfsp          v_mount
+#define vfs_bsize       mnt_stat.f_bsize
+#define vfs_fsid        mnt_stat.f_fsid
+#define va_nodeid       va_fileid
+#define vfs_vnodecovered mnt_vnodecovered
+#define direct          dirent
+#define vnode_t         struct vnode
+
+#define VN_RELE(vp)     vrele(((struct vnode *)(vp)))
+#define VN_HOLD(vp)     VREF(((struct vnode *)(vp)))
+
+#endif
+#endif /* AFS_PARAM_H */
diff --git a/src/config/param.ppc_darwin_14_usr.h b/src/config/param.ppc_darwin_14_usr.h
new file mode 100644 (file)
index 0000000..ca107f5
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef AFS_PARAM_H
+#define AFS_PARAM_H
+
+#define AFS_VFSINCL_ENV 1       /* NOBODY uses this.... */
+#define AFS_ENV                 1
+#define AFS_64BIT_ENV           1       /* Defines afs_int32 as int, not long. */
+#define AFS_PPC_ENV 1
+
+#include <afs/afs_sysnames.h>
+#define AFS_USERSPACE_ENV
+#define AFS_USR_DARWIN_ENV
+#define AFS_USR_DARWIN13_ENV
+#define AFS_USR_DARWIN14_ENV
+#define AFS_NONFSTRANS 
+#define AFS_SYSCALL             230
+
+/* File system entry (used if mount.h doesn't define MOUNT_AFS */
+#define AFS_MOUNT_AFS    "afs"
+
+/* Machine / Operating system information */
+#define sys_ppc_darwin_12   1
+#define sys_ppc_darwin_13   1
+#define sys_ppc_darwin_14   1
+#define SYS_NAME        "ppc_darwin_14"
+#define SYS_NAME_ID     SYS_NAME_ID_ppc_darwin_14
+#define AFSBIG_ENDIAN   1
+#define AFS_HAVE_FFS    1       /* Use system's ffs. */
+
+#define AFS_UIOSYS      UIO_SYSSPACE
+#define AFS_UIOUSER     UIO_USERSPACE
+
+#define AFS_GCPAGS                0       /* if nonzero, garbage collect PAGs */
+#define RXK_LISTENER_ENV          1
+
+#define AFS_VFS34       1       /* What is VFS34??? */
+#define afsio_iov       uio_iov
+#define afsio_iovcnt    uio_iovcnt
+#define afsio_offset    uio_offset
+#define afsio_seg       uio_segflg
+#define afsio_resid     uio_resid
+#define AFS_UIOSYS      UIO_SYSSPACE
+#define AFS_UIOUSER     UIO_USERSPACE
+#define        VATTR_NULL      usr_vattr_null
+
+#define AFS_DIRENT
+#ifndef CMSERVERPREF
+#define CMSERVERPREF
+#endif
+
+#endif /* AFS_PARAM_H */
diff --git a/src/config/param.sparc_linux24.h b/src/config/param.sparc_linux24.h
new file mode 100644 (file)
index 0000000..2bff46e
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 1998 by Transarc Corporation */
+
+
+#ifndef AFS_PARAM_H
+#define AFS_PARAM_H
+
+/* In user space the AFS_LINUX20_ENV should be sufficient. In the kernel,
+ * it's a judgment call. If something is obviously sparc specific, use that
+ * #define instead. Note that "20" refers to the linux 2.0 kernel. The "2"
+ * in the sysname is the current version of the client. This takes into
+ * account the perferred OS user space configuration as well as the kernel.
+ */
+
+#define AFS_LINUX20_ENV        1
+#define AFS_LINUX22_ENV        1
+#define AFS_LINUX24_ENV        1
+#define AFS_SPARC_LINUX20_ENV  1
+#define AFS_SPARC_LINUX22_ENV  1
+#define AFS_SPARC_LINUX24_ENV  1
+#define AFS_NONFSTRANS 1
+
+#define AFS_MOUNT_AFS "afs"    /* The name of the filesystem type. */
+#define AFS_SYSCALL 227
+#define AFS_64BIT_IOPS_ENV  1
+#define AFS_NAMEI_ENV     1   /* User space interface to file system */
+
+#if defined(__KERNEL__) && !defined(KDUMP_KERNEL)
+#include <linux/config.h>
+#ifdef CONFIG_SMP
+#undef CONFIG_SMP
+#endif
+/* Using "AFS_SMP" to map to however many #define's are required to get
+ * MP to compile for Linux
+ */
+#ifdef AFS_SMP
+#define CONFIG_SMP
+#ifndef __SMP__
+#define __SMP__
+#endif
+#define AFS_GLOBAL_SUNLOCK
+#endif
+
+#if defined(MODULE) && defined(CONFIG_MODVERSIONS)
+#define MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#endif /* __KERNEL__  && !DUMP_KERNEL*/
+
+#include <afs/afs_sysnames.h>
+
+#define AFS_USERSPACE_IP_ADDR 1
+#define RXK_LISTENER_ENV 1
+#define AFS_GCPAGS             0       /* if nonzero, garbage collect PAGs */
+
+/* Machine / Operating system information */
+#define SYS_NAME       "sparc_linux24"
+#define SYS_NAME_ID    SYS_NAME_ID_sparc_linux24
+#define AFSBIG_ENDIAN    1
+#define AFS_HAVE_FFS        1       /* Use system's ffs. */
+#define AFS_HAVE_STATVFS    0  /* System doesn't support statvfs */
+#define AFS_VM_RDWR_ENV            1   /* read/write implemented via VM */
+
+#ifdef KERNEL
+#ifndef MIN
+#define MIN(A,B) ((A) < (B) ? (A) : (B))
+#endif
+#ifndef MAX
+#define MAX(A,B) ((A) > (B) ? (A) : (B))
+#endif
+#endif /* KERNEL */
+
+#if defined(AFS_SMP) && defined(CONFIG_MODVERSIONS)
+/* hack, I don't know what else with theese symbols */
+#define _do_spin_lock _do_spin_lock_R__ver__do_spin_lock
+#define _do_spin_unlock _do_spin_unlock_R__ver__do_spin_unlock
+#define kernel_flag kernel_flag_R__ver_kernel_flag
+#endif
+
+/* on sparclinux is O_LARGEFILE defined but there is not off64_t,
+   so small hack to get usd_file.c work */
+#ifndef KERNEL
+#define __USE_FILE_OFFSET64 1
+#define __USE_LARGEFILE64 1
+#if !defined off64_t
+#define off64_t __off64_t
+#endif
+#endif
+
+#endif /* AFS_PARAM_H */
diff --git a/src/config/param.sparc_linux24_usr.h b/src/config/param.sparc_linux24_usr.h
new file mode 100644 (file)
index 0000000..49c6d7a
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) 1998 by Transarc Corporation */
+
+
+#ifndef AFS_PARAM_H
+#define AFS_PARAM_H
+
+/* In user space the AFS_LINUX20_ENV should be sufficient. In the kernel,
+ * it's a judgment call. If something is obviously sparc specific, use that
+ * #define instead. Note that "20" refers to the linux 2.0 kernel. The "2"
+ * in the sysname is the current version of the client. This takes into
+ * account the perferred OS user space configuration as well as the kernel.
+ */
+
+#define UKERNEL                        1       /* user space kernel */
+#define AFS_ENV                        1
+#define AFS_USR_LINUX20_ENV    1
+#define AFS_USR_LINUX22_ENV    1
+#define AFS_USR_LINUX24_ENV    1
+#define AFS_NONFSTRANS 1
+
+#define AFS_MOUNT_AFS "afs"    /* The name of the filesystem type. */
+#define AFS_SYSCALL 227
+#define AFS_64BIT_IOPS_ENV  1
+#define AFS_NAMEI_ENV     1   /* User space interface to file system */
+#include <afs/afs_sysnames.h>
+
+#define AFS_USERSPACE_IP_ADDR 1
+#define RXK_LISTENER_ENV 1
+#define AFS_GCPAGS             0       /* if nonzero, garbage collect PAGs */
+
+
+/* Machine / Operating system information */
+#define SYS_NAME       "sparc_linux24"
+#define SYS_NAME_ID    SYS_NAME_ID_sparc_linux24
+#define AFSBIG_ENDIAN    1
+#define AFS_HAVE_FFS        1       /* Use system's ffs. */
+#define AFS_HAVE_STATVFS    0  /* System doesn't support statvfs */
+#define AFS_VM_RDWR_ENV            1   /* read/write implemented via VM */
+
+#define        afsio_iov       uio_iov
+#define        afsio_iovcnt    uio_iovcnt
+#define        afsio_offset    uio_offset
+#define        afsio_seg       uio_segflg
+#define        afsio_fmode     uio_fmode
+#define        afsio_resid     uio_resid
+#define        AFS_UIOSYS      1
+#define        AFS_UIOUSER     UIO_USERSPACE
+#define        AFS_CLBYTES     MCLBYTES
+#define        AFS_MINCHANGE   2
+#define        VATTR_NULL      usr_vattr_null
+
+#define AFS_DIRENT
+#ifndef CMSERVERPREF
+#define CMSERVERPREF
+#endif
+
+#endif /* AFS_PARAM_H */
diff --git a/src/rx/rxperf.c b/src/rx/rxperf.c
new file mode 100644 (file)
index 0000000..ad824ed
--- /dev/null
@@ -0,0 +1,931 @@
+/*
+ * 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
+ *    at such time that OpenAFS documentation is written.
+ * 
+ * 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
+
+/* 
+nn * We are using getopt since we want it to be possible to link to
+ * transarc libs.
+ */
+
+#ifdef RCSID
+RCSID("$Id: rxperf.c,v 1.1 2002/01/22 19:54:22 hartmans Exp $");
+#endif
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <unistd.h>
+#include <signal.h>
+#ifdef HAVE_ERRX
+#include <err.h> /* not stricly right, but if we have a errx() there
+                 * is hopefully a err.h */
+#endif
+#include "rx.h"
+#include "rx_null.h"
+#include "rx_globals.h"
+
+#if defined(u_int32)
+#define u_int32_t u_int32
+#elif defined(hget32)
+#define u_int32_t afs_uint32
+#endif
+
+static const char *__progname;
+
+#ifndef HAVE_WARNX
+static void
+warnx(const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    fprintf(stderr, "%s: ", __progname);
+    vfprintf (stderr, fmt, args);
+    fprintf(stderr, "\n");
+    va_end(args);
+}
+#endif /* !HAVE_WARNX */
+     
+#ifndef HAVE_ERRX
+static void
+errx(int eval, const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    fprintf(stderr, "%s: ", __progname);
+    vfprintf (stderr, fmt, args);
+    fprintf(stderr, "\n");
+    va_end(args);
+
+    exit(eval);
+}
+#endif /* !HAVE_ERRX */
+
+#ifndef HAVE_WARN
+static void
+warn(const char *fmt, ...)
+{
+    va_list args;
+    char *errstr;
+
+    va_start(args, fmt);
+    fprintf(stderr, "%s: ", __progname);
+    vfprintf (stderr, fmt, args);
+
+    errstr = strerror(errno);
+    
+    fprintf(stderr, ": %s\n", errstr ? errstr : "unknown error");
+    va_end(args);
+}
+#endif /* !HAVE_WARN */
+     
+#ifndef HAVE_ERR
+static void
+err(int eval, const char *fmt, ...)
+{
+    va_list args;
+    char *errstr;
+
+    va_start(args, fmt);
+    fprintf(stderr, "%s: ", __progname);
+    vfprintf (stderr, fmt, args);
+
+    errstr = strerror(errno);
+    
+    fprintf(stderr, ": %s\n", errstr ? errstr : "unknown error");
+    va_end(args);
+
+    exit(eval);
+}
+#endif /* !HAVE_ERR */
+
+#define DEFAULT_PORT 7009      /* To match tcpdump */
+#define DEFAULT_HOST "127.0.0.1"
+#define DEFAULT_BYTES 1000000
+#define RXPERF_BUFSIZE 10000
+
+enum { RX_PERF_VERSION = 3 };
+enum { RX_SERVER_ID = 147 };
+enum { RX_PERF_UNKNOWN = -1, RX_PERF_SEND = 0, RX_PERF_RECV = 1, 
+       RX_PERF_RPC=3, RX_PERF_FILE=4 };
+
+enum { RXPERF_MAGIC_COOKIE = 0x4711 };
+
+/*
+ *
+ */
+
+#if DEBUG
+#define DBFPRINT(x) do { printf x ; } while(0)
+#else
+#define DBFPRINT(x)
+#endif
+
+static void
+sigusr1 (int foo)
+{
+    exit (2); /* XXX profiler */
+}
+
+static void
+sigint (int foo)
+{
+    rx_Finalize();
+    exit (2); /* XXX profiler */
+}
+
+/*
+ *
+ */
+
+static struct timeval timer_start;
+static struct timeval timer_stop;
+static int timer_check = 0;
+
+static void
+start_timer (void)
+{
+    timer_check++;
+    gettimeofday (&timer_start, NULL);
+}
+
+/*
+ *
+ */
+
+static void
+end_and_print_timer (char *str)
+{
+    long long start_l, stop_l;
+
+    timer_check--; 
+    assert (timer_check == 0);
+    gettimeofday(&timer_stop, NULL);
+    start_l = timer_start.tv_sec * 1000000 + timer_start.tv_usec;
+    stop_l = timer_stop.tv_sec * 1000000 + timer_stop.tv_usec;
+    printf("%s:\t%8llu msec\n", str, (stop_l-start_l)/1000);
+}
+
+/*
+ *
+ */
+
+static u_long
+str2addr (const char *s)
+{
+    struct in_addr server;
+    struct hostent *h;
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+    if (inet_addr(s) != INADDR_NONE)
+        return inet_addr(s);
+    h = gethostbyname (s);
+    if (h != NULL) {
+       memcpy (&server, h->h_addr_list[0], sizeof(server));
+       return server.s_addr;
+    }
+    return 0;
+}
+
+
+/*
+ *
+ */
+
+static void
+get_sec(int serverp, struct rx_securityClass** sec, int *secureindex)
+{
+    if (serverp) {
+       *sec = rxnull_NewServerSecurityObject();
+       *secureindex = 1;
+    } else {
+       *sec = rxnull_NewClientSecurityObject();
+       *secureindex = 0;
+    }
+}
+
+/*
+ * process the "RPC" and return the results
+ */
+
+char somebuf[RXPERF_BUFSIZE];
+
+int32_t rxwrite_size = sizeof(somebuf);
+int32_t rxread_size = sizeof(somebuf);
+
+static int
+readbytes(struct rx_call *call, int32_t bytes)
+{
+    int32_t size;
+
+    while (bytes > 0) {
+       size = rxread_size;
+       if (size > bytes)
+           size = bytes;
+       if (rx_Read (call, somebuf, size) != size)
+           return 1;
+       bytes -= size;
+    }
+    return 0;
+}
+
+static int
+sendbytes(struct rx_call *call, int32_t bytes)
+{
+    int32_t size;
+
+    while (bytes > 0) {
+       size = rxwrite_size;
+       if (size > bytes)
+           size = bytes;
+       if (rx_Write (call, somebuf, size) != size)
+           return 1;
+       bytes -= size;
+    }
+    return 0;
+}
+
+
+static int32_t
+rxperf_ExecuteRequest(struct rx_call *call)
+{
+    int32_t version;
+    int32_t command;
+    u_int32_t bytes;
+    u_int32_t recvb;
+    u_int32_t sendb;
+    u_int32_t data;
+    u_int32_t num;
+    u_int32_t *readwrite;
+    int i;
+    int readp=TRUE;
+
+    DBFPRINT(("got a request\n"));
+
+    if (rx_Read (call, &version, 4) != 4) {
+       warn ("rx_Read failed to read version");
+       return -1;
+    }
+
+    if (htonl(RX_PERF_VERSION) != version) {
+       warnx ("client has wrong version");
+       return -1;
+    }
+       
+    if (rx_Read (call, &command, 4) != 4) {
+       warnx ("rx_Read failed to read command");
+       return -1;
+    }
+    command = ntohl(command);
+
+    if (rx_Read (call, &data, 4) != 4) {
+       warnx ("rx_Read failed to read size");
+       return -1;
+    }
+    rxread_size = ntohl(data);
+    if (rxread_size > sizeof(somebuf)) {
+       warnx("rxread_size too large %d", rxread_size);
+       return -1;
+    }
+
+    if (rx_Read (call, &data, 4) != 4) {
+       warnx ("rx_Read failed to write size");
+       return -1;
+    }
+    rxwrite_size = ntohl(data);
+    if (rxwrite_size > sizeof(somebuf)) {
+       warnx("rxwrite_size too large %d", rxwrite_size);
+       return -1;
+    }
+
+    switch (command) {
+    case RX_PERF_SEND:
+       DBFPRINT(("got a send request\n"));
+
+       if (rx_Read (call, &bytes, 4) != 4) {
+           warnx ("rx_Read failed to read bytes");
+           return -1;
+       }
+       bytes = ntohl(bytes);
+
+       DBFPRINT(("reading(%d) ", bytes));
+       readbytes(call, bytes);
+
+       data = htonl(RXPERF_MAGIC_COOKIE);
+       if (rx_Write (call, &data, 4) != 4) {
+           warnx ("rx_Write failed when sending back result");
+           return -1;
+       }
+       DBFPRINT(("done\n"));
+
+       break;
+    case RX_PERF_RPC:
+       DBFPRINT(("got a rpc request, reading commands\n"));
+       
+       if (rx_Read (call, &recvb, 4) != 4) {
+           warnx ("rx_Read failed to read recvbytes");
+           return -1;
+       }
+       recvb = ntohl(recvb);
+       if (rx_Read (call, &sendb, 4) != 4) {
+           warnx ("rx_Read failed to read sendbytes");
+           return -1;
+       }
+       sendb = ntohl(sendb);
+
+       DBFPRINT(("read(%d) ", recvb));
+       if (readbytes(call, recvb)) {
+           warnx("readbytes failed");
+           return -1;
+       }
+       DBFPRINT(("send(%d) ", sendb));
+       if (sendbytes(call, sendb)) {
+           warnx("sendbytes failed");
+           return -1;
+       }
+       
+       DBFPRINT(("done\n"));
+
+       data = htonl(RXPERF_MAGIC_COOKIE);
+       if (rx_Write (call, &data, 4) != 4) {
+           warnx ( "rx_Write failed when sending back magic cookie");
+           return -1;
+       }
+
+       break;
+    case RX_PERF_FILE:
+       if (rx_Read (call, &data, 4) != 4)
+           errx (1, "failed to read num from client");
+       num = ntohl(data);
+
+       readwrite = malloc(num*sizeof(u_int32_t));
+       if(readwrite == NULL)
+           err(1, "malloc");
+
+       if (rx_Read (call, readwrite, num*sizeof(u_int32_t)) !=
+           num*sizeof(u_int32_t))
+           errx (1, "failed to read recvlist from client");
+
+           for(i=0; i < num; i++) {
+               if(readwrite[i] == 0) {
+                   DBFPRINT(("readp %d", readwrite[i] ));
+                   readp = !readp;
+               }
+
+               bytes = ntohl(readwrite[i])*sizeof(u_int32_t);
+
+               if(readp) {
+                   DBFPRINT(("read\n"));
+                   readbytes(call, bytes);
+               } else {
+                   sendbytes(call, bytes);
+                   DBFPRINT(("send\n"));
+               }
+           }
+
+       break;
+    case RX_PERF_RECV:
+       DBFPRINT(("got a recv request\n"));
+
+       if (rx_Read (call, &bytes, 4) != 4) {
+           warnx ("rx_Read failed to read bytes");
+           return -1;
+       }
+       bytes = ntohl(bytes);
+
+       DBFPRINT(("sending(%d) ", bytes));
+       sendbytes(call, bytes);
+
+       data = htonl(RXPERF_MAGIC_COOKIE);
+       if (rx_Write (call, &data, 4) != 4) {
+           warnx ("rx_Write failed when sending back result");
+           return -1;
+       }
+       DBFPRINT(("done\n"));
+
+       break;
+    default:
+       warnx ("client sent a unsupported command");
+       return -1;
+    }
+    DBFPRINT(("done with command\n"));
+
+    return 0;
+}
+
+/*
+ *
+ */
+
+static void
+do_server (int port)
+{
+    struct rx_service *service;
+    struct rx_securityClass *secureobj;
+    int secureindex;
+    int ret;
+
+    ret = rx_Init (port);
+    if (ret)
+       errx (1, "rx_Init failed");
+
+    get_sec(1, &secureobj, &secureindex);
+    
+    service = rx_NewService (0,
+                            RX_SERVER_ID,
+                            "rxperf", 
+                            &secureobj, 
+                            secureindex, 
+                            rxperf_ExecuteRequest);
+    if (service == NULL) 
+       errx(1, "Cant create server");
+
+    rx_StartServer(1) ;
+    abort();
+}
+
+/*
+ *
+ */
+
+static void
+readfile(const char *filename, u_int32_t **readwrite, u_int32_t *size)
+{
+    FILE *f;
+    u_int32_t len=16;
+    u_int32_t num=0;
+    u_int32_t data;
+    char *ptr;
+    char buf[RXPERF_BUFSIZE];
+
+    *readwrite = malloc(sizeof(u_int32_t)*len);
+
+    if(*readwrite == NULL)
+       err(1, "malloc");
+
+    f=fopen(filename, "r");
+    if(f==NULL)
+       err(1, "fopen");
+
+    while(fgets(buf, sizeof(buf), f) != NULL) {
+       if(num >= len) {
+           len=len*2;
+           *readwrite = realloc(*readwrite, len*sizeof(u_int32_t));
+           if(*readwrite == NULL)
+               err(1, "realloc");
+       }
+
+       if(*buf != '\n') {
+           data = htonl(strtol (buf, &ptr, 0));
+           if (ptr && ptr == buf)
+               errx (1, "can't resolve number of bytes to transfer");
+       } else {
+           data = 0;
+       }
+       
+       (*readwrite)[num] =data;
+       num++;
+    }
+
+    *size = num;
+
+    
+    if(fclose(f) == -1)
+       err(1, "fclose");
+}
+
+
+/*
+ *
+ */
+
+static void
+do_client (const char *server, int port, char *filename,
+          int32_t command, int32_t times, 
+          int32_t bytes, int32_t sendtimes, int32_t recvtimes)
+{
+    struct rx_connection *conn;
+    struct rx_call *call;
+    u_int32_t addr = str2addr(server);
+    struct rx_securityClass *secureobj;
+    int secureindex;
+    int32_t data;
+    int32_t num;
+    int ret;
+    int i;
+    int readp = FALSE;
+    char stamp[1024];
+    u_int32_t size;
+
+    u_int32_t *readwrite;
+
+    ret = rx_Init (0);
+    if (ret)
+       errx (1, "rx_Init failed");
+
+    get_sec(0, &secureobj, &secureindex);
+
+    conn = rx_NewConnection(addr, 
+                           port, 
+                           RX_SERVER_ID,
+                           secureobj,
+                           secureindex);
+    if (conn == NULL)
+       errx (1, "failed to contact server");
+
+    sprintf (stamp, "send\t%d times\t%d writes\t%d reads", times, sendtimes, recvtimes);
+    start_timer();
+
+    for(i=0; i < times ; i++) {
+
+       DBFPRINT(("starting command "));
+
+       call = rx_NewCall (conn);
+       if (call == NULL)
+           errx (1, "rx_NewCall failed");
+       
+       data = htonl(RX_PERF_VERSION);
+       if (rx_Write (call, &data, 4) != 4)
+           errx (1, "rx_Write failed to send version");
+       
+       data = htonl(command);
+       if (rx_Write (call, &data, 4) != 4)
+           errx (1, "rx_Write failed to send command");
+
+       data = htonl(rxread_size);
+       if (rx_Write (call, &data, 4) != 4)
+           errx (1, "rx_Write failed to send read size");
+       data = htonl(rxwrite_size);
+       if (rx_Write (call, &data, 4) != 4)
+           errx (1, "rx_Write failed to send write read");
+
+
+       switch (command) {
+       case RX_PERF_RECV:
+           DBFPRINT(("command "));
+
+           data = htonl (bytes);
+           if (rx_Write (call, &data, 4) != 4)
+               errx (1, "rx_Write failed to send size");           
+           
+           DBFPRINT(("sending(%d) ", bytes));
+           if (readbytes(call, bytes))
+               errx(1, "sendbytes");
+
+           if (rx_Read (call, &data, 4) != 4)
+               errx (1, "failed to read result from server");
+           
+           if (data != htonl(RXPERF_MAGIC_COOKIE))
+               warn("server send wrong magic cookie in responce");
+
+           DBFPRINT(("done\n"));
+
+           break;
+       case RX_PERF_SEND:
+           DBFPRINT(("command "));
+
+           data = htonl (bytes);
+           if (rx_Write (call, &data, 4) != 4)
+               errx (1, "rx_Write failed to send size");           
+           
+           DBFPRINT(("sending(%d) ", bytes));
+           if (sendbytes(call, bytes))
+               errx(1, "sendbytes");
+
+           if (rx_Read (call, &data, 4) != 4)
+               errx (1, "failed to read result from server");
+           
+           if (data != htonl(RXPERF_MAGIC_COOKIE))
+               warn("server send wrong magic cookie in responce");
+
+           DBFPRINT(("done\n"));
+
+           break;
+       case RX_PERF_RPC:
+           DBFPRINT(("commands "));
+
+           data = htonl(sendtimes);
+           if (rx_Write(call, &data, 4) != 4)
+               errx (1, "rx_Write failed to send command");
+           
+           data = htonl(recvtimes);
+           if (rx_Write (call, &data, 4) != 4)
+               errx (1, "rx_Write failed to send command");
+           
+           DBFPRINT(("send(%d) ", sendtimes));
+           sendbytes(call, sendtimes);
+           
+           DBFPRINT(("recv(%d) ", recvtimes));
+           readbytes(call, recvtimes);
+           
+           if (rx_Read (call, &bytes, 4) != 4)
+               errx (1, "failed to read result from server");
+           
+           if (bytes != htonl(RXPERF_MAGIC_COOKIE))
+               warn("server send wrong magic cookie in responce");
+
+           DBFPRINT(("done\n"));
+
+           break;
+       case RX_PERF_FILE:
+           readfile(filename, &readwrite, &num);
+
+           data = htonl(num);
+           if (rx_Write(call, &data, sizeof(data)) != 4)
+               errx (1, "rx_Write failed to send size");
+
+           if (rx_Write(call, readwrite, num*sizeof(u_int32_t)) 
+               != num*sizeof(u_int32_t))
+               errx (1, "rx_Write failed to send list");
+
+           for(i=0; i < num; i++) {
+               if(readwrite[i] == 0)
+                   readp = !readp;
+
+               size = ntohl(readwrite[i])*sizeof(u_int32_t);
+
+               if(readp) {
+                   readbytes(call, size);
+                   DBFPRINT(("read\n"));
+               } else {
+                   sendbytes(call, size);
+                   DBFPRINT(("send\n"));
+               }
+           }
+           break;
+       default:
+           abort();
+       }
+
+       rx_EndCall (call, 0);
+    }
+
+    end_and_print_timer (stamp);
+    DBFPRINT(("done for good\n"));
+
+    rx_Finalize();
+}
+
+static void
+usage()
+{
+#define COMMON ""
+
+    fprintf(stderr, "usage: %s client -c send -b <bytes>\n",
+           __progname);
+    fprintf(stderr, "usage: %s client -c recv -b <bytes>\n",
+           __progname);
+    fprintf(stderr, "usage: %s client -c rpc  -S <sendbytes> -R <recvbytes>\n",
+           __progname);
+    fprintf(stderr, "usage: %s client -c file -f filename\n", 
+           __progname);
+    fprintf (stderr, "%s: usage:       common option to the client "
+            "-w <write-bytes> -r <read-bytes> -T times -p port -s server\n",
+            __progname);
+    fprintf(stderr, "usage: %s server -p port\n", __progname);
+#undef COMMMON
+    exit(1);
+}
+
+/*
+ * do argument processing and call networking functions
+ */
+
+static int
+rxperf_server (int argc, char **argv)
+{
+    int port      = DEFAULT_PORT;
+    char *ptr;
+    int ch;
+
+    while ((ch = getopt(argc, argv, "r:d:p:w:")) != -1) {
+       switch (ch) {
+       case 'd':
+#ifdef RXDEBUG
+           rx_debugFile = fopen(optarg, "w");
+           if (rx_debugFile == NULL)
+               err(1, "fopen %s", optarg);
+#else
+           errx(1, "compiled without RXDEBUG");
+#endif
+           break;
+       case 'r':
+           rxread_size = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx (1, "can't resolve readsize");
+           if (rxread_size > sizeof(somebuf))
+             errx(1, "%d > sizeof(somebuf) (%d)",
+                  rxread_size, sizeof(somebuf));
+           break;
+       case 'p':
+           port = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx (1, "can't resolve portname");
+           break;
+       case 'w':
+           rxwrite_size = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx (1, "can't resolve writesize");
+           if (rxwrite_size > sizeof(somebuf))
+               errx(1, "%d > sizeof(somebuf) (%d)",
+                    rxwrite_size, sizeof(somebuf));
+           break;
+       default:
+           usage();
+       }
+    }
+
+    if (optind != argc)
+       usage();
+    
+    do_server (htons(port));
+
+    return 0;
+}
+
+/*
+ * do argument processing and call networking functions
+ */
+
+static int
+rxperf_client (int argc, char **argv)
+{
+    char *host    = DEFAULT_HOST;
+    int bytes     = DEFAULT_BYTES;
+    int port      = DEFAULT_PORT;
+    char *filename = NULL;
+    int32_t cmd;
+    int sendtimes = 3;
+    int recvtimes = 30;
+    int times = 100;
+    char *ptr;
+    int ch;
+
+    cmd = RX_PERF_UNKNOWN;
+    
+    while ((ch  = getopt(argc, argv, "T:S:R:b:c:d:p:r:s:w:f:")) != -1) {
+       switch (ch) {
+       case 'b':
+           bytes = strtol (optarg, &ptr, 0);
+           if (ptr && *ptr != '\0')
+               errx (1, "can't resolve number of bytes to transfer");
+           break;
+       case 'c':
+           if (strcasecmp(optarg, "send") == 0)
+             cmd = RX_PERF_SEND;
+           else if (strcasecmp(optarg, "recv") == 0)
+               cmd = RX_PERF_RECV;
+           else if (strcasecmp(optarg, "rpc") == 0)
+               cmd = RX_PERF_RPC;
+           else if (strcasecmp(optarg, "file") == 0)
+               cmd = RX_PERF_FILE;
+           else
+               errx(1, "unknown command %s", optarg);
+           break;
+       case 'd':
+#ifdef RXDEBUG
+           rx_debugFile = fopen(optarg, "w");
+           if (rx_debugFile == NULL)
+               err(1, "fopen %s", optarg);
+#else
+           errx(1, "compiled without RXDEBUG");
+#endif
+           break;
+       case 'p':
+           port = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx (1, "can't resolve portname");
+           break;
+       case 'r':
+           rxread_size = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx (1, "can't resolve readsize");
+           if (rxread_size > sizeof(somebuf))
+               errx(1, "%d > sizeof(somebuf) (%d)",
+                    rxread_size, sizeof(somebuf));
+           break;
+       case 's':
+           host = strdup(optarg);
+           if (host == NULL)
+               err(1, "strdup");
+           break;
+       case 'w':
+           rxwrite_size = strtol(optarg, &ptr, 0);
+           if (ptr != 0 && ptr[0] != '\0')
+               errx (1, "can't resolve writesize");
+           if (rxwrite_size > sizeof(somebuf))
+               errx(1, "%d > sizeof(somebuf) (%d)",
+                    rxwrite_size, sizeof(somebuf));
+           break;
+       case 'T':
+           times = strtol (optarg, &ptr, 0);
+           if (ptr && *ptr != '\0')
+               errx (1, "can't resolve number of bytes to transfer");
+           break;
+       case 'S':
+           sendtimes = strtol (optarg, &ptr, 0);
+           if (ptr && *ptr != '\0')
+               errx (1, "can't resolve number of bytes to transfer");
+           break;
+       case 'R':
+           recvtimes = strtol (optarg, &ptr, 0);
+           if (ptr && *ptr != '\0')
+               errx (1, "can't resolve number of bytes to transfer");
+           break;
+       case 'f':
+           filename = optarg;
+           break;
+       default:
+           usage();
+       }
+    }
+
+    if (optind != argc)
+       usage();
+    
+    if (cmd == RX_PERF_UNKNOWN)
+       errx(1, "no command given to the client");
+    
+    do_client(host, htons(port), filename, cmd, times, bytes, 
+             sendtimes, recvtimes);
+    
+    return 0;
+}
+
+/*
+ * setup world and call cmd
+ */
+
+int
+main(int argc, char **argv)
+{
+    PROCESS pid;
+
+    __progname = strrchr(argv[0], '/');
+    if (__progname == 0)
+      __progname = argv[0];
+
+    signal (SIGUSR1, sigusr1);
+    signal (SIGINT, sigint);
+
+    LWP_InitializeProcessSupport (LWP_NORMAL_PRIORITY, &pid);
+    
+    memset (somebuf, 0, sizeof(somebuf));
+
+    if (argc >= 2 && strcmp(argv[1], "server") == 0)
+       rxperf_server(argc - 1, argv + 1);
+    else if (argc >= 2 && strcmp(argv[1], "client") == 0)
+       rxperf_client(argc - 1, argv + 1);
+    else
+       usage();
+    return 0;
+}
+
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
new file mode 100644 (file)
index 0000000..b3d9f07
--- /dev/null
@@ -0,0 +1,380 @@
+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}
+
+INCDIRS=-I${TOP_OBJDIR}/src/config -I${TOP_INCDIR}/afs -I${TOP_INCDIR}
+INCLIBS=-L${SRCDIR}/lib/afs -L${TOP_LIBDIR}
+
+LIBS=\
+       libdumpscan.a \
+       libxfiles.a \
+       ${TOP_LIBDIR}/libauth.a \
+       ${TOP_LIBDIR}/libaudit.a \
+       ${TOP_LIBDIR}/libvolser.a \
+       ${TOP_LIBDIR}/libvldb.a \
+       ${TOP_LIBDIR}/libubik.a \
+       ${TOP_LIBDIR}/librxkad.a \
+       ${TOP_LIBDIR}/libsys.a \
+       ${TOP_LIBDIR}/librx.a \
+       ${TOP_LIBDIR}/liblwp.a \
+       ${TOP_LIBDIR}/util.a \
+       ${TOP_LIBDIR}/libcom_err.a \
+       ${XLIBS}
+
+OBJS_afsdump_scan    = afsdump_scan.o repair.o
+OBJS_afsdump_xsed    = afsdump_xsed.o repair.o
+OBJS_libxfiles.a     = xfiles.o xf_errs.o xf_printf.o int64.o \
+                       xf_files.o xf_rxcall.o xf_profile.o
+OBJS_libdumpscan.a   = primitive.o util.o dumpscan_errs.o parsetag.o \
+                       parsedump.o parsevol.o parsevnode.o dump.o \
+                       directory.o pathname.o backuphdr.o stagehdr.o
+
+TARGETS = libxfiles.a libdumpscan.a \
+          afsdump_scan afsdump_dirlist afsdump_extract dumptool
+
+afsdump_scan: libxfiles.a libdumpscan.a $(OBJS_afsdump_scan)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_scan $(OBJS_afsdump_scan) $(LIBS)
+
+afsdump_xsed: libxfiles.a libdumpscan.a $(OBJS_afsdump_xsed)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_xsed $(OBJS_afsdump_xsed) $(LIBS)
+
+afsdump_dirlist: libxfiles.a libdumpscan.a afsdump_dirlist.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_dirlist afsdump_dirlist.o $(LIBS)
+
+afsdump_extract: libxfiles.a libdumpscan.a afsdump_extract.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_extract afsdump_extract.o $(LIBS)
+
+null-search: libxfiles.a libdumpscan.a null-search.c
+       $(CC) $(CFLAGS) $(LDFLAGS) -o null-search null-search.c $(LIBS)
+
+dumptool: dumptool.c
+       $(CC) $(CFLAGS) $(LDFLAGS) -o dumptool dumptool.c
+
+libxfiles.a: $(OBJS_libxfiles.a)
+       -rm -f libxfiles.a
+       $(AR) r libxfiles.a $(OBJS_libxfiles.a)
+       $(RANLIB) libxfiles.a
+
+libdumpscan.a: $(OBJS_libdumpscan.a)
+       -rm -f libdumpscan.a
+       $(AR) r libdumpscan.a $(OBJS_libdumpscan.a)
+       $(RANLIB) libdumpscan.a
+
+xf_errs.c xf_errs.h: xf_errs.et
+       $(COMPILE_ET) xf_errs.et
+
+dumpscan_errs.c dumpscan_errs.h: dumpscan_errs.et
+       $(COMPILE_ET) dumpscan_errs.et
+
+util.o xfiles.o xf_files.o: xf_errs.h
+backuphdr.o directory.o parsedump.o parsetag.o: dumpscan_errs.h
+parsevnode.o parsevol.o pathname.o repair.o:    dumpscan_errs.h
+stagehdr.o util.o:                              dumpscan_errs.h
+
+${DEST}/etc/afsdump_scan: afsdump_scan
+       ${INSTALL} $? $@
+
+${DEST}/etc/afsdump_dirlist: afsdump_dirlist
+       ${INSTALL} $? $@
+
+${DEST}/etc/afsdump_extract: afsdump_extract
+       ${INSTALL} $? $@
+
+${DEST}/etc/dumptool: dumptool
+       ${INSTALL} $? $@
+
+${DESTDIR}${sbindir}/afsdump_scan: afsdump_scan
+       ${INSTALL} $? $@
+
+${DESTDIR}${sbindir}/afsdump_dirlist: afsdump_dirlist
+       ${INSTALL} $? $@
+
+${DESTDIR}${sbindir}/afsdump_extract: afsdump_extract
+       ${INSTALL} $? $@
+
+${DESTDIR}${sbindir}/dumptool: dumptool
+       ${INSTALL} $? $@
+
+${TOP_LIBDIR}/libxfiles.a: libxfiles.a
+       ${INSTALL} $? $@
+
+${TOP_LIBDIR}/libdumpscan.a: libdumpscan.a
+       ${INSTALL} $? $@
+
+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
+
+OpenAFS/OS.pm: OpenAFS/OS-$(MKAFS_OSTYPE).pm
+       $(CP) OpenAFS/OS-$(MKAFS_OSTYPE).pm OpenAFS/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=src/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
+
+dest:
+
+install:
+
+uninstall:
+
+all: run-tests OpenAFS/OS.pm libxfiles.a libdumpscan.a $(TEST_PROGRAMS)\
+       afsdump_scan afsdump_dirlist afsdump_extract dumptool
+
+clean:
+       -rm -f xf_errs.c xf_errs.h dumpscan_errs.c dumpscan_errs.h *.o \
+       $(TARGETS) run-tests $(TEST_PROGRAMS) OS.pm
+
+include ../config/Makefile.version
+
+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/OpenAFS/Auth-Heimdal.pm b/src/tests/OpenAFS/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/OpenAFS/CMU_copyright.pm b/src/tests/OpenAFS/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/OpenAFS/ConfigUtils.pm b/src/tests/OpenAFS/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/OpenAFS/Dirpath.pm.in b/src/tests/OpenAFS/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/OpenAFS/OS-LINUX.pm b/src/tests/OpenAFS/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/OpenAFS/OS-SOLARIS.pm b/src/tests/OpenAFS/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/OpenAFS/afsconf.pm b/src/tests/OpenAFS/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/OpenAFS/bos.pm b/src/tests/OpenAFS/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/OpenAFS/config.pm b/src/tests/OpenAFS/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/OpenAFS/errtrans.pm b/src/tests/OpenAFS/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/OpenAFS/fs.pm b/src/tests/OpenAFS/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/OpenAFS/kas.pm b/src/tests/OpenAFS/kas.pm
new file mode 100644 (file)
index 0000000..376f62a
--- /dev/null
@@ -0,0 +1,325 @@
+# CMUCS AFStools
+# Copyright (c) 1996, Carnegie Mellon University
+# All rights reserved.
+#
+# See CMU_copyright.ph for use and distribution information
+#
+#: * kas.pm - Wrappers around KAS commands (authentication maintenance)
+#: * This module provides wrappers around the various kaserver commands
+#: * giving them a nice perl-based interface.  At present, this module
+#: * requires a special 'krbkas' which uses existing Kerberos tickets
+#: * which the caller must have already required (using 'kaslog').
+#:
+
+package OpenAFS::kas;
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT :afs_internal);
+use OpenAFS::wrapper;
+use POSIX ();
+use Exporter;
+
+$VERSION   = '';
+$VERSION   = '1.00';
+@ISA       = qw(Exporter);
+@EXPORT    = qw(&AFS_kas_create        &AFS_kas_setf
+                &AFS_kas_delete        &AFS_kas_setkey
+                &AFS_kas_examine       &AFS_kas_setpw
+                &AFS_kas_randomkey     &AFS_kas_stringtokey
+                &AFS_kas_list);
+
+# Instructions to parse kas error messages
+@kas_err_parse = ( [ ' : \[.*\] (.*), wait one second$', '.' ],
+                   [ ' : \[.*\] (.*) \(retrying\)$',     '.' ],
+                   [ ' : \[.*\] (.*)',                   '-' ]);
+
+# Instructions to parse attributes of an entry
+@kas_entry_parse = (
+    [ '^User data for (.*) \((.*)\)$',      'princ', 'flags', '.'        ],
+    [ '^User data for (.*)',                'princ'                      ],
+    [ 'key \((\d+)\) cksum is (\d+),',      'kvno', 'cksum'              ],
+    [ 'last cpw: (.*)',                     \&parsestamp, 'stamp_cpw'    ],
+    [ 'password will (never) expire',       'stamp_pwexp'                ],
+    [ 'password will expire: ([^\.]*)',     \&parsestamp, 'stamp_pwexp'  ],
+    [ 'An (unlimited) number of',           'max_badauth'                ],
+    [ '(\d+) consecutive unsuccessful',     'max_badauth'                ],
+    [ 'for this user is ([\d\.]+) minutes', 'locktime'                   ],
+    [ 'for this user is (not limited)',     'locktime'                   ],
+    [ 'User is locked (forever)',           'locked'                     ],
+    [ 'User is locked until (.*)',          \&parsestamp, 'locked'       ],
+    [ 'entry (never) expires',              'stamp_expire'               ],
+    [ 'entry expires on ([^\.]*)\.',        \&parsestamp, 'stamp_expire' ],
+    [ 'Max ticket lifetime (.*) hours',     'maxlife'                    ],
+    [ 'Last mod on (.*) by',                \&parsestamp, 'stamp_update' ],
+    [ 'Last mod on .* by (.*)',             'last_writer'                ]);
+
+
+@Months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+           'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
+%Months = map(($Months[$_] => $_), 0..11);
+
+# Parse a timestamp
+sub parsestamp {
+  my($stamp) = @_;
+  my($MM, $DD, $YYYY, $hh, $mm, $ss);
+
+  if ($stamp =~ /^\S+ (\S+) (\d+) (\d+):(\d+):(\d+) (\d+)/) {
+    ($MM, $DD, $hh, $mm, $ss, $YYYY) = ($1, $2, $3, $4, $5, $6);
+    $YYYY -= 1900;
+    $MM = $Months{$MM};
+    if (defined($MM)) {
+      $stamp = POSIX::mktime($ss, $mm, $hh, $DD, $MM, $YYYY);
+    }
+  }
+  $stamp;
+}
+
+
+# Turn an 8-byte key into a string we can give to kas
+sub stringize_key {
+  my($key) = @_;
+  my(@chars) = unpack('CCCCCCCC', $key);
+
+  sprintf("\\%03o" x 8, @chars);
+}
+
+
+# Turn a string into an 8-byte DES key
+sub unstringize_key {
+  my($string) = @_;
+  my($char, $key);
+
+  while ($string ne '') {
+    if ($string =~ /^\\(\d\d\d)/) {
+      $char = $1;
+      $string = $';
+      $key .= chr(oct($char));
+    } else {
+      $key .= substr($string, 0, 1);
+      $string =~ s/^.//;
+    }
+  }
+  $key;
+}
+
+
+#: AFS_kas_create($princ, $initpass, [$cell])
+#: Create a principal with name $princ, and initial password $initpass
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{kas_create} = '$princ, $initpass, [$cell] => Success?';
+sub AFS_kas_create {
+  my($print, $initpass, $cell) = @_;
+  my(@args, $id);
+
+  @args = ('create', '-name', $princ, '-initial_password', $initpass);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('krbkas', \@args, [ @kas_err_parse ]);
+  1;
+}
+
+
+#: AFS_kas_delete($princ, [$cell])
+#: Delete the principal $princ.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{kas_delete} = '$princ, [$cell] => Success?';
+sub AFS_kas_delete {
+  my($princ, $cell) = @_;
+  my(@args);
+
+  @args = ('delete', '-name', $princ);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('krbkas', \@args, [ @kas_err_parse ]);
+  1;
+}
+
+
+#: AFS_kas_examine($princ, [$cell])
+#: Examine the prinicpal $princ, and return information about it.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return an associative array with some or all of the following:
+#: - princ        Name of this principal
+#: - kvno         Key version number
+#: - cksum        Key checksum
+#: - maxlife      Maximum ticket lifetime (in hours)
+#: - stamp_expire Time this principal expires, or 'never'
+#: - stamp_pwexp  Time this principal's password expires, or 'never'
+#: - stamp_cpw    Time this principal's password was last changed
+#: - stamp_update Time this princiapl was last modified
+#: - last_writer  Administrator who last modified this principal
+#: - max_badauth  Maximum number of bad auth attempts, or 'unlimited'
+#: - locktime     Penalty time for bad auth (in minutes), or 'not limited'
+#: - locked       Set and non-empty if account is locked
+#: - expired      Set and non-empty if account is expired
+#: - flags        Reference to a list of flags
+#:
+$AFS_Help{kas_examine} = '$princ, [$cell] => %info';
+sub AFS_kas_examine {
+  my($vol, $cell) = @_;
+  my(%result, @args, $flags);
+
+  @args = ('examine', '-name', $princ);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  %result = &wrapper('krbkas', \@args, [ @kas_err_parse, @kas_entry_parse ]);
+
+  if ($result{flags}) {
+    $result{expired} = 1 if ($result{flags} =~ /expired/);
+    $result{flags} = [ split(/\+/, $result{flags}) ];
+  }
+  %result;
+}
+
+
+#: AFS_kas_list([$cell])
+#: Get a list of principals in the kaserver database
+#: If specified, work in $cell instead of the default cell.
+#: On success, return an associative array whose keys are names of kaserver
+#: principals, and each of whose values is an associative array describing
+#: the corresponding principal, containing some or all of the same elements
+#: that may be returned by AFS_kas_examine
+#:
+$AFS_Help{kas_list} = '[$cell] => %princs';
+sub AFS_kas_list {
+  my($cell) = @_;
+  my(@args, %finres, %plist);
+
+  @args = ('list', '-long');
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  %finres = &wrapper('krbkas', \@args,
+    [ @kas_err_parse,
+    [ '^User data for (.*)', sub {
+      my(%pinfo) = %OpenAFS::wrapper::result;
+
+      if ($pinfo{name}) {
+        $plist{$pinfo{name}} = \%pinfo;
+        %OpenAFS::wrapper::result = ();
+      }
+    }],
+      @kas_entry_parse ]);
+
+  if ($finres{name}) {
+    $plist{$finres{name}} = \%finres;
+  }
+  %plist;
+}
+
+
+#: AFS_kas_setf($princ, \%attrs, [$cell])
+#: Change the attributes of the principal $princ.
+#: If specified, operate in cell $cell instead of the default cell.
+#: The associative array %attrs specifies the attributes to change and
+#: their new values.  Any of the following attributes may be changed:
+#: - flags        Entry flags
+#: - expire       Expiration time (mm/dd/yy)
+#: - lifetime     Maximum ticket lifetime (seconds)
+#: - pwexpires    Maximum password lifetime (days)
+#: - reuse        Permit password reuse (yes/no)
+#: - attempts     Maximum failed authentication attempts
+#: - locktime     Authentication failure penalty (minutes or hh:mm)
+#: 
+#: On success, return 1.
+#:
+$AFS_Help{kas_setf} = '$princ, \%attrs, [$cell] => Success?';
+sub AFS_kas_setf {
+  my($princ, $attrs, $cell) = @_;
+  my(%result, @args);
+
+  @args = ('setfields', '-name', $princ);
+  push(@args, '-flags',      $$attrs{flags})     if ($$attrs{flags});
+  push(@args, '-expiration', $$attrs{expire})    if ($$attrs{expire});
+  push(@args, '-lifetime',   $$attrs{lifetime})  if ($$attrs{lifetime});
+  push(@args, '-pwexpires',  $$attrs{pwexpires}) if ($$attrs{pwexpires});
+  push(@args, '-reuse',      $$attrs{reuse})     if ($$attrs{reuse});
+  push(@args, '-attempts',   $$attrs{attempts})  if ($$attrs{attempts});
+  push(@args, '-locktime',   $$attrs{locktime})  if ($$attrs{locktime});
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('krbkas', \@args, [ @kas_err_parse ]);
+  1;
+}
+
+
+#: AFS_kas_setkey($princ, $key, [$kvno], [$cell])
+#: Change the key of principal $princ to the specified value.
+#: $key is the 8-byte DES key to use for this principal.
+#: If specified, set the key version number to $kvno.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{kas_setkey} = '$princ, $key, [$kvno], [$cell] => Success?';
+sub AFS_kas_setkey {
+  my($princ, $key, $kvno, $cell) = @_;
+  my(@args);
+
+  @args = ('setkey', '-name', $princ, '-new_key', &stringize_key($key));
+  push(@args, '-kvno', $kvno) if (defined($kvno));
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('krbkas', \@args, [ @kas_err_parse ]);
+  1;
+}
+
+
+#: AFS_kas_setpw($princ, $password, [$kvno], [$cell])
+#: Change the key of principal $princ to the specified value.
+#: $password is the new password to use.
+#: If specified, set the key version number to $kvno.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{kas_setpw} = '$princ, $password, [$kvno], [$cell] => Success?';
+sub AFS_kas_setpw {
+  my($princ, $password, $kvno, $cell) = @_;
+  my(@args);
+
+  @args = ('setpasswd', '-name', $princ, '-new_password', $password);
+  push(@args, '-kvno', $kvno) if (defined($kvno));
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('krbkas', \@args, [ @kas_err_parse ]);
+  1;
+}
+
+
+#: AFS_kas_stringtokey($string, [$cell])
+#: Convert the specified string to a DES key
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return the resulting key
+$AFS_Help{kas_stringtokey} = '$string, [$cell] => $key';
+sub AFS_kas_stringtokey {
+  my($string, $cell) = @_;
+  my(@args, $key);
+
+  @args = ('stringtokey', '-string', $string);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('krbkas', \@args,
+    [ @kas_err_parse,
+      [ q/^Converting .* in realm .* yields key='(.*)'.$/, \$key ]]);
+  &unstringize_key($key);
+}
+
+
+#: AFS_kas_randomkey([$cell])
+#: Ask the kaserver to generate a random DES key
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return the resulting key
+$AFS_Help{kas_randomkey} = '[$cell] => $key';
+sub AFS_kas_randomkey {
+  my($cell) = @_;
+  my(@args, $key);
+
+  @args = ('getrandomkey');
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('krbkas', \@args,
+    [ @kas_err_parse,
+      [ '^Key: (\S+)', \$key ]]);
+  &unstringize_key($key);
+}
+
+1;
diff --git a/src/tests/OpenAFS/pts.pm b/src/tests/OpenAFS/pts.pm
new file mode 100644 (file)
index 0000000..715b5e1
--- /dev/null
@@ -0,0 +1,306 @@
+# CMUCS AFStools
+# Copyright (c) 1996, Carnegie Mellon University
+# All rights reserved.
+#
+# See CMU_copyright.ph for use and distribution information
+#
+#: * pts.pm - Wrappers around PTS commands (user/group maintenance)
+#: * This module provides wrappers around the various PTS commands, giving
+#: * them a nice perl-based interface.  Someday, they might talk to the
+#: * ptserver directly instead of using 'pts', but not anytime soon.
+#:
+
+package OpenAFS::pts;
+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_pts_createuser    &AFS_pts_listmax
+               &AFS_pts_creategroup   &AFS_pts_setmax
+               &AFS_pts_delete        &AFS_pts_add
+               &AFS_pts_rename        &AFS_pts_remove
+               &AFS_pts_examine       &AFS_pts_members
+               &AFS_pts_chown         &AFS_pts_listown
+               &AFS_pts_setf);
+
+
+#: AFS_pts_createuser($user, [$id], [$cell])
+#: Create a PTS user with $user as its name.
+#: If specified, use $id as the PTS id; otherwise, AFS picks one.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return the PTS id of the newly-created user.
+#:
+$AFS_Help{pts_createuser} = '$user, [$id], [$cell] => $uid';
+sub AFS_pts_createuser {
+  my($user, $id, $cell) = @_;
+  my(@args, $uid);
+
+  @args = ('createuser', '-name', $user);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  push(@args, '-id', $id) if ($id);
+  &wrapper('pts', \@args, [[ '^User .* has id (\d+)', \$uid ]]);
+  $uid;
+}
+
+
+#: AFS_pts_creategroup($group, [$id], [$owner], [$cell])
+#: Create a PTS group with $group as its name.
+#: If specified, use $id as the PTS id; otherwise, AFS picks one.
+#: If specified, use $owner as the owner, instead of the current user.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return the PTS id of the newly-created group.
+#:
+$AFS_Help{pts_creategroup} = '$group, [$id], [$owner], [$cell] => $gid';
+sub AFS_pts_creategroup {
+  my($group, $id, $owner, $cell) = @_;
+  my(@args, $uid);
+
+  @args = ('creategroup', '-name', $group);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  push(@args, '-id', $id) if ($id);
+  push(@args, '-owner', $owner) if ($owner);
+  &wrapper('pts', \@args, [[ '^group .* has id (\-\d+)', \$uid ]]);
+  $uid;
+}
+
+
+#: AFS_pts_delete(\@objs, [$cell])
+#: Attempt to destroy PTS objects listed in @objs.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return 1.
+#: If multiple objects are specified and only some are destroyed, some
+#: operations may be left untried.
+#:
+$AFS_Help{pts_delete} = '\@objs, [$cell] => Success?';
+sub AFS_pts_delete {
+  my($objs, $cell) = @_;
+  my(@args);
+
+  @args = ('delete', '-nameorid', @$objs);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args);
+  1;
+}
+
+
+#: AFS_pts_rename($old, $new, [$cell])
+#: Rename the PTS object $old to have the name $new.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{pts_rename} = '$old, $new, [$cell] => Success?';
+sub AFS_pts_rename {
+  my($old, $new, $cell) = @_;
+  my(@args);
+
+  @args = ('rename', '-oldname', $old, '-newname', $new);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args);
+  1;
+}
+
+
+#: AFS_pts_examine($obj, [$cell])
+#: Examine the PTS object $obj, and return information about it.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return an associative array with some or all of the following:
+#: - name         Name of this object
+#: - id           ID of this object
+#: - owner        Name or ID of owner
+#: - creator      Name or ID of creator
+#: - mem_count    Number of members (group) or memberships (user)
+#: - flags        Privacy/access flags (as a string)
+#: - group_quota  Remaining group quota
+#:
+$AFS_Help{pts_examine} = '$obj, [$cell] => %info';
+sub AFS_pts_examine {
+  my($obj, $cell) = @_;
+  my(@args);
+
+  @args = ('examine', '-nameorid', $obj);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args,
+          [[ '^Name\: (.*)\, id\: ([\-0-9]+)\, owner\: (.*)\, creator\: (.*)\,$', #',
+             'name', 'id', 'owner', 'creator' ],
+           [ '^  membership\: (\d+)\, flags\: (.....)\, group quota\: (\d+)\.$',  #',
+             'mem_count', 'flags', 'group_quota' ]
+           ]);
+}
+
+
+#: AFS_pts_chown($obj, $owner, [$cell])
+#: Change the owner of the PTS object $obj to be $owner.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{pts_chown} = '$obj, $owner, [$cell] => Success?';
+sub AFS_pts_chown {
+  my($obj, $owner, $cell) = @_;
+  my(@args);
+
+  @args = ('chown', '-name', $obj, '-owner', $owner);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args);
+  1;
+}
+
+
+#: AFS_pts_setf($obj, [$access], [$gquota], [$cell])
+#: Change the access flags and/or group quota for the PTS object $obj.
+#: If specified, $access specifies the new access flags in the standard 'SOMAR'
+#: format; individual flags may be specified as '.' to keep the current value.
+#: If specified, $gquota specifies the new group quota.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{pts_setf} = '$obj, [$access], [$gquota], [$cell] => Success?';
+sub AFS_pts_setf {
+  my($obj, $access, $gquota, $cell) = @_;
+  my(%result, @args);
+
+  @args = ('setfields', '-nameorid', $obj);
+  push(@args, '-groupquota', $gquota) if ($gquota ne '');
+  if ($access) {
+    my(@old, @new, $i);
+    # Ensure access is 5 characters
+    if (length($access) < 5) {
+      $access .= ('.' x (5 - length($access)));
+    } elsif (length($access) > 5) {
+      substr($access, 5) = '';
+    }
+
+    %result = &AFS_pts_examine($obj, $cell);
+
+    @old = split(//, $result{'flags'});
+    @new = split(//, $access);
+    foreach $i (0 .. 4) {
+      $new[$i] = $old[$i] if ($new[$i] eq '.');
+    }
+    $access = join('', @new);
+    if ($access ne $result{'flags'}) {
+      push(@args, '-access', $access);
+    }
+  }
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args);
+  1;
+}
+
+
+#: AFS_pts_listmax([$cell])
+#: Fetch the maximum assigned group and user ID.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, returns (maxuid, maxgid)
+#:
+$AFS_Help{pts_listmax} = '[$cell] => ($maxuid, $maxgid)';
+sub AFS_pts_listmax {
+  my($cell) = @_;
+  my(@args, $uid, $gid);
+
+  @args = ('listmax');
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args,
+          [[ '^Max user id is (\d+) and max group id is (\-\d+).',
+             \$uid, \$gid ]]);
+  ($uid, $gid);
+}
+
+
+#: AFS_pts_setmax([$maxuser], [$maxgroup], [$cell])
+#: Set the maximum assigned group and/or user ID.
+#: If specified, $maxuser is the new maximum user ID
+#: If specified, $maxgroup is the new maximum group ID
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{pts_setmax} = '[$maxuser], [$maxgroup], [$cell] => Success?';
+sub AFS_pts_setmax {
+  my($maxuser, $maxgroup, $cell) = @_;
+  my(@args);
+
+  @args = ('setmax');
+  push(@args, '-group', $maxgroup) if ($maxgroup);
+  push(@args, '-user',  $maxuser)  if ($maxuser);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args);
+  1;
+}
+
+#: AFS_pts_add(\@users, \@groups, [$cell])
+#: Add users specified in @users to groups specified in @groups.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return 1.
+#: If multiple users and/or groups are specified and only some memberships
+#: are added, some operations may be left untried.
+#:
+$AFS_Help{pts_add} = '\@users, \@groups, [$cell] => Success?';
+sub AFS_pts_add {
+  my($users, $groups, $cell) = @_;
+  my(@args);
+
+  @args = ('adduser', '-user', @$users, '-group', @$groups);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args);
+  1;
+}
+
+
+#: AFS_pts_remove(\@users, \@groups, [$cell])
+#: Remove users specified in @users from groups specified in @groups.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return 1.
+#: If multiple users and/or groups are specified and only some memberships
+#: are removed, some operations may be left untried.
+#:
+$AFS_Help{pts_remove} = '\@users, \@groups, [$cell] => Success?';
+sub AFS_pts_remove {
+  my($users, $groups, $cell) = @_;
+  my(@args);
+
+  @args = ('removeuser', '-user', @$users, '-group', @$groups);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args);
+  1;
+}
+
+
+#: AFS_pts_members($obj, [$cell])
+#: If $obj specifies a group, retrieve a list of its members.
+#: If $obj specifies a user, retrieve a list of groups to which it belongs.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return the resulting list.
+#:
+$AFS_Help{pts_members} = '$obj, [$cell] => @members';
+sub AFS_pts_members {
+  my($obj, $cell) = @_;
+  my(@args, @grouplist);
+
+  @args = ('membership', '-nameorid', $obj);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args, [[ '^  (.*)', \@grouplist ]]);
+  @grouplist;
+}  
+
+
+#: AFS_pts_listown($owner, [$cell])
+#: Retrieve a list of PTS groups owned by the PTS object $obj.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return the resulting list.
+#:
+$AFS_Help{pts_listown} = '$owner, [$cell] => @owned';
+sub AFS_pts_listown {
+  my($owner, $cell) = @_;
+  my(@args, @grouplist);
+
+  @args = ('listowned', '-nameorid', $owner);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('pts', \@args, [[ '^  (.*)', \@grouplist ]]);
+  @grouplist;
+}  
+
+
+1;
diff --git a/src/tests/OpenAFS/util.pm b/src/tests/OpenAFS/util.pm
new file mode 100644 (file)
index 0000000..ec1c52a
--- /dev/null
@@ -0,0 +1,356 @@
+# CMUCS AFStools
+# Copyright (c) 1996, Carnegie Mellon University
+# All rights reserved.
+#
+# See CMUCS/CMU_copyright.ph for use and distribution information
+
+package OpenAFS::util;
+
+=head1 NAME
+
+OpenAFS::util - General AFS utilities
+
+=head1 SYNOPSIS
+
+  use OpenAFS::util;
+
+  AFS_Init();
+  AFS_Trace($subject, $level);
+  AFS_SetParm($parm, $value);
+
+  use OpenAFS::util qw(GetOpts_AFS);
+  %options = GetOpts_AFS(\@argv, \@optlist);
+
+=head1 DESCRIPTION
+
+This module defines a variety of AFS-related utility functions.  Virtually
+every application that uses AFStools will need to use some of the utilities
+defined in this module.  In addition, a variety of global variables are
+defined here for use by all the AFStools modules.  Most of these are
+private, but a few are semi-public.
+
+=cut
+
+use OpenAFS::CMU_copyright;
+use OpenAFS::config;
+require OpenAFS::afsconf;   ## Avoid circular 'use' dependencies
+use Exporter;
+
+$VERSION   = '';
+$VERSION   = '1.00';
+@ISA       = qw(Exporter);
+@EXPORT    = qw(&AFS_Init
+               &AFS_Trace
+               &AFS_SetParm);
+@EXPORT_OK = qw(%AFS_Parms
+                %AFS_Trace
+               %AFS_Help
+                %AFScmd
+               &GetOpts_AFS
+               &GetOpts_AFS_Help);
+%EXPORT_TAGS = (afs_internal => [qw(%AFS_Parms %AFS_Trace %AFScmd %AFS_Help)],
+                afs_getopts  => [qw(&GetOpts_AFS &GetOpts_AFS_Help)] );
+
+
+=head2 AFS_Init()
+
+This function does basic initialization of AFStools.  It must be called before
+any other AFStools function.
+
+=cut
+
+sub AFS_Init
+{
+  my(@dirs, $c, $i, $x);
+
+  $AFS_Parms{'authlvl'}  = 1;
+  $AFS_Parms{'confdir'}  = $def_ConfDir;
+  $AFS_Parms{'cell'}     = OpenAFS::afsconf::AFS_conf_localcell();
+
+  # Search for AFS commands
+  @dirs = @CmdPath;
+  foreach $c (@CmdList)
+    {
+      $AFScmd{$c} = '';
+      foreach $i ($[ .. $#dirs)
+       {
+          $x = $dirs[$i];
+         if (-x "$x/$c" && ! -d "$x/$c")
+           {
+             $AFScmd{$c} = "$x/$c";
+              splice(@dirs, $i, 1);   # Move this item to the start of the array
+             unshift(@dirs, $x);
+             last;
+           }
+       }
+      return "Unable to locate $c!" if (!$AFScmd{$c});
+    }
+  0;
+}
+
+
+=head2 AFS_Trace($subject, $level)
+
+Sets the tracing level for a particular "subject" to the specified level.
+All tracing levels start at 0, and can be set to higher values to get debugging
+information from different parts of AFStools.  This function is generally
+only of use to people debugging or extending AFStools.
+
+=cut
+
+$AFS_Help{Trace} = '$subject, $level => void';
+sub AFS_Trace {
+  my($subject, $level) = @_;
+
+  $AFS_Trace{$subject} = $level;
+}
+
+
+=head2 AFS_SetParm($parm, $value)
+
+Sets the AFStools parameter I<$parm> to I<$value>.  AFStools parameters are
+used to alter the behaviour of various parts of the system.  The following
+parameters are currently defined:
+
+=over 10
+
+=item authlvl
+
+The authentication level to use for commands that talk directly to AFS
+servers (bos, vos, pts, etc.).  Set to 0 for unauthenticated access (-noauth),
+1 to use the user's existing tokens, or 2 to use the AFS service key
+(-localauth).
+
+=item cell
+
+The default AFS cell in which to work.  This is initially the workstation's
+local cell.
+
+=item confdir
+
+The AFS configuration directory to use.  If none is specified, the default
+(as defined in OpenAFS::config) will be used.
+
+=item vostrace
+
+Set the tracing level used by various B<vos> utilities.  The default is 0,
+which disables any tracing of activity of B<vos> commands.  A setting of 1
+copies output from all commands except those which are invoked solely to
+get information; a setting of 2 additionally uses the "-verbose" command
+on any command whose output is copied.  If a setting of 3 is used, all
+B<vos> commands will be invoked with "-verbose", and have their output
+copied to stdout.
+
+=back
+
+=cut
+
+$AFS_Help{SetParm} = '$parm, $value => void';
+sub AFS_SetParm {
+  my($parm, $value) = @_;
+
+  $AFS_Parms{$parm} = $value;
+}
+
+
+#: GetOpts_AFS(\@argv, \@optlist)
+#: Parse AFS-style options.
+#: \@argv is a hard reference to the list of arguments to be parsed.
+#: \@optlist is a hard reference to the list of option specifications for valid
+#: options; in their default order.  Each option specification, in turn, is a
+#: hard reference to an associative array containing some of the following
+#: elements:
+#:     name       => The name of the argument
+#:     numargs    => Number of arguments (0, 1, or -1 for multiple)
+#:     required   => If nonzero, this argument is required
+#:     default    => Value to give this option if not specified
+#:     noauto     => Don't use this option for unadorned arguments
+#:
+#: Results are returned in the form of an associative array of options and
+#: their values:
+#: - Boolean (0-argument) options have a value of 1 if specified.  This type
+#:   of option may not be marked 'required'.
+#: - Simple (1-argument) options have a value which is the string given by the
+#:   user.
+#: - Multiple-argument options have a value which is a hard reference to an
+#:   array of values given by the user.
+#:
+#: Argument parsing is done in a similar manner to the argument parser used by
+#: various AFS utilities.  Options have multi-character names, and may not be
+#: combined with their arguments or other options.  Those options which take
+#: arguments use up at least the next argument, regardless of whether it begins
+#: with a dash.  Options which can take multiple arguments will eat at least
+#: one argument, as well as any following argument up to the next option (i.e.,
+#: the next argument beginning with a dash).  An "unadorned" argument will be
+#: used by the next argument-taking option.  If there are multiple unadorned
+#: arguments, they will be used up by successive arguments much in the same
+#: way Perl handles list assignment - each one-argument (scalar) option will
+#: use one argument; the first multi-argument (list) option will use up any
+#: remaining unadorned arguments.
+#:
+#: On completion, @argv will be left with any unparsed arguments (this can
+#: happen if the last option specified is _not_ a multi-argument option, and
+#: there are no "defaulted" options).  This is considered to be an error
+#: condition.
+#:
+sub GetOpts_AFS_Help {
+  my($cmd, $optlist) = @_;
+  my($option, $optname, $desc);
+
+  foreach $option (@$optlist) {
+    $optname = '-' . $$option{name};
+    if ($$option{numargs}) {
+      $desc = $$option{desc} ? $$option{desc} : $$option{name};
+      $desc = " <$desc>";
+      $desc .= '+' if ($$option{numargs} < 0);
+      $optname .= $desc;
+    }
+    $optname = "[$optname]" if (!$$option{required});
+    $cmd .= " $optname";
+  }
+  $cmd;
+}
+
+sub _which_opt {
+  my($optname, @options) = @_;
+  my($o, $which, $n);
+
+  foreach $o (@options) {
+    next unless ($o =~ /^$optname/);
+    $n++;
+    $which = $o;
+  }
+  ($n == 1) ? $which : $optname;
+}
+
+sub GetOpts_AFS {
+  my($argv, $optlist) = @_;
+  my(@autolist, %opttbl, %result);
+  my($stop, $key, $value, $diemsg);
+
+  # Initialization:
+  @autolist = map {
+    if ($_->{numargs} && !$_->{noauto} && !$stop) {
+      $stop = 1 if ($_->{numargs} < 0);
+      ($_->{name});
+    } else {
+      ();
+    }
+  } (@$optlist, { name=>'-help', numargs=>0, required=>0 } );
+  %opttbl = map { $_->{name} => $_ } @$optlist;
+
+  while (@$argv) {
+    my($optname, $optkind);
+
+    # Parse the next argument.  It can either be an option, or an
+    # unadorned argument.  If the former, shift it off and process it.
+    # Otherwise, grab the next "automatic" option.  If there are no
+    # more automatic options, we have extra arguments and should return.
+    if ($argv->[0] =~ /^-(.+)/) {  # Got an option!
+      $optname = $1;
+      shift(@$argv);
+    } else {                       # An unadorned argument
+      if (@autolist) {
+       $optname = shift(@autolist);
+      } else {
+       $diemsg = join(' ', "Extra arguments:", @$argv) unless ($diemsg);
+        shift @$argv;
+        next;
+      }
+    }
+    $optname = &_which_opt($optname, keys %opttbl);
+
+    # Find out how many arguments this thing wants, then remove it from
+    # the option table and automatic option list.
+    $optkind = $opttbl{$optname}->{numargs};
+    delete $opttbl{$optname};
+    @autolist = grep($_ ne $optname, @autolist);
+
+    # Parse arguments (if any), and set the result value
+    if (!$optkind) {               # Boolean!
+      $result{$optname} = 1;
+    } elsif ($optkind == 1) {      # Single argument
+      # Shift off a single argument, or signal an error
+      if (!@$argv) {
+        $diemsg = "No argument for -$optname" unless ($diemsg);
+        next;
+      }
+      $result{$optname} = shift(@$argv);
+    } elsif ($optkind < 0) {       # Multiple arguments
+      # Shift off at least one argument, and any additional
+      # ones that are present.  EXCEPT, if there are no more
+      # explicitly-specified options but there ARE automatic
+      # options left in our list, then only eat up one.
+      my($val, @val);
+      if (!@$argv) {
+       $diemsg = "No argument for -$optname" unless ($diemsg);
+        next;
+      }
+      $val = shift(@$argv);
+      push(@val, shift @$argv) while (@$argv && $argv->[0] !~ /^-/);
+      if (@autolist && !@$argv) {
+       unshift(@$argv, @val);
+       @val = ($val);
+      } else {
+       unshift(@val, $val);
+      }
+      $result{$optname} = [@val];
+    } else {
+      die "Invalid argument spec for -$optname ($optkind)\n";
+    }
+  }
+
+  # Now for a little clean-up
+  # Set default values for any unspecified option that has them.
+  # Set an error condition if there are any required options that
+  # were not specified.
+  while (($key, $value) = each %opttbl) {
+    if ($value->{required}) {
+      $diemsg = "Required option -$key not specified" unless($diemsg);
+    }
+    $result{$key} = $value->{default};
+  }
+  if ($diemsg && !$result{help}) { die $diemsg . "\n" }
+  %result;
+}
+
+
+1;
+
+=head1 VARIABLES
+
+The following global variables are defined by B<OpenAFS::util>.  None of these
+are exported by default.  Those marked "Private" should not be used outside
+AFStools; their names, meaning, and even existence may change at any time.
+
+=over 12
+
+=item %AFS_Help - Help info
+
+This array contains argument lists for all publicly-exported AFStools
+functions with names of the form AFS_*.  It is intended for programs like
+B<testbed>, which provide a direct interactive interface to AFStools.
+
+=item %AFS_Parms - Parameter settings  [Private]
+
+This array contains the settings of AFStools parameters set with
+B<OpenAFS::util::AFS_SetParm>.
+
+=item %AFS_Trace - Tracing levels  [Private]
+
+This array contains the tracing levels set with B<OpenAFS::util::AFS_Trace>.
+
+=item %AFScmd - AFS command locations  [Private]
+
+This array contains paths to the various AFS command binaries, for use
+by B<OpenAFS::wrapper::wrapper> and possibly other AFStools functions.
+
+=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/OpenAFS/vos.pm b/src/tests/OpenAFS/vos.pm
new file mode 100644 (file)
index 0000000..3f1ae6a
--- /dev/null
@@ -0,0 +1,803 @@
+# CMUCS AFStools
+# Copyright (c) 1996, Carnegie Mellon University
+# All rights reserved.
+#
+# See CMU_copyright.ph for use and distribution information
+#
+#: * vos.pm - Wrappers around VOS commands (volume maintenance)
+#: * This module provides wrappers around the various volserver and VLDB
+#: * commands, giving them a nice perl-based interface.  Someday, they might
+#: * talk to the servers directly instead of using 'vos', but not anytime
+#: * soon.
+#:
+
+package OpenAFS::vos;
+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_vos_create        &AFS_vos_listvldb
+                &AFS_vos_remove        &AFS_vos_delentry
+                &AFS_vos_rename        &AFS_vos_syncserv
+                &AFS_vos_move          &AFS_vos_syncvldb
+                &AFS_vos_examine       &AFS_vos_lock
+                &AFS_vos_addsite       &AFS_vos_unlock
+                &AFS_vos_remsite       &AFS_vos_unlockvldb
+                &AFS_vos_release       &AFS_vos_changeaddr
+                &AFS_vos_backup        &AFS_vos_listpart
+                &AFS_vos_backupsys     &AFS_vos_partinfo
+                &AFS_vos_dump          &AFS_vos_listvol
+                &AFS_vos_restore       &AFS_vos_zap
+                &AFS_vos_status);
+
+$vos_err_parse = [ 'Error in vos (.*) command', '-(.*)' ];
+
+
+#: AFS_vos_create($vol, $server, $part, [$quota], [$cell])
+#: Create a volume with name $vol
+#: The server name ($server) may be a hostname or IP address
+#: The partition may be a partition name (/vicepx), letter (x), or number (24)
+#: If specified, use $quota for the initial quota instead of 5000 blocks.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return the volume ID.
+#:
+$AFS_Help{vos_create} = '$vol, $server, $part, [$quota], [$cell] => $volid';
+sub AFS_vos_create {
+  my($vol, $server, $part, $quota, $cell) = @_;
+  my(@args, $id);
+
+  @args = ('create', '-name', $vol, '-server', $server, '-part', $part);
+  push(@args, '-maxquota', $quota) if ($quota ne '');
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args, 
+          [$vos_err_parse,
+           ['^Volume (\d+) created on partition \/vicep\S+ of \S+', \$id ],
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  $id;
+}
+
+
+#: AFS_vos_remove($vol, $server, $part, [$cell])
+#: Remove the volume $vol from the server and partition specified by $server and
+#: $part.  If appropriate, also remove the corresponding VLDB entry.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_remove} = '$vol, $server, $part, [$cell] => Success?';
+sub AFS_vos_remove {
+  my($vol, $server, $part, $cell) = @_;
+  my(@args);
+
+  @args = ('remove', '-id', $vol, '-server', $server, '-part', $part);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_rename($old, $new, [$cell])
+#: Rename the volume $old to have the name $new.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_rename} = '$old, $new, [$cell] => Success?';
+sub AFS_vos_rename {
+  my($old, $new, $cell) = @_;
+  my(@args);
+
+  @args = ('rename', '-oldname', $old, '-newname', $new);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_move($vol, $fromsrv, $frompart, $tosrv, $topart, [$cell])
+#: Move the volume specified by $vol.
+#: The source location is specified by $fromsrv and $frompart.
+#: The destination location is specified by $tosrv and $topart.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+
+#:
+$AFS_Help{vos_move} = '$vol, $fromsrv, $frompart, $tosrv, $topart, [$cell] => Success?';
+sub AFS_vos_move {
+  my($vol, $fromsrv, $frompart, $tosrv, $topart, $cell) = @_;
+  my(@args);
+
+  @args = ('move', '-id', $vol,
+          '-fromserver', $fromsrv, '-frompartition', $frompart,
+          '-toserver', $tosrv, '-topartition', $topart);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_examine($vol, [$cell])
+#: Examine the volume $vol, and return information about it.
+#: If specified, operate in cell $cell instead of the default cell.
+#: On success, return an associative array with some or all of the following:
+#: - name         Name of this volume
+#: - id           ID of this volume
+#: - kind         Kind of volume (RW, RO, or BK)
+#: - inuse        Disk space in use
+#: - maxquota     Maximum disk usage quota
+#: - minquota     Minimum disk usage quota (optional)
+#: - stamp_create Time when volume was originally created
+#: - stamp_update Time volume was last modified
+#: - stamp_backup Time backup volume was cloned, or 'Never'
+#: - stamp_copy   Time this copy of volume was made
+#: - backup_flag  State of automatic backups: empty or 'disabled'
+#: - dayuse       Number of accesses in the past day
+#: - rwid         ID of read-write volume (even if this is RO or BK)
+#: - roid         ID of read-only volume (even if this is RW or BK)
+#: - bkid         ID of backup volume (even if this is RW or RO)
+#: - rwserv       Name of server where read/write volume is
+#: - rwpart       Name of partition where read/write volume is
+#: - rosites      Reference to a list of read-only sites.  Each site, in turn,
+#:                is a reference to a two-element list (server, part).
+#:
+$AFS_Help{vos_examine} = '$vol, [$cell] => %info';
+sub AFS_vos_examine {
+  my($vol, $cell) = @_;
+  my(%result, @args, @rosites);
+
+  @args = ('examine', '-id', $vol);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  %result = &wrapper('vos', \@args,
+                    [$vos_err_parse,
+                     ['^(\S+)\s*(\d+)\s*(RW|RO|BK)\s*(\d+)\s*K',          'name', 'id', 'kind', 'inuse'],
+                     ['MaxQuota\s*(\d+)\s*K',                             'maxquota'     ],
+                     ['MinQuota\s*(\d+)\s*K',                             'minquota'     ],
+                     ['Creation\s*(.*\S+)',                               'stamp_create' ],
+                     ['Last Update\s*(.*\S+)',                            'stamp_update' ],
+                     ['Backup\s+([^\d\s].*\S+)',                          'stamp_backup' ],
+                     ['Copy\s*(.*\S+)',                                   'stamp_copy'   ],
+                     ['Automatic backups are (disabled) for this volume', 'backup_flag'  ],
+                     ['(\d+) accesses in the past day',                   'dayuse'       ],
+                     ['RWrite\:\s*(\d+)',                                 'rwid'         ],
+                     ['ROnly\:\s*(\d+)',                                  'roid'         ],
+                     ['Backup\:\s*(\d+)',                                 'bkid'         ],
+                     ['server (\S+) partition /vicep(\S+) RW Site',       'rwserv', 'rwpart'],
+                     ['server (\S+) partition /vicep(\S+) RO Site',       sub {
+                       push(@rosites, [$_[0], $_[1]]);
+                     }],
+                     ($AFS_Parms{'vostrace'} > 2) ? ([ '', '?']) : () ]);
+
+  $result{'rosites'} = \@rosites if (@rosites);
+  %result;
+}
+
+
+
+#: AFS_vos_addsite($vol, $server, $part, [$cell])
+#: Add a replication site for volume $vol
+#: The server name ($server) may be a hostname or IP address
+#: The partition may be a partition name (/vicepx), letter (x), or number (24)
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_addsite} = '$vol, $server, $part, [$cell] => Success?';
+sub AFS_vos_addsite {
+  my($vol, $server, $part, $cell) = @_;
+  my(@args);
+
+  @args = ('addsite', '-id', $vol, '-server', $server, '-part', $part);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_remsite($vol, $server, $part, [$cell])
+#: Remove a replication site for volume $vol
+#: The server name ($server) may be a hostname or IP address
+#: The partition may be a partition name (/vicepx), letter (x), or number (24)
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_remsite} = '$vol, $server, $part, [$cell] => Success?';
+sub AFS_vos_remsite {
+  my($vol, $server, $part, $cell) = @_;
+  my(@args);
+
+  @args = ('remsite', '-id', $vol, '-server', $server, '-part', $part);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_release($vol, [$cell], [$force])
+#: Release the volume $vol.
+#: If $force is specified and non-zero, use the "-f" switch.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_release} = '$vol, [$cell], [$force] => Success?';
+sub AFS_vos_release {
+  my($vol, $cell, $force) = @_;
+  my(@args);
+
+  @args = ('release', '-id', $vol);
+  push(@args, '-f')                if ($force);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_backup($vol, [$cell])
+#: Make a backup of the volume $vol.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_backup} = '$vol, [$cell] => Success?';
+sub AFS_vos_backup {
+  my($vol, $cell) = @_;
+  my(@args);
+
+  @args = ('backup', '-id', $vol);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_backupsys([$prefix], [$server, [$part]], [$exclude], [$cell])
+#: Do en masse backups of AFS volumes.
+#: If specified, match only volumes whose names begin with $prefix
+#: If specified, limit work to the $server and, if given, $part.
+#: If $exclude is specified and non-zero, backup only volumes NOT matched.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_backupsys} = '[$prefix], [$server, [$part]], [$exclude], [$cell] => Success?';
+sub AFS_vos_backupsys {
+  my($prefix, $server, $part, $exclude, $cell) = @_;
+  my(@args);
+
+  @args = ('backupsys');
+  push(@args, '-prefix', $prefix)  if ($prefix);
+  push(@args, '-server', $server)  if ($server);
+  push(@args, '-partition', $part) if ($server && $part);
+  push(@args, '-exclude')          if ($exclude);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_dump($vol, [$time], [$file], [$cell])
+#: Dump the volume $vol
+#: If specified, do an incremental dump since $time instead of a full dump.
+#: If specified, dump to $file instead of STDOUT
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_dump} = '$vol, [$time], [$file], [$cell] => Success?';
+sub AFS_vos_dump {
+  my($vol, $time, $file, $cell) = @_;
+  my(@args);
+
+  @args = ('dump', '-id', $vol);
+  push(@args, '-time', ($time ? $time : 0));
+  push(@args, '-file', $file)      if ($file);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ],
+          { pass_stdout => !$file });
+  1;
+}
+
+
+#: AFS_vos_restore($vol, $server, $part, [$file], [$id], [$owmode], [$cell])
+#: Restore the volume $vol to partition $part on server $server.
+#: If specified, restore from $file instead of STDIN
+#: If specified, use the volume ID $id
+#: If specified, $owmode must be 'abort', 'full', or 'incremental', and
+#: indicates what to do if the volume exists.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_restore} = '$vol, $server, $part, [$file], [$id], [$owmode], [$cell] => Success?';
+sub AFS_vos_restore {
+  my($vol, $server, $part, $file, $id, $owmode, $cell) = @_;
+  my(@args);
+
+  @args = ('restore', '-name', $vol, '-server', $server, '-partition', $part);
+  push(@args, '-file', $file)      if ($file);
+  push(@args, '-id', $id)          if ($id);
+  push(@args, '-overwrite', $owmode) if ($owmode);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_listvldb([$vol], [$server, [$part]], [$locked], [$cell])
+#: Get a list of volumes in the VLDB.
+#: If specified, list only the volume $vol
+#: If specified, list only volumes on the server $server.
+#: If specified with $server, list only volumes on the partition $part.
+#: If $locked is specified and nonzero, list only locked VLDB entries
+#: If specified, work in $cell instead of the default cell.
+#: On success, return an associative array whose keys are names of volumes
+#: on the specified server, and each of whose values is an associative
+#: array describing the corresponding volume, containing some or all of
+#: these elements:
+#: - name         Name of this volume (same as key)
+#: - rwid         ID of read-write volume (even if this is RO or BK)
+#: - roid         ID of read-only volume (even if this is RW or BK)
+#: - bkid         ID of backup volume (even if this is RW or RO)
+#: - locked       Empty or LOCKED to indicate VLDB entry is locked
+#: - rwserv       Name of server where read/write volume is
+#: - rwpart       Name of partition where read/write volume is
+#: - rosites      Reference to a list of read-only sites.  Each site, in turn,
+#:                is a reference to a two-element list (server, part).
+#:
+$AFS_Help{vos_listvldb} = '[$vol], [$server, [$part]], [$locked], [$cell] => %vols';
+sub AFS_vos_listvldb {
+  my($vol, $server, $part, $locked, $cell) = @_;
+  my(%finres, %vlist, @rosites);
+
+  @args = ('listvldb');
+  push(@args, '-name', $vol)       if ($vol);
+  push(@args, '-server', $server)  if ($server);
+  push(@args, '-partition', $part) if ($part && $server);
+  push(@args, '-locked')           if ($locked);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  %finres = &wrapper('vos', \@args,
+                    [$vos_err_parse,
+                     ['^(VLDB|Total) entries', '.'],
+                     ['^(\S+)', sub {
+                       my(%vinfo) = %OpenAFS::wrapper::result;
+
+                       if ($vinfo{name}) {
+                         $vinfo{rosites} = [@rosites] if (@rosites);
+                         $vlist{$vinfo{name}} = \%vinfo;
+
+                         @rosites = ();
+                         %OpenAFS::wrapper::result = ();
+                       }
+                     }],
+                     ['^(\S+)',                                           'name'         ],
+                     ['RWrite\:\s*(\d+)',                                 'rwid'         ],
+                     ['ROnly\:\s*(\d+)',                                  'roid'         ],
+                     ['Backup\:\s*(\d+)',                                 'bkid'         ],
+                     ['Volume is currently (LOCKED)',                     'locked'       ],
+                     ['server (\S+) partition /vicep(\S+) RW Site',       'rwserv', 'rwpart'],
+                     ['server (\S+) partition /vicep(\S+) RO Site',       sub {
+                       push(@rosites, [$_[0], $_[1]]);
+                     }],
+                     ($AFS_Parms{'vostrace'} > 2) ? ([ '', '?']) : () ]);
+
+  if ($finres{name}) {
+    $finres{rosites} = [@rosites] if (@rosites);
+    $vlist{$finres{name}} = \%finres;
+  }
+  %vlist;
+}
+
+
+
+#: AFS_vos_delentry($vol, [$cell])
+#: Delete the VLDB entry for the volume $vol
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_delentry} = '$vol, [$cell] => Success?';
+sub AFS_vos_delentry {
+  my($vol, $cell) = @_;
+  my(@args);
+
+  @args = ('delentry', '-id', $vol);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_syncserv($server, [$part], [$cell], [$force])
+#: Synchronize the server $server with the VLDB
+#: If specified, synchronize only partition $part
+#: If specified, work in $cell instead of the default cell
+#: If $force is specified, force updates to occur
+#: On success, return 1.
+#:
+$AFS_Help{vos_syncserv} = '$server, [$part], [$cell], [$force] => Success?';
+sub AFS_vos_syncserv {
+  my($server, $part, $cell, $force) = @_;
+  my(@args);
+
+  @args = ('syncserv', '-server', $server);
+  push(@args, '-partition', $part) if ($part);
+  push(@args, '-force')            if ($force);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_syncvldb($server, [$part], [$cell], [$force])
+#: Synchronize the VLDB with server $server
+#: If specified, synchronize only partition $part
+#: If specified, work in $cell instead of the default cell
+#: If $force is specified, force updates to occur
+#: On success, return 1.
+#:
+$AFS_Help{vos_syncvldb} = '$server, [$part], [$cell], [$force] => Success?';
+sub AFS_vos_syncvldb {
+  my($server, $part, $cell, $force) = @_;
+  my(@args);
+
+  @args = ('syncvldb', '-server', $server);
+  push(@args, '-partition', $part) if ($part);
+  push(@args, '-force')            if ($force);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_lock($vol, [$cell])
+#: Lock the VLDB entry for volume $vol.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_lock} = '$vol, [$cell] => Success?';
+sub AFS_vos_lock {
+  my($vol, $cell) = @_;
+  my(@args);
+
+  @args = ('lock', '-id', $vol);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_unlock($vol, [$cell])
+#: Unlock the VLDB entry for volume $vol.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_unlock} = '$vol, [$cell] => Success?';
+sub AFS_vos_unlock {
+  my($vol, $cell) = @_;
+  my(@args);
+
+  @args = ('unlock', '-id', $vol);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_unlockvldb([$server, [$part]], [$cell])
+#: Unlock some or all VLDB entries
+#: If specified, unlock only entries for volumes on server $server
+#: If specified with $server, unlock only entries for volumes on
+#: partition $part, instead of entries for volumes on all partitions
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_unlockvldb} = '[$server, [$part]], [$cell] => Success?';
+sub AFS_vos_unlockvldb {
+  my($server, $part, $cell) = @_;
+  my(@args);
+
+  @args = ('unlockvldb');
+  push(@args, '-server', $server)  if ($server);
+  push(@args, '-partition', $part) if ($server && $part);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_changeaddr($old, $new, [$cell])
+#: Change the IP address of server $old to $new.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return 1.
+#:
+$AFS_Help{vos_changeaddr} = '$old, $new, [$cell] => Success?';
+sub AFS_vos_changeaddr {
+  my($old, $new, $cell) = @_;
+  my(@args);
+
+  @args = ('changeaddr', '-oldaddr', $old, '-newaddr', $new);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_listpart($server, [$cell])
+#: Retrieve a list of partitions on server $server
+#: If specified, work in $cell instead of the default cell.
+#: On success, return a list of partition letters
+#:
+$AFS_Help{vos_listpart} = '$server, [$cell] => @parts';
+sub AFS_vos_listpart {
+  my($server, $cell) = @_;
+  my(@args, @parts);
+
+  @args = ('listpart', '-server', $server);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           [ '^(.*\/vicep.*)$', #',
+            sub {
+              push(@parts, map {
+                my($x) = $_;
+                $x =~ s/^\/vicep//;
+                $x;
+              } split(' ', $_[0]));
+            }],
+           ($AFS_Parms{'vostrace'} > 2) ? ([ '', '?']) : () ]);
+  @parts;
+}
+
+
+#: AFS_vos_partinfo($server, [$part], [$cell])
+#: Get information about partitions on server $server.
+#: If specified, only get info about partition $part.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return an associative array whose keys are partition letters,
+#: and each of whose values is a reference to a 2-element list, consisting
+#: of the total size of the partition and the amount of space used.
+#:
+$AFS_Help{vos_partinfo} = '$server, [$part], [$cell] => %info';
+sub AFS_vos_partinfo {
+  my($server, $part, $cell) = @_;
+  my(@args, %parts);
+
+  @args = ('partinfo', '-server', $server);
+  push(@args, '-partition', $part) if ($part);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           [ '^Free space on partition /vicep(.+)\: (\d+) K blocks out of total (\d+)',
+            sub {
+              $parts{$_[0]} = [ $_[1], $_[2] ];
+            }],
+           ($AFS_Parms{'vostrace'} > 2) ? ([ '', '?']) : () ]);
+  %parts;
+}
+
+
+#: AFS_vos_listvol($server, [$part], [$cell])
+#: Get a list of volumes on the server $server.
+#: If specified, list only volumes on the partition $part.
+#: If specified, work in $cell instead of the default cell.
+#: On success, return an associative array whose keys are names of volumes
+#: on the specified server, and each of whose values is an associative
+#: array describing the corresponding volume, containing some or all of
+#: these elements:
+#: - name         Name of this volume (same as key)
+#: - id           ID of this volume
+#: - kind         Kind of volume (RW, RO, or BK)
+#: - inuse        Disk space in use
+#: - maxquota     Maximum disk usage quota
+#: - minquota     Minimum disk usage quota (optional)
+#: - stamp_create Time when volume was originally created
+#: - stamp_update Time volume was last modified
+#: - stamp_backup Time backup volume was cloned, or 'Never'
+#: - stamp_copy   Time this copy of volume was made
+#: - backup_flag  State of automatic backups: empty or 'disabled'
+#: - dayuse       Number of accesses in the past day
+#: - serv         Server where this volume is located
+#: - part         Partition where this volume is located
+#:
+$AFS_Help{vos_listvol} = '$server, [$part], [$cell] => %vols';
+sub AFS_vos_listvol {
+  my($server, $part, $cell) = @_;
+  my(%finres, %vlist);
+
+  @args = ('listvol', '-server', $server, '-long');
+  push(@args, '-partition', $part) if ($part);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  %finres = &wrapper('vos', \@args,
+                    [$vos_err_parse,
+                     ['^\S+\s*\d+\s*(RW|RO|BK)', sub {
+                       my(%vinfo) = %OpenAFS::wrapper::result;
+
+                       if ($vinfo{name}) {
+                         $vlist{$vinfo{name}} = \%vinfo;
+                         %OpenAFS::wrapper::result = ();
+                       }
+                     }],
+                     ['^(\S+)\s*(\d+)\s*(RW|RO|BK)\s*(\d+)\s*K',          'name', 'id', 'kind', 'inuse'],
+                     ['(\S+)\s*\/vicep(\S+)\:',                           'serv', 'part' ],
+                     ['MaxQuota\s*(\d+)\s*K',                             'maxquota'     ],
+                     ['MinQuota\s*(\d+)\s*K',                             'minquota'     ],
+                     ['Creation\s*(.*\S+)',                               'stamp_create' ],
+                     ['Last Update\s*(.*\S+)',                            'stamp_update' ],
+                     ['Backup\s+([^\d\s].*\S+)',                          'stamp_backup' ],
+                     ['Copy\s*(.*\S+)',                                   'stamp_copy'   ],
+                     ['Automatic backups are (disabled) for this volume', 'backup_flag'  ],
+                     ['(\d+) accesses in the past day',                   'dayuse'       ],
+                     ($AFS_Parms{'vostrace'} > 2) ? ([ '', '?']) : () ]);
+
+  if ($finres{name}) {
+    $vlist{$finres{name}} = \%finres;
+  }
+  %vlist;
+}
+
+#: AFS_vos_zap($vol, $server, $part, [$cell], [$force])
+#: Remove the volume $vol from the server and partition specified by $server and
+#: $part.  Don't bother messing with the VLDB.
+#: If specified, work in $cell instead of the default cell.
+#: If $force is specified, force the zap to happen
+#: On success, return 1.
+#:
+$AFS_Help{vos_zap} = '$vol, $server, $part, [$cell], [$force] => Success?';
+sub AFS_vos_zap {
+  my($vol, $server, $part, $cell, $force) = @_;
+  my(@args);
+
+  @args = ('zap', '-id', $vol, '-server', $server, '-part', $part);
+  push(@args, '-force')            if ($force);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 1);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           $AFS_Parms{'vostrace'} ? ([ '', '?']) : () ]);
+  1;
+}
+
+
+#: AFS_vos_status($server, [$cell])
+#: Get information about outstanding transactions on $server
+#: If specified, work in $cell instead of the default cell
+#: On success, return a list of transactions, each of which is a reference
+#: to an associative array containing some or all of these elements:
+#: - transid      Transaction ID
+#: - stamp_create Time the transaction was created
+#: - volid        Volume ID
+#: - part         Partition letter
+#: - action       Action or procedure
+#: - flags        Volume attach flags
+#: If there are no transactions, the list will be empty.
+#:
+$AFS_Help{vos_status} = '$server, [$cell] => @trans';
+sub AFS_vos_status {
+  my($server, $cell) = @_;
+  my(@trlist);
+
+  @args = ('status', '-server', $server);
+  push(@args, '-noauth')           if ($AFS_Parms{'authlvl'} == 0);
+  push(@args, '-localauth')        if ($AFS_Parms{'authlvl'} == 2);
+  push(@args, '-verbose')          if ($AFS_Parms{'vostrace'} > 2);
+  push(@args, '-cell', $cell ? $cell : $AFS_Parms{'cell'});
+  &wrapper('vos', \@args,
+          [$vos_err_parse,
+           ['^(\-)', sub {
+             my(%trinfo) = %OpenAFS::wrapper::result;
+             
+             if ($trinfo{transid}) {
+               push(@trlist, \%trinfo);
+               %OpenAFS::wrapper::result = ();
+             }
+           }],
+           ['^transaction\:\s*(\d+)\s*created: (.*\S+)',        'transid', 'stamp_create'],
+           ['^attachFlags:\s*(.*\S+)',                          'flags'],
+           ['^volume:\s*(\d+)\s*partition\: \/vicep(\S+)\s*procedure\:\s*(\S+)',
+            'volid', 'part', 'action'],
+           ($AFS_Parms{'vostrace'} > 2) ? ([ '', '?']) : () ]);
+
+  @trlist;
+}
+
+1;
diff --git a/src/tests/OpenAFS/wrapper.pm b/src/tests/OpenAFS/wrapper.pm
new file mode 100644 (file)
index 0000000..4e4931f
--- /dev/null
@@ -0,0 +1,729 @@
+# CMUCS AFStools
+# Copyright (c) 1996, 2001 Carnegie Mellon University
+# All rights reserved.
+#
+# See CMU_copyright.ph for use and distribution information
+
+package OpenAFS::wrapper;
+
+=head1 NAME
+
+OpenAFS::wrapper - AFS command wrapper
+
+=head1 SYNOPSIS
+
+  use OpenAFS::wrapper;
+  %result = &wrapper($cmd, \@args, \@pspec, \%options);
+
+=head1 DESCRIPTION
+
+This module provides a generic wrapper for calling an external program and
+parsing its output.  It is primarily intended for use by AFStools for calling
+AFS commands, but is general enough to be used for running just about any
+utility program.  The wrapper is implemented by a single function,
+B<OpenAFS::wrapper::wrapper>, which takes several arguments:
+
+=over 4
+
+=item $cmd
+
+The command to run.  This can be a full path, or it can be a simple command
+name, in which case B<wrapper()> will find the binary on its internal path.
+
+=item \@args
+
+A reference to the list of arguments to be passed to the command.  Each
+element of the list is passed as a single argument, as in B<exec()>.
+
+=item \@pspec
+
+A reference to the list describing how to parse the command's output.
+See below for details.
+
+=item \%options
+
+A reference to a table of command execution and parsing options.
+
+=back
+
+On success, B<wrapper()> returns an associative array of data gathered
+from the command's output.  The exact contents of this array are
+caller-defined, and depend on the parsing instructions given.  On failure,
+an exception will be thrown (using B<die>), describing the reason for the
+failure.
+
+The I<%options> table may be used to pass any or all of the following
+options into B<wrapper()>, describing how the command should be executed
+and its output parsed:
+
+=over 4
+
+=item pass_stderr
+
+If specified and nonzero, the command's stderr will be passed directly
+to the calling program's, instead of being parsed.  This is useful when
+we want to process the command's output, but let the user see any
+diagnostic output or error messages.
+
+=item pass_stdout
+
+If specified and nonzero, the command's stdout will be passed directly
+to the calling program's, instead of being parsed.  This is useful when
+the command being run produces diagnostic or error messages on stderr
+that we want to parse, but provides bulk data on stdout that we don't
+want to touch (e.g. B<vos dump> when the output file is stdout).
+
+=item path
+
+If specified, the path to be used for the program to execute, instead of
+deriving it from the command name.  This is useful when we want the
+command's argv[0] (which is always I<$cmd}) to be different from the
+path to the program.
+
+=item errors_last
+
+If specified and nonzero, the built-in instructions for catching errors
+from the command will be added to the end of the instructions in @pspec
+instead of to the beginning.
+
+=back
+
+=head1 PARSING COMMAND OUTPUT
+
+The I<@pspec> list describes how to parse command output.  Each element
+of the list acts like an "instruction" describing how to parse the command's
+output.  As each line of output is received from the program, the parsing
+instructions are run over that line in order.  This process continues for
+every line of output until the program terminates, or the process is
+aborted early by flow-control operators.
+
+Each parsing instruction is a reference to a list, which consists of a
+regular expression and a list of "actions".  As a line of output is
+processed, it is compared to each instruction's regexp in turn.  Whenever
+a match is found, the actions associated with that instruction are taken,
+in order.  Each instruction's regexp may contain one or more parenthesized
+subexpressions; generally, each "action" uses up one subexpression, but there
+are some exceptions.  Due to the current design of B<wrapper()>, each regexp
+must have at least one subexpression, even if it is not used.
+
+The acceptable actions are listed below, each followed by a number in brackets
+indicating how many subexpressions are "used" by this action.  It is an error
+if there are not enough subexpressions left to satisfy an action.  In the
+following descriptions, I<$action> is the action itself (typically a string or
+reference), I<$value> is the value of the subexpression that will be used, and
+I<%result> is the result table that will be returned by B<wrapper> when the
+command completes.
+
+=over 4
+
+=item string  [1]
+
+Sets $result{$action} to $value.  Note that several specific strings have
+special meaning, and more may be added in the future.  To ensure compatibility
+with future versions of B<wrapper>, use only valid Perl identifiers as
+"string" actions.
+
+=item scalar ref  [1]
+
+Sets $$action to $value.
+
+=item list ref  [*]
+
+Pushes the remaining subexpression values onto @$action.  This action uses
+all remaining subexpression values.
+
+=item hash ref  [2]
+
+Sets $$action{$value0} to $value1.
+
+=item code ref  [*]
+
+Calls the referenced function, with all remaining subexpression values as
+its arguments.  Any values returned by the function will be used to refill
+the (now empty) subexpression value list, and thus may be used as arguments
+by subsequent actions.  If only a few values are required, use a function
+like this:
+
+  sub usetwo {  # uses two values and preserves the rest
+    my($val1, $val2, @rest) = @_;
+
+    print STDOUT "Got $val1, $val2\n";
+    @rest;
+  }
+
+=item '.'  [0]
+
+End processing for this line of output, ignoring any remaining instructions.
+Remaining actions in this instruction will be processed.
+
+=item '+n'  [0]
+
+Skip the next I<n> instructions.  This, along with the '.' action, can be
+used to build simple flow-control constructs based on the contents of
+lines of output.
+
+=item '-x'  [0..1]
+
+Signal an error after this instruction.  Remaining actions in this instruction
+will be processed, but no further instructions will be processed for this
+line, and no further lines of output will be processed.  If I<x> is given,
+it will be used as a regexp to match against the B<previous> line of output,
+and the first parenthesized subexpression resulting from that match will be
+used as the error string.  Otherwise, one subexpression from the current
+line will be used up as the error string.
+
+=item '?'  [1]
+
+Prints $value to STDOUT.
+
+=back
+
+=cut
+
+use OpenAFS::CMU_copyright;
+use OpenAFS::util qw(:DEFAULT :afs_internal);
+use Exporter;
+use Symbol;
+
+$VERSION   = '';
+$VERSION   = '1.00';
+@ISA       = qw(Exporter);
+@EXPORT    = qw(&wrapper);
+@EXPORT_OK = qw(&wrapper &fast_wrapper);
+
+sub wrapper {
+  my($cmd, $args, $instrs, $options) = @_;
+  my($prevline, $pid, $exception);
+  my(@instrs, $instr, $action, @values, $path);
+  local(%result);
+  my(@werrinstrs) = ([ '^(wrapper\:.*)',       '-' ]);
+  my(@cerrinstrs) = ([ '^(' . $cmd  . '\:.*)', '-' ],
+                     [ '^(' . $path . '\:.*)', '-' ]);
+
+  if ($options->{errors_last}) {
+    @instrs = (@werrinstrs, @$instrs, @cerrinstrs);
+  } else {
+    @instrs = (@werrinstrs, @cerrinstrs, @$instrs);
+  }
+
+  if ($options->{path}) {
+    $path = $options->{path};
+  } elsif ($cmd =~ /^\//) {
+    $path = $cmd;
+  } else {
+    $path = $AFScmd{$cmd};
+  }
+
+  if ($AFS_Trace{wrapper}) {
+    print STDERR "Instructions:\n";
+    foreach $instr (@$instrs) {
+      print STDERR "  /", $instr->[0], "/\n";
+      if ($AFS_Trace{wrapper} > 2) {
+       my(@actions) = @$instr;
+       shift(@actions);
+       print "  => ",
+       join(', ', map { ref($_) ? "<" . ref($_) . " reference>"
+                          : $_ } @actions),
+         "\n";
+      }
+    }
+  }
+
+  ## Start the child
+  if ($options->{pass_stdout}) {
+    open(REALSTDOUT, ">&STDOUT");
+  }
+  $pid = open(AFSCMD, "-|");
+  if (!defined($pid)) {
+    die "wrapper: Fork failed for $cmd: $!\n";
+  }
+
+  ## Run the appropriate program
+  if (!$pid) {
+
+    if ($AFS_Trace{wrapper} > 1) {
+      print STDERR "Command: $path ", join(' ', @$args), "\n";
+    }
+
+    open(STDERR, ">&STDOUT") if (!$options{pass_stderr});
+    if ($options{pass_stdout}) {
+      open(STDOUT, ">&REALSTDOUT");
+      close(REALSTDOUT);
+    }
+
+    { exec($path $cmd, @$args); }
+    # Need to be careful here - we might be doing "vos dump" to STDOUT
+    if ($options{pass_stdout}) {
+      print STDERR "wrapper: Exec failed for $cmd: $!\n";
+    } else {
+      print STDOUT "wrapper: Exec failed for $cmd: $!\n";
+    }
+    exit(127);
+  }
+  if ($options{pass_stdout}) {
+    close(REALSTDOUT);
+  }
+
+  ## Now, parse the output
+ line:
+  while (<AFSCMD>) {
+    my($skip) = 0;
+
+    print STDERR $_ if ($AFS_Trace{wrapper} > 3);
+    chop;
+
+  instr:
+    foreach $instr (@instrs) {
+      my($dot, $action, @actions);
+
+      if ($skip) {
+       $skip--;
+       next instr;
+      }
+      $dot = 0;
+      if ($instr->[0]) {
+       @values = ($_ =~ $instr->[0]);
+       next instr if (!@values);
+      } else {
+       @values = ();
+      }
+      
+    act:
+      @actions = @$instr;
+      shift(@actions);
+      foreach $action (@actions) {
+       if      (ref($action) eq 'SCALAR') {
+         if (@values) {
+           $$action = shift(@values);
+         } else {
+           last act;
+         }
+       } elsif (ref($action) eq 'ARRAY') {
+         push(@$action, @values);
+         @values = ();
+       } elsif (ref($action) eq 'HASH') {
+         if (@values > 1) {
+           $$action{$values[0]} = $values[1];
+           shift(@values); shift(@values);
+         } elsif (@values) {
+           $$action{shift @values} = '';
+           last act;
+         } else {
+           last act;
+         }
+       } elsif (ref($action) eq 'CODE') {
+         @values = &$action(@values);
+       } elsif (ref($action)) {
+         $exception = "Unknown reference to " . ref($action)
+                     . "in parse instructions";
+         last line;
+       } else {                  ## Must be a string!
+         if ($action eq '.') {
+           $dot = 1;
+         } elsif ($action =~ /\+(\d+)/) {
+           $skip = $1;
+         } elsif ($action =~ /-(.*)/) {
+           my($pat) = $1;
+
+           if ($pat && $prevline) {
+             ($exception) = ($prevline =~ $pat);
+           } elsif (@values) {
+             $exception = shift(@values);
+           } else {
+             $exception = $_;
+           }
+         } elsif ($action eq '?') {
+           print STDOUT (@values ? shift(@values) : $_), "\n";
+         } elsif (@values) {
+           $result{$action} = shift(@values);
+         } else {
+           last act;
+         }
+       }
+      }
+      
+      last line if ($exception);
+      last instr if ($dot);
+    }
+    $prevline = $_;
+  }
+  close(AFSCMD);
+  $exception .= "\n" if ($exception && $exception !~ /\n$/);
+  die $exception if ($exception);
+  %result;
+}
+
+
+## Generate code for a fast wrapper (see example below)
+sub _fastwrap_gen {
+  my($instrs, $refs) = @_;
+  my($SRC, $N, $N1, $X, $instr, $pattern, @actions, $action);
+
+  $N = $X = 0;
+  $N1 = 1;
+
+  $SRC = <<'#####';
+sub {
+  my($FD, $refs) = @_;
+  my($prevline, @values, $skip, $exception);
+
+  line: while (<$FD>) {
+#####
+
+  $SRC .= "    print STDERR \$_;\n" if ($AFS_Trace{'wrapper'} > 3);
+  $SRC .= "    chop;\n";
+
+  foreach $instr (@$instrs) {
+    ($pattern, @actions) = (@$instr);
+    $SRC .= ($pattern ? <<"#####" : <<"#####");
+
+    instr_$N:
+    die \$exception if \$exception;
+    if (\$skip) { \$skip-- } else {
+      \@values = (\$_ =~ /$pattern/);
+      if (\@values) {
+#####
+
+    instr_$N:
+    die \$exception if \$exception;
+    if (\$skip) { \$skip-- } else {
+      \@values = ();
+      if (1) {
+#####
+
+    foreach $action (@actions) {
+      if      (ref($action) eq 'SCALAR') {
+        $refs[++$X] = $action;
+        $SRC .= <<"#####";
+
+        if (\@values) { \${\$refs[$X]} = shift (\@values) }
+        else { goto instr_$N1 }
+#####
+
+      } elsif (ref($action) eq 'ARRAY') {
+        $refs[++$X] = $action;
+        $SRC .= <<"#####";
+
+        push(\@{\$refs[$X]}, \@values);
+        \@values = ();
+#####
+
+      } elsif (ref($action) eq 'HASH') {
+        $refs[++$X] = $action;
+        $SRC .= <<"#####";
+
+        if (\@values > 1) {
+          \$refs[$X]{\$values[0]} = shift(\$values[1]);
+          shift(\@values); shift(\@values);
+        } elsif (\@values) {
+          \$refs[$X]{shift(\@values)} = '';
+          goto instr_$N1;
+        } else {
+          goto instr_$N1;
+        }
+#####
+
+      } elsif (ref($action) eq 'CODE') {
+        $refs[++$X] = $action;
+        $SRC .= "\n        \@values = \$refs[$X]->(\@values);\n";
+
+      } elsif (ref($action)) {
+        die "Unknown reference to " . ref($action) . "in parse instructions\n";
+
+      } elsif ($action eq '.') {
+        $SRC .= "\n        next line;\n";
+
+      } elsif ($action eq '?') {
+        $SRC .= <<"#####";
+
+        if (\@values) { print STDOUT shift(\@values), "\\n" }
+        else         { print STDOUT \$_, "\\n" }
+#####
+
+      } elsif ($action =~ /\+(\d+)/) {
+        $SRC .= "\n        \$skip = $1;\n";
+
+      } elsif ($action =~ /-(.*)/) {
+        $SRC .= $1 ? <<"#####" : <<"#####";
+
+        if (\$prevline)  { (\$exception) = (\$prevline =~ /$1/) }
+        elsif (\@values) { \$exception = shift(\@values) }
+        else            { \$exception = \$_ }
+#####
+
+        if (\@values)    { \$exception = shift(\@values) }
+        else            { \$exception = \$_ }
+#####
+
+      } else {
+        $SRC .= <<"#####";
+
+        if (\@values) { \$result{"\Q$action\E"} = shift(\@values) }
+        else { goto instr_$N1 }
+#####
+      }
+    }
+
+    $N++; $N1++;
+    $SRC .= <<'#####';
+      }
+    }
+#####
+  }
+
+  $SRC .= <<'#####';
+  } continue {
+    die $exception if $exception;
+    $prevline = $_;
+  }
+}
+#####
+
+  $SRC;
+}
+
+####################### Example code #######################
+# sub {
+#   my($FD, $refs) = @_;
+#   my($prevline, @values, $skip, $exception);
+# 
+#   line: while (<$FD>) {
+#     print STDERR $_;     ## if ($AFS_Trace{'wrapper'} > 3);
+#     chop;
+# 
+#     ## Following block repeated for each instruction
+#     instr_N:
+#     die $exception if $exception;
+#     if ($skip) { $skip-- } else {
+#       @values = ($_ =~ /## pattern ##/);    ## () if no pattern
+#       if (@values) {                        ## 1 if no pattern
+#         ## For each action, include one of the following blocks:
+# 
+#         ## SCALAR ref
+#         if (@values) { ${$refs[X]} = shift (@values) }
+#         else { goto instr_N+1 }
+# 
+#         ## ARRAY ref
+#         push(@{$refs[X]}, @values);
+#         @values = ();
+# 
+#         ## HASH ref
+#         if (@values > 1) {
+#           $refs[X]{shift(@values)} = shift(@values);
+#         } elsif (@values) {
+#           $refs[X]{shift(@values)} = '';
+#           goto instr_N+1;
+#         } else {
+#           goto instr_N+1;
+#         }
+# 
+#         ## CODE ref
+#         @values = $refs[X]->(@values);
+# 
+#         ## string '.'
+#         next line;
+# 
+#         ## string '?'
+#         if (@values) { print STDOUT shift(@values), "\n" }
+#         else         { print STDOUT $_, "\n" }
+# 
+#         ## string '+DDD'
+#         $skip = DDD;
+# 
+#         ## string '-XXX'
+#         if ($prevline)  { ($exception) = ($prefline =~ /XXX/) }
+#         elsif (@values) { $exception = shift(@values) }
+#         else            { $exception = $_ }
+#         
+#         ## string '-'
+#         if (@values)    { $exception = shift(@values) }
+#         else            { $exception = $_ }
+# 
+#         ## anything else
+#         if (@values) { $result{XXX} = shift(@values) }
+#         else { goto instr_N+1 }
+#       }
+#     }
+# 
+#   } continue {
+#     die $exception if $exception;
+#     $prevline = $_;
+#   }
+# }
+############################################################
+
+
+## The following does exactly the same thing as wrapper(),
+## but should be considerably faster.  Instead of interpreting
+## parsing instructions, it translates them into perl code,
+## which is then compiled into the interpreter.  The chief
+## benefit to this approach is that we no longer compile
+## one RE per instruction per line of input.
+
+sub fast_wrapper {
+  my($cmd, $args, $instrs, $options) = @_;
+  my(@instrs, $SRC, $CODE, $path, $pid, $refs, $FD, $exception);
+  local(%result);
+  my(@werrinstrs) = ([ '^(wrapper\:.*)',       '-' ]);
+  my(@cerrinstrs) = ([ '^(' . $cmd  . '\:.*)', '-' ],
+                     [ '^(' . $path . '\:.*)', '-' ]);
+
+  $FD = gensym;
+  $refs = [];
+  if ($options->{errors_last}) {
+    @instrs = (@werrinstrs, @$instrs, @cerrinstrs);
+  } else {
+    @instrs = (@werrinstrs, @cerrinstrs, @$instrs);
+  }
+  $SRC = _fastwrap_gen(\@instrs, $refs);
+  $CODE = eval $SRC;
+
+  if ($options->{path}) {
+    $path = $options->{path};
+  } elsif ($cmd =~ /^\//) {
+    $path = $cmd;
+  } else {
+    $path = $AFScmd{$cmd};
+  }
+
+  if ($AFS_Trace{'wrapper'}) {
+    print STDERR "Instructions:\n";
+    foreach $instr (@$instrs) {
+      print STDERR "  /", $instr->[0], "/\n";
+      if ($AFS_Trace{'wrapper'} > 2) {
+       my(@actions) = @$instr;
+       shift(@actions);
+       print "  => ",
+       join(', ', map { ref($_) ? "<" . ref($_) . " reference>"
+                          : $_ } @actions),
+         "\n";
+      }
+    }
+  }
+
+  if ($AFS_Trace{'wrapper'} > 2) { print STDERR "Input parse code:\n$SRC\n" }
+
+  ## Start the child
+  if ($options->{pass_stdout}) {
+    open(REALSTDOUT, ">&STDOUT");
+  }
+  $pid = open($FD, "-|");
+  if (!defined($pid)) {
+    die "wrapper: Fork failed for $cmd: $!\n";
+  }
+
+  ## Run the appropriate program
+  if (!$pid) {
+    if ($AFS_Trace{'wrapper'} > 1) {
+      print STDERR "Command: $path ", join(' ', @$args), "\n";
+    }
+
+    open(STDERR, ">&STDOUT") if (!$options{pass_stderr});
+    if ($options{pass_stdout}) {
+      open(STDOUT, ">&REALSTDOUT");
+      close(REALSTDOUT);
+    }
+
+    { exec($path $cmd, @$args) }
+    # Need to be careful here - we might be doing "vos dump" to STDOUT
+    if ($options{pass_stdout}) {
+      print STDERR "wrapper: Exec failed for $cmd: $!\n";
+    } else {
+      print STDOUT "wrapper: Exec failed for $cmd: $!\n";
+    }
+    exit(127);
+  }
+  if ($options{pass_stdout}) {
+    close(REALSTDOUT);
+  }
+
+  ## Now, parse the output
+  eval { $CODE->($FD, $refs) };
+  $exception = $@;
+
+  close($FD);
+
+  $exception .= "\n" if ($exception && $exception !~ /\n$/);
+  die $exception if ($exception);
+  %result;
+}
+
+
+1;
+
+=head1 EXAMPLES
+
+The following set of instructions is used by B<wrapper> to detect errors
+issued by the command, or by the child process spawned to invoke the command.
+I<$cmd> is the name of the command to run, and I<$path> is the path to the
+binary actually invoked.
+
+  [ '^(wrapper\:.*)',       '-' ]
+  [ '^(' . $cmd  . '\:.*)', '-' ]
+  [ '^(' . $path . '\:.*)', '-' ]
+
+The following instruction is added by the B<OpenAFS::vos> module to catch errors
+generated by B<vos> commands, which often take the form of a generic error
+message (Error in vos XXX command), with a description of the specific problem
+on the preceeding line:
+
+  [ 'Error in vos (.*) command', '-(.*)' ]
+
+If the AFStools parameter I<vostrace> is nonzero, the following instruction
+is added to force all lines of output to be copied to STDOUT.  Note that this
+is different from specifying the I<pass_stdout> option, which would pass the
+command's STDOUT directly to ours without parsing it.
+
+  [ '', '?' ]
+
+B<OpenAFS::vos::AFS_vos_listvldb> uses the following instructions to parse the
+output of "vos listvldb".  This is a fairly complex example, which illustrates
+many of the features of B<wrapper>.
+
+  1  ['^(VLDB|Total) entries', '.']
+  2  ['^(\S+)', sub {
+       my(%vinfo) = %OpenAFS::wrapper::result;
+       if ($vinfo{name}) {
+         $vinfo{rosites} = [@rosites] if (@rosites);
+         $vlist{$vinfo{name}} = \%vinfo;
+         @rosites = ();
+         %OpenAFS::wrapper::result = ();
+       }
+     }],
+  3  ['^(\S+)',                       'name'   ],
+  4  ['RWrite\:\s*(\d+)',             'rwid'   ],
+  5  ['ROnly\:\s*(\d+)',              'roid'   ],
+  6  ['Backup\:\s*(\d+)',             'bkid'   ],
+  7  ['Volume is currently (LOCKED)', 'locked' ],
+  8  ['server (\S+) partition /vicep(\S+) RW Site',       'rwserv', 'rwpart'],
+  9  ['server (\S+) partition /vicep(\S+) RO Site',       sub {
+       push(@rosites, [$_[0], $_[1]]);
+     }],
+
+Instruction 1 matchees the header and trailer lines printed out by B<vos>, and
+terminates processing of those lines before instructions 2 and 3 have a chance
+to match it.  This is a simple example of a conditional - the next two
+instructions are used only if this one doesn't match.  If we wanted to consider
+additional instructions even on lines that do match this one, we could place
+them above this one, or use '+2' instead of '.', which would skip only the next
+two instructions and allow remaining ones to be processed.
+
+Instruction 2 matches the first line printed for each volume, stores away any
+information that has been collected about the previous volume, and prepares for
+the new one.  Besides being a good example of use of a code reference as an
+action, this instruction also takes advantage of the fact that B<wrapper>'s
+%result array is a dynamically-scoped variable, and so can be modified by code
+referenced in parsing instructions.
+
+The remaining instructions are fairly simple.  Instructions 3 through 8 use
+simple strings to add information about the volume to %result.  Instruction 9
+is a bit more complicated; it uses a function to add a server/partition pair
+to the current volume's list of RO sites.
+
+=head1 COPYRIGHT
+
+The CMUCS AFStools, including this module are
+Copyright (c) 1996, 2001 Carnegie Mellon University.  All rights reserved.
+For use and redistribution information, see CMUCS/CMU_copyright.pm
+
+=cut
diff --git a/src/tests/README b/src/tests/README
new file mode 100644 (file)
index 0000000..f73299e
--- /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) Write a file larger than the cache. (fcachesize-write-file)
+20) Read a file larger than the cache. (fcachesize-read-file)
+30) Restore volume with a bad uniquifier in it, salvage, check. (baduniq)
+40) Check for bad dentry caching on Linux taking advantage of last test. (?)
+
+---
+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/README.dumptool b/src/tests/README.dumptool
new file mode 100644 (file)
index 0000000..9af5ac7
--- /dev/null
@@ -0,0 +1,152 @@
+$Id: README.dumptool,v 1.1 2002/01/22 19:54:39 hartmans Exp $
+
+This is the README for dumptool, a program to interactively restore
+AFS volume dump files.
+
+
+INTRODUCTION
+
+Dumptool arose out of a need here at NRL to perform maintenance of
+MR-AFS (Multi-Resident AFS) volumes.  After it was written, we found
+that it worked great on standard AFS volumes as well, and relatively
+few changes were required to make it compile with a standard AFS
+installation.
+
+Dumptool provides an interface similar to the interactive Unix restore;
+given a dump file, a user can navigate through the filesystem inside
+the dump using familiar commands such as "cd" and "ls".  Also provided
+is a "cp" command to copy individual files out of the dump into a
+normal filesystem space.  This eliminates the need to restore an
+entire volume just to retrieve a single file.
+
+Dumptool was written at the Naval Research Laboratory by Ken Hornstein
+<kenh@cmf.nrl.navy.mil>.  The latest and greatest version of dumptool
+can always be found in the AFS contrib directory at:
+
+/afs/transarc.com/public/afs-contrib/dumptool/
+
+
+INSTALLATION & OPERATION
+
+The standard Makefile target will build a dumptool for a vanilla AFS
+installation.  The "mrafs" target will build a dumptool that can
+operate on MR-AFS dumps.  In either case, you may need to change some
+of the Makefile variables to reflect your site; see the Makefile for
+more information.
+
+Once dumptool is built successfully, you can run it on any AFS dump
+file.  Without any additional arguments, dumptool will scan the dump file,
+build indexes of all listed vnodes, and present a prompt (">") that
+accepts the following commands:
+
+       ls      Lists files in the current directory.  Filename globbing
+               (e.g., wildcards such as * ?) are supported via the system
+               fnmatch() function.  Accepts the following flags:
+
+           -l  Generates a "long" listing, similar to the -l switch for
+               the Unix ls.  Displays Unix mode mask, owner, group,
+               and file size.
+           -i  Displays volume, vnode, and uniquifier for each matching
+               file in the format volume.vnode.uniquifier.  Note that
+               the volume displayed is that of the _parent_ volume,
+               which in the case of a backup volume is the _original_
+               volume from which it was generated.
+           -F  Append / to filenames for directories, @ for symlinks,
+               and * for files which have the execute bits set.
+           -R  Recurse through all subdirectories.
+       
+       cd      Change the current directory
+
+       cp      Copy a file from the dump.  Note that globbing is NOT
+               supported, and you must give a filename (the Unix
+               idiom of just giving a destination directory for the
+               second argument to cp will NOT work).
+       
+       vcp     Copy a file from the dump, by the vnode.  The first
+               argument is the vnode number, optionally followed by
+               the uniqifier.  E.g:
+
+               vcp 126278 /tmp/file1
+               vcp 126278.43289 /tmp/file2
+       
+       quit    Exits dumptool.
+       exit
+
+
+ADDITIONAL OPTIONS TO DUMPTOOL
+
+Dumptool supports a number of command-line options.  They are detailed
+below:
+
+       -v      Verbose mode.  Output additional information during dump
+               processing.  Each -v will increate output.
+
+       -f      Force dump processing.  Attempt to continue processing
+               a dump even when some errors are detected.  Not completely
+               tested.
+       
+       -i      Inode dump.  Dump a list of all files in the volume,
+               with their volume/vnode/uniqifier information.
+
+
+SUPPORT FOR MR-AFS
+
+Dumptool also supports the extra information in MR-AFS dumps, and
+provides some extra commands/options for dealing with MR-AFS dumps:
+
+Additional command line options:
+
+       -d      Dump all residency filenames in the dump file to standard
+               output.
+       
+       -t      Residency tag information.  Allows a user to specify the
+               tag of a residency if the rsserver is not available.
+               Format of option is Residency/Tag
+       
+       -r      Residency filesystem information.  Allows a user to specify
+               the residency filesystem information if dumptool is not
+               run on the same host as the residency in the dump.  Format
+               of option is Residency/Type/Size/Algorithm.
+
+Additional commands:
+
+       file    Displays to standard output the residency filename of a
+               given dump filename.  All residencies available are shown.
+
+
+CAVEATS
+
+The user interface needs some work.  "ls" doesn't support nearly as many
+options as the standard Unix one.  "cp" also doesn't have all of the features
+found in common Unix variants.
+
+Right now two passes are done through the dump file to scan all vnodes.
+With some clever work this could be sped up somewhat and changed to only
+do a single scan.
+
+
+MODIFYING DUMPTOOL
+
+I welcome changes to dumptool, but I have some guidelines.
+
+First, I DEMAND that the changes be sent in context diff format.  I prefer
+unidiff (diff -u), but standard context diffs are okay.  It's extremely
+difficult to deal with new code in any other way.
+
+If the changes you want to do require some significant
+rearchitecturing, it might be a good idea to contact me first.  That
+way we can coordinate the modifications in a meaningful way (I might
+have made changes since the last released version).
+
+If you're making MR-AFS specific changes, please follow the example
+I've set and protect them with #ifdef RESIDENCY.
+
+And please ... follow my code style, okay?  I always try to follow
+whatever wacky code style I find in source code that I modify, and I
+think it's only polite for you to do the same.
+
+
+CONTACT INFORMATION
+
+As always, please send comments, suggestions, or new features to me,
+Ken Hornstein <kenh@cmf.nrl.navy.mil>.  Shar and enjoy.
diff --git a/src/tests/TEMPLATE b/src/tests/TEMPLATE
new file mode 100644 (file)
index 0000000..6448750
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
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/afscp.c b/src/tests/afscp.c
new file mode 100644 (file)
index 0000000..6cb8931
--- /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 <afs/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/afsdump_dirlist.c b/src/tests/afsdump_dirlist.c
new file mode 100644 (file)
index 0000000..78d6037
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* afsdump_dirlist.c - List an AFS directory file */
+
+#include <sys/fcntl.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "dumpscan.h"
+
+extern int optind;
+extern char *optarg;
+
+char *argv0;
+static char *input_path;
+static int quiet, verbose, error_count;
+
+static path_hashinfo phi;
+static dump_parser dp;
+
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+  if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+  fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
+  fprintf(stderr, "  -h     Print this help message\n");
+  fprintf(stderr, "  -q     Quiet mode (don't print errors)\n");
+  fprintf(stderr, "  -v     Verbose mode\n");
+  exit(status);
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+  int c;
+
+  /* Set the program name */
+  if (argv0 = strrchr(argv[0], '/')) argv0++;
+  else argv0 = argv[0];
+
+  /* Initialize options */
+  input_path = 0;
+  quiet = verbose = 0;
+
+  /* Initialize other stuff */
+  error_count = 0;
+
+  /* Parse the options */
+  while ((c = getopt(argc, argv, "hqv")) != EOF) {
+    switch (c) {
+      case 'q': quiet        = 1;                         continue;
+      case 'v': verbose      = 1;                         continue;
+      case 'h': usage(0, 0);
+      default:  usage(1, "Invalid option!");
+    }
+  }
+
+  if (quiet && verbose) usage(1, "Can't specify both -q and -v");
+
+  /* Parse non-option arguments */
+  if (argc - optind > 1) usage(1, "Too many arguments!");
+  input_path = (argc == optind) ? "-" : argv[optind];
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+  va_list alist;
+
+  error_count++;
+  if (!quiet) {
+    va_start(alist, msg);
+    com_err_va(argv0, code, msg, alist);
+    va_end(alist);
+  }
+}
+
+
+/* Main program */
+void main(int argc, char **argv)
+{
+  XFILE input_file;
+  afs_uint32 r;
+
+  parse_options(argc, argv);
+  initialize_acfg_error_table();
+  initialize_AVds_error_table();
+  initialize_rxk_error_table();
+  initialize_u_error_table();
+  initialize_vl_error_table();
+  initialize_vols_error_table();
+  initialize_xFil_error_table();
+  r = xfopen(&input_file, O_RDONLY, input_path);
+  if (r) {
+    com_err(argv0, r, "opening %s", input_path);
+    exit(2);
+  }
+
+  memset(&dp, 0, sizeof(dp));
+  dp.cb_error     = my_error_cb;
+  dp.print_flags  = DSPRINT_DIR;
+  if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
+
+  r = ParseDirectory(&input_file, &dp, 0, 1);
+  xfclose(&input_file);
+
+  if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
+  if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
+  exit(0);
+}
diff --git a/src/tests/afsdump_extract.c b/src/tests/afsdump_extract.c
new file mode 100644 (file)
index 0000000..e92c66e
--- /dev/null
@@ -0,0 +1,526 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* afsdump_extract.c - Extract files from an AFS dump */
+
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+
+#define COPYBUFSIZE (256*1024)
+
+extern int optind;
+extern char *optarg;
+
+char *argv0;
+static char **file_names;
+static int *file_vnums, name_count, vnum_count;
+
+static char *input_path, *target;
+static int quiet, verbose, error_count, dirs_done, extract_all;
+static int nomode, use_realpath, use_vnum;
+static int do_acls, do_headers;
+
+static path_hashinfo phi;
+static dump_parser dp;
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+  if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+  fprintf(stderr, "Usage: %s [options] dumpfile [dest [files...]]\n", argv0);
+  fprintf(stderr, "  -A     Save ACL's\n");
+  fprintf(stderr, "  -H     Save headers\n");
+  fprintf(stderr, "  -h     Print this help message\n");
+  fprintf(stderr, "  -i     Use vnode numbers\n");
+  fprintf(stderr, "  -n     Don't actually create files\n");
+  fprintf(stderr, "  -p     Use real pathnames internally\n");
+  fprintf(stderr, "  -q     Quiet mode (don't print errors)\n");
+  fprintf(stderr, "  -v     Verbose mode\n");
+  fprintf(stderr, "The destination directory defaults to .\n");
+  fprintf(stderr, "Files may be vnode numbers or volume-relative paths;\n");
+  fprintf(stderr, "If vnode numbers are used, files will be extracted\n");
+  fprintf(stderr, "a name generated from the vnode number and uniqifier.\n");
+  fprintf(stderr, "If paths are used, -p is implied and files will be\n");
+  fprintf(stderr, "into correctly-named files.\n");
+  exit(status);
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+  int c, i, i_name, i_vnum;
+
+  /* Set the program name */
+  if (argv0 = strrchr(argv[0], '/')) argv0++;
+  else argv0 = argv[0];
+
+  /* Initialize options */
+  input_path = 0;
+  quiet = verbose = nomode = 0;
+  use_realpath = use_vnum = do_acls = do_headers = extract_all = 0;
+
+  /* Initialize other stuff */
+  error_count = 0;
+
+  /* Parse the options */
+  while ((c = getopt(argc, argv, "AHhinpqv")) != EOF) {
+    switch (c) {
+      case 'A': do_acls      = 1;                         continue;
+      case 'H': do_headers   = 1;                         continue;
+      case 'i': use_vnum     = 1;                         continue;
+      case 'n': nomode       = 1;                         continue;
+      case 'p': use_realpath = 1;                         continue;
+      case 'q': quiet        = 1;                         continue;
+      case 'v': verbose      = 1;                         continue;
+      case 'h': usage(0, 0);
+      default:  usage(1, "Invalid option!");
+    }
+  }
+
+  if (quiet && verbose) usage(1, "Can't specify both -q and -v");
+
+  /* Parse non-option arguments */
+  if (argc - optind < 1) usage(1, "Dumpfile name required!");
+  input_path = argv[optind];
+
+  if (argc - optind < 2) target = ".";
+  target = argv[optind + 1];
+
+  vnum_count = name_count = 0;
+  if (argc - optind < 3) extract_all = 1;
+  else {
+    argv += optind + 2;
+    argc -= optind + 2;
+    for (i = 0; i < argc; i++) {
+      if (argv[i][0] == '/') name_count++;
+      else                   vnum_count++;
+    }
+    file_names = (char **)malloc(name_count + sizeof(char *));
+    file_vnums = (afs_uint32 *)malloc(vnum_count + sizeof(afs_uint32));
+    if (name_count) use_realpath = 1;
+
+    i_name = i_vnum = 0;
+    for (i = 0; i < argc; i++) {
+      if (argv[i][0] == '/') file_names[i_name++] = argv[i];
+      else                   file_vnums[i_vnum++] = strtol(argv[i], 0, 0);
+    }
+  }
+}
+
+
+static int mkdirp(char *path)
+{
+  char *x = path, slash;
+  struct stat statbuf;
+
+  for (;;) {
+    while (*x && *x != '/') x++;
+    slash = *x;
+    *x = 0;
+
+    if (stat(path, &statbuf)) {
+      if (errno == ENOENT) {
+        if (verbose) printf("> mkdir %s\n", path);
+        if (!mkdir(path, 0755)) errno = 0;
+      }
+    }
+    if (!slash) break;
+    *x++ = '/';
+    if (errno) return errno;
+  }
+
+  return 0;
+}
+
+
+static char *modestr(int mode)
+{
+  static char str[10];
+  int i;
+
+  strcpy(str, "rwxrwxrwx");
+  for (i = 0; i < 9; i++) {
+    if (!(mode & (1 << i)))
+      str[8 - i] = '-';
+  }
+  if (mode & 01000) str[8] = (str[8] == '-') ? 'T' : 't';
+  if (mode & 02000) str[5] = (str[5] == '-') ? 'S' : 's';
+  if (mode & 04000) str[2] = (str[2] == '-') ? 'S' : 's';
+  return str;
+}
+
+
+static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+static char *datestr(time_t date)
+{
+  static char str[13];
+  time_t clock = time(0);
+  struct tm *now, *then;
+  int diff;
+
+  now = localtime(&clock);
+  then = localtime(&date);
+
+  diff = now->tm_mon - then->tm_mon;
+  if (then->tm_year == now->tm_year - 1) diff += 12;
+  if (then->tm_year == now->tm_year + 1) diff -= 12;
+
+  if (diff < 5 || diff > 5)
+    sprintf(str, "%3s %2d  %4d", month[then->tm_mon], then->tm_mday,
+            then->tm_year + 1900);
+  else
+    sprintf(str, "%3s %2d %2d:%2d", month[then->tm_mon], then->tm_mday,
+            then->tm_hour, then->tm_min);
+  return str;
+}
+
+
+/* Should we use this vnode?
+ * Return 0 if no, non-0 if yes
+ */
+static int usevnode(XFILE *X, afs_uint32 vnum, char *vnodepath)
+{
+  int vl, vpl, r, i;
+
+  /* Special case */
+  if (extract_all || !strcmp(vnodepath, "/"))
+    return 1;
+
+  for (i = 0; i < vnum_count; i++)
+    if (vnum == file_vnums[i]) return 2;
+
+  vl = strlen(vnodepath);
+/*fprintf(stderr, "++ checking %s\n", vnodepath);*/
+  for (i = 0; i < name_count; i++) {
+    vpl = strlen(file_names[i]);
+/*  fprintf(stderr, "   %s\n", file_names[i]);*/
+
+    if (vl > vpl) {
+      r = !strncmp(file_names[i], vnodepath, vpl) && vnodepath[vpl] == '/';
+    } else if (vl < vpl) {
+      r = !strncmp(file_names[i], vnodepath, vl) && file_names[i][vl] == '/';
+    } else {
+      r = !strcmp(file_names[i], vnodepath);
+    }
+    if (r) return 1;
+  }
+  return 0;
+}
+
+
+static int copyfile(XFILE *in, XFILE *out, int size)
+{
+  static char buf[COPYBUFSIZE];
+  int nr, nw, r;
+
+  while (size) {
+    nr = (size > COPYBUFSIZE) ? COPYBUFSIZE : size;
+    if (r = xfread(in, buf, nr)) return r;
+    if (r = xfwrite(out, buf, nr)) return r;
+    size -= nr;
+  }
+  return 0;
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+  va_list alist;
+
+  error_count++;
+  if (!quiet) {
+    va_start(alist, msg);
+    com_err_va(argv0, code, msg, alist);
+    va_end(alist);
+  }
+}
+
+
+static afs_uint32 dumphdr_cb(afs_dump_header *hdr, XFILE *X, void *refcon)
+{
+  return 0;
+}
+
+
+static afs_uint32 volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
+{
+  return 0;
+}
+
+
+static afs_uint32 directory_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+  char *vnodepath;
+  int r, use;
+
+  /* Should we even use this? */
+  if (!use_vnum) {
+    if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
+      return r;
+    if (!(use = usevnode(X, v->vnode, vnodepath))) {
+      free(vnodepath);
+      return 0;
+    }
+  }
+
+  /* Print it out */
+  if (verbose) {
+    if (use_vnum) 
+      printf("d%s %3d %-11d %11d %s #%d:%d\n",
+             modestr(v->mode), v->nlinks, v->owner, v->size,
+             datestr(v->server_date), v->vnode, v->vuniq);
+    else
+      printf("d%s %3d %-11d %11d %s %s\n",
+             modestr(v->mode), v->nlinks, v->owner, v->size,
+             datestr(v->server_date), vnodepath);
+  }
+  else if (!quiet && !use_vnum)
+    printf("%s\n", vnodepath);
+
+  /* Make the directory, if needed */
+  if (!nomode && !use_vnum && use != 2) {
+    if (strcmp(vnodepath, "/")
+      && (r = mkdirp(vnodepath + 1))) {
+      free(vnodepath);
+      return r;
+    }
+    if (do_acls) {
+      /* XXX do ACL's later */
+    }
+  }
+  if (!use_vnum) free(vnodepath);
+  return 0;
+}
+
+
+static afs_uint32 file_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+  char *vnodepath, vnpx[30];
+  u_int64 where;
+  XFILE OX;
+  int r, use;
+
+  if (!dirs_done) {
+    dirs_done = 1;
+    if (verbose) printf("* Extracting files...\n");
+  }
+
+  /* Should we even use this? */
+  if (!use_vnum) {
+    if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
+      return r;
+    if (!(use = usevnode(X, v->vnode, vnodepath))) {
+      free(vnodepath);
+      return 0;
+    }
+    if (use == 2) {
+      free(vnodepath);
+      sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
+      vnodepath = vnpx;
+    }
+  } else {
+    sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
+    vnodepath = vnpx;
+  }
+
+  /* Print it out */
+  if (verbose) {
+    printf("-%s %3d %-11d %11d %s %s\n",
+           modestr(v->mode), v->nlinks, v->owner, v->size,
+           datestr(v->server_date), vnodepath);
+  } else if (!quiet) {
+    printf("%s\n", vnodepath);
+  }
+
+  if (!nomode) {
+    if ((r = xftell(X, &where))
+    ||  (r = xfseek(X, &v->d_offset))
+    ||  (r = xfopen_path(&OX, O_RDWR|O_CREAT|O_TRUNC, vnodepath + 1, 0644))) {
+      if (!use_vnum) free(vnodepath);
+      return r;
+    }
+    r = copyfile(X, &OX, v->size);
+    xfclose(&OX);
+    xfseek(X, &where);
+  } else r = 0;
+
+  if (!use_vnum && use != 2) free(vnodepath);
+  return r;
+}
+
+
+static afs_uint32 symlink_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+  char *vnodepath, *linktarget, vnpx[30];
+  u_int64 where;
+  int r, use;
+
+  if (!dirs_done) {
+    dirs_done = 1;
+    if (verbose) printf("* Extracting files...\n");
+  }
+
+  /* Should we even use this? */
+  if (!use_vnum) {
+    if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
+      return r;
+    if (!(use = usevnode(X, v->vnode, vnodepath))) {
+      free(vnodepath);
+      return 0;
+    }
+    if (use == 2) {
+      free(vnodepath);
+      sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
+      vnodepath = vnpx;
+    }
+  } else {
+    sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
+    vnodepath = vnpx;
+  }
+
+  if (!(linktarget = (char *)malloc(v->size + 1))) {
+    if (!use_vnum && use != 2) free(vnodepath);
+    return DSERR_MEM;
+  }
+  if ((r = xftell(X, &where))
+  ||  (r = xfseek(X, &v->d_offset))
+  ||  (r = xfread(X, linktarget, v->size))) {
+    if (!use_vnum && use != 2) free(vnodepath);
+    free(linktarget);
+    return r;
+  }
+  xfseek(X, &where);
+  linktarget[v->size] = 0;
+
+  /* Print it out */
+  if (verbose)
+    printf("l%s %3d %-11d %11d %s %s -> %s\n",
+           modestr(v->mode), v->nlinks, v->owner, v->size,
+           datestr(v->server_date), vnodepath, linktarget);
+  else if (!quiet)
+    printf("%s\n", vnodepath);
+
+  r = 0;
+  if (!nomode) {
+    if (symlink(linktarget, vnodepath + 1))
+      r = errno;
+  }
+
+  free(linktarget);
+  if (!use_vnum && use != 2) free(vnodepath);
+  return r;
+}
+
+
+static afs_uint32 lose_cb(afs_vnode *v, XFILE *F, void *refcon)
+{
+  int r;
+
+  if (!dirs_done) {
+    dirs_done = 1;
+    if (verbose) printf("* Extracting files...\n");
+  }
+
+  return 0;
+}
+
+
+/* Main program */
+void main(int argc, char **argv)
+{
+  XFILE input_file;
+  afs_uint32 r;
+
+  parse_options(argc, argv);
+  initialize_acfg_error_table();
+  initialize_AVds_error_table();
+  initialize_rxk_error_table();
+  initialize_u_error_table();
+  initialize_vl_error_table();
+  initialize_vols_error_table();
+  initialize_xFil_error_table();
+  r = xfopen(&input_file, O_RDONLY, input_path);
+  if (r) {
+    com_err(argv0, r, "opening %s", input_path);
+    exit(2);
+  }
+
+  memset(&dp, 0, sizeof(dp));
+  dp.cb_error       = my_error_cb;
+  if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
+  dirs_done = 0;
+
+  if (!use_vnum) {
+    u_int64 where;
+
+    memset(&phi, 0, sizeof(phi));
+    phi.p = &dp;
+
+    if (verbose) printf("* Building pathname info...\n");
+    if ((r = xftell(&input_file, &where))
+    ||  (r = Path_PreScan(&input_file, &phi, 1))
+    ||  (r = xfseek(&input_file, &where))) {
+      com_err(argv0, r, "- path initialization failed");
+      xfclose(&input_file);
+      exit(1);
+    }
+  }
+
+  dp.cb_vnode_dir   = directory_cb;
+  dp.cb_vnode_file  = file_cb;
+  dp.cb_vnode_link  = symlink_cb;
+  dp.cb_vnode_empty = lose_cb;
+  dp.cb_vnode_wierd = lose_cb;
+  if (do_headers) {
+    dp.cb_dumphdr   = dumphdr_cb;
+    dp.cb_volhdr    = volhdr_cb;
+  }
+
+  if (!nomode) {
+    mkdir(target, 0755);
+    if (chdir(target)) {
+      fprintf(stderr, "chdir %s failed: %s\n", target, strerror(errno));
+      exit(1);
+    }
+  }
+  r = ParseDumpFile(&input_file, &dp);
+
+  if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
+  if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
+  exit(0);
+}
diff --git a/src/tests/afsdump_scan.c b/src/tests/afsdump_scan.c
new file mode 100644 (file)
index 0000000..ae95d8b
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* afsdump_scan.c - General-purpose dump scanner */
+
+#include <sys/fcntl.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "dumpscan.h"
+
+extern int optind;
+extern char *optarg;
+
+extern XFILE repair_output;
+extern afs_uint32 repair_dumphdr_cb(afs_dump_header *, XFILE *, void *);
+extern afs_uint32 repair_volhdr_cb(afs_vol_header *, XFILE *, void *);
+extern afs_uint32 repair_vnode_cb(afs_vnode *, XFILE *, void *);
+
+char *argv0;
+static char *input_path, *gendump_path;
+static afs_uint32 printflags, repairflags;
+static int quiet, verbose, error_count;
+
+static path_hashinfo phi;
+static dump_parser dp;
+
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+  if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+  fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
+  fprintf(stderr, "  -Pxxx  Set print options:\n");
+  fprintf(stderr, "          B = Print backup system header (if any)\n");
+  fprintf(stderr, "          H = Print AFS dump header\n");
+  fprintf(stderr, "          V = Print AFS volume header\n");
+  fprintf(stderr, "          v = List vnodes\n");
+  fprintf(stderr, "          p = Include path to each vnode\n");
+  fprintf(stderr, "          i = Include info for each vnode\n");
+  fprintf(stderr, "          d = List directory contents\n");
+  fprintf(stderr, "          a = List access control lists\n");
+  fprintf(stderr, "          g = Print debugging info\n");
+  fprintf(stderr, "  -Rxxx  Set repair options:\n");
+  fprintf(stderr, "          0 = Skip null tags\n");
+  fprintf(stderr, "          b = Seek backward to find skipped tags\n");
+  fprintf(stderr, "          d = Resync after vnode data\n");
+  fprintf(stderr, "          v = Resync after corrupted vnodes\n");
+  fprintf(stderr, "  -h     Print this help message\n");
+  fprintf(stderr, "  -gxxx  Generate a new dump in file xxx\n");
+  fprintf(stderr, "  -q     Quiet mode (don't print errors)\n");
+  fprintf(stderr, "  -v     Verbose mode\n");
+  exit(status);
+}
+
+
+/* Parse the argument given to the -P option.
+ * Returns the resulting * dumpscan print flags (DSPRINT_*).
+ * If an unrecognized flag is used, prints an error message and exits.
+ */
+static afs_uint32 parse_printflags(char *flags)
+{
+  afs_uint32 result = 0;
+  char *x;
+
+  for (x = flags; *x; x++) switch (*x) {
+    case 'B': result |= DSPRINT_BCKHDR;  continue;
+    case 'H': result |= DSPRINT_DUMPHDR; continue;
+    case 'V': result |= DSPRINT_VOLHDR;  continue;
+    case 'v': result |= DSPRINT_ITEM;    continue;
+    case 'p': result |= DSPRINT_PATH;    continue;
+    case 'i': result |= DSPRINT_VNODE;   continue;
+    case 'd': result |= DSPRINT_DIR;     continue;
+    case 'a': result |= DSPRINT_ACL;     continue;
+    case 'g': result |= DSPRINT_DEBUG;   continue;
+    default:  usage(1, "Invalid print options!");
+  }
+  return result;
+}
+
+
+/* Parse the argument given to the -R option.
+ * Returns the resulting * dumpscan repair flags (DSFIX_*).
+ * If an unrecognized flag is used, prints an error message and exits.
+ */
+static afs_uint32 parse_repairflags(char *flags)
+{
+  afs_uint32 result = 0;
+  char *x;
+
+  for (x = flags; *x; x++) switch (*x) {
+    case '0': result |= DSFIX_SKIP;   continue;
+    case 'b': result |= DSFIX_RSKIP;  continue;
+    case 'd': result |= DSFIX_VDSYNC; continue;
+    case 'v': result |= DSFIX_VFSYNC; continue;
+    default:  usage(1, "Invalid repair options!");
+  }
+  return result;
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+  int c;
+
+  /* Set the program name */
+  if (argv0 = strrchr(argv[0], '/')) argv0++;
+  else argv0 = argv[0];
+
+  /* Initialize options */
+  input_path = gendump_path = 0;
+  printflags = repairflags = 0;
+  quiet = verbose = 0;
+
+  /* Initialize other stuff */
+  error_count = 0;
+
+  /* Parse the options */
+  while ((c = getopt(argc, argv, "P:R:g:hqv")) != EOF) {
+    switch (c) {
+      case 'P': printflags   = parse_printflags(optarg);  continue;
+      case 'R': repairflags  = parse_repairflags(optarg); continue;
+      case 'g': gendump_path = optarg;                    continue;
+      case 'q': quiet        = 1;                         continue;
+      case 'v': verbose      = 1;                         continue;
+      case 'h': usage(0, 0);
+      default:  usage(1, "Invalid option!");
+    }
+  }
+
+  if (quiet && verbose) usage(1, "Can't specify both -q and -v");
+
+  /* Parse non-option arguments */
+  if (argc - optind > 1) usage(1, "Too many arguments!");
+  input_path = (argc == optind) ? "-" : argv[optind];
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+  va_list alist;
+
+  error_count++;
+  if (!quiet) {
+    va_start(alist, msg);
+    com_err_va(argv0, code, msg, alist);
+    va_end(alist);
+  }
+}
+
+
+/* A callback to print the path of a vnode. */
+static afs_uint32 print_vnode_path(afs_vnode *v, XFILE *X, void *refcon)
+{
+  afs_uint32 r;
+  char *name = 0;
+
+  /* Do repair, but only for known vnode types */
+  if (gendump_path
+  &&  (!(v->field_mask & F_VNODE_TYPE)
+       || v->type != vFile
+       || v->type != vDirectory
+       || v->type != vSymlink)) {
+    r = repair_vnode_cb(v, X, refcon);
+    if (r) return r;
+  }
+  r = Path_Build(X, &phi, v->vnode, &name, 0);
+  if (!r && name) printf(" Path: %s\n", name);
+  if (name) free(name);
+  return r;
+}
+
+
+/* Setup for generating a repaired dump */
+static afs_uint32 setup_repair(void)
+{
+  afs_uint32 r;
+
+  r = xfopen(&repair_output, O_RDWR|O_CREAT|O_TRUNC, gendump_path);
+  if (r) return r;
+
+  dp.cb_dumphdr     = repair_dumphdr_cb;
+  dp.cb_volhdr      = repair_volhdr_cb;
+  dp.cb_vnode_dir   = repair_vnode_cb;
+  dp.cb_vnode_file  = repair_vnode_cb;
+  dp.cb_vnode_link  = repair_vnode_cb;
+  dp.cb_vnode_empty = repair_vnode_cb;
+  return 0;
+}
+
+
+/* Main program */
+void main(int argc, char **argv)
+{
+  XFILE input_file;
+  afs_uint32 r;
+
+  parse_options(argc, argv);
+  initialize_acfg_error_table();
+  initialize_AVds_error_table();
+  initialize_rxk_error_table();
+  initialize_u_error_table();
+  initialize_vl_error_table();
+  initialize_vols_error_table();
+  initialize_xFil_error_table();
+  r = xfopen(&input_file, O_RDONLY, input_path);
+  if (r) {
+    com_err(argv0, r, "opening %s", input_path);
+    exit(2);
+  }
+
+  memset(&dp, 0, sizeof(dp));
+  dp.cb_error     = my_error_cb;
+  dp.repair_flags = repairflags;
+  if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
+  else {
+    if (repairflags)
+      fprintf(stderr, "Repair modes available only for seekable dumps\n");
+    if (printflags & DSPRINT_PATH)
+      fprintf(stderr, "Path-printing available only for seekable dumps\n");
+    if (repairflags || (printflags & DSPRINT_PATH))
+      exit(1);
+  }
+
+  if (gendump_path && (r = setup_repair())) {
+    com_err(argv0, r, "setting up repair output");
+    xfclose(&input_file);
+    exit(2);
+  }
+
+  if (printflags & DSPRINT_PATH) {
+    u_int64 where;
+
+    dp.print_flags = printflags & DSPRINT_DEBUG;
+    memset(&phi, 0, sizeof(phi));
+    phi.p = &dp;
+
+    if ((r = xftell(&input_file, &where))
+    ||  (r = Path_PreScan(&input_file, &phi, 0))
+    ||  (r = xfseek(&input_file, &where))) {
+      com_err(argv0, r, "- path initialization failed");
+      xfclose(&input_file);
+      exit(2);
+    }
+
+    dp.cb_vnode_dir   = print_vnode_path;
+    dp.cb_vnode_file  = print_vnode_path;
+    dp.cb_vnode_link  = print_vnode_path;
+    dp.cb_vnode_empty = print_vnode_path;
+    dp.cb_vnode_wierd = print_vnode_path;
+  }
+
+  dp.print_flags  = printflags;
+  r = ParseDumpFile(&input_file, &dp);
+  xfclose(&input_file);
+  if (gendump_path) {
+    if (!r) r = DumpDumpEnd(&repair_output);
+    if (!r) r = xfclose(&repair_output);
+    else xfclose(&repair_output);
+  }
+
+  if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
+  if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
+  exit(0);
+}
diff --git a/src/tests/afsdump_xsed.c b/src/tests/afsdump_xsed.c
new file mode 100644 (file)
index 0000000..f4f9e0f
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * COPYRIGHT NOTICE
+ * Copyright (c) 1997 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.
+ */
+
+/* UB - Unified Backups */
+/* methods/afs/dumpscan/afsdump_scan.c - General-purpose dump scanner */
+
+#include "dumpscan.h"
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+extern int opterr, optind;
+extern char *optarg;
+
+extern XFILE repair_output;
+extern afs_uint32 repair_dumphdr_cb(afs_dump_header *, XFILE *, void *);
+extern afs_uint32 repair_volhdr_cb(afs_vol_header *, XFILE *, void *);
+extern afs_uint32 repair_vnode_cb(afs_vnode *, XFILE *, void *);
+
+char *argv0;
+static char *input_path, *gendump_path;
+static afs_uint32 printflags, repairflags, add_admin;
+static int quiet, verbose, error_count;
+
+static path_hashinfo phi;
+static dump_parser dp;
+
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+  if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+  fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
+  fprintf(stderr, "  -Pxxx  Set print options:\n");
+  fprintf(stderr, "          B = Print backup system header (if any)\n");
+  fprintf(stderr, "          H = Print AFS dump header\n");
+  fprintf(stderr, "          V = Print AFS volume header\n");
+  fprintf(stderr, "          v = List vnodes\n");
+  fprintf(stderr, "          p = Include path to each vnode\n");
+  fprintf(stderr, "          i = Include info for each vnode\n");
+  fprintf(stderr, "          d = List directory contents\n");
+  fprintf(stderr, "          a = List access control lists\n");
+  fprintf(stderr, "          g = Print debugging info\n");
+  fprintf(stderr, "  -Rxxx  Set repair options:\n");
+  fprintf(stderr, "          0 = Skip null tags\n");
+  fprintf(stderr, "          b = Seek backward to find skipped tags\n");
+  fprintf(stderr, "          d = Resync after vnode data\n");
+  fprintf(stderr, "          v = Resync after corrupted vnodes\n");
+  fprintf(stderr, "  -Annn  Add all rights for ID nnn to every directory\n");
+  fprintf(stderr, "  -h     Print this help message\n");
+  fprintf(stderr, "  -gxxx  Generate a new dump in file xxx\n");
+  fprintf(stderr, "  -q     Quiet mode (don't print errors)\n");
+  fprintf(stderr, "  -v     Verbose mode\n");
+  exit(status);
+}
+
+
+/* Parse the argument given to the -P option.
+ * Returns the resulting * dumpscan print flags (DSPRINT_*).
+ * If an unrecognized flag is used, prints an error message and exits.
+ */
+static afs_uint32 parse_printflags(char *flags)
+{
+  afs_uint32 result = 0;
+  char *x;
+
+  for (x = flags; *x; x++) switch (*x) {
+    case 'B': result |= DSPRINT_BCKHDR;  continue;
+    case 'H': result |= DSPRINT_DUMPHDR; continue;
+    case 'V': result |= DSPRINT_VOLHDR;  continue;
+    case 'v': result |= DSPRINT_ITEM;    continue;
+    case 'p': result |= DSPRINT_PATH;    continue;
+    case 'i': result |= DSPRINT_VNODE;   continue;
+    case 'd': result |= DSPRINT_DIR;     continue;
+    case 'a': result |= DSPRINT_ACL;     continue;
+    case 'g': result |= DSPRINT_DEBUG;   continue;
+    default:  usage(1, "Invalid print options!");
+  }
+  return result;
+}
+
+
+/* Parse the argument given to the -R option.
+ * Returns the resulting * dumpscan repair flags (DSFIX_*).
+ * If an unrecognized flag is used, prints an error message and exits.
+ */
+static afs_uint32 parse_repairflags(char *flags)
+{
+  afs_uint32 result = 0;
+  char *x;
+
+  for (x = flags; *x; x++) switch (*x) {
+    case '0': result |= DSFIX_SKIP;    continue;
+    case 'b': result |= DSFIX_RSKIP;   continue;
+    case 'd': result |= DSFIX_VDSYNC;  continue;
+    case 'v': result |= DSFIX_VFSYNC;  continue;
+    default:  usage(1, "Invalid repair options!");
+  }
+  return result;
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+  int c;
+
+  /* Set the program name */
+  if (argv0 = strrchr(argv[0], '/')) argv0++;
+  else argv0 = argv[0];
+
+  /* Initialize options */
+  input_path = gendump_path = 0;
+  printflags = repairflags = add_admin = 0;
+  quiet = verbose = 0;
+
+  /* Initialize other stuff */
+  error_count = 0;
+
+  /* Parse the options */
+  while ((c = getopt(argc, argv, "A:P:R:g:hv")) != EOF) {
+    switch (c) {
+      case 'A': add_admin    = atoi(optarg);              continue;
+      case 'P': printflags   = parse_printflags(optarg);  continue;
+      case 'R': repairflags  = parse_repairflags(optarg); continue;
+      case 'g': gendump_path = optarg;                    continue;
+      case 'q': quiet        = 1;                         continue;
+      case 'v': verbose      = 1;                         continue;
+      case 'h': usage(0, 0);
+      default:  usage(1, "Invalid option!");
+    }
+  }
+
+  if (quiet && verbose) usage(1, "Can't specify both -q and -v");
+
+  /* Parse non-option arguments */
+  if (argc - optind > 1) usage(1, "Too many arguments!");
+  input_path = (argc == optind) ? "-" : argv[optind];
+  if (add_admin && !gendump_path) add_admin = 0;
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+  va_list alist;
+
+  error_count++;
+  if (!quiet) {
+    va_start(alist, msg);
+    com_err_va(argv0, code, msg, alist);
+    va_end(alist);
+  }
+}
+
+
+/* A callback to print the path of a vnode. */
+static afs_uint32 print_vnode_path(afs_vnode *v, XFILE *X, void *refcon)
+{
+  afs_uint32 r;
+  char *name = 0;
+
+  /* Do repair, but only for known vnode types */
+  if (gendump_path
+  &&  (!(v->field_mask & F_VNODE_TYPE)
+       || v->type != vFile
+       || v->type != vDirectory
+       || v->type != vSymlink)) {
+    r = repair_vnode_cb(v, X, refcon);
+    if (r) return r;
+  }
+  r = Path_Build(X, &phi, v->vnode, &name, 0);
+  if (!r && name) printf(" Path: %s\n", name);
+  if (name) free(name);
+  return r;
+}
+
+
+static afs_uint32 munge_admin_acl(afs_vnode *v, XFILE *X, void *refcon)
+{
+  struct acl_accessList *acl;
+  int add_entry = 1, remove_entry = -1;
+  int i, o, n;
+
+  acl = (struct acl_accessList *)(v->acl);
+  o = n = ntohl(acl->positive);
+  for (i = 0; i < n; i++)
+    if (ntohl(acl->entries[i].id) == add_admin) add_entry = 0;
+  n = ntohl(acl->negative);
+  for (i = o; i < n + o; i++)
+    if (ntohl(acl->entries[i].id) == add_admin) remove_entry = i;
+
+  if (add_entry) {
+    for (i = (remove_entry < 0) ? o + n : remove_entry; i > o; i--) {
+      acl->entries[i].id     = acl->entries[i-1].id;
+      acl->entries[i].rights = acl->entries[i-1].rights;
+    }
+    acl->entries[o].id = htonl(add_admin);
+    acl->entries[o].rights = htonl((PRSFS_READ   | PRSFS_LOOKUP
+                                  | PRSFS_INSERT | PRSFS_DELETE
+                                  | PRSFS_WRITE  | PRSFS_LOCK
+                                  | PRSFS_ADMINISTER));
+    acl->positive = htonl(o + 1);
+    if (remove_entry < 0) acl->total = htonl(o + n + 1);
+    else acl->negative = htonl(n - 1);
+  } else if (remove_entry >= 0) {
+    for (i = remove_entry; i < o + n - 1; i++) {
+      acl->entries[i].id     = acl->entries[i+1].id;
+      acl->entries[i].rights = acl->entries[i+1].rights;
+    }
+    acl->negative = htonl(n - 1);
+    acl->total    = htonl(o + n - 1);
+  }
+  return repair_vnode_cb(v, X, refcon);
+}
+
+
+/* Setup for generating a repaired dump */
+static afs_uint32 setup_repair(void)
+{
+  afs_uint32 r;
+
+  r = xfopen(&repair_output, gendump_path, O_RDWR, 0644);
+  if (r) return r;
+
+  dp.cb_dumphdr     = repair_dumphdr_cb;
+  dp.cb_volhdr      = repair_volhdr_cb;
+  dp.cb_vnode_dir   = repair_vnode_cb;
+  dp.cb_vnode_file  = repair_vnode_cb;
+  dp.cb_vnode_link  = repair_vnode_cb;
+  dp.cb_vnode_empty = repair_vnode_cb;
+  return 0;
+}
+
+
+/* Main program */
+void main(int argc, char **argv)
+{
+  XFILE *X;
+  afs_uint32 r;
+
+  parse_options(argc, argv);
+  initialize_UB_error_table();
+  initialize_UBsp_error_table();
+  initialize_AVds_error_table();
+  r = xfopen(&X, input_path, O_RDONLY, 0);
+  if (r) {
+    com_err(argv0, r, "opening %s", input_path);
+    exit(2);
+  }
+
+  bzero(&dp, sizeof(dp));
+  dp.cb_error     = my_error_cb;
+  dp.repair_flags = repairflags;
+  if (X->is_seekable) dp.flags |= DSFLAG_SEEK;
+  else {
+    if (repairflags)
+      fprintf(stderr, "Repair modes available only for seekable dumps\n");
+    if (printflags & DSPRINT_PATH)
+      fprintf(stderr, "Path-printing available only for seekable dumps\n");
+    if (repairflags || (printflags & DSPRINT_PATH))
+      exit(1);
+  }
+
+  if (gendump_path && (r = setup_repair())) {
+    com_err(argv0, r, "setting up repair output");
+    xfclose(X);
+    exit(2);
+  }
+
+  if (printflags & DSPRINT_PATH) {
+    u_int64 where;
+
+    dp.print_flags = printflags & DSPRINT_DEBUG;
+    bzero(&phi, sizeof(phi));
+    phi.p = &dp;
+
+    if ((r = xftell(X, &where))
+    ||  (r = Path_PreScan(X, &phi, 0))
+    ||  (r = xfseek(X, &where))) {
+      com_err(argv0, r, "- path initialization failed");
+      xfclose(X);
+      exit(2);
+    }
+
+    dp.cb_vnode_dir   = print_vnode_path;
+    dp.cb_vnode_file  = print_vnode_path;
+    dp.cb_vnode_link  = print_vnode_path;
+    dp.cb_vnode_empty = print_vnode_path;
+    dp.cb_vnode_wierd = print_vnode_path;
+  }
+
+  if (add_admin) {
+    dp.cb_vnode_dir = munge_admin_acl;
+  }
+
+  dp.print_flags  = printflags;
+  r = ParseDumpFile(X, &dp);
+  if (gendump_path) {
+    if (!r) r = DumpDumpEnd(&repair_output);
+    if (!r) r = xfclose(&repair_output);
+    else xfclose(&repair_output);
+  }
+
+  if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
+  if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
+  exit(0);
+}
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..de50ce9
--- /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: apwd.c,v 1.1 2002/01/22 19:54:39 hartmans Exp $");
+
+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..578adf2
--- /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: asu.c,v 1.1 2002/01/22 19:54:39 hartmans Exp $");
+#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/backuphdr.c b/src/tests/backuphdr.c
new file mode 100644 (file)
index 0000000..88c9759
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* backuphdr.c - Parse and print backup system headers */
+
+#include <stdlib.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "stagehdr.h"
+
+afs_uint32 try_backuphdr(XFILE *X, char *tag, tagged_field *field,
+                      afs_uint32 value, tag_parse_info *pi,
+                      void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  backup_system_header bh;
+  u_int64 where;
+  afs_uint32 r;
+
+  /* Which header should we try (if any)? */
+  switch (*tag) {
+    case STAGE_VERSMIN: r = ParseStageHdr(X, tag, &bh); break;
+    default: return DSERR_MAGIC;
+  }
+  if (r) return r;
+
+  /* Do something with it... */
+  if (p->print_flags & DSPRINT_BCKHDR) PrintBackupHdr(&bh);
+  if (p->cb_bckhdr) {
+    r = xftell(X, &where);
+    if (!r && p->cb_bckhdr)
+      r = (p->cb_bckhdr)(&bh, X, p->refcon);
+    if (p->flags & DSFLAG_SEEK) {
+      if (!r) r = xfseek(X, &where);
+      else xfseek(X, &where);
+    }
+  }
+  if (bh.server)  free(bh.server);
+  if (bh.part)    free(bh.part);
+  if (bh.volname) free(bh.volname);
+  return r;
+}
+
+
+void PrintBackupHdr(backup_system_header *hdr)
+{
+  time_t from = hdr->from_date, to = hdr->to_date, dd = hdr->dump_date;
+
+  printf("* BACKUP SYSTEM HEADER\n");
+  printf(" Version:    %d\n", hdr->version);
+  printf(" Volume:     %s (%d)\n", hdr->volname, hdr->volid);
+  printf(" Location:   %s %s\n", hdr->server, hdr->part);
+  printf(" Level:      %d\n", hdr->level);
+  printf(" Range:      %d => %d\n", hdr->from_date, hdr->to_date);
+  printf("          == %s", ctime(&from));
+  printf("          => %s", ctime(&to));
+  printf(" Dump Time:  %d == %s", hdr->dump_date, ctime(&dd));
+  printf(" Dump Flags: 0x%08x\n", hdr->flags);
+  printf(" Length:     %d\n", hdr->dumplen);
+  printf(" File Num:   %d\n", hdr->filenum);
+}
diff --git a/src/tests/baduniq.pl b/src/tests/baduniq.pl
new file mode 100755 (executable)
index 0000000..3477593
--- /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, $ret);
+$host = `hostname`;
+&AFS_Init();
+
+&AFS_vos_restore("badvol","localhost","a","/usr/tmp/t.uniq-bad","100","full",);
+&AFS_bos_salvage("localhost","a","badvol",,,,,,);
+&AFS_fs_mkmount("badvol", "badvol",,,);
+if ( -f "badvol/test" ) {
+ &AFS_fs_rmmount("badvol");
+ exit(0);
+}
+&AFS_fs_rmmount("badvol");
+exit(1);
+
+
+
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..3dc09f8
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $Id: boot-strap-arla,v 1.1 2002/01/22 19:54:39 hartmans Exp $
+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/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..5b30ff1
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+set -x
+# $Id: build-and-run-rcs,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+##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..8e1f853
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: build-emacs,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..a4f9f00
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: build-emacs-j,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..e1c0910
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: build-gdb,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..5dfc854
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $Id: build-openafs,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+FS=${FS:-${objdir}/../appl/fs/fs}
+
+${FS} sq . 0
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+test -f /usr/tmp/openafs-1.2.2-src.tar.gz && cp /usr/tmp/openafs-1.2.2-src.tar.gz openafs-1.2.2-src.tar.gz
+test -f openafs-1.2.2-src.tar.gz || wget http://www.openafs.org/dl/1.2.2/openafs-1.2.2-src.tar.gz 2>&4
+$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..6d067cb
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+# $Id: checkpwd,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+$objdir/apwd
diff --git a/src/tests/compare-inum-mp b/src/tests/compare-inum-mp
new file mode 100755 (executable)
index 0000000..fa745cc
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+# $Id: compare-inum-mp,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..a0cf4fe
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: compare-inums,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+$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..638863b
--- /dev/null
@@ -0,0 +1,77 @@
+#!/bin/sh
+# $Id: compare-with-local,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+#################################################################
+#
+# 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/copy-and-diff-gnu-mirror b/src/tests/copy-and-diff-gnu-mirror
new file mode 100755 (executable)
index 0000000..947ef4e
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# $Id: copy-and-diff-gnu-mirror,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..07366f8
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/sh
+# $Id: copy-file,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..25577ad
--- /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: create-dirs.c,v 1.1 2002/01/22 19:54:40 hartmans Exp $");
+#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..868312f
--- /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: create-files.c,v 1.1 2002/01/22 19:54:40 hartmans Exp $");
+#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..d02aa18
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: create-remove-dirs,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..6f62526
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: create-remove-files,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..316d18d
--- /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: create-remove.c,v 1.1 2002/01/22 19:54:40 hartmans Exp $");
+#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..a5f64f0
--- /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: create-stat.c,v 1.1 2002/01/22 19:54:40 hartmans Exp $");
+#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..f38bc6f
--- /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: create-symlinks.c,v 1.1 2002/01/22 19:54:40 hartmans Exp $");
+#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..5606dda
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+# $Id: dd,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..a17c9b9
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id: deep-tree,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..99829d6
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $Id: deep-tree2,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+
+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..70b54fc
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $Id: dir-size-mismatch,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+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..bfd4473
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $Id: dir-tree,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+
+#######################################################
+#
+# 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/directory.c b/src/tests/directory.c
new file mode 100644 (file)
index 0000000..f270723
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* directory.c - Parse an AFS directory */
+/* See the end of this file for a description of the directory format */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "xf_errs.h"
+#include "dumpfmt.h"
+#include "internal.h"
+
+#include <afs/dir.h>
+
+static afs_dir_page page;
+
+#define allocbit(x) (page.header.freebitmap[(x)>>3] & (1 << ((x) & 7)))
+#define DPHE (DHE + 1)
+
+static void fixup(char *name, int l)
+{
+  name += 16;
+  l -= 15;
+
+  while (l-- > 0) {
+    name[0] = name[4];
+    name++;
+  }
+}
+
+afs_uint32 parse_directory(XFILE *X, dump_parser *p, afs_vnode *v,
+                        afs_uint32 size, int toeof)
+{
+  afs_dir_entry de;
+  int pgno, i, j, l, n;
+  afs_uint32 r;
+  u_int64 where;
+
+  if (p->print_flags & DSPRINT_DIR) {
+    printf("  VNode      Uniqifier   Name\n");
+    printf("  ========== ==========  ==============================\n");
+  }
+  if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r;
+  for (pgno = 0; toeof || size; pgno++, size -= (toeof ? 0 : AFS_PAGESIZE)) {
+    if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r;
+    if (r = xfread(X, &page, AFS_PAGESIZE)) {
+      if (toeof && r == ERROR_XFILE_EOF) break;
+      return r;
+    }
+    if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r;
+    if (page.header.tag != htons(1234)) {
+      if (p->cb_error)
+        (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
+                      "Invalid page tag (%d) in page %d",
+                      ntohs(page.header.tag), pgno);
+      return DSERR_MAGIC;
+    }
+    for (i = (pgno ? 1 : DPHE); i < EPP; i++) {
+      if (!allocbit(i)) continue;
+      if (page.entry[i].flag != FFIRST) {
+        if (p->cb_error)
+          (p->cb_error)(DSERR_MAGIC, 0, p->err_refcon,
+                        "Invalid entry flag %d in entry %d/%d; skipping...",
+                        page.entry[i].flag, pgno, i);
+        continue;
+      }
+      n = (EPP - i - 1) * 32 + 16;
+      for (l = 0; n && page.entry[i].name[l]; l++, n--);
+      if (page.entry[i].name[l]) {
+        if (p->cb_error)
+          (p->cb_error)(DSERR_FMT, 0, p->err_refcon,
+                        "Filename too long in entry %d/%d; skipping page",
+                        pgno, i);
+        break;
+      }
+/*    fixup(page.entry[i].name, l); */
+      if (pgno) de.slot = i - 1 + (pgno - 1) * (EPP - 1) + (EPP - DPHE);
+      else de.slot = i - DPHE;
+      de.name  = page.entry[i].name;
+      de.vnode = ntohl(page.entry[i].vnode);
+      de.uniq  = ntohl(page.entry[i].vunique);
+      if (p->print_flags & DSPRINT_DIR)
+        printf("  %10d %10d  %s\n", de.vnode, de.uniq, de.name);
+      if (p->cb_dirent) {
+        r = (p->cb_dirent)(v, &de, X, p->refcon);
+      }
+      if (p->cb_dirent && (r = (p->cb_dirent)(v, &de, X, p->refcon)))
+        return r;
+      i += ((l + 16) >> 5);
+    }
+  }
+  if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r;
+  return 0;
+}
+
+
+afs_uint32 ParseDirectory(XFILE *X, dump_parser *p, afs_uint32 size, int toeof)
+{
+  afs_uint32 r;
+
+  r = parse_directory(X, p, 0, size, toeof);
+}
+
+
+typedef struct {
+  char **name;
+  afs_uint32 *vnode;
+  afs_uint32 *vuniq;
+} dirlookup_stat;
+
+
+static afs_uint32 dirlookup_cb(afs_vnode *v, afs_dir_entry *de,
+                            XFILE *X, void *refcon)
+{
+  dirlookup_stat *s = (dirlookup_stat *)refcon;
+
+  if (s->name && s->name[0]) {                  /* Search by filename */
+    if (strcmp(de->name, s->name[0])) return 0; /* Not it! */
+    if (s->vnode) s->vnode[0] = de->vnode;
+    if (s->vuniq) s->vuniq[0] = de->uniq;
+  } else if (s->vnode) {                        /* Search by vnode */
+    if (de->vnode != s->vnode[0]) return 0;     /* Not it! */
+    if (s->name) {
+      s->name[0] = (char *)malloc(strlen(de->name) + 1);
+      if (!s->name[0]) return ENOMEM;
+      strcpy(s->name[0], de->name);
+    }
+    if (s->vuniq) s->vuniq[0] = de->uniq;
+  }
+  return DSERR_DONE;
+}
+
+
+/* Look up an entry in a directory, by name or vnode.
+ * If *name is NULL, we are looking up by vnode.
+ * Otherwise, we are looking for a filename.
+ * In any event, any of name, vnode, vuniq that are
+ * neither NULL nor the search key are filled in on
+ * success.
+ *
+ * Call this with X pointing to the start of the directory,
+ * and size set to the length of the directory.
+ * Returns 0 on success, whether or not the entry is found.
+ */
+afs_uint32 DirectoryLookup(XFILE *X, dump_parser *p, afs_uint32 size,
+                    char **name, afs_uint32 *vnode, afs_uint32 *vuniq)
+{
+  dump_parser my_p;
+  dirlookup_stat my_s;
+  afs_uint32 r;
+
+  memset(&my_s, 0, sizeof(my_s));
+  my_s.name  = name;
+  my_s.vnode = vnode;
+  my_s.vuniq = vuniq;
+
+  memset(&my_p, 0, sizeof(my_p));
+  my_p.refcon = (void *)&my_s;
+  my_p.err_refcon = p->err_refcon;
+  my_p.cb_error = p->cb_error;
+  my_p.cb_dirent  = dirlookup_cb;
+
+  r = parse_directory(X, &my_p, 0, size, 0);
+  if (!r) r = DSERR_DONE;
+  return handle_return(r, X, 0, p);
+}
+
+
+/* AFS directory format:
+ * AFS directories are stored in volume dumps in exactly the same format
+ * that is used on disk, which makes them relatively easy to dump and restore,
+ * but means we have to do some work to interpret them.
+ *
+ * The ACL for a directory is stored on disk in the last part of a "large"
+ * (directory) vnode.  This part of the vnode, which has fixed size
+ * SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE, is copied directly into
+ * the dump file with a tag of 'A' (VTAG_ACL).  The structure of this
+ * section is described in <afs/acl.h>.
+ *
+ * The name-to-vnode mappings are also stored exactly as they appear on
+ * disk, using the file data ('f') attribute.  As usual, this attribute
+ * consists of a 32-bit number containing the size, immediately followed
+ * by the data itself.  The interesting structures and constants are
+ * defined in <afs/dir.h>
+ * 
+ * A directory consists of one or more 'pages', each of which is 2K
+ * (AFS_PAGESIZE).  Each page contains EPP (currently 64) 'entries', each
+ * of which is 32 bytes.  The first page begins with a DirHeader, which
+ * is DHE entries long, and includes a PageHeader.  All other pages begin
+ * with just a PageHeader, which is 1 entry long.  Every other entry is
+ * a DirEntry, a DirXEntry (name extension), or unused.
+ *
+ * A Page Header contains the following elements:
+ * - pgcount    contains a count of the number of pages in the directory,
+ *              if the directory is new-style (>128 pages), or 0 if it is
+ *              old-style.  This field is meaningful only in the Dir Header.
+ * - tag        a magic number, which must be 1234
+ * - freecount  apparently unused
+ * - freebitmap A bitmap of free entries.  Each byte corresponds to 8
+ *              entries, with the least significant bit referring to the
+ *              first of those.  Each bit is set iff the corresponding
+ *              entry is allocated.  Entries used by the page and dir
+ *              headers are considered allocated.
+ *
+ * A Dir Header consists of a Page Header, followed by an allocation map
+ * and hash table.  The allocation map contains one byte for each of the
+ * first 128 pages; that byte contains the number of entries in that page
+ * that are allocated.  Every page that actually exists has at peast one
+ * entry allocated (the Page Header); if a byte in this map is 0, it means
+ * that the page does not yet exist.
+ *
+ * Each bucket in the hash table is a linked list, using 'blob numbers'
+ * as pointers.  A blob number is defined as (page# * EPP) + entry#.
+ * The head of each chain is kept in the hash table, and the next pointers
+ * are kept in the 'next' entry of each directory.
+ *
+ * Directory entries themselves contain the following elements:
+ * - flag    Set to FFIRST iff this is the first blob in an entry
+ *           (otherwise it will be a name continuation).  This is
+ *           probably not reliable.
+ * - length  Unused
+ * - next    Pointer to the next element in this hash chain
+ * - fid     FileID (vnode and uniquifier)
+ * - name    Filename (null-terminated)
+ */
diff --git a/src/tests/dump.c b/src/tests/dump.c
new file mode 100644 (file)
index 0000000..8d228fd
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* dump.c - Write out parts of a volume dump */
+
+#include "dumpscan.h"
+#include "dumpfmt.h"
+
+#define COPYBUFSIZE 65536
+
+afs_uint32 DumpDumpHeader(XFILE *OX, afs_dump_header *hdr)
+{
+  afs_uint32 r;
+
+  if (r = WriteTagInt32Pair(OX, TAG_DUMPHEADER, hdr->magic, hdr->version))
+    return r;
+
+  if (hdr->field_mask & F_DUMPHDR_VOLID) {
+    if (r = WriteTagInt32(OX, DHTAG_VOLID, hdr->volid)) return r;
+  }
+  if (hdr->field_mask & F_DUMPHDR_VOLNAME) {
+    if (r = WriteByte(OX, DHTAG_VOLNAME)) return r;
+    if (r = WriteString(OX, hdr->volname)) return r;
+  }
+  if (hdr->field_mask & (F_DUMPHDR_FROM | F_DUMPHDR_TO)) {
+    if (r = WriteTagInt16(OX, DHTAG_DUMPTIMES, 2))
+      return r;
+    if (r = WriteInt32(OX, (hdr->field_mask & F_DUMPHDR_FROM)
+                       ? hdr->from_date : 0))
+      return r;
+    if (r = WriteInt32(OX, (hdr->field_mask & F_DUMPHDR_TO)
+                       ? hdr->to_date : time(0)))
+      return r;
+  }
+  return 0;
+}
+
+
+afs_uint32 DumpVolumeHeader(XFILE *OX, afs_vol_header *hdr)
+{
+  afs_uint32 r;
+  int i;
+
+  if (r = WriteByte(OX, TAG_VOLHEADER)) return r;
+
+  if (hdr->field_mask & F_VOLHDR_VOLID) {
+    if (r = WriteTagInt32(OX, VHTAG_VOLID, hdr->volid)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_VOLVERS) {
+    if (r = WriteTagInt32(OX, VHTAG_VERS, hdr->volvers)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_VOLNAME) {
+    if (r = WriteByte(OX, VHTAG_VOLNAME)) return r;
+    if (r = WriteString(OX, hdr->volname)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_INSERV) {
+    if (r = WriteTagByte(OX, VHTAG_INSERV, hdr->flag_inservice)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_BLESSED) {
+    if (r = WriteTagByte(OX, VHTAG_BLESSED, hdr->flag_blessed)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_VOLUNIQ) {
+    if (r = WriteTagInt32(OX, VHTAG_VUNIQ, hdr->voluniq)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_VOLTYPE) {
+    if (r = WriteTagByte(OX, VHTAG_TYPE, hdr->voltype)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_PARENT) {
+    if (r = WriteTagInt32(OX, VHTAG_PARENT, hdr->parent_volid)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_CLONE) {
+    if (r = WriteTagInt32(OX, VHTAG_CLONE, hdr->clone_volid)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_MAXQ) {
+    if (r = WriteTagInt32(OX, VHTAG_MAXQUOTA, hdr->maxquota)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_MINQ) {
+    if (r = WriteTagInt32(OX, VHTAG_MINQUOTA, hdr->minquota)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_DISKUSED) {
+    if (r = WriteTagInt32(OX, VHTAG_DISKUSED, hdr->diskused)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_NFILES) {
+    if (r = WriteTagInt32(OX, VHTAG_FILECNT, hdr->nfiles)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_ACCOUNT) {
+    if (r = WriteTagInt32(OX, VHTAG_ACCOUNT, hdr->account_no)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_OWNER) {
+    if (r = WriteTagInt32(OX, VHTAG_OWNER, hdr->owner)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_CREATE_DATE) {
+    if (r = WriteTagInt32(OX, VHTAG_CREAT, hdr->create_date)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_ACCESS_DATE) {
+    if (r = WriteTagInt32(OX, VHTAG_ACCESS, hdr->access_date)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_UPDATE_DATE) {
+    if (r = WriteTagInt32(OX, VHTAG_UPDATE, hdr->update_date)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_EXPIRE_DATE) {
+    if (r = WriteTagInt32(OX, VHTAG_EXPIRE, hdr->expire_date)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_BACKUP_DATE) {
+    if (r = WriteTagInt32(OX, VHTAG_BACKUP, hdr->backup_date)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_OFFLINE_MSG) {
+    if (r = WriteTagInt32(OX, VHTAG_OFFLINE, hdr->offline_msg)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_MOTD) {
+    if (r = WriteTagInt32(OX, VHTAG_MOTD, hdr->motd_msg)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_WEEKUSE) {
+    if (r = WriteTagInt16(OX, VHTAG_WEEKUSE, 7)) return r;
+    for (i = 0; i < 7; i++)
+      if (r = WriteInt32(OX, hdr->weekuse[i])) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_DAYUSE_DATE) {
+    if (r = WriteTagInt32(OX, VHTAG_DUDATE, hdr->dayuse_date)) return r;
+  }
+  if (hdr->field_mask & F_VOLHDR_DAYUSE) {
+    if (r = WriteTagInt32(OX, VHTAG_DAYUSE, hdr->dayuse)) return r;
+  }
+  return 0;
+}
+
+
+afs_uint32 DumpVNode(XFILE *OX, afs_vnode *v)
+{
+  afs_uint32 r;
+
+  if (r = WriteTagInt32Pair(OX, TAG_VNODE, v->vnode, v->vuniq)) return r;
+
+  if (v->field_mask & F_VNODE_TYPE) {
+    if (r = WriteTagByte(OX, VTAG_TYPE, v->type)) return r;
+  }
+  if (v->field_mask & F_VNODE_NLINKS) {
+    if (r = WriteTagInt16(OX, VTAG_NLINKS, v->nlinks)) return r;
+  }
+  if (v->field_mask & F_VNODE_DVERS) {
+    if (r = WriteTagInt32(OX, VTAG_DVERS, v->datavers)) return r;
+  }
+  if (v->field_mask & F_VNODE_SDATE) {
+    if (r = WriteTagInt32(OX, VTAG_SERVER_DATE, v->server_date)) return r;
+  }
+  if (v->field_mask & F_VNODE_AUTHOR) {
+    if (r = WriteTagInt32(OX, VTAG_AUTHOR, v->author)) return r;
+  }
+  if (v->field_mask & F_VNODE_OWNER) {
+    if (r = WriteTagInt32(OX, VTAG_OWNER, v->owner)) return r;
+  }
+  if (v->field_mask & F_VNODE_GROUP) {
+    if (r = WriteTagInt32(OX, VTAG_GROUP, v->group)) return r;
+  }
+  if (v->field_mask & F_VNODE_MODE) {
+    if (r = WriteTagInt16(OX, VTAG_MODE, v->mode)) return r;
+  }
+  if (v->field_mask & F_VNODE_PARENT) {
+    if (r = WriteTagInt32(OX, VTAG_PARENT, v->parent)) return r;
+  }
+  if (v->field_mask & F_VNODE_CDATE) {
+    if (r = WriteTagInt32(OX, VTAG_CLIENT_DATE, v->client_date)) return r;
+  }
+  if (v->field_mask & F_VNODE_ACL) {
+    if (r = WriteByte(OX, VTAG_ACL)) return r;
+    if (r = xfwrite(OX, v->acl, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE))
+      return r;
+  }
+  return 0;
+}
+
+
+afs_uint32 DumpVNodeData(XFILE *OX, char *buf, afs_uint32 size)
+{
+  afs_uint32 r;
+
+  if (r = WriteTagInt32(OX, VTAG_DATA, size)) return r;
+  if (r = xfwrite(OX, buf, size)) return r;
+  return 0;
+}
+
+
+afs_uint32 CopyVNodeData(XFILE *OX, XFILE *X, afs_uint32 size)
+{
+  afs_uint32 r, n;
+  static char buf[COPYBUFSIZE];
+
+  if (r = WriteTagInt32(OX, VTAG_DATA, size)) return r;
+  while (size) {
+    n = (size > COPYBUFSIZE) ? COPYBUFSIZE : size;
+    if (r = xfread(X, buf, n)) return r;
+    if (r = xfwrite(OX, buf, n)) return r;
+    size -= n;
+  }
+  return 0;
+}
+
+
+afs_uint32 DumpDumpEnd(XFILE *OX) {
+  afs_uint32 r;
+
+  if (r = WriteTagInt32(OX, TAG_DUMPEND, DUMPENDMAGIC)) return r;
+  return 0;
+}
diff --git a/src/tests/dumpfmt.h b/src/tests/dumpfmt.h
new file mode 100644 (file)
index 0000000..766b697
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* dumpfmt.h - Description of AFS dump format */
+
+#ifndef _DUMPFMT_H_
+#define _DUMPFMT_H_
+
+#include "intNN.h"
+
+/* AFS dump file format:
+ * All data in AFS dumps is tagged; that is, each data item is preceeded
+ * by a 1-byte tag which identifies what the data item is.  There is no
+ * explicit mention of what the data type is, but the type of each possible
+ * data item (and thus, each possible tag) is fixed.  Usually this is
+ * a relatively simple, fixed amount of data (byte, short, word), but
+ * sometimes it is more complex.
+ *
+ * There is some amount of structure to an AFS volume dump.  Basically,
+ * you get a dump header, followed by a volume header, followed by some
+ * vnodes, followed by a dump end.  Each of these items (header, vnode,
+ * dump end) consists of a tag, a fixed amount of required information,
+ * and 0 or more tagged attributes (except dump-end, which has no attributes).
+ *
+ * Vnodes, in turn, are usually listed in a particular order.  First, we
+ * list all the directory vnodes in the volume, in increasing order by
+ * vnode.  Then, we list all the file vnodes, again in increasing order.
+ * Directory vnodes must have a complete set of attributes and data, but
+ * in an incremental dump, file vnodes may have no attributes if the vnode
+ * has not changed since the reference date.
+ *
+ * The primary purpose of this file is to define the tags and some magic
+ * numbers.  There is also some information that is defined in the Transarc
+ * provided header files.
+ */
+
+
+/** MAGIC NUMBERS **/
+#define DUMPVERSION     1
+#define DUMPBEGINMAGIC  0xb3a11322
+#define DUMPENDMAGIC    0x3a214b6e
+
+
+/** TOP-LEVEL TAGS **/
+#define TAG_DUMPHEADER  1
+#define TAG_VOLHEADER   2
+#define TAG_VNODE       3
+#define TAG_DUMPEND     4
+
+
+/** DUMP HEADER TAGS **/
+#define DHTAG_VOLNAME    'n'
+#define DHTAG_VOLID      'v'
+#define DHTAG_DUMPTIMES  't'
+
+
+/** VOLUME HEADER TAGS **/
+#define VHTAG_VOLID      'i'
+#define VHTAG_VERS       'v'
+#define VHTAG_VOLNAME    'n'
+#define VHTAG_INSERV     's'
+#define VHTAG_BLESSED    'b'
+#define VHTAG_VUNIQ      'u'
+#define VHTAG_TYPE       't'
+#define VHTAG_PARENT     'p'
+#define VHTAG_CLONE      'c'
+#define VHTAG_MAXQUOTA   'q'
+#define VHTAG_MINQUOTA   'm'
+#define VHTAG_DISKUSED   'd'
+#define VHTAG_FILECNT    'f'
+#define VHTAG_ACCOUNT    'a'
+#define VHTAG_OWNER      'o'
+#define VHTAG_CREAT      'C'
+#define VHTAG_ACCESS     'A'
+#define VHTAG_UPDATE     'U'
+#define VHTAG_EXPIRE     'E'
+#define VHTAG_BACKUP     'B'
+#define VHTAG_OFFLINE    'O'
+#define VHTAG_MOTD       'M'
+#define VHTAG_WEEKUSE    'W'
+#define VHTAG_DUDATE     'D'
+#define VHTAG_DAYUSE     'Z'
+
+
+/** VNODE TAGS **/
+#define VTAG_TYPE        't'
+#define VTAG_NLINKS      'l'
+#define VTAG_DVERS       'v'
+#define VTAG_CLIENT_DATE 'm'
+#define VTAG_AUTHOR      'a'
+#define VTAG_OWNER       'o'
+#define VTAG_GROUP       'g'
+#define VTAG_MODE        'b'
+#define VTAG_PARENT      'p'
+#define VTAG_SERVER_DATE 's'
+#define VTAG_ACL         'A'
+#define VTAG_DATA        'f'
+
+
+#define AFS_DIR_EPP 64
+
+typedef struct {
+  afs_uint16 pgcount;
+  afs_uint16 tag;
+  char freecount;
+  char freebitmap[AFS_DIR_EPP/8];
+  char padding[32 - (5 + AFS_DIR_EPP/8)];
+} afs_dir_pagehdr;
+
+typedef struct {
+  char flag;
+  char length;
+  afs_uint16 next;
+  afs_uint32 vnode;
+  afs_uint32 vunique;
+  char name[16];
+  char padding[4];
+} afs_dir_direntry;
+
+typedef union {
+  afs_dir_pagehdr header;
+  afs_dir_direntry entry[AFS_DIR_EPP];
+} afs_dir_page;
+
+#endif /* _DUMPFMT_H_ */
diff --git a/src/tests/dumpscan.h b/src/tests/dumpscan.h
new file mode 100644 (file)
index 0000000..a6b3a24
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* dumpscan.h - Public interface */
+
+#ifndef _DUMPSCAN_H_
+#define _DUMPSCAN_H_
+
+#include "intNN.h"
+#include "xfiles.h"
+
+#include <lock.h>
+#include <afs/afsint.h>
+#include <afs/nfs.h>
+#include <afs/ihandle.h>
+#include <afs/vnode.h>
+#include <afs/cmd.h>
+#include <afs/auth.h>
+#include <afs/bnode.h>
+#include <afs/cellconfig.h>
+#include <afs/kautils.h>
+#include <afs/pterror.h>
+#include <afs/vlserver.h>
+#include <afs/volser.h>
+#include <ubik.h>
+
+/* Random useful types */
+typedef struct tagged_field tagged_field;
+typedef struct tag_parse_info tag_parse_info;
+typedef afs_uint32 (*tag_parser)(XFILE *, unsigned char *, tagged_field *,
+                              afs_uint32, tag_parse_info *, void *, void *);
+
+/* Error codes used within dumpscan.
+ * Any of the routines declared below, or callbacks used by them,
+ * may signal a system error by returning the error number, or
+ * some other error by returning a com_err code.  Note that
+ * ParseTaggedData does _not_ return DSERR_TAG; instead, it returns
+ * 0, assuming the tag will be handled at a higher level.
+ *
+ * In addition, these errors may be reported to the caller of
+ * ParseDumpFile using the error callback.  Such reports will be
+ * issued whether or not error recovery is possible or attempted.
+ *
+ * NB: These errors are now in dumpscan_errs.h
+ */
+
+
+/* Backup system dump header */
+/* Right now, this looks a lot like an old stage header.  Eventually, it
+ * should contain enough fields to fully represent headers from old or
+ * new stage, Transarc, or other backup systems, and the appropriate read
+ * functions should extract as much data as possible from the actual file
+ * to fill this in. */
+typedef struct {
+  afs_uint32 version;
+  afs_uint32 from_date;
+  afs_uint32 to_date;
+  afs_uint32 dump_date;
+  afs_uint32 filenum;
+  unsigned char *server;
+  unsigned char *part;
+  unsigned char *volname;
+  afs_uint32 volid;
+  afs_uint32 dumplen;
+  afs_uint32 level;
+  afs_uint32 magic;
+  afs_uint32 cksum;
+  afs_uint32 flags;
+} backup_system_header;
+
+
+/** AFS dump header **/
+#define F_DUMPHDR_VOLID       0x00000001
+#define F_DUMPHDR_VOLNAME     0x00000002
+#define F_DUMPHDR_FROM        0x00000004
+#define F_DUMPHDR_TO          0x00000008
+typedef struct {
+  u_int64 offset;           /* Where in the file is it? */
+  afs_uint32 field_mask;       /* What fields are present? */
+  afs_uint32 magic;            /* Magic number */
+  afs_uint32 version;          /* Dump format version */
+  afs_uint32 volid;            /* VolID of volume in dump */
+  unsigned char *volname;   /* Name of volume in dump */
+  afs_uint32 from_date;        /* Reference date */
+  afs_uint32 to_date;          /* Date of dump */
+} afs_dump_header;
+
+
+/** AFS volume header **/
+#define F_VOLHDR_VOLID        0x00000001
+#define F_VOLHDR_VOLVERS      0x00000002
+#define F_VOLHDR_VOLNAME      0x00000004
+#define F_VOLHDR_INSERV       0x00000008
+#define F_VOLHDR_BLESSED      0x00000010
+#define F_VOLHDR_VOLUNIQ      0x00000020
+#define F_VOLHDR_VOLTYPE      0x00000040
+#define F_VOLHDR_PARENT       0x00000080
+#define F_VOLHDR_CLONE        0x00000100
+#define F_VOLHDR_MAXQ         0x00000200
+#define F_VOLHDR_MINQ         0x00000400
+#define F_VOLHDR_DISKUSED     0x00000800
+#define F_VOLHDR_NFILES       0x00001000
+#define F_VOLHDR_ACCOUNT      0x00002000
+#define F_VOLHDR_OWNER        0x00004000
+#define F_VOLHDR_CREATE_DATE  0x00008000
+#define F_VOLHDR_ACCESS_DATE  0x00010000
+#define F_VOLHDR_UPDATE_DATE  0x00020000
+#define F_VOLHDR_EXPIRE_DATE  0x00040000
+#define F_VOLHDR_BACKUP_DATE  0x00080000
+#define F_VOLHDR_OFFLINE_MSG  0x00100000
+#define F_VOLHDR_MOTD         0x00200000
+#define F_VOLHDR_WEEKUSE      0x00400000
+#define F_VOLHDR_DAYUSE       0x00800000
+#define F_VOLHDR_DAYUSE_DATE  0x01000000
+typedef struct {
+  u_int64 offset;           /* Where in the file is it? */
+  afs_uint32 field_mask;       /* What fields are present? */
+  afs_uint32 volid;            /* Volume ID */
+  afs_uint32 volvers;          /* ?? */
+  unsigned char *volname;   /* Volume Name */
+  int     flag_inservice;   /* Inservice flag (0 or not) */
+  int     flag_blessed;     /* Blessed to come online (0 or not) */
+  afs_uint32 voluniq;          /* Volume uniquifier */
+  int     voltype;          /* Volume type */
+  afs_uint32 parent_volid;     /* Parent volume ID */
+  afs_uint32 clone_volid;      /* Clone volume ID */
+  afs_uint32 maxquota;         /* Max quota */
+  afs_uint32 minquota;         /* Min quota (obsolete) */
+  afs_uint32 diskused;         /* Disk blocks used */
+  afs_uint32 nfiles;           /* Number of files in volume */
+  afs_uint32 account_no;       /* Account number (unused) */
+  afs_uint32 owner;            /* Volume owner */
+  afs_uint32 create_date;      /* Creation date of this copy */
+  afs_uint32 access_date;      /* Last access */
+  afs_uint32 update_date;      /* Last modification */
+  afs_uint32 expire_date;      /* Expiration (unused) */
+  afs_uint32 backup_date;      /* Last backup clone */
+  unsigned char *offline_msg; /* Offline message */
+  unsigned char *motd_msg;    /* Volume MOTD */
+  afs_uint32 weekuse[7];       /* Weekuse data */
+  afs_uint32 dayuse;           /* # accesses in last day */
+  afs_uint32 dayuse_date;      /* Date for which dayuse is valid */
+} afs_vol_header;
+
+
+/** AFS vnode **/
+#define F_VNODE_TYPE          0x00000001
+#define F_VNODE_NLINKS        0x00000002
+#define F_VNODE_PARENT        0x00000004
+#define F_VNODE_DVERS         0x00000008
+#define F_VNODE_AUTHOR        0x00000010
+#define F_VNODE_OWNER         0x00000020
+#define F_VNODE_GROUP         0x00000040
+#define F_VNODE_MODE          0x00000080
+#define F_VNODE_CDATE         0x00000100
+#define F_VNODE_SDATE         0x00000200
+#define F_VNODE_SIZE          0x00000800
+#define F_VNODE_DATA          0x00001000
+#define F_VNODE_ACL           0x00000400
+typedef struct {
+  u_int64 offset;           /* Where in the file is it? */
+  afs_uint32 field_mask;       /* What fields are present? */
+  afs_uint32 vnode;            /* Vnode number */
+  afs_uint32 vuniq;            /* Uniquifier */
+  int     type;             /* Vnode type */
+  afs_uint16 nlinks;           /* Number of links (should be in 1 dir!) */
+  afs_uint32 parent;           /* Parent vnode */
+  afs_uint32 datavers;         /* Data version */
+  afs_uint32 author;           /* Last writer */
+  afs_uint32 owner;            /* Owner UID */
+  afs_uint32 group;            /* Owning group */
+  afs_uint16 mode;             /* UNIX mode bits */
+  afs_uint32 client_date;      /* Last modified date from client */
+  afs_uint32 server_date;      /* Last modified date on server */
+  afs_uint32 size;             /* Size of data */
+  u_int64 d_offset;         /* Where in the file is the data? */
+  unsigned char acl[SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE];
+} afs_vnode;
+
+
+/** AFS directory entry **/
+typedef struct {
+  int  slot;                /* Directory slot # (info only) */
+  char *name;               /* Name of entry */
+  afs_uint32 vnode;            /* Vnode number */
+  afs_uint32 uniq;             /* Uniquifier */
+} afs_dir_entry;
+
+
+/** Tagged field definitions **/
+#define DKIND_NOOP      0x00  /* No data */
+#define DKIND_BYTE      0x10  /* 1 byte  - decimal */
+#define DKIND_HEX8      0x11  /* 1 byte  - hex */
+#define DKIND_CHAR      0x12  /* 1 byte  - character */
+#define DKIND_FLAG      0x13  /* 1 byte  - true/false */
+#define DKIND_INT16     0x20  /* 2 bytes - decimal */
+#define DKIND_HEX16     0x21  /* 2 bytes - hex */
+#define DKIND_INT32     0x30  /* 4 bytes - decimal */
+#define DKIND_HEX32     0x31  /* 4 bytes - hex */
+#define DKIND_TIME      0x32  /* 4 bytes - time */
+#define DKIND_STRING    0x40  /* ASCIIZ string */
+#define DKIND_SPECIAL   0x50  /* Custom parser */
+#define DKIND_MASK     (~0x0f)
+struct tag_parse_info {
+  void *err_refcon;
+  afs_uint32 (*cb_error)(afs_uint32, int, void *, char *, ...);
+  afs_uint32 flags;
+#define TPFLAG_SKIP   0x0001
+#define TPFLAG_RSKIP  0x0002
+  int shift_offset;
+  u_int64 shift_start;
+};
+struct tagged_field {
+  char tag;        /* Tag character */
+  int  kind;       /* Kind of object */
+  char *label;     /* Label to use (for debugging) */
+  tag_parser func; /* Parser function (for DKIND_SPECIAL) */
+  void *refptr;    /* Reference pointer (for parser's use) */
+  int  refarg;     /* Reference argument (for parser's use) */
+};
+
+
+/** Control structure for parsing volume dumps **/
+typedef struct {
+  /* Callback functions:
+   * Whenever a "complex" object is parsed, we call a callback function.
+   * The callback gets a pointer to the complex object, the file pointer
+   * for the dump we're parsing, and the value of refcon in this structure.
+   * Callbacks should return 0 if all is well, non-0 to abort the dump.
+   * By convention, positive numbers should be errno values, and negative
+   * numbers can be used for other things.  It is OK to _try_ to seek anywhere
+   * in the file.  Beware, though, that the input is not always seekable.
+   * Also, note that the structures passed to these callbacks are going to
+   * go away after the callback returns.  There is no way to prevent this;
+   * make a copy if you want one.
+   */
+  void *refcon;
+  afs_uint32 (*cb_bckhdr)(backup_system_header *, XFILE *, void *); /* Backup   */
+  afs_uint32 (*cb_dumphdr)(afs_dump_header *, XFILE *, void *); /* Dump hdr     */
+  afs_uint32 (*cb_volhdr)(afs_vol_header *, XFILE *, void *);   /* Volume hdr   */
+  afs_uint32 (*cb_vnode_dir)(afs_vnode *, XFILE *, void *);     /* Directory    */
+  afs_uint32 (*cb_vnode_file)(afs_vnode *, XFILE *, void *);    /* File         */
+  afs_uint32 (*cb_vnode_link)(afs_vnode *, XFILE *, void *);    /* Symlink      */
+  afs_uint32 (*cb_vnode_empty)(afs_vnode *, XFILE *, void *);   /* vnode+uniq   */
+  afs_uint32 (*cb_vnode_wierd)(afs_vnode *, XFILE *, void *);   /* Unknown type */
+
+  /* This function is called when there is an error in the dump. */
+  /* (cb_error)(errno, fatal, refcon, msg_fmt, msg_args...) */
+  void *err_refcon; /* If set, use instead of refcon for dir entries */
+  afs_uint32 (*cb_error)(afs_uint32, int, void *, char *, ...);
+
+  /* This function is called for each directory entry, if set */
+  afs_uint32 (*cb_dirent)(afs_vnode *, afs_dir_entry *, XFILE *, void *);
+
+  int flags;            /* Flags and options */
+#define DSFLAG_SEEK     0x0001  /* Input file is seekable */
+
+  int print_flags;      /* Flags to control what is printed */
+#define DSPRINT_BCKHDR  0x0001  /* Print backup system header */
+#define DSPRINT_DUMPHDR 0x0002  /* Print AFS dump header */
+#define DSPRINT_VOLHDR  0x0004  /* Print AFS volume header */
+#define DSPRINT_ITEM    0x0010  /* Print top-level tags */
+#define DSPRINT_VNODE   0x0020  /* Print vnode attributes */
+#define DSPRINT_ACL     0x0040  /* Print directory ACL's */
+#define DSPRINT_DIR     0x0080  /* Print directory contents */
+#define DSPRINT_DEBUG   0x0100  /* Print debugging info */
+#define DSPRINT_PATH    0x0200  /* Print vnode paths */
+
+  int repair_flags;     /* Flags to control what is repaired.
+                         * Most of these _require_ DSFLAG_SEEK */
+#define DSFIX_SKIP      0x0001  /* Try to skip null tags */
+#define DSFIX_RSKIP     0x0002  /* Seek back to fing skipped tags */
+#define DSFIX_VDSYNC    0x0004  /* Resync location after vnode data */
+#define DSFIX_VFSYNC    0x0008  /* Try to resync after bad vnode */
+
+  /** Things below this point for internal use only **/
+  afs_uint32 vol_uniquifier;
+} dump_parser;
+
+
+/** Hash table and control info for pathname manipulation **/
+typedef struct vhash_ent {
+  struct vhash_ent *next;    /* Pointer to next entry */
+  afs_uint32 vnode;             /* VNode number */
+  afs_uint32 parent;            /* Parent VNode number */
+  u_int64 v_offset;          /* Offset to start of vnode */
+  u_int64 d_offset;          /* Offset to data (0 if none) */
+  afs_uint32 d_size;            /* Size of data */
+} vhash_ent;
+typedef struct {
+  afs_uint32 n_vnodes;          /* Number of vnodes in volume */
+  afs_uint32 n_dirs;            /* Number of file vnodes */
+  afs_uint32 n_files;           /* Number of directory vnodes */
+  int hash_size;             /* Hash table size (bits) */
+  vhash_ent **hash_table;    /* Hash table */
+  dump_parser *p;            /* Dump parser to use */
+} path_hashinfo;
+
+
+/** Function prototypes **/
+/** Only the functions declared below are public interfaces **/
+/** Maybe someday, I'll write man pages for these **/
+
+/* primitive.c - I/O primitives */
+extern afs_uint32 ReadByte(XFILE *, unsigned char *);
+extern afs_uint32 ReadInt16(XFILE *, afs_uint16 *);
+extern afs_uint32 ReadInt32(XFILE *, afs_uint32 *);
+extern afs_uint32 ReadString(XFILE *, unsigned char **);
+extern afs_uint32 WriteByte(XFILE *, unsigned char);
+extern afs_uint32 WriteInt16(XFILE *, afs_uint16);
+extern afs_uint32 WriteInt32(XFILE *, afs_uint32);
+extern afs_uint32 WriteString(XFILE *, unsigned char *);
+extern afs_uint32 WriteTagByte(XFILE *, unsigned char, unsigned char);
+extern afs_uint32 WriteTagInt16(XFILE *, unsigned char, afs_uint16);
+extern afs_uint32 WriteTagInt32(XFILE *, unsigned char, afs_uint32);
+extern afs_uint32 WriteTagInt32Pair(XFILE *, unsigned char, afs_uint32, afs_uint32);
+
+/* parsetag.c - Parse tagged data */
+extern afs_uint32 ParseTaggedData(XFILE *, tagged_field *, unsigned char *,
+                           tag_parse_info *, void *, void *);
+
+/* stagehdr.c - Parse and dump Stage dump headers */
+extern afs_uint32 ParseStageHdr(XFILE *, unsigned char *, backup_system_header *);
+extern afs_uint32 DumpStagehdr(XFILE *, backup_system_header *);
+
+/* backuphdr.c - Parse and print backup system headers */
+extern void PrintBackupHdr(backup_system_header *);
+
+/* parsedump.c - Parse all or part of a volume dump */
+extern afs_uint32 ParseDumpFile(XFILE *, dump_parser *);
+extern afs_uint32 ParseDumpHeader(XFILE *, dump_parser *);
+extern afs_uint32 ParseVolumeHeader(XFILE *, dump_parser *);
+extern afs_uint32 ParseVNode(XFILE *, dump_parser *);
+
+
+/* directory.c - Directory parsing and lookup */
+extern afs_uint32 ParseDirectory(XFILE *, dump_parser *, afs_uint32, int);
+extern afs_uint32 DirectoryLookup(XFILE *, dump_parser *, afs_uint32,
+                           char **, afs_uint32 *, afs_uint32 *);
+
+/* dump.c - Dump parts of a volume dump */
+extern afs_uint32 DumpDumpHeader(XFILE *, afs_dump_header *);
+extern afs_uint32 DumpVolumeHeader(XFILE *, afs_vol_header *);
+extern afs_uint32 DumpVNode(XFILE *, afs_vnode *);
+extern afs_uint32 DumpVnodeData(XFILE *, char *, afs_uint32);
+extern afs_uint32 CopyVnodeData(XFILE *, XFILE *, afs_uint32);
+
+/* pathname.c - Follow and construct pathnames */
+extern afs_uint32 Path_PreScan(XFILE *, path_hashinfo *, int);
+extern void Path_FreeHashTable(path_hashinfo *);
+extern afs_uint32 Path_Follow(XFILE *, path_hashinfo *, char *, vhash_ent *);
+extern afs_uint32 Path_Build(XFILE *, path_hashinfo *, afs_uint32, char **, int);
+
+#endif
diff --git a/src/tests/dumpscan_errs.et b/src/tests/dumpscan_errs.et
new file mode 100644 (file)
index 0000000..22c38c3
--- /dev/null
@@ -0,0 +1,37 @@
+# COPYRIGHT NOTICE
+# Copyright (c) 1997 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.
+
+# UB - Unified Backups
+# methods/afs/dumpscan/afsdump_errs.et - AFS dump scanner errors
+
+error_table AVds
+  ec DSERR_TAG,            "Unknown tag in AFS volume dump"
+  ec DSERR_MAGIC,          "Bad magic number in AFS volume dump"
+  ec DSERR_BOGUS,          "Bogus value in AFS volume dump"
+  ec DSERR_FMT,            "AFS volume dump format incorrect"
+  ec DSERR_KEEP,           "[AFS dumpscan internal: keep string]"
+  ec DSERR_PANIC,          "[AFS dumpscan internal: panic]"
+  ec DSERR_DONE,           "[AFS dumpscan internal: done]"
+  ec DSERR_MEM,            "[AFS dumpscan internal: out of memory]"
+end
diff --git a/src/tests/dumptool.c b/src/tests/dumptool.c
new file mode 100644 (file)
index 0000000..57a6ad0
--- /dev/null
@@ -0,0 +1,2640 @@
+/*
+ * $Id: dumptool.c,v 1.1 2002/01/22 19:54:40 hartmans Exp $
+ *
+ * dumptool - A tool to manage MR-AFS dump files
+ *
+ * The dump file format ought to be documented _somewhere_, and
+ * this seems like a good as a place as any ...
+ *
+ * A AFS dump file is marked off into a series of sections.  Each
+ * section marked by a dump tag.  A tag is a single byte who's value
+ * corresponds with the next section.  The sections are (in order):
+ *
+ * DUMPHEADER (tag 0x01)
+ * VOLUMEHEADER (tag 0x02)
+ * VNODE (tag 0x03)
+ * DUMPEND (tag 0x04)
+ *
+ * Descriptions of the sections follow.  Note that in all cases, data is
+ * stored in the dump in network byte order.
+ *
+ * DUMPHEADER:
+ *
+ * DUMPHEADER contains two parts: the DUMPMAGIC magic number (32 bits)
+ * and the dump header itself.
+ *
+ * The dump header itself consists of a series of tagged values,
+ * each tag marking out members of the DumpHeader structure.  The
+ * routine ReadDumpHeader explains the specifics of these tags.
+ *
+ * VOLUMEHEADER:
+ *
+ * VOLUMEHEADER is a series of tagged values corresponding to the elements
+ * of the VolumeDiskData structure.  See ReadVolumeHeader for more
+ * information
+ *
+ * VNODE:
+ *
+ * The VNODE section is all vnodes contained in the volume (each vnode
+ * itself is marked with the VNODE tag, so it's really a sequence of
+ * VNODE tags, unlike other sections).
+ *
+ * Each vnode consists of three parts: the vnode number (32 bits), the
+ * uniqifier (32 bits), and a tagged list of elements corresponding to
+ * the elements of the VnodeDiskData structure.  See ScanVnodes for
+ * more information.  Note that if file data is associated with a vnode,
+ * it will be contained here.
+ *
+ * DUMPEND:
+ *
+ * The DUMPEND section consists of one part: the DUMPENDMAGIC magic
+ * number (32 bits).
+ * 
+ * Notes:
+ *
+ * The tagged elements are all ASCII letters, as opposed to the section
+ * headers (which are 0x01, 0x02, ...).  Thus, an easy way to tell when
+ * you've reached the end of an element sequence is to check to see if
+ * the next tag is a printable character (this code tests for < 20).
+ *
+ * "vos dump" dumps the large vnode index, then the small vnode index,
+ * so directories will appear first in the VNODE section.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <termios.h>
+#include <fnmatch.h>
+
+#include <lock.h>
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <afs/nfs.h>
+#include <afs/acl.h>
+#if !defined(PRE_AFS_36) && !defined(RESIDENCY)
+#include <afs/ihandle.h>
+#endif /* !defined(PRE_AFS_36) && !defined(RESIDENCY) */
+#include <afs/vnode.h>
+#include <afs/volume.h>
+
+#ifdef RESIDENCY
+#include <afs/rsdefs.h>
+#include <afs/remioint.h>
+#endif /* RESIDENCY */
+
+#include <afs/dir.h>
+
+/*
+ * Sigh.  Linux blows it again
+ */
+
+#ifdef linux
+#include <pty.h>
+#endif
+
+/*
+ * Stuff that is in private AFS header files, unfortunately
+ */
+
+#define DUMPVERSION    1
+#define DUMPENDMAGIC   0x3A214B6E
+#define DUMPBEGINMAGIC 0xB3A11322
+#define D_DUMPHEADER   1
+#define D_VOLUMEHEADER 2
+#define D_VNODE                3
+#define D_DUMPEND      4
+#define D_MAX          20
+
+#define MAXDUMPTIMES   50
+
+struct DumpHeader {
+       int32_t version;
+       VolumeId volumeId;
+       char volumeName[VNAMESIZE];
+       int nDumpTimes;             /* Number of pairs */
+       struct {
+               int32_t from, to;
+       } dumpTimes[MAXDUMPTIMES];
+};
+
+/*
+ * Our command-line arguments
+ */
+
+#ifdef RESIDENCY
+struct {
+       int Algorithm;          /* Conversion algorithm */
+       int Size;               /* Directory hierarchy size */
+       int FSType;             /* File system type */
+       int DeviceTag;          /* Device Tag */
+} rscmdlineinfo[RS_MAXRESIDENCIES];
+
+/*
+ * This stuff comes from ufsname.c (which itself takes it from
+ * ufs_interfaces.c)
+ */
+
+/* There is an assumption that all of the prefixes will have exactly one '/' */
+static char *Ufs_Prefixes[] = {"/ufs", "/slowufs", "/cdmf", "/sdmf"};
+#define MAX_ITERATIONS 10
+#define UFS_SUMMARYTREENAME "Summaries"
+#define UFS_STAGINGTREENAME "Staging"
+#define UFS_VOLUMEHEADERTREENAME "VolHeaders"
+#define UFS_VOLUMETREENAME "Volumes"
+#define UFS_ALGORITHMBASE 'A'
+#define UFS_MOUNTPOINTBASE 'a'
+#define UFS_ALGORITHMS 3
+#define UFS_LINK_MAX 64 /* Arbitrary. */
+#define HARD_LINKED_FILE -2
+#define TAGSTONAME(FileName, MountPoint, Sections, Level1, RWVolume, Vnode, Uniquifier, Algorithm) \
+{ \
+    if (Level1) \
+        sprintf(FileName,"%s/%lu/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
+                (Sections)[0], (Sections)[1], UFS_ALGORITHMBASE + Algorithm, \
+                (Sections)[2], (Sections)[3], RWVolume, Vnode, Uniquifier); \
+    else \
+        sprintf(FileName,"%s/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
+                (Sections)[0], UFS_ALGORITHMBASE + Algorithm, \
+                (Sections)[1], (Sections)[2], RWVolume, Vnode, Uniquifier); \
+}
+#define TAGSTOSTAGINGNAME(FileName, MountPoint, RWVolume, Vnode, Uniquifier) \
+    sprintf(FileName,"%s/%s/%lu.%lu.%lu", MountPoint, \
+           UFS_STAGINGTREENAME, RWVolume, Vnode, Uniquifier)
+#define TAGSTOVOLUMEHEADERNAME(FileName, MountPoint, FileTag1, FileTag2) \
+    sprintf(FileName,"%s/%s/%lu", MountPoint, UFS_VOLUMEHEADERTREENAME, \
+           FileTag1)
+#define TAGSTOVOLUMEINFONAME(FileName, MountPoint, FileTag1, FileTag2) \
+    sprintf(FileName,"%s/%s/%lu/%lu", MountPoint, \
+           UFS_VOLUMETREENAME, FileTag2, FileTag1)
+#define TAGSTOVOLUMENAME(FileName, MountPoint, FileTag1, FileTag2, RWVolume) \
+    sprintf(FileName,"%s/%s/%lu/%lu.%lu", MountPoint, \
+           UFS_VOLUMETREENAME, FileTag2, FileTag1, RWVolume)
+#define TAGSTOSUMMARYNAME(FileName, MountPoint, FileTag1, FileTag2, SummaryRequestor, Residency) \
+    sprintf(FileName,"%s/%s/%lu.%lu.%lu.%lu", MountPoint, \
+           UFS_SUMMARYTREENAME, FileTag1, FileTag2, SummaryRequestor, \
+           Residency)
+#define DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTagNumber, FSType) \
+    sprintf(MountPoint,"%s%c", Ufs_Prefixes[FSType], UFS_MOUNTPOINTBASE + \
+           DeviceTagNumber)
+#define MOUNTPOINTTODEVICETAGNUMBER(MountPoint) \
+    MountPoint[strlen(MountPoint) - 1] - UFS_MOUNTPOINTBASE
+#define DEVICETAGNUMBERTOVOLUMEHEADERTREE(TreeName, MountPoint) \
+    sprintf(TreeName,"%s/%s", MountPoint, UFS_VOLUMEHEADERTREENAME)
+#define UFS_RESIDENCIES_FILE "Residencies"
+
+/* We don't ever want to map to uid/gid -1.  fchown() takes that as a
+   don't change flag.  We know however that volume number range from
+   0x2000000 to 0x20FFFFFF (see VAllocateVolumeId() in vol/vutil.c)
+   so we will use that to insure that -1 never appears. */
+#define RWVolumeToUid(RWVolume) ((RWVolume >> 12) & 0xFFFF)
+#define RWVolumeToGid(RWVolume) ((RWVolume & 0xFFF) | \
+                                (((RWVolume >> 28) & 0xF) << 12))
+#define UidGidToRWVolume(Uid, Gid) ((Gid & 0xFFF) | ((Uid & 0xFFFF) << 12) | \
+                                   ((Gid & 0xF000) << 16))
+
+
+/* These routines generate a file name to correspond to the given tag
+   numbers. */
+
+/* The following entropy array contains the order of bits from highest entropy
+   to lowest in the numbers FileTag1 and FileTag2.  Bit numbers 32 and above
+   correspond to FileTag2.  This ordering was determined by examining all read-
+   write volumes in the psc.edu cell. */
+char UfsEntropy[1][64] = {
+  {1, 2, 3, 4, 33, 5, 6, 7, 44, 45, 46, 36, 8, 34, 42, 35, 
+     9, 40, 38, 32, 43, 10, 39, 37, 11, 41, 12, 13, 14, 0, 
+     15, 16, 61, 17, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 
+     50, 49, 48, 47, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 
+     21, 20, 19, 18, 62, 63},
+};
+
+uint32_t Directories[3][2] = { {256, 0}, {256, 16}, {256, 256}, };
+#endif /* RESIDENCY */
+
+static int verbose = 0;
+static int numNoDirData = 0;
+static int termsize = 0;
+int Testing = 0;
+#ifdef RESIDENCY
+extern resid ServerRequestorId;
+#endif /* RESIDENCY */
+
+/*
+ * We use this structure to hold vnode data in our hash table.
+ * It's indexed by vnode number.
+ */
+
+struct vnodeData {
+       struct VnodeDiskObject *vnode;  /* A pointer to the disk vnode */
+       int vnodeNumber;                /* The vnode number */
+       long dumpdata;                  /* File offset of dump data (if
+                                          available */
+       unsigned char *filedata;        /* A pointer to the actual file
+                                          data itself (if available) */
+       unsigned int datalength;        /* The length of the data */
+};
+
+/*
+ * This contains the current location when we're doing a scan of a
+ * directory.
+ */
+
+struct DirCursor {
+       int hashbucket;                 /* Current hash bucket */
+       int entry;                      /* Entry within hash bucket */
+};
+
+/*
+ * Arrays to hold vnode data
+ */
+
+struct vnodeData **LargeVnodeIndex;
+struct vnodeData **SmallVnodeIndex;
+int numLargeVnodes = 0;
+int numSmallVnodes = 0;
+
+/*
+ * Crap for the libraries
+ */
+
+int ShutdownInProgress = 0;
+
+/*
+ * Our local function prototypes
+ */
+
+static int ReadDumpHeader(FILE *, struct DumpHeader *);
+static int ReadVolumeHeader(FILE *, VolumeDiskData *);
+static int ScanVnodes(FILE *, VolumeDiskData *, int);
+static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
+static struct vnodeData *InsertVnode(unsigned int, struct VnodeDiskObject *);
+static struct vnodeData *GetVnode(unsigned int);
+static int CompareVnode(const void *, const void *);
+static void InteractiveRestore(FILE *, VolumeDiskData *);
+static void DirectoryList(int, char **, struct vnodeData *, VolumeDiskData *);
+static void DirListInternal(struct vnodeData *, char *[], int, int, int, int,
+                           int, int, VolumeDiskData *, char *);
+static int CompareDirEntry(const void *, const void *);
+static struct vnodeData *ChangeDirectory(int, char **, struct vnodeData *);
+static void CopyFile(int, char **, struct vnodeData *, FILE *);
+static void CopyVnode(int, char **, FILE *);
+static void DumpAllFiles(int, char **, struct vnodeData *, VolumeDiskData *);
+static void DumpAllResidencies(FILE *, struct vnodeData *, VolumeDiskData *);
+static struct vnodeData *FindFile(struct vnodeData *, char *);
+static void ResetDirCursor(struct DirCursor *, struct vnodeData *);
+static struct DirEntry *ReadNextDir(struct DirCursor *, struct vnodeData *);
+static void MakeArgv(char *, int *, char ***);
+static char *GetToken(char *, char **, char *, char *[]);
+static int ReadInt16(FILE *, uint16_t *);
+static int ReadInt32(FILE *, uint32_t *);
+static int ReadString(FILE *, char *, int);
+static int ReadByteString(FILE *, void *, int);
+
+int
+main(int argc, char *argv[])
+{
+       int c, errflg = 0, dumpvnodes = 0, force = 0, inode = 0;
+       unsigned int magic;
+       struct DumpHeader dheader;
+       VolumeDiskData vol;
+       long offset;
+       int Res, Arg1, Arg2, Arg3, i;
+       char *p;
+       struct winsize win;
+       FILE *f;
+
+#ifdef RESIDENCY
+       for (i = 0; i < RS_MAXRESIDENCIES; i++) {
+               rscmdlineinfo[i].Algorithm = -1;
+               rscmdlineinfo[i].Size = -1;
+               rscmdlineinfo[i].DeviceTag = -1;
+               rscmdlineinfo[i].FSType = - 1;
+       }
+#endif /* RESIDENCY */
+
+       /*
+        * Sigh, this is dumb, but we need the terminal window size
+        * to do intelligent things with "ls" later on.
+        */
+
+       if (isatty(STDOUT_FILENO)) {
+               if ((p = getenv("COLUMNS")) != NULL)
+                       termsize = atoi(p);
+               else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+                        win.ws_col > 0)
+                       termsize = win.ws_col;
+       }
+
+       while ((c = getopt(argc, argv, "difr:t:v")) != EOF)
+               switch (c) {
+               case 't':
+#ifdef RESIDENCY
+                       if (sscanf(optarg, "%d/%d", &Res, &Arg1) != 2) {
+                               errflg++;
+                               break;
+                       }
+
+                       if (1 << (ffs(Res) - 1) != Res) {
+                               fprintf(stderr, "Invalid residency %d\n", Res);
+                               errflg++;
+                               break;
+                       }
+
+                       if (Arg1 < 0 || Arg1 > 26) {
+                               fprintf(stderr, "Invalid device tag: %d\n",
+                                       Arg1);
+                               errflg++;
+                               break;
+                       }
+                       rscmdlineinfo[ffs(Res) - 1].DeviceTag = Arg1;
+#else /* RESIDENCY */
+                       fprintf(stderr, "-t not supported in non-MRAFS "
+                               "dumptool.\n");
+                       errflg++;
+#endif /* RESIDENCY */
+                       break;
+
+               case 'r':
+#ifdef RESIDENCY
+                       if (sscanf(optarg, "%d/%d/%d/%d", &Res, &Arg1, &Arg2,
+                                  &Arg3) != 4) {
+                               errflg++;
+                               break;
+                       }
+
+                       if (Arg1 < 0 || Arg1 > 3) {
+                               fprintf(stderr, "Invalid fstype: %d\n", Arg1);
+                               errflg++;
+                               break;
+                       }
+
+                       if (Arg2 < 0 || Arg2 > 2) {
+                               fprintf(stderr, "Invalid size: %d\n", Arg2);
+                               errflg++;
+                               break;
+                       }
+
+                       if (Arg3 <= 0 || Arg3 > UFS_ALGORITHMS) {
+                               fprintf(stderr, "Invalid algorithm: %d\n",
+                                       Arg3);
+                               errflg++;
+                               break;
+                       }
+                       rscmdlineinfo[ffs(Res) - 1].FSType = Arg1;
+                       rscmdlineinfo[ffs(Res) - 1].Size = Arg2;
+                       rscmdlineinfo[ffs(Res) - 1].Algorithm = Arg3;
+#else /* RESIDENCY */
+                       fprintf(stderr, "-r not supported in non-MRAFS "
+                               "dumptool.\n");
+                       errflg++;
+#endif /* RESIDENCY */
+                       break;
+               case 'd':
+#ifdef RESIDENCY
+                       dumpvnodes++;
+#else /* RESIDENCY */
+                       fprintf(stderr, "-d not supported in non-MRAFS "
+                               "dumptool.\n");
+                       errflg++;
+#endif /* RESIDENCY */
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               case 'f':
+                       force++;
+                       break;
+               case 'i':
+                       inode++;
+                       break;
+               case '?':
+               default:
+                       errflg++;
+               }
+       
+       if (errflg || optind == argc) {
+               fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
+#ifdef RESIDENCY
+                       "[-t Residency/Tag]\n\t"
+                       "[-r Residency/Type/Size/Algorithm]\n\t"
+                       "[-d] filename [file_in_dump [file in dump ...]]\n",
+#else /* RESIDENCY */
+                       "filename\n",
+#endif /* RESIDENCY */
+                       argv[0]);
+               exit(1);
+       }
+
+       /*
+        * Try opening the dump file
+        */
+
+       if ((f = fopen(argv[optind], "rb")) == NULL) {
+               fprintf(stderr, "open of dumpfile %s failed: %s\n", argv[optind],
+                       strerror(errno));
+               exit(1);
+       }
+
+       if (ReadDumpHeader(f, &dheader)) {
+               fprintf(stderr, "Failed to read dump header!\n");
+               exit(1);
+       }
+
+       if (verbose)
+               printf("Dump is for volume %lu (%s)\n", dheader.volumeId,
+                       dheader.volumeName);
+
+       if (getc(f) != D_VOLUMEHEADER) {
+               fprintf(stderr, "Volume header is missing from dump, aborting\n");
+               exit(1);
+       }
+
+       if (ReadVolumeHeader(f, &vol)) {
+               fprintf(stderr, "Unable to read volume header\n");
+               exit(1);
+       }
+
+       if (verbose) {
+               printf("Volume information:\n");
+               printf("\tid = %lu\n", vol.id);
+               printf("\tparent id = %lu\n", vol.parentId);
+               printf("\tname = %s\n", vol.name);
+               printf("\tflags =");
+               if (vol.inUse)
+                       printf(" inUse");
+               if (vol.inService)
+                       printf(" inService");
+               if (vol.blessed)
+                       printf(" blessed");
+               if (vol.needsSalvaged)
+                       printf(" needsSalvaged");
+               printf("\n");
+               printf("\tuniquifier = %lu\n", vol.uniquifier);
+               printf("\tCreation date = %s", ctime((time_t *) &vol.creationDate));
+               printf("\tLast access date = %s", ctime((time_t *) &vol.accessDate));
+               printf("\tLast update date = %s", ctime((time_t *) &vol.updateDate));
+               printf("\tVolume owner = %lu\n", vol.owner);
+       }
+
+       if (verbose)
+               printf("Scanning vnodes (this may take a while)\n");
+
+       /*
+        * We need to do two vnode scans; one to get the number of
+        * vnodes, the other to actually build the index.
+        */
+
+       offset = ftell(f);
+
+       if (ScanVnodes(f, &vol, 1)) {
+               fprintf(stderr, "First vnode scan failed, aborting\n");
+               exit(1);
+       }
+
+       fseek(f, offset, SEEK_SET);
+
+       if (ScanVnodes(f, &vol, 0)) {
+               fprintf(stderr, "Second vnode scan failed, aborting\n");
+               exit(1);
+       }
+
+       if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) ||
+           magic != DUMPENDMAGIC) {
+               fprintf(stderr, "Couldn't find dump postamble, ");
+               if (! force) {
+                       fprintf(stderr, "aborting (use -f to override)\n");
+                       exit(1);
+               } else {
+                       fprintf(stderr, "continuing anyway\n");
+                       fprintf(stderr, "WARNING: Dump may not be complete!\n");
+               }
+       }
+
+       /*
+        * If we wanted to simply dump all vnodes, do it now
+        */
+
+#ifdef RESIDENCY
+       if (dumpvnodes) {
+               struct vnodeData *vdata;
+
+               for (i = 0; i < numLargeVnodes; i++) {
+
+                       vdata = LargeVnodeIndex[i];
+
+                       if (vdata->vnode->type == vFidLookup)
+                               if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
+                                       fprintf(stderr, "DumpVnodeFile failed, "
+                                               "aborting\n");
+                                       exit(1);
+                               }
+               }
+
+               for (i = 0; i < numSmallVnodes; i++) {
+
+                       vdata = SmallVnodeIndex[i];
+
+                       if (vdata->vnode->type == vFidLookup)
+                               if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
+                                       fprintf(stderr, "DumpVnodeFile failed, "
+                                               "aborting\n");
+                                       exit(1);
+                               }
+               }
+
+       } else
+#endif /* RESIDENCY */
+       if (inode) {
+               /*
+                * Dump out all filenames with their corresponding FID
+                */
+               
+               struct vnodeData *rootvdata;
+
+               if ((rootvdata = GetVnode(1)) == NULL) {
+                       fprintf(stderr, "Can't get vnode data for root "
+                               "vnode!  Aborting\n");
+                       exit(1);
+               }
+
+               DirListInternal(rootvdata, NULL, 0, 0, 1, 0, 1, 0, &vol, "");
+               
+       } else if (argc > optind + 1) {
+#ifdef RESIDENCY
+               /*
+                * Dump out residencies of files given on the command line.
+                */
+
+               struct vnodeData *vdata, *rootvdata;
+
+               if ((rootvdata = GetVnode(1)) == NULL) {
+                       fprintf(stderr, "Can't get vnode data for root "
+                               "vnode!  Aborting\n");
+                       exit(1);
+               }
+
+               for (i = optind + 1; i < argc; i++) {
+
+                       if ((vdata = FindFile(rootvdata, argv[i])) == NULL) {
+                               fprintf(stderr, "Skipping file %s\n",
+                                       argv[i]);
+                               continue;
+                       }
+
+                       if (verbose)
+                               printf("Residency locations for %s:\n",
+                                      argv[i]);
+
+                       while (vdata->vnode->NextVnodeId != 0) {
+
+                               vdata = GetVnode(vdata->vnode->NextVnodeId);
+
+                               if (vdata == NULL) {
+                                       fprintf(stderr, "We had a vnode chain "
+                                               "pointer to a vnode that "
+                                               "doesn't exist, aborting!\n");
+                                       exit(1);
+                               }
+                               if (vdata->vnode->type == vFidLookup)
+                                       DumpVnodeFile(stdout, vdata->vnode,
+                                                     &vol);
+                       }
+               }
+#else /* RESIDENCY */
+               fprintf(stderr, "Extra arguments after dump filename: %s\n",
+                       argv[optind]);
+               exit(1);
+#endif /* RESIDENCY */
+       } else {
+               /*
+                * Perform an interactive restore
+                */
+       
+               InteractiveRestore(f, &vol);
+       }
+
+       exit(0);
+}
+
+/*
+ * Read the dump header, which is at the beginning of every dump
+ */
+
+static int
+ReadDumpHeader(FILE *f, struct DumpHeader *header)
+{
+       unsigned int magic;
+       int tag, i;
+
+       if (getc(f) != D_DUMPHEADER ||
+           ReadInt32(f, &magic) || ReadInt32(f, (unsigned int *)
+                                             &header->version) ||
+           magic != DUMPBEGINMAGIC) {
+               if (verbose)
+                       fprintf(stderr, "Couldn't find dump magic numbers\n");
+               return -1;
+       }
+
+       header->volumeId = 0;
+       header->nDumpTimes = 0;
+
+       while ((tag = getc(f)) > D_MAX && tag != EOF) {
+               unsigned short length;
+               switch (tag) {
+               case 'v':
+                       if (ReadInt32(f, &header->volumeId)) {
+                               if (verbose)
+                                       fprintf(stderr, "Failed to read "
+                                               "volumeId\n");
+                               return -1;
+                       }
+                       break;
+               case 'n':
+                       if (ReadString(f, header->volumeName,
+                                      sizeof(header->volumeName))) {
+                               if (verbose)
+                                       fprintf(stderr, "Failed to read "
+                                               "volume name\n");
+                               return -1;
+                       }
+                       break;
+               case 't':
+                       if (ReadInt16(f, &length)) {
+                               if (verbose)
+                                       fprintf(stderr, "Failed to read "
+                                               "dump time array length\n");
+                               return -1;
+                       }
+                       header->nDumpTimes = (length >> 1);
+                       for (i = 0; i < header->nDumpTimes; i++)
+                               if (ReadInt32(f, (unsigned int *)
+                                             &header->dumpTimes[i].from) ||
+                                   ReadInt32(f, (unsigned int *)
+                                             &header->dumpTimes[i].to)) {
+                                       if (verbose)
+                                               fprintf(stderr, "Failed to "
+                                                       "read dump times\n");
+                                       return -1;
+                               }
+                       break;
+               default:
+                       if (verbose)
+                               fprintf(stderr, "Unknown dump tag \"%c\"\n",
+                                       tag);
+                       return -1;
+               }
+       }
+
+       if (!header->volumeId || !header->nDumpTimes) {
+               if (verbose) 
+                       fprintf(stderr, "We didn't get a volume Id or "
+                               "dump times listing\n");
+               return 1;
+       }
+
+       ungetc(tag, f);
+       return 0;
+}
+
+/*
+ * Read the volume header; this is the information stored in VolumeDiskData.
+ *
+ * I'm not sure we need all of this, but read it in just in case.
+ */
+
+static int
+ReadVolumeHeader(FILE *f, VolumeDiskData *vol)
+{
+       int tag;
+       unsigned int trash;
+       memset((void *) vol, 0, sizeof(*vol));
+
+       while ((tag = getc(f)) > D_MAX && tag != EOF) {
+               switch (tag) {
+               case 'i':
+                       if (ReadInt32(f, &vol->id))
+                               return -1;
+                       break;
+               case 'v':
+                       if (ReadInt32(f, &trash))
+                               return -1;
+                       break;
+               case 'n':
+                       if (ReadString(f, vol->name, sizeof(vol->name)))
+                               return -1;
+                       break;
+               case 's':
+                       vol->inService = getc(f);
+                       break;
+               case 'b':
+                       vol->blessed = getc(f);
+                       break;
+               case 'u':
+                       if (ReadInt32(f, &vol->uniquifier))
+                               return -1;
+                       break;
+               case 't':
+                       vol->type = getc(f);
+                       break;
+               case 'p':
+                       if (ReadInt32(f, &vol->parentId))
+                               return -1;
+                       break;
+               case 'c':
+                       if (ReadInt32(f, &vol->cloneId))
+                               return -1;
+                       break;
+               case 'q':
+                       if (ReadInt32(f, (uint32_t *) &vol->maxquota))
+                               return -1;
+                       break;
+               case 'm':
+                       if (ReadInt32(f, (uint32_t *) &vol->minquota))
+                               return -1;
+                       break;
+               case 'd':
+                       if (ReadInt32(f, (uint32_t *) &vol->diskused))
+                               return -1;
+                       break;
+               case 'f':
+                       if (ReadInt32(f, (uint32_t *) &vol->filecount))
+                               return -1;
+                       break;
+               case 'a':
+                       if (ReadInt32(f, &vol->accountNumber))
+                               return -1;
+                       break;
+               case 'o':
+                       if (ReadInt32(f, &vol->owner))
+                               return -1;
+                       break;
+               case 'C':
+                       if (ReadInt32(f, &vol->creationDate))
+                               return -1;
+                       break;
+               case 'A':
+                       if (ReadInt32(f, &vol->accessDate))
+                               return -1;
+                       break;
+               case 'U':
+                       if (ReadInt32(f, &vol->updateDate))
+                               return -1;
+                       break;
+               case 'E':
+                       if (ReadInt32(f, &vol->expirationDate))
+                               return -1;
+                       break;
+               case 'B':
+                       if (ReadInt32(f, &vol->backupDate))
+                               return -1;
+                       break;
+               case 'O':
+                       if (ReadString(f, vol->offlineMessage,
+                                      sizeof(vol->offlineMessage)))
+                               return -1;
+                       break;
+               case 'M':
+                       if (ReadString(f, (char *) vol->stat_reads, VMSGSIZE))
+                               return -1;
+                       break;
+               case 'W': {
+                       unsigned short length;
+                       int i;
+                       unsigned int data;
+                       if (ReadInt16(f, &length))
+                               return -1;
+                       for (i = 0; i < length; i++) {
+                               if (ReadInt32(f, &data))
+                                       return -1;
+                               if (i < sizeof(vol->weekUse) /
+                                              sizeof(vol->weekUse[0]))
+                                       vol->weekUse[i] = data;
+                       }
+                       break;
+               }
+               case 'D':
+                       if (ReadInt32(f, &vol->dayUseDate))
+                               return -1;
+                       break;
+               case 'Z':
+                       if (ReadInt32(f, (uint32_t *) &vol->dayUse))
+                               return -1;
+                       break;
+#ifdef RESIDENCY
+               case 'R': {
+                       unsigned short length;
+                       int i;
+                       unsigned int data;
+
+                       if (ReadInt16(f, &length))
+                               return -1;
+                       for (i = 0; i < length; i++) {
+                               if (ReadInt32(f, &data))
+                                       return -1;
+                               if (i < sizeof(vol->DesiredInfo.DesiredResidencyWords) /
+                                       sizeof(vol->DesiredInfo.DesiredResidencyWords[0]))
+                                       vol->DesiredInfo.DesiredResidencyWords[i] = data;
+                       }
+                       break;
+               }
+               case 'S': {
+                       unsigned short length;
+                       int i;
+                       unsigned int data;
+
+                       if (ReadInt16(f, &length))
+                               return -1;
+                       for (i = 0; i < length; i++) {
+                               if (ReadInt32(f, &data))
+                                       return -1;
+                               if (i < sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords) /
+                                       sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords[0]))
+                                       vol->UnDesiredInfo.UnDesiredResidencyWords[i] = data;
+                       }
+                       break;
+               }
+#endif
+               default:
+                       if (verbose)
+                               fprintf(stderr, "Unknown dump tag \"%c\"\n",
+                                       tag);
+                       return -1;
+               }
+       }
+
+       ungetc(tag, f);
+       return 0;
+}
+
+/*
+ * Scan all our vnode entries, and build indexing information.
+ */
+
+static int
+ScanVnodes(FILE *f, VolumeDiskData *vol, int sizescan)
+{
+       int vnodeNumber;
+       int tag;
+       int numFileVnodes = 0;
+       int numDirVnodes = 0;
+       unsigned char buf[SIZEOF_LARGEDISKVNODE];
+       struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
+       long offset, oldoffset;
+       struct vnodeData *vdata;
+       unsigned int length;
+
+       tag = getc(f);
+
+       while (tag == D_VNODE) {
+
+               offset = 0;
+               length = 0;
+               vnode->type = -1;
+               vnode->length = -1;
+
+               if (ReadInt32(f, (uint32_t *) &vnodeNumber))
+               {
+                       fprintf(stderr, "failed int32 for 'vnodenum'\n");
+                       return -1;
+               }
+
+               if (ReadInt32(f, &vnode->uniquifier))
+               {
+                       fprintf(stderr, "failed int32 for 'uniquifier'\n");
+                       return -1;
+               }
+               
+               if (verbose > 1 && !sizescan)
+                       printf("Got vnode %d\n", vnodeNumber);
+               
+               while ((tag = getc(f)) > D_MAX && tag != EOF)
+                       switch (tag) {
+                       case 't':
+                               vnode->type = (VnodeType) getc(f);
+                               break;
+                       case 'l':
+                               {
+                                       unsigned short tmp;
+                                       if (ReadInt16(f, &tmp))
+                                       {
+                                               fprintf(stderr, "failed int16 for 'l'\n");
+                                               return -1;
+                                       }
+                                       vnode->linkCount = tmp;
+                               }
+                               break;
+                       case 'v':
+                               if (ReadInt32(f, &vnode->dataVersion))
+                               {
+                                       fprintf(stderr, "failed int32 for 'v'\n");
+                                       return -1;
+                               }
+                               break;
+                       case 'm':
+                               if (ReadInt32(f, (uint32_t *) &vnode->unixModifyTime))
+                               {
+                                       fprintf(stderr, "failed int32 for 'm'\n");
+                                       return -1;
+                               }
+                               break;
+                       case 's':
+                               if (ReadInt32(f, (uint32_t *) &vnode->serverModifyTime))
+                               {
+                                       fprintf(stderr, "failed int32 for 's'\n");
+                                       return -1;
+                               }
+                               break;
+                       case 'a':
+                               if (ReadInt32(f, &vnode->author))
+                               {
+                                       fprintf(stderr, "failed int32 for 'a'\n");
+                                       return -1;
+                               }
+                               break;
+                       case 'o':
+                               if (ReadInt32(f, &vnode->owner))
+                               {
+                                       fprintf(stderr, "failed int32 for 'o'\n");
+                                       return -1;
+                               }
+                               break;
+                       case 'g':
+                               if (ReadInt32(f, (uint32_t *) &vnode->group))
+                               {
+                                       fprintf(stderr, "failed int32 for 'g'\n");
+                                       return -1;
+                               }
+                               break;
+                       case 'b': {
+                               unsigned short modeBits;
+                               if (ReadInt16(f, &modeBits))
+                                       return -1;
+                               vnode->modeBits = modeBits;
+                               break;
+                       }
+                       case 'p':
+                               if (ReadInt32(f, &vnode->parent))
+                               {
+                                       fprintf(stderr, "failed int32 for 'p'\n");
+                                       return -1;
+                               }
+                               break;
+#ifdef RESIDENCY
+                       case 'N':
+                               if (ReadInt32(f, &vnode->NextVnodeId))
+                               {
+                                       fprintf(stderr, "failed int32 for 'N'\n");
+                                       return -1;
+                               }
+                               break;
+                       case 'R':
+                               if (ReadInt32(f, &VLkp_Residencies(vnode)))
+                               {
+                                       fprintf(stderr, "failed int32 for 'R'\n");
+                                       return -1;
+                               }
+                               break;
+#endif
+                       case 'S':
+                               if (ReadInt32(f, &vnode->length))
+                               {
+                                       fprintf(stderr, "failed int32 for 'S'\n");
+                                       return -1;
+                               }
+                               break;
+                       case 'F':
+                               if (ReadInt32(f, (uint32_t *) &vnode->vn_ino_lo))
+                                       return -1;
+                               break;
+                       case 'A':
+                               if (ReadByteString(f,
+                                               (void *)VVnodeDiskACL(vnode),
+                                               VAclDiskSize(vnode)))
+                               {
+                                       fprintf(stderr, "failed readbystring for 'A'\n");
+                                       return -1;
+                               }
+#if 0
+                               acl_NtohACL(VVnodeDiskACL(vnode));
+#endif
+                               break;
+#ifdef RESIDENCY 
+                       case 'h':
+                               if (ReadInt32(f, &vnode->length_hi))
+                               {
+                                       fprintf(stderr, "failed int32 for 'h'\n");
+                                       return -1;
+                               }
+#endif
+                       case 'f':
+                               if (verbose > 1 && ! sizescan)
+                                       printf("We have file data!\n");
+                               if (ReadInt32(f, &length))
+                               {
+                                       fprintf(stderr, "failed int32 for 'f'\n");
+                                       return -1;
+                               }
+                               vnode->length = length;
+                               offset = ftell(f);
+                               fseek(f, length, SEEK_CUR);
+                               break;
+                       default:
+                               if (verbose)
+                               fprintf(stderr, "Unknown dump tag \"%c\"\n",
+                                       tag);
+                       return -1;
+               }
+
+               /*
+                * If we're doing an incremental restore, then vnodes
+                * will be listed in the dump, but won't contain any
+                * vnode information at all (I don't know why they're
+                * included _at all_).  If we get one of these vnodes, then
+                * just skip it (because we can't do anything with it.
+                */
+
+               if (vnode->type == -1)
+                       continue;
+
+#ifdef RESIDENCY
+               if (verbose > 1 && vnode->type == vFidLookup && ! sizescan) {
+                       printf("This is an auxiliary vnode (lookup) for vnode %d, residency %d\n",
+                               VLkp_ParentVnodeId(vnode),
+                               VLkp_Residencies(vnode));
+                       if (DumpVnodeFile(stdout, vnode, vol))
+                               return -1;
+               }
+
+               if (verbose > 1 && vnode->type == vAccessHistory && ! sizescan)
+                       printf("This is an auxiliary vnode (history) for vnode %d\n",
+                               VLkp_ParentVnodeId(vnode));
+#endif
+
+               if (vnode->type == vDirectory)
+                       numDirVnodes++;
+               else
+                       numFileVnodes++;
+
+               /*
+                * We know now all we would ever know about the vnode;
+                * insert it into our hash table (but only if we're not
+                * doing a vnode scan).
+                */
+
+               if (!sizescan) {
+
+                       vdata = InsertVnode(vnodeNumber, vnode);
+
+                       if (vdata == NULL) {
+                               if (verbose)
+                                       fprintf(stderr, "Failed to insert "
+                                               "vnode into hash table");
+                               return -1;
+                       }
+
+                       vdata->dumpdata = offset;
+                       vdata->datalength = length;
+
+                       /*
+                        * Save directory data, since we'll need it later.
+                        */
+
+                       if (vnode->type == vDirectory && length) {
+
+                               vdata->filedata = malloc(length);
+
+                               if (!vdata->filedata) {
+                                       if (verbose)
+                                               fprintf(stderr, "Unable to "
+                                                       "allocate space for "
+                                                       "file data (%d)\n",
+                                                       length);
+                                       return -1;
+                               }
+
+                               oldoffset = ftell(f);
+                               fseek(f, offset, SEEK_SET);
+
+                               if (fread(vdata->filedata, length, 1, f) != 1) {
+                                       if (verbose)
+                                               fprintf(stderr, "Unable to "
+                                                       "read in file data!\n");
+                                       return -1;
+                               }
+
+                               fseek(f, oldoffset, SEEK_SET);
+                       } else if (vnode->type == vDirectory)
+                               /*
+                                * Warn the user we may not have all directory
+                                * vnodes
+                                */
+                               numNoDirData++;
+               }
+       }
+
+       ungetc(tag, f);
+
+       if (!sizescan) {
+
+               numLargeVnodes = numDirVnodes;
+               numSmallVnodes = numFileVnodes;
+
+       } else {
+               LargeVnodeIndex = (struct vnodeData **)
+                                       malloc(numDirVnodes *
+                                               sizeof(struct vnodeData));
+               SmallVnodeIndex = (struct vnodeData **)
+                                       malloc(numFileVnodes *
+                                               sizeof(struct vnodeData));
+               
+               if (LargeVnodeIndex == NULL || SmallVnodeIndex == NULL) {
+                       if (verbose)
+                               fprintf(stderr, "Unable to allocate space "
+                                       "for vnode tables\n");
+                       return -1;
+               }
+       }
+
+       if (verbose)
+               fprintf(stderr,"%s vnode scan completed\n",
+                       sizescan ? "Primary" : "Secondary");
+
+       return 0;
+}
+
+/*
+ * Perform an interactive restore
+ *
+ * Parsing the directory information is a pain, but other than that
+ * we just use the other tools we already have in here.
+ */
+
+static void
+InteractiveRestore(FILE *f, VolumeDiskData *vol)
+{
+       struct vnodeData *vdatacwd;     /* Vnode data for our current dir */
+       char cmdbuf[256];
+       int argc;
+       char **argv;
+
+       /*
+        * Let's see if we can at least get the data for our root directory.
+        * If we can't, there's no way we can do an interactive restore.
+        */
+
+       if ((vdatacwd = GetVnode(1)) == NULL) {
+               fprintf(stderr, "No entry for our root vnode!  Aborting\n");
+               return;
+       }
+
+       if (! vdatacwd->filedata) {
+               fprintf(stderr, "There is no directory data for the root "
+                       "vnode (1.1).  An interactive\nrestore is not "
+                       "possible.\n");
+               return;
+       }
+
+       /*
+        * If you're doing a selective dump correctly, then you should get all
+        * directory vnode data.  But just in case you didn't, let the user
+        * know there may be a problem.
+        */
+
+       if (numNoDirData)
+               fprintf(stderr, "WARNING: %d directory vnodes had no file "
+                       "data.  An interactive restore\nmay not be possible\n",
+                       numNoDirData);
+
+       printf("> ");
+       while (fgets(cmdbuf, 256, stdin)) {
+
+               cmdbuf[strlen(cmdbuf) - 1] = '\0';
+
+               if (strlen(cmdbuf) == 0) {
+                       printf("> ");
+                       continue;
+               }
+
+               MakeArgv(cmdbuf, &argc, &argv);
+
+               if (strcmp(argv[0], "ls") == 0) {
+                       DirectoryList(argc, argv, vdatacwd, vol);
+               } else if (strcmp(argv[0], "cd") == 0) {
+                       struct vnodeData *newvdata;
+
+                       newvdata = ChangeDirectory(argc, argv, vdatacwd);
+
+                       if (newvdata)
+                               vdatacwd = newvdata;
+               } else if (strcmp(argv[0], "file") == 0) {
+                       DumpAllFiles(argc, argv, vdatacwd, vol);
+               } else if (strcmp(argv[0], "cp") == 0) {
+                       CopyFile(argc, argv, vdatacwd, f);
+               } else if (strcmp(argv[0], "vcp") == 0) {
+                       CopyVnode(argc, argv, f);
+               } else if (strcmp(argv[0], "quit") == 0 ||
+                          strcmp(argv[0], "exit") == 0)
+                       break;
+               else if (strcmp(argv[0], "?") == 0 ||
+                        strcmp(argv[0], "help") == 0) {
+                       printf("Valid commands are:\n");
+                       printf("\tls\t\tList current directory\n");
+                       printf("\tcd\t\tChange current directory\n");
+                       printf("\tcp\t\tCopy file from dump\n");
+                       printf("\tvcp\t\tCopy file from dump (via vnode)\n");
+#ifdef RESIDENCY
+                       printf("\tfile\t\tList residency filenames\n");
+#endif /* RESIDENCY */
+                       printf("\tquit | exit\tExit program\n");
+                       printf("\thelp | ?\tBrief help\n");
+               } else 
+                       fprintf(stderr, "Unknown command, \"%s\", enter "
+                               "\"help\" for a list of commands.\n",
+                               argv[0]);
+               
+               printf("> ");
+       }
+
+       return;
+}
+
+/*
+ * Do a listing of all files in a directory.  Sigh, I wish this wasn't
+ * so complicated.
+ *
+ * With the reorganizing, this is just a front-end to DirListInternal()
+ */
+
+static void
+DirectoryList(int argc, char **argv, struct vnodeData *vdata,
+             VolumeDiskData *vol)
+{
+       int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
+       int c;
+
+       optind = 1;
+
+       while ((c = getopt(argc, argv, "liFRs")) != EOF)
+               switch (c) {
+               case 'l':
+                       lflag++;
+                       break;
+               case 'i':
+                       iflag++;
+                       break;
+               case 'F':
+                       Fflag++;
+                       break;
+               case 'R':
+                       Rflag++;
+               case 's':
+                       sflag++;
+                       break;
+               case '?':
+               default:
+                       errflg++;
+               }
+
+       if (errflg) {
+               fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
+                       argv[0]);
+               return;
+       }
+
+       DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
+                       Fflag, Rflag, 1, vol, NULL);
+
+       return;
+}
+
+/*
+ * Function that does the REAL work in terms of directory listing
+ */
+
+static void
+DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
+               int lflag, int iflag, int Fflag, int Rflag, int verbose,
+               VolumeDiskData *vol, char *path)
+{
+       struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
+       struct DirCursor cursor;
+       struct vnodeData *lvdata;
+
+       int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
+       int numrecurse = 0;
+               
+       if (! vdata->filedata) {
+               fprintf(stderr, "There is no vnode data for this "
+                       "directory!\n");
+               return;
+       }
+
+       ResetDirCursor(&cursor, vdata);
+
+       /*
+        * Scan through the whole directory
+        */
+
+       while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
+
+               /*
+                * If we didn't get any filenames on the command line,
+                * get them all.
+                */
+
+               if (numpathnames == 0) {
+                       eplist = realloc(eplist, sizeof(struct DirEntry *) *
+                                        ++numentries);
+                       eplist[numentries - 1] = ep;
+                       if (strlen(ep->name) > longestname)
+                               longestname = strlen(ep->name);
+                       if (Rflag)
+                               if ((lvdata = GetVnode(ntohl(ep->fid.vnode))) &&
+                                   lvdata->vnode->type == vDirectory &&
+                                   !(strcmp(ep->name, ".") == 0 ||
+                                     strcmp(ep->name, "..") == 0)) {
+                                       eprecurse = realloc(eprecurse,
+                                               sizeof(struct DirEntry *) *
+                                               ++numrecurse);
+                                       eprecurse[numrecurse - 1] = ep;
+                               }
+
+               } else {
+                       /*
+                        * Do glob matching via fnmatch()
+                        */
+
+                       for (i = 0; i < numpathnames; i++)
+                               if (fnmatch(pathnames[i], ep->name,
+                                               FNM_PATHNAME) == 0) {
+                                       eplist = realloc(eplist,
+                                                sizeof(struct DirEntry *) *
+                                                ++numentries);
+                                       eplist[numentries - 1] = ep;
+                                       if (strlen(ep->name) > longestname)
+                                               longestname = strlen(ep->name);
+                                       if (Rflag)
+                                               if ((lvdata =
+                                            GetVnode(ntohl(ep->fid.vnode))) &&
+                                                   lvdata->vnode->type ==
+                                                               vDirectory &&
+                                              !(strcmp(ep->name, ".") == 0 ||
+                                                strcmp(ep->name, "..") == 0)) {
+                                                       eprecurse =
+                                                            realloc(eprecurse,
+                                               sizeof(struct DirEntry *) *
+                                                               ++numrecurse);
+                                                eprecurse[numrecurse - 1] = ep;
+                                               }
+                                       break;
+                               }
+               }
+       }
+
+       qsort((void *) eplist, numentries, sizeof(struct DirEntry *),
+             CompareDirEntry);
+
+       if (Rflag && eprecurse)
+               qsort((void *) eprecurse, numrecurse,
+                     sizeof(struct DirEntry *), CompareDirEntry);
+       /*
+        * We don't have to do column printing if we have the -l or the -i
+        * options.  Sigh, column printing is WAY TOO FUCKING COMPLICATED!
+        */
+
+       if (!lflag && !iflag) {
+               char c;
+
+               if (Fflag)
+                       longestname++;
+
+               longestname++;
+
+               numcols = termsize / longestname ? termsize / longestname : 1;
+               numrows = numentries / numcols +
+                       (numentries % numcols ? 1 : 0);
+
+               for (i = 0; i < numrows; i++) {
+                       col = 0;
+                       while (col < numcols && (i + col * numrows) <
+                                                               numentries) {
+                               ep = eplist[i + col++ * numrows];
+                               if (Fflag) {
+                                       if (!(lvdata =
+                                              GetVnode(ntohl(ep->fid.vnode))))
+                                               c = ' ';
+                                       else if (lvdata->vnode->type ==
+                                                  vDirectory)
+                                               c = '/';
+                                       else if (lvdata->vnode->type ==
+                                                  vSymlink)
+                                               c = '@';
+                                       else if (lvdata->vnode->modeBits &
+                                                0111 != 0)
+                                               c = '*';
+                                       else
+                                               c = ' ';
+                               printf("%s%-*c", ep->name,
+                                      longestname - strlen(ep->name), c);
+                               } else
+                                       printf("%-*s", longestname, ep->name);
+                       }
+
+                       printf("\n");
+               }
+       } else if (iflag)
+               for (i = 0; i < numentries; i++)
+                       if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
+                               printf("%d.0.0\t%s\n",
+                                      vol->parentId ? vol->parentId : vol->id,
+                                      eplist[i]->name);
+                       else
+                               if (path)
+                                       printf("%d.%d.%d\t%s/%s\n",
+                                              vol->id,
+                                              ntohl(eplist[i]->fid.vnode),
+                                              ntohl(eplist[i]->fid.vunique),
+                                              path, eplist[i]->name);
+                               else
+                                       printf("%d.%d.%d\t%s\n",
+                                              vol->id,
+                                              ntohl(eplist[i]->fid.vnode),
+                                              ntohl(eplist[i]->fid.vunique),
+                                              eplist[i]->name);
+       else if (lflag) {
+               for (i = 0; i < numentries; i++)
+                       if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
+                               printf("----------   0 0        "
+                                      "0                 0 %s\n",
+                                              eplist[i]->name);
+                       else {
+                               switch (lvdata->vnode->type) {
+                               case vDirectory:
+                                       printf("d");
+                                       break;
+                               case vSymlink:
+                                       printf("l");
+                                       break;
+                               default:
+                                       printf("-");
+                               }
+
+                               for (j = 8; j >= 0; j--) {
+                                       if (lvdata->vnode->modeBits & (1 << j))
+                                               switch (j % 3) {
+                                                       case 2: printf("r");
+                                                               break;
+                                                       case 1: printf("w");
+                                                               break;
+                                                       case 0: printf("x");
+                                               }
+                                       else
+                                               printf("-");
+                               }
+
+                               printf(" %-3d %-8d %-8d %10d %s\n",
+                                      lvdata->vnode->linkCount,
+                                      lvdata->vnode->owner,
+                                      lvdata->vnode->group,
+                                      lvdata->vnode->length,
+                                      eplist[i]->name);
+                       }
+       }
+
+       free(eplist);
+
+       if (Rflag && eprecurse) {
+               char *lpath;
+               lpath = NULL;
+               for (i = 0; i < numrecurse; i++) {
+                       if (verbose)
+                               printf("\n%s:\n", eprecurse[i]->name);
+                       if (path) {
+                               lpath = malloc(strlen(path) +
+                                              strlen(eprecurse[i]->name) + 2);
+                               if (lpath)
+                                       sprintf(lpath, "%s/%s", path,
+                                               eprecurse[i]->name);
+                       }
+                       DirListInternal(
+                                     GetVnode(ntohl(eprecurse[i]->fid.vnode)),
+                                       NULL, 0, lflag, iflag, Fflag, Rflag,
+                                       verbose, vol, lpath);
+                       if (lpath) {
+                               free(lpath);
+                               lpath = NULL;
+                       }
+               }
+       }
+
+       if (eprecurse)
+               free(eprecurse);
+
+       return;
+}
+
+
+/*
+ * Directory name comparison function, used by qsort
+ */
+
+static int
+CompareDirEntry(const void *e1, const void *e2)
+{
+       struct DirEntry **ep1 = (struct DirEntry **) e1;
+       struct DirEntry **ep2 = (struct DirEntry **) e2;
+
+       return strcmp((*ep1)->name, (*ep2)->name);
+}
+
+/*
+ * Change a directory.  Return a pointer to our new vdata structure for
+ * this directory.
+ */
+
+static struct vnodeData *
+ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
+{
+       struct vnodeData *newvdatacwd;
+
+       if (argc != 2) {
+               fprintf(stderr, "Usage: %s directory\n", argv[0]);
+               return NULL;
+       }
+
+       if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
+               return NULL;
+
+       if (newvdatacwd->vnode->type != vDirectory) {
+               fprintf(stderr, "%s: Not a directory\n", argv[1]);
+               return NULL;
+       }
+
+       if (newvdatacwd->filedata == NULL) {
+               fprintf(stderr, "%s: No directory data found.\n", argv[1]);
+               return NULL;
+       }
+
+       return newvdatacwd;
+}
+
+/*
+ * Copy a file from out of the dump file
+ */
+
+#define COPYBUFSIZE 8192
+
+static void
+CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE *f)
+{
+       struct vnodeData *vdata;
+       FILE *out;
+       long cur = 0;
+       int bytes, ret;
+       char buffer[COPYBUFSIZE];
+
+       if (argc != 3) {
+               fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
+               return;
+       }
+
+       if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
+               return;
+
+       if (vdata->dumpdata == 0) {
+               fprintf(stderr, "File %s has no data in dump file\n",
+                       argv[1]);
+               return;
+       }
+
+       if ((out = fopen(argv[2], "wb")) == NULL) {
+               fprintf(stderr, "Open of %s failed: %s\n", argv[2],
+                       strerror(errno));
+               return;
+       }
+
+       if (fseek(f, vdata->dumpdata, SEEK_SET)) {
+               fprintf(stderr, "Seek failed: %s\n", strerror(errno));
+               fclose(out);
+               return;
+       }
+
+       while (cur < vdata->datalength) {
+
+               bytes = cur + COPYBUFSIZE < vdata->datalength ?
+                       COPYBUFSIZE : vdata->datalength - cur;
+
+               ret = fread(buffer, sizeof(char), bytes, f);
+               if (ret != bytes) {
+                       if (ret != 0)
+                               fprintf(stderr, "Short read (expected %d, "
+                                       "got %d)\n", bytes, ret);
+                       else
+                               fprintf(stderr, "Error during read: %s\n",
+                                       strerror(errno));
+                       fclose(out);
+                       return;
+               }
+
+               ret = fwrite(buffer, sizeof(char), bytes, out);
+               if (ret != bytes) {
+                       if (ret != 0)
+                               fprintf(stderr, "Short write (expected %d, "
+                                       "got %d)\n", bytes, ret);
+                       else
+                               fprintf(stderr, "Error during write: %s\n",
+                                       strerror(errno));
+                       fclose(out);
+                       return;
+               }
+
+               cur += bytes;
+       }
+
+       fclose(out);
+}
+
+/*
+ * Copy a file from out of the dump file, by using the vnode
+ */
+
+static void
+CopyVnode(int argc, char *argv[], FILE *f)
+{
+       struct vnodeData *vdata;
+       FILE *out;
+       long cur = 0;
+       int bytes, ret;
+       char buffer[COPYBUFSIZE];
+       unsigned int vnode, uniquifier = 0;
+
+       if (argc != 3) {
+               fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n",
+                       argv[0]);
+               return;
+       }
+
+       ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
+
+       if (ret < 1) {
+               fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
+               return;
+       }
+
+       if (!(vdata = GetVnode(vnode))) {
+               fprintf(stderr, "Vnode %d not in dump file\n", vnode);
+               return;
+       }
+
+       if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
+               fprintf(stderr, "Specified uniquifier %d did not match "
+                       "uniquifier %d found in dump file!\n", uniquifier,
+                       vdata->vnode->uniquifier);
+               return;
+       }
+
+       if (vdata->dumpdata == 0) {
+               fprintf(stderr, "File %s has no data in dump file\n",
+                       argv[1]);
+               return;
+       }
+
+       if ((out = fopen(argv[2], "wb")) == NULL) {
+               fprintf(stderr, "Open of %s failed: %s\n", argv[2],
+                       strerror(errno));
+               return;
+       }
+
+       if (fseek(f, vdata->dumpdata, SEEK_SET)) {
+               fprintf(stderr, "Seek failed: %s\n", strerror(errno));
+               fclose(out);
+               return;
+       }
+
+       while (cur < vdata->datalength) {
+
+               bytes = cur + COPYBUFSIZE < vdata->datalength ?
+                       COPYBUFSIZE : vdata->datalength - cur;
+
+               ret = fread(buffer, sizeof(char), bytes, f);
+               if (ret != bytes) {
+                       if (ret != 0)
+                               fprintf(stderr, "Short read (expected %d, "
+                                       "got %d)\n", bytes, ret);
+                       else
+                               fprintf(stderr, "Error during read: %s\n",
+                                       strerror(errno));
+                       fclose(out);
+                       return;
+               }
+
+               ret = fwrite(buffer, sizeof(char), bytes, out);
+               if (ret != bytes) {
+                       if (ret != 0)
+                               fprintf(stderr, "Short write (expected %d, "
+                                       "got %d)\n", bytes, ret);
+                       else
+                               fprintf(stderr, "Error during write: %s\n",
+                                       strerror(errno));
+                       fclose(out);
+                       return;
+               }
+
+               cur += bytes;
+       }
+
+       fclose(out);
+}
+/*
+ * Dump all residency filenames associated with a file, or all files
+ * within a directory.
+ */
+
+static void
+DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
+            VolumeDiskData *vol)
+{
+#ifdef RESIDENCY
+       struct vnodeData *vdata, *nvdata;
+       struct DirCursor cursor;
+       struct DirEntry *ep;
+       FILE *f = stdout;
+       int c, i;
+       int dflag = 0, fflag = 0, errflg = 0;
+
+       optind = 1;
+
+       while ((c = getopt(argc, argv, "df:")) != EOF)
+               switch (c) {
+               case 'd':
+                       dflag++;
+                       break;
+               case 'f':
+                       if ((f = fopen(optarg, "a")) == NULL) {
+                               fprintf(stderr, "Cannot open \"%s\": %s\n",
+                                       optarg, strerror(errno));
+                               return;
+                       }
+                       fflag++;
+                       break;
+               case 'h':
+               case '?':
+               default:
+                       errflg++;
+               }
+       
+       if (errflg || argc == optind) {
+               fprintf(stderr, "Usage: %s [-d] [-f filename] file "
+                       "[file ...]\n", argv[0]);
+               if (fflag)
+                       fclose(f);
+               return;
+       }
+
+       for (i = optind; i < argc; i++) {
+
+               if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
+                       continue;
+
+               if (vdata->vnode->type == vDirectory && ! dflag) {
+                       
+                       ResetDirCursor(&cursor, vdata);
+
+                       while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
+
+                               if (!(nvdata =
+                                            GetVnode(ntohl(ep->fid.vnode)))) {
+                                       fprintf(stderr, "Cannot find vnode "
+                                               "entry for %s (%d)\n",
+                                               ep->name, ntohl(ep->fid.vnode));
+                                       continue;
+                               }
+
+
+                               if (!fflag) {
+                                       printf("Residency locations for %s:\n",
+                                       ep->name);
+
+                                       if (nvdata->dumpdata)
+                                               printf("Local disk (in dump "
+                                                      "file)\n");
+                               }
+
+                               DumpAllResidencies(f, nvdata, vol);
+                       
+                       }
+
+               } else {
+                       if (!fflag) {
+                               printf("Residency locations for %s:\n",
+                                      argv[i]);
+
+                               if (vdata->dumpdata)
+                                       printf("Local disk (in dump file)\n");
+                       }
+
+                       DumpAllResidencies(f, vdata, vol);
+               }
+       }
+
+       if (fflag)
+               fclose(f);
+#else /* RESIDENCY */
+       fprintf(stderr, "The \"file\" command is not available in the non-"
+               "MRAFS version of dumptool.\n");
+#endif /* RESIDENCY */
+       return;
+}
+
+/*
+ * Take a vnode, traverse the vnode chain, and dump out all files on
+ * all residencies corresponding to that parent vnode.
+ */
+
+#ifdef RESIDENCY
+static void
+DumpAllResidencies(FILE *f, struct vnodeData *vdata, struct VolumeDiskData *vol)
+{
+       unsigned int nextVnodeNum;
+
+       while (nextVnodeNum = vdata->vnode->NextVnodeId) {
+               if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
+                       fprintf(stderr, "We had a pointer to %lu in it's "
+                               "vnode chain, but there\nisn't a record of "
+                               "it!  The dump might be corrupt.\n",
+                               nextVnodeNum);
+                       return;
+               }
+
+               if (vdata->vnode->type == vFidLookup)
+                       DumpVnodeFile(f, vdata->vnode, vol);
+       }
+
+       return;
+}
+#endif
+
+
+/*
+ * Given a directory vnode and a filename, return the vnode corresponding
+ * to the file in that directory.
+ * 
+ * We now handle pathnames with directories in them.
+ */
+
+static struct vnodeData *
+FindFile(struct vnodeData *vdatacwd, char *filename)
+{
+       struct DirHeader *dhp;
+       struct DirEntry *ep;
+       int i, num;
+       struct vnodeData *vdata;
+       char *c, newstr[MAXPATHLEN];
+
+       if (! vdatacwd->filedata) {
+               fprintf(stderr, "There is no vnode data for this "
+                       "directory!\n");
+               return NULL;
+       }
+
+       /*
+        * If we have a "/" in here, look up the vnode data for the
+        * directory (everything before the "/") and use that as our
+        * current directory.  We automagically handle multiple directories
+        * by using FindFile recursively.
+        */
+
+       if ((c = strrchr(filename, '/')) != NULL) {
+
+               strncpy(newstr, filename, c - filename);
+               newstr[c - filename] = '\0';
+
+               if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
+                       return NULL;
+
+               if (vdatacwd->vnode->type != vDirectory) {
+                       fprintf(stderr, "%s: Not a directory\n", newstr);
+                       return NULL;
+               }
+
+               filename = c + 1;
+       }
+
+       dhp = (struct DirHeader *) vdatacwd->filedata;
+
+       i = DirHash(filename);
+
+       num = ntohs(dhp->hashTable[i]);
+
+       while (num) {
+               ep = (struct DirEntry *) (vdatacwd->filedata + (num * 32));
+               if (strcmp(ep->name, filename) == 0)
+                       break;
+               num = ntohs(ep->next);
+       }
+
+       if (! num) {
+               fprintf(stderr, "%s: No such file or directory\n", filename);
+               return NULL;
+       }
+
+       if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
+               fprintf(stderr, "%s: No vnode information for %lu found\n",
+                       filename, ntohl(ep->fid.vnode));
+               return NULL;
+       }
+
+       return vdata;
+}
+
+/*
+ * Reset a structure containing the current directory scan location
+ */
+
+static void
+ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
+{
+       struct DirHeader *dhp;
+
+       cursor->hashbucket = 0;
+
+       dhp = (struct DirHeader *) vdata->filedata;
+
+       cursor->entry = ntohs(dhp->hashTable[0]);
+}
+
+/*
+ * Given a cursor and a directory entry, return the next entry in the
+ * directory.
+ */
+
+static struct DirEntry *
+ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
+{
+       struct DirHeader *dhp;
+       struct DirEntry *ep;
+
+       dhp = (struct DirHeader *) vdata->filedata;
+
+       if (cursor->entry) {
+               ep = (struct DirEntry *) (vdata->filedata +
+                                                       (cursor->entry * 32));
+               cursor->entry = ntohs(ep->next);
+               return ep;
+       } else {
+               while (++(cursor->hashbucket) < NHASHENT) {
+                       cursor->entry =
+                               ntohs(dhp->hashTable[cursor->hashbucket]);
+                       if (cursor->entry) {
+                               ep = (struct DirEntry *) (vdata->filedata +
+                                                       (cursor->entry * 32));
+                               cursor->entry = ntohs(ep->next);
+                               return ep;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * Given a string, split it up into components a la Unix argc/argv.
+ *
+ * This code is most stolen from ftp.
+ */
+
+static void
+MakeArgv(char *string, int *argc, char ***argv)
+{
+       static char *largv[64];
+       char **la = largv;
+       char *s = string;
+       static char argbuf[256];
+       char *ap = argbuf;
+
+       *argc = 0;
+       *argv = largv;
+
+       while (*la++ = GetToken(s, &s, ap, &ap))
+               (*argc)++;
+}
+
+/*
+ * Return a pointer to the next token, and update the current string
+ * position.
+ */
+
+static char *
+GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
+{
+       char *sp = string;
+       char *ap = argbuf;
+       int got_one = 0;
+
+S0:
+       switch (*sp) {
+
+       case '\0':
+               goto OUTTOKEN;
+       
+       case ' ':
+       case '\t':
+               sp++; goto S0;
+       
+       default:
+               goto S1;
+       }
+
+S1:
+       switch (*sp) {
+
+       case ' ':
+       case '\t':
+       case '\0':
+               goto OUTTOKEN;  /* End of our token */
+
+       case '\\':
+               sp++; goto S2;  /* Get next character */
+
+       case '"':
+               sp++; goto S3;  /* Get quoted string */
+       
+       default:
+               *ap++ = *sp++;  /* Add a character to our token */
+               got_one = 1;
+               goto S1;
+       }
+
+S2:
+       switch (*sp) {
+
+       case '\0':
+               goto OUTTOKEN;
+
+       default:
+               *ap++ = *sp++;
+               got_one = 1;
+               goto S1;
+       }
+
+S3:
+       switch (*sp) {
+
+       case '\0':
+               goto OUTTOKEN;
+       
+       case '"':
+               sp++; goto S1;
+       
+       default:
+               *ap++ = *sp++;
+               got_one = 1;
+               goto S3;
+       }
+
+OUTTOKEN:
+       if (got_one)
+               *ap++ = '\0';
+       *nextargbuf = ap;               /* Update storage pointer */
+       *nexttoken = sp;                /* Update token pointer */
+
+       return got_one ? argbuf : NULL;
+}
+
+/*
+ * Insert vnodes into our hash table.
+ */
+
+static struct vnodeData *
+InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
+{
+       struct VnodeDiskObject *nvnode;
+       struct vnodeData *vdata;
+       static int curSmallVnodeIndex = 0;
+       static int curLargeVnodeIndex = 0;
+       struct vnodeData ***vnodeIndex;
+       int *curIndex;
+
+       nvnode = (struct VnodeDiskObject *) malloc(sizeof(struct VnodeDiskObject));
+
+       if (!nvnode) {
+               if (verbose)
+                       fprintf(stderr, "Unable to allocate space for vnode\n");
+               return NULL;
+       }
+
+       memcpy((void *) nvnode, (void *) vnode, sizeof(struct VnodeDiskObject));
+
+       if (vnodeNumber & 1) {
+               vnodeIndex = &LargeVnodeIndex;
+               curIndex = &curLargeVnodeIndex;
+       } else {
+               vnodeIndex = &SmallVnodeIndex;
+               curIndex = &curSmallVnodeIndex;
+       }
+
+       vdata = (struct vnodeData *) malloc(sizeof(struct vnodeData));
+
+       vdata->vnode = nvnode;
+       vdata->vnodeNumber = vnodeNumber;
+       vdata->dumpdata = 0;
+       vdata->filedata = 0;
+       vdata->datalength = 0;
+
+       (*vnodeIndex)[(*curIndex)++] = vdata;
+
+       return vdata;
+}
+
+/*
+ * Routine to retrieve a vnode from the hash table.
+ */
+
+static struct vnodeData *
+GetVnode(unsigned int vnodeNumber)
+{
+       struct vnodeData vnode, *vnodep, **tmp;
+
+       vnode.vnodeNumber = vnodeNumber;
+       vnodep = &vnode;
+
+       tmp = (struct vnodeData **)
+               bsearch((void *) &vnodep,
+                       vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
+                       vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
+                       sizeof(struct vnodeData *), CompareVnode);
+
+       return tmp ? *tmp : NULL;
+}
+
+/*
+ * Our comparator function for bsearch
+ */
+
+static int
+CompareVnode(const void *node1, const void *node2)
+{
+       struct vnodeData **vnode1 = (struct vnodeData **) node1;
+       struct vnodeData **vnode2 = (struct vnodeData **) node2;
+
+       if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
+               return 0;
+       else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
+               return 1;
+       else
+               return -1;
+}
+
+#ifdef RESIDENCY
+/*
+ * Dump out the filename corresponding to a particular vnode.
+ *
+ * This routine has the following dependancies:
+ *
+ * - Only will work on UFS filesystems at this point
+ * - Has to talk to the rsserver.
+ * - Can only determine UFS algorithm type when run on the same machine
+ *   as the residency (unless you manually specify algorithm information)
+ */
+
+static int
+DumpVnodeFile(FILE *f, struct VnodeDiskObject *vnode, VolumeDiskData *vol)
+{
+       static int rscache = 0;
+       static rsaccessinfoList rsnlist = {0, 0};
+       char MountPoint[MAXPATHLEN + 1];
+       char FileName[MAXPATHLEN + 1];
+       unsigned int Size, Level[4];
+       unsigned int DeviceTag, Algorithm;
+       FileSystems *FSInfo;
+       int i, found, FSType, rsindex;
+
+       /*
+        * Maybe we found out something about this residency via the
+        * command-line; check that first.
+        */
+
+       rsindex = ffs(VLkp_Residencies(vnode)) - 1;
+
+       /*
+        * We need to get information from the rsserver (so we can
+        * find out the device tag for a given residency).  If we
+        * haven't cached that, talk to the rsserver to get it.
+        * If we have info about this already, then don't talk to
+        * the rsserver (this lets us still do disaster recovery if
+        * MR-AFS is completely hosed).
+        */
+
+       if (! rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
+               int code;
+
+               code = ServerInitResidencyConnection();
+
+               if (code) {
+                       fprintf(stderr, "ServerInitResidencyConnection failed "
+                               "with code %d\n", code);
+                       return -1;
+               }
+
+               code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
+
+               if (code) {
+                       fprintf(stderr, "rs_GetResidencySummary failed "
+                               "with code %d\n", code);
+                       return -1;
+               }
+
+               rscache = 1;
+       }
+
+       /*
+        * For a given residency (as specified in the vnode),
+        * find out it's device tag number, either via the rsserver
+        * or via the command line.
+        */
+
+       if (rscmdlineinfo[rsindex].DeviceTag != -1) {
+               DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
+               found = 1;
+       } else
+               for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) &&
+                                                               (!found); i++) {
+                       if (rsnlist.rsaccessinfoList_val[i].id.residency ==
+                           VLkp_Residencies(vnode)) {
+                               found = 1;
+                               DeviceTag =
+                            rsnlist.rsaccessinfoList_val[i].devicetagnumber;
+                               break;
+                       }
+               }
+
+       if (! found) {
+               if (verbose)
+                       fprintf(stderr, "Unable to find residency %d in "
+                               "rsserver database, aborting\n",
+                               VLkp_Residencies(vnode));
+               return -1;
+       }
+
+       /*
+        * Okay, now we've got the DeviceTag ... which we can use to
+        * lookup the on-disk configuration information (which we
+        * assume is locally stored).  We also need the DeviceTag to
+        * print out which partition we're using (but that comes later).
+        *
+        * We lookup the on-disk configuration information by calling
+        * Ufs_GetFSInfo() to get the configuration information on the
+        * filesystems specified by the given DeviceTag.
+        *
+        * Before we call Ufs_GetFSInfo, check the command-line cache;
+        * if we got something via the command-line, don't go to disk.
+        */
+
+       if (rscmdlineinfo[rsindex].FSType == -1 &&
+           Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
+               if (verbose)
+                       fprintf(stderr, "Ufs_GetFSInfo failed for DeviceTag "
+                               "%d, Residency %d\n", DeviceTag,
+                               VLkp_Residencies(vnode));
+               return -1;
+       }
+
+       /*
+        * The FSInfo structure has the last two things we need: the
+        * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
+        * ends up being how many directories are being used on the
+        * residency filesystem).
+        *
+        * With these last two parameters, use routines stolen from
+        * ufsname to generate the filename.
+        *
+        * (Actually, I lied - we also need the "Size" parameter, which
+        * we can also get from FSInfo);
+        */
+
+       if (rscmdlineinfo[rsindex].FSType != -1) {
+               FSType = rscmdlineinfo[rsindex].FSType;
+               Algorithm = rscmdlineinfo[rsindex].Algorithm;
+               Size = rscmdlineinfo[rsindex].Size;
+       } else {
+               FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
+               Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
+               if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
+                       Size = 0;
+               else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
+                       Size = 1;
+               else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
+                       Size = 2;
+               else {
+                       if (verbose)
+                               fprintf(stderr, "Unknown directory size %d, "
+                                       "aborting\n",
+                                       FSInfo->FileSystems_u.UfsInterface.Directories[1]);
+                       return -1;
+               }
+       }
+
+       /*
+        * First, generate our mount point from the DeviceTag and
+        * FSType.
+        */
+
+       DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
+
+       /*
+        * Then, generate the "level" (directory bitmasks) from the
+        * file tags, size, and algorithm
+        */
+
+       UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
+                      Size, Level, VLkp_ParentVnodeId(vnode),
+                      VLkp_ParentUniquifierId(vnode));
+
+       /*
+        * Finally, take the above information and generate the
+        * corresponding filename (this macro ends up being a
+        * sprintf() call)
+        */
+
+       TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
+                  vol->parentId, VLkp_ParentVnodeId(vnode),
+                  VLkp_ParentUniquifierId(vnode), Algorithm);
+
+       fprintf(f, "%s\n", FileName);
+
+       return 0;
+}
+#endif
+
+/*
+ * Read a 16 bit integer in network order
+ */
+
+static int
+ReadInt16(FILE *f, unsigned short *s)
+{
+       unsigned short in;
+
+       if (fread((void *)&in, sizeof(in), 1, f) != 1) {
+               if (verbose)
+                       fprintf(stderr, "ReadInt16 failed!\n");
+               return -1;
+       }
+
+       *s = ntohs(in);
+
+       return 0;
+}
+
+
+/*
+ * Read a 32 bit integer in network order
+ */
+
+static int
+ReadInt32(FILE *f, unsigned int *i)
+{
+       unsigned int in;
+
+       if (fread((void *)&in, sizeof(in), 1, f) != 1) {
+               if (verbose)
+                       fprintf(stderr, "ReadInt32 failed!\n");
+               return -1;
+       }
+
+       *i = ntohl((unsigned long) in);
+
+       return 0;
+}
+
+/*
+ * Read a string from a dump file
+ */
+
+static int
+ReadString(FILE *f, char *string, int maxlen)
+{
+       int c;
+
+       while (maxlen--) {
+               if ((*string++ = getc(f)) == 0)
+                       break;
+       }
+
+       /*
+        * I'm not sure what the _hell_ this is supposed to do ...
+        * but it was in the original dump code
+        */
+
+       if (string[-1]) {
+               while ((c = getc(f)) && c != EOF);
+               string[-1] = 0;
+       }
+
+       return 0;
+}
+
+static int
+ReadByteString(FILE *f, void *s, int size)
+{
+       unsigned char *c = (unsigned char *) s;
+
+       while (size--)
+               *c++ = getc(f);
+       
+       return 0;
+}
+
+/*
+ * The directory hashing algorithm used by AFS
+ */
+
+DirHash (string)
+    register char *string; {
+    /* Hash a string to a number between 0 and NHASHENT. */
+    register unsigned char tc;
+    register int hval;
+    register int tval;
+    hval = 0;
+    while(tc=(*string++)) {
+        hval *= 173;
+        hval  += tc;
+    }
+    tval = hval & (NHASHENT-1);
+#ifdef AFS_CRAY_ENV     /* actually, any > 32 bit environment */
+    if (tval == 0) return tval;
+    else if (hval & 0x80000000) tval = NHASHENT-tval;
+#else /* AFS_CRAY_ENV */
+    if (tval == 0) return tval;
+    else if (hval < 0) tval = NHASHENT-tval;
+#endif /* AFS_CRAY_ENV */
+    return tval;
+}
+
+#ifdef RESIDENCY
+/*
+ * Sigh, we need this for the AFS libraries
+ */
+
+int
+LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
+         char *g, char *h, char *i, char *j, char *k)
+{
+       if (level <= 0) {
+               fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
+       }
+       return 0;
+}
+
+/*
+ * These are routines taken from AFS libraries and programs.  Most of
+ * them are from ufsname.c, but a few are from the dir library (the dir
+ * library has a bunch of hidden dependancies, so it's not suitable to
+ * include it outright).
+ */
+
+UfsEntropiesToTags(HighEntropy,LowEntropy,Algorithm,FileTag1,FileTag2)
+    uint32_t HighEntropy;
+    uint32_t LowEntropy;
+    uint32_t Algorithm;
+    uint32_t *FileTag1;
+    uint32_t *FileTag2;
+{
+    int i;
+
+    if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
+        return -1;
+    *FileTag1 = 0;
+    *FileTag2 = 0;
+    for (i=0;i<32;++i) {
+        if (UfsEntropy[Algorithm-1][i] < 32)
+           *FileTag1 |= ((HighEntropy & (1 << i)) == 0) ?
+               0 : 1 << UfsEntropy[Algorithm-1][i];
+       else
+           *FileTag2 |= ((HighEntropy & (1 << i)) == 0) ?
+               0 : 1 << (UfsEntropy[Algorithm-1][i] - 32);
+    }
+    for (i=32;i<64;++i) {
+        if (UfsEntropy[Algorithm-1][i] < 32)
+           *FileTag1 |=((LowEntropy & (1 << (i - 32))) == 0) ?
+               0 : 1 << UfsEntropy[Algorithm-1][i];
+       else
+           *FileTag2 |=((LowEntropy & (1 << (i - 32))) == 0) ?
+               0 : 1 << (UfsEntropy[Algorithm-1][i] - 32);
+    }
+    return 0;
+}
+
+uint32_t UfsTagsToHighEntropy(FileTag1,FileTag2,Algorithm)
+    uint32_t FileTag1;
+    uint32_t FileTag2;
+    uint32_t Algorithm;
+{
+    int i;
+    uint32_t Value;
+
+    Value = 0;
+    for (i=0;i<32;++i) {
+        if (UfsEntropy[Algorithm-1][i] < 32)
+           Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm-1][i]))
+                     == 0) ? 0: 1 << i;
+       else
+           Value |= ((FileTag2 & (1 << (UfsEntropy[Algorithm-1][i] - 
+                                        32))) == 0) ? 0: 1 << i;
+    }
+    return Value;
+}
+
+uint32_t UfsTagsToLowEntropy(FileTag1,FileTag2,Algorithm)
+    uint32_t FileTag1;
+    uint32_t FileTag2;
+    uint32_t Algorithm;
+{
+    int i;
+    uint32_t Value;
+
+    Value = 0;
+    for (i=32;i<64;++i) {
+        if (UfsEntropy[Algorithm-1][i] < 32)
+           Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm-1][i])) 
+                     == 0) ? 0: 1 << (i - 32);
+       else
+           Value |= ((FileTag2 & (1 << (UfsEntropy[Algorithm-1][i] -
+                                        32))) == 0) ? 0: 1 << (i - 32) ;
+    }
+    return Value;
+}
+
+UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode, Uniquifier)
+    uint32_t FileTag1;
+    uint32_t FileTag2;
+    uint32_t Algorithm;
+    uint32_t Size;
+    uint32_t Sections[4];
+    uint32_t vnode;
+    uint32_t Uniquifier;
+{
+    uint32_t HighEntropy;
+    uint32_t LowEntropy;
+
+    switch (Algorithm) {
+        case 1:
+            LowEntropy = UfsTagsToLowEntropy(
+                                FileTag1,
+                                FileTag2,
+                                Algorithm);
+            HighEntropy = UfsTagsToHighEntropy(
+                                FileTag1,
+                                FileTag2,
+                                Algorithm);
+            Sections[0] = HighEntropy % Directories[Size][0];
+            HighEntropy /= Directories[Size][0];
+            if (Directories[Size][1]) {
+                Sections[1] = HighEntropy % Directories[Size][1];
+                HighEntropy /= Directories[Size][1];
+                Sections[2] = HighEntropy;
+                Sections[3] = LowEntropy;
+            } else {
+                Sections[1] = HighEntropy;
+                Sections[2] = LowEntropy;
+            }
+            break;
+        case 2:
+            Sections[0] = FileTag1 & 0xff;
+            if (Directories[Size][1]) {
+                Sections[1] = Uniquifier & 0xff;
+                if (Directories[Size][1] == 16) Sections[1] &= 0xf;
+                Sections[2] = FileTag1;
+                Sections[3] = FileTag2;
+            } else {
+                Sections[1] = FileTag1;
+                Sections[2] = FileTag2;
+            }
+            break;
+        case 3:
+            Sections[0] = FileTag1 & 0xff;
+            if (Directories[Size][1]) {
+                Sections[1] = (vnode >> 1) & 0xff;
+                if (Directories[Size][1] == 16) Sections[1] &= 0xf;
+                Sections[2] = FileTag1;
+                Sections[3] = FileTag2;
+            } else {
+                Sections[1] = FileTag1;
+                Sections[2] = FileTag2;
+            }
+            break;
+        default:
+            fprintf(stderr,"UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
+            return -1;
+    }
+    return 0;
+}
+
+#include <afs/afscbdummies.h>
+#endif /* RESIDENCY */
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..6473117
--- /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: err.c,v 1.1 2002/01/22 19:54:40 hartmans Exp $");
+#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..31ca72c
--- /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: err.h,v 1.1 2002/01/22 19:54:41 hartmans Exp $ */
+
+#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/errx.c b/src/tests/errx.c
new file mode 100644 (file)
index 0000000..afedd0c
--- /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: errx.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#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..708f9b8
--- /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: exit-wo-close.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#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..2527efd
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# $Id: fcachesize-dir,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+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..44c2d45
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# $Id: fcachesize-file-small,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+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..55147c4
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# $Id: fcachesize-read-file,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+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..35f6dfd
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# $Id: fcachesize-write-file,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+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..e89dedb
--- /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: fhbench.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+
+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..84ddb5e
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: find-and-cat-netbsd,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+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..07014c8
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: find-linux,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+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..f7b7a69
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id: fs-flush,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+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..ae2c71f
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id: fs-sa-la,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+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_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");
+                       break;
+               case OP_TRUNCATE:
+                       down = lp->args[0] < lp->args[1];
+                       prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
+                           down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
+                       if (badoff >= lp->args[!down] &&
+                           badoff < lp->args[!!down])
+                               prt("\t******WWWW");
+                       break;
+               case OP_SKIPPED:
+                       prt("SKIPPED (no operation)");
+                       break;
+               default:
+                       prt("BOGUS LOG ENTRY (operation code = %d)!",
+                           lp->operation);
+               }
+               if (closeopen)
+                       prt("\n\t\tCLOSE/OPEN");
+               prt("\n");
+               i++;
+               if (i == LOGSIZE)
+                       i = 0;
+       }
+}
+
+
+void
+save_buffer(char *buffer, off_t bufferlength, int fd)
+{
+       off_t ret;
+       ssize_t byteswritten;
+
+       if (fd <= 0 || bufferlength == 0)
+               return;
+
+       if (bufferlength > SSIZE_MAX) {
+               prt("fsx flaw: overflow in save_buffer\n");
+               exit(67);
+       }
+       if (lite) {
+               off_t size_by_seek = lseek(fd, (off_t)0, L_XTND);
+               if (size_by_seek == (off_t)-1)
+                       prterr("save_buffer: lseek eof");
+               else if (bufferlength > size_by_seek) {
+                       warn("save_buffer: .fsxgood file too short... will save 0x%qx bytes instead of 0x%qx\n", (unsigned long long)size_by_seek,
+                            (unsigned long long)bufferlength);
+                       bufferlength = size_by_seek;
+               }
+       }
+
+       ret = lseek(fd, (off_t)0, SEEK_SET);
+       if (ret == (off_t)-1)
+               prterr("save_buffer: lseek 0");
+       
+       byteswritten = write(fd, buffer, (size_t)bufferlength);
+       if (byteswritten != bufferlength) {
+               if (byteswritten == -1)
+                       prterr("save_buffer write");
+               else
+                       warn("save_buffer: short write, 0x%x bytes instead of 0x%qx\n",
+                            (unsigned)byteswritten,
+                            (unsigned long long)bufferlength);
+       }
+}
+
+
+void
+report_failure(int status)
+{
+       logdump();
+       
+       if (fsxgoodfd) {
+               if (good_buf) {
+                       save_buffer(good_buf, file_size, fsxgoodfd);
+                       prt("Correct content saved for comparison\n");
+                       prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n",
+                           fname, fname);
+               }
+               close(fsxgoodfd);
+       }
+       exit(status);
+}
+
+
+#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
+                                       *(((unsigned char *)(cp)) + 1)))
+
+void
+check_buffers(unsigned offset, unsigned size)
+{
+       unsigned char c, t;
+       unsigned i = 0;
+       unsigned n = 0;
+       unsigned op = 0;
+       unsigned bad = 0;
+
+       if (bcmp(good_buf + offset, temp_buf, size) != 0) {
+               prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n",
+                   offset, size);
+               prt("OFFSET\tGOOD\tBAD\tRANGE\n");
+               while (size > 0) {
+                       c = good_buf[offset];
+                       t = temp_buf[i];
+                       if (c != t) {
+                               if (n == 0) {
+                                       bad = short_at(&temp_buf[i]);
+                                       prt("0x%5x\t0x%04x\t0x%04x", offset,
+                                           short_at(&good_buf[offset]), bad);
+                                       op = temp_buf[offset & 1 ? i+1 : i];
+                               }
+                               n++;
+                               badoff = offset;
+                       }
+                       offset++;
+                       i++;
+                       size--;
+               }
+               if (n) {
+                       prt("\t0x%5x\n", n);
+                       if (bad)
+                               prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff));
+                       else
+                               prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n");
+               } else
+                       prt("????????????????\n");
+               report_failure(110);
+       }
+}
+
+
+void
+check_size(void)
+{
+       struct stat     statbuf;
+       off_t   size_by_seek;
+
+       if (fstat(fd, &statbuf)) {
+               prterr("check_size: fstat");
+               statbuf.st_size = -1;
+       }
+       size_by_seek = lseek(fd, (off_t)0, L_XTND);
+       if (file_size != statbuf.st_size || file_size != size_by_seek) {
+               prt("Size error: expected 0x%qx stat 0x%qx seek 0x%qx\n",
+                   (unsigned long long)file_size,
+                   (unsigned long long)statbuf.st_size,
+                   (unsigned long long)size_by_seek);
+               report_failure(120);
+       }
+}
+
+
+void
+check_trunc_hack(void)
+{
+       struct stat statbuf;
+
+       ftruncate(fd, (off_t)0);
+       ftruncate(fd, (off_t)100000);
+       fstat(fd, &statbuf);
+       if (statbuf.st_size != (off_t)100000) {
+               prt("no extend on truncate! not posix!\n");
+               exit(130);
+       }
+       ftruncate(fd, 0);
+}
+
+
+void
+doread(unsigned offset, unsigned size)
+{
+       off_t ret;
+       unsigned iret;
+
+       offset -= offset % readbdy;
+       if (size == 0) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping zero size read\n");
+               log4(OP_SKIPPED, OP_READ, offset, size);
+               return;
+       }
+       if (size + offset > file_size) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping seek/read past end of file\n");
+               log4(OP_SKIPPED, OP_READ, offset, size);
+               return;
+       }
+
+       log4(OP_READ, offset, size, 0);
+
+       if (testcalls <= simulatedopcount)
+               return;
+
+       if (!quiet && (progressinterval && testcalls % progressinterval == 0 ||
+                      debug &&
+                      (monitorstart == -1 ||
+                       offset + size > monitorstart &&
+                       (monitorend == -1 || offset <= monitorend))))
+               prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+                   offset, offset + size - 1, size);
+       ret = lseek(fd, (off_t)offset, SEEK_SET);
+       if (ret == (off_t)-1) {
+               prterr("doread: lseek");
+               report_failure(140);
+       }
+       iret = read(fd, temp_buf, size);
+       if (iret != size) {
+               if (iret == -1)
+                       prterr("doread: read");
+               else
+                       prt("short read: 0x%x bytes instead of 0x%x\n",
+                           iret, size);
+               report_failure(141);
+       }
+       check_buffers(offset, size);
+}
+
+
+void
+domapread(unsigned offset, unsigned size)
+{
+       unsigned pg_offset;
+       unsigned map_size;
+       char    *p;
+
+       offset -= offset % readbdy;
+       if (size == 0) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping zero size read\n");
+               log4(OP_SKIPPED, OP_MAPREAD, offset, size);
+               return;
+       }
+       if (size + offset > file_size) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping seek/read past end of file\n");
+               log4(OP_SKIPPED, OP_MAPREAD, offset, size);
+               return;
+       }
+
+       log4(OP_MAPREAD, offset, size, 0);
+
+       if (testcalls <= simulatedopcount)
+               return;
+
+       if (!quiet && (progressinterval && testcalls % progressinterval == 0 ||
+                      debug &&
+                      (monitorstart == -1 ||
+                       offset + size > monitorstart &&
+                       (monitorend == -1 || offset <= monitorend))))
+               prt("%lu mapread\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+                   offset, offset + size - 1, size);
+
+       pg_offset = offset & PAGE_MASK;
+       map_size  = pg_offset + size;
+
+       if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_FILE, fd,
+                             (off_t)(offset - pg_offset))) == (char *)-1) {
+               prterr("domapread: mmap");
+               report_failure(190);
+       }
+       memcpy(temp_buf, p + pg_offset, size);
+       if (munmap(p, map_size) != 0) {
+               prterr("domapread: munmap");
+               report_failure(191);
+       }
+
+       check_buffers(offset, size);
+}
+
+
+void
+gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
+{
+       while (size--) {
+               good_buf[offset] = testcalls % 256; 
+               if (offset % 2)
+                       good_buf[offset] += original_buf[offset];
+               offset++;
+       }
+}
+
+
+void
+dowrite(unsigned offset, unsigned size)
+{
+       off_t ret;
+       unsigned iret;
+
+       offset -= offset % writebdy;
+       if (size == 0) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping zero size write\n");
+               log4(OP_SKIPPED, OP_WRITE, offset, size);
+               return;
+       }
+
+       log4(OP_WRITE, offset, size, file_size);
+
+       gendata(original_buf, good_buf, offset, size);
+       if (file_size < offset + size) {
+               if (file_size < offset)
+                       bzero(good_buf + file_size, offset - file_size);
+               file_size = offset + size;
+               if (lite) {
+                       warn("Lite file size bug in fsx!");
+                       report_failure(149);
+               }
+       }
+
+       if (testcalls <= simulatedopcount)
+               return;
+
+       if (!quiet && (progressinterval && testcalls % progressinterval == 0 ||
+                      debug &&
+                      (monitorstart == -1 ||
+                       offset + size > monitorstart &&
+                       (monitorend == -1 || offset <= monitorend))))
+               prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+                   offset, offset + size - 1, size);
+       ret = lseek(fd, (off_t)offset, SEEK_SET);
+       if (ret == (off_t)-1) {
+               prterr("dowrite: lseek");
+               report_failure(150);
+       }
+       iret = write(fd, good_buf + offset, size);
+       if (iret != size) {
+               if (iret == -1)
+                       prterr("dowrite: write");
+               else
+                       prt("short write: 0x%x bytes instead of 0x%x\n",
+                           iret, size);
+               report_failure(151);
+       }
+}
+
+
+void
+domapwrite(unsigned offset, unsigned size)
+{
+       unsigned pg_offset;
+       unsigned map_size;
+       off_t    cur_filesize;
+       char    *p;
+
+       offset -= offset % writebdy;
+       if (size == 0) {
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("skipping zero size write\n");
+               log4(OP_SKIPPED, OP_MAPWRITE, offset, size);
+               return;
+       }
+       cur_filesize = file_size;
+
+       log4(OP_MAPWRITE, offset, size, 0);
+
+       gendata(original_buf, good_buf, offset, size);
+       if (file_size < offset + size) {
+               if (file_size < offset)
+                       bzero(good_buf + file_size, offset - file_size);
+               file_size = offset + size;
+               if (lite) {
+                       warn("Lite file size bug in fsx!");
+                       report_failure(200);
+               }
+       }
+
+       if (testcalls <= simulatedopcount)
+               return;
+
+       if (!quiet && (progressinterval && testcalls % progressinterval == 0 ||
+                      debug &&
+                      (monitorstart == -1 ||
+                       offset + size > monitorstart &&
+                       (monitorend == -1 || offset <= monitorend))))
+               prt("%lu mapwrite\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+                   offset, offset + size - 1, size);
+
+       if (file_size > cur_filesize) {
+               if (ftruncate(fd, file_size) == -1) {
+                       prterr("domapwrite: ftruncate");
+                       exit(201);
+               }
+       }
+       pg_offset = offset & PAGE_MASK;
+       map_size  = pg_offset + size;
+
+       if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
+                             MAP_FILE | MAP_SHARED, fd,
+                             (off_t)(offset - pg_offset))) == (char *)-1) {
+               prterr("domapwrite: mmap");
+               report_failure(202);
+       }
+       memcpy(p + pg_offset, good_buf + offset, size);
+       if (msync(p, map_size, 0) != 0) {
+               prterr("domapwrite: msync");
+               report_failure(203);
+       }
+       if (munmap(p, map_size) != 0) {
+               prterr("domapwrite: munmap");
+               report_failure(204);
+       }
+}
+
+
+void
+dotruncate(unsigned size)
+{
+       int oldsize = file_size;
+
+       size -= size % truncbdy;
+       if (size > biggest) {
+               biggest = size;
+               if (!quiet && testcalls > simulatedopcount)
+                       prt("truncating to largest ever: 0x%x\n", size);
+       }
+
+       log4(OP_TRUNCATE, size, (unsigned)file_size, 0);
+
+       if (size > file_size)
+               bzero(good_buf + file_size, size - file_size);
+       file_size = size;
+
+       if (testcalls <= simulatedopcount)
+               return;
+       
+       if (progressinterval && testcalls % progressinterval == 0 ||
+           debug && (monitorstart == -1 || monitorend == -1 ||
+                     size <= monitorend))
+               prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size);
+       if (ftruncate(fd, (off_t)size) == -1) {
+               prt("ftruncate1: %x\n", size);
+               prterr("dotruncate: ftruncate");
+               report_failure(160);
+       }
+}
+
+
+void
+writefileimage()
+{
+       ssize_t iret;
+
+       if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
+               prterr("writefileimage: lseek");
+               report_failure(171);
+       }
+       iret = write(fd, good_buf, file_size);
+       if ((off_t)iret != file_size) {
+               if (iret == -1)
+                       prterr("writefileimage: write");
+               else
+                       prt("short write: 0x%x bytes instead of 0x%qx\n",
+                           iret, (unsigned long long)file_size);
+               report_failure(172);
+       }
+       if (lite ? 0 : ftruncate(fd, file_size) == -1) {
+               prt("ftruncate2: %qx\n", (unsigned long long)file_size);
+               prterr("writefileimage: ftruncate");
+               report_failure(173);
+       }
+}
+
+
+void
+docloseopen(void)
+{ 
+       if (testcalls <= simulatedopcount)
+               return;
+
+       if (debug)
+               prt("%lu close/open\n", testcalls);
+       if (close(fd)) {
+               prterr("docloseopen: close");
+               report_failure(180);
+       }
+       fd = open(fname, O_RDWR, 0);
+       if (fd < 0) {
+               prterr("docloseopen: open");
+               report_failure(181);
+       }
+}
+
+
+void
+test(void)
+{
+       unsigned long   offset;
+       unsigned long   size = maxoplen;
+       unsigned long   rv = random();
+       unsigned long   op = rv % (3 + !lite + mapped_writes);
+
+        /* turn off the map read if necessary */
+
+        if (op == 2 && !mapped_reads)
+            op = 0;
+
+       if (simulatedopcount > 0 && testcalls == simulatedopcount)
+               writefileimage();
+
+       testcalls++;
+
+       closeopen = (rv >> 3) < (1 << 28) / closeprob;
+
+       if (debugstart > 0 && testcalls >= debugstart)
+               debug = 1;
+
+       if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
+               prt("%lu...\n", testcalls);
+
+       /*
+        * READ:        op = 0
+        * WRITE:       op = 1
+        * MAPREAD:     op = 2
+        * TRUNCATE:    op = 3
+        * MAPWRITE:    op = 3 or 4
+        */
+       if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */
+               dotruncate(random() % maxfilelen);
+       else {
+               if (randomoplen)
+                       size = random() % (maxoplen+1);
+               if (lite ? 0 : op == 3)
+                       dotruncate(size);
+               else {
+                       offset = random();
+                       if (op == 1 || op == (lite ? 3 : 4)) {
+                               offset %= maxfilelen;
+                               if (offset + size > maxfilelen)
+                                       size = maxfilelen - offset;
+                               if (op != 1)
+                                       domapwrite(offset, size);
+                               else
+                                       dowrite(offset, size);
+                       } else {
+                               if (file_size)
+                                       offset %= file_size;
+                               else
+                                       offset = 0;
+                               if (offset + size > file_size)
+                                       size = file_size - offset;
+                               if (op != 0)
+                                       domapread(offset, size);
+                               else
+                                       doread(offset, size);
+                       }
+               }
+       }
+       if (sizechecks && testcalls > simulatedopcount)
+               check_size();
+       if (closeopen)
+               docloseopen();
+}
+
+
+void
+cleanup(sig)
+       int     sig;
+{
+       if (sig)
+               prt("signal %d\n", sig);
+       prt("testcalls = %lu\n", testcalls);
+       exit(sig);
+}
+
+
+void
+usage(void)
+{
+       fprintf(stdout, "usage: %s",
+               "fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\
+       -b opnum: beginning operation number (default 1)\n\
+       -c P: 1 in P chance of file close+open at each op (default infinity)\n\
+       -d: debug output for all operations\n\
+       -l flen: the upper bound on file size (default 262144)\n\
+       -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
+       -n: no verifications of file size\n\
+       -o oplen: the upper bound on operation size (default 65536)\n\
+       -p progressinterval: debug output at specified operation interval\n\
+       -q: quieter operation\n\
+       -r readbdy: 4096 would make reads page aligned (default 1)\n\
+       -s style: 1 gives smaller truncates (default 0)\n\
+       -t truncbdy: 4096 would make truncates page aligned (default 1)\n\
+       -w writebdy: 4096 would make writes page aligned (default 1)\n\
+       -D startingop: debug output starting at specified operation\n\
+       -L: fsxLite - no file creations & no file size changes\n\
+       -N numops: total # operations to do (default infinity)\n\
+       -O: use oplen (see -o flag) for every op (default random)\n\
+       -P: save .fsxlog and .fsxgood files in dirpath (default ./)\n\
+       -S seed: for random # generator (default 1) 0 gets timestamp\n\
+       -W: mapped write operations DISabled\n\
+        -R: read() system calls only (mapped reads disabled)\n\
+       fname: this filename is REQUIRED (no default)\n");
+       exit(90);
+}
+
+
+int
+getnum(char *s, char **e)
+{
+       int ret = -1;
+
+       *e = (char *) 0;
+       ret = strtol(s, e, 0);
+       if (*e)
+               switch (**e) {
+               case 'b':
+               case 'B':
+                       ret *= 512;
+                       *e = *e + 1;
+                       break;
+               case 'k':
+               case 'K':
+                       ret *= 1024;
+                       *e = *e + 1;
+                       break;
+               case 'm':
+               case 'M':
+                       ret *= 1024*1024;
+                       *e = *e + 1;
+                       break;
+               case 'w':
+               case 'W':
+                       ret *= 4;
+                       *e = *e + 1;
+                       break;
+               }
+       return (ret);
+}
+
+
+int
+main(int argc, char **argv)
+{
+       int     i, style, ch;
+       char    *endp;
+       char goodfile[1024];
+       char logfile[1024];
+
+       goodfile[0] = 0;
+       logfile[0] = 0;
+
+       setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
+
+       while ((ch = getopt(argc, argv, "b:c:dl:m:no:p:qr:s:t:w:D:LN:OP:RS:W"))
+              != EOF)
+               switch (ch) {
+               case 'b':
+                       simulatedopcount = getnum(optarg, &endp);
+                       if (!quiet)
+                               fprintf(stdout, "Will begin at operation %ld\n",
+                                       simulatedopcount);
+                       if (simulatedopcount == 0)
+                               usage();
+                       simulatedopcount -= 1;
+                       break;
+               case 'c':
+                       closeprob = getnum(optarg, &endp);
+                       if (!quiet)
+                               fprintf(stdout,
+                                       "Chance of close/open is 1 in %d\n",
+                                       closeprob);
+                       if (closeprob <= 0)
+                               usage();
+                       break;
+               case 'd':
+                       debug = 1;
+                       break;
+               case 'l':
+                       maxfilelen = getnum(optarg, &endp);
+                       if (maxfilelen <= 0)
+                               usage();
+                       break;
+               case 'm':
+                       monitorstart = getnum(optarg, &endp);
+                       if (monitorstart < 0)
+                               usage();
+                       if (!endp || *endp++ != ':')
+                               usage();
+                       monitorend = getnum(endp, &endp);
+                       if (monitorend < 0)
+                               usage();
+                       if (monitorend == 0)
+                               monitorend = -1; /* aka infinity */
+                       debug = 1;
+               case 'n':
+                       sizechecks = 0;
+                       break;
+               case 'o':
+                       maxoplen = getnum(optarg, &endp);
+                       if (maxoplen <= 0)
+                               usage();
+                       break;
+               case 'p':
+                       progressinterval = getnum(optarg, &endp);
+                       if (progressinterval < 0)
+                               usage();
+                       break;
+               case 'q':
+                       quiet = 1;
+                       break;
+               case 'r':
+                       readbdy = getnum(optarg, &endp);
+                       if (readbdy <= 0)
+                               usage();
+                       break;
+               case 's':
+                       style = getnum(optarg, &endp);
+                       if (style < 0 || style > 1)
+                               usage();
+                       break;
+               case 't':
+                       truncbdy = getnum(optarg, &endp);
+                       if (truncbdy <= 0)
+                               usage();
+                       break;
+               case 'w':
+                       writebdy = getnum(optarg, &endp);
+                       if (writebdy <= 0)
+                               usage();
+                       break;
+               case 'D':
+                       debugstart = getnum(optarg, &endp);
+                       if (debugstart < 1)
+                               usage();
+                       break;
+               case 'L':
+                       lite = 1;
+                       break;
+               case 'N':
+                       numops = getnum(optarg, &endp);
+                       if (numops < 0)
+                               usage();
+                       break;
+               case 'O':
+                       randomoplen = 0;
+                       break;
+               case 'P':
+                       strncpy(goodfile, optarg, sizeof(goodfile));
+                       strcat(goodfile, "/");
+                       strncpy(logfile, optarg, sizeof(logfile));
+                       strcat(logfile, "/");
+                       break;
+                case 'R':
+                        mapped_reads = 0;
+                        break;
+               case 'S':
+                        seed = getnum(optarg, &endp);
+                       if (seed == 0)
+                               seed = time(0) % 10000;
+                       if (!quiet)
+                               fprintf(stdout, "Seed set to %d\n", seed);
+                       if (seed < 0)
+                               usage();
+                       break;
+               case 'W':
+                       mapped_writes = 0;
+                       if (!quiet)
+                               fprintf(stdout, "mapped writes DISABLED\n");
+                       break;
+              
+               default:
+                       usage();
+                       /* NOTREACHED */
+               }
+       argc -= optind;
+       argv += optind;
+       if (argc != 1)
+               usage();
+       fname = argv[0];
+
+       signal(SIGHUP,  cleanup);
+       signal(SIGINT,  cleanup);
+       signal(SIGPIPE, cleanup);
+       signal(SIGALRM, cleanup);
+       signal(SIGTERM, cleanup);
+       signal(SIGXCPU, cleanup);
+       signal(SIGXFSZ, cleanup);
+       signal(SIGVTALRM,       cleanup);
+       signal(SIGUSR1, cleanup);
+       signal(SIGUSR2, cleanup);
+
+       initstate(seed, state, 256);
+       setstate(state);
+       fd = open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666);
+       if (fd < 0) {
+               prterr(fname);
+               exit(91);
+       }
+       strncat(goodfile, fname, 256);
+       strcat (goodfile, ".fsxgood");
+       fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
+       if (fsxgoodfd < 0) {
+               prterr(goodfile);
+               exit(92);
+       }
+       strncat(logfile, fname, 256);
+       strcat (logfile, ".fsxlog");
+       fsxlogf = fopen(logfile, "w");
+       if (fsxlogf == NULL) {
+               prterr(logfile);
+               exit(93);
+       }
+       if (lite) {
+               off_t ret;
+               file_size = maxfilelen = lseek(fd, (off_t)0, L_XTND);
+               if (file_size == (off_t)-1) {
+                       prterr(fname);
+                       warn("main: lseek eof");
+                       exit(94);
+               }
+               ret = lseek(fd, (off_t)0, SEEK_SET);
+               if (ret == (off_t)-1) {
+                       prterr(fname);
+                       warn("main: lseek 0");
+                       exit(95);
+               }
+       }
+       original_buf = (char *) malloc(maxfilelen);
+       for (i = 0; i < maxfilelen; i++)
+               original_buf[i] = random() % 256;
+       good_buf = (char *) malloc(maxfilelen);
+       bzero(good_buf, maxfilelen);
+       temp_buf = (char *) malloc(maxoplen);
+       bzero(temp_buf, maxoplen);
+       if (lite) {     /* zero entire existing file */
+               ssize_t written;
+
+               written = write(fd, good_buf, (size_t)maxfilelen);
+               if (written != maxfilelen) {
+                       if (written == -1) {
+                               prterr(fname);
+                               warn("main: error on write");
+                       } else
+                               warn("main: short write, 0x%x bytes instead of 0x%x\n",
+                                    (unsigned)written, maxfilelen);
+                       exit(98);
+               }
+       } else 
+               check_trunc_hack();
+
+       while (numops == -1 || numops--)
+               test();
+
+       if (close(fd)) {
+               prterr("close");
+               report_failure(99);
+       }
+       prt("All operations completed A-OK!\n");
+
+       exit(0);
+       return 0;
+}
diff --git a/src/tests/ga-test.c b/src/tests/ga-test.c
new file mode 100644 (file)
index 0000000..0d11a81
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * Test if agetarg works as expected
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include <err.h>
+
+#include <agetarg.h>
+
+RCSID("$Id: ga-test.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+
+typedef struct {
+    int style;
+    int argc;
+    char *argv[10];
+    enum { GA_SUCCESS = 0, GA_FAILURE } retval ;
+} ga_tests;
+
+
+/* XXX TODO: aarg_negative_flag, manualpage generation ? */
+
+/*
+ *
+ */
+
+static void
+test_simple_string (void)
+{
+    char *string;
+    int i, optind;
+    ga_tests tests[] = {
+       { AARG_GNUSTYLE, 2, { "string", "--string=foo", NULL } },
+       { AARG_GNUSTYLE, 3, { "string", "-s", "foo", NULL} },
+       { AARG_AFSSTYLE, 3, { "string", "-string", "foo", NULL} },
+       { AARG_AFSSTYLE, 3, { "string", "-strin", "foo", NULL} },
+       { AARG_AFSSTYLE, 3, { "string", "-st", "foo", NULL}, GA_FAILURE },
+       { AARG_AFSSTYLE, 2, { "string", "--flag"},              GA_FAILURE },
+       { AARG_AFSSTYLE, 2, { "string", "foo", NULL} }
+    };
+
+    struct agetargs args[] = {
+       { "string", 's', aarg_string, NULL,
+         "string test", "stringfoo", aarg_mandatory},
+       { "strip", 0, aarg_string, NULL,
+         "strip test", "stripfoo", aarg_optional},
+       { NULL, 0, aarg_end, NULL, NULL }
+    }, *a = args;
+
+    a->value = &string;
+
+    for (i = 0 ; i < sizeof(tests)/sizeof(*tests); i++) {
+       string = NULL;
+       optind = 0;
+
+       if (agetarg (args, tests[i].argc, tests[i].argv, &optind, 
+                   tests[i].style)) {
+           if (tests[i].retval == GA_FAILURE)
+               continue;
+           warnx ("test_string: %s failed for test %d",
+                  tests[i].argv[1], i);
+           continue;
+       } else {
+           if (tests[i].retval != GA_SUCCESS) {
+               warnx ("test_string: %s failed to fail for test %d",
+                      tests[i].argv[1], i);
+               continue;
+           }
+       }
+       
+       if (optind != tests[i].argc) {
+           warnx ("argc != optind for test %s, %d", tests[i].argv[1], i);
+           continue;
+       }
+
+       if (string == NULL || strcmp (string, "foo") != 0) {
+           warnx ("error parsing for test %d: string", i);
+           continue;
+       }
+    }
+}
+
+/*
+ *
+ */
+
+static void
+test_simple_strings (void)
+{
+    agetarg_strings strings;
+
+    int i, optind;
+    ga_tests tests[] = {
+       { AARG_GNUSTYLE, 3, { "strings", 
+                            "--strings=foo", "--strings=bar", NULL } },
+       { AARG_GNUSTYLE, 5, { "strings", "-s", "foo", "-s", "bar", NULL} },
+       { AARG_AFSSTYLE, 4, { "strings", "-string", "foo", "bar", NULL} }
+#if 0
+       { AARG_AFSSTYLE, 3, { "strings", "foo", "bar", NULL} }
+#endif
+    };
+
+    struct agetargs args[] = {
+       { "strings", 's', aarg_strings, NULL,
+         "strings test", "stringsfoo", aarg_optional},
+       { NULL, 0, aarg_end, NULL, NULL }
+    }, *a = args;
+
+    a->value = &strings;
+
+    for (i = 0 ; i < sizeof(tests)/sizeof(*tests); i++) {
+       strings.num_strings = 0;
+       strings.strings = NULL;
+       optind = 0;
+
+       if (agetarg (args, tests[i].argc, tests[i].argv, &optind, 
+                   tests[i].style)) {
+           if (tests[i].retval == GA_FAILURE)
+               continue;
+           warnx ("test_strings: %s failed for test %d",
+                  tests[i].argv[1], i);
+           continue;
+       } else {
+           if (tests[i].retval != GA_SUCCESS) {
+               warnx ("test_strings: %s failed to fail for test %d",
+                      tests[i].argv[1], i);
+               continue;
+           }
+       }
+       
+       if (optind != tests[i].argc) {
+           warnx ("argc != optind for test %s, %d",
+                  tests[i].argv[1], i);
+           continue;
+       }
+
+       if (strings.num_strings != 2 
+           || strcmp(strings.strings[0], "foo") != 0
+           || strcmp(strings.strings[1], "bar") != 0)
+       {
+           warnx ("error parsing for test %d: strings", i);
+           continue;
+       }
+    }
+}
+
+/*
+ *
+ */
+
+static void
+test_simple_integer (void)
+{
+    int integer;
+    int i, optind;
+    ga_tests tests[] = {
+       { AARG_GNUSTYLE, 2, { "integer", "--integer=4711", NULL } },
+       { AARG_GNUSTYLE, 3, { "integer", "-i", "4711", NULL} },
+       { AARG_AFSSTYLE, 3, { "integer", "-integer", "4711", NULL} },
+       { AARG_AFSSTYLE, 2, { "integer", "4711", NULL} }
+    };
+
+    struct agetargs args[] = {
+       { "integer", 'i', aarg_integer, NULL,
+         "integer test", "integer", aarg_mandatory},
+       { NULL, 0, aarg_end, NULL, NULL }
+    }, *a = args;
+
+    a->value = &integer;
+
+    for (i = 0 ; i < sizeof(tests)/sizeof(*tests); i++) {
+       integer = 0;
+       optind = 0;
+
+       if (agetarg (args, tests[i].argc, tests[i].argv, &optind, 
+                   tests[i].style)) {
+           if (tests[i].retval == GA_FAILURE)
+               continue;
+           warnx ("test_integer: %s failed for test %d",
+                  tests[i].argv[1], i);
+           continue;
+       } else {
+           if (tests[i].retval != GA_SUCCESS) {
+               warnx ("test_integer: %s failed to fail for test %d",
+                      tests[i].argv[1], i);
+               continue;
+           }
+       }
+       
+       if (optind != tests[i].argc) {
+           warnx ("argc != optind for test %s, %d",
+                  tests[i].argv[1], i);        
+           continue;
+       }
+
+       if (integer != 4711) {
+           warnx ("error parsing for test %d: integer 4711", i);
+           continue;
+       }
+    }
+}
+
+/*
+ *
+ */
+
+static void
+test_simple_flag (void)
+{
+    int flag;
+    int i, optind;
+    ga_tests tests[] = {
+       { AARG_GNUSTYLE, 2, { "flag", "--flag=yes", NULL },     GA_SUCCESS },
+       { AARG_GNUSTYLE, 2, { "flag", "-g", NULL},              GA_SUCCESS },
+       { AARG_AFSSTYLE, 2, { "flag", "--flag"},                GA_FAILURE },
+       { AARG_AFSSTYLE, 2, { "flag", "-flag", NULL},           GA_SUCCESS },
+#if 0
+       /* XXX */
+       { AARG_AFSSTYLE, 2, { "flag", "yes", NULL},             GA_SUCCESS },
+#endif
+       { AARG_GNUSTYLE, 2, { "flag", "--no-flag", NULL},       GA_SUCCESS }
+    };
+
+    struct agetargs args[] = {
+       { "flag", 'g', aarg_flag, NULL,
+         "flag", "flag bar", aarg_optional},
+       { NULL, 0, aarg_end, NULL, NULL }
+    }, *a = args;
+
+    a->value = &flag;
+
+    for (i = 0 ; i < sizeof(tests)/sizeof(*tests); i++) {
+       if (i < 4)
+           flag = 0;
+       else
+           flag = 1;
+       optind = 0;
+
+       if (agetarg (args, tests[i].argc, tests[i].argv, &optind, 
+                   tests[i].style)) {
+           if (tests[i].retval == GA_FAILURE)
+               continue;
+           warnx ("test_flag: %s failed for test %d",
+                  tests[i].argv[1], i);
+           continue;
+       } else {
+           if (tests[i].retval != GA_SUCCESS) {
+               warnx ("test_flag: %s failed to fail for test %d",
+                      tests[i].argv[1], i);
+               continue;
+           }
+       }
+       
+       if (optind != tests[i].argc) {
+           warnx ("argc != optind for test %s, %d",
+                  tests[i].argv[1], i);
+           continue;
+       }
+
+       if (i < 4) {
+           if (flag == 0) {
+               warnx ("error parsing for test %d: flag %s",
+                      i,
+                      tests[i].argv[1]);
+               continue;
+           }
+       } else {
+           if (flag != 0) {
+               warnx ("error parsing test %d: flag %s",
+                      i,
+                      tests[i].argv[1]);
+                   continue;
+           }
+       }
+    }
+}
+
+/*
+ *
+ */
+
+int
+main (int argc, char **argv)
+{
+
+    test_simple_string();
+    test_simple_strings();
+    test_simple_integer();
+    test_simple_flag();
+    
+    return 0;
+}
diff --git a/src/tests/generic-build b/src/tests/generic-build
new file mode 100755 (executable)
index 0000000..93b2d5f
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $Id: generic-build,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+if test $# -ne 1 -a $# -ne 2; then
+  echo "Usage: $0 file [directory]"
+  exit 1
+fi
+filename=$1
+if test $# -gt 1; then
+  b=$2
+else
+  b=`basename $filename .tar.gz`
+fi
+obj=$b-obj
+
+gzip -dc $filename | tar xvf - >&4 2>&1 || exit 1
+cd $b || exit 1
+./configure >&4 || exit 1
+make $MAKEFLAGS >&4 || exit 1
diff --git a/src/tests/getdents-and-unlink1 b/src/tests/getdents-and-unlink1
new file mode 100755 (executable)
index 0000000..b901a93
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: getdents-and-unlink1,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+gzip -dc ${AFSROOT}/stacken.kth.se/ftp/pub/gnu/emacs/emacs-20.7.tar.gz |
+tar vxf - >&4 2>&1 || exit 1
+cd emacs-20.7 || exit 1
+$objdir/kill-softer lisp || exit 1
+test -d lisp && exit 1
+exit 0
diff --git a/src/tests/getdents-and-unlink2 b/src/tests/getdents-and-unlink2
new file mode 100755 (executable)
index 0000000..18fad08
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: getdents-and-unlink2,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+gzip -dc ${AFSROOT}/stacken.kth.se/ftp/pub/gnu/emacs/emacs-20.7.tar.gz |
+tar vxf - >&4 2>&1 || exit 1
+cd emacs-20.7 || exit 1
+$objdir/rm-rf lisp || exit 1
+test -d lisp && exit 1
+exit 0
diff --git a/src/tests/getdents-and-unlink3 b/src/tests/getdents-and-unlink3
new file mode 100755 (executable)
index 0000000..8064c7d
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: getdents-and-unlink3,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+gzip -dc ${AFSROOT}/stacken.kth.se/ftp/pub/gnu/emacs/emacs-20.7.tar.gz |
+tar vxf - >&4 2>&1 || exit 1
+cd emacs-20.7 || exit 1
+$objdir/kill-softly lisp || exit 1
+test -d lisp && exit 1
+exit 0
diff --git a/src/tests/grind-arla-with-cvs b/src/tests/grind-arla-with-cvs
new file mode 100755 (executable)
index 0000000..15134bf
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+if [ x`uname` != xLinux ] ; then
+    echo This test does not run on this architecture
+    exit 1
+fi
+
+echo '***********************************************************'
+echo '*                                                         *'
+echo '*               Infinite run until error                  *'
+echo '*                                                         *'
+echo '***********************************************************'
+sleep 5
+
+# First argument is our working dir
+test $1 || exit 1
+mkdir $1
+cd $1 || exit 1
+
+TOPDIR=$PWD
+export TOPDIR
+CVSROOT=/afs/stacken.kth.se/src/SourceRepository
+export CVSROOT
+
+# test if cvs takes -R
+cvs -R help 2>&1 | grep Usage: > /dev/null && exit 1
+
+cvs -R checkout arla
+while true; do
+       echo Starting at $TOPDIR
+
+       cd $TOPDIR || exit 1
+       cd arla || exit 1
+       cvs -R update -A -d
+       sh HACKING
+       cd $TOPDIR || exit 1
+       mkdir arla-obj
+       cd arla-obj || exit 1
+       
+       ../arla/configure && mv xfs/linux/Makefile xfs/linux/Makefile.old && sed 's/ -Werror//g' < xfs/linux/Makefile.old > xfs/linux/Makefile &&  make || exit 1
+
+       cd $TOPDIR || exit 1
+       cd arla || exit 1
+       cvs -R update -r arla-0-35-branch -d
+       sh HACKING
+       cd $TOPDIR || exit 1
+       mkdir arla-obj
+       cd arla-obj || exit 1
+       ../arla/configure && mv xfs/linux/Makefile xfs/linux/Makefile.old && sed 's/ -Werror//g' < xfs/linux/Makefile.old > xfs/linux/Makefile &&  make || exit 1
+done
+       
+       
diff --git a/src/tests/hardlink1.c b/src/tests/hardlink1.c
new file mode 100644 (file)
index 0000000..440a18a
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 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 <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: hardlink1.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#endif
+
+int
+main(int argc, char *argv[])
+{
+    int fd1, fd2;
+    int ret;
+    struct stat sb1, sb2;
+
+
+    fd1 = open("foo", O_RDWR|O_CREAT, 0666);
+    if (fd1 < 0)
+       err (1, "open foo");
+
+    ret = fstat (fd1, &sb1);
+    if (ret < 0)
+       err (1, "stat foo");
+
+    if (sb1.st_nlink != 1)
+       errx (1, "foo.st_nlink != 1");
+
+    ret = link ("foo", "bar");
+    if (ret < 0)
+       err (1, "link foo, bar");
+
+    ret = fstat (fd1, &sb1);
+    if (ret < 0)
+       err (1, "stat foo");
+
+    ret = lstat ("bar", &sb2);
+    if (ret < 0)
+       err (1, "stat bar");
+
+    if (sb1.st_nlink != 2)
+       errx (1, "foo.st_nlink != 2");
+
+    if (sb2.st_nlink != 2)
+       errx (1, "bar.st_nlink != 2");
+
+    if (sb1.st_dev    != sb2.st_dev
+       || sb1.st_ino != sb2.st_ino)
+       errx (1, "dev and ino differ");
+
+    fd2 = open("bar", O_RDONLY, 0);
+    if (fd2 < 0)
+       err (1, "open bar");
+
+    ret = fstat (fd2, &sb2);
+    if (ret < 0)
+       err (1, "fstat bar");
+    
+    if (sb2.st_nlink != 2)
+       errx (1, "bar.st_nlink != 2");
+
+    if (write (fd1, "hej", 3) != 3)
+       errx (1, "write to foo");
+
+    ret = fstat (fd1, &sb1);
+    if (ret < 0)
+       err (1, "stat foo");
+
+    if (sb1.st_size != 3)
+       errx (1, "foo.st_size != 3");
+
+    ret = close (fd1);
+    if (ret < 0)
+       err (1, "close foo");
+
+    ret = fstat (fd2, &sb2);
+    if (ret < 0)
+       err (1, "fstat bar");
+
+    if (sb2.st_size != 3)
+       errx (1, "bar.st_size != 3");
+
+    ret = close (fd2);
+    if (ret < 0)
+       err (1, "close bar");
+
+    if (unlink ("foo") < 0)
+       err (1, "unlink foo");
+
+    fd2 = open("bar", O_RDONLY, 0);
+    if (fd2 < 0)
+       err (1, "open bar");
+
+    ret = fstat (fd2, &sb2);
+    if (ret < 0)
+       err (1, "fstat bar");
+    
+    if (sb2.st_nlink != 1)
+       errx (1, "bar.st_nlink != 1");
+
+    ret = close (fd2);
+    if (ret < 0)
+       err (1, "close bar");
+
+    if (unlink ("bar") < 0)
+       err (1, "unlink bar");
+
+    return 0;
+}
diff --git a/src/tests/hardlink2.c b/src/tests/hardlink2.c
new file mode 100644 (file)
index 0000000..61e4493
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 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 <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: hardlink2.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#endif
+
+int
+main(int argc, char *argv[])
+{
+    int fd1;
+    int ret;
+    struct stat sb1;
+
+
+    ret = mkdir ("1", 0777);
+    if (ret < 0)
+       err (1, "mkdir 1");
+
+    ret = link ("1", "2");
+    if (ret == 0)
+       errx (1, "link 1 2 should have failed");
+
+    ret = rmdir ("1");
+    if (ret < 0)
+       err (1, "rmdir 1");
+
+    return 0;
+}
diff --git a/src/tests/hardlink3 b/src/tests/hardlink3
new file mode 100644 (file)
index 0000000..3b7dc95
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+# $Id: hardlink3,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+
+FS=${FS:-${objdir}/../appl/fs/fs}
+
+touch file
+for i in `awk 'BEGIN {for(i=0; i < 1000; ++i) printf "%d\n", i}' /dev/null`; do
+ ln file file$i
+done
+
+# now trigger bulkstatus
+for i in `awk 'BEGIN {for(i=0; i < 1000; ++i) printf "%d\n", i}' /dev/null`; do
+ ls -l file > /dev/null 2>&1 || exit 1
+ ${FS} flush file 
+done
+
+# just stat them all
+for i in `awk 'BEGIN {for(i=0; i < 1000; ++i) printf "%d\n", i}' /dev/null`; do
+ ls -l file$i > /dev/null 2>&1  || exit 1
+done
+
+#clean up
+for i in `awk 'BEGIN {for(i=0; i < 1000; ++i) printf "%d\n", i}' /dev/null`; do
+ rm file$i > /dev/null 2>&1  || exit 1
+done
+rm file
\ No newline at end of file
diff --git a/src/tests/hardlink4.c b/src/tests/hardlink4.c
new file mode 100644 (file)
index 0000000..86b095b
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 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 <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: hardlink4.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#endif
+
+int
+main(int argc, char *argv[])
+{
+    int fd1;
+    int ret;
+    struct stat sb1;
+
+
+    ret = mkdir ("1", 0777);
+    if (ret < 0)
+       err (1, "mkdir 1");
+
+    ret = mkdir ("2", 0777);
+    if (ret < 0)
+       err (1, "mkdir 2");
+
+    fd1 = open("1/foo", O_RDWR|O_CREAT, 0666);
+    if (fd1 < 0)
+       err (1, "open 1/foo");
+
+    ret = fstat (fd1, &sb1);
+    if (ret < 0)
+       err (1, "stat foo");
+
+    if (sb1.st_nlink != 1)
+       errx (1, "foo.st_nlink != 1");
+
+    ret = close (fd1);
+    if (ret < 0)
+       err (1, "close 1/foo");
+
+    ret = link ("1/foo", "2/foo");
+    if (ret == 0)
+       unlink ("2/foo");
+    if (ret < 0 && errno != EXDEV)
+       err (1, "link 1/foo, 2/foo");
+
+    ret = unlink ("1/foo");
+    if (ret < 0)
+       err (1, "unlink 1/foo");
+
+    ret = rmdir ("1");
+    if (ret < 0)
+       err (1, "rmdir 1");
+
+    ret = rmdir ("2");
+    if (ret < 0)
+       err (1, "rmdir 2");
+    return 0;
+}
diff --git a/src/tests/hardlink5 b/src/tests/hardlink5
new file mode 100644 (file)
index 0000000..42d01b6
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+# $Id: hardlink5,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+
+FS=${FS:-${objdir}/../appl/fs/fs}
+
+touch file
+ln file ../../service/file && exit 1
+rm file
+
diff --git a/src/tests/hello-world.in b/src/tests/hello-world.in
new file mode 100644 (file)
index 0000000..5b1c9f3
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+# $Id: hello-world.in,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+cat <<FOO > foo.c
+int main() { return 0; }
+FOO
+%CC% -o foo foo.c || exit 1
+./foo || exit 1
+rm -f foo foo.c
diff --git a/src/tests/int64.c b/src/tests/int64.c
new file mode 100644 (file)
index 0000000..4d4a68f
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* int64.c - Support for 64-bit integers */
+
+#include <stdio.h>
+#include <string.h>
+#include "intNN.h"
+
+char *hexify_int64(u_int64 *X, char *buf)
+{
+  static char mybuf[17];
+
+#ifdef NATIVE_INT64
+  char c, *p;
+  u_int64 x = *X;
+
+  if (!buf) buf = mybuf;
+  p = buf + 16;
+  *p-- = 0;
+  while (x && p >= buf) {
+    c = x & 0xf;
+    c += ((c < 10) ? '0' : 'a' - 10);
+    *p-- = c;
+    x >>= 4;
+  }
+  while (p >= buf) *p-- = '0';
+
+#else
+  if (!buf) buf = mybuf;
+  sprintf(buf, "%08lx%08lx", X->hi, X->lo);
+#endif
+
+  return buf;
+}
+
+
+#ifdef NATIVE_INT64
+char *decimate_int64(u_int64 *X, char *buf)
+{
+  static char mybuf[21];
+  char *p;
+  u_int64 x = *X;
+
+  if (!buf) buf = mybuf;
+  p = buf + 21;
+  *--p = 0;
+  while (x && p > buf) {
+    *--p = ((x % 10) + '0');
+    x /= 10;
+  }
+  if (!*p) *--p = '0';
+  return p;
+}
+
+#else
+static char bitvals[64][21] = {
+/*                1 */ "00000000000000000001",
+/*                2 */ "00000000000000000002",
+/*                4 */ "00000000000000000004",
+/*                8 */ "00000000000000000008",
+/*               10 */ "00000000000000000016",
+/*               20 */ "00000000000000000032",
+/*               40 */ "00000000000000000064",
+/*               80 */ "00000000000000000128",
+/*              100 */ "00000000000000000256",
+/*              200 */ "00000000000000000512",
+/*              400 */ "00000000000000001024",
+/*              800 */ "00000000000000002048",
+/*             1000 */ "00000000000000004096",
+/*             2000 */ "00000000000000008192",
+/*             4000 */ "00000000000000016384",
+/*             8000 */ "00000000000000032768",
+/*            10000 */ "00000000000000065536",
+/*            20000 */ "00000000000000131072",
+/*            40000 */ "00000000000000262144",
+/*            80000 */ "00000000000000524288",
+/*           100000 */ "00000000000001048576",
+/*           200000 */ "00000000000002097152",
+/*           400000 */ "00000000000004194304",
+/*           800000 */ "00000000000008388608",
+/*          1000000 */ "00000000000016777216",
+/*          2000000 */ "00000000000033554432",
+/*          4000000 */ "00000000000067108864",
+/*          8000000 */ "00000000000134217728",
+/*         10000000 */ "00000000000268435456",
+/*         20000000 */ "00000000000536870912",
+/*         40000000 */ "00000000001073741824",
+/*         80000000 */ "00000000002147483648",
+/*        100000000 */ "00000000004294967296",
+/*        200000000 */ "00000000008589934592",
+/*        400000000 */ "00000000017179869184",
+/*        800000000 */ "00000000034359738368",
+/*       1000000000 */ "00000000068719476736",
+/*       2000000000 */ "00000000137438953472",
+/*       4000000000 */ "00000000274877906944",
+/*       8000000000 */ "00000000549755813888",
+/*      10000000000 */ "00000001099511627776",
+/*      20000000000 */ "00000002199023255552",
+/*      40000000000 */ "00000004398046511104",
+/*      80000000000 */ "00000008796093022208",
+/*     100000000000 */ "00000017592186044416",
+/*     200000000000 */ "00000035184372088832",
+/*     400000000000 */ "00000070368744177664",
+/*     800000000000 */ "00000140737488355328",
+/*    1000000000000 */ "00000281474976710656",
+/*    2000000000000 */ "00000562949953421312",
+/*    4000000000000 */ "00001125899906842624",
+/*    8000000000000 */ "00002251799813685248",
+/*   10000000000000 */ "00004503599627370496",
+/*   20000000000000 */ "00009007199254740992",
+/*   40000000000000 */ "00018014398509481984",
+/*   80000000000000 */ "00036028797018963968",
+/*  100000000000000 */ "00072057594037927936",
+/*  200000000000000 */ "00144115188075855872",
+/*  400000000000000 */ "00288230376151711744",
+/*  800000000000000 */ "00576460752303423488",
+/* 1000000000000000 */ "01152921504606846976",
+/* 2000000000000000 */ "02305843009213693952",
+/* 4000000000000000 */ "04611686018427387904",
+/* 8000000000000000 */ "09223372036854775808" };
+
+
+static void prep_table(void)
+{
+  int bit, digit;
+
+  if (bitvals[0][0] < '0') return;
+  for (bit = 0; bit < 64; bit++)
+    for (digit = 0; digit < 20; digit++)
+      bitvals[bit][digit] -= '0';
+}
+
+
+static void add_bit(int bit, char *answer)
+{
+  int digit;
+
+  for (digit = 19; digit >= 0; digit--) {
+    answer[digit] += bitvals[bit][digit];
+    if (!digit) break;
+    while(answer[digit] > 9) {
+      answer[digit] -= 10;
+      answer[digit-1]++;
+    }
+  }
+}
+
+
+static void decimate(unsigned long hi, unsigned long lo, char *answer)
+{
+  unsigned long mask;
+  int bit, digit;
+
+  memset(answer, 0, 21);
+  for (bit = 0, mask = 1; bit < 32; bit++, mask <<= 1)
+    if (lo&mask) add_bit(bit, answer);
+  for (bit = 0, mask = 1; bit < 32; bit++, mask <<= 1)
+    if (hi&mask) add_bit(bit + 32, answer);
+
+  for (digit = 0; digit < 20; digit++)
+    answer[digit] += '0';
+}
+
+char *decimate_int64(u_int64 *X, char *buf)
+{
+  static char mybuf[21];
+  char *p;
+
+  prep_table();
+  if (!buf) buf = mybuf;
+  decimate(X->hi, X->lo, buf);
+  for (p = buf; *p == '0'; p++);
+  return (*p) ? p : p-1;
+}
+
+#endif /* NATIVE_INT64 */
+
+
+void shift_int64(u_int64 *X, int bits)
+{
+#ifdef NATIVE_INT64
+  if (bits < 0) *X >>= (-bits);
+  else          *X <<= bits;
+#else
+  if (bits < 0) {
+    bits = -bits;
+    if (bits >= 32) {
+      X->lo = ((X->hi & 0xffffffffL) >> (bits - 32));
+      X->hi = 0;
+    } else {
+      X->lo = ((X->lo & 0xffffffffL) >> bits)
+            | ((X->hi & ((1 << (32 - bits)) - 1)) << (32 - bits));
+      X->hi = ((X->hi & 0xffffffffL) >> bits);
+    }
+  } else {
+    if (bits >= 32) {
+      X->hi = ((X->lo & 0xffffffffL) << (bits - 32));
+      X->lo = 0;
+    } else {
+      X->hi = ((X->hi & 0xffffffffL) << bits)
+            | ((X->lo & (((1 << bits) - 1) << (32 - bits))) >> (32 - bits));
+      X->lo = ((X->lo & 0xffffffffL) << bits);
+    }
+  }
+#endif
+}
+
+
+#ifdef TEST_INT64
+
+/** the rest of this is for testing the int64 suite **/
+
+#ifdef NATIVE_INT64
+
+#define xize(x) #x
+#define stringize(x) xize(x)
+#define INT64_NAME stringize(unsigned NATIVE_INT64)
+
+
+#endif /* NATIVE_INT64 */
+
+
+void verify_int64_size () {
+#ifdef NATIVE_INT64
+  signed char testchar = -1;
+  unsigned int testint = (unsigned char)testchar;
+
+  printf("We think '%s' is a native 64-bit type\n", INT64_NAME);
+
+  if (testint != 0xff) {
+    printf("testint = 0x%x; should be 0xff\n", testint);
+    fprintf(stderr, "Hmm...  char's are not 8 bits.  That sucks!\n");
+    exit(-1);
+  }
+  printf("Looks like a char is 8 bits...\n");
+
+  if (sizeof(unsigned NATIVE_INT64) != 8) {
+    printf("sizeof(%s) = %d; should be 8\n", INT64_NAME, sizeof(unsigned NATIVE_INT64));
+    fprintf(stderr, "Hey!  You said a %s was 64-bits wide!\n", INT64_NAME);
+    exit(-1);
+  }
+  printf("Yippee!  We have a native 64-bit type (%s)\n\n", INT64_NAME);
+
+#else /* !NATIVE_INT64 */
+
+  printf("Using fake 64-bit integers...\n\n");
+#endif /* NATIVE_INT64 */
+}
+
+
+void test_int64_constructs(void)
+{
+  u_int64 x, y;
+  afs_uint32 hi, lo;
+  int failures = 0, pass;
+  char buf[17];
+
+  printf("Constructor/accessor tests:\n");
+  printf("Setting x := %s\n", INT64_TEST_STR);
+  mk64(x, INT64_TEST_HI, INT64_TEST_LO);
+
+#ifdef NATIVE_INT64
+  pass = (x == INT64_TEST_CONST);
+  hexify_int64(&x, buf);
+  printf("NATIVE mk64: x       = 0x%16s                %s\n",
+         buf, pass ? "PASSED" : "FAILED");
+  if (!pass) failures++;
+#else
+  pass = (x.hi == INT64_TEST_HI && x.lo == INT64_TEST_LO);
+  printf("FAKE mk64:   x.hi    = 0x%08lx  x.lo    = 0x%08lx  %s\n",
+         x.hi, x.lo, pass ? "PASSED" : "FAILED");
+  if (!pass) failures++;
+#endif
+
+  pass = (hi64(x) == INT64_TEST_HI && lo64(x) == INT64_TEST_LO);
+  printf("hi64/lo64:   hi64(x) = 0x%08lx  lo64(x) = 0x%08lx  %s\n",
+         hi64(x), lo64(x), pass ? "PASSED" : "FAILED");
+  if (!pass) failures++;
+
+  ex64(x, hi, lo);
+  pass = (hi == INT64_TEST_HI && lo == INT64_TEST_LO);
+  printf("ex64:        hi      = 0x%08lx  lo      = 0x%08lx  %s\n",
+         hi, lo, pass ? "PASSED" : "FAILED");
+  if (!pass) failures++;
+
+  cp64(y, x);
+  pass = (hi64(y) == INT64_TEST_HI && lo64(y) == INT64_TEST_LO);
+  printf("cp64:        hi64(y) = 0x%08lx  lo64(y) = 0x%08lx  %s\n",
+         hi64(y), lo64(y), pass ? "PASSED" : "FAILED");
+  if (!pass) failures++;
+
+  if (failures) printf("%d/4 tests FAILED\n\n", failures);
+  else          printf("All 4 tests PASSED\n\n");
+}
+
+
+void test_int64_compares()
+{
+#define NCOMPARE 9
+  u_int64 control, test[NCOMPARE];
+  char cbuf[17], tbuf[17];
+  int i, r, result[NCOMPARE];
+  int pass, failures, FAILURES = 0;
+
+  printf("Comparison tests:\n");
+
+  mk64(control, 0x12345678, 0xabcdabcd);
+  mk64(test[0], 0x12340000, 0xabcd0000);  result[0] = +1;
+  mk64(test[1], 0x12340000, 0xabcdabcd);  result[1] = +1;
+  mk64(test[2], 0x12340000, 0xabcdffff);  result[2] = +1;
+  mk64(test[3], 0x12345678, 0xabcd0000);  result[3] = +1;
+  mk64(test[4], 0x12345678, 0xabcdabcd);  result[4] =  0;
+  mk64(test[5], 0x12345678, 0xabcdffff);  result[5] = -1;
+  mk64(test[6], 0x1234ffff, 0xabcd0000);  result[6] = -1;
+  mk64(test[7], 0x1234ffff, 0xabcdabcd);  result[7] = -1;
+  mk64(test[8], 0x1234ffff, 0xabcdffff);  result[8] = -1;
+
+  for (i = 0; i < NCOMPARE; i++) {
+    failures = 0;
+    hexify_int64(&control, cbuf);
+    hexify_int64(&test[i], tbuf);
+
+    r = eq64(control, test[i]);
+    pass = (r == (result[i] == 0));   if (!pass) failures++;
+    printf("0x%s == 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+    r = ne64(control, test[i]);
+    pass = (r == (result[i] != 0));   if (!pass) failures++;
+    printf("0x%s != 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+    r = lt64(control, test[i]);
+    pass = (r == (result[i] <  0));   if (!pass) failures++;
+    printf("0x%s <  0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+    r = le64(control, test[i]);
+    pass = (r == (result[i] <= 0));   if (!pass) failures++;
+    printf("0x%s <= 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+    r = gt64(control, test[i]);
+    pass = (r == (result[i] >  0));   if (!pass) failures++;
+    printf("0x%s >  0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+    r = ge64(control, test[i]);
+    pass = (r == (result[i] >= 0));   if (!pass) failures++;
+    printf("0x%s >= 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+    r = zero64(test[i]);
+    pass = !r;                        if (!pass) failures++;
+    printf("0x%s is nonzero            %s\n",
+           tbuf, pass ? "PASSED" : "FAILED");
+
+    if (failures) printf("%d/7 tests on this pair FAILED\n\n", failures);
+    else          printf("All 7 tests on this pair PASSED\n\n");
+  }
+
+  mk64(control, 0, 0);
+  pass = zero64(control);  if (!pass) FAILURES++;
+  printf("0x0000000000000000 is zero               %s\n",
+         pass ? "PASSED" : "FAILED");
+  
+  if (FAILURES)
+    printf("%d/%d comparison tests FAILED\n\n", FAILURES, 7 * NCOMPARE + 1);
+  else
+    printf("All %d comparison tests PASSED\n\n", 7 * NCOMPARE + 1);
+}
+
+
+void test_int64_arith()
+{
+  printf("No arithmetic tests yet!!!\n");
+}
+
+
+void main() {
+  verify_int64_size();
+  test_int64_constructs();
+  test_int64_compares();
+  test_int64_arith();
+  exit(0);
+}
+#endif
diff --git a/src/tests/intNN.h b/src/tests/intNN.h
new file mode 100644 (file)
index 0000000..9646052
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+#ifndef _INTNN_H_
+#define _INTNN_H_
+
+/* intNN.h - Sized integer types */
+#include <afs/stds.h>
+#if 0
+typedef short afs_int16;
+typedef unsigned short afs_uint16;
+
+typedef long afs_int32;
+typedef unsigned long afs_uint32;
+#endif
+
+
+/* Support for 64-bit integers.
+ * Presently, only unsigned 64-bit numbers are supported.
+ */
+#define INT64_TEST_STR "0x12345678fedcba98"
+#define INT64_TEST_HI  0x12345678
+#define INT64_TEST_LO  0xfedcba98
+
+
+#ifdef NATIVE_INT64
+typedef unsigned NATIVE_INT64 u_int64;
+
+/* construct/extract/assign */
+#define mk64(X,H,L) ((X) = ( ((u_int64)(H) << 32) \
+                           | ((u_int64)(L) & 0xffffffff)))
+#define hi64(Y)     ((afs_uint32)(((Y) >> 32) & 0xffffffff))
+#define lo64(Y)     ((afs_uint32)((Y) & 0xffffffff))
+#define ex64(Y,H,L) ((H) = hi64(Y), (L) = lo64(Y))
+#define cp64(X,Y)   ((X) = (Y))
+#define get64(X)    (X)
+#define set64(X,V)  ((X) = (V))
+
+/* Comparison */
+#define eq64(X,Y)   ((X) == (Y))
+#define ne64(X,Y)   ((X) != (Y))
+#define lt64(X,Y)   ((X) <  (Y))
+#define le64(X,Y)   ((X) <= (Y))
+#define gt64(X,Y)   ((X) >  (Y))
+#define ge64(X,Y)   ((X) >= (Y))
+#define zero64(X)   (!(X))
+
+/* Arithmetic */
+#define add64_32(X,A,B) ((X) = (A) + (u_int64)(B))
+#define add64_64(X,A,B) ((X) = (A) + (B))
+#define sub64_32(X,A,B) ((X) = (A) - (u_int64)(B))
+#define sub64_64(X,A,B) ((X) = (A) - (B))
+
+/* Byte-order */
+#ifdef WORDS_BIGENDIAN
+#define hton64(X,Y) cp64(X,Y)
+#define ntoh64(X,Y) cp64(X,Y)
+#else
+#define hton64(X,Y) mk64(X,htonl(lo64(Y)),htonl(hi64(Y)))
+#define ntoh64(X,Y) mk64(X,ntohl(lo64(Y)),ntohl(hi64(Y)))
+#endif
+
+#else /* !NATIVE_INT64 */
+/** We have to provide our own 64-bit integers **/
+typedef struct { afs_uint32 hi, lo; } u_int64;
+
+/* construct/extract/assign */
+#define mk64(X,H,L) ((X).hi = (H), (X).lo = (L))
+#define ex64(Y,H,L) ((H) = (Y).hi, (L) = (Y).lo)
+#define hi64(Y)     ((Y).hi)
+#define lo64(Y)     ((Y).lo)
+#define cp64(X,Y)   ((X).hi = (Y).hi, (X).lo = (Y).lo)
+#define get64(X)    ((X).lo)
+#define set64(X,V)  ((X).hi = 0, (X).lo = (V))
+
+/* Comparison */
+#define eq64(A,B) ((A).hi == (B).hi && (A).lo == (B).lo)
+#define ne64(A,B) ((A).hi != (B).hi || (A).lo != (B).lo)
+#define lt64(A,B) ((A).hi <  (B).hi || ((A).hi == (B).hi && (A).lo <  (B).lo))
+#define le64(A,B) ((A).hi <  (B).hi || ((A).hi == (B).hi && (A).lo <= (B).lo))
+#define gt64(A,B) ((A).hi >  (B).hi || ((A).hi == (B).hi && (A).lo >  (B).lo))
+#define ge64(A,B) ((A).hi >  (B).hi || ((A).hi == (B).hi && (A).lo >= (B).lo))
+#define zero64(X) ((X).hi == 0 && (X).lo == 0)
+
+/* Arithmetic */
+#define add64_32(X,A,B) (                                              \
+  (X).lo = (A).lo + (B),                                               \
+  (X).hi = (A).hi +                                                    \
+   (((((A).lo & 0x80000000) ^  ((B) & 0x80000000)) && !((X).lo & 0x80000000)) \
+  || (((A).lo & 0x80000000) && ((B) & 0x80000000)))                     \
+  )
+#define add64_64(X,A,B) (add64_32(X,A,(B).lo), (X).hi += (B).hi)
+
+#define sub64_32(X,A,B) ((X).lo = (A).lo - (B), \
+                         (X).hi = (A).hi - ((A).lo < (B)))
+#define sub64_64(X,A,B) (sub64_32(X,A,(B).lo), (X).hi -= (B).hi)
+
+/* Byte-order */
+#define hton64(X,Y) mk64(X,htonl(hi64(Y)),htonl(lo64(Y)))
+#define ntoh64(X,Y) mk64(X,ntohl(hi64(Y)),ntohl(lo64(Y)))
+
+#endif /* NATIVE_INT64 */
+
+
+/* The following are too complex to be macros: */
+
+/* char *hexify_int64(u_int64 a, char *buf)
+ * Produces an ASCII representation of a in hexadecimal, and returns
+ * a pointer to the resulting string.  If buf is non-NULL, it is taken
+ * to be a pointer to the buffer to be used, which must be at least 17
+ * bytes long.  This function is thread-safe iff buf is provided.
+ */
+extern char *hexify_int64(u_int64 *, char *);
+
+/* char *decimate_int64(u_int64 a, char *buf)
+ * Produces an ASCII representation of a in decimal, and returns
+ * a pointer to the resulting string.  If buf is non-NULL, it is taken
+ * to be a pointer to the buffer to be used, which must be at least 21
+ * bytes long.  This function is thread-safe iff buf is provided.
+ */
+extern char *decimate_int64(u_int64 *, char *);
+
+/* void shift_int64(u_int64 a, int bits)
+ * Shifts the 64-bit integer in a by the specified number of bits.
+ * If bits is positive, the shift is to the left; if negative, the
+ * shift is to the right.
+ */
+extern void shift_int64(u_int64 *, int);
+
+#endif /* _INTNN_H_ */
diff --git a/src/tests/internal.h b/src/tests/internal.h
new file mode 100644 (file)
index 0000000..04233db
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* internal.h - Routines for internal use only */
+
+#include "xfiles.h"
+#include "dumpscan.h"
+
+
+/* parsevol.c - Routines to parse volume headers */
+extern afs_uint32 parse_volhdr(XFILE *, unsigned char *, tagged_field *, afs_uint32,
+                            tag_parse_info *, void *, void *);
+
+/* parsevnode.c - Routines to parse vnodes and their fields */
+extern afs_uint32 parse_vnode(XFILE *, unsigned char *, tagged_field *, afs_uint32,
+                           tag_parse_info *, void *, void *);
+
+/* directory.c - Routines for parsing AFS directories */
+extern afs_uint32 parse_directory(XFILE *, dump_parser *, afs_vnode *,
+                               afs_uint32, int);
+
+/* backuphdr.c - Generic support for backup system headers */
+extern afs_uint32 try_backuphdr(XFILE *X, unsigned char *tag, tagged_field *field,
+                             afs_uint32 value, tag_parse_info *pi,
+                             void *g_refcon, void *l_refcon);
+
+/* util.c - Random utilities */
+extern afs_uint32 handle_return(int, XFILE *, unsigned char, dump_parser *);
+extern void prep_pi(dump_parser *, tag_parse_info *);
+extern afs_uint32 match_next_vnode(XFILE *, dump_parser *, u_int64 *, afs_uint32);
diff --git a/src/tests/intr-read.c b/src/tests/intr-read.c
new file mode 100644 (file)
index 0000000..7c2d9df
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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 <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+#include <err.h>
+
+#define RETSIGTYPE void
+#ifndef MAXPATHLEN
+#ifdef PATH_MAX
+#define MAXPATHLEN PATH_MAX
+#else
+#define MAXPATHLEN 4096
+#endif
+#endif
+
+static sig_atomic_t set_alarm = 1;
+
+static RETSIGTYPE
+sigalrm(int foo)
+{
+    signal(SIGALRM, sigalrm);
+    set_alarm = 1;
+}
+
+static void
+try_read(const char *filename)
+{
+    int fd;
+
+    fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+       if (errno == EINTR)
+           err(1, "open %s was interrupted", filename);
+    } else {
+       close(fd);
+    }
+}
+
+static void
+find(const char *dirname)
+{
+    DIR *dir;
+    struct dirent *dp;
+
+    dir = opendir(dirname);
+    if (dir == NULL)
+       err (1, "opendir %s", dirname);
+    while ((dp = readdir(dir)) != NULL) {
+       char fname[MAXPATHLEN];
+       struct stat sb;
+
+       if (set_alarm) {
+           alarm(1);
+           set_alarm = 0;
+       }
+       if (strcmp (dp->d_name, ".") == 0
+           || strcmp (dp->d_name, "..") == 0)
+           continue;
+       snprintf(fname, sizeof(fname), "%s/%s", dirname, dp->d_name);
+       if (lstat(fname, &sb) < 0)
+           err(1, "stat %s", fname);
+       if (S_ISDIR(sb.st_mode))
+         find(fname);
+       else
+         try_read(fname);
+    }
+    closedir(dir);
+}
+
+int
+main(int argc, char **argv)
+{
+    struct sigaction sa;
+
+    sa.sa_handler = sigalrm;
+    sigfillset(&sa.sa_mask);
+    sa.sa_flags   = 0;
+    sigaction(SIGALRM, &sa, NULL);
+    while (--argc)
+       find(*++argv);
+    return 0;
+}
diff --git a/src/tests/intr-read1 b/src/tests/intr-read1
new file mode 100755 (executable)
index 0000000..387ce07
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: intr-read1,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+$objdir/intr-read ${AFSROOT}/stacken.kth.se/ftp/pub/gnu/gnu-0.2 || exit 1
+exit 0
diff --git a/src/tests/invalidate-file.c b/src/tests/invalidate-file.c
new file mode 100644 (file)
index 0000000..bbc6841
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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/mman.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <atypes.h>
+
+#include <kafs.h>
+
+#include <fs.h>
+#include <arlalib.h>
+
+#include <err.h>
+
+RCSID("$Id: invalidate-file.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+#ifdef KERBEROS
+
+static void
+create_write_file (char *filename)
+{
+    int ret;
+    int fd;
+
+    fs_invalidate (filename);
+
+    fd = open(filename, O_RDWR|O_CREAT, 0666);
+    if (fd < 0)
+       err (1, "open(rw): %s", filename);
+
+    ret = write (fd, "foo", 3);
+    if (ret < 0)
+       err (1, "write");
+    
+    fs_invalidate (filename);
+    
+    ret = write (fd, "foo", 3);
+    if (ret < 0)
+       err (1, "write2");
+    
+    ret = close (fd);
+    if (ret < 0)
+       err (1, "close");
+}
+
+static void
+read_file (char *filename)
+{
+    int ret;
+    int fd;
+    char buf[3];
+
+    fs_invalidate (filename);
+
+    fd = open(filename, O_RDONLY, 0666);
+    if (fd < 0)
+       err (1, "open(ro)");
+
+    ret = read (fd, buf, sizeof(buf));
+    if (ret < 0)
+       err (1, "read");
+    
+    fs_invalidate (filename);
+    
+    ret = read (fd, buf, sizeof(buf));
+    if (ret < 0)
+       err (1, "read");
+    
+    ret = close (fd);
+    if (ret < 0)
+       err (1, "close");
+}
+
+static void
+mmap_read_file (char *filename)
+{
+    int fd;
+    void *v;
+    char buf[6];
+
+    fs_invalidate (filename);
+
+    fd = open(filename, O_RDONLY, 0666);
+    if (fd < 0)
+       err (1, "open(ro-mmap)");
+
+    v = mmap (NULL, 6, PROT_READ, MAP_SHARED, fd, 0);
+    if (v == (void *)MAP_FAILED)
+       err (1, "mmap(ro) %s", filename);
+
+    memcpy (buf, v, 3);
+    fs_invalidate (filename);
+    memcpy (buf, v, 3);
+
+    munmap (v, 6);
+}
+
+static void
+mmap_write_file (char *filename)
+{
+    int fd;
+    void *v;
+
+    fs_invalidate (filename);
+
+    fd = open (filename, O_RDWR, 0666);
+    if (fd < 0)
+       err (1, "open(rw-mmap)");
+
+    v = mmap (NULL, 6, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    if (v == (void *)MAP_FAILED)
+       err (1, "mmap(rw) %s", filename);
+
+    memcpy (v, "foo", 3);
+    fs_invalidate (filename);
+    memcpy (v, "foo", 3);
+
+    munmap (v, 6);
+    close (fd);
+}
+
+int
+main(int argc, char **argv)
+{
+    char *filename = "foo";
+    
+
+#ifdef KERBEROS
+    if (!k_hasafs())
+#endif
+       exit (1);
+    
+    create_write_file (filename);
+    read_file (filename);
+    read_file (filename);
+    read_file (filename);
+    read_file (filename);
+    mmap_read_file (filename);
+    mmap_read_file (filename);
+    mmap_read_file (filename);
+    mmap_read_file (filename);
+    mmap_write_file (filename);
+    mmap_write_file (filename);
+    mmap_write_file (filename);
+    mmap_write_file (filename);
+    
+    return 0;
+}
+
+#else
+
+int
+main(int argc, char **argv)
+{
+
+    errx (1, "no kafs support");
+}
+#endif
diff --git a/src/tests/kill-softer.c b/src/tests/kill-softer.c
new file mode 100644 (file)
index 0000000..e14c7d0
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: kill-softer.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#endif
+
+static FILE *verbose;
+
+struct entry {
+    char *name;
+    int status;
+};
+
+static void
+kill_one (struct entry *ents, int ind, int curents);
+
+static void
+do_dir (const char *dirname);
+
+static void
+kill_dir (const char *dirname);
+
+static void
+kill_one (struct entry *ents, int ind, int curents)
+{
+    int ret;
+    int i;
+
+    ret = unlink (ents[ind].name);
+    if (ret < 0) {
+       if (errno == EISDIR || errno == EPERM)
+           do_dir (ents[ind].name);
+       else
+           err (1, "unlink %s", ents[ind].name);
+    }
+    ents[ind].status = 0;
+    for (i = 0; i <= ind; ++i) {
+       struct stat sb;
+
+       ret = lstat (ents[i].name, &sb);
+       if (ret == 0 || errno != ENOENT)
+           err (1, "%s still exists?", ents[i].name);
+    }
+
+    for (i = ind + 1; i < curents; ++i) {
+       struct stat sb;
+
+       ret = lstat (ents[i].name, &sb);
+       if (ret < 0)
+           err (1, "stat %s", ents[i].name);
+    }
+}
+
+static void
+do_dir (const char *dirname)
+{
+    int ret;
+
+    ret = chdir (dirname);
+    if (ret < 0)
+       err (1, "chdir %s", dirname);
+    kill_dir (dirname);
+    ret = chdir ("..");
+    if (ret < 0)
+       err (1, "chdir ..");
+    ret = rmdir (dirname);
+    if (ret < 0)
+       err (1, "rmdir %s", dirname);
+}
+
+static void
+kill_dir (const char *dirname)
+{
+    struct entry *ents;
+    int maxents;
+    int curents = 0;
+    DIR *dir;
+    struct dirent *dp;
+    int i;
+
+    fprintf (verbose, "reading %s\n", dirname);
+
+    dir = opendir (".");
+    if (dir == NULL)
+       err (1, "opendir %s", dirname);
+    maxents = 10;
+    ents = malloc (sizeof (*ents) * maxents);
+    if (ents == NULL)
+       err (1, "malloc");
+    while ((dp = readdir (dir)) != NULL) {
+       if (strcmp (dp->d_name, ".") == 0
+           || strcmp (dp->d_name, "..") == 0)
+           continue;
+
+       if (curents >= maxents) {
+           maxents *= 2;
+           ents = realloc (ents, sizeof(*ents) * maxents);
+           if (ents == NULL)
+               err (1, "realloc");
+       }
+       ents[curents].name   = strdup (dp->d_name);
+       ents[curents].status = 1;
+       ++curents;
+       fprintf (verbose, "  adding %s\n", dp->d_name);
+    }
+    closedir (dir);
+    dir = opendir (".");
+    if (dir == NULL)
+       err (1, "opendir %s", dirname);
+    i = 0;
+    while((dp = readdir (dir)) != NULL) {
+       if (strcmp (dp->d_name, ".") == 0
+           || strcmp (dp->d_name, "..") == 0)
+           continue;
+
+       if (strcmp (ents[i].name, dp->d_name) != 0) {
+           errx (1, "%s != %s", ents[i].name, dp->d_name);
+       }
+       fprintf (verbose, "  deleting %s\n", ents[i].name);
+       kill_one (ents, i, curents);
+       ++i;
+    }
+    if (i != curents)
+       errx (1, "missing %d entries in %s", curents - i, dirname);
+    closedir (dir);
+    free (ents);
+    fprintf (verbose, "end of %s\n", dirname);
+}
+
+int
+main(int argc, char **argv)
+{
+
+    verbose = fdopen (4, "w");
+    if (verbose == NULL) {
+       verbose = fopen ("/dev/null", "w");
+       if (verbose == NULL)
+           err (1, "fopen /dev/null");
+    }
+
+    if (argc != 2)
+       errx (1, "usage: %s directory", argv[0]);
+    do_dir (argv[1]);
+    return 0;
+}
diff --git a/src/tests/kill-softly.c b/src/tests/kill-softly.c
new file mode 100644 (file)
index 0000000..bc5558b
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: kill-softly.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#endif
+
+struct entry {
+    char *name;
+    int status;
+};
+
+static void
+kill_one (struct entry *ents, int ind, int curents);
+
+static void
+do_dir (const char *dirname);
+
+static void
+kill_dir (const char *dirname);
+
+static void
+kill_one (struct entry *ents, int ind, int curents)
+{
+    int ret;
+    int i;
+
+    ret = unlink (ents[ind].name);
+    if (ret < 0) {
+       if (errno == EISDIR || errno == EPERM)
+           do_dir (ents[ind].name);
+       else
+           err (1, "unlink %s", ents[ind].name);
+    }
+    ents[ind].status = 0;
+    for (i = 0; i <= ind; ++i) {
+       struct stat sb;
+
+       ret = lstat (ents[i].name, &sb);
+       if (ret == 0 || errno != ENOENT)
+           err (1, "%s still exists?", ents[i].name);
+    }
+
+    for (i = ind + 1; i < curents; ++i) {
+       struct stat sb;
+
+       ret = lstat (ents[i].name, &sb);
+       if (ret < 0)
+           err (1, "stat %s", ents[i].name);
+    }
+}
+
+static void
+do_dir (const char *dirname)
+{
+    int ret;
+
+    ret = chdir (dirname);
+    if (ret < 0)
+       err (1, "chdir %s", dirname);
+    kill_dir (dirname);
+    ret = chdir ("..");
+    if (ret < 0)
+       err (1, "chdir ..");
+    ret = rmdir (dirname);
+    if (ret < 0)
+       err (1, "rmdir %s", dirname);
+}
+
+static void
+kill_dir (const char *dirname)
+{
+    struct entry *ents;
+    int maxents;
+    int curents = 0;
+    DIR *dir;
+    struct dirent *dp;
+    int i;
+
+    dir = opendir (".");
+    if (dir == NULL)
+       err (1, "opendir %s", dirname);
+    maxents = 10;
+    ents = malloc (sizeof (*ents) * maxents);
+    if (ents == NULL)
+       err (1, "malloc");
+    while ((dp = readdir (dir)) != NULL) {
+       if (strcmp (dp->d_name, ".") == 0
+           || strcmp (dp->d_name, "..") == 0)
+           continue;
+
+       if (curents >= maxents) {
+           maxents *= 2;
+           ents = realloc (ents, sizeof(*ents) * maxents);
+           if (ents == NULL)
+               err (1, "realloc");
+       }
+       ents[curents].name   = strdup (dp->d_name);
+       ents[curents].status = 1;
+       ++curents;
+    }
+    closedir (dir);
+    for (i = 0; i < curents; ++i)
+       kill_one (ents, i, curents);
+    free (ents);
+}
+
+int
+main(int argc, char **argv)
+{
+
+    if (argc != 2)
+       errx (1, "usage: %s directory", argv[0]);
+    do_dir (argv[1]);
+    return 0;
+}
diff --git a/src/tests/kotest b/src/tests/kotest
new file mode 100755 (executable)
index 0000000..0745aa6
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: kotest,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+exec ${objdir}/../lib/ko/kotest
diff --git a/src/tests/large-dir-16384 b/src/tests/large-dir-16384
new file mode 100755 (executable)
index 0000000..66c0232
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: large-dir-16384,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+$objdir/large-dir large-dir-16384 16384
diff --git a/src/tests/large-dir-extra b/src/tests/large-dir-extra
new file mode 100755 (executable)
index 0000000..42ff3cd
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# $Id: large-dir-extra,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+for i in 10 20 30 31 40 50 60 70 80 90 100; do
+  $objdir/large-dir2 large-dir-$i $i || exit 1
+  $objdir/large-dir3 large-dir-$i $i || exit 1
+done
diff --git a/src/tests/large-dir.c b/src/tests/large-dir.c
new file mode 100644 (file)
index 0000000..f32bc2e
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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: large-dir.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#endif
+
+static int
+creat_files (const char *dirname, int count)
+{
+    struct stat sb;
+    int i;
+    DIR *d;
+    struct dirent *dp;
+    
+    if (mkdir (dirname, 0777) < 0)
+       err (1, "mkdir %s", dirname);
+
+    if (chdir (dirname) < 0)
+       err (1, "chdir %s", dirname);
+    if (stat (".", &sb) < 0)
+       err (1, "stat .");
+    if (sb.st_size != 2048)
+       errx (1, "size != 2048");
+    for (i = 0; i < count; ++i) {
+       char num[17];
+       int fd;
+
+       snprintf (num, sizeof(num), "%d", i);
+       
+       fd = open (num, O_CREAT | O_EXCL, 0777);
+       if (fd < 0)
+           err (1, "open %s", num);
+       if (close (fd) < 0)
+           err (1, "close %s", num);
+    }
+    if (stat (".", &sb) < 0)
+       err (1, "stat .");
+
+    d = opendir (".");
+    if (d == NULL)
+       err (1, "opendir .");
+    for (i = -2; i < count; ++i) {
+       char num[17];
+
+       dp = readdir (d);
+       if (dp == NULL)
+           errx (1, "out of entries at %d?", i);
+       if (i == -2)
+           strcpy (num, ".");
+       else if (i == -1)
+           strcpy (num, "..");
+       else
+           snprintf (num, sizeof(num), "%d", i);
+       if (strcmp (num, dp->d_name) != 0)
+           errx (1, "'%s' != '%s'", num, dp->d_name);
+    }
+    if (readdir (d) != NULL)
+       errx (1, "more entries?");
+    closedir (d);
+    for (i = 0; i < count; ++i) {
+       char num[17];
+
+       snprintf (num, sizeof(num), "%d", i);
+       
+       if (unlink (num) < 0)
+           err (1, "unlink %s", num);
+    }
+    d = opendir (".");
+    if (d == NULL)
+       err (1, "opendir .");
+    dp = readdir (d);
+    if (dp == NULL || strcmp (dp->d_name, ".") != 0)
+       errx (1, "where's .?");
+    dp = readdir (d);
+    if (dp == NULL || strcmp (dp->d_name, "..") != 0)
+       errx (1, "where's ..?");
+    if (readdir (d) != NULL)
+       errx (1, "even more entries?");
+    closedir (d);
+    if (stat (".", &sb) < 0)
+       err (1, "stat .");
+#if 0
+    if (sb.st_size != 2048)
+       errx (1, "size != 2048");
+#endif
+    return 0;
+}
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s directory number-of-files\n", __progname);
+    exit (ret);
+}
+
+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]);
+
+    return creat_files (argv[1], count);
+}
diff --git a/src/tests/large-dir2.c b/src/tests/large-dir2.c
new file mode 100644 (file)
index 0000000..be0a0b9
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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: large-dir2.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#endif
+
+static int
+creat_files (const char *dirname, int count)
+{
+    struct stat sb;
+    int i;
+    DIR *d;
+    struct dirent *dp;
+    
+    srand (time (NULL));
+
+    if (mkdir (dirname, 0777) < 0)
+       err (1, "mkdir %s", dirname);
+
+    if (chdir (dirname) < 0)
+       err (1, "chdir %s", dirname);
+    if (stat (".", &sb) < 0)
+       err (1, "stat .");
+#if 0
+    if (sb.st_size != 2048)
+       errx (1, "size != 2048");
+#endif
+    for (i = 0; i < count; ++i) {
+       char fname[256];
+       int len;
+       int j;
+       int fd;
+
+       len = 1 + rand () % (sizeof(fname) - 2);
+
+       for (j = 0; j < len; ++j)
+           fname[j] = 'A' + rand() % ('z' - 'A');
+       fname[j] = '\0';
+
+       fd = open (fname, O_CREAT | O_EXCL, 0777);
+       if (fd < 0)
+           err (1, "open %s", fname);
+       if (close (fd) < 0)
+           err (1, "close %s", fname);
+    }
+    if (stat (".", &sb) < 0)
+       err (1, "stat .");
+
+    d = opendir (".");
+    if (d == NULL)
+       err (1, "opendir .");
+    while ((dp = readdir (d)) != NULL) {
+       if (strcmp (dp->d_name, ".") == 0
+           || strcmp (dp->d_name, "..") == 0)
+           continue;
+
+       if (unlink (dp->d_name) < 0)
+           err (1, "unlink %s", dp->d_name);
+    }
+    closedir (d);
+    if (chdir ("..") < 0)
+       err (1, "chdir ..");
+    if (rmdir (dirname) < 0)
+       err (1, "rmdir");
+    return 0;
+}
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s directory number-of-files\n", __progname);
+    exit (ret);
+}
+
+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]);
+
+    return creat_files (argv[1], count);
+}
diff --git a/src/tests/large-dir3.c b/src/tests/large-dir3.c
new file mode 100644 (file)
index 0000000..0144529
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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: large-dir3.c,v 1.1 2002/01/22 19:54:41 hartmans Exp $");
+#endif
+
+static int
+creat_files (const char *dirname, int count)
+{
+    struct stat sb;
+    int i;
+    DIR *d;
+    struct dirent *dp;
+    
+    if (mkdir (dirname, 0777) < 0)
+       err (1, "mkdir %s", dirname);
+
+    if (chdir (dirname) < 0)
+       err (1, "chdir %s", dirname);
+    if (stat (".", &sb) < 0)
+       err (1, "stat .");
+    for (i = 0; i < count; ++i) {
+       char num[17];
+       int fd;
+
+       snprintf (num, sizeof(num), "%d", i);
+       
+       fd = open (num, O_CREAT | O_EXCL, 0777);
+       if (fd < 0)
+           err (1, "open %s", num);
+       if (close (fd) < 0)
+           err (1, "close %s", num);
+    }
+    if (stat (".", &sb) < 0)
+       err (1, "stat .");
+
+    d = opendir (".");
+    if (d == NULL)
+       err (1, "opendir .");
+    while ((dp = readdir (d)) != NULL) {
+       if (strcmp (dp->d_name, ".") == 0
+           || strcmp (dp->d_name, "..") == 0)
+           continue;
+
+       if (unlink (dp->d_name) < 0)
+           err (1, "unlink %s", dp->d_name);
+    }
+    closedir (d);
+    if (chdir ("..") < 0)
+       err (1, "chdir ..");
+    if (rmdir (dirname) < 0)
+       err (1, "rmdir");
+    return 0;
+}
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s directory number-of-files\n", __progname);
+    exit (ret);
+}
+
+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]);
+
+    return creat_files (argv[1], count);
+}
diff --git a/src/tests/large-filename b/src/tests/large-filename
new file mode 100644 (file)
index 0000000..6cadbe7
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id: large-filename,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+touch aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 2>/dev/null >/dev/null || exit 1
+rm aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 2>/dev/null >/dev/null || exit 1
+exit 0
diff --git a/src/tests/ls-afs b/src/tests/ls-afs
new file mode 100644 (file)
index 0000000..1f66341
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: ls-afs,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+ls -l $AFSROOT >/dev/null
+true
diff --git a/src/tests/make-page.c b/src/tests/make-page.c
new file mode 100644 (file)
index 0000000..9a04299
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+
+#include <err.h>
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+    int mb = 10;
+    int ret;
+    size_t sz;
+    void *mmap_buf;
+
+    srand(getpid() * time(NULL));
+
+    sz = mb * 1024 * 1024;
+
+#ifdef MAP_ANON
+    mmap_buf = mmap (NULL, sz, PROT_READ|PROT_WRITE,
+                    MAP_ANON|MAP_PRIVATE, -1, 0);
+#else
+    {
+       int fd;
+
+       fd = open ("/dev/zero", O_RDWR);
+       if (fd < 0)
+           err (1, "open /dev/zero");
+       mmap_buf = mmap (NULL, sz, PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE, fd, 0);
+       close (fd);
+    }
+#endif
+    if (mmap_buf == (void *)MAP_FAILED)
+       err (1, "mmap");    
+
+    while (1) {
+       int *foo = (int *) ((unsigned char *) mmap_buf + (((rand() % (sz - 9)) + 7) & ~7));
+       struct timeval tv = { 0, 1000} ;
+       *foo = 10;
+       select (0, NULL, NULL, NULL, &tv);
+    }
+    
+    ret = munmap (mmap_buf, sz);
+    if (ret)
+       err (1, "munmap");
+}
diff --git a/src/tests/many-dirs b/src/tests/many-dirs
new file mode 100644 (file)
index 0000000..2976102
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id: many-dirs,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+mkdir foobar || exit 1
+(cd foobar && $objdir/create-dirs 1000) || exit 1
+$objdir/rm-rf foobar || exit 1
diff --git a/src/tests/many-fetchs b/src/tests/many-fetchs
new file mode 100644 (file)
index 0000000..77aa1c4
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+# $Id: many-fetchs,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+FS=${FS:-${objdir}/../appl/fs/fs}
+
+touch foo
+
+echo "foobar" > foo
+
+for i in `awk 'BEGIN {for(i=0; i < 1000; ++i) printf "%d\n", i}' /dev/null`; do
+    ${FS} flush foo
+    cat foo > /dev/null || exit 1
+done
+
+rm foo
\ No newline at end of file
diff --git a/src/tests/many-files b/src/tests/many-files
new file mode 100644 (file)
index 0000000..f4e7e9e
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: many-files,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+$objdir/create-files 1000 0
diff --git a/src/tests/many-files-with-content b/src/tests/many-files-with-content
new file mode 100644 (file)
index 0000000..ef20c73
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: many-files-with-content,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+$objdir/create-files 1000 10
diff --git a/src/tests/many-stores b/src/tests/many-stores
new file mode 100644 (file)
index 0000000..c91109c
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $Id: many-stores,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+touch foo
+
+for i in `awk 'BEGIN {for(i=0; i < 1000; ++i) printf "%d\n", i}' /dev/null`; do
+    echo "foo$i" >> foo || exit 1
+done
+
+rm foo
\ No newline at end of file
diff --git a/src/tests/many-symlinks b/src/tests/many-symlinks
new file mode 100644 (file)
index 0000000..5aff2da
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: many-symlinks,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+
+$objdir/create-symlinks 1000
diff --git a/src/tests/mkdir b/src/tests/mkdir
new file mode 100644 (file)
index 0000000..9616bf9
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $Id: mkdir,v 1.1 2002/01/22 19:54:41 hartmans Exp $
+mkdir foo || exit 1
+echo hej > foo/1 || exit 1
+rmdir foo >/dev/null 2>&1 
+test -d foo || exit 1
+rm -f foo/1 || exit 1
+rmdir foo || exit 1
+test -d foo && exit 1
+exit 0
diff --git a/src/tests/mkdir-lnk b/src/tests/mkdir-lnk
new file mode 100755 (executable)
index 0000000..f2247a2
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+mkdir foo || exit 1
+ls -ld foo | awk '{if($2 != 2) { exit(1) }}'  || exit 1
+mkdir foo/1 || exit 1
+ls -ld foo | awk '{if($2 != 3) { exit(1) }}'  || exit 1
+mkdir foo/2 || exit 1
+ls -ld foo | awk '{if($2 != 4) { exit(1) }}'  || exit 1
+rmdir foo/1 || exit 1
+ls -ld foo | awk '{if($2 != 3) { exit(1) }}'  || exit 1
+rmdir foo/2 || exit 1
+ls -ld foo | awk '{if($2 != 2) { exit(1) }}'  || exit 1
+rmdir foo || exit 1
diff --git a/src/tests/mkdir1 b/src/tests/mkdir1
new file mode 100755 (executable)
index 0000000..e5c9825
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# $Id: mkdir1,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+mkdir foobar || exit 1
+test -d foobar || exit 1
+test -d foobar/. || exit 1
+test -d foobar/.. || exit 1
+rmdir foobar || exit 1
diff --git a/src/tests/mkdir2.c b/src/tests/mkdir2.c
new file mode 100644 (file)
index 0000000..75f58cf
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 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 <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: mkdir2.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+int
+main(int argc, char *argv[])
+{
+    int ret;
+    struct stat dot_sb, sb;
+
+
+    ret = mkdir ("foo", 0777);
+    if (ret < 0)
+       err (1, "mkdir foo");
+    ret = lstat (".", &dot_sb);
+    if (ret < 0)
+       err (1, "lstat .");
+    ret = lstat ("foo", &sb);
+    if (ret < 0)
+       err (1, "lstat foo");
+    if (sb.st_nlink != 2)
+       errx (1, "sb.st_link != 2");
+    ret = lstat ("foo/.", &sb);
+    if (ret < 0)
+       err (1, "lstat foo/.");
+    if (sb.st_nlink != 2)
+       errx (1, "sb.st_link != 2");
+    ret = lstat ("foo/..", &sb);
+    if (ret < 0)
+       err (1, "lstat foo");
+    if (sb.st_nlink != dot_sb.st_nlink)
+       errx (1, "sb.st_link != dot_sb.st_nlink");
+    ret = rmdir ("foo");
+    if (ret < 0)
+       err (1, "rmdir foo");
+    return 0;
+}
diff --git a/src/tests/mkdir3.c b/src/tests/mkdir3.c
new file mode 100644 (file)
index 0000000..6e1582a
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 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 <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: mkdir3.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+int
+main(int argc, char *argv[])
+{
+    int ret;
+    struct stat dot_sb, sb;
+    int fd;
+
+    ret = mkdir ("foo", 0777);
+    if (ret < 0)
+       err (1, "mkdir foo");
+    ret = lstat (".", &dot_sb);
+    if (ret < 0)
+       err (1, "lstat .");
+    ret = lstat ("foo", &sb);
+    if (ret < 0)
+       err (1, "lstat foo");
+    if (sb.st_nlink != 2)
+       errx (1, "sb.st_link != 2");
+    ret = lstat ("foo/.", &sb);
+    if (ret < 0)
+       err (1, "lstat foo/.");
+    if (sb.st_nlink != 2)
+       errx (1, "sb.st_link != 2");
+    ret = lstat ("foo/..", &sb);
+    if (ret < 0)
+       err (1, "lstat foo");
+    if (sb.st_nlink != dot_sb.st_nlink)
+       errx (1, "sb.st_link != dot_sb.st_nlink");
+    ret = mkdir ("foo/bar", 0777);
+    if (ret < 0)
+       err (1, "mkdir bar");
+    fd = open ("foo/baz", O_CREAT|O_RDWR, 0600);
+    if (fd < 0)
+       err (1, "creat baz");
+    close(fd);
+    ret = lstat ("foo", &sb);
+    if (ret < 0)
+       err (1, "lstat foo");
+    if (sb.st_nlink != 3)
+       errx (1, "sb.st_link != 3");
+    ret = unlink ("foo/baz");
+    if (ret < 0)
+       err (1, "unlink baz");
+    ret = rmdir ("foo/bar");
+    if (ret < 0)
+       err (1, "rmdir bar");
+    ret = rmdir ("foo");
+    if (ret < 0)
+       err (1, "rmdir foo");
+    return 0;
+}
diff --git a/src/tests/mkm-rmm b/src/tests/mkm-rmm
new file mode 100755 (executable)
index 0000000..e3ab0b2
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# $Id: mkm-rmm,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+FS=${FS:-${objdir}/../appl/fs/fs}
+${FS} sa . system:anyuser all || exit 1
+${FS} mkm root.cell root.cell || exit 1
+test -d root.cell || exit 1 
+${FS} rmm root.cell || exit 1
+test -d root.cell && exit 1 
+${FS} mkm root.cell root.cell || exit 1
+test -d root.cell || exit 1 
+${FS} rmm root.cell || exit 1
+test -d root.cell && exit 1 
+exit 0
diff --git a/src/tests/mmap-and-read.c b/src/tests/mmap-and-read.c
new file mode 100644 (file)
index 0000000..5b6cdac
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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 <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: mmap-and-read.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+static char *
+generate_random_file (const char *filename,
+                     unsigned npages,
+                     unsigned pagesize,
+                     int writep)
+{
+    int fd;
+    char *buf, *fbuf;
+    int i;
+    int prot;
+    int flags;
+    size_t sz = npages * pagesize;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+
+    for (i = 0; i < npages; ++i)
+       memset (buf + pagesize * i, '0' + i, pagesize);
+
+    fd = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
+    if (fd < 0)
+       err (1, "open %s", filename);
+
+    if (ftruncate (fd, sz) < 0)
+       err (1, "ftruncate");
+
+    prot = PROT_READ | PROT_WRITE;
+    flags = MAP_SHARED;
+
+    fbuf = mmap (0, sz, prot, flags, fd, 0);
+    if (fbuf == (void *)MAP_FAILED)
+       err (1, "mmap");
+
+    if (writep) {
+       if(write(fd, "hej\n", 4) != 4)
+           err(1, "write");
+    }
+
+    memcpy (fbuf, buf, sz);
+
+#if 0
+    if (msync (fbuf, sz, MS_SYNC))
+       err(1, "msync");
+#endif
+
+    if (munmap (fbuf, sz) != 0)
+       err (1, "munmap");
+
+    if (close (fd))
+       err (1, "close");
+    return buf;
+}
+
+static char *
+read_file (int fd, size_t sz)
+{
+    char *buf;
+    ssize_t ret;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+    ret = read (fd, buf, sz);
+    if (ret < 0)
+        err (1, "read");
+    if (ret != sz)
+        errx(1, "short read %d < %u", (int)ret, (unsigned)sz);
+    return buf;
+}
+
+static int
+test (const char *file, int writep)
+{
+    const size_t sz  = 4 * getpagesize();
+    char *buf;
+    char *malloc_buf;
+    int fd;
+    int ret;
+
+    buf = generate_random_file (file, 4, getpagesize(), writep);
+
+    fd = open (file, O_RDONLY, 0);
+    if (fd < 0)
+       err (1, "open %s", file);
+
+    malloc_buf = read_file (fd, sz);
+    close (fd);
+    ret = memcmp (buf, malloc_buf, sz);
+    free (buf);
+    
+    return ret;
+}
+
+
+int
+main (int argc, char **argv)
+{
+
+
+    srand (time(NULL));
+
+    if (test ("foo", 1) != 0)
+       errx (1, "test(1)");
+    if (test ("bar", 0) != 0)
+       errx (1, "test(2)");
+
+    return 0;
+}
diff --git a/src/tests/mmap-cat.c b/src/tests/mmap-cat.c
new file mode 100644 (file)
index 0000000..3893022
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * 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 <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <err.h>
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+static void
+doit_mmap(int fd, struct stat *sb)
+{
+    void *mmap_buf;
+    int ret;
+
+    mmap_buf = mmap (NULL, sb->st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (mmap_buf == (void *)MAP_FAILED)
+       err (1, "mmap");
+    ret = write (1, mmap_buf, sb->st_size);
+    if (ret != sb->st_size)
+       err(1, "write returned %d wanted to write %d",
+           ret, (int)sb->st_size);
+    munmap(mmap_buf, sb->st_size);
+}
+
+
+static void
+doit_read(int fd, struct stat *sb)
+{
+    int ret;
+    void *read_buf;
+
+    read_buf = malloc(sb->st_size);
+    if (read_buf == NULL)
+       err(1, "malloc(%d)", (int)sb->st_size);
+    ret = read(fd, read_buf, sb->st_size);
+    if (ret != sb->st_size)
+       err(1, "read returned %d wanted to write %d",
+           ret, (int)sb->st_size);
+    ret = write (1, read_buf, sb->st_size);
+    if (ret != sb->st_size)
+       err(1, "write returned %d wanted to write %d",
+           ret, (int)sb->st_size);
+    free(read_buf);
+}
+
+static void
+doit (const char *filename, void (*func)(int, struct stat *))
+{
+    struct stat sb;
+    int fd;
+    int ret;
+
+    fd = open (filename, O_RDONLY);
+    if (fd < 0)
+       err(1, "open %s", filename);
+    ret = fstat (fd, &sb);
+    (*func)(fd, &sb);
+    if (ret < 0)
+       err (1, "stat %s", filename);
+    close (fd);
+}
+
+static int read_flag;
+static int mmap_flag;
+static int help_flag;
+
+static void
+usage (int exit_val)
+{
+    fprintf(stderr, "mmap-cat [-m|-r] filename\n");
+    exit (exit_val);
+}
+
+int
+main(int argc, char **argv)
+{
+    int optind = 0;
+
+    if (argc != 2)
+       usage(1);
+
+    if (!strcmp(argv[1],"-m")) {
+      mmap_flag++;
+    } else
+    if (!strcmp(argv[1],"-r")) {
+      read_flag++;
+    } else
+      usage (1);
+
+    if (read_flag && mmap_flag)
+       errx(1, "can't do both mmap and read");
+
+    if (read_flag)
+       doit(argv[0], doit_read);
+    if (mmap_flag)
+       doit(argv[0], doit_mmap);
+
+    return 0;
+}
diff --git a/src/tests/mmap-shared-write.c b/src/tests/mmap-shared-write.c
new file mode 100644 (file)
index 0000000..66ad31f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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 <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+#ifdef RCSID
+RCSID("$Id: mmap-shared-write.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+static int
+doit (const char *filename)
+{
+    int fd;
+    size_t sz = getpagesize ();
+    void *v;
+
+    fd = open (filename, O_RDWR | O_CREAT, 0600);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    if (ftruncate (fd, sz) < 0)
+       err (1, "ftruncate %s", filename);
+    v = mmap (NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (v == (void *)MAP_FAILED)
+       err (1, "mmap %s", filename);
+
+    memset (v, 'z', sz);
+
+    msync (v, sz, MS_SYNC);
+
+    if (close (fd) < 0)
+       err (1, "close %s", filename);
+    return 0;
+}
+
+static void
+usage(void)
+{
+    errx (1, "usage: [filename]");
+}
+
+int
+main (int argc, char **argv)
+{
+    const char *filename = "foo";
+
+
+    if (argc != 1 && argc != 2)
+       usage ();
+
+    if (argc == 2)
+       filename = argv[1];
+
+    return doit (filename);
+}
diff --git a/src/tests/mmap-vs-read.c b/src/tests/mmap-vs-read.c
new file mode 100644 (file)
index 0000000..dc45c06
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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 <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: mmap-vs-read.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+static int debug = 0;
+
+static void
+generate_file (const char *filename, int randomp, size_t sz)
+{
+    int fd;
+    char *buf;
+    int i;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+
+    fd = open (filename, O_WRONLY | O_CREAT, 0666);
+    if (fd < 0)
+       err (1, "open %s", filename);
+
+    for (i = 0; i < sz; ++i)
+       if (randomp)
+           buf[i] = rand();
+       else
+           buf[0] = 0;
+
+    if (write (fd, buf, sz) != sz)
+       err (1, "write");
+    if (close (fd))
+       err (1, "close");
+    free (buf);
+}
+
+static char *
+read_file (int fd, size_t sz)
+{
+    char *buf;
+    ssize_t ret;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+    ret = read (fd, buf, sz);
+    if (ret < 0)
+        err(1, "read");
+    if (ret != sz)
+        errx(1, "short read %d < %u", (int)ret, (unsigned)sz);
+    return buf;
+}
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+static void *
+mmap_file (int fd, size_t sz)
+{
+    void *ret;
+
+    ret = mmap (0, sz, PROT_READ, MAP_SHARED, fd, 0);
+    if (ret == (void *)MAP_FAILED)
+       err (1, "mmap");
+    return ret;
+}
+
+static void __attribute__ ((__unused__))
+print_area (unsigned char *ptr,  size_t len)
+{
+    while (len--) {
+       printf ("%x", *ptr);
+       ptr++;
+    }
+}
+
+static int
+do_test (int randomp)
+{
+    unsigned char *malloc_buf;
+    void *mmap_buf;
+    int fd;
+    const char *file = "foo";
+    const size_t sz  = 4 * getpagesize();
+
+    generate_file (file, randomp, sz);
+
+    fd = open (file, O_RDONLY, 0);
+    if (fd < 0)
+       err (1, "open %s", file);
+
+    mmap_buf   = mmap_file (fd, sz);
+    malloc_buf = read_file (fd, sz);
+    close (fd);
+    unlink (file);
+    if (memcmp (malloc_buf, mmap_buf, sz) != 0) {
+       if (debug) {
+           printf ("type: %s\n", randomp ? "random" : "allzero");
+           printf ("read: ");
+           print_area (malloc_buf, sz);
+           printf ("\nmmap: ");
+           print_area (mmap_buf, sz);
+           printf ("\n");
+       }
+       return 1;
+    }
+    return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+
+    if (argc != 1)
+       debug = 1;
+
+    srand (time(NULL));
+
+    if (do_test (0))
+       return 1;
+    if (do_test (1))
+       return 2;
+
+    return 0;
+}
diff --git a/src/tests/mmap-vs-read2.c b/src/tests/mmap-vs-read2.c
new file mode 100644 (file)
index 0000000..c9f2ca4
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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 <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: mmap-vs-read2.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+static int debug = 0;
+
+static void
+generate_file (const char *filename, int randomp, size_t sz)
+{
+    int fd;
+    char *buf;
+    int i;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+
+    fd = open (filename, O_WRONLY | O_CREAT, 0666);
+    if (fd < 0)
+       err (1, "open %s", filename);
+
+    for (i = 0; i < sz; ++i)
+       if (randomp)
+           buf[i] = rand();
+       else
+           buf[0] = 0;
+
+    if (write (fd, buf, sz) != sz)
+       err (1, "write");
+    if (close (fd))
+       err (1, "close");
+    free (buf);
+}
+
+static unsigned char *
+read_file (int fd, size_t sz)
+{
+    unsigned char *buf;
+    ssize_t ret;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+    ret = read(fd, buf, sz);
+    if(ret < 0)
+        err(1, "read");
+    if (ret != sz)
+        errx(1, "short read %d < %u", (int)ret, (unsigned)sz);
+    return buf;
+}
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+static void *
+mmap_file (int fd, size_t sz)
+{
+    void *ret;
+
+    ret = mmap (0, sz, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (ret == (void *)MAP_FAILED)
+       err (1, "mmap");
+    return ret;
+}
+
+static void __attribute__ ((__unused__))
+print_area (unsigned char *ptr,  size_t len)
+{
+    while (len--) {
+       printf ("%x", *ptr);
+       ptr++;
+    }
+}
+
+static int
+do_test (int randomp)
+{
+    unsigned char *malloc_buf;
+    void *mmap_buf;
+    int fd;
+    const char *file = "foo";
+    const size_t sz  = 3 * getpagesize() / 2;
+
+    generate_file (file, randomp, sz);
+
+    fd = open (file, O_RDONLY, 0);
+    if (fd < 0)
+       err (1, "open %s", file);
+
+    mmap_buf   = mmap_file (fd, sz);
+    malloc_buf = read_file (fd, sz);
+    close (fd);
+    unlink (file);
+    if (memcmp (malloc_buf, mmap_buf, sz) != 0) {
+       if (debug) {
+           printf ("type: %s\n", randomp ? "random" : "allzero");
+           printf ("read: ");
+           print_area (malloc_buf, sz);
+           printf ("\nmmap: ");
+           print_area (mmap_buf, sz);
+           printf ("\n");
+       }
+       return 1;
+    }
+    return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+
+    if (argc != 1)
+       debug = 1;
+
+    srand (time(NULL));
+
+    if (do_test (0))
+       return 1;
+    if (do_test (1))
+       return 2;
+
+    return 0;
+}
diff --git a/src/tests/mountpoint.in b/src/tests/mountpoint.in
new file mode 100644 (file)
index 0000000..5295ed8
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: mountpoint.in,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+FS=${FS:-${objdir}/../appl/fs/fs}
+${FS} sa . system:anyuser all || exit 1
+${FS} mkm no-such-volume no-such-volume 2>/dev/null || exit 1
+if ls no-such-volume 2>/dev/null && touch no-such-volume/foo 2>/dev/null; then
+  ${FS} rmm no-such-volume; exit 1
+fi
+${FS} rmm no-such-volume || exit 1
diff --git a/src/tests/null-search.c b/src/tests/null-search.c
new file mode 100644 (file)
index 0000000..39afb04
--- /dev/null
@@ -0,0 +1,150 @@
+#include <sys/fcntl.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "dumpscan.h"
+
+char *argv0;
+static char *input_path = 0;
+static int quiet = 0, showpaths = 0, searchcount = 1;
+static int error_count = 0, bad_count = 0;
+static path_hashinfo phi;
+static dump_parser dp;
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+  if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+  fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
+  fprintf(stderr, "  -h     Print this help message\n");
+  fprintf(stderr, "  -p     Print paths of bad vnodes\n");
+  fprintf(stderr, "  -q     Quiet mode (don't print errors)\n");
+  exit(status);
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+  int c;
+
+  if (argv0 = strrchr(argv[0], '/')) argv0++;
+  else argv0 = argv[0];
+
+  /* Parse the options */
+  while ((c = getopt(argc, argv, "n:hpq")) != EOF) {
+    switch (c) {
+      case 'n': searchcount  = atoi(optarg); continue;
+      case 'p': showpaths    = 1;            continue;
+      case 'q': quiet        = 1;            continue;
+      case 'h': usage(0, 0);
+      default:  usage(1, "Invalid option!");
+    }
+  }
+
+  if (argc - optind > 1) usage(1, "Too many arguments!");
+  input_path = (argc == optind) ? "-" : argv[optind];
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+  va_list alist;
+
+  error_count++;
+  if (!quiet) {
+    va_start(alist, msg);
+    com_err_va(argv0, code, msg, alist);
+    va_end(alist);
+  }
+}
+
+
+/* A callback to process file vnodes */
+static afs_uint32 my_file_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+  static char buf[1024];
+  afs_uint32 size, nulls, cnulls, maxcnulls, n, r;
+  char *name = 0;
+  int i;
+
+  nulls = cnulls = maxcnulls = 0;
+  size = v->size;
+  if ((r = xfseek(X, &v->d_offset))) return r;
+  while (size) {
+    n = (size > 1024) ? 1024 : size;
+    if (r = xfread(X, buf, n)) return r;
+    for (i = 0; i < n; i++) {
+      if (buf[i]) {
+        if (cnulls > maxcnulls) maxcnulls = cnulls;
+        cnulls = 0;
+      } else {
+        nulls++;
+        cnulls++;
+      }
+    }
+    size -= n;
+  }
+  if (maxcnulls >= searchcount) {
+    bad_count++;
+    if (showpaths) Path_Build(X, &phi, v->vnode, &name, 0);
+    if (name) {
+      printf("*** BAD %d (%s) - %d nulls, %d consecutive\n",
+             v->vnode, name, nulls, maxcnulls);
+      free(name);
+    } else {
+      printf("*** BAD %d - %d nulls, %d consecutive\n",
+             v->vnode, nulls, maxcnulls);
+    }
+  }
+  return r;
+}
+
+
+int main(int argc, char **argv)
+{
+  XFILE input_file;
+  afs_uint32 r;
+
+  parse_options(argc, argv);
+  initialize_acfg_error_table();
+  initialize_AVds_error_table();
+  initialize_rxk_error_table();
+  initialize_u_error_table();
+  initialize_vl_error_table();
+  initialize_vols_error_table();
+  initialize_xFil_error_table();
+  r = xfopen(&input_file, O_RDONLY, input_path);
+  if (r) {
+    com_err(argv0, r, "opening %s", input_path);
+    exit(2);
+  }
+
+  memset(&dp, 0, sizeof(dp));
+  dp.cb_error      = my_error_cb;
+  if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
+  if (showpaths) {
+    u_int64 where;
+
+    memset(&phi, 0, sizeof(phi));
+    phi.p = &dp;
+
+    if ((r = xftell(&input_file, &where))
+    ||  (r = Path_PreScan(&input_file, &phi, 0))
+    ||  (r = xfseek(&input_file, &where))) {
+      com_err(argv0, r, "- path initialization failed");
+      xfclose(&input_file);
+      exit(2);
+    }
+  }
+
+  dp.cb_vnode_file = my_file_cb;
+  r = ParseDumpFile(&input_file, &dp);
+  xfclose(&input_file);
+
+  if (error_count) printf("*** %d errors\n", error_count);
+  if (bad_count)   printf("*** %d bad files\n", bad_count);
+  if (r && !quiet) printf("*** FAILED: %s\n", error_message(r));
+}
diff --git a/src/tests/parallel1 b/src/tests/parallel1
new file mode 100644 (file)
index 0000000..83949ea
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: parallel1,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+$objdir/test-parallel1 1>&4
+
diff --git a/src/tests/parsedump.c b/src/tests/parsedump.c
new file mode 100644 (file)
index 0000000..edf6903
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* parsedump.c - Parse a volume dump file */
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+#include "internal.h"
+#include "stagehdr.h"
+
+static afs_uint32 parse_dumphdr  (XFILE *, unsigned char *, tagged_field *,
+                               afs_uint32, tag_parse_info *, void *, void *);
+static afs_uint32 parse_dumpend  (XFILE *, unsigned char *, tagged_field *,
+                               afs_uint32, tag_parse_info *, void *, void *);
+static afs_uint32 store_dumphdr  (XFILE *, unsigned char *, tagged_field *,
+                               afs_uint32, tag_parse_info *, void *, void *);
+static afs_uint32 parse_dumptimes(XFILE *, unsigned char *, tagged_field *,
+                               afs_uint32, tag_parse_info *, void *, void *);
+
+/** Field list for top-level objects **/
+static tagged_field top_fields[] = {
+  { TAG_DUMPHEADER,  DKIND_SPECIAL, "* DUMP HEADER",   parse_dumphdr, 0, 0 },
+  { TAG_VOLHEADER,   DKIND_SPECIAL, "* VOLUME HEADER", parse_volhdr,  0, 0 },
+  { TAG_VNODE,       DKIND_SPECIAL, "* VNODE ",        parse_vnode,   0, 0 },
+  { TAG_DUMPEND,     DKIND_INT32,   "* DUMP END",      parse_dumpend, 0, 0 },
+  { STAGE_VERSMIN,   DKIND_SPECIAL, "* STAGE HEADER",  try_backuphdr, 0, 0 },
+  { 0,0,0,0,0,0 }};
+
+
+/** Field list for dump headers **/
+static tagged_field dumphdr_fields[] = {
+  { DHTAG_VOLNAME,   DKIND_STRING,  " Volume name:  ", store_dumphdr,   0, 0 },
+  { DHTAG_VOLID,     DKIND_INT32,   " Volume ID:    ", store_dumphdr,   0, 0 },
+  { DHTAG_DUMPTIMES, DKIND_SPECIAL, " Dump Range:   ", parse_dumptimes, 0, 0 },
+  { 0,0,0,0,0,0 }};
+
+
+/* Parse a dump header, including its tagged attributes, and call the
+ * dump-header callback, if one is defined.
+ */
+static afs_uint32 parse_dumphdr(XFILE *X, unsigned char *tag, tagged_field *field,
+                             afs_uint32 value, tag_parse_info *pi,
+                             void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_dump_header hdr;
+  u_int64 where;
+  afs_uint32 r;
+
+  memset(&hdr, 0, sizeof(hdr));
+  if (r = xftell(X, &where)) return r;
+  sub64_32(hdr.offset, where, 1);
+
+  if (r = ReadInt32(X, &hdr.magic)) return r;
+  if (r = ReadInt32(X, &hdr.version)) return r;
+
+  if (hdr.magic != DUMPBEGINMAGIC) {
+    if (p->cb_error)
+      (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
+                    "Invalid magic number (0x%08x) in dump header",
+                    hdr.magic);
+    return DSERR_MAGIC;
+  }
+  if (hdr.version != DUMPVERSION) {
+    if (p->cb_error)
+      (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
+                    "Unknown dump format version (%d) in dump header",
+                    hdr.version);
+    return DSERR_MAGIC;
+  }
+
+  if (p->print_flags & DSPRINT_DUMPHDR)
+    printf("%s [%s = 0x%s]\n", field->label,
+      decimate_int64(&hdr.offset, 0), hexify_int64(&hdr.offset, 0));
+  if (p->print_flags & DSPRINT_DUMPHDR) {
+    printf(" Magic number: 0x%08x\n", hdr.magic);
+    printf(" Version:      %d\n", hdr.version);
+  }
+  r = ParseTaggedData(X, dumphdr_fields, tag, pi, g_refcon, (void *)&hdr);
+
+  if (!r && p->cb_dumphdr) {
+    r = xftell(X, &where);
+    if (!r) r = (p->cb_dumphdr)(&hdr, X, p->refcon);
+    if (p->flags & DSFLAG_SEEK) {
+      if (!r) r = xfseek(X, &where);
+      else xfseek(X, &where);
+    }
+  }
+  if (hdr.field_mask & F_DUMPHDR_VOLNAME)
+    free(hdr.volname);
+  return r;
+}
+
+
+/* Store tagged attributes into a dump header */
+static afs_uint32 store_dumphdr(XFILE *X, unsigned char *tag, tagged_field *field,
+                             afs_uint32 value, tag_parse_info *pi,
+                             void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_dump_header *hdr = (afs_dump_header *)l_refcon;
+
+  switch (field->tag) {
+  case DHTAG_VOLID:
+    hdr->field_mask |= F_DUMPHDR_VOLID;
+    hdr->volid = value;
+    if (p->print_flags & DSPRINT_DUMPHDR)
+      printf("%s%d\n", field->label, hdr->volid);
+    return 0;
+
+  case DHTAG_VOLNAME:
+    if (tag && tag[0]) {
+      hdr->field_mask |= F_DUMPHDR_VOLNAME;
+      hdr->volname = tag;
+      if (p->print_flags & DSPRINT_DUMPHDR)
+        printf("%s%s\n", field->label, hdr->volname);
+      return DSERR_KEEP;
+    } else return 0;
+
+  default:
+    if (p->print_flags & DSPRINT_DUMPHDR)
+      printf("%s<<< UNKNOWN FIELD >>>\n", field->label);
+    return 0;
+  }
+}
+
+
+/* Parse and store the dump time range from a dump header */
+static afs_uint32 parse_dumptimes(XFILE *X, unsigned char *tag,
+                               tagged_field *field, afs_uint32 value,
+                               tag_parse_info *pi,
+                               void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_dump_header *hdr = (afs_dump_header *)l_refcon;
+  afs_uint16 count;
+  afs_uint32 r;
+
+  if (r = ReadInt16(X, &count)) return r;
+  if (count != 2) {
+    if (p->cb_error)
+      (p->cb_error)(DSERR_FMT, 1, p->err_refcon,
+                    "Incorrect array count (%d) in dump times", count);
+    return DSERR_FMT;
+  }
+  if (r = ReadInt32(X, &hdr->from_date)) return r;
+  if (r = ReadInt32(X, &hdr->to_date)) return r;
+  hdr->field_mask |= (F_DUMPHDR_FROM | F_DUMPHDR_TO);
+  if (p->print_flags & DSPRINT_DUMPHDR)
+    printf("%s%d => %d\n", field->label, hdr->from_date, hdr->to_date);
+
+  return ReadByte(X, tag);
+}
+
+
+/* Parse a dump_end record */
+static afs_uint32 parse_dumpend(XFILE *X, unsigned char *tag, tagged_field *field,
+                             afs_uint32 value, tag_parse_info *pi,
+                             void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_uint32 r;
+
+  if (value != DUMPENDMAGIC) {
+    if (p->cb_error)
+      (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
+                    "Invalid magic number (0x%08x) in dump trailer",
+                    value);
+    return DSERR_MAGIC;
+  }
+  if (p->print_flags & (DSPRINT_DUMPHDR | DSPRINT_ITEM))
+    printf("%s\n", field->label);
+  return DSERR_DONE;
+}
+
+
+
+afs_uint32 ParseDumpFile(XFILE *X, dump_parser *p)
+{
+  tag_parse_info pi;
+  unsigned char tag;
+  afs_uint32 r;
+
+  prep_pi(p, &pi);
+  r = ParseTaggedData(X, top_fields, &tag, &pi, (void *)p, 0);
+  return handle_return(r, X, tag, p);
+}
+
+
+afs_uint32 ParseDumpHeader(XFILE *X, dump_parser *p)
+{
+  tag_parse_info pi;
+  unsigned char tag;
+  afs_uint32 r;
+
+  prep_pi(p, &pi);
+  if (r = ReadByte(X, &tag)) return handle_return(r, X, tag, p);
+  if (tag != TAG_DUMPHEADER) return handle_return(0, X, tag, p);
+  r = parse_dumphdr(X, &tag, &top_fields[0], 0, &pi, (void *)p, 0);
+  if (!r && tag >= 1 && tag <= 4) r = DSERR_DONE;
+  return handle_return(r, X, tag, p);
+}
+
+
+afs_uint32 ParseVolumeHeader(XFILE *X, dump_parser *p)
+{
+  tag_parse_info pi;
+  unsigned char tag;
+  afs_uint32 r;
+
+  prep_pi(p, &pi);
+  if (r = ReadByte(X, &tag)) return handle_return(r, X, tag, p);
+  if (tag != TAG_VOLHEADER) return handle_return(0, X, tag, p);
+  r = parse_volhdr(X, &tag, &top_fields[1], 0, &pi, (void *)p, 0);
+  if (!r && tag >= 1 && tag <= 4) r = DSERR_DONE;
+  return handle_return(r, X, tag, p);
+}
+
+
+afs_uint32 ParseVNode(XFILE *X, dump_parser *p)
+{
+  tag_parse_info pi;
+  unsigned char tag;
+  afs_uint32 r;
+
+  prep_pi(p, &pi);
+  if (r = ReadByte(X, &tag)) return handle_return(r, X, tag, p);
+  if (tag != TAG_VNODE) return handle_return(0, X, tag, p);
+  r = parse_vnode(X, &tag, &top_fields[2], 0, &pi, (void *)p, 0);
+  if (!r && tag >= 1 && tag <= 4) r = DSERR_DONE;
+  return handle_return(r, X, tag, p);
+}
diff --git a/src/tests/parsetag.c b/src/tests/parsetag.c
new file mode 100644 (file)
index 0000000..037ea38
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* parsetag.c - Parse a tagged data stream */
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+
+/* If a parser function is defined, it will be called after the data value
+ * (if any) is read.  The parser is called as follows:
+ *
+ *   parser(input_file, &tag, &field_rec, value, g_refcon, l_refcon);
+ *
+ * - input_file is the FILE * for the input stream
+ * - field_rec is a pointer to the field record for the field just read
+ * - g_refcon and l_refcon are as passed in to ParseTaggedData
+ * - For integer types, value is the integer value
+ * - For DKIND_STRING, tag is a pointer to the string just read
+ * - For DKIND_SPEACH, tag is a pointer to the place to put the next tag.
+ *
+ * If the field type is DKIND_SPECIAL, the parser is expected to read its
+ * own data from the input stream, and return when ParseTaggedData is supposed
+ * to take over, with the next tag to process in *tag.  At no other time
+ * should the parser read, write, or reposition the input stream.
+ *
+ * The parser routine should return 0 on success, non-0 on failure.  If the
+ * data type is DKIND_STRING, the parser may return DSERR_KEEP to indicate
+ * that the memory allocated for the value should not be freed.
+ */
+
+/* Parse a file containing tagged data and attributes **/
+afs_uint32 ParseTaggedData(XFILE *X, tagged_field *fields, unsigned char *tag,
+                    tag_parse_info *pi, void *g_refcon, void *l_refcon)
+{
+  int i = -1;
+  afs_uint32 r, val;
+  afs_uint16 val16;
+  unsigned char val8;
+  unsigned char *strval;
+
+  for (;;) {
+    if (i < 0 || (fields[i].kind & DKIND_MASK) != DKIND_SPECIAL) {
+      /* Need to read in a tag */
+      if (r = ReadByte(X, tag)) return r;
+    }
+
+    /* Simple error recovery - if we encounter a 0, it can never be
+     * a valid tag.  If TPFLAG_SKIP is set, we can skip over any
+     * such null bytes, and process whatever tag we find beyond.
+     * In addition, if TPFLAG_RSKIP is set, then the next time
+     * we encounter a 0, try skipping backwards.  That seems to
+     * work much of the time.
+     */
+    if (!*tag && pi->shift_offset && (pi->flags & TPFLAG_RSKIP)) {
+      u_int64 where, tmp64a, tmp64b;
+      char buf1[21], buf2[21], buf3[21];
+      char *p1, *p2, *p3;
+
+      if (r = xftell(X, &tmp64a)) return r;
+      sub64_32(where, tmp64a, pi->shift_offset + 1);
+      if (r = xfseek(X, &where)) return r;
+      if (pi->cb_error){
+        (pi->cb_error)(DSERR_FMT, 0, pi->err_refcon,
+                       "Inserted %d bytes before offset %d",
+                       pi->shift_offset, decimate_int64(&where, 0));
+        add64_32(tmp64a, pi->shift_start, pi->shift_offset);
+        p1 = decimate_int64(&tmp64a, buf1);
+        sub64_64(tmp64b, where, tmp64a);
+        p2 = decimate_int64(&tmp64b, buf2);
+        p3 = decimate_int64(&pi->shift_start, buf3);
+        (pi->cb_error)(DSERR_FMT, 0, pi->err_refcon,
+                       ">>> SHIFT start=%s length=%s target=%s",
+                       p1, p2, p3);
+      }
+      pi->shift_offset = 0;
+      if (r = ReadByte(X, tag)) return r;
+    }
+    if (!*tag && (pi->flags & TPFLAG_SKIP)) {
+      int count = 0;
+      u_int64 where, tmp64a;
+
+      if (r = xftell(X, &where)) return r;
+      
+      while (!*tag) {
+        if (r = ReadByte(X, tag)) return r;
+        count++;
+      }
+      pi->shift_offset += count;
+      cp64(pi->shift_start, where);
+      if (pi->cb_error) {
+        sub64_32(tmp64a, where, 1);
+        (pi->cb_error)(DSERR_FMT, 0, pi->err_refcon,
+                       "Skipped %d bytes at offset %s",
+                       count, decimate_int64(&tmp64a, 0));
+      }
+    }
+
+    for (i = 0; fields[i].tag && fields[i].tag != *tag; i++);
+    if (!fields[i].tag) return 0;
+
+    switch (fields[i].kind & DKIND_MASK) {
+    case DKIND_NOOP:
+      if (fields[i].func) {
+        r = (fields[i].func)(X, 0, fields+i, 0, pi, g_refcon, l_refcon);
+        if (r) return r;
+      }
+      break;
+
+    case DKIND_BYTE:
+      if (r = ReadByte(X, &val8)) return r;
+      if (fields[i].func) {
+        r = (fields[i].func)(X, 0, fields+i, val8, pi, g_refcon, l_refcon);
+        if (r) return r;
+      }
+      break;
+
+    case DKIND_INT16:
+      if (r = ReadInt16(X, &val16)) return r;
+      if (fields[i].func) {
+        r = (fields[i].func)(X, 0, fields+i, val16, pi, g_refcon, l_refcon);
+        if (r) return r;
+      }
+      break;
+
+    case DKIND_INT32:
+      if (r = ReadInt32(X, &val)) return r;
+      if (fields[i].func) {
+        r = (fields[i].func)(X, 0, fields+i, val, pi, g_refcon, l_refcon);
+        if (r) return r;
+      }
+      break;
+
+    case DKIND_STRING: 
+      if (r = ReadString(X, &strval)) return r;
+      if (fields[i].func) {
+        r = (fields[i].func)(X, strval, fields+i, 0, pi, g_refcon, l_refcon);
+        if (r != DSERR_KEEP) free(strval);
+        if (r && r != DSERR_KEEP) return r;
+      } else free(strval);
+      break;
+
+    case DKIND_SPECIAL:
+      if (fields[i].func) {
+        r = (fields[i].func)(X, tag, fields+i, 0, pi, g_refcon, l_refcon);
+        if (r) return r;
+      } else i = -1;
+    }
+  }
+}
diff --git a/src/tests/parsevnode.c b/src/tests/parsevnode.c
new file mode 100644 (file)
index 0000000..09f86ce
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* parsevnode.c - Parse a VNode */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+#include "internal.h"
+
+#include <afs/acl.h>
+#include <afs/prs_fs.h>
+
+static afs_uint32 LastGoodVNode = 0;
+static afs_uint32 store_vnode(XFILE *, unsigned char *, tagged_field *, afs_uint32,
+                           tag_parse_info *, void *, void *);
+static afs_uint32 parse_acl  (XFILE *, unsigned char *, tagged_field *, afs_uint32,
+                           tag_parse_info *, void *, void *);
+static afs_uint32 parse_vdata(XFILE *, unsigned char *, tagged_field *, afs_uint32,
+                           tag_parse_info *, void *, void *);
+
+/** Field list for vnodes **/
+static tagged_field vnode_fields[] = {
+  { VTAG_TYPE,        DKIND_BYTE,    " VNode type:   ", store_vnode, 0, 0 },
+  { VTAG_NLINKS,      DKIND_INT16,   " Link count:   ", store_vnode, 0, 0 },
+  { VTAG_DVERS,       DKIND_INT32,   " Version:      ", store_vnode, 0, 0 },
+  { VTAG_CLIENT_DATE, DKIND_TIME,    " Server Date:  ", store_vnode, 0, 0 },
+  { VTAG_AUTHOR,      DKIND_INT32,   " Author:       ", store_vnode, 0, 0 },
+  { VTAG_OWNER,       DKIND_INT32,   " Owner:        ", store_vnode, 0, 0 },
+  { VTAG_GROUP,       DKIND_INT32,   " Group:        ", store_vnode, 0, 0 },
+  { VTAG_MODE,        DKIND_INT16,   " UNIX mode:    ", store_vnode, 0, 0 },
+  { VTAG_PARENT,      DKIND_INT32,   " Parent:       ", store_vnode, 0, 0 },
+  { VTAG_SERVER_DATE, DKIND_TIME,    " Client Date:  ", store_vnode, 0, 0 },
+  { VTAG_ACL,         DKIND_SPECIAL, " xxxxxxxx ACL: ", parse_acl,   0, 0 },
+  { VTAG_DATA,        DKIND_SPECIAL, " Contents:     ", parse_vdata, 0, 0 },
+  { 0,0,0,0,0,0 }};
+
+
+static afs_uint32 resync_vnode(XFILE *X, dump_parser *p, afs_vnode *v,
+                            int start, int limit)
+{
+  u_int64 where, expected_where;
+  afs_uint32 r;
+  int i;
+
+  if (r = xftell(X, &expected_where)) return r;
+  cp64(where, expected_where);
+
+  r = match_next_vnode(X, p, &where, v->vnode);
+  if (r && r != DSERR_FMT) return r;
+  if (r) for (i = -start; i < limit; i++) {
+    add64_32(where, expected_where, i);
+    r = match_next_vnode(X, p, &where, v->vnode);
+    if (!r) break;
+    if (r != DSERR_FMT) return r;
+  }
+  if (r) {
+    if (p->cb_error)
+      (p->cb_error)(r, 1, p->err_refcon,
+                    "Unable to resync after vnode %d [%s = 0x%s]",
+                    v->vnode, decimate_int64(&expected_where, 0),
+                    hexify_int64(&expected_where, 0));
+    return r;
+  }
+  if (ne64(where, expected_where) && p->cb_error) {
+    (p->cb_error)(DSERR_FMT, 0, p->err_refcon,
+                  "Vnode after %d not in expected location",
+                  v->vnode);
+    (p->cb_error)(DSERR_FMT, 0, p->err_refcon, "Expected location: %s = 0x%s",
+                  decimate_int64(&expected_where, 0),
+                  hexify_int64(&expected_where, 0));
+    (p->cb_error)(DSERR_FMT, 0, p->err_refcon, "Actual location: %s = 0x%s",
+                  decimate_int64(&where, 0), hexify_int64(&where, 0));
+  }
+  return xfseek(X, &where);
+}
+
+
+/* Parse a VNode, including any tagged attributes and data, and call the
+ * appropriate callback, if one is defined.
+ */
+afs_uint32 parse_vnode(XFILE *X, unsigned char *tag, tagged_field *field,
+                    afs_uint32 value, tag_parse_info *pi,
+                    void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_uint32 (*cb)(afs_vnode *, XFILE *, void *);
+  u_int64 where, offset2k;
+  afs_vnode v;
+  afs_uint32 r;
+
+
+  if (r = xftell(X, &where)) return r;
+  memset(&v, 0, sizeof(v));
+  sub64_32(v.offset, where, 1);
+  if (r = ReadInt32(X, &v.vnode)) return r;
+  if (r = ReadInt32(X, &v.vuniq)) return r;
+
+  mk64(offset2k, 0, 2048);
+  if (!LastGoodVNode
+  || ((p->flags & DSFLAG_SEEK) && v.vnode == 1
+       && lt64(v.offset, offset2k)))
+    LastGoodVNode = -1;
+
+  if (p->print_flags & DSPRINT_ITEM) {
+    printf("%s %d/%d [%s = 0x%s]\n", field->label, v.vnode, v.vuniq,
+           decimate_int64(&where, 0), hexify_int64(&where, 0));
+  }
+
+  r = ParseTaggedData(X, vnode_fields, tag, pi, g_refcon, (void *)&v);
+
+  /* Try to resync, if requested */
+  if (!r && (p->repair_flags & DSFIX_VFSYNC)) {
+    afs_uint32 drop;
+    u_int64 xwhere;
+
+    if (r = xftell(X, &where)) return r;
+    sub64_32(xwhere, where, 1);
+
+    /* Are we at the start of a valid vnode (or dump end)? */
+    r = match_next_vnode(X, p, &xwhere, v.vnode);
+    if (r && r != DSERR_FMT) return r;
+    if (r) { /* Nope. */
+      /* Was _this_ a valid vnode?  If so, we can keep it and search for
+       * the next one.  Otherwise, we throw it out, and start the search
+       * at the starting point of this vnode.
+       */
+      drop = r = match_next_vnode(X, p, &v.offset, LastGoodVNode);
+      if (r && r != DSERR_FMT) return r;
+      if (!r) {
+        add64_32(where, v.offset, 1);
+        if (r = xfseek(X, &v.offset)) return r;
+      } else {
+        if (r = xfseek(X, &xwhere)) return r;
+      }
+      if (r = resync_vnode(X, p, &v, 0, 1024)) return r;
+      if (r = ReadByte(X, tag)) return r;
+      if (drop) {
+        if (p->cb_error)
+          (p->cb_error)(DSERR_FMT, 0, p->err_refcon,
+                        "Dropping vnode %d", v.vnode);
+        return 0;
+      }
+    } else {
+      if (r = xfseek(X, &where)) return r;
+    }
+  }
+  LastGoodVNode = v.vnode;
+
+  if (!r) {
+    if (v.field_mask & F_VNODE_TYPE)
+      switch (v.type) {
+      case vFile:      cb = p->cb_vnode_file;  break;
+      case vDirectory: cb = p->cb_vnode_dir;   break;
+      case vSymlink:   cb = p->cb_vnode_link;  break;
+      default:         cb = p->cb_vnode_wierd; break;
+      }
+    else               cb = p->cb_vnode_empty;
+    if (cb) {
+      u_int64 where;
+
+      if (r = xftell(X, &where)) return r;
+      r = (cb)(&v, X, p->refcon);
+      if (p->flags & DSFLAG_SEEK) {
+        if (!r) r = xfseek(X, &where);
+        else xfseek(X, &where);
+      }
+    }
+  }
+  return r;
+}
+
+
+/* Store data in a vnode */
+static afs_uint32 store_vnode(XFILE *X, unsigned char *tag, tagged_field *field,
+                           afs_uint32 value, tag_parse_info *pi,
+                           void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_vnode *v = (afs_vnode *)l_refcon;
+  time_t when;
+  afs_uint32 r = 0;
+
+  switch (field->tag) {
+  case VTAG_TYPE:
+    v->field_mask |= F_VNODE_TYPE;
+    v->type = value;
+    if (p->print_flags & DSPRINT_VNODE) {
+      switch (value) {
+      case vFile:
+        printf("%sFile (%d)\n", field->label, value);
+        break;
+      case vDirectory:
+        printf("%sDirectory (%d)\n", field->label, value);
+        break;
+      case vSymlink:
+        printf("%sSymbolic Link (%d)\n", field->label, value);
+        break;
+      default:
+        printf("%s??? (%d)\n", field->label, value);
+      }
+      return r;
+    }
+    break;
+
+  case VTAG_NLINKS:
+    v->field_mask |= F_VNODE_NLINKS;
+    v->nlinks = value;
+    break;
+
+  case VTAG_DVERS:
+    v->field_mask |= F_VNODE_DVERS;
+    v->datavers = value;
+    break;
+
+  case VTAG_CLIENT_DATE:
+    v->field_mask |= F_VNODE_CDATE;
+    v->client_date = value;
+    break;
+
+  case VTAG_SERVER_DATE:
+    v->field_mask |= F_VNODE_SDATE;
+    v->server_date = value;
+    break;
+
+  case VTAG_AUTHOR:
+    v->field_mask |= F_VNODE_AUTHOR;
+    v->author = value;
+    break;
+
+  case VTAG_OWNER:
+    v->field_mask |= F_VNODE_OWNER;
+    v->owner = value;
+    break;
+
+  case VTAG_GROUP:
+    v->field_mask |= F_VNODE_GROUP;
+    v->group = value;
+    break;
+
+  case VTAG_MODE:
+    v->field_mask |= F_VNODE_MODE;
+    v->mode = value;
+    break;
+
+  case VTAG_PARENT:
+    v->field_mask |= F_VNODE_PARENT;
+    v->parent = value;
+    break;
+  }
+
+  if (p->print_flags & DSPRINT_VNODE)
+    switch (field->kind) {
+    case DKIND_BYTE:
+    case DKIND_INT16:
+    case DKIND_INT32:  printf("%s%d\n",     field->label, value); break;
+    case DKIND_HEX8:   printf("%s0x%02x\n", field->label, value); break;
+    case DKIND_HEX16:  printf("%s0x%04x\n", field->label, value); break;
+    case DKIND_HEX32:  printf("%s0x%08x\n", field->label, value); break;
+    case DKIND_CHAR:   printf("%s%c\n",     field->label, value); break;
+    case DKIND_STRING: printf("%s%s\n",     field->label, tag);   break;
+    case DKIND_FLAG:
+      printf("%s%s\n", field->label, value ? "true" : "false");
+      break;
+    case DKIND_TIME:
+      when = value;
+      printf("%s%s", field->label, ctime(&when));
+      break;
+  }
+  return r;
+}
+
+
+static char *rights2str(afs_uint32 rights)
+{
+  static char str[16];
+  char *p = str;
+
+  if (rights & PRSFS_READ)       *p++ = 'r';
+  if (rights & PRSFS_LOOKUP)     *p++ = 'l';
+  if (rights & PRSFS_INSERT)     *p++ = 'i';
+  if (rights & PRSFS_DELETE)     *p++ = 'd';
+  if (rights & PRSFS_WRITE)      *p++ = 'w';
+  if (rights & PRSFS_LOCK)       *p++ = 'k';
+  if (rights & PRSFS_ADMINISTER) *p++ = 'a';
+  if (rights & PRSFS_USR0)       *p++ = 'A';
+  if (rights & PRSFS_USR1)       *p++ = 'B';
+  if (rights & PRSFS_USR2)       *p++ = 'C';
+  if (rights & PRSFS_USR3)       *p++ = 'D';
+  if (rights & PRSFS_USR4)       *p++ = 'E';
+  if (rights & PRSFS_USR5)       *p++ = 'F';
+  if (rights & PRSFS_USR6)       *p++ = 'G';
+  if (rights & PRSFS_USR7)       *p++ = 'H';
+
+  *p = 0;
+  if (!str[0]) strcpy(str, "none");
+  return str;
+}
+
+
+/* Parse and store the ACL data from a directory vnode */
+static afs_uint32 parse_acl(XFILE *X, unsigned char *tag, tagged_field *field,
+                         afs_uint32 value, tag_parse_info *pi,
+                         void *g_refcon, void *l_refcon)
+{
+  struct acl_accessList *acl;
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_vnode *v = (afs_vnode *)l_refcon;
+  afs_uint32 r, i, n;
+
+  if (r = xfread(X, v->acl, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE))
+    return r;
+
+  v->field_mask |= F_VNODE_ACL;
+  if (p->print_flags & DSPRINT_ACL) {
+    acl = (struct acl_accessList *)(v->acl);
+    n = ntohl(acl->positive);
+    if (n) {
+      printf("Positive ACL: %d entries\n", n);
+      for (i = 0; i < n; i++)
+        printf("              %9d  %s\n",
+               ntohl(acl->entries[i].id),
+               rights2str(acl->entries[i].rights));
+    }
+    n = ntohl(acl->negative);
+    if (n) {
+      printf("Positive ACL: %d entries\n", n);
+      for (i = ntohl(acl->positive); i < ntohl(acl->total); i++)
+        printf("              %9d  %s\n",
+               ntohl(acl->entries[i].id),
+               rights2str(acl->entries[i].rights));
+    }
+  }
+  return ReadByte(X, tag);
+}
+
+
+/* Parse or skip over the vnode data */
+static afs_uint32 parse_vdata(XFILE *X, unsigned char *tag, tagged_field *field,
+                           afs_uint32 value, tag_parse_info *pi,
+                           void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_vnode *v = (afs_vnode *)l_refcon;
+  static char *symlink_buf = 0;
+  static int symlink_size = 0;
+  afs_uint32 r;
+
+  if (r = ReadInt32(X, &v->size)) return r;
+  v->field_mask |= F_VNODE_SIZE;
+
+  if (v->size) {
+    v->field_mask |= F_VNODE_DATA;
+    if (r = xftell(X, &v->d_offset)) return r;
+    if (p->print_flags & DSPRINT_VNODE)
+      printf("%s%d (0x%08x) bytes at %s (0x%s)\n", field->label,
+             v->size, v->size, decimate_int64(&v->d_offset, 0),
+             hexify_int64(&v->d_offset, 0));
+    
+    switch (v->type) {
+    case vSymlink:
+      if (v->size > symlink_size) {
+        if (symlink_buf) symlink_buf = (char *)realloc(symlink_buf, v->size + 1);
+        else symlink_buf = (char *)malloc(v->size + 1);
+        symlink_size = symlink_buf ? v->size : 0;
+      }
+      if (symlink_buf) {
+        if (r = xfread(X, symlink_buf, v->size)) return r;
+        symlink_buf[v->size] = 0;
+        if (p->print_flags & DSPRINT_VNODE)
+          printf("Target:       %s\n", symlink_buf);
+      } else {
+        /* Call the callback here, because it's non-fatal */
+        if (p->cb_error)
+          (p->cb_error)(ENOMEM, 0, p->err_refcon,
+                        "Out of memory reading symlink");
+        if (r = xfskip(X, v->size)) return r;
+      }
+      break;
+
+    case vDirectory:
+      if (p->cb_dirent || (p->print_flags & DSPRINT_DIR)) {
+        if (r = parse_directory(X, p, v, v->size, 0)) return r;
+        break;
+      }
+
+    default:
+      if (r = xfskip(X, v->size)) return r;
+    }
+  } else if (p->print_flags & DSPRINT_VNODE) {
+    printf("%sEmpty\n", field->label);
+  }
+  if (p->repair_flags & DSFIX_VDSYNC) {
+    r = resync_vnode(X, p, v, 10, 15);
+    if (r) return r;
+  }
+  return ReadByte(X, tag);
+}
diff --git a/src/tests/parsevol.c b/src/tests/parsevol.c
new file mode 100644 (file)
index 0000000..86143dd
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* parsevol.c - Parse a volume header */
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+
+static afs_uint32 store_volhdr   (XFILE *, unsigned char *, tagged_field *,
+                               afs_uint32, tag_parse_info *, void *, void *);
+static afs_uint32 parse_weekuse  (XFILE *, unsigned char *, tagged_field *,
+                               afs_uint32, tag_parse_info *, void *, void *);
+
+/** Field list for volume headers **/
+static tagged_field volhdr_fields[] = {
+  { VHTAG_VOLID,     DKIND_INT32,   " Volume ID:   ", store_volhdr,  0, 0 },
+  { VHTAG_VERS,      DKIND_INT32,   " Version:     ", store_volhdr,  0, 0 },
+  { VHTAG_VOLNAME,   DKIND_STRING,  " Volume name: ", store_volhdr,  0, 0 },
+  { VHTAG_INSERV,    DKIND_FLAG,    " In service?  ", store_volhdr,  0, 0 },
+  { VHTAG_BLESSED,   DKIND_FLAG,    " Blessed?     ", store_volhdr,  0, 0 },
+  { VHTAG_VUNIQ,     DKIND_INT32,   " Uniquifier:  ", store_volhdr,  0, 0 },
+  { VHTAG_TYPE,      DKIND_BYTE,    " Type:        ", store_volhdr,  0, 0 },
+  { VHTAG_PARENT,    DKIND_INT32,   " Parent ID:   ", store_volhdr,  0, 0 },
+  { VHTAG_CLONE,     DKIND_INT32,   " Clone ID:    ", store_volhdr,  0, 0 },
+  { VHTAG_MAXQUOTA,  DKIND_INT32,   " Max quota:   ", store_volhdr,  0, 0 },
+  { VHTAG_MINQUOTA,  DKIND_INT32,   " Min quota:   ", store_volhdr,  0, 0 },
+  { VHTAG_DISKUSED,  DKIND_INT32,   " Disk used:   ", store_volhdr,  0, 0 },
+  { VHTAG_FILECNT,   DKIND_INT32,   " File count:  ", store_volhdr,  0, 0 },
+  { VHTAG_ACCOUNT,   DKIND_INT32,   " Account:     ", store_volhdr,  0, 0 },
+  { VHTAG_OWNER,     DKIND_INT32,   " Owner:       ", store_volhdr,  0, 0 },
+  { VHTAG_CREAT,     DKIND_TIME,    " Created:     ", store_volhdr,  0, 0 },
+  { VHTAG_ACCESS,    DKIND_TIME,    " Accessed:    ", store_volhdr,  0, 0 },
+  { VHTAG_UPDATE,    DKIND_TIME,    " Updated:     ", store_volhdr,  0, 0 },
+  { VHTAG_EXPIRE,    DKIND_TIME,    " Expires:     ", store_volhdr,  0, 0 },
+  { VHTAG_BACKUP,    DKIND_TIME,    " Backed up:   ", store_volhdr,  0, 0 },
+  { VHTAG_OFFLINE,   DKIND_STRING,  " Offine Msg:  ", store_volhdr,  0, 0 },
+  { VHTAG_MOTD,      DKIND_STRING,  " MOTD:        ", store_volhdr,  0, 0 },
+  { VHTAG_WEEKUSE,   DKIND_SPECIAL, " Weekuse:     ", parse_weekuse, 0, 0 },
+  { VHTAG_DUDATE,    DKIND_TIME,    " Dayuse Date: ", store_volhdr,  0, 0 },
+  { VHTAG_DAYUSE,    DKIND_INT32,   " Daily usage: ", store_volhdr,  0, 0 },
+  { 0,0,0,0,0,0 }};
+
+
+/* Parse a volume header, including any tagged attributes, and call the
+ * volume-header callback, if one is defined.
+ */
+afs_uint32 parse_volhdr(XFILE *X, unsigned char *tag, tagged_field *field,
+                     afs_uint32 value, tag_parse_info *pi,
+                     void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_vol_header hdr;
+  u_int64 where;
+  afs_uint32 r;
+
+  memset(&hdr, 0, sizeof(hdr));
+  if (r = xftell(X, &where)) return r;
+  sub64_32(hdr.offset, where, 1);
+  if (p->print_flags & DSPRINT_VOLHDR)
+    printf("%s [%s = 0x%s]\n", field->label,
+           decimate_int64(&hdr.offset, 0), hexify_int64(&hdr.offset, 0));
+
+  r = ParseTaggedData(X, volhdr_fields, tag, pi, g_refcon, (void *)&hdr);
+
+  if (!r && p->cb_volhdr) {
+    if (r = xftell(X, &where)) return r;
+    r = (p->cb_volhdr)(&hdr, X, p->refcon);
+    if (p->flags & DSFLAG_SEEK) {
+      if (!r) r = xfseek(X, &where);
+      else xfseek(X, &where);
+    }
+  }
+  if (hdr.field_mask & F_VOLHDR_VOLUNIQ)
+    p->vol_uniquifier = hdr.voluniq;
+  if (hdr.field_mask & F_VOLHDR_VOLNAME)
+    free(hdr.volname);
+  if (hdr.field_mask & F_VOLHDR_OFFLINE_MSG)
+    free(hdr.offline_msg);
+  if (hdr.field_mask & F_VOLHDR_MOTD)
+    free(hdr.motd_msg);
+  return r;
+}
+
+
+/* Store data in a volume header */
+static afs_uint32 store_volhdr(XFILE *X, unsigned char *tag, tagged_field *field,
+                            afs_uint32 value, tag_parse_info *pi,
+                            void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_vol_header *hdr = (afs_vol_header *)l_refcon;
+  time_t when;
+  afs_uint32 r = 0;
+
+  switch (field->tag) {
+  case VHTAG_VOLID:
+    hdr->field_mask |= F_VOLHDR_VOLID;
+    hdr->volid = value;
+    break;
+
+  case VHTAG_VERS:
+    hdr->field_mask |= F_VOLHDR_VOLVERS;
+    hdr->volvers = value;
+    break;
+
+  case VHTAG_VOLNAME:
+    if (tag && tag[0]) {
+      hdr->field_mask |= F_VOLHDR_VOLNAME;
+      hdr->volname = tag;
+      r = DSERR_KEEP;
+    }
+    break;
+
+  case VHTAG_INSERV:
+    hdr->field_mask |= F_VOLHDR_INSERV;
+    hdr->flag_inservice = value;
+    break;
+
+  case VHTAG_BLESSED:
+    hdr->field_mask |= F_VOLHDR_BLESSED;
+    hdr->flag_blessed = value;
+    break;
+
+  case VHTAG_VUNIQ:
+    hdr->field_mask |= F_VOLHDR_VOLUNIQ;
+    hdr->voluniq = value;
+    break;
+
+  case VHTAG_TYPE:
+    hdr->field_mask |= F_VOLHDR_VOLTYPE;
+    hdr->voltype = value;
+    break;
+
+  case VHTAG_PARENT:
+    hdr->field_mask |= F_VOLHDR_PARENT;
+    hdr->parent_volid = value;
+    break;
+
+  case VHTAG_CLONE:
+    hdr->field_mask |= F_VOLHDR_CLONE;
+    hdr->clone_volid = value;
+    break;
+
+  case VHTAG_MAXQUOTA:
+    hdr->field_mask |= F_VOLHDR_MAXQ;
+    hdr->maxquota = value;
+    break;
+
+  case VHTAG_MINQUOTA:
+    hdr->field_mask |= F_VOLHDR_MINQ;
+    hdr->minquota = value;
+    break;
+
+  case VHTAG_DISKUSED:
+    hdr->field_mask |= F_VOLHDR_DISKUSED;
+    hdr->diskused = value;
+    break;
+
+  case VHTAG_FILECNT:
+    hdr->field_mask |= F_VOLHDR_NFILES;
+    hdr->nfiles = value;
+    break;
+
+  case VHTAG_ACCOUNT:
+    hdr->field_mask |= F_VOLHDR_ACCOUNT;
+    hdr->account_no = value;
+    break;
+
+  case VHTAG_OWNER:
+    hdr->field_mask |= F_VOLHDR_OWNER;
+    hdr->owner = value;
+    break;
+
+  case VHTAG_CREAT:
+    hdr->field_mask |= F_VOLHDR_CREATE_DATE;
+    hdr->create_date = value;
+    break;
+
+  case VHTAG_ACCESS:
+    hdr->field_mask |= F_VOLHDR_ACCESS_DATE;
+    hdr->access_date = value;
+    break;
+
+  case VHTAG_UPDATE:
+    hdr->field_mask |= F_VOLHDR_UPDATE_DATE;
+    hdr->update_date = value;
+    break;
+
+  case VHTAG_EXPIRE:
+    hdr->field_mask |= F_VOLHDR_EXPIRE_DATE;
+    hdr->expire_date = value;
+    break;
+
+  case VHTAG_BACKUP:
+    hdr->field_mask |= F_VOLHDR_BACKUP_DATE;
+    hdr->backup_date = value;
+    break;
+
+  case VHTAG_OFFLINE:
+    if (tag && tag[0]) {
+      hdr->field_mask |= F_VOLHDR_OFFLINE_MSG;
+      hdr->offline_msg = tag;
+      r = DSERR_KEEP;
+    }
+    break;
+
+  case VHTAG_MOTD:
+    if (tag && tag[0]) {
+      hdr->field_mask |= F_VOLHDR_MOTD;
+      hdr->motd_msg = tag;
+      r = DSERR_KEEP;
+    }
+    break;
+
+  case VHTAG_DUDATE:
+    hdr->field_mask |= F_VOLHDR_DAYUSE_DATE;
+    hdr->dayuse_date = value;
+    break;
+
+  case VHTAG_DAYUSE:
+    hdr->field_mask |= F_VOLHDR_DAYUSE;
+    hdr->dayuse = value;
+    break;
+  }
+
+  if (p->print_flags & DSPRINT_VOLHDR)
+    switch (field->kind) {
+    case DKIND_BYTE:
+    case DKIND_INT16:
+    case DKIND_INT32:  printf("%s%d\n",     field->label, value); break;
+    case DKIND_HEX8:   printf("%s0x%02x\n", field->label, value); break;
+    case DKIND_HEX16:  printf("%s0x%04x\n", field->label, value); break;
+    case DKIND_HEX32:  printf("%s0x%08x\n", field->label, value); break;
+    case DKIND_CHAR:   printf("%s%c\n",     field->label, value); break;
+    case DKIND_STRING: printf("%s%s\n",     field->label, tag);   break;
+    case DKIND_FLAG:
+      printf("%s%s\n", field->label, value ? "true" : "false");
+      break;
+    case DKIND_TIME:
+      when = value;
+      printf("%s%s", field->label, ctime(&when));
+      break;
+  }
+  return r;
+}
+
+
+/* Parse and store the week use data from a volume header */
+static afs_uint32 parse_weekuse(XFILE *X, unsigned char *tag, tagged_field *field,
+                             afs_uint32 value, tag_parse_info *pi,
+                             void *g_refcon, void *l_refcon)
+{
+  dump_parser *p = (dump_parser *)g_refcon;
+  afs_vol_header *hdr = (afs_vol_header *)l_refcon;
+  afs_uint16 count;
+  afs_uint32 r;
+  unsigned int i;
+
+  if (r = ReadInt16(X, &count)) return r;
+  if (count != 7) {
+    if (p->cb_error)
+      (p->cb_error)(DSERR_FMT, 1, p->err_refcon,
+                    "Incorrect array count (%d) in weekuse data", count);
+    return DSERR_FMT;
+  }
+  for (i = 0; i < count; i++)
+    if (r = ReadInt32(X, hdr->weekuse + i)) return r;
+  hdr->field_mask |= F_VOLHDR_WEEKUSE;
+  if (p->print_flags & DSPRINT_VOLHDR) {
+    printf("%s%10d %10d %10d %10d\n", field->label,
+           hdr->weekuse[0], hdr->weekuse[1], hdr->weekuse[2], hdr->weekuse[3]);
+    printf("%s%10d %10d %10d\n", field->label,
+           hdr->weekuse[4], hdr->weekuse[5], hdr->weekuse[6]);
+  }
+  return ReadByte(X, tag);
+}
diff --git a/src/tests/pathname.c b/src/tests/pathname.c
new file mode 100644 (file)
index 0000000..ee3af28
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* pathname.c - Pathname lookup and traversal */
+
+#include <errno.h>
+#include <string.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+
+/* Hash function for a vnode */
+#define BUCKET_SIZE 32
+#define vnode_hash(phi,vnode) ((vnode) & ((1 << (phi)->hash_size) - 1))
+
+
+static vhash_ent *get_vhash_ent(path_hashinfo *phi, afs_uint32 vnode, int make)
+{
+  int key = vnode_hash(phi, vnode);
+  vhash_ent *vhe;
+
+  for (vhe = phi->hash_table[key];
+       vhe && vhe->vnode != vnode;
+       vhe = vhe->next);
+  if (make && !vhe) {
+    vhe = (vhash_ent *)malloc(sizeof(vhash_ent));
+    if (vhe) {
+      memset(vhe, 0, sizeof(vhash_ent));
+      vhe->vnode = vnode;
+      vhe->next = phi->hash_table[key];
+      phi->hash_table[key] = vhe;
+    }
+  }
+  return vhe;
+}
+
+
+static afs_uint32 volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
+{
+  path_hashinfo *phi = (path_hashinfo *)refcon;
+  int nfiles, hsize;
+
+  if (hdr->field_mask & F_VOLHDR_NFILES) {
+    nfiles = phi->n_vnodes = hdr->nfiles;
+    for (phi->hash_size = 1;
+         nfiles > BUCKET_SIZE;
+         phi->hash_size++, nfiles >>= 1);
+    hsize = (1 << phi->hash_size);
+    phi->hash_table = (vhash_ent **)malloc(hsize * sizeof(vhash_ent *));
+    if (!phi->hash_table) return ENOMEM;
+    memset(phi->hash_table, 0, hsize * sizeof(vhash_ent *));
+    return 0;
+  } else {
+    if (phi->p->cb_error)
+      (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+                         "File count missing from volume header");
+    return DSERR_FMT;
+  }
+}
+
+
+static afs_uint32 vnode_keep(afs_vnode *v, XFILE *X, void *refcon)
+{
+  path_hashinfo *phi = (path_hashinfo *)refcon;
+  vhash_ent *vhe;
+
+  if (!phi->hash_table) {
+    if (phi->p->cb_error)
+      (phi->p->cb_error)(DSERR_FMT, 1, phi->p->refcon,
+                         "No volume header in dump???");
+    return DSERR_FMT;
+  }
+  vhe = get_vhash_ent(phi, v->vnode, 1);
+  if (!vhe) return ENOMEM;
+  cp64(vhe->v_offset, v->offset);
+  if (v->field_mask & F_VNODE_PARENT)
+    vhe->parent = v->parent;
+  if (v->field_mask & F_VNODE_DATA) {
+    cp64(vhe->d_offset, v->d_offset);
+    vhe->d_size   = v->size;
+  }
+  if ((v->field_mask & F_VNODE_TYPE) && v->type == vDirectory)
+    phi->n_dirs++;
+  else
+    phi->n_files++;
+  return 0;
+}
+
+
+static afs_uint32 vnode_stop(afs_vnode *v, XFILE *X, void *refcon)
+{
+  path_hashinfo *phi = (path_hashinfo *)refcon;
+  int r;
+
+  /* If the file is seekable, try to position so we can pick up later... */
+  if (phi->p->flags && DSFLAG_SEEK)
+    if (r = xfseek(X, &v->offset)) return r;
+  return DSERR_DONE;
+}
+
+
+static afs_uint32 dirent_cb(afs_vnode *v, afs_dir_entry *de,
+                         XFILE *X, void *refcon)
+{
+  path_hashinfo *phi = (path_hashinfo *)refcon;
+  vhash_ent *vhe;
+
+  if (!phi->hash_table) {
+    if (phi->p->cb_error)
+      (phi->p->cb_error)(DSERR_FMT, 1, phi->p->refcon,
+                         "No volume header in dump???");
+    return DSERR_FMT;
+  }
+  if (!strcmp(de->name, ".") || !strcmp(de->name, "..")) return 0;
+  vhe = get_vhash_ent(phi, de->vnode, 1);
+  if (!vhe) return ENOMEM;
+  vhe->parent = v->vnode;
+  return 0;
+}
+
+
+/* Prescan the vnodes in a dump file, collecting information that will
+ * be useful in generating and following pathnames.  
+ */
+afs_uint32 Path_PreScan(XFILE *X, path_hashinfo *phi, int full)
+{
+  dump_parser my_p, *p = phi->p;
+  int r;
+
+  memset(phi, 0, sizeof(path_hashinfo));
+  phi->p = p;
+  memset(&my_p, 0, sizeof(my_p));
+  my_p.refcon       = (void *)phi;
+  my_p.cb_volhdr    = volhdr_cb;
+  my_p.cb_vnode_dir = vnode_keep;
+  if (full) {
+    my_p.cb_vnode_file  = vnode_keep;
+    my_p.cb_vnode_link  = vnode_keep;
+    my_p.cb_vnode_empty = vnode_keep;
+    my_p.cb_vnode_wierd = vnode_keep;
+  } else {
+    my_p.cb_vnode_file  = vnode_stop;
+    my_p.cb_vnode_link  = vnode_stop;
+    my_p.cb_vnode_empty = vnode_stop;
+    my_p.cb_vnode_wierd = vnode_stop;
+  }
+  my_p.err_refcon   = p->err_refcon;
+  my_p.cb_error     = p->cb_error;
+  my_p.cb_dirent    = dirent_cb;
+  my_p.flags        = p->flags;
+  my_p.print_flags  = p->print_flags;
+  my_p.repair_flags = p->repair_flags;
+
+  return ParseDumpFile(X, &my_p);
+}
+
+
+/* Free the hash table in a path_hashinfo */
+void Path_FreeHashTable(path_hashinfo *phi)
+{
+  int i, size;
+  vhash_ent *vhe, *next_vhe;
+
+  if (phi->hash_table) {
+    size = (1 << phi->hash_size);
+    for (i = 0; i < size; i++)
+      for (vhe = phi->hash_table[i]; vhe; vhe = next_vhe) {
+        next_vhe = vhe->next;
+        free(vhe);
+      }
+    free(phi->hash_table);
+  }
+}
+
+
+/* Follow a pathname to the vnode it represents */
+afs_uint32 Path_Follow(XFILE *X, path_hashinfo *phi,
+                    char *path, vhash_ent *his_vhe)
+{
+  vhash_ent *vhe;
+  char *name;
+  afs_uint32 r, vnum = 1;
+
+  if (*path == '/') path++;
+  name = strtok(path, "/");
+
+  for (name = strtok(path, "/"); name; name = strtok(0, "/")) {
+    if (!(vnum & 1)) {
+      if (phi->p->cb_error)
+        (phi->p->cb_error)(ENOTDIR, 1, phi->p->err_refcon,
+                           "Not a directory vnode");
+      return ENOTDIR;
+    }
+    vhe = get_vhash_ent(phi, vnum, 0);
+    if (!vhe) {
+      if (phi->p->cb_error)
+        (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+                           "Vnode %d not found in hash table", vnum);
+      return DSERR_FMT;
+    }
+    if (zero64(vhe->d_offset)) {
+      if (phi->p->cb_error)
+        (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+                           "Directory vnode %d is incomplete", vnum);
+      return DSERR_FMT;
+    }
+    if (r = xfseek(X, &vhe->d_offset)) {
+      if (phi->p->cb_error)
+        (phi->p->cb_error)(r, 1, phi->p->err_refcon,
+                           "Unable to seek to directory %d", vnum);
+      return r;
+    }
+    vnum = 0;
+    r = DirectoryLookup(X, phi->p, vhe->d_size, &name, &vnum, 0);
+    if (r) return r;
+    if (!vnum) {
+      if (phi->p->cb_error)
+        (phi->p->cb_error)(ENOENT, 1, phi->p->err_refcon,
+                           "No such vnode");
+      return ENOENT;
+    }
+  }
+  vhe = get_vhash_ent(phi, vnum, 0);
+  if (!vhe) {
+    if (phi->p->cb_error)
+      (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+                         "Vnode %d not found in hash table", vnum);
+    return DSERR_FMT;
+  }
+  if (his_vhe) *his_vhe = *vhe;
+  return 0;
+}
+
+
+afs_uint32 Path_Build(XFILE *X, path_hashinfo *phi, afs_uint32 vnode,
+                   char **his_path, int fast)
+{
+  vhash_ent *vhe;
+  char *name, *path = 0, fastbuf[12];
+  char *x, *y;
+  afs_uint32 parent, r;
+  int nl, pl = 0;
+
+  if (vnode == 1) {
+    *his_path = (char *)malloc(2);
+    if (!his_path) {
+      if (phi->p->cb_error)
+        (phi->p->cb_error)(ENOMEM, 1, phi->p->err_refcon,
+                           "No memory for pathname of vnode 1");
+      return ENOMEM;
+    }
+    strcpy(*his_path, "/");
+    return 0;
+  }
+
+  *his_path = 0;
+  vhe = get_vhash_ent(phi, vnode, 0);
+  if (!vhe) {
+    if (phi->p->cb_error)
+      (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+                         "Vnode %d not found in hash table", vnode);
+    return DSERR_FMT;
+  }
+  while (vnode != 1) {
+    /* Find the parent */
+    if (!vhe->parent) {
+      if (phi->p->cb_error)
+        (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+                           "Vnode %d has no parent?", vnode);
+      if (path) free(path);
+      return DSERR_FMT;
+    }
+    parent = vhe->parent;
+    vhe = get_vhash_ent(phi, parent, 0);
+    if (phi->p->print_flags & DSPRINT_DEBUG)
+      fprintf(stderr, "Searching for vnode %d in parent %d\n", vnode, parent);
+    if (!vhe) {
+      if (phi->p->cb_error)
+        (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+                           "Vnode %d not found in hash table", parent);
+      if (path) free(path);
+      return DSERR_FMT;
+    }
+
+    if (fast) {
+      /* Make up a path component from the vnode number */
+      sprintf(fastbuf, "%d", vnode);
+      name = fastbuf;
+    } else {
+      /* Do a reverse-lookup in the parent directory */
+      if (zero64(vhe->d_offset)) {
+        if (phi->p->cb_error)
+          (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+                             "Directory vnode %d is incomplete", parent);
+        if (path) free(path);
+        return DSERR_FMT;
+      }
+      if (r = xfseek(X, &vhe->d_offset)) {
+        if (phi->p->cb_error)
+          (phi->p->cb_error)(errno, 1, phi->p->err_refcon,
+                             "Unable to seek to directory %d", parent);
+        if (path) free(path);
+        return r;
+      }
+
+      name = 0;
+      r = DirectoryLookup(X, phi->p, vhe->d_size, &name, &vnode, 0);
+      if (r) return r;
+      if (!name) {
+        if (phi->p->cb_error)
+          (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+                             "No entry for vnode %d in directory %d",
+                             vnode, parent);
+        if (path) free(path);
+        return ENOENT;
+      }
+    }
+
+    nl = strlen(name);
+    if (path) {
+      path = (char *)realloc(path, nl + pl + 2);
+      if (!path) {
+        if (phi->p->cb_error)
+          (phi->p->cb_error)(ENOMEM, 1, phi->p->err_refcon,
+                             "No memory for pathname of vnode 1");
+        return ENOMEM;
+      }
+      x = path + pl;
+      y = x + nl + 1;
+      while (x >= path) *y-- = *x--;
+      path[0] = '/';
+      for (x = name, y = path + 1; *x;) *y++ = *x++;
+      pl += nl + 1;
+    } else {
+      path = (char *)malloc(nl + 2);
+      if (!path) {
+        if (phi->p->cb_error)
+          (phi->p->cb_error)(ENOMEM, 1, phi->p->err_refcon,
+                             "No memory for pathname of vnode 1");
+        return ENOMEM;
+      }
+      path[0] = '/';
+      strcpy(path + 1, name);
+      pl = nl + 1;
+    }
+    if (!fast) free(name);
+    vnode = parent;
+  }
+  *his_path = path;
+  return 0;
+}
diff --git a/src/tests/pine.c b/src/tests/pine.c
new file mode 100644 (file)
index 0000000..f25e36a
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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 <sys/stat.h>
+
+#include <err.h>
+
+#define LOCK           "mailbox-name.lock"
+
+int
+main(int argc, char *argv[])
+{
+    int ret;
+    struct stat sb;
+    char unique[1024];
+    int retrycount = 0;
+
+
+    snprintf (unique, sizeof(unique), LOCK ".%d.%d",
+             getpid(), (int)time(NULL));
+
+    ret = umask(077);
+    if (ret < 0)
+       err (1, "umask");
+
+    ret = open(unique, O_WRONLY|O_CREAT|O_EXCL, 0666);
+    if (ret < 0)
+       errx (1, "open");
+
+    close (ret);
+    
+ retry:
+    retrycount++;
+    if (retrycount > 10000000)
+       errx (1, "failed getting the lock");
+    ret = link(unique, LOCK);
+    if (ret < 0)
+       goto retry;
+    
+    ret = stat(unique, &sb);
+    if (ret < 0)
+       errx (1, "stat");
+    
+    if (sb.st_nlink != 2)
+       goto retry;
+
+    ret = chmod (LOCK, 0666);
+    if (ret < 0)
+       errx (1, "chmod");
+
+    ret = unlink (LOCK);
+    if (ret < 0)
+       err (1, "unlink " LOCK);
+
+    ret = unlink (unique);
+    if (ret < 0)
+       err (1, "unlink: %s", unique);
+
+    return 0;
+}
diff --git a/src/tests/primitive.c b/src/tests/primitive.c
new file mode 100644 (file)
index 0000000..95dcac2
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* primitive.c - Routines for reading and writing low-level things */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumpscan.h"
+
+#define BUFSIZE 256
+
+
+afs_uint32 ReadByte(XFILE *X, unsigned char *val)
+{
+  return xfread(X, val, 1);
+}
+
+afs_uint32 ReadInt16(XFILE *X, afs_uint16 *val)
+{
+  afs_uint32 r;
+
+  if (r = xfread(X, val, 2)) return r;
+  *val = ntohs(*val);
+  return 0;
+}
+
+afs_uint32 ReadInt32(XFILE *X, afs_uint32 *val)
+{
+  afs_uint32 r;
+
+  if (r = xfread(X, val, 4)) return r;
+  *val = ntohl(*val);
+  return 0;
+}
+
+/* Read in a NUL-terminated string.  This method is kind of messy, but
+ * has the advantage that it reads the data stream only once, doesn't
+ * read anything extra, and never has to seek on the data stream.
+ */
+afs_uint32 ReadString(XFILE *X, unsigned char **val)
+{
+  static unsigned char buf[BUFSIZE];
+  unsigned char *result = 0;
+  afs_uint32 r;
+  int i, l = 0;
+
+  *val = 0;
+  for (;;) {
+    for (i = 0; i < BUFSIZE; i++) {
+      r = ReadByte(X, buf + i);
+      if (r) {
+        if (result) free(result);
+        return r;
+      }
+      if (!buf[i]) break;
+    }
+    /* iff we found a null, i < BUFSIZE and buf[i] holds the NUL */
+    if (result) result = (unsigned char *)realloc(result, l + i + 1);
+    else result = (unsigned char *)malloc(i + 1);
+    if (!result) return ENOMEM;
+    memcpy(result + l, buf, i);
+    result[l+i] = 0;
+    l += i;
+    if (i < BUFSIZE) break;
+  }
+  *val = result;
+  return 0;
+}
+
+
+afs_uint32 WriteByte(XFILE *X, unsigned char val)
+{
+  return xfwrite(X, &val, 1);
+}
+
+afs_uint32 WriteInt16(XFILE *X, afs_uint16 val)
+{
+  val = htons(val);
+  return xfwrite(X, &val, 2);
+}
+
+afs_uint32 WriteInt32(XFILE *X, afs_uint32 val)
+{
+  val = htonl(val);
+  return xfwrite(X, &val, 4);
+}
+
+afs_uint32 WriteString(XFILE *X, unsigned char *str)
+{
+  int len = strlen((char *)str) + 1;
+  return xfwrite(X, str, len);
+}
+
+afs_uint32 WriteTagByte(XFILE *X, unsigned char tag, unsigned char val)
+{
+  char buffer[2];
+  buffer[0] = tag;
+  buffer[1] = val;
+  return xfwrite(X, buffer, 2);
+}
+
+afs_uint32 WriteTagInt16(XFILE *X, unsigned char tag, afs_uint16 val)
+{
+  char buffer[3];
+  buffer[0] = tag;
+  buffer[1] = (val & 0xff00) >> 8;
+  buffer[2] = val & 0xff;
+  return xfwrite(X, buffer, 3);
+}
+
+afs_uint32 WriteTagInt32(XFILE *X, unsigned char tag, afs_uint32 val)
+{
+  char buffer[5];
+  buffer[0] = tag;
+  buffer[1] = (val & 0xff000000) >> 24;
+  buffer[2] = (val & 0xff0000) >> 16;
+  buffer[3] = (val & 0xff00) >> 8;
+  buffer[4] = val & 0xff;
+  return xfwrite(X, buffer, 5);
+}
+
+afs_uint32 WriteTagInt32Pair(XFILE *X, unsigned char tag,
+                             afs_uint32 val1, afs_uint32 val2)
+{
+  char buffer[9];
+  buffer[0] = tag;
+  buffer[1] = (val1 & 0xff000000) >> 24;
+  buffer[2] = (val1 & 0xff0000) >> 16;
+  buffer[3] = (val1 & 0xff00) >> 8;
+  buffer[4] = val1 & 0xff;
+  buffer[5] = (val2 & 0xff000000) >> 24;
+  buffer[6] = (val2 & 0xff0000) >> 16;
+  buffer[7] = (val2 & 0xff00) >> 8;
+  buffer[8] = val2 & 0xff;
+  return xfwrite(X, buffer, 9);
+}
diff --git a/src/tests/ptsadduser.pl b/src/tests/ptsadduser.pl
new file mode 100755 (executable)
index 0000000..5218bff
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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;
+
+&AFS_Init();
+
+&AFS_pts_add([testuser1],[testgroup1],);
+
+exit(0);
+
+
+
diff --git a/src/tests/ptschown.pl b/src/tests/ptschown.pl
new file mode 100755 (executable)
index 0000000..812eac7
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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;
+
+&AFS_Init();
+
+&AFS_pts_chown(testgroup1,testuser1,);
+
+exit(0);
+
+
+
diff --git a/src/tests/ptscreategroup.pl b/src/tests/ptscreategroup.pl
new file mode 100755 (executable)
index 0000000..8a904c0
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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;
+
+&AFS_Init();
+
+&AFS_pts_creategroup(testgroup1,,);
+
+exit(0);
+
+
+
diff --git a/src/tests/ptscreateuser.pl b/src/tests/ptscreateuser.pl
new file mode 100755 (executable)
index 0000000..2286fc8
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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;
+
+&AFS_Init();
+
+&AFS_pts_createuser(testuser1,,);
+
+exit(0);
+
+
+
diff --git a/src/tests/ptsdeletegroup.pl b/src/tests/ptsdeletegroup.pl
new file mode 100755 (executable)
index 0000000..11dbbc0
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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;
+
+&AFS_Init();
+
+&AFS_pts_delete([testgroup1],);
+
+exit(0);
+
+
+
diff --git a/src/tests/ptsdeleteuser.pl b/src/tests/ptsdeleteuser.pl
new file mode 100755 (executable)
index 0000000..f4f2d07
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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;
+
+&AFS_Init();
+
+&AFS_pts_delete([testuser1],);
+
+exit(0);
+
+
+
diff --git a/src/tests/ptsexaminegroup.pl b/src/tests/ptsexaminegroup.pl
new file mode 100755 (executable)
index 0000000..4297a53
--- /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 (%info);
+&AFS_Init();
+
+%info = &AFS_pts_examine(testgroup1,);
+if ($info{'creator'} ne "admin") {
+    exit(1);
+}
+if ($info{'mem_count'} != 1) {
+    exit(1);
+}
+if ($info{'owner'} ne "testuser1") {
+    exit(1);
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/ptsexamineuser.pl b/src/tests/ptsexamineuser.pl
new file mode 100755 (executable)
index 0000000..c869fed
--- /dev/null
@@ -0,0 +1,24 @@
+#!/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 (%info);
+&AFS_Init();
+
+%info = &AFS_pts_examine(testuser1,);
+if ($info{'creator'} ne "admin") {
+    exit(1);
+}
+if ($info{'mem_count'} != 1) {
+    exit(1);
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/ptslistmax.pl b/src/tests/ptslistmax.pl
new file mode 100755 (executable)
index 0000000..dc42ed7
--- /dev/null
@@ -0,0 +1,24 @@
+#!/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 (@info);
+&AFS_Init();
+
+@info = &AFS_pts_listmax();
+if ($info[0] != 100) {
+    exit(1);
+}
+if ($info[1] != -300) {
+    exit(1);
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/ptslistown.pl b/src/tests/ptslistown.pl
new file mode 100755 (executable)
index 0000000..0133f9c
--- /dev/null
@@ -0,0 +1,23 @@
+#!/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 (@owned, $group);
+&AFS_Init();
+
+@owned = &AFS_pts_listown(testuser1,);
+while ($group = pop(@owned)) {
+    if ($group ne "testgroup1") {
+       exit(1);
+    }
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/ptsmembersgroup.pl b/src/tests/ptsmembersgroup.pl
new file mode 100755 (executable)
index 0000000..ecff23c
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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 (@membership, $group);
+&AFS_Init();
+
+@membership = &AFS_pts_members(testgroup1,);
+while ($group = pop(@membership)) {
+    if ($group ne "testuser1") {
+       exit(1);
+    }
+}
+&AFS_pts_add([admin],[testgroup1],);
+@membership = &AFS_pts_members(testgroup1,);
+while ($group = pop(@membership)) {
+    if ($group eq "testuser1") {
+    } else {
+       if ($group eq "admin") {
+       } else {
+           exit(1);
+       }
+    }
+}
+&AFS_pts_remove([admin],["testgroup1"],);
+
+exit(0);
+
+
+
diff --git a/src/tests/ptsmembersuser.pl b/src/tests/ptsmembersuser.pl
new file mode 100755 (executable)
index 0000000..4172b4e
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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 (@membership, $group);
+&AFS_Init();
+
+@membership = &AFS_pts_members(testuser1,);
+while ($group = pop(@membership)) {
+    if ($group ne "testgroup1") {
+       exit(1);
+    }
+}
+&AFS_pts_add([testuser1],["system:administrators"],);
+@membership = &AFS_pts_members(testuser1,);
+while ($group = pop(@membership)) {
+    if ($group eq "testgroup1") {
+    } else {
+       if ($group eq "system:administrators") {
+       } else {
+           exit(1);
+       }
+    }
+}
+&AFS_pts_remove([testuser1],["system:administrators"],);
+
+exit(0);
+
+
+
diff --git a/src/tests/ptsremove.pl b/src/tests/ptsremove.pl
new file mode 100755 (executable)
index 0000000..67c165a
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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;
+
+&AFS_Init();
+
+&AFS_pts_remove([testuser1],[testgroup1],);
+
+exit(0);
+
+
+
diff --git a/src/tests/ptssetf.pl b/src/tests/ptssetf.pl
new file mode 100755 (executable)
index 0000000..08c4011
--- /dev/null
@@ -0,0 +1,28 @@
+#!/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 (%info);
+&AFS_Init();
+
+&AFS_pts_setf(testuser1,"S-M--",30,);
+%info = &AFS_pts_examine(testuser1,);
+if ($info{'creator'} ne "admin") {
+    exit(1);
+}
+if ($info{'flags'} ne "S-M--") {
+    exit(1);
+}
+if ($info{'group_quota'} != 30) {
+    exit(1);
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/ptssetmax.pl b/src/tests/ptssetmax.pl
new file mode 100755 (executable)
index 0000000..ab4c456
--- /dev/null
@@ -0,0 +1,17 @@
+#!/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;
+
+&AFS_Init();
+
+&AFS_pts_setmax(100,-300,);
+
+exit(0);
+
+
+
diff --git a/src/tests/read-vs-mmap.c b/src/tests/read-vs-mmap.c
new file mode 100644 (file)
index 0000000..dba46d8
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * 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 <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: read-vs-mmap.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+static int debug = 0;
+
+static void
+generate_file (const char *filename, int randomp, size_t sz)
+{
+    int fd;
+    char *buf;
+    int i;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+
+    fd = open (filename, O_WRONLY | O_CREAT, 0666);
+    if (fd < 0)
+       err (1, "open %s", filename);
+
+    for (i = 0; i < sz; ++i)
+       if (randomp)
+           buf[i] = rand();
+       else
+           buf[0] = 0;
+
+    if (write (fd, buf, sz) != sz)
+       err (1, "write");
+    if (close (fd))
+       err (1, "close");
+    free (buf);
+}
+
+static unsigned char *
+read_file (int fd, size_t sz)
+{
+    unsigned char *buf;
+    ssize_t ret;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+    ret = read(fd, buf, sz);
+    if(ret < 0)
+      err(1, "read");
+    if(ret != sz)
+      errx(1, "short read %d < %u", (int)ret, (unsigned)sz);
+    return buf;
+}
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+static void *
+mmap_file (int fd, size_t sz)
+{
+    void *ret;
+
+    ret = mmap (0, sz, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (ret == (void *)MAP_FAILED)
+       err (1, "mmap");
+    return ret;
+}
+
+static void __attribute__ ((__unused__))
+print_area (unsigned char *ptr,  size_t len)
+{
+    while (len--) {
+       printf ("%x", *ptr);
+       ptr++;
+    }
+}
+
+static int
+do_test (int randomp)
+{
+    unsigned char *malloc_buf;
+    void *mmap_buf;
+    int fd;
+    const char *file = "foo";
+    const size_t sz  = 16384;
+
+    generate_file (file, randomp, sz);
+
+    fd = open (file, O_RDONLY, 0);
+    if (fd < 0)
+       err (1, "open %s", file);
+
+    malloc_buf = read_file (fd, sz);
+    mmap_buf   = mmap_file (fd, sz);
+    close (fd);
+    unlink (file);
+    if (memcmp (malloc_buf, mmap_buf, sz) != 0) {
+       if (debug) {
+           printf ("type: %s\n", randomp ? "random" : "allzero");
+           printf ("read: ");
+           print_area (malloc_buf, sz);
+           printf ("\nmmap: ");
+           print_area (mmap_buf, sz);
+           printf ("\n");
+       }
+       return 1;
+    }
+    return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+    if (argc != 1)
+       debug = 1;
+
+    srand (time(NULL));
+
+    if (do_test (0))
+       return 1;
+    if (do_test (1))
+       return 2;
+
+    return 0;
+}
diff --git a/src/tests/read-vs-mmap2.c b/src/tests/read-vs-mmap2.c
new file mode 100644 (file)
index 0000000..1a37754
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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 <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: read-vs-mmap2.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+static void
+generate_random_file (const char *filename, size_t sz)
+{
+    int fd;
+    char *buf;
+    int i;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+
+    fd = open (filename, O_WRONLY | O_CREAT, 0666);
+    if (fd < 0)
+       err (1, "open %s", filename);
+
+    for (i = 0; i < sz; ++i)
+       buf[i] = rand();
+
+    if (write (fd, buf, sz) != sz)
+       err (1, "write");
+    if (close (fd))
+       err (1, "close");
+    free (buf);
+}
+
+static char *
+read_file (int fd, size_t sz)
+{
+    char *buf;
+    ssize_t ret;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+    ret = read(fd, buf, sz);
+    if(ret < 0)
+        err(1, "read");
+    if(ret != sz)
+        errx(1, "short read %d < %u", (int)ret, (unsigned)sz);
+    return buf;
+}
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+static void *
+mmap_file (int fd, size_t sz)
+{
+    void *ret;
+
+    ret = mmap (0, sz, PROT_READ, MAP_SHARED, fd, 0);
+    if (ret == (void *)MAP_FAILED)
+       err (1, "mmap");
+    return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+    const char *file = "foo";
+    const size_t sz  = 16384;
+    char *malloc_buf;
+    void *mmap_buf;
+    int fd;
+
+    srand (time(NULL));
+
+    generate_random_file (file, sz);
+
+    fd = open (file, O_RDONLY, 0);
+    if (fd < 0)
+       err (1, "open %s", file);
+
+    malloc_buf = read_file (fd, sz);
+    mmap_buf   = mmap_file (fd, sz);
+    close (fd);
+    unlink (file);
+    if (memcmp (malloc_buf, mmap_buf, sz) != 0)
+       return 1;
+    return 0;
+}
diff --git a/src/tests/read-write.c b/src/tests/read-write.c
new file mode 100644 (file)
index 0000000..6f73f72
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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 <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: read-write.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+static char *
+write_random_file (int fd, size_t sz)
+{
+    char *buf;
+    int i;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+
+    for (i = 0; i < sz; ++i)
+       buf[i] = rand();
+
+    if (write (fd, buf, sz) != sz)
+       err (1, "write");
+
+    return buf;
+}
+
+static void
+write_null_file (int fd, size_t sz)
+{
+    char *buf;
+    int i;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+
+    for (i = 0; i < sz; ++i)
+       buf[i] = 0;
+
+    if (write (fd, buf, sz) != sz)
+       err (1, "write");
+
+    free (buf);
+}
+
+static char *
+read_file (int fd, size_t sz)
+{
+    char *buf;
+    ssize_t ret;
+
+    buf = malloc (sz);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+    ret = read(fd, buf, sz);
+    if(ret < 0)
+       err (1, "read");
+    else if(ret == 0)
+        errx(1, "EOF on read");
+    return buf;
+}
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+    const char *file = "foo";
+    const size_t sz  = 16384;
+    char *random_buf;
+    char *read_buf1;
+    char *read_buf2;
+    int fd;
+
+
+    srand (time(NULL));
+
+    fd = open (file, O_RDWR | O_CREAT, 0);
+    if (fd < 0)
+       err (1, "open %s", file);
+
+    if (lseek(fd, 0, SEEK_SET) < 0)
+       err (1, "lseek");
+    write_null_file(fd, sz);
+    if (lseek(fd, 0, SEEK_SET) < 0)
+       err (1, "lseek");
+    read_buf1 = read_file (fd, sz);
+    if (lseek(fd, 0, SEEK_SET) < 0)
+       err (1, "lseek");
+    random_buf = write_random_file(fd, sz);
+    if (lseek(fd, 0, SEEK_SET) < 0)
+       err (1, "lseek");
+    read_buf2 = read_file (fd, sz);
+
+    close (fd);
+    unlink (file);
+    if (memcmp (random_buf, read_buf2, sz) != 0)
+       return 1;
+    return 0;
+}
diff --git a/src/tests/readdir-vs-lstat.c b/src/tests/readdir-vs-lstat.c
new file mode 100644 (file)
index 0000000..8d7d548
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: readdir-vs-lstat.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+static int
+verify_inodes (const char *dirname)
+{
+    DIR *d;
+    struct dirent *dp;
+    
+    if (chdir (dirname) < 0)
+       err (1, "chdir %s", dirname);
+
+    d = opendir (".");
+    if (d == NULL)
+       err (1, "opendir %s", dirname);
+    while ((dp = readdir (d)) != NULL) {
+       struct stat sb;
+
+       if (lstat (dp->d_name, &sb) < 0) {
+           if (errno == EACCES)
+               continue;
+           err (1, "lstat %s", dp->d_name);
+       }
+       if (dp->d_ino != sb.st_ino)
+           errx (1, "%s: inode %u != %u", dp->d_name,
+                 (unsigned)dp->d_ino, (unsigned)sb.st_ino);
+    }
+    closedir (d);
+    return 0;
+}
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s [directory]\n", __progname);
+    exit (ret);
+}
+
+int
+main(int argc, char **argv)
+{
+    char *name = ".";
+
+
+    if (argc > 2)
+       usage (1);
+
+    if (argc > 1)
+       name = argv[1];
+
+    return verify_inodes (name);
+}
diff --git a/src/tests/readfile-wo-create b/src/tests/readfile-wo-create
new file mode 100755 (executable)
index 0000000..209fd34
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+FOO=`cat $AFSROOT/stacken.kth.se/ftp/pub/arla/tests/used-by-arla-check`
+test "X"$FOO = "Xfoo" || exit 1
diff --git a/src/tests/reauth.pl b/src/tests/reauth.pl
new file mode 100755 (executable)
index 0000000..8ff8039
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env perl
+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);
+
+&OpenAFS::Auth::authadmin();
diff --git a/src/tests/rename-under-feet.c b/src/tests/rename-under-feet.c
new file mode 100644 (file)
index 0000000..79e359a
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+
+#define RETSIGTYPE void
+
+static void
+emkdir (const char *path, mode_t mode)
+{
+    int ret = mkdir (path, mode);
+    if (ret < 0)
+       err (1, "mkdir %s", path);
+}
+
+static pid_t child_pid;
+
+static sig_atomic_t term_sig = 0;
+
+static RETSIGTYPE
+child_sigterm (int signo)
+{
+    term_sig = 1;
+}
+
+static int
+child_chdir (const char *path)
+{
+    int ret;
+    int pfd[2];
+
+    ret = pipe (pfd);
+    if (ret < 0)
+       err (1, "pipe");
+
+    child_pid = fork ();
+    if (child_pid < 0)
+       err (1, "fork");
+    if (child_pid != 0) {
+       close (pfd[1]);
+       return pfd[0];
+    } else {
+       char buf[256];
+       struct sigaction sa;
+       FILE *fp;
+
+       sa.sa_handler = child_sigterm;
+       sigfillset(&sa.sa_mask);
+       sa.sa_flags = 0;
+       sigaction (SIGTERM, &sa, NULL);
+
+       close (pfd[0]);
+       ret = chdir (path);
+       if (ret < 0)
+           err (1, "chdir %s", path);
+       ret = write (pfd[1], "", 1);
+       if (ret != 1)
+           err (1, "write");
+       while (!term_sig)
+           pause ();
+#if 0
+       if(getcwd (buf, sizeof(buf)) == NULL)
+           err (1, "getcwd");
+#endif
+       fp = fdopen (4, "w");
+       if (fp != NULL)
+           fprintf (fp, "child: cwd = %s\n", buf);
+       exit (0);
+    }
+}
+
+static void
+kill_child (void)
+{
+    kill (child_pid, SIGTERM);
+}
+
+int
+main (int argc, char **argv)
+{
+    struct stat sb;
+    int ret;
+    int fd;
+    char buf[1];
+    int status;
+
+
+    emkdir ("one", 0777);
+    emkdir ("two", 0777);
+    emkdir ("one/a", 0777);
+
+    fd = child_chdir ("one/a");
+    atexit (kill_child);
+    ret = read (fd, buf, 1);
+    if (ret < 0)
+        err(1, "read");
+    if (ret == 0)
+        errx(1, "EOF on read");
+
+    ret = rename ("one/a", "two/a");
+    if (ret < 0)
+       err (1, "rename one/a two");
+    ret = lstat ("two/a", &sb);
+    if (ret < 0)
+       err (1, "lstat two/a");
+    ret = lstat ("one/a", &sb);
+    if (ret != -1 || errno != ENOENT)
+       errx (1, "one/a still exists");
+    kill_child ();
+    waitpid (child_pid, &status, 0);
+    ret = lstat ("one/a", &sb);
+    if (ret != -1 || errno != ENOENT)
+       errx (1, "one/a still exists after child");
+    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+       rmdir ("one/a");
+       rmdir ("two/a");
+       rmdir ("one");
+       rmdir ("two");
+       return 0;
+    } else
+       return 1;
+}
diff --git a/src/tests/rename1 b/src/tests/rename1
new file mode 100755 (executable)
index 0000000..af0061b
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# $Id: rename1,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+touch foo || exit 1
+mv foo bar || exit 1
+test -f foo && exit 1
+test -f bar || exit 1
+rm bar || exit 1
diff --git a/src/tests/rename2 b/src/tests/rename2
new file mode 100644 (file)
index 0000000..6961ccc
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# $Id: rename2,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+touch foo bar || exit 1
+mv foo bar || exit 1
+test -f foo && exit 1
+test -f bar || exit 1
+rm bar || exit 1
diff --git a/src/tests/rename3 b/src/tests/rename3
new file mode 100755 (executable)
index 0000000..e74515e
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: rename3,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+echo foo > foo || exit 1
+sed 's/foo/bar/' foo > bar || exit 1
+rm foo || exit 1
+test -f foo && exit 1
+mv bar foo || exit 1
+test -f bar && exit 1
+test -f foo || exit 1
diff --git a/src/tests/rename4 b/src/tests/rename4
new file mode 100755 (executable)
index 0000000..b8246ee
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: rename4,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+mkdir old_parent new_parent old_parent/victim || exit 1
+mv old_parent/victim new_parent || exit 1
+test -d old_parent || exit 1
+test -d new_parent || exit 1
+test -d old_parent/victim && exit 1
+test -d new_parent/victim || exit 1
+rmdir new_parent/victim new_parent old_parent
diff --git a/src/tests/rename5.c b/src/tests/rename5.c
new file mode 100644 (file)
index 0000000..92441cf
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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 <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>
+
+static void
+emkdir (const char *path, mode_t mode)
+{
+    int ret;
+
+    ret = mkdir (path, mode);
+    if (ret < 0)
+       err (1, "mkdir %s", path);
+}
+
+static void
+elstat (const char *path, struct stat *sb)
+{
+    int ret;
+
+    ret = lstat (path, sb);
+    if (ret < 0)
+       err (1, "lstat %s", path);
+}
+
+static void
+check_inum (const struct stat *sb1, const struct stat *sb2)
+{
+    if (sb1->st_ino != sb2->st_ino)
+       errx (1, "wrong inode-number %u != %u",
+             (unsigned)sb1->st_ino, (unsigned)sb2->st_ino);
+}
+
+int
+main(int argc, char **argv)
+{
+    int ret;
+    struct stat old_sb, new_sb, dot_sb;
+
+    emkdir ("old_parent", 0777);
+    emkdir ("new_parent", 0777);
+    emkdir ("old_parent/victim", 0777);
+
+    elstat ("old_parent", &old_sb);
+    elstat ("new_parent", &new_sb);
+    elstat ("old_parent/victim/..", &dot_sb);
+    check_inum (&old_sb, &dot_sb);
+
+    ret = rename("old_parent/victim", "new_parent/victim");
+    if (ret < 0)
+       err (1, "rename old_parent/victim new_parent/victim");
+
+    elstat ("new_parent/victim/..", &dot_sb);
+
+    check_inum (&new_sb, &dot_sb);
+
+    return 0;
+}
diff --git a/src/tests/rename6.c b/src/tests/rename6.c
new file mode 100644 (file)
index 0000000..3b62387
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 <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>
+
+int
+main(int argc, char **argv)
+{
+    int ret;
+    int fd;
+    struct stat old_sb, new_sb, dot_sb;
+
+    fd = open("foo", O_RDWR|O_CREAT|O_TRUNC, 0644);
+    if (fd < 0)
+       err (1, "open1");
+    ret = close (fd);
+    if (ret < 0)
+       err (1, "close1");
+
+    ret = rename("foo", "../../service/foo");
+    if (ret == 0)
+       err (1, "rename didn't fail");
+
+    unlink("foo");
+    return 0;
+}
diff --git a/src/tests/repair.c b/src/tests/repair.c
new file mode 100644 (file)
index 0000000..ece84b1
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* repair.c - Routines to generate a repaired dump */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+
+#include <afs/acl.h>
+#include <afs/dir.h>
+#include <afs/prs_fs.h>
+
+XFILE repair_output;
+int repair_verbose;
+#define RV repair_verbose
+
+
+/* Try to dump a dump header.  Generate missing fields, if neccessary */
+afs_uint32 repair_dumphdr_cb(afs_dump_header *hdr, XFILE *X, void *refcon)
+{
+  afs_uint32 r, field_mask = hdr->field_mask;
+  char volname[22];
+
+  if (!(field_mask & F_DUMPHDR_VOLID)) {
+    if (RV) fprintf(stderr, ">>> DUMP HEADER missing volume ID\n");
+    return DSERR_FMT;
+  }
+  if (!(field_mask & F_DUMPHDR_VOLNAME)) {
+    if (RV) {
+      fprintf(stderr, ">>> DUMP HEADER missing volume name\n");
+      fprintf(stderr, ">>> Will use RESTORED.%d\n", hdr->volid);
+    }
+    sprintf(volname, "RESTORED.%d", hdr->volid);
+    hdr->volname = (unsigned char *)malloc(strlen(volname) + 1);
+    if (!hdr->volname) return ENOMEM;
+    strcpy(hdr->volname, volname);
+    hdr->field_mask |= F_DUMPHDR_VOLNAME;
+  }
+  if (!(field_mask & F_DUMPHDR_FROM)) {
+    if (RV) fprintf(stderr, ">>> DUMP HEADER missing from time (using 0)\n");
+    hdr->from_date = 0;
+    hdr->field_mask |= F_DUMPHDR_FROM;
+  }
+  if (!(field_mask & F_DUMPHDR_TO)) {
+    hdr->to_date = time(0);
+    if (RV) fprintf(stderr, ">>> DUMP HEADER missing from time (using %d)\n",
+      hdr->to_date);
+    hdr->field_mask |= F_DUMPHDR_TO;
+  }
+
+  return DumpDumpHeader(&repair_output, hdr);
+}
+
+
+/* Try to dump a volume header.  Generate missing fields, if necessary */
+afs_uint32 repair_volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
+{
+  afs_uint32 r, field_mask = hdr->field_mask;
+  char volname[22];
+
+  if (!(field_mask & F_VOLHDR_VOLID)) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing volume ID\n");
+    return DSERR_FMT;
+  }
+  if (!(field_mask & F_VOLHDR_VOLVERS)) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing version (using 1)\n");
+    hdr->volvers = 1;
+    hdr->field_mask |= F_VOLHDR_VOLVERS;
+  } else if (hdr->volvers != 1) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER bogus version %d (using 1)\n",
+            hdr->volvers);
+    hdr->volvers = 1;
+  }
+  if (!(field_mask & F_VOLHDR_VOLNAME)) {
+    if (RV) {
+      fprintf(stderr, ">>> VOL HEADER missing volume name\n");
+      fprintf(stderr, ">>> Will use RESTORED.%d\n", hdr->volid);
+    }
+    sprintf(volname, "RESTORED.%d", hdr->volid);
+    hdr->volname = (unsigned char *)malloc(strlen(volname) + 1);
+    if (!hdr->volname) return ENOMEM;
+    strcpy(hdr->volname, volname);
+    hdr->field_mask |= F_VOLHDR_VOLNAME;
+  }
+  if (!(field_mask & F_VOLHDR_INSERV)) {
+    if (RV)
+      fprintf(stderr, ">>> VOL HEADER missing in-service flag (using 1)\n");
+    hdr->flag_inservice = 1;
+    hdr->field_mask |= F_VOLHDR_INSERV;
+  }
+  if (!(field_mask & F_VOLHDR_BLESSED)) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing blessed flag (using 1)\n");
+    hdr->flag_blessed = 1;
+    hdr->field_mask |= F_VOLHDR_BLESSED;
+  }
+  if (!(field_mask & F_VOLHDR_VOLUNIQ)) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing uniquifier (using 1)\n");
+    hdr->voluniq = 1;
+    hdr->field_mask |= F_VOLHDR_VOLUNIQ;
+  }
+  if (!(field_mask & F_VOLHDR_VOLTYPE)) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing type (using 0: RW)\n");
+    hdr->voltype = 0;
+    hdr->field_mask |= F_VOLHDR_VOLTYPE;
+  } else if (hdr->voltype < 0 || hdr->voltype > 2) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER bogus type %d (using 0: RW)\n",
+            hdr->voltype);
+    hdr->voltype = 0;
+  }
+  if (!(field_mask & F_VOLHDR_PARENT)) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER parent (using %d)\n", hdr->volid);
+    hdr->parent_volid = hdr->volid;
+    hdr->field_mask |= F_VOLHDR_PARENT;
+  }
+  if (!(field_mask & F_VOLHDR_MAXQ)) {
+    if (field_mask & F_VOLHDR_DISKUSED) hdr->maxquota = hdr->diskused;
+    else hdr->maxquota = 1;
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing max quota (using %d)\n",
+            hdr->maxquota);
+    hdr->field_mask |= F_VOLHDR_MAXQ;
+  }
+  if (!(field_mask & F_VOLHDR_DISKUSED)) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing disk used (using 2048)\n");
+    hdr->diskused = 2048;
+    hdr->field_mask |= F_VOLHDR_DISKUSED;
+  }
+  if (!(field_mask & F_VOLHDR_NFILES)) {
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing file count (using 1)\n");
+    hdr->nfiles = 1;
+    hdr->field_mask |= F_VOLHDR_NFILES;
+  }
+  if (!(field_mask & F_VOLHDR_CREATE_DATE)) {
+    hdr->create_date = 0;
+    if ((field_mask & F_VOLHDR_ACCESS_DATE)
+    &&  (!hdr->create_date || hdr->access_date < hdr->create_date))
+      hdr->create_date = hdr->access_date;
+    if ((field_mask & F_VOLHDR_UPDATE_DATE)
+    &&  (!hdr->create_date || hdr->update_date < hdr->create_date))
+      hdr->create_date = hdr->update_date;
+    if ((field_mask & F_VOLHDR_BACKUP_DATE)
+    &&  (!hdr->create_date || hdr->backup_date < hdr->create_date))
+      hdr->create_date = hdr->backup_date;
+
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing create date (using %d)\n",
+            hdr->create_date);
+    hdr->field_mask |= F_VOLHDR_CREATE_DATE;
+  }
+  if (!(field_mask & F_VOLHDR_ACCESS_DATE)) {
+    hdr->access_date = 0;
+    if ((field_mask & F_VOLHDR_CREATE_DATE)
+    &&  (!hdr->access_date || hdr->create_date > hdr->access_date))
+      hdr->access_date = hdr->create_date;
+    if ((field_mask & F_VOLHDR_UPDATE_DATE)
+    &&  (!hdr->access_date || hdr->update_date > hdr->access_date))
+      hdr->access_date = hdr->update_date;
+    if ((field_mask & F_VOLHDR_BACKUP_DATE)
+    &&  (!hdr->access_date || hdr->backup_date > hdr->access_date))
+      hdr->access_date = hdr->backup_date;
+
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing access date (using %d)\n",
+            hdr->access_date);
+    hdr->field_mask |= F_VOLHDR_ACCESS_DATE;
+  }
+  if (!(field_mask & F_VOLHDR_UPDATE_DATE)) {
+    hdr->update_date = 0;
+    if ((field_mask & F_VOLHDR_CREATE_DATE)
+    &&  (!hdr->update_date || hdr->create_date > hdr->update_date))
+      hdr->update_date = hdr->create_date;
+    if ((field_mask & F_VOLHDR_ACCESS_DATE) && !hdr->update_date)
+      hdr->update_date = hdr->access_date;
+    if ((field_mask & F_VOLHDR_BACKUP_DATE) && !hdr->update_date)
+      hdr->update_date = hdr->backup_date;
+
+    if (RV) fprintf(stderr, ">>> VOL HEADER missing update date (using %d)\n",
+            hdr->update_date);
+    hdr->field_mask |= F_VOLHDR_UPDATE_DATE;
+  }
+
+  return DumpVolumeHeader(&repair_output, hdr);
+}
+
+
+/* Try to dump a vnode.  Generate missing fields, if necessary */
+afs_uint32 repair_vnode_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+  afs_uint32 r, field_mask = v->field_mask;
+
+  if ((v->vnode & 1) && !field_mask) {
+    if (RV) fprintf(stderr, ">>> VNODE %d is directory but has no fields?\n");
+    v->type = vDirectory;
+    v->field_mask |= F_VNODE_TYPE;
+    field_mask = F_VNODE_TYPE; /* Messy! */
+  }
+  if (field_mask && !(field_mask & F_VNODE_TYPE)) {
+    v->type = (v->vnode & 1) ? vDirectory : vFile;
+    if (RV) fprintf(stderr, ">>> VNODE %d missing type (using %d)\n",
+            v->vnode, v->type);
+    v->field_mask |= F_VNODE_TYPE;
+  }
+  if (field_mask && !(field_mask & F_VNODE_NLINKS)) {
+    if (RV)
+      fprintf(stderr, ">>> VNODE %d missing link count (using 1)\n", v->vnode);
+    v->nlinks = 1;
+    v->field_mask |= F_VNODE_NLINKS;
+  }
+  if (field_mask && !(field_mask & F_VNODE_PARENT)) {
+    if (RV)
+      fprintf(stderr, ">>> VNODE %d missing parent (using 1)\n", v->vnode);
+    v->parent = 1;
+    v->field_mask |= F_VNODE_PARENT;
+  }
+  if (field_mask && !(field_mask & F_VNODE_DVERS)) {
+    if (RV) fprintf(stderr, ">>> VNODE %d missing data version (using 1)\n",
+              v->vnode);
+    v->datavers = 1;
+    v->field_mask |= F_VNODE_DVERS;
+  }
+  if (field_mask && !(field_mask & F_VNODE_AUTHOR)) {
+    if (field_mask & F_VNODE_OWNER) v->author = v->owner;
+    else v->author = 0;
+    if (RV) fprintf(stderr, ">>> VNODE %d missing author (using %d)\n",
+            v->vnode, v->author);
+    v->field_mask |= F_VNODE_AUTHOR;
+  }
+  if (field_mask && !(field_mask & F_VNODE_OWNER)) {
+    if (field_mask & F_VNODE_AUTHOR) v->owner = v->author;
+    else v->owner = 0;
+    if (RV) fprintf(stderr, ">>> VNODE %d missing owner (using %d)\n",
+            v->vnode, v->owner);
+    v->field_mask |= F_VNODE_OWNER;
+  }
+  if (field_mask && !(field_mask & F_VNODE_MODE)) {
+    v->mode = (v->vnode & 1) ? 0755 : 0644;
+    if (RV) fprintf(stderr, ">>> VNODE missing mode (using %d)\n", v->mode);
+    v->field_mask |= F_VNODE_MODE;
+  }
+  if (field_mask && !(field_mask & F_VNODE_CDATE)) {
+    if (field_mask & F_VNODE_SDATE) v->client_date = v->server_date;
+    else v->client_date = 0;
+
+    if (RV) fprintf(stderr, ">>> VNODE %d missing client date (using %d)\n",
+            v->vnode, v->client_date);
+    v->field_mask |= F_VNODE_CDATE;
+  }
+  if (field_mask && !(field_mask & F_VNODE_SDATE)) {
+    if (field_mask & F_VNODE_CDATE) v->server_date = v->client_date;
+    else v->server_date = 0;
+
+    if (RV) fprintf(stderr, ">>> VNODE %d missing server date (using %d)\n",
+            v->vnode, v->server_date);
+    v->field_mask |= F_VNODE_SDATE;
+  }
+  if (field_mask && !(field_mask & F_VNODE_SIZE)) {
+    if (RV) fprintf(stderr, ">>> VNODE %d has no data size (using 0)\n");
+    v->size = 0;
+    v->field_mask |= F_VNODE_SIZE;
+  }
+  if ((field_mask & F_VNODE_DATA) && !v->size) {
+    if (RV)
+      fprintf(stderr, ">>> VNODE %d has data, but size == 0 (ignoring)\n",
+            v->vnode);
+    v->field_mask &=~ F_VNODE_DATA;
+  }
+  if (field_mask && v->type == vDirectory && !(field_mask & F_VNODE_ACL)) {
+    struct acl_accessList *acl = (struct acl_accessList *)v->acl;
+    if (RV) {
+      fprintf(stderr, ">>> VNODE %d is directory but has no ACL\n");
+      fprintf(stderr, ">>> Will generate default ACL\n");
+    }
+    memset(v->acl, 0, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE);
+    acl->size = htonl(SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE);
+    acl->version = htonl(ACL_ACLVERSION);
+    acl->total = htonl(v->owner ? 0 : 1);
+    acl->positive = acl->total;
+    acl->negative = 0;
+    if (v->owner) {
+      acl->entries[0].id = htonl(v->owner);
+      acl->entries[0].rights = htonl((PRSFS_READ   | PRSFS_WRITE
+                                    | PRSFS_INSERT | PRSFS_LOOKUP
+                                    | PRSFS_DELETE | PRSFS_LOCK
+                                    | PRSFS_ADMINISTER));
+    }
+    v->field_mask |= F_VNODE_ACL;
+  }
+
+  r = DumpVNode(&repair_output, v);
+  if (r) return r;
+
+  if (v->size) {
+    if (r = xfseek(X, &v->d_offset)) return r;
+    r = CopyVNodeData(&repair_output, X, v->size);
+  } else if (v->type == vDirectory) {
+    afs_dir_page page;
+    struct DirHeader *dhp = (struct DirHeader *)&page;
+    int i;
+
+    if (RV) {
+      fprintf(stderr, ">>> VNODE %d is directory but has no contents\n");
+      fprintf(stderr, ">>> Will generate deafult directory entries\n");
+    }
+    memset(&page, 0, sizeof(page));
+
+    /* Page and Directory Headers */
+    page.header.tag = htons(1234);
+    page.header.freecount = (EPP - DHE - 3);
+    page.header.freebitmap[0] = 0xff;
+    page.header.freebitmap[1] = 0x7f;
+    dhp->alloMap[0] = EPP - DHE - 3;
+    for (i = 1; i < MAXPAGES; i++) dhp->alloMap[i] = EPP;
+
+    /* Entry for . */
+    page.entry[DHE + 1].flag    = FFIRST;
+    page.entry[DHE + 1].length  = 1;
+    page.entry[DHE + 1].vnode   = v->vnode;
+    page.entry[DHE + 1].vunique = v->vuniq;
+    strcpy(page.entry[DHE + 1].name, ".");
+    dhp->hashTable[0x2e] = DHE + 1;
+
+    /* Entry for .. */
+    page.entry[DHE + 2].flag    = FFIRST;
+    page.entry[DHE + 2].length  = 1;
+    page.entry[DHE + 2].vnode   = v->parent;
+    page.entry[DHE + 2].vunique = 1;         /* Can't have everything! */
+    strcpy(page.entry[DHE + 2].name, "..");
+    dhp->hashTable[0x44] = DHE + 2;
+
+    r = DumpVNodeData(&repair_output, (char *)&page, 2048);
+  } else if (field_mask) {
+    /* We wrote out attributes, so we should also write the 0-length data */
+    r = DumpVNodeData(&repair_output, "", 0);
+  }
+
+  return r;
+}
diff --git a/src/tests/rewrite-emacs b/src/tests/rewrite-emacs
new file mode 100755 (executable)
index 0000000..9f5eaa1
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $Id: rewrite-emacs,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+emacsver=20.7
+gzip -dc ${AFSROOT}/stacken.kth.se/ftp/pub/gnu/emacs/emacs-${emacsver}.tar.gz |
+tar vxf - >&4 2>&1 || exit 1
+find emacs-${emacsver} -size 0 -print | xargs rm || exit 1
+find emacs-${emacsver} -print | xargs chmod u+w || exit 1
+$objdir/truncate-files emacs-${emacsver} || exit 1
+exit 0
diff --git a/src/tests/rm-rf.c b/src/tests/rm-rf.c
new file mode 100644 (file)
index 0000000..288ea49
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: rm-rf.c,v 1.1 2002/01/22 19:54:42 hartmans Exp $");
+#endif
+
+static void
+kill_one (const char *filename);
+
+static void
+kill_dir (const char *dirname);
+
+static void
+do_dir (const char *dirname);
+
+static void
+kill_one (const char *filename)
+{
+    int ret;
+
+    ret = unlink (filename);
+    if (ret < 0) {
+       if (errno == EISDIR || errno == EPERM)
+           do_dir (filename);
+       else
+           err (1, "unlink %s", filename);
+    }
+}
+
+static void
+do_dir (const char *dirname)
+{
+    int ret;
+
+    ret = fs_rmmount (dirname);
+    if (ret == 0)
+      return;
+
+    ret = chdir (dirname);
+    if (ret < 0)
+       err (1, "chdir %s", dirname);
+    kill_dir (dirname);
+    ret = chdir ("..");
+    if (ret < 0)
+       err (1, "chdir ..");
+    ret = rmdir (dirname);
+    if (ret < 0)
+       err (1, "rmdir %s", dirname);
+}
+
+static void
+kill_dir (const char *dirname)
+{
+    DIR *dir;
+    struct dirent *dp;
+
+    dir = opendir (".");
+    if (dir == NULL)
+       err (1, "opendir %s", dirname);
+    while ((dp = readdir (dir)) != NULL) {
+       if (strcmp (dp->d_name, ".") == 0
+           || strcmp (dp->d_name, "..") == 0)
+           continue;
+
+       kill_one (dp->d_name);
+    }
+    closedir(dir);
+}
+
+int
+main(int argc, char **argv)
+{
+
+    if (argc < 2)
+       errx (1, "usage: %s directory [...]", argv[0]);
+    while (argc >= 2) {
+       do_dir (argv[1]);
+       argc--;
+       argv++;
+    }
+    return 0;
+}
diff --git a/src/tests/run-fsx b/src/tests/run-fsx
new file mode 100755 (executable)
index 0000000..cd0b851
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# $Id: run-fsx,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+FS=${FS:-${objdir}/../appl/fs/fs}
+
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+${objdir}/fsx -N 25000 -RW -c 1 fsxtmp
+
diff --git a/src/tests/run-rcs b/src/tests/run-rcs
new file mode 100644 (file)
index 0000000..10000f6
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+echo row1 > testfile
+echo log1 | ci -u testfile
+co -l testfile
+echo row2 >> testfile
+echo log2 | ci -u testfile
+co -l testfile
+echo row3 >> testfile
+echo log3 | ci -u testfile
+wc -l testfile | grep '3 testfile' || exit 1
+
diff --git a/src/tests/run-suite.pl b/src/tests/run-suite.pl
new file mode 100755 (executable)
index 0000000..d1559d6
--- /dev/null
@@ -0,0 +1,233 @@
+#!/usr/bin/env perl
+# 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
+          $shutdown_needed $csdb);
+my $rl = new Term::ReadLine('run-suite');
+
+=head1  NAME
+
+   run-suite - Set up AFS cell and test.
+
+=head1 SYNOPSIS
+
+B<run-suite> [B<--cellname> cellname] [B<--cachesize> size]
+
+=head1 DESCRIPTION
+
+
+This script sets up an AFS cell, then runs a suite of tests against the 
+cell to verify the build.
+
+The B<cellname> option specifies the name of the cell.
+
+The B<cachesize> option specifies the size of the AFS cache.
+
+=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 (
+           "cellname=s" => \$cellname, 
+          "cachesize=s" => \$cachesize,
+           "partition=s" => \$part,
+           "admin=s" => \$admin);
+
+if ($> != 0) {
+  die "This script should almost always be run as 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 = "admin" 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;
+
+unlink "$openafsdirpath->{'viceetcdir'}/CellServDB";
+unlink "$openafsdirpath->{'viceetcdir'}/ThisCell";
+
+my $lcell = "${cellname}";
+
+#let bosserver create symlinks
+run("$openafsinitcmd->{'filesrv-start'}");
+unwind("$openafsinitcmd->{'filesrv-stop'}");
+$shutdown_needed = 1;
+run ("$openafsdirpath->{'afssrvbindir'}/bos setcellname $server $lcell -localauth ||true");
+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");
+unwind("$openafsdirpath->{'afssrvbindir'}/bos stop $server ptserver -localauth -wait");
+
+run("$openafsdirpath->{'afssrvbindir'}/bos create $server vlserver simple $openafsdirpath->{'afssrvlibexecdir'}/vlserver -localauth");
+unwind("$openafsdirpath->{'afssrvbindir'}/bos delete $server vlserver -localauth");
+unwind("$openafsdirpath->{'afssrvbindir'}/bos stop $server vlserver -localauth -wait");
+
+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 ");
+unwind( "$openafsdirpath->{'afssrvbindir'}/bos stop $server fs -localauth -wait");
+run("$openafsdirpath->{'afssrvbindir'}/bos restart $server -all -bosserver -localauth");
+
+print "Waiting for database elections: ";
+sleep(90);
+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;
+
+mkdir "/usr/vice/cache", 0700;
+mkdir "/afs", 0777;
+
+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'}");
+
+$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 ");
+
+run("$openafsinitcmd->{'client-restart'}");
+
+`cp ./t.uniq-bad /usr/tmp`;
+
+system ("pagsh -c './test-front.sh $lcell'");
+
+@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/run-tests.in b/src/tests/run-tests.in
new file mode 100644 (file)
index 0000000..464d6ed
--- /dev/null
@@ -0,0 +1,417 @@
+#!/bin/sh
+#
+# $Id: run-tests.in,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+#
+srcdir=@srcdir@
+objdir=`pwd`
+SHELL=/bin/sh
+VERSION=@VERSION@
+PACKAGE=@PACKAGE@
+host=@host@
+RUNAS=nobody
+FS=@afssrvbindir@/fs
+export FS
+
+AFSROOT=${AFSROOT-/afs}
+export AFSROOT
+
+BASIC_TESTS="creat1                    \
+           mkdir1                      \
+           mkdir2                      \
+           symlink                     \
+           hardlink1                   \
+           hardlink4                   \
+           hardlink2                   \
+           hardlink5                   \
+           touch1                      \
+           write1                      \
+           write3                      \
+           rename1                     \
+           hardlink3                   \
+           write2                      \
+           append1                     \
+           rename2                     \
+           rename4                     \
+           rename6                     \
+           rename-under-feet           \
+           large-filename              \
+           fchmod                      \
+           utime-file                  \
+           utime-dir                   \
+           mkdir3"
+
+MTPT_TESTS="mkm-rmm                    \
+           mountpoint"
+
+ACL_TESTS="acladduser.pl               \
+           acladdgroup.pl              \
+           acladdrights.pl             \
+           acladdnegrights.pl          \
+           aclclearnegrights.pl        \
+           aclremoveuser.pl            \
+           aclremovegroup.pl           \
+           aclcopy.pl"
+
+EXEC_TESTS="exec                       \
+           hello-world                 \
+           build-openafs"
+
+MMAP_TESTS="append-over-page           \
+           mmap-shared-write           \
+           mmap-vs-read2               \
+           mmap-vs-read                \
+           read-vs-mmap2               \
+           read-vs-mmap"
+
+FS_TESTS="strange-characters           \
+           pine                        \
+           parallel1                   \
+           write-large"
+
+AFS_TESTS="write-ro                    \
+           too-many-files              \
+           setpag                      \
+           setgroups"
+
+RMT_TESTS="extcopyin                   \
+           extcopyout"
+
+ABUSE_TESTS="read-write                        \
+           create-remove-files         \
+           run-fsx"
+
+PTS_TESTS="ptscreateuser.pl            \
+           ptscreategroup.pl           \
+           ptsadduser.pl               \
+           ptschown.pl                 \
+           ptsmembersuser.pl           \
+           ptsmembersgroup.pl          \
+           ptsexamineuser.pl           \
+           ptsexaminegroup.pl          \
+           ptsremove.pl                \
+           ptslistown.pl               \
+           ptssetmax.pl                \
+           ptslistmax.pl               \
+           ptssetf.pl                  \
+           ptsdeletegroup.pl           \
+           ptsdeleteuser.pl"
+
+VOS_TESTS="voscreate.pl                \
+           vosmove.pl                  \
+           vosaddsite.pl               \
+           vosrelease.pl               \
+           vosremsite.pl               \
+           vosremove.pl                \
+           vosdelentry.pl              \
+           vossyncvldb.pl              \
+           voszap.pl                   \
+           vossyncserv.pl              \
+           voslock.pl                  \
+           vosunlock.pl                \
+           vosunlockall.pl             \
+           vosrename.pl                \
+           voslistvol.pl               \
+           voslistvldb.pl              \
+           vospartinfo.pl              \
+           voslistpart.pl              \
+           vosbackup.pl                \
+           vosexamine.pl               \
+           vosdump.pl                  \
+           vosrestore.pl"
+
+BOS_TESTS="bosaddhost.pl               \
+           boslisthosts.pl             \
+           bosremovehost.pl            \
+           bosadduser.pl               \
+           boslistusers.pl             \
+           bosremoveuser.pl            \
+           bosinstall.pl               \
+           bosexec.pl                  \
+           boscreate.pl                \
+           bosdeleterunning.pl         \
+           bosstatus.pl                \
+           bosstop.pl                  \
+           bosrestartstopped.pl        \
+           bosstart.pl                 \
+           bosshutdown.pl              \
+           bosdelete.pl                \
+           bosaddkey.pl                \
+           boslistkeys.pl              \
+           bosremovekey.pl             \
+           bossalvagevolume.pl         \
+           bossalvagepart.pl           \
+           bossalvageserver.pl"
+
+REG_TESTS="fcachesize-write-file       \
+           fcachesize-read-file        \
+           baduniq.pl"
+
+ALL_TESTS="creat1                      \
+           mkdir1                      \
+           mkdir2                      \
+           symlink                     \
+           hardlink1                   \
+           hardlink4                   \
+           hardlink2                   \
+           hardlink5                   \
+           touch1                      \
+           write1                      \
+           write3                      \
+           rename1                     \
+           hardlink3                   \
+           write2                      \
+           append1                     \
+           rename2                     \
+           rename4                     \
+           rename6                     \
+           rename-under-feet           \
+           large-filename              \
+           fchmod                      \
+           utime-file                  \
+           utime-dir                   \
+           mkdir3                      \
+           mkm-rmm                     \
+           mountpoint                  \
+           acladduser.pl               \
+           acladdgroup.pl              \
+           acladdrights.pl             \
+           acladdnegrights.pl          \
+           aclclearnegrights.pl        \
+           aclremoveuser.pl            \
+           aclremovegroup.pl           \
+           aclcopy.pl                  \
+           exec                        \
+           hello-world                 \
+           build-openafs               \
+           append-over-page            \
+           mmap-shared-write           \
+           mmap-vs-read2               \
+           mmap-vs-read                \
+           read-vs-mmap2               \
+           read-vs-mmap                \
+           strange-characters          \
+           pine                        \
+           parallel1                   \
+           write-large                 \
+           write-ro                    \
+           too-many-files              \
+           setpag                      \
+           setgroups                   \
+           extcopyin                   \
+           extcopyout                  \
+           read-write                  \
+           create-remove-files         \
+           run-fsx                     \
+           ptscreateuser.pl            \
+           ptscreategroup.pl           \
+           ptsadduser.pl               \
+           ptschown.pl                 \
+           ptsmembersuser.pl           \
+           ptsmembersgroup.pl          \
+           ptsexamineuser.pl           \
+           ptsexaminegroup.pl          \
+           ptsremove.pl                \
+           ptslistown.pl               \
+           ptssetmax.pl                \
+           ptslistmax.pl               \
+           ptssetf.pl                  \
+           ptsdeletegroup.pl           \
+           ptsdeleteuser.pl            \
+           voscreate.pl                \
+           vosmove.pl                  \
+           vosaddsite.pl               \
+           vosrelease.pl               \
+           vosremsite.pl               \
+           vosremove.pl                \
+           vosdelentry.pl              \
+           vossyncvldb.pl              \
+           voszap.pl                   \
+           vossyncserv.pl              \
+           voslock.pl                  \
+           vosunlock.pl                \
+           vosunlockall.pl             \
+           vosrename.pl                \
+           voslistvol.pl               \
+           voslistvldb.pl              \
+           vospartinfo.pl              \
+           voslistpart.pl              \
+           vosbackup.pl                \
+           vosexamine.pl               \
+           vosdump.pl                  \
+           vosrestore.pl               \
+           bosaddhost.pl               \
+           boslisthosts.pl             \
+           bosremovehost.pl            \
+           bosadduser.pl               \
+           boslistusers.pl             \
+           bosremoveuser.pl            \
+           bosinstall.pl               \
+           bosexec.pl                  \
+           boscreate.pl                \
+           bosdeleterunning.pl         \
+           bosstatus.pl                \
+           bosstop.pl                  \
+           bosrestartstopped.pl        \
+           bosstart.pl                 \
+           bosshutdown.pl              \
+           bosdelete.pl                \
+           bosaddkey.pl                \
+           boslistkeys.pl              \
+           bosremovekey.pl             \
+           bossalvagevolume.pl         \
+           bossalvagepart.pl           \
+           bossalvageserver.pl         \
+           fcachesize-write-file       \
+           fcachesize-read-file        \
+           baduniq.pl"
+
+TESTS="$ALL_TESTS"
+TEST_MODE="all"
+
+linebreak=":-------------------------------;"
+
+PARALLELL=
+FAST=
+LARGE=
+PRINT_CACHESIZE=
+usage="Usage: $0 [-user user] [-all] [-fast] [-large] [-j] [-verbose] [-x] tests ..."
+while true
+do
+  case $1 in
+  -all) ALL=yes;;
+  -fast) FAST=yes;;
+  -large) LARGE=yes;;
+  -j) PARALLELL="&";;
+  -verbose) VERBOSE=yes;;
+  -user) RUNAS=$1; shift;;
+  -x) SHELLVERBOSE="-x";;
+  -p) PRINT_CACHESIZE="yes";;
+  -basic) TESTS="$BASIC_TESTS";TEST_MODE="basic";;
+  -mtpt) TESTS="$MTPT_TESTS";TEST_MODE="mtpt";;
+  -acl) TESTS="$ACL_TESTS";TEST_MODE="acl";;
+  -exec) TESTS="$EXEC_TESTS";TEST_MODE="exec";;
+  -mmap) TESTS="$MMAP_TESTS";TEST_MODE="mmap";;
+  -fs) TESTS="$FS_TESTS";TEST_MODE="fs";;
+  -afs) TESTS="$AFS_TESTS";TEST_MODE="afs";;
+  -rmt) TESTS="$RMT_TESTS";TEST_MODE="rmt";;
+  -abuse) TESTS="$ABUSE_TESTS";TEST_MODE="abuse";;
+  -pts) TESTS="$PTS_TESTS";TEST_MODE="pts";;
+  -vos) TESTS="$VOS_TESTS";TEST_MODE="vos";;
+  -bos) TESTS="$BOS_TESTS";TEST_MODE="bos";;
+  -reg) TESTS="$REG_TESTS";TEST_MODE="reg";;
+  -help|--help) echo $usage; 
+       echo "tests available: $linebreak"; for a in "$ALL_TESTS"; do echo $a ; done;
+       exit 0;;
+  -version|--version) echo "$0 $Id: run-tests.in,v 1.1 2002/01/22 19:54:42 hartmans Exp $"; exit 0;;
+  -*) echo "$0: Bad option $1"; echo $usage; exit 1;;
+  *) break;;
+  esac
+  shift
+done
+
+if test "X$WORKDIR" = "X";then
+       echo "WORKDIR=workdir $0 $* or env WORKDIR=workdir $0 $*"; exit 1;
+fi
+
+RUNTESTS=
+if test "X$ALL" != "X" ; then
+    RUNTESTS="$TESTS"
+elif test $# -lt 1; then
+    echo $usage; exit
+else
+    RUNTESTS=$*
+fi
+
+# these are variables exported to the scripts
+
+export FAST
+export LARGE
+export VERBOSE
+export SHELLVERBOSE
+
+# and file descriptors
+
+# 3 - progress
+# 4 - details
+
+if test "$VERBOSE" = "yes"; then
+  exec 3>/dev/null
+  exec 4>&1
+else
+  exec 3>&1
+  exec 4>/dev/null
+fi
+
+# Find out where we really are
+
+srcdir=`cd $srcdir; pwd`
+objdir=`cd $objdir; pwd`
+
+export srcdir
+export objdir
+
+echo "-------------------------------------------------"
+echo "$PACKAGE-$VERSION"
+echo "hosttype $host"
+echo "${SHELL},${SHELLVERBOSE},${VERBOSE},${PARALLELL},${FAST}"
+echo "testmode ${TEST_MODE}"
+echo "runas ${RUNAS}"
+echo "${srcdir}"
+echo "${objdir}"
+echo "${WORKDIR}"
+date
+echo "-------------------------------------------------"
+
+test "X$VERBOSE" != "X" && echo "Running tests"
+
+FAILEDTESTS=
+exitval=0
+
+for a in $RUNTESTS; do
+  #
+  # XXX Test if binary in $srcdir, shellscript in $srcdir else
+  # its a binary in objdir
+  #
+  if test -x ${srcdir}/$a ; then
+    b="${srcdir}/$a"
+  elif test -f ${srcdir}/$a ; then
+    b="${SHELL} ${SHELLVERBOSE} ${srcdir}/$a"
+  else
+    b="${objdir}/$a"
+  fi
+  echo "Running $a"
+  test "X$VERBOSE" != "X" && echo "Running test $a ($b)."
+  if test "$a" = "setgroups" ; then
+     b="${objdir}/asu root $b"
+  else
+     b="${objdir}/asu $RUNAS $b"
+  fi
+  tmpdir="`hostname`-$a-`date +%Y-%m-%d-%H-%M-%S`-$$"
+  cd $WORKDIR && mkdir $tmpdir && (cd $tmpdir && $b ${PARALLELL})
+  saved_res=$?
+  test "X$VERBOSE" != "X" && echo "Saved res = $saved_res"
+  if test "X${PARALLELL}" = "X" ;then
+     if test $saved_res != 0 ; then 
+       echo "Test $a FAILED"
+        FAILEDTESTS="${FAILEDTESTS} $a"; 
+        exitval=$savedres
+     else
+       test "X$VERBOSE" != "X" && echo "Test $a succeeded, tmpdir is removed"
+       ${objdir}/rm-rf $tmpdir
+     fi
+     test "X$VERBOSE" != "X" && echo "Done test $a."
+  fi
+  test "X${PRINT_CACHESIZE}" = Xyes && $objdir/../appl/fs/fs calculate
+done
+
+wait
+date
+
+if test "$FAILEDTESTS"; then
+  echo "-----------------------------------------------------------"
+  echo "Failed test(s) were: $FAILEDTESTS"
+else
+  echo "All test(s) were succesful!"
+fi
+
+exit $exitval
diff --git a/src/tests/setgroups b/src/tests/setgroups
new file mode 100755 (executable)
index 0000000..0d6acea
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: setgroups,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+
+$objdir/test-setgroups nobody 1>&4
diff --git a/src/tests/setpag b/src/tests/setpag
new file mode 100755 (executable)
index 0000000..beff874
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id: setpag,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+
+$objdir/test-setpag 1>&4
diff --git a/src/tests/shallow-tree b/src/tests/shallow-tree
new file mode 100644 (file)
index 0000000..97bc66e
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: shallow-tree,v 1.1 2002/01/22 19:54:42 hartmans Exp $
+
+mkdir foo && ( cd foo && $SHELL $SHELLVERBOSE ${srcdir}/dir-tree 3 "0 1 2 3 4" )
+${objdir}/rm-rf foo
\ No newline at end of file
diff --git a/src/tests/stagehdr.c b/src/tests/stagehdr.c
new file mode 100644 (file)
index 0000000..be63426
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* stagehdr.c - Parse and dump stage backup headers */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "xf_errs.h"
+#include "stagehdr.h"
+
+static afs_uint32 hdr_checksum(char *buf, int size)
+{
+  afs_uint32 sum = 0, n = size / sizeof(afs_uint32), *words = (afs_uint32 *)buf;
+
+  while (--n)
+    sum += ntohl(*words++);
+  return sum;
+}
+
+
+/* Parse a stage backup header.
+ * If tag is non-NULL, *tag should contain the first byte (already read),
+ * and will be filled in with the first byte after the header, if one exists.
+ * On success, returns 0 and leaves us positioned after the header
+ * On failure, returns an error and position is undefined
+ * Iff there is no header, returns DSERR_MAGIC and leaves us
+ * positioned where we started.
+ */
+afs_uint32 ParseStageHdr(XFILE *X, unsigned char *tag, backup_system_header *hdr)
+{
+  char buf[STAGE_HDRLEN];
+  struct stage_header *bckhdr = (struct stage_header *)buf;
+  u_int64 where;
+  afs_uint32 r;
+
+  if (r = xftell(X, &where)) return r;
+  if (hdr) memset(hdr, 0, sizeof(*hdr));
+  if (tag) {
+    if (*tag != STAGE_VERSMIN) return DSERR_MAGIC;
+    buf[0] = *tag;
+    r = xfread(X, buf + 1, STAGE_HDRLEN - 1);
+  } else {
+    r = xfread(X, buf, STAGE_HDRLEN);
+  }
+
+  if (r == ERROR_XFILE_EOF) {
+    r = xfseek(X, &where);
+    return r ? r : DSERR_MAGIC;
+  } else if (r) return r;
+
+  if (bckhdr->c_vers < STAGE_VERSMIN
+  ||  ntohl(bckhdr->c_magic) != STAGE_MAGIC
+  ||  hdr_checksum(buf, STAGE_HDRLEN) != STAGE_CHECKSUM) {
+    r = xfseek(X, &where);
+    return r ? r : DSERR_MAGIC;
+  }
+
+  if (hdr) {
+    hdr->version   = bckhdr->c_vers;
+    hdr->from_date = ntohl(bckhdr->c_fdate);
+    hdr->to_date   = ntohl(bckhdr->c_tdate);
+    hdr->dump_date = ntohl(bckhdr->c_time);
+    hdr->filenum   = ntohl(bckhdr->c_filenum);
+    hdr->volid     = ntohl(bckhdr->c_id);
+    hdr->dumplen   = ntohl(bckhdr->c_length);
+    hdr->level     = ntohl(bckhdr->c_level);
+    hdr->magic     = ntohl(bckhdr->c_magic);
+    hdr->cksum     = ntohl(bckhdr->c_checksum);
+    hdr->flags     = ntohl(bckhdr->c_flags);
+    hdr->server    = malloc(strlen(bckhdr->c_host) + 1);
+    hdr->part      = malloc(strlen(bckhdr->c_disk) + 1);
+    hdr->volname   = malloc(strlen(bckhdr->c_name) + 1);
+
+    if (!hdr->server || !hdr->part || !hdr->volname) {
+      if (hdr->server)  free(hdr->server);
+      if (hdr->part)    free(hdr->part);
+      if (hdr->volname) free(hdr->volname);
+      return ENOMEM;
+    }
+    strcpy(hdr->server,  bckhdr->c_host);
+    strcpy(hdr->part,    bckhdr->c_disk);
+    strcpy(hdr->volname, bckhdr->c_name);
+  }
+
+  if (tag) return ReadByte(X, tag);
+  else return 0;
+}
+
+
+/* Dump a stage backup header */
+afs_uint32 DumpStageHdr(XFILE *OX, backup_system_header *hdr)
+{
+  char buf[STAGE_HDRLEN];
+  struct stage_header *bckhdr = (struct stage_header *)buf;
+  afs_uint32 checksum;
+  afs_uint32 r;
+
+  memset(buf, 0, STAGE_HDRLEN);
+  bckhdr->c_vers     = hdr->version;
+  bckhdr->c_fdate    = htonl(hdr->from_date);
+  bckhdr->c_tdate    = htonl(hdr->to_date);
+  bckhdr->c_filenum  = htonl(hdr->filenum);
+  bckhdr->c_time     = htonl(hdr->dump_date);
+  bckhdr->c_id       = htonl(hdr->volid);
+  bckhdr->c_length   = htonl(hdr->dumplen);
+  bckhdr->c_level    = htonl(hdr->level);
+  bckhdr->c_magic    = htonl(STAGE_MAGIC);
+  bckhdr->c_flags    = htonl(hdr->flags);
+
+  strcpy(bckhdr->c_host, hdr->server);
+  strcpy(bckhdr->c_disk, hdr->part);
+  strcpy(bckhdr->c_name, hdr->volname);
+
+  /* Now, compute the checksum */
+  checksum = hdr_checksum(buf, STAGE_HDRLEN);
+  bckhdr->c_checksum = htonl(STAGE_CHECKSUM - checksum);
+
+  if (r = xfwrite(OX, buf, STAGE_HDRLEN)) return r;
+  return 0;
+}
diff --git a/src/tests/stagehdr.h b/src/tests/stagehdr.h
new file mode 100644 (file)
index 0000000..985fe9e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* stagehdr.h - (old) Stage backup header format */
+
+#ifndef _STAGEHDR_H_
+#define _STAGEHDR_H_
+
+#include "intNN.h"
+
+/* Stage-related constants */
+#define STAGE_MAGIC    0x00adf8bc       /* magic number for stage header */
+#define STAGE_CHECKSUM 84446            /* checksum (same as 4.2bsd dump) */
+#define STAGE_VERSMIN  20               /* minimum version */
+#define STAGE_NAMLEN   64               /* length of host/part/vol names */
+#define STAGE_HDRLEN   1024             /* size of the header */
+
+struct stage_header {
+  unsigned char c_vers;               /* header version (starts at 20) */
+  unsigned char c_notused[3];
+  afs_uint32       c_fdate;              /* dump "from" date */
+  afs_uint32       c_tdate;              /* dump "to" date */
+  afs_uint32       c_filenum;            /* tape file number */
+  afs_uint32       c_time;               /* time dump was done */
+  char          c_host[STAGE_NAMLEN]; /* hostname volume came from */
+  char          c_disk[STAGE_NAMLEN]; /* partition volume came from */
+  char          c_name[STAGE_NAMLEN]; /* volume name */
+  afs_uint32       c_id;                 /* volume ID */
+  afs_uint32       c_length;             /* length of the dump */
+  afs_uint32       c_level;              /* dump level */
+  afs_uint32       c_magic;              /* magic number */
+  afs_uint32       c_checksum;           /* checksum of backup header */
+  afs_uint32       c_flags;              /* feature flags */
+};
+
+#endif /* _STAGEHDR_H_ */
diff --git a/src/tests/still-there-p.c b/src/tests/still-there-p.c
new file mode 100644 (file)
index 0000000..90b92cd
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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 <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+
+#include <err.h>
+
+#define TEST_BUFFER_SZ         (1024*8)
+
+int
+main(int argc, char **argv)
+{
+    const char *file = "foo";
+    char otherbuf[TEST_BUFFER_SZ];
+    char buf[TEST_BUFFER_SZ];
+    int fd;
+       
+
+    fd = open (file, O_RDWR|O_TRUNC|O_CREAT, 0644);
+    if (fd < 0)
+       err(1, "open(%s)", file);
+
+    if (write (fd, buf, sizeof(buf)) != sizeof(buf))
+       errx(1, "write");
+
+    while (1) {
+       if (lseek(fd, 0, SEEK_SET) < 0)
+           err(1, "lseek");
+
+       if (read(fd, otherbuf, sizeof(otherbuf)) != sizeof(otherbuf)) {
+           struct stat sb;
+
+           if (fstat(fd, &sb) < 0)
+               err(1, "fstat");
+           printf("size: %d\n", (int)sb.st_size);
+           printf ("lseek(SEEK_CUR): %d\n", (int)lseek(fd, 0, SEEK_CUR));
+           errx(1, "read");
+       }
+
+       if (memcmp(buf, otherbuf, sizeof(buf)) != 0)
+           errx (1, "buf != otherbuf");
+    }
+    close(fd);
+
+    return 0;
+}
diff --git a/src/tests/strange-characters b/src/tests/strange-characters
new file mode 100755 (executable)
index 0000000..a2e85ba
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# $Id: strange-characters,v 1.1 2002/01/22 19:54:43 hartmans Exp $
+for i in Ã¥ Ã¤ Ã¶ Ã¥Ã¤Ã¶; do
+  touch $i || exit 1
+  test -f $i || exit 1
+  rm $i || exit 1
+done
diff --git a/src/tests/strange-characters-c.c b/src/tests/strange-characters-c.c
new file mode 100644 (file)
index 0000000..42d1204
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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 <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: strange-characters-c.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+static void
+creat_file (char *name)
+{
+    int fd;
+
+    fd = open (name, O_WRONLY | O_CREAT | O_EXCL, 0777);
+    if (fd < 0)
+       err (1, "open %s", name);
+    if (close (fd) < 0)
+       err (1, "close %s", name);
+}
+
+static void
+look_at_file (char *name)
+{
+    int fd;
+
+    fd = open (name, O_RDONLY | O_EXCL, 0777);
+    if (fd < 0)
+       err (1, "open %s", name);
+    if (close (fd) < 0)
+       err (1, "close %s", name);
+}
+
+static void
+usage (int ret)
+{
+    fprintf (stderr, "%s\n", __progname);
+    exit (ret);
+}
+
+int
+main(int argc, char **argv)
+{
+    char *file = "åäö";
+
+
+    if (argc != 1)
+       usage (1);
+
+    creat_file (file);
+    look_at_file (file);
+    return 0;
+}
diff --git a/src/tests/strange-other-characters b/src/tests/strange-other-characters
new file mode 100644 (file)
index 0000000..6547ead
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: strange-other-characters,v 1.1 2002/01/22 19:54:43 hartmans Exp $
+dir=$AFSROOT/stacken.kth.se/ftp/pub/arla/tests
+
+test -f $dir/åäö || exit 1
diff --git a/src/tests/symlink.c b/src/tests/symlink.c
new file mode 100644 (file)
index 0000000..c961107
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 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 <err.h>
+
+#ifdef RCSID
+RCSID("$Id: symlink.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+int
+main(int argc, char **argv)
+{
+    int ret;
+    struct stat sb;
+
+
+    ret = symlink ("foo", "bar");
+    if (ret < 0)
+       err (1, "symlink foo,bar");
+    ret = lstat ("bar", &sb);
+    if (ret < 0)
+       err (1, "lstat bar");
+    if ((sb.st_mode & S_IFLNK) != S_IFLNK)
+       errx (1, "bar is not symlink");
+    ret = unlink ("bar");
+    if (ret < 0)
+       err (1, "unlink bar");
+    return 0;
+}
diff --git a/src/tests/t.uniq-bad b/src/tests/t.uniq-bad
new file mode 100644 (file)
index 0000000..1848482
Binary files /dev/null and b/src/tests/t.uniq-bad differ
diff --git a/src/tests/test-front.sh b/src/tests/test-front.sh
new file mode 100755 (executable)
index 0000000..9e999a3
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+pwd=`pwd`
+cell=$1
+./reauth.pl
+PERL5LIB=$pwd
+export PERL5LIB
+WORKDIR=/afs/${cell}/unreplicated
+export WORKDIR
+./run-tests -all
+
diff --git a/src/tests/test-gunzip-gnu-mirror b/src/tests/test-gunzip-gnu-mirror
new file mode 100755 (executable)
index 0000000..dc8bde7
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# $Id: test-gunzip-gnu-mirror,v 1.1 2002/01/22 19:54:43 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+original=${1-$AFSROOT/stacken.kth.se/ftp/pub/gnu}
+cd $original || exit 1
+find . -name '*.gz' -print | while read i; do
+  foo=`gunzip --verbose --test $i 2>&1`
+  echo $foo >& 4
+  case "$foo" in
+*not*in*gzip*format*) ;;
+*OK*) ;;
+*) exit 1 ;;
+  esac
+done
diff --git a/src/tests/test-parallel1.c b/src/tests/test-parallel1.c
new file mode 100644 (file)
index 0000000..125c3f4
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include <err.h>
+
+#include <fcntl.h>
+
+#ifdef RCSID
+RCSID("$Id: test-parallel1.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+#define WORKER_TIMES 100
+#define NUM_WORKER 10
+
+static int
+worker (int num)
+{
+    int i, fd;
+
+    for (i = 0 ; i < WORKER_TIMES ; i++) {
+       fd = open ("foo", O_CREAT|O_RDWR, 0600);
+       if (fd >= 0) {
+           fchmod (fd, 0700);
+           close (fd);
+       }
+       unlink("foo");
+       if (i % 1000) {
+           printf (" %d", num);
+           fflush (stdout);
+       }
+    }
+    return 0;
+}
+
+
+int
+main(int argc, char **argv)
+{
+    int i, ret;
+    
+
+    for (i = 0; i < NUM_WORKER ; i++) {
+       int ret;
+       
+       ret = fork();
+       switch (ret) {
+       case 0:
+           return worker(i);
+       case -1:
+           err (1, "fork");
+       }
+    }
+    i = NUM_WORKER;
+    while (i && wait (&ret)) {
+       i--;
+       if (ret)
+           err (1, "wait: %d", ret);
+    }
+    return 0;
+}
diff --git a/src/tests/test-parallel2.c b/src/tests/test-parallel2.c
new file mode 100644 (file)
index 0000000..e129711
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <err.h>
+
+#include <fcntl.h>
+
+#ifdef RCSID
+RCSID("$Id: test-parallel2.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+#define WORKER_TIMES 1000
+#define NUM_WORKER 100
+
+static int
+getcwd_worker (int num)
+{
+    char name[17];
+    int i;
+
+    snprintf (name, sizeof(name), "%d", num);
+    if (mkdir (name, 0777) < 0)
+       err (1, "mkdir %s", name);
+    if (chdir (name) < 0)
+       err (1, "chdir %s", name);
+    for (i = 0; i < WORKER_TIMES; ++i) {
+       char buf[256];
+
+       getcwd (buf, sizeof(buf));
+    }
+    return 0;
+}
+
+static int
+mkdir_worker (int num)
+{
+    int i;
+
+    for (i = 0; i < WORKER_TIMES; ++i){
+       char name[256];
+
+       snprintf (name, sizeof(name), "m%d-%d", num, i);
+       mkdir (name, 0777);
+    }
+    return 0;
+}
+
+static int
+mkdir_rmdir_worker (int num)
+{
+    int i;
+
+    for (i = 0; i < WORKER_TIMES; ++i){
+       char name[256];
+
+       snprintf (name, sizeof(name), "rm%d-%d", num, i);
+       mkdir (name, 0777);
+    }
+    for (i = 0; i < WORKER_TIMES; ++i){
+       char name[256];
+
+       snprintf (name, sizeof(name), "rm%d-%d", num, i);
+       rmdir (name);
+    }
+    return 0;
+}
+
+static int
+rename_worker (int num)
+{
+    int i;
+
+    for (i = 0; i < WORKER_TIMES; ++i){
+       char name[256];
+       int fd;
+
+       snprintf (name, sizeof(name), "rm%d-%d", num, i);
+       fd = open (name, O_WRONLY | O_CREAT, 0777);
+       close (fd);
+    }
+    for (i = 0; i < WORKER_TIMES; ++i){
+       char name[256], name2[256];
+
+       snprintf (name, sizeof(name), "rm%d-%d", num, i);
+       snprintf (name2, sizeof(name2), "rn%d-%d", num, i);
+       rename (name, name2);
+    }
+    return 0;
+}
+
+static int
+stat_worker (int num)
+{
+    char name[17];
+    int i;
+    char buf[256];
+    struct stat sb;
+
+    snprintf (name, sizeof(name), "%d", num);
+    if (mkdir (name, 0777) < 0)
+       err (1, "mkdir %s", name);
+    if (chdir (name) < 0)
+       err (1, "chdir %s", name);
+    for (i = 0; i < WORKER_TIMES; ++i) {
+       getcwd (buf, sizeof(buf));
+       stat (buf, &sb);
+    }
+    return 0;
+}
+
+static int (*workers[])(int) = {getcwd_worker, mkdir_worker,
+                               mkdir_rmdir_worker, rename_worker,
+                               stat_worker};
+
+static int nworkers = sizeof(workers)/sizeof(*workers);
+
+int
+main(int argc, char **argv)
+{
+    int i, ret;
+    
+
+    for (i = 0; i < NUM_WORKER ; i++) {
+       int ret;
+       
+       ret = fork();
+       switch (ret) {
+       case 0:
+           return (*workers[i % nworkers])(i);
+       case -1:
+           err (1, "fork");
+       }
+    }
+    i = NUM_WORKER;
+    while (i && wait (&ret)) {
+       i--;
+       if (ret)
+           err (1, "wait: %d", ret);
+    }
+    return 0;
+}
diff --git a/src/tests/test-setgroups.c b/src/tests/test-setgroups.c
new file mode 100644 (file)
index 0000000..2915f30
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <limits.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: test-setgroups.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+#if !defined(NGROUPS) && defined(NGROUPS_MAX)
+#define NGROUPS NGROUPS_MAX
+#endif
+
+static void
+print_groups (int ngroups, gid_t groups[NGROUPS])
+{
+    int i;
+
+    printf ("groups: ");
+    for (i = 0; i < ngroups; ++i)
+       printf ("%d%s", groups[i], (i < ngroups - 1) ? ", " : "");
+    printf ("\n");
+}    
+
+int
+main(int argc, char **argv)
+{
+    char *user;
+    char *this_user;
+    struct passwd *this_pwd, *pwd;
+    int ret;
+    gid_t groups[NGROUPS];
+    int ngroups;
+    gid_t pag0, pag1, pag2;
+
+
+    if (argc != 2)
+       errx (1, "Usage: %s user", argv[0]);
+    user = argv[1];
+
+    this_pwd = getpwuid (getuid ());
+    if (this_pwd == NULL)
+       errx (1, "Who are you?");
+    this_user = strdup (this_pwd->pw_name);
+
+    pwd = getpwnam (user);
+    if (pwd == NULL)
+       errx (1, "User %s not found", user);
+
+    ngroups = getgroups (NGROUPS, groups);
+    if (ngroups < 0)
+       err (1, "getgroups %d", NGROUPS);
+    printf ("user %s ", this_user);
+    print_groups (ngroups, groups);
+    printf ("doing setpag()\n");
+    ret = setpag ();
+    if (ret < 0)
+       err (1, "setpag");
+
+    ngroups = getgroups (NGROUPS, groups);
+    if (ngroups < 0)
+       err (1, "getgroups %d", NGROUPS);
+    pag0 = groups[0];
+    pag1 = groups[1];
+    pag2 = groups[2];
+    printf ("user %s ", this_user);
+    print_groups (ngroups, groups);
+
+    ret = initgroups (user, pwd->pw_gid);
+    if (ret < 0)
+       err (1, "initgroups");
+
+    ngroups = getgroups (NGROUPS, groups);
+    if (ngroups < 0)
+       err (1, "getgroups %d", NGROUPS);
+    printf ("user %s ", user);
+    print_groups (ngroups, groups);
+    if ((groups[0] == pag0 && groups[1] == pag1)
+       || (groups[1] == pag1 && groups[2] == pag2))
+       return 0;
+    else
+       return 1;
+}
+
diff --git a/src/tests/test-setpag.c b/src/tests/test-setpag.c
new file mode 100644 (file)
index 0000000..c159f52
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <limits.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: test-setpag.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+#if !defined(NGROUPS) && defined(NGROUPS_MAX)
+#define NGROUPS NGROUPS_MAX
+#endif
+
+static void
+print_groups (int ngroups, gid_t groups[NGROUPS])
+{
+    int i;
+
+    printf ("groups: ");
+    for (i = 0; i < ngroups; ++i)
+       printf ("%d%s", groups[i], (i < ngroups - 1) ? ", " : "");
+    printf ("\n");
+}    
+
+int
+main(int argc, char **argv)
+{
+    int ret;
+    gid_t groups[NGROUPS];
+    int ngroups;
+    gid_t pag1, pag2;
+    pid_t pid;
+
+    if (argc != 1)
+       errx (1, "Usage: %s", argv[0]);
+
+    ngroups = getgroups (NGROUPS, groups);
+    if (ngroups < 0)
+       err (1, "getgroups %d", NGROUPS);
+    pag1 = groups[1];
+    pag2 = groups[2];
+    printf ("in parent ");
+    print_groups (ngroups, groups);
+    pid = fork ();
+    if (pid < 0)
+       err (1, "fork");
+    if (pid == 0) {
+       ret = setpag ();
+       if (ret < 0)
+           err (1, "setpag");
+       ngroups = getgroups (NGROUPS, groups);
+       if (ngroups < 0)
+           err (1, "getgroups %d", NGROUPS);
+       printf ("in child ");
+       print_groups (ngroups, groups);
+       return 0;
+    } else {
+       int status;
+
+       while(waitpid (pid, &status, WNOHANG | WUNTRACED) != pid)
+           ;
+       if (status)
+           return 1;
+       ngroups = getgroups (NGROUPS, groups);
+       if (ngroups < 0)
+           err (1, "getgroups %d", NGROUPS);
+       printf ("in parent ");
+       print_groups (ngroups, groups);
+       if (groups[1] == pag1 && groups[2] == pag2)
+           return 0;
+       else
+           return 1;
+    }
+}
diff --git a/src/tests/too-many-files b/src/tests/too-many-files
new file mode 100644 (file)
index 0000000..2aba4f0
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $Id: too-many-files,v 1.1 2002/01/22 19:54:43 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+
+$objdir/create-files 31707 0
diff --git a/src/tests/touch1 b/src/tests/touch1
new file mode 100755 (executable)
index 0000000..61badc5
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+touch foobar || exit 1
+test -f foobar || exit 1
+rm foobar || exit 1
diff --git a/src/tests/truncate-files.c b/src/tests/truncate-files.c
new file mode 100644 (file)
index 0000000..6eb8bc2
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: truncate-files.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+static void do_dir(const char *);
+static void repeat_dir(const char *);
+
+static void
+do_dir(const char *dirname)
+{
+    int ret;
+
+    ret = chdir (dirname);
+    if (ret < 0)
+       err (1, "chdir %s", dirname);
+    repeat_dir (dirname);
+    ret = chdir ("..");
+    if (ret < 0)
+       err (1, "chdir ..");
+}
+
+static void
+read_and_truncate (const char *filename, const struct stat *sb)
+{
+    int fd;
+    char *buf;
+    int ret;
+    struct stat sb2;
+
+    buf = malloc (sb->st_size);
+    if (buf == NULL)
+       err (1, "malloc %lu", (unsigned long)sb->st_size);
+    fd = open (filename, O_RDONLY);
+    if (fd < 0)
+       err (1, "open readonly %s", filename);
+    ret = read (fd, buf, sb->st_size);
+    if (ret < 0)
+       err (1, "read %s", filename);
+    if (ret != sb->st_size)
+       errx (1, "short read from %s", filename);
+    if (close (fd))
+       err (1, "close reading %s", filename);
+    fd = open (filename, O_WRONLY | O_TRUNC, 0);
+    if (fd < 0)
+       err(1, "open wronly-trunc %s", filename);
+    ret = write (fd, buf, sb->st_size);
+    if (ret < 0)
+       err (1, "write %s", filename);
+    if (ret != sb->st_size)
+       errx (1, "short write %s", filename);
+    if (close (fd))
+       err (1, "close writing %s", filename);
+    ret = lstat (filename, &sb2);
+    if (ret < 0)
+       err (1, "stat %s", filename);
+    if (sb2.st_size != sb->st_size)
+       errx (1, "wrong size after re-writing %s: %lu != %lu",
+             filename,
+             (unsigned long)sb->st_size, (unsigned long)sb2.st_size);
+    free(buf);
+}
+
+static void
+repeat_dir (const char *dirname)
+{
+    DIR *dir;
+    struct dirent *dp;
+
+    dir = opendir (".");
+    if (dir == NULL)
+       err(1, "opendir %s", dirname);
+    while ((dp = readdir (dir)) != NULL) {
+       struct stat sb;
+       int ret;
+
+       if (strcmp (dp->d_name, ".") == 0
+           || strcmp (dp->d_name, "..") == 0)
+           continue;
+
+       ret = lstat (dp->d_name, &sb);
+       if (ret < 0)
+           err (1, "lstat %s", dp->d_name);
+       if (S_ISDIR(sb.st_mode))
+           do_dir (dp->d_name);
+       else if (S_ISREG(sb.st_mode))
+           read_and_truncate (dp->d_name, &sb);
+    }
+    closedir (dir);
+}
+
+
+int
+main(int argc, char **argv)
+{
+
+    if (argc != 2)
+       errx (1, "usage: %s directory", argv[0]);
+    do_dir (argv[1]);
+    return 0;
+}
diff --git a/src/tests/truncate.c b/src/tests/truncate.c
new file mode 100644 (file)
index 0000000..0e41bec
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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>
+
+static void
+create_and_write (char *name, const char *buf)
+{
+    int fd, ret;
+    int len = strlen(buf);
+
+    fd = open (name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+    if (fd < 0)
+       err (1, "open");
+    ret = write (fd, buf, len);
+    if (ret != len)
+       err (1, "write");
+    ret = close (fd);
+    if (ret < 0)
+       err (1, "close");
+}
+
+static void
+check_size (char *name, int len)
+{
+    struct stat sb;
+    int ret;
+
+    ret = stat(name, &sb);
+    if (ret < 0)
+       err (1, "stat");
+
+    if (len != sb.st_size)
+       errx (1, "len != sb.st_size");
+}
+
+int
+main(int argc, char **argv)
+{
+    int ret;
+
+
+    create_and_write ("foo", "hej\n");
+
+    ret = truncate ("foo", 0);
+    if (ret < 0)
+       err (1, "truncate(0)");
+
+    check_size ("foo", 0);
+
+    ret = unlink("foo");
+    if (ret < 0)
+       errx (1, "unlink");
+
+    create_and_write ("bar", "hej\nhej\n");
+
+    ret = truncate ("bar", 16);
+    if (ret < 0)
+       err (1, "truncate(16)");
+
+    check_size ("bar", 16);
+
+    ret = unlink("bar");
+    if (ret < 0)
+       errx (1, "unlink");
+
+    return 0;
+}
diff --git a/src/tests/untar-emacs b/src/tests/untar-emacs
new file mode 100755 (executable)
index 0000000..83a774c
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id: untar-emacs,v 1.1 2002/01/22 19:54:43 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+for i in 1 2 3 4 5 6 7 8 9 10; do
+  $objdir/echo-n '.' >&3
+  gzip -dc $AFSROOT/stacken.kth.se/ftp/pub/gnu/emacs/emacs-20.7.tar.gz | tar xvf - >&4 || exit 1
+  rm -rf emacs-20.7
+done
+echo >&3
diff --git a/src/tests/untar-openafs b/src/tests/untar-openafs
new file mode 100755 (executable)
index 0000000..cf15e84
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $Id: untar-openafs,v 1.1 2002/01/22 19:54:43 hartmans Exp $
+if test "X$FAST" != "X" ; then echo "Not running $0" ;  exit 0 ; fi
+wget http://www.openafs.org/dl/1.2.2/openafs-1.2.2-src.tar.gz
+for i in 1 2 3 4 5 6 7 8 9 10; do
+  $objdir/echo-n '.' >&3
+  gzip -dc openafs-1.2.2-src.tar.gz | tar xvf - >&4 || exit 1
+  rm -rf openafs-1.2.2
+done
+echo >&3
diff --git a/src/tests/util.c b/src/tests/util.c
new file mode 100644 (file)
index 0000000..7c9ac4d
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* util.c - Useful utilities */
+
+#include <errno.h>
+
+#include "xf_errs.h"
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+
+
+/* Take care of errno, ERROR_XFILE_EOF, and ENOMEM return codes.
+ * Call whatever callbacks are necessary, and return the code to
+ * actually use.  If you don't want '0' to result in a DSERR_TAG,
+ * then you must translate it to DSERR_DONE before calling this.
+ */
+/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/
+int handle_return(int r, XFILE *X, unsigned char tag, dump_parser *p)
+{
+  u_int64 where, xwhere;
+
+  switch (r) {
+  case 0:
+    if (p->cb_error) {
+      xftell(X, &where);
+      sub64_32(xwhere, where, 1);
+      (p->cb_error)(DSERR_TAG, 1, p->err_refcon,
+                    (tag > 0x20 && tag < 0x7f)
+                    ? "Unexpected tag '%c' at %s = 0x%s"
+                    : "Unexpected tag 0x%02x at %s = 0x%s",
+                    tag, decimate_int64(&xwhere, 0), hexify_int64(&xwhere, 0));
+    }
+    return DSERR_TAG;
+    
+  case ERROR_XFILE_EOF:
+    if (p->cb_error) {
+      xftell(X, &where);
+      (p->cb_error)(ERROR_XFILE_EOF, 1, p->err_refcon,
+                    "Unexpected EOF at %s = 0x%s",
+                    decimate_int64(&where, 0), hexify_int64(&where, 0));
+    }
+    return ERROR_XFILE_EOF;
+    
+  case ENOMEM:
+    if (p->cb_error) {
+      xftell(X, &where);
+      (p->cb_error)(ENOMEM, 1, p->err_refcon,
+                    "Out of memory at %s = 0x%s",
+                    decimate_int64(&where, 0), hexify_int64(&where, 0));
+    }
+    return ENOMEM;
+    
+  case DSERR_DONE:
+    return 0;
+
+  default:
+    /* For other negative valuees, the callback was already done */
+    if (r > 0 && p->cb_error)
+      (p->cb_error)(r, 1, p->err_refcon,
+                    "System error %d reading dump file", r);
+    return r;
+  }
+}
+
+
+/* Prepare a tag_parse_info for use by the dump parser. *
+/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/
+void prep_pi(dump_parser *p, tag_parse_info *pi)
+{
+  memset(pi, 0, sizeof(tag_parse_info));
+  pi->err_refcon = p->err_refcon;
+  pi->cb_error = p->cb_error;
+
+  if (p->repair_flags & DSFIX_SKIP)
+    pi->flags |= TPFLAG_SKIP;
+  if ((p->flags & DSFLAG_SEEK) && (p->repair_flags & DSFIX_RSKIP))
+    pi->flags |= TPFLAG_RSKIP;
+}
+
+
+/* Does the designated location match a vnode?
+ * Returns 0 if yes, DSERR_FMT if no, something else on error
+ */
+/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/
+int match_next_vnode(XFILE *X, dump_parser *p, u_int64 *where, afs_uint32 vnode)
+{
+  afs_uint32 r, x, y, z;
+  unsigned char tag;
+
+  if (r = xfseek(X, where)) return r;
+  if (r = ReadByte(X, &tag)) return r;
+  switch (tag) {
+  case 3:  /* A vnode? */
+    if (r = ReadInt32(X, &x)) return r;
+    if (r = ReadInt32(X, &y)) return r;
+    if (r = ReadByte(X, &tag)) return r;
+    if ( !((vnode & 1) && !(x & 1) && x < vnode)
+    &&   !((vnode & 1) == (x & 1) && x > vnode))
+      return DSERR_FMT;
+    if (x > vnode && x - vnode > 10000) return DSERR_FMT;
+    if (y < 0 || y > p->vol_uniquifier)  return DSERR_FMT;
+
+    /* Now, what follows the vnode/uniquifier? */
+    switch (tag) {
+    case 3:   /* Another vnode? - Only if this is a non-directory */
+      if (x & 1) return DSERR_FMT;
+      if (r = ReadInt32(X, &z)) return r;
+      if ( !((x & 1) && !(z & 1) && z < x)
+      &&   !((x & 1) == (z & 1) && z > x))
+        return DSERR_FMT;
+      return 0;
+
+    case 4:   /* Dump end - Only if this is a non-directory */
+      if (x & 1) return DSERR_FMT;
+      if (r = ReadInt32(X, &z)) return r;
+      if (z != DUMPENDMAGIC) return DSERR_FMT;
+      return 0;
+
+    case 't': /* Vnode type byte */
+      if (r = ReadByte(X, &tag)) return r;
+      if ((tag == vFile || tag == vSymlink) && !(x & 1)) return 0;
+      if (tag == vDirectory && (x & 1)) return 0;
+      return DSERR_FMT;
+
+    default:
+      return DSERR_FMT;
+    }
+
+  case 4:  /* A dump end? */
+    if (r = ReadInt32(X, &x)) return r;
+    if (x != DUMPENDMAGIC) return DSERR_FMT;
+    return 0;
+
+  default:
+    return DSERR_FMT;
+  }
+}
diff --git a/src/tests/utime-dir.c b/src/tests/utime-dir.c
new file mode 100644 (file)
index 0000000..0eece44
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <err.h>
+
+static void
+doit (const char *filename)
+{
+    int ret;
+    struct timeval tv[2];
+
+    ret = mkdir (filename, 0700);
+    if (ret < 0)
+       err (1, "mkdir %s", filename);
+    gettimeofday (&tv[0], NULL);
+    tv[1] = tv[0];
+    ret = utimes (filename, tv);
+    if (ret < 0)
+       err(1, "utimes %s", filename);
+}
+
+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/utime-file.c b/src/tests/utime-file.c
new file mode 100644 (file)
index 0000000..b1ffa94
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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
+
+#ifdef RCSID
+RCSID("$Id: utime-file.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <err.h>
+
+int
+main (int argc, char ** argv)
+{
+    int len;
+    int ret;
+    int fd;
+    char *filename = "foo";
+    char *buf;
+    struct stat sb;
+    struct utimbuf t;
+
+    switch (argc) {
+    case 1:
+       len = 8 * 1024; break;
+    case 2:
+       len = atoi(argv[1]);
+       if (len == 0)
+           errx (1, "invalid len");
+    default:
+       errx (1, "argv != [12]");
+    }
+
+    buf = malloc (len);
+    memset (buf, 'a', len);
+
+    fd = open (filename, O_RDWR|O_CREAT|O_EXCL, 0744);
+    if (fd < 0)
+       errx (1, "open");
+    ret = fstat (fd, &sb);
+    if (ret < 0)
+       errx (1, "open");
+
+    ret = ftruncate (fd, len);
+    fstat (fd, &sb);
+    lseek (fd, 0, SEEK_SET);
+    write (fd, buf, len);
+    fstat (fd, &sb);
+
+    t.modtime = t.actime = time (NULL); 
+    utime (filename, &t);
+
+    close (fd);
+    free (buf);
+
+    return 0;
+}
diff --git a/src/tests/visit-volumes b/src/tests/visit-volumes
new file mode 100644 (file)
index 0000000..1f991be
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id: visit-volumes,v 1.1 2002/01/22 19:54:43 hartmans Exp $
+ls ${AFSROOT}/nada.kth.se/* >&4 2>&4 || exit 1
+ls -l ${AFSROOT}/nada.kth.se/* >&4 2>&4 || exit 1
+ls ${AFSROOT}/nada.kth.se/*/* >&4 2>&4 || exit 1
+ls -l ${AFSROOT}/nada.kth.se/*/* >&4 2>&4 || exit 1
diff --git a/src/tests/vosaddsite.pl b/src/tests/vosaddsite.pl
new file mode 100755 (executable)
index 0000000..c23c446
--- /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_vos_addsite("testvol","localhost","b",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosbackup.pl b/src/tests/vosbackup.pl
new file mode 100755 (executable)
index 0000000..a485829
--- /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_vos_backup("rep",);
+
+exit(0);
+
+
+
diff --git a/src/tests/voscreate.pl b/src/tests/voscreate.pl
new file mode 100755 (executable)
index 0000000..fd78e9e
--- /dev/null
@@ -0,0 +1,20 @@
+#!/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();
+
+$ret = &AFS_vos_create("testvol","localhost","a",,);
+$ret = &AFS_vos_create("testvol2","localhost","a",,);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosdelentry.pl b/src/tests/vosdelentry.pl
new file mode 100755 (executable)
index 0000000..9ab7102
--- /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_vos_delentry("testvol",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosdump.pl b/src/tests/vosdump.pl
new file mode 100755 (executable)
index 0000000..eabc5a2
--- /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_vos_dump("service",0,"/usr/tmp/service.dump",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosexamine.pl b/src/tests/vosexamine.pl
new file mode 100755 (executable)
index 0000000..a8be8f0
--- /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 ($host, %info, %info2, @rosites, $tmp, @rosite);
+$host = `hostname`;
+chomp $host;
+&AFS_Init();
+
+%info = &AFS_vos_examine("rep",);
+if ($info{'rwpart'} ne "a") {
+    exit 1;
+}
+
+$ret = $info{'rosites'};
+@rosites = @$ret;
+while ($ret = pop(@rosites)) {
+    @rosite = @$ret;
+    if ($rosite[1] ne "a") {
+       exit 1;
+    }
+}
+
+exit(0);
+
+
+
diff --git a/src/tests/voslistpart.pl b/src/tests/voslistpart.pl
new file mode 100755 (executable)
index 0000000..45c5b0a
--- /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, $ret, @parts, $count);
+$host = `hostname`;
+&AFS_Init();
+
+@parts = &AFS_vos_listpart("localhost",);
+$ret = shift(@parts);
+if ($ret ne "a") {
+    exit (1);
+}
+$ret = shift(@parts);
+if ($ret ne "b") {
+    exit (1);
+}
+exit(0);
+
+
+
diff --git a/src/tests/voslistvldb.pl b/src/tests/voslistvldb.pl
new file mode 100755 (executable)
index 0000000..3a951ca
--- /dev/null
@@ -0,0 +1,24 @@
+#!/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, %vols, $lvol, %vol);
+$host = `hostname`;
+&AFS_Init();
+
+%vols = &AFS_vos_listvldb(undef,"localhost","b",,);
+$lvol=$vols{'testvol3'};
+%vol=%$lvol;
+# if it worked it worked...
+if ($vol{'rwpart'} ne "b") {
+    exit(1);
+}
+exit(0);
+
+
+
diff --git a/src/tests/voslistvol.pl b/src/tests/voslistvol.pl
new file mode 100755 (executable)
index 0000000..f7543fe
--- /dev/null
@@ -0,0 +1,24 @@
+#!/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, %vols, $lvol, %vol);
+$host = `hostname`;
+&AFS_Init();
+
+%vols = &AFS_vos_listvol("localhost","b",);
+$lvol=$vols{'testvol3'};
+%vol=%$lvol;
+# if it worked it worked...
+if ($vol{'part'} ne "b") {
+    exit(1);
+}
+exit(0);
+
+
+
diff --git a/src/tests/voslock.pl b/src/tests/voslock.pl
new file mode 100755 (executable)
index 0000000..7f1bec8
--- /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_vos_lock("testvol",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosmove.pl b/src/tests/vosmove.pl
new file mode 100755 (executable)
index 0000000..5240547
--- /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_vos_move("testvol","localhost","a","localhost","b",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vospartinfo.pl b/src/tests/vospartinfo.pl
new file mode 100755 (executable)
index 0000000..701cb35
--- /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, %info);
+$host = `hostname`;
+&AFS_Init();
+
+%info = &AFS_vos_partinfo("localhost",,);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosrelease.pl b/src/tests/vosrelease.pl
new file mode 100755 (executable)
index 0000000..479d297
--- /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_vos_release("testvol",,);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosremove.pl b/src/tests/vosremove.pl
new file mode 100755 (executable)
index 0000000..5fd53e7
--- /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_vos_remove("testvol.readonly","localhost","b",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosremsite.pl b/src/tests/vosremsite.pl
new file mode 100755 (executable)
index 0000000..c93e271
--- /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_vos_remsite("testvol","localhost","b",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosrename.pl b/src/tests/vosrename.pl
new file mode 100755 (executable)
index 0000000..45bdfdb
--- /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_vos_rename("testvol","testvol3",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosrestore.pl b/src/tests/vosrestore.pl
new file mode 100755 (executable)
index 0000000..9ab0d93
--- /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_vos_restore("service2","localhost","a","/usr/tmp/service.dump",,"full",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vossyncserv.pl b/src/tests/vossyncserv.pl
new file mode 100755 (executable)
index 0000000..a6ed963
--- /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_vos_syncserv("localhost","a",,);
+
+exit(0);
+
+
+
diff --git a/src/tests/vossyncvldb.pl b/src/tests/vossyncvldb.pl
new file mode 100755 (executable)
index 0000000..47c4aa9
--- /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_vos_syncvldb("localhost","b",,);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosunlock.pl b/src/tests/vosunlock.pl
new file mode 100755 (executable)
index 0000000..5dfd1fc
--- /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_vos_unlock("testvol",);
+
+exit(0);
+
+
+
diff --git a/src/tests/vosunlockall.pl b/src/tests/vosunlockall.pl
new file mode 100755 (executable)
index 0000000..6d9c55f
--- /dev/null
@@ -0,0 +1,21 @@
+#!/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_vos_lock("testvol",);
+&AFS_vos_lock("service",);
+&AFS_vos_unlockvldb("localhost",,);
+
+exit(0);
+
+
+
diff --git a/src/tests/voszap.pl b/src/tests/voszap.pl
new file mode 100755 (executable)
index 0000000..bacce85
--- /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_vos_zap("testvol2","localhost","a",,);
+
+exit(0);
+
+
+
diff --git a/src/tests/warn.c b/src/tests/warn.c
new file mode 100644 (file)
index 0000000..119ee08
--- /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: warn.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+#include "err.h"
+
+void
+warn(const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vwarn(fmt, ap);
+  va_end(ap);
+}
diff --git a/src/tests/warnx.c b/src/tests/warnx.c
new file mode 100644 (file)
index 0000000..fc49b54
--- /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: warnx.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+#include "err.h"
+
+void
+warnx(const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vwarnx(fmt, ap);
+  va_end(ap);
+}
diff --git a/src/tests/write-closed.c b/src/tests/write-closed.c
new file mode 100644 (file)
index 0000000..7941bf9
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 <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 void
+doit (const char *filename)
+{
+    int fd;
+    int ret;
+    void *buf;
+
+    fd = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    ret = ftruncate (fd, 1);
+    if (ret < 0)
+       err (1, "ftruncate %s", filename);
+    buf = mmap (NULL, 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (buf == (void *) MAP_FAILED)
+       err (1, "mmap");
+    if (fchmod (fd, 0) < 0)
+       err (1, "fchmod %s, 0", filename);
+    ret = close (fd);
+    if (ret < 0)
+       err (1, "close %s", filename);
+    *((char *)buf) = 0x17;
+    ret = munmap (buf, 1);
+    if (ret < 0)
+       err (1, "munmap");
+}
+
+int
+main(int argc, char **argv)
+{
+    const char *file = "foo";
+
+    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/write-closed2.c b/src/tests/write-closed2.c
new file mode 100644 (file)
index 0000000..b68374d
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <err.h>
+#include <netinet/in.h>
+#include <afs/param.h>
+#include <afs/stds.h>
+#include <afs/vice.h>
+#include <afs/venus.h>
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+static int
+set_acl (char *dir)
+{
+    struct ViceIoctl a_params;
+    char *foo = "1\n0\nsystem:anyuser 0\n";
+
+    a_params.in_size  = strlen(foo);
+    a_params.out_size = 0;
+    a_params.in       = foo;
+    a_params.out      = NULL;
+
+    return pioctl (dir, VIOCSETAL, &a_params, 1);
+}
+
+static void
+doit (const char *filename)
+{
+    int fd;
+    int ret;
+    void *buf;
+
+    ret = mkdir ("bad", 0777);
+    if (ret < 0)
+       err (1, "mkdir bad");
+
+    ret = chdir ("bad");
+    if (ret < 0)
+       err (1, "chdir bad");
+
+    fd = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    ret = ftruncate (fd, 1);
+    if (ret < 0)
+       err (1, "ftruncate %s", filename);
+    buf = mmap (NULL, 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (buf == (void *) MAP_FAILED)
+       err (1, "mmap");
+    ret = set_acl (".");
+    if (ret < 0)
+       err (1, "setacl failed");
+
+    ret = close (fd);
+    if (ret < 0)
+       err (1, "close %s", filename);
+    *((char *)buf) = 0x17;
+    ret = munmap (buf, 1);
+    if (ret < 0)
+       err (1, "munmap");
+}
+
+int
+main(int argc, char **argv)
+{
+    const char *file = "foo";
+
+
+    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/write-large.c b/src/tests/write-large.c
new file mode 100644 (file)
index 0000000..3d02570
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+#include <err.h>
+
+const char *fn = "foobar";
+
+static void
+check_size(const char *fn, size_t sz, int paranoia)
+{
+    struct stat sb;
+
+    if (paranoia)
+       return;
+
+    if (stat(fn, &sb) < 0)
+       err(1, "stat");
+    if (sb.st_size != sz)
+       errx(1, "st_size mismatch %d != %d", (int)sb.st_size, (int)sz);
+}
+
+int
+main(int argc, char **argv)
+{
+    int fd, cnt, ret;
+    int buf[1024];
+
+#ifdef O_LARGEFILE
+    fd = open(fn, O_RDWR|O_CREAT|O_TRUNC|O_LARGEFILE, 0644);
+#else
+    fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0644);
+#endif
+    if (fd < 0)
+       err(1, "open1");
+    cnt=0;
+    while (cnt < 2097151) {
+      ret = write(fd,buf,1024);
+      if (ret != 1024)
+       errx(1, "write1 %d %d", cnt, ret);
+      cnt++;
+    }
+    ret = write(fd,buf,1024);
+    if (ret != 1023)
+      errx(1, "write1 last %d", ret);
+    if (close(fd) < 0)
+       err(1, "close1");
+    
+    check_size(fn, 2147483647, 0);
+    
+    return 0;
+}
diff --git a/src/tests/write-rand.c b/src/tests/write-rand.c
new file mode 100644 (file)
index 0000000..ab17301
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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 <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: write-rand.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+static char *
+write_random_file (int fd, size_t sz)
+{
+    char *buf;
+    int i, j;
+
+    j = sz;
+    if (j > 2048) {
+      j = 2048;
+    }
+    buf = malloc (j);
+    if (buf == NULL)
+       err (1, "malloc %u", (unsigned)sz);
+
+    for (i = 0; i < j; ++i) {
+      buf[i] = rand();
+    }      
+    while (sz > 0) {
+      if (write (fd, buf, j) != j)
+       err (1, "write");
+      
+      sz -= j;
+      j = sz;
+      if (j > 2048)
+       j = 2048;
+    }
+
+    return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+    const char *file;
+    const size_t sz;
+    char *random_buf;
+    char *read_buf1;
+    char *read_buf2;
+    int fd;
+
+    if (argc != 3) 
+      errx (1, "usage: %s file size", argv[0]);
+
+    file = argv[1];
+    sz = atoi(argv[2]);
+
+    srand (time(NULL));
+
+    fd = open (file, O_RDWR | O_CREAT, 0755);
+    if (fd < 0)
+       err (1, "open %s", file);
+
+    if (lseek(fd, 0, SEEK_SET) < 0)
+       err (1, "lseek");
+    write_random_file(fd, sz);
+
+    close (fd);
+    return 0;
+}
diff --git a/src/tests/write-ro b/src/tests/write-ro
new file mode 100755 (executable)
index 0000000..9be34f0
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+touch ../../replicated/foo || exit 0
+exit 1
diff --git a/src/tests/write-ro-file.c b/src/tests/write-ro-file.c
new file mode 100644 (file)
index 0000000..1937ed3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 <unistd.h>
+#include <fcntl.h>
+
+#include <err.h>
+
+#ifdef RCSID
+RCSID("$Id: write-ro-file.c,v 1.1 2002/01/22 19:54:43 hartmans Exp $");
+#endif
+
+int
+main(int argc, char *argv[])
+{
+  int fd;
+  int ret;
+
+  fd = open("foo", O_RDWR|O_CREAT, 0);
+  if (fd < 0)
+      err (1, "open foo");
+  ret = write (fd, "foo", 3);
+  if (ret < 0) {
+      unlink("foo");
+      err (1, "write foo");
+  }
+  ret = close (fd);
+  if (ret < 0) {
+      unlink("foo");
+      err (1, "close foo");
+  }
+  unlink("foo");
+  return 0;
+}
diff --git a/src/tests/write-ucc.c b/src/tests/write-ucc.c
new file mode 100644 (file)
index 0000000..f94afeb
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <err.h>
+
+static void
+doit (const char *filename)
+{
+    int fd;
+    int ret;
+    struct timeval tv[2];
+    struct stat sb;
+
+    fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+    if (fd < 0)
+       err (1, "open %s", filename);
+    ret = write (fd, "hej\n", 4);
+    if(ret < 0)
+       err (1, "write %s", filename);
+    if (ret != 4)
+       errx (1, "short write to %s", filename);
+    gettimeofday (&tv[0], NULL);
+    tv[1] = tv[0];
+    ret = utimes (filename, tv);
+    if(ret < 0)
+       err (1, "utimes %s", filename);
+    ret = chmod (filename, 0644);
+    if (ret < 0)
+       err (1, "chmod %s", filename);
+    ret = chown (filename, 0, 0);
+    ret = fstat (fd, &sb);
+    if (ret < 0)
+       err (1, "fstat %s", filename);
+    if (sb.st_size != 4)
+       errx (1, "stat 1: size = %lu != 4", (unsigned long)sb.st_size);
+    ret = close (fd);
+    if (ret < 0)
+       err (1, "close %s", filename);
+    ret = stat (filename, &sb);
+    if (ret < 0)
+       err (1, "stat %s", filename);
+    if (sb.st_size != 4)
+       errx (1, "stat 1: size = %lu != 4", (unsigned long)sb.st_size);
+}
+
+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/write1 b/src/tests/write1
new file mode 100755 (executable)
index 0000000..00d386d
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+echo hej > foo || exit 1
+if test X`cat foo` != X"hej"; then exit 1; fi
+rm foo || exit 1
diff --git a/src/tests/write2 b/src/tests/write2
new file mode 100755 (executable)
index 0000000..90808c6
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+echo hopp > foo || exit 1
+if test X`cat foo` != "Xhopp"; then exit 1; fi
+echo hej > foo || exit 1
+if test X`cat foo` != "Xhej"; then exit 1; fi
+rm foo || exit 1
diff --git a/src/tests/write3.c b/src/tests/write3.c
new file mode 100644 (file)
index 0000000..6de1511
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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 <sys/types.h>
+
+#include <stdio.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+#include <err.h>
+
+const char *fn = "foobar";
+
+static void
+check_size(const char *fn, size_t sz, int paranoia)
+{
+    struct stat sb;
+
+    if (paranoia)
+       return;
+
+    if (stat(fn, &sb) < 0)
+       err(1, "stat");
+    if (sb.st_size != sz)
+       errx(1, "st_size mismatch %d != %d", (int)sb.st_size, (int)sz);
+}
+
+static void
+check_size_read(int fd, size_t sz)
+{
+    off_t old_off;
+    size_t sz2;
+    void *buf;
+
+    if ((old_off = lseek(fd, 0, SEEK_CUR)) < 0)
+       err(1, "lseek");
+
+    if (lseek(fd, 0, SEEK_SET) < 0)
+       err(1, "lseek");
+    buf = malloc(sz);
+    if (buf == NULL)
+       errx(1, "malloc");
+    if ((sz2 = read(fd, buf, sz)) < 0)
+       errx(1, "read");
+    if (sz2 != sz)
+       errx(1, "end before end: sz2 (%u) != sz (%u)", (unsigned)sz2,
+            (unsigned)sz);
+    if ((sz2 = lseek(fd, 0, SEEK_END)) < 0)
+       errx(1, "lseek");
+    if (sz2 != sz)
+       errx(1, "end past end: sz2 (%u) != sz (%u)", (unsigned)sz2,
+            (unsigned)sz);
+    free(buf);
+}
+
+
+int
+main(int argc, char **argv)
+{
+    int fd;
+
+    fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0644);
+    if (fd < 0)
+       err(1, "open1");
+    if (write(fd,"kaka", 4) != 4)
+       errx(1, "write1");
+    check_size(fn, 4, 1);
+    if (close(fd) < 0)
+       err(1, "close1");
+    
+    check_size(fn, 4, 0);
+    
+    fd = open(fn,O_RDWR|O_CREAT|O_TRUNC,644);
+    if (fd < 0)
+       err(1, "open2");
+    check_size(fn, 0, 1);
+    if (write(fd,"kaka", 4) != 4)
+       errx(1, "write2");
+    check_size(fn, 4, 1);
+    check_size_read(fd, 4);
+    if (close(fd) < 0)
+        err(1, "close2");
+    check_size(fn, 4, 1);
+
+    unlink(fn);
+
+    return 0;
+}
diff --git a/src/tests/xf_errs.et b/src/tests/xf_errs.et
new file mode 100644 (file)
index 0000000..03cca8f
--- /dev/null
@@ -0,0 +1,37 @@
+# CMUCS AFStools
+# dumpscan - routines for scanning and manipulating AFS volume dumps
+#
+# Copyright (c) 1998 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.
+
+# xf_errs.et - Error table for xfiles
+
+error_table xFil
+  ec ERROR_XFILE_EOF,            "EOF while reading XFILE"
+  ec ERROR_XFILE_WRONLY,         "XFILE may not be opened write-only"
+  ec ERROR_XFILE_RDONLY,         "XFILE is read-only"
+  ec ERROR_XFILE_NOSEEK,         "XFILE is not seekable"
+  ec ERROR_XFILE_ISPASS,         "XFILE passthru already set"
+  ec ERROR_XFILE_NOPASS,         "XFILE passthru not set"
+  ec ERROR_XFILE_TYPE,           "unknown XFILE type"
+end
diff --git a/src/tests/xf_files.c b/src/tests/xf_files.c
new file mode 100644 (file)
index 0000000..877e1ae
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* xf_files.c - XFILE routines for accessing UNIX files */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#define O_MODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
+
+
+/* do_read for stdio xfiles */
+static afs_uint32 xf_FILE_do_read(XFILE *X, void *buf, afs_uint32 count)
+{
+  FILE *F = X->refcon;
+
+  /* XXX: handle short and interrupted reads */
+  if (fread(buf, count, 1, F) != 1)
+    return ferror(F) ? errno : ERROR_XFILE_EOF;
+  return 0;
+}
+
+
+/* do_write for stdio xfiles */
+static afs_uint32 xf_FILE_do_write(XFILE *X, void *buf, afs_uint32 count)
+{
+  FILE *F = X->refcon;
+
+  /* XXX: handle interrupted writes */
+  if (fwrite(buf, count, 1, F) != 1)
+    return errno;
+  return 0;
+}
+
+
+/* do_tell for stdio xfiles */
+static afs_uint32 xf_FILE_do_tell(XFILE *X, u_int64 *offset)
+{
+  FILE *F = X->refcon;
+  off_t where;
+
+  where = ftell(F);
+  if (where == -1) return errno;
+  set64(*offset, where);
+  return 0;
+}
+
+
+/* do_seek for stdio xfiles */
+static afs_uint32 xf_FILE_do_seek(XFILE *X, u_int64 *offset)
+{
+  FILE *F = X->refcon;
+  off_t where = get64(*offset);
+
+  if (fseek(F, where, SEEK_SET) == -1) return errno;
+  return 0;
+}
+
+
+/* do_skip for stdio xfiles */
+static afs_uint32 xf_FILE_do_skip(XFILE *X, afs_uint32 count)
+{
+  FILE *F = X->refcon;
+
+  if (fseek(F, count, SEEK_CUR) == -1) return errno;
+  return 0;
+}
+
+
+/* do_close for stdio xfiles */
+static afs_uint32 xf_FILE_do_close(XFILE *X)
+{
+  FILE *F = X->refcon;
+
+  X->refcon = 0;
+  if (fclose(F)) return errno;
+  return 0;
+}
+
+
+/* Prepare a stdio XFILE */
+static void prepare(XFILE *X, FILE *F, int xflag)
+{
+  struct stat st;
+
+  memset(X, 0, sizeof(*X));
+  X->do_read  = xf_FILE_do_read;
+  X->do_write = xf_FILE_do_write;
+  X->do_tell  = xf_FILE_do_tell;
+  X->do_close = xf_FILE_do_close;
+  X->refcon = F;
+  if (xflag == O_RDWR) X->is_writable = 1;
+
+  if (!fstat(fileno(F), &st)
+  && ((st.st_mode & S_IFMT) == S_IFREG
+  ||  (st.st_mode & S_IFMT) == S_IFBLK)) {
+    X->is_seekable = 1;
+    X->do_seek = xf_FILE_do_seek;
+    X->do_skip = xf_FILE_do_skip;
+  }
+}
+
+
+/* Open an XFILE by path */
+afs_uint32 xfopen_path(XFILE *X, int flag, char *path, int mode)
+{
+  FILE *F = 0;
+  int fd = -1, xflag;
+  afs_uint32 code;
+
+  xflag = flag & O_MODE_MASK;
+  if (xflag == O_WRONLY) return ERROR_XFILE_WRONLY;
+
+  if ((fd = open(path, flag, mode)) < 0) return errno;
+  if (!(F = fdopen(fd, (xflag == O_RDONLY) ? "r" : "r+"))) {
+    code = errno;
+    close(fd);
+    return code;
+  }
+
+  prepare(X, F, xflag);
+  return 0;
+}
+
+
+/* Open an XFILE by FILE * */
+afs_uint32 xfopen_FILE(XFILE *X, int flag, FILE *F)
+{
+  flag &= O_MODE_MASK;
+  if (flag == O_WRONLY) return ERROR_XFILE_WRONLY;
+  prepare(X, F, flag);
+  return 0;
+}
+
+
+/* Open an XFILE by file descriptor */
+afs_uint32 xfopen_fd(XFILE *X, int flag, int fd)
+{
+  FILE *F;
+
+  flag &= O_MODE_MASK;
+  if (flag == O_WRONLY) return ERROR_XFILE_WRONLY;
+  if (!(F = fdopen(fd, (flag == O_RDONLY) ? "r" : "r+"))) return errno;
+  prepare(X, F, flag);
+  return 0;
+}
+
+
+/* open-by-name support for filenames */
+afs_uint32 xfon_path(XFILE *X, int flag, char *name)
+{
+  return xfopen_path(X, flag, name, 0644);
+}
+
+
+/* open-by-name support for file descriptors */
+afs_uint32 xfon_fd(XFILE *X, int flag, char *name)
+{
+  int fd = atoi(name);
+  return xfopen_fd(X, flag, fd);
+}
+
+
+/* open-by-name support for standard I/O */
+afs_uint32 xfon_stdio(XFILE *X, int flag)
+{
+  flag &= O_MODE_MASK;
+  if (flag == O_WRONLY) flag = O_RDWR;
+  return xfopen_FILE(X, flag, (flag == O_RDONLY) ? stdin : stdout);
+}
diff --git a/src/tests/xf_printf.c b/src/tests/xf_printf.c
new file mode 100644 (file)
index 0000000..d1060ea
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdarg.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#define SPBUFLEN 40
+static char spbuf[SPBUFLEN + 1] = "";
+
+
+#define MAXPREC 100
+
+/* Generate an ASCII representation of an integer <val>, as follows:
+ * <base> indicates the base to be used (2-36)
+ * <uc> is nonzero if letter digits should be uppercase
+ * <prec> is the minimum number of digits
+ * The resulting number is stored in <buf>, which must be long enough
+ * to receive it.  The minimum length is <prec> or ceil(log{base}(val)),
+ * whichever is larger, plus room for a trailing NUL.
+ */
+static void mkint(char *buf, unsigned long val, int base, int uc, int prec)
+{
+  int len = 0, dig, i;
+
+  while (val) {
+    dig = val % base;
+    val = (val - dig) / base;
+    if (dig < 10)  dig = dig + '0';
+    else if (uc) dig = dig + 'A' - 10;
+    else         dig = dig + 'a' - 10;
+    buf[len++] = dig;
+  }
+  while (len < prec) buf[len++] = '0';
+  for (i = 0; i < (len + 1) / 2; i++) {
+    dig = buf[i];
+    buf[i] = buf[len - i - 1];
+    buf[len - i - 1] = dig;
+  }
+  buf[len] = 0;
+}
+
+
+/* Write spaces faster than one at a time */
+static afs_uint32 wsp(XFILE *X, int count)
+{
+  char *x;
+  afs_uint32 err;
+  int i;
+
+  if (!spbuf[0]) {
+    for (x = spbuf, i = SPBUFLEN; i; x++, i--) *x = ' ';
+  }
+
+  while (count > SPBUFLEN) {
+    err = xfwrite(X, spbuf, SPBUFLEN);
+    if (err) return err;
+    count -= SPBUFLEN;
+  }
+  if (count > 0) return xfwrite(X, spbuf, count);
+  return 0;
+}
+
+
+/* This function is a mostly-complete implementation of snprintf,
+ * with the following features:
+ *
+ *   - Actually obeys the length limit, which (unfortunately) many
+ *     implementations of snprintf do not.
+ *  
+ *   - Supports all the standard format specifiers for integers
+ *     (d, i, o, u, x, X), floating-point values (f, e, E, g, G),
+ *     and strings and characters (c, s, %), plus a few unusual
+ *     but useful ones described below.
+ *  
+ *   - Supports all the standard flags (-, 0, +, space, #).  These
+ *     flags are ignored if used when they are not appropriate.
+ *  
+ *   - Supports the standard size modifiers for short (h), long (h),
+ *     and double (L) arguments.  These modifiers are ignored if used
+ *     when they are not appropriate.
+ *  
+ *   - Supports minimum field width and precision, where appropriate,
+ *     including the use of '*' to specify a value given as an argument
+ *     instead of in the format string.  There is a maximum precision
+ *     of 100 digits.
+ *  
+ *   - At present, the 'p' specifier for printing pointers is not
+ *     implemented, because it is inherently non-portable and thus
+ *     can be implemented correctly only by the compiler's run-time
+ *     library.
+ *
+ *   - Floating-point specifier (%e, %f, %g) are implemented by
+ *     calling the standard sprintf, and thus may be unsafe.
+ *  
+ *   - The '%...$' notation is used primarily when the format string
+ *     is specified by the user, who knows but cannot change the order
+ *     of the arguments.  Such usage is inherently dangerous and
+ *     insecure; thus, it is not supported.
+ *  
+ * The custom format specifier '%I' is supported.  This specifier
+ * takes as its argument an unsigned long integer containing an
+ * IPv4 address in network byte order.  The address is rendered
+ * either as a hostname or as a dotted quad, as follows:
+ *  
+ *   - If precision is nonzero or unspecified, a hostname lookup
+ *     is attempted; if it is successful, the hostname is printed.
+ *     If the hostname lookup fails, the address is printed in
+ *     dotted-quad notation.
+ *  
+ *   - If precision is explicitly specified as 0, then the hostname
+ *     lookup is skipped, and dotted-quad notation is always used.
+ *  
+ *   - If a hostname is to be printed:
+ *     + The precision controls the maximum number of characters
+ *       printed, as with %s.
+ *     + If the '#' flag is specified, any letters in the hostname
+ *       will be forced to lower case before printing.
+ *     + If the '+' flag is specified, any letters in the hostname
+ *       will be forced to upper case before printing.  If both
+ *       '#' and '+' are given, the '+' flag will be ignored.
+ *     + The '0' and ' ' flags have no effect.
+ *  
+ *   - If a dotted quad is to be printed:
+ *     + The precision has no effect; dotted quads are always
+ *       7 to 12 characters in length, depending on the value
+ *       to be printed and the format flags used.
+ *     + If the '0' flag is given, each field (byte) of the address
+ *       will be padded with '0' on the left to three digits.
+ *     + If the ' ' flag is given, each field (byte) of the address
+ *       will be padded with spaces on the left to three digits.  If
+ *       both '0' and ' ' are given, the ' ' flag will be ignored.
+ *     + The '#' and '+' flags have no effect.
+ */
+
+afs_uint32 vxfprintf(XFILE *X, char *fmt, va_list ap)
+{
+  unsigned int width, precision, haveprec, len;
+  int ljust, plsign, spsign, altform, zfill;
+  int hflag, lflag, count, *countp, j;
+  char *x, *y, *lit = 0, xbuf[MAXPREC + 21], fbuf[20];
+  struct hostent *he;
+  struct in_addr ia;
+  unsigned long UVAL;
+  long SVAL, *lcountp;
+  double FVAL;
+  short *hcountp;
+  afs_uint32 err;
+
+  count = 0;
+  while (*fmt) {
+    if (*fmt != '%') {
+      if (!lit) lit = fmt;
+      fmt++;
+      count++;
+      continue;
+    }
+    if (lit) {
+      if ((err = xfwrite(X, lit, fmt - lit))) return err;
+      lit = 0;
+    }
+
+    /** Found a format specifier **/
+    ljust = plsign = spsign = altform = zfill = 0;
+    width = precision = haveprec = 0;
+    hflag = lflag = 0;
+    fmt++;
+
+    /* parse format flags */
+    while (*fmt) {
+      switch (*fmt) {
+        case '-': ljust   = 1; fmt++; continue;      /* left justify */
+        case '+': plsign  = 1; fmt++; continue;      /* use + or - */
+        case ' ': spsign  = 1; fmt++; continue;      /* use space or - */
+        case '#': altform = 1; fmt++; continue;      /* alternate form */
+        case '0': zfill   = 1; fmt++; continue;      /* pad with 0 */
+        default: break;
+      }
+      break;
+    }
+
+    /* parse minimum width */
+    if (*fmt == '*') {
+      width = va_arg(ap, int);
+      fmt++;
+    } else while (isdigit(*fmt)) {
+      width = (width * 10) + (*fmt - '0');
+      fmt++;
+    }
+
+    /* parse precision */
+    if (*fmt == '.') {
+      fmt++;
+      haveprec = 1;
+      if (*fmt == '*') {
+        precision = va_arg(ap, int);
+        fmt++;
+      } else while (isdigit(*fmt)) {
+        precision = (precision * 10) + (*fmt - '0');
+        fmt++;
+      }
+    }
+
+    /* parse size flags */
+    while (*fmt) {
+      switch (*fmt) {
+        case 'h': hflag   = 1; fmt++; continue;      /* short argument */
+        case 'l': lflag   = 1; fmt++; continue;      /* long argument */
+        default: break;
+      }
+      break;
+    }
+
+    /* parse format specifier */
+    if (!*fmt) break;
+    switch (*fmt++) {
+      case 'e':
+      case 'E':
+      case 'f':
+      case 'g':
+      case 'G':
+        FVAL = va_arg(ap, double);
+        sprintf(fbuf, "%%%s%s.*L%c", plsign ? "+" : (spsign ? " " : ""),
+                altform ? "#" : "", fmt[-1]);
+        if (!haveprec) precision = 6;
+        if (precision > MAXPREC) precision = MAXPREC;
+        sprintf(xbuf, fbuf, precision, FVAL);
+        x = xbuf;
+        len = strlen(x);
+        break;
+
+      case 'i': 
+      case 'd': /* signed decimal integer */
+        if      (lflag) SVAL = va_arg(ap, long);
+        else if (hflag) SVAL = va_arg(ap, int);
+        else            SVAL = va_arg(ap, int);
+        UVAL = (SVAL < 0) ? -SVAL : SVAL;
+
+        if (SVAL < 0)    xbuf[0] = '-';
+        else if (plsign) xbuf[0] = '+';
+        else if (spsign) xbuf[0] = ' ';
+        else             xbuf[0] = 0;
+
+        if (!haveprec) {
+          if (zfill && !ljust) precision = width - !!xbuf[0];
+          else precision = 1;
+          if (precision < 1 + !!xbuf[0]) precision = 1 + !!xbuf[0];
+        }
+        if (precision > MAXPREC) precision = MAXPREC;
+
+        mkint(xbuf + 1, UVAL, 10, 0, precision);
+        x = xbuf + !xbuf[0];
+        len = strlen(x);
+        break;
+
+
+      case 'o': /* unsigned octal integer */
+        if      (lflag) UVAL = va_arg(ap, unsigned long);
+        else if (hflag) UVAL = va_arg(ap, unsigned int);
+        else            UVAL = va_arg(ap, unsigned int);
+
+        xbuf[0] = '0';
+
+        if (!haveprec) {
+          if (zfill && !ljust) precision = width;
+          else precision = 1;
+        }
+        if (precision > MAXPREC) precision = MAXPREC;
+
+        mkint(xbuf + 1, UVAL, 8, 0, precision);
+        x = xbuf + (xbuf[1] == '0' || !altform);
+        len = strlen(x);
+        break;
+
+      case 'u': /* unsigned decimal integer */
+        if      (lflag) UVAL = va_arg(ap, unsigned long);
+        else if (hflag) UVAL = va_arg(ap, unsigned int);
+        else            UVAL = va_arg(ap, unsigned int);
+
+        if (!haveprec) {
+          if (zfill && !ljust) precision = width;
+          else precision = 1;
+        }
+        if (precision > MAXPREC) precision = MAXPREC;
+
+        mkint(xbuf, UVAL, 10, 0, precision);
+        x = xbuf;
+        len = strlen(x);
+        break;
+
+      case 'x': 
+      case 'X': /* unsigned hexadecimal integer */
+        if      (lflag) UVAL = va_arg(ap, unsigned long);
+        else if (hflag) UVAL = va_arg(ap, unsigned int);
+        else            UVAL = va_arg(ap, unsigned int);
+
+        xbuf[0] = '0';
+        xbuf[1] = 'x';
+
+        if (!haveprec) {
+          if (zfill && !ljust) precision = width;
+          else precision = 1;
+        }
+        if (precision > MAXPREC) precision = MAXPREC;
+
+        mkint(xbuf + 2, UVAL, 16, 0, precision);
+        x = xbuf + ((altform && UVAL) ? 0 : 2);
+        len = strlen(x);
+        break;
+
+      case '%': /* literal % */
+        xbuf[0] = '%';
+        xbuf[1] = 0;
+        x = xbuf;
+        len = 1;
+        break;
+
+      case 'c': /* character */
+        xbuf[0] = va_arg(ap, int);
+        xbuf[1] = 0;
+        x = xbuf;
+        len = 1;
+        break;
+
+      case 's': /* string */
+        x = va_arg(ap, char *);
+        if (!x) x = "<null>";
+        len = strlen(x);
+        if (haveprec && precision < len) len = precision;
+        break;
+
+      case 'I': /* IP address:
+         * value is provided as a network-order unsigned long integer
+         * precision specifies max hostname length, as for %s
+         * if precision is explicitly 0, no hostname lookup is done
+         * if 0fill specified, IPaddr fields are 0-filled to 3 digits
+         * if spsign specified, IPaddr fields are space-filled to 3 digits
+         */
+        UVAL = va_arg(ap, unsigned long);
+        ia.s_addr = UVAL;
+        /* XXX: add support for an application-provided function
+         * for doing hostname lookups.  We don't do it automatically
+         * because on some platforms that would prevent us from
+         * being fully statically linked.
+         */
+        if (haveprec && !precision) he = 0;
+        else he = gethostbyaddr((char *)&ia, 4, AF_INET);
+        if (he) {
+          x = he->h_name;
+          len = strlen(x);
+          if (haveprec && precision < len) len = precision;
+          if (altform)
+            for (y = x; *y; y++) if (isupper(*y)) *y = tolower(*y);
+          else if (plsign)
+            for (y = x; *y; y++) if (islower(*y)) *y = toupper(*y);
+        } else {
+          UVAL = ntohl(UVAL);
+          if      (zfill)  x = "%03u.%03u.%03u.%03u";
+          else if (spsign) x = "%3u.%3u.%3u.%3u";
+          else             x = "%u.%u.%u.%u";
+          sprintf(xbuf, x,
+                  (UVAL & 0xff000000) >> 24, (UVAL & 0x00ff0000) >> 16,
+                  (UVAL & 0x0000ff00) >> 8,  (UVAL & 0x000000ff));
+          x = xbuf;
+          len = strlen(xbuf);
+        }
+        break;
+
+      case 'n': /* report count so far */
+        if (lflag) {
+          lcountp = va_arg(ap, long *);
+          *lcountp = count;
+        } else if (hflag) {
+          hcountp = va_arg(ap, short *);
+          *hcountp = count;
+        } else {
+          countp = va_arg(ap, int *);
+          *countp = count;
+        }
+        continue;
+
+      default: /* unknown specifier */
+        continue;
+    }
+
+    /* render the results */
+    if (!width)        width = len;
+    j = width - len;
+    if (j > 0) count += j;
+    count += len;
+
+    if (!ljust && (err = wsp(X, j))) return err;
+    if ((err = xfwrite(X, x, len))) return err;
+    if (ljust && (err = wsp(X, j))) return err;
+  }
+  if (lit && (err = xfwrite(X, lit, fmt - lit))) return err;
+  return 0;
+lose:
+  return err;
+}
+
+
+afs_uint32 xfprintf(XFILE *X, char *fmt, ...)
+{
+  va_list ap;
+  afs_uint32 err;
+
+  va_start(ap, fmt);
+  err = vxfprintf(X, fmt, ap);
+  va_end(ap);
+  return err;
+}
diff --git a/src/tests/xf_profile.c b/src/tests/xf_profile.c
new file mode 100644 (file)
index 0000000..9f9dd50
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* xf_profile.c - XFILE routines for read/write profiling */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#define O_MODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
+
+typedef struct {
+  XFILE content;
+  XFILE profile;
+} PFILE;
+
+
+/* do_read for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_read(XFILE *X, void *buf, afs_uint32 count)
+{
+  PFILE *PF = X->refcon;
+  afs_uint32 err;
+
+  err = xfread(&PF->content, buf, count);
+  xfprintf(&PF->profile, "R %ld =%ld\n", (long)count, (long)err);
+  return err;
+}
+
+
+/* do_write for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_write(XFILE *X, void *buf, afs_uint32 count)
+{
+  PFILE *PF = X->refcon;
+  afs_uint32 err;
+
+  err = xfwrite(&PF->content, buf, count);
+  xfprintf(&PF->profile, "W %ld =%ld\n", (long)count, (long)err);
+  return err;
+}
+
+
+/* do_tell for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_tell(XFILE *X, u_int64 *offset)
+{
+  PFILE *PF = X->refcon;
+  afs_uint32 err;
+
+  err = xftell(&PF->content, offset);
+  if (err) xfprintf(&PF->profile, "TELL ERR =%ld\n", (long)err);
+  else     xfprintf(&PF->profile, "TELL %s =0\n", hexify_int64(offset, 0));
+  return err;
+}
+
+
+/* do_seek for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_seek(XFILE *X, u_int64 *offset)
+{
+  PFILE *PF = X->refcon;
+  afs_uint32 err;
+
+  err = xfseek(&PF->content, offset);
+  xfprintf(&PF->profile, "SEEK %s =%ld\n", hexify_int64(offset, 0), (long)err);
+  return err;
+}
+
+
+/* do_skip for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_skip(XFILE *X, afs_uint32 count)
+{
+  PFILE *PF = X->refcon;
+  afs_uint32 err;
+
+  err = xfskip(&PF->content, count);
+  xfprintf(&PF->profile, "SKIP %ld =%ld\n", (long)count, (long)err);
+  return err;
+}
+
+
+/* do_close for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_close(XFILE *X)
+{
+  PFILE *PF = X->refcon;
+  afs_uint32 err, err2;
+
+  err = xfclose(&PF->content);
+  err2 = xfclose(&PF->profile);
+  free(PF);
+  return err ? err : err2;
+}
+
+
+/* Open a profiled XFILE */
+afs_uint32 xfopen_profile(XFILE *X, int flag, char *xname, char *profile)
+{
+  PFILE *PF;
+  afs_uint32 err;
+
+  PF = malloc(sizeof(*PF));
+  if (!PF) return ENOMEM;
+  memset(PF, 0, sizeof(*PF));
+
+  err = xfopen(&PF->profile, O_RDWR|O_CREAT|O_TRUNC, profile);
+  if (err) {
+    free(PF);
+    return err;
+  }
+
+  err = xfopen(&PF->content, flag, xname);
+  if (err) {
+    xfclose(&PF->profile);
+    free(PF);
+    return err;
+  }
+
+  memset(X, 0, sizeof(*X));
+  X->refcon = PF;
+  X->do_read  = xf_PROFILE_do_read;
+  X->do_write = xf_PROFILE_do_write;
+  X->do_tell  = xf_PROFILE_do_tell;
+  X->do_close = xf_PROFILE_do_close;
+  X->is_writable = PF->content.is_writable;
+  if (PF->content.is_seekable) {
+    X->is_seekable;
+    X->do_seek  = xf_PROFILE_do_seek;
+    X->do_skip  = xf_PROFILE_do_skip;
+  }
+  xfprintf(&PF->profile, "OPEN %s\n", xname);
+  return 0;
+}
+
+
+afs_uint32 xfon_profile(XFILE *X, int flag, char *name)
+{
+  char *x, *profile, *xname;
+  afs_uint32 err;
+
+  if (!(name = strdup(name))) return ENOMEM;
+
+  profile = "-";
+  xname = name;
+  for (x = name; *x; x++) {
+    if (x[0] == ':' && x[1] == ':') {
+      *x = 0;
+      profile = name;
+      xname = x + 2;
+      break;
+    }
+  }
+  if (!*name) profile = "-";
+  err = xfopen_profile(X, flag, xname, profile);
+  free(name);
+  return err;
+}
diff --git a/src/tests/xf_rxcall.c b/src/tests/xf_rxcall.c
new file mode 100644 (file)
index 0000000..957f7ab
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* xf_rxcall.c - XFILE routines for Rx bulk data transfers */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <netdb.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#include <rx/xdr.h>
+#include <rx/rx.h>
+#include <rx/rx_null.h>
+#include <rx/rxkad.h>
+#include <afs/auth.h>
+#include <afs/cellconfig.h>
+#include <afs/vlserver.h>
+#include <afs/volser.h>
+
+#ifndef AFSCONF_CLIENTNAME
+#include <afs/dirpath.h>
+#define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
+#endif
+
+#define O_MODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
+
+struct rxinfo {
+  struct rx_connection *conn;  /* connection */
+  struct rx_call *call;        /* call */
+  afs_int32 tid;                   /* volser transaction ID */
+  afs_uint32 code;                /* result code */
+};
+
+static afs_uint32 xf_rxcall_do_read(XFILE *X, void *buf, afs_uint32 count)
+{
+  struct rxinfo *i = X->refcon;
+  afs_uint32 xcount;
+
+  xcount = rx_Read(i->call, buf, count);
+  if (xcount == count) return 0;
+  i->code = rx_EndCall(i->call, 0);
+  i->call = 0;
+  return i->code ? i->code : ERROR_XFILE_RDONLY;
+}
+
+
+static afs_uint32 xf_rxcall_do_write(XFILE *X, void *buf, afs_uint32 count)
+{
+  struct rxinfo *i = X->refcon;
+  afs_uint32 xcount;
+
+  xcount = rx_Write(i->call, buf, count);
+  if (xcount == count) return 0;
+  i->code = rx_EndCall(i->call, 0);
+  i->call = 0;
+  return i->code;
+}
+
+
+static afs_uint32 xf_rxcall_do_close(XFILE *X)
+{
+  struct rxinfo *i = X->refcon;
+  afs_uint32 code;
+
+  if (i->call) {
+    code = rx_EndCall(i->call, i->code);
+    i->call = 0;
+  } else {
+    code = i->code;
+  }
+  free(i);
+  return code;
+}
+
+
+static afs_uint32 xf_voldump_do_close(XFILE *X)
+{
+  struct rxinfo *i = X->refcon;
+  struct rx_connection *conn = i->conn;
+  afs_uint32 code, rcode, xcode;
+  afs_int32 tid = i->tid;
+
+  code = xf_rxcall_do_close(X);
+  xcode = AFSVolEndTrans(conn, tid, &rcode);
+  if (!code) code = xcode ? xcode : rcode;
+  return code;
+}
+
+
+afs_uint32 xfopen_rxcall(XFILE *X, int flag, struct rx_call *call)
+{
+  struct rxinfo *i;
+
+  flag &= O_MODE_MASK;
+  if (flag == O_WRONLY) return ERROR_XFILE_WRONLY;
+  memset(X, 0, sizeof(*X));
+  if (!(i = (struct rxinfo *)malloc(sizeof(struct rxinfo)))) return ENOMEM;
+  i->call = call;
+  i->code = 0;
+  X->do_read  = xf_rxcall_do_read;
+  X->do_write = xf_rxcall_do_write;
+  X->do_close = xf_rxcall_do_close;
+  X->is_writable = (flag == O_RDWR);
+  X->refcon = i;
+  return 0;
+}
+
+
+afs_uint32 xfopen_voldump(XFILE *X, struct rx_connection *conn,
+                       afs_int32 part, afs_int32 volid, afs_int32 date)
+{
+  struct rx_call *call;
+  struct rxinfo *i;
+  afs_uint32 code, rcode;
+  afs_int32 tid;
+
+  if (code = AFSVolTransCreate(conn, volid, part, ITBusy, &tid)) return code;
+  call = rx_NewCall(conn);
+  if ((code = StartAFSVolDump(call, tid, date))
+  ||  (code = xfopen_rxcall(X, O_RDONLY, call))) {
+    rx_EndCall(call, 0);
+    AFSVolEndTrans(conn, tid, &rcode);
+    return code;
+  }
+
+  i = X->refcon;
+  i->conn = conn;
+  i->tid = tid;
+  X->do_close = xf_voldump_do_close;
+  return 0;
+}
+
+
+afs_uint32 xfon_voldump(XFILE *X, int flag, char *name)
+{
+  struct hostent *he;
+  struct rx_securityClass *class;
+  struct rx_connection *conn;
+  struct ktc_principal sname;
+  struct ktc_token token;
+  struct afsconf_dir *confdir;
+  afs_uint32 code, server_addr;
+  afs_int32 volid, partid, date;
+  int isnum, index;
+  char *x, *y;
+
+  /* Parse out the optional date and server location */
+  if (code = rx_Init(0)) return code;
+  if (!(name = strdup(name))) return ENOMEM;
+  if (x = strrchr(name, ',')) {
+    *x++ = 0;
+    date = atoi(x);
+  } else {
+    date = 0;
+  }
+  if (x = strrchr(name, '@')) {
+    int a, b, c, d;
+
+    *x++ = 0;
+    if (!(y = strchr(x, '/'))) {
+      free(name);
+      return VL_BADPARTITION;
+    }
+    *y++ = 0;
+    if (sscanf(x, "%d.%d.%d.%d", &a, &b, &c, &d) == 4
+    &&  a >= 0 && a <= 255 && b >= 0 && b <= 255
+    &&  c >= 0 && c <= 255 && d >= 0 && d <= 255) {
+      server_addr = (a << 24) | (b << 16) | (c << 8) | d;
+      server_addr = htonl(server_addr);
+    } else {
+      he = gethostbyname(x);
+      if (!he) {
+        free(name);
+        return VL_BADSERVER;
+      }
+      memcpy(&server_addr, he->h_addr, sizeof(server_addr));
+    }
+    partid = volutil_GetPartitionID(y);
+    if (partid < 0) {
+      free(name);
+      return VL_BADPARTITION;
+    }
+  }
+
+  /* Get tokens and set up a security object */
+  confdir = afsconf_Open(AFSCONF_CLIENTNAME);
+  if (!confdir) {
+    free(name);
+    return AFSCONF_NODB;
+  }
+  if (code = afsconf_GetLocalCell(confdir, sname.cell, MAXKTCNAMELEN)) {
+    free(name);
+    return code;
+  }
+  afsconf_Close(confdir);
+  strcpy(sname.name, "afs");
+  sname.instance[0] = 0;
+  code = ktc_GetToken(&sname, &token, sizeof(token), 0);
+  if (code) {
+    class = rxnull_NewClientSecurityObject();
+    index = 0;
+  } else {
+    class = rxkad_NewClientSecurityObject(rxkad_clear, &token.sessionKey,
+            token.kvno, token.ticketLen, token.ticket);
+    index = 2;
+  }
+
+  /* Figure out the volume ID, looking it up in the VLDB if neccessary.
+   * Also look up the server and partition, if they were not specified.
+   */
+  for (isnum = 1, y = name; *y; y++)
+    if (*y < '0' || *y > '9') isnum = 0;
+  if (isnum) {
+    volid = atoi(name);
+    if (!x) {
+      fprintf(stderr, "XXX: need to lookup volume by ID!\n");
+      exit(-1);
+    }
+  } else {
+    fprintf(stderr, "XXX: need to lookup volume by name!\n");
+    exit(-1);
+  }
+  free(name);
+
+  /* Establish a connection and start the call */
+  conn = rx_NewConnection(server_addr, htons(AFSCONF_VOLUMEPORT),
+                          VOLSERVICE_ID, class, index);
+  return xfopen_voldump(X, conn, partid, volid, date);
+}
diff --git a/src/tests/xfiles.c b/src/tests/xfiles.c
new file mode 100644 (file)
index 0000000..6b026f5
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* xfiles.c - General support routines for xfiles */
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#define SKIP_SIZE 65536
+
+extern afs_uint32 xfon_path(XFILE *, int, char *);
+extern afs_uint32 xfon_fd(XFILE *, int, char *);
+extern afs_uint32 xfon_voldump(XFILE *, int, char *);
+extern afs_uint32 xfon_profile(XFILE *, int, char *);
+extern afs_uint32 xfon_stdio(XFILE *, int);
+
+struct xftype {
+  struct xftype *next;
+  char *name;
+  afs_uint32 (*do_on)(XFILE *, int, char *);
+};
+
+
+static struct xftype *xftypes = 0;
+static int did_register_defaults = 0;
+
+
+afs_uint32 xfread(XFILE *X, void *buf, afs_uint32 count)
+{
+  afs_uint32 code;
+  u_int64 tmp64;
+
+  code = (X->do_read)(X, buf, count);
+  if (code) return code;
+
+  add64_32(tmp64, X->filepos, count);
+  cp64(X->filepos, tmp64);
+  if (X->passthru) return xfwrite(X->passthru, buf, count);
+  return 0;
+}
+
+
+afs_uint32 xfwrite(XFILE *X, void *buf, afs_uint32 count)
+{
+  afs_uint32 code;
+  u_int64 tmp64;
+
+  if (!X->is_writable) return ERROR_XFILE_RDONLY;
+  code = (X->do_write)(X, buf, count);
+  if (code) return code;
+
+  add64_32(tmp64, X->filepos, count);
+  cp64(X->filepos, tmp64);
+  return 0;
+}
+
+
+afs_uint32 xftell(XFILE *X, u_int64 *offset)
+{
+  if (X->do_tell) return (X->do_tell)(X, offset);
+  cp64(*offset, X->filepos);
+  return 0;
+}
+
+
+afs_uint32 xfseek(XFILE *X, u_int64 *offset)
+{
+  afs_uint32 code;
+
+  if (!X->do_seek) return ERROR_XFILE_NOSEEK;
+  code = (X->do_seek)(X, offset);
+  if (code) return code;
+  cp64(X->filepos, *offset);
+  return 0;
+}
+
+
+afs_uint32 xfskip(XFILE *X, afs_uint32 count)
+{
+  afs_uint32 code;
+  u_int64 tmp64;
+
+  /* Use the skip method, if there is one */
+  if (X->do_skip && !X->passthru) {
+    code = (X->do_skip)(X, count);
+    if (code) return code;
+    add64_32(tmp64, X->filepos, count);
+    cp64(X->filepos, tmp64);
+    return 0;
+  }
+
+  /* Simulate using absolute seek, if available */
+  if (X->do_seek && !X->passthru) {
+    if (code = xftell(X, &tmp64)) return code;
+    add64_32(X->filepos, tmp64, count);
+    cp64(tmp64, X->filepos);
+    return xfseek(X, &tmp64);
+  }
+
+  /* Do it the hard/slow way - read all the data to be skipped.
+   * This is done if no other method is available, or if we are
+   * supposed to be copying all the data to another XFILE
+   */
+  {
+    char buf[SKIP_SIZE];
+    afs_uint32 n;
+
+    while (count) {
+      n = (count > SKIP_SIZE) ? SKIP_SIZE : count;
+      if (code = xfread(X, buf, n)) return code;
+      count -= n;
+    }
+    return 0;
+  }
+}
+
+
+afs_uint32 xfpass(XFILE *X, XFILE *Y)
+{
+  if (X->passthru) return ERROR_XFILE_ISPASS;
+  if (!Y->is_writable) return ERROR_XFILE_RDONLY;
+  X->passthru = Y;
+  return 0;
+}
+
+
+afs_uint32 xfunpass(XFILE *X)
+{
+  if (!X->passthru) return ERROR_XFILE_NOPASS;
+  X->passthru = 0;
+  return 0;
+}
+
+
+afs_uint32 xfclose(XFILE *X)
+{
+  int code = 0;
+
+  if (X->do_close) code = (X->do_close)(X);
+  memset(X, 0, sizeof(*X));
+  return 0;
+}
+
+
+afs_uint32 xfregister(char *name, afs_uint32 (*do_on)(XFILE *, int, char *))
+{
+  struct xftype *x;
+
+  if (!(x = (struct xftype *)malloc(sizeof(struct xftype)))) return ENOMEM;
+  memset(x, 0, sizeof(*x));
+  x->next = xftypes;
+  x->name = name;
+  x->do_on = do_on;
+  xftypes = x;
+}
+
+
+static void register_default_types(void)
+{
+  xfregister("FILE",    xfon_path);
+  xfregister("FD",      xfon_fd);
+  xfregister("AFSDUMP", xfon_voldump);
+  xfregister("PROFILE", xfon_profile);
+  did_register_defaults = 1;
+}
+
+
+afs_uint32 xfopen(XFILE *X, int flag, char *name)
+{
+  struct xftype *x;
+  char *type, *sep;
+
+  if (!did_register_defaults) register_default_types();
+  if (!strcmp(name, "-")) return xfon_stdio(X, flag);
+
+  for (type = name; *name && *name != ':'; name++);
+  if (*name) {
+    sep = name;
+    *name++ = 0;
+  } else {
+    sep = 0;
+    name = type;
+    type = "FILE";
+  }
+
+  for (x = xftypes; x; x = x->next)
+    if (!strcmp(type, x->name)) break;
+  if (sep) *sep = ':';
+  if (x) return (x->do_on)(X, flag, name);
+  return ERROR_XFILE_TYPE;
+}
diff --git a/src/tests/xfiles.h b/src/tests/xfiles.h
new file mode 100644 (file)
index 0000000..661ac23
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 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.
+ */
+
+/* xfiles.h - Type, constant, and function declarations for
+ * extensible file-like things */
+
+#ifndef _XFILES_H_
+#define _XFILES_H_
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "intNN.h"
+
+struct rx_call;
+struct rx_connection;
+
+/* The XFILE structure */
+typedef struct XFILE XFILE;
+struct XFILE {
+  afs_uint32 (*do_read)(XFILE *, void *, afs_uint32);   /* read data */
+  afs_uint32 (*do_write)(XFILE *, void *, afs_uint32);  /* write data */
+  afs_uint32 (*do_tell)(XFILE *, u_int64 *);         /* find position */
+  afs_uint32 (*do_seek)(XFILE *, u_int64 *);         /* set position */
+  afs_uint32 (*do_skip)(XFILE *, afs_uint32);           /* skip forward */
+  afs_uint32 (*do_close)(XFILE *);                   /* close */
+  u_int64 filepos;                                /* position (counted) */
+  int is_seekable;                                /* 1 if seek works */
+  int is_writable;                                /* 1 if write works */
+  XFILE *passthru;                                /* XFILE to pass thru to */
+  void *refcon;                                   /* type-specific data */
+};
+
+
+/* Functions for opening XFILEs.  For these, the first two arguments are
+ * always a pointer to an XFILE to fill in, and the mode in which to
+ * open the file.  O_RDONLY and O_RDWR are permitted; O_WRONLY is not.
+ * Other open modes may or may not be used, depending on the object type.
+ * Remaining arguments are a function of the object type
+ */
+extern afs_uint32 xfopen     (XFILE *, int, char *);      /* open by TYPE:name */
+extern afs_uint32 xfopen_path(XFILE *, int, char *, int); /* open by path   */
+extern afs_uint32 xfopen_FILE(XFILE *, int, FILE *);      /* open by FILE * */
+extern afs_uint32 xfopen_fd  (XFILE *, int, int);         /* open by fd     */
+extern afs_uint32 xfopen_rxcall (XFILE *, int, struct rx_call *);
+extern afs_uint32 xfopen_voldump(XFILE *, struct rx_connection *,
+                              afs_int32, afs_int32, afs_int32);
+extern afs_uint32 xfopen_profile(XFILE *, int, char *, char *);
+
+extern afs_uint32 xfregister(char *, afs_uint32 (*)(XFILE *, int, char *));
+
+/* Standard operations on XFILEs */
+extern afs_uint32 xfread(XFILE *, void *, afs_uint32);     /* read data */
+extern afs_uint32 xfwrite(XFILE *, void *, afs_uint32);    /* write data */
+extern afs_uint32 xfprintf(XFILE *, char *, ...);          /* formatted */
+extern afs_uint32 vxfprintf(XFILE *, char *, va_list);     /* formatted VA */
+extern afs_uint32 xftell(XFILE *, u_int64 *);              /* get position */
+extern afs_uint32 xfseek(XFILE *, u_int64 *);              /* set position */
+extern afs_uint32 xfskip(XFILE *, afs_uint32);             /* skip forward */
+extern afs_uint32 xfpass(XFILE *, XFILE *);                /* set passthru */
+extern afs_uint32 xfunpass(XFILE *);                       /* unset passthru */
+extern afs_uint32 xfclose(XFILE *);                        /* close */
+
+#endif /* _XFILES_H_ */
diff --git a/src/tools/install/RPM.README b/src/tools/install/RPM.README
new file mode 100644 (file)
index 0000000..135e77a
--- /dev/null
@@ -0,0 +1,33 @@
+## RPM creation documentation ##
+## Steps to creating an openafs-tools-cmd binary distribution RPM ##
+##
+## Copyright 2001, International Business Machines Corporation and others.
+## All Rights Reserved.
+## 
+## This software has been released under the terms of the IBM Public
+## License.  For details, see the LICENSE file in the top-level source
+## directory or online at http://www.openafs.org/dl/license10.html
+##
+## openafs-tools, Version 1.2.2 ##
+
+Follow these steps to create a binary distribution RPM for the 
+openafs-tools-cmd package no Red Hat Linux:
+
+1) Copy the spec file to your SPECS directory.
+
+  cp openafs-tools-cmd-1.2.2-1.spec /usr/src/redhat/SPECS/
+
+2) Create the source package by running:
+
+  ./make_rpm_source
+
+  This creates the source tar and moves it to the 
+/usr/src/redhat/SOURCES directory
+
+3) Now you can create the RPM:
+
+  cd /usr/src/redhat/SPECS
+  rpm -ba --clean openafs-tools-cmd-1.2.2-1.i386.rpm
+
+  The RPM is now ready for use in the 
+/usr/src/redhat/RPMS directory.
diff --git a/src/tools/install/afs_uninstall b/src/tools/install/afs_uninstall
new file mode 100644 (file)
index 0000000..79d6293
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+# OpenAFS uninstallation script for Linux
+# openafs-tools, Version 1.2.2
+#
+# Copyright 2001, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+#
+# the directory with the openafs-tools files:
+afscodeFileDir=/usr/afs/tools/install/
+#
+echo "Uninstall" > $afscodeFileDir/.afs_state
+echo "begin" >> $afscodeFileDir/.afs_state
+bosserver_process=$(ps -Ao pid,cmd | grep boss)
+kill ${bosserver_process%% /*}
+rm -rf /vicep*/*
+rm -rf /etc/rc.d/rc*.d/*afs*
+perl $afscodeFileDir/write_pam.pl disable
+rm -f /lib/security/pam_afs.so
+rm -rf /usr/afs/db
+rm -rf /usr/afs/etc
+rm -rf /usr/afs/local
+rm -rf /usr/afs/logs
+rm -f /usr/vice/etc/CellServDB
+rm -f /usr/vice/etc/ThisCell
+rm -f /usr/vice/etc/AFSLog
+rm -rf /usr/vice/cache
+mkdir /usr/vice/cache
+echo "Uninstall" > $afscodeFileDir/.afs_state
+echo "complete" >> $afscodeFileDir/.afs_state
+
+
+
+
diff --git a/src/tools/install/afsinit_both b/src/tools/install/afsinit_both
new file mode 100644 (file)
index 0000000..c08e252
--- /dev/null
@@ -0,0 +1,37 @@
+#! /bin/sh
+# Copyright 2000, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+
+# Configuration information for AFS client
+
+# AFS_CLIENT and AFS_SERVER determine if we should start the client and or
+# the bosserver. Possible values are on and off.
+AFS_CLIENT=on
+AFS_SERVER=on
+
+# AFS client configuration options:
+LARGE="-stat 2800 -dcache 2400 -daemons 5 -volumes 128"
+MEDIUM="-stat 2000 -dcache 800 -daemons 3 -volumes 70"
+SMALL="-stat 300 -dcache 100 -daemons 2 -volumes 50"
+OPTIONS=$MEDIUM
+
+# Set to "-verbose" for a lot of debugging information from afsd. Only
+# useful for debugging as it prints _a lot_ of information.
+VERBOSE=
+
+# AFSD_OPTIONS are the options passed to afsd.
+AFSD_OPTIONS="$OPTIONS $VERBOSE"
+
+
+# Sample server preferences function. Set server preferences using this.
+# afs_serverprefs() {
+#    /usr/afsws/etc/fs setserverprefs <host> <rank>
+#}
+
+# Either the name of an executable script or a set of commands go here.
+# AFS_POST_INIT=afs_serverprefs
+AFS_POST_INIT=
diff --git a/src/tools/install/afsinit_client b/src/tools/install/afsinit_client
new file mode 100644 (file)
index 0000000..a368504
--- /dev/null
@@ -0,0 +1,37 @@
+#! /bin/sh
+# Copyright 2000, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+
+# Configuration information for AFS client
+
+# AFS_CLIENT and AFS_SERVER determine if we should start the client and or
+# the bosserver. Possible values are on and off.
+AFS_CLIENT=on
+AFS_SERVER=off
+
+# AFS client configuration options:
+LARGE="-stat 2800 -dcache 2400 -daemons 5 -volumes 128"
+MEDIUM="-stat 2000 -dcache 800 -daemons 3 -volumes 70"
+SMALL="-stat 300 -dcache 100 -daemons 2 -volumes 50"
+OPTIONS=$MEDIUM
+
+# Set to "-verbose" for a lot of debugging information from afsd. Only
+# useful for debugging as it prints _a lot_ of information.
+VERBOSE=
+
+# AFSD_OPTIONS are the options passed to afsd.
+AFSD_OPTIONS="$OPTIONS $VERBOSE"
+
+
+# Sample server preferences function. Set server preferences using this.
+# afs_serverprefs() {
+#    /usr/afsws/etc/fs setserverprefs <host> <rank>
+#}
+
+# Either the name of an executable script or a set of commands go here.
+# AFS_POST_INIT=afs_serverprefs
+AFS_POST_INIT=
diff --git a/src/tools/install/afsinit_server b/src/tools/install/afsinit_server
new file mode 100644 (file)
index 0000000..f661b29
--- /dev/null
@@ -0,0 +1,37 @@
+#! /bin/sh
+# Copyright 2000, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+
+# Configuration information for AFS client
+
+# AFS_CLIENT and AFS_SERVER determine if we should start the client and or
+# the bosserver. Possible values are on and off.
+AFS_CLIENT=off
+AFS_SERVER=on
+
+# AFS client configuration options:
+LARGE="-stat 2800 -dcache 2400 -daemons 5 -volumes 128"
+MEDIUM="-stat 2000 -dcache 800 -daemons 3 -volumes 70"
+SMALL="-stat 300 -dcache 100 -daemons 2 -volumes 50"
+OPTIONS=$MEDIUM
+
+# Set to "-verbose" for a lot of debugging information from afsd. Only
+# useful for debugging as it prints _a lot_ of information.
+VERBOSE=
+
+# AFSD_OPTIONS are the options passed to afsd.
+AFSD_OPTIONS="$OPTIONS $VERBOSE"
+
+
+# Sample server preferences function. Set server preferences using this.
+# afs_serverprefs() {
+#    /usr/afsws/etc/fs setserverprefs <host> <rank>
+#}
+
+# Either the name of an executable script or a set of commands go here.
+# AFS_POST_INIT=afs_serverprefs
+AFS_POST_INIT=
diff --git a/src/tools/install/check_udebug.pl b/src/tools/install/check_udebug.pl
new file mode 100644 (file)
index 0000000..9e9305a
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+#
+# A perl script that checks to ensure the udebug output for a vlserver
+# claims that a quorum has been elected.
+#
+# openafs-tools, Version 1.2.2
+
+# Copyright 2002, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+#
+
+$serverName = $ARGV[0];
+
+$afscodeFileDir = "/usr/afs/tools/install/";
+$udebugOutput = $afscodeFileDir . "udebug.out.$$";
+
+$foundQuorum = 0;
+$recovery = 0;
+
+while( !($foundQuorum and $recovery) ) {
+
+    system( "/usr/afs/bin/udebug $serverName vlserver &> $udebugOutput" ) == 0
+       or (system( "rm -f $udebugOutput" ) == 0 
+           and die "check_udebug: the call to udebug (for server $serverName) failed or was killed\n");
+
+    open( UDEBUG, "<$udebugOutput");
+    @udebug = <UDEBUG>;
+    close(UDEBUG);
+
+    $newServerName = $serverName;
+
+    foreach $line (@udebug) {
+
+       # check the udebug output.  if this is the sync site, we've 
+       # found our quorum.  otherwise, if a last yes has been cast
+       # we'll check if that site is the sync site.  otherwise, if
+       # the last yes vote has not been cast, we'll keep on 
+       # checking this site until it is.
+       if( $line =~ m/^I am sync site(.*)/ ) {
+           $foundQuorum = 1;
+       } elsif( $line =~ m/^Last yes vote for ([^\s]*) .*/ ) {
+           $newServerName = $1;
+        } elsif( $line =~ m/^Recovery state (.*)\n$/ ) {
+           if( $1 != 0 ) {
+               $recovery = 1;
+           }
+       }
+       
+    }
+
+    # if this isn't the sync site, try somewhere else.
+    if( !$foundQuorum ) {
+       $serverName = $newServerName;
+    }
+
+}
+
+system( "rm -f $udebugOutput" );
+
+#return once we've found the sync site.
diff --git a/src/tools/install/install_afs b/src/tools/install/install_afs
new file mode 100644 (file)
index 0000000..a8bfa14
--- /dev/null
@@ -0,0 +1,686 @@
+#!/bin/sh
+#
+# A command line interface to execute the installation of OpenAFS.
+#
+# openafs-tools, Version 1.2.2
+
+# Copyright 2001, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+#
+
+afscodeDir=/usr/afs/tools/install/
+
+firstServer=1
+addServer=2
+notServer=3
+
+isClient=1
+notClient=2
+
+if [ $# -gt 0 ]; then 
+if [ $1 = "help" ]; then 
+
+  echo -e "OpenAFS Installation for Linux: Help Mode\n"
+  echo -e "The command install_afs takes the following optional arguments.  If any\nneeded information is not provided on the command line, it will be\nprompted for the user to input.\n"
+  echo -e "\t-machineName (or -m) name: where name specifies\n\t  the name of the machine the command is being run on"
+  echo -e "\t-cellName (or -c) cell: where cell specifies the\n\t  name of the home cell of this machine"
+  echo -e "\t-shortCell (or -s) scell: where scell is the shortcut\n\t   name desired for the home cell.  Ignored if this\n\t   is not the first server"
+  echo -e "\t-hardDrive (or -h) hd: where hd is the device name on\n\t   which to mount the first AFS partition.  Ignored if this\n\t   is not a server"
+  echo -e "\t-serverType (or -st) type: where type can be \"first\",\n\t   \"additional\", or \"not\", specifying whether this is\n\t   to be the first server in a cell, an additional server\n\t   for the cell, or not a server at all"
+  echo -e "\t-clientType (or -ct) type: where type can be \"client\"\n\t   or \"not\", specifying whether this machine is to be an\n\t   AFS client or not"
+  echo -e "\t-adminPassword (or -p) password: the administrative\n\t    password of the cell.  Ignored if this is not a server"
+  echo -e "\t-existingServer (or -e) name: the name of an\n\t   existing server already in the cell.  Ignored if\n\t   this is not an additional server"
+  echo -e "\t-scriptDirectory (or -d) name: the name of the\n\t   directory containing these OpenAFS installation\n\t   scripts"
+  echo -e "\t-noConf (or -n): Do not ask for confirmation before\n\t    performing the installation."
+  echo -e "\thelp: Display this help dialogue"
+  echo
+  exit 0
+
+fi fi
+
+# Check the state file to ensure AFS is not installed already
+if [ -r $afscodeDir/.afs_state ]; then
+  read state < $afscodeDir/.afs_state
+  if [ $state = "Install" ]; then
+    echo -e "You have already run the OpenAFS installation program.  You must uninstall OpenAFS before you install it again."
+    exit 0
+  fi
+fi
+
+while [ $# -gt 0 ]; do
+
+  flag=$1
+  if [ $# -ne 0 ]; then 
+    shift
+  fi
+  if [ $flag != "-noConf" -a $flag != "-n" ]; then
+    val=$1
+    if [ $# -ne 0 ]; then 
+      shift
+    fi
+  else 
+    val=1
+  fi
+
+  # if the value is empty
+  if [ -z $val ]; then
+    echo -e No value given to $flag flag.  Use \"install_afs help\" for syntax.
+    exit 0
+  fi
+  # if the value is a flag
+  if [ -z ${val##-*} ]; then
+    echo -e No value given to $flag flag.  Use \"install_afs help\" for syntax.
+    exit 0
+  fi
+
+  if [ $flag = "-machineName" -o $flag = "-m" ]; then
+     machineName=$val
+  else
+  if [ $flag = "-cellName" -o $flag = "-c" ]; then
+     cellName=$val
+  else
+  if [ $flag = "-shortCell" -o $flag = "-s" ]; then
+     shortCell=$val
+  else
+  if [ $flag = "-hardDrive" -o $flag = "-h" ]; then
+     hardDrive=$val
+  else
+  if [ $flag = "-scriptDirectory" -o $flag = "-d" ]; then
+     scriptDir=$val
+  else
+  if [ $flag = "-serverType" -o $flag = "-st" ]; then
+     server=$val
+     if [ $val = "first" ]; then
+       serverType=$firstServer
+     else if [ $val = "additional" ]; then
+       serverType=$addServer
+     else if [ $val = "not" ]; then
+       serverType=$notServer
+     else 
+       echo -e Invalid value for -serverType flag.  Use \"install_afs help\" for syntax.
+       exit 0;
+     fi fi fi
+      
+  else
+  if [ $flag = "-clientType" -o $flag = "-ct" ]; then
+     client=$val
+     if [ $val = "client" ]; then
+       clientType=$isClient
+     else if [ $val = "not" ]; then
+       clientType=$notClient
+     else 
+       echo -e Invalid value for $flag flag.  Use \"install_afs help\" for syntax.
+       exit 0;
+     fi fi
+      
+  else
+  if [ $flag = "-adminPassword" -o $flag = "-p" ]; then
+     adminPassword=$val
+  else 
+  if [ $flag = "-existingServer" -o $flag = "-e" ]; then
+     existingServer=$val
+  else
+  if [ $flag = "-noConf"  -o $flag = "-n" ]; then
+     noConf=$val
+  else
+    echo Invalid flag $flag.  Use \"install_afs help\" for syntax.
+    exit 0;
+  fi fi fi fi fi fi fi fi fi fi
+done
+
+# Collect variables not given:
+
+echo
+while [ -z $server ]; do
+  echo -ne "Provide the server type for this machine (\"first\", \"additional\", or \"not\"),\n   or hit enter to accept the default (\"first\"): "
+  read server
+
+  if [ -z $server ]; then
+    server="first"
+  fi
+
+  if [ $server = "first" ]; then
+    serverType=$firstServer
+  else if [ $server = "additional" ]; then
+    serverType=$addServer
+  else if [ $server = "not" ]; then
+    serverType=$notServer
+  else 
+    echo -e Invalid value for server type.  Please choose \"first\", \"additional\", or \"not\".
+    server=""
+  fi fi fi
+
+done
+
+while [ -z $client ]; do
+  echo -ne "Provide the client type for this machine (\"client\" or \"not\"), or hit enter to\n   accept the default (\"client\"): "
+  read client
+
+  if [ -z $client ]; then
+    client="client"
+  fi
+
+  if [ $client = "client" ]; then
+    clientType=$isClient
+  else if [ $client = "not" ]; then
+    clientType=$notClient
+  else 
+    echo -e Invalid value for client type.  Please choose \"client\" or \"not\".
+    client=""
+  fi fi
+
+done
+
+if [ $serverType -eq $notServer ]; then
+  if [ $clientType -eq $notClient ]; then
+     echo -e "This machine must be either a server or a client."
+     exit 0
+  fi
+fi
+
+while [ -z $cellName ]; do
+  echo -ne "Provide the name of the cell (in the form of cellname.domainname):\n   "
+  read cellName
+done
+
+while [ -z $machineName ]; do
+  read default < /etc/HOSTNAME
+  echo -ne "Provide the name of this machine, or hit enter to accept the\n   default ($default): "
+  read machineName
+
+  if [ -z $machineName ]; then
+    machineName=$default
+  fi
+
+done
+
+if [ $serverType -ne $notServer ]; then 
+    
+  while [ -z $hardDrive ]; do
+    echo -ne "Provide the name of the device on which to mount the AFS partition,\n   i.e. hda5: "
+    read hardDrive
+  done
+
+fi
+
+if [ $serverType -eq $firstServer ]; then 
+    
+  while [ -z $shortCell  ]; do
+    default=${cellName%%.*}
+    echo -ne "Provide a shortcut name for your cell, or press Enter to accept the\n   default ($default): "
+    read shortCell
+    if [ -z $shortCell ]; then
+      shortCell=$default
+    fi
+
+  done
+
+fi
+
+if [ $serverType -eq $addServer ]; then 
+    
+  while [ -z $existingServer ]; do
+    echo -ne "Provide the name of the first server in this cell:\n   "
+    read existingServer
+  done
+
+fi
+
+while [ -z $scriptDir ]; do
+  default=$afscodeDir
+  echo -ne "Provide the directory of this installation script, or press Enter to accept\n   the default ($default): "
+  read scriptDir
+
+  if [ -z $scriptDir ]; then
+    scriptDir=$default
+  fi
+
+done
+
+if [ $serverType -ne $notServer ]; then 
+  while [ -z $adminPassword ]; do
+    echo -ne "Provide the administrative password of this cell: "
+    stty -echo echonl
+    read adminPassword
+    stty echo
+    echo -ne "Please confirm the password: "
+    stty -echo echonl
+    read adminPassword2
+    stty echo
+
+    if [ -z $adminPassword ]; then
+      echo -e "You must give a password"
+    else 
+    if [ -z $adminPassword2 ]; then
+      echo -e "You must confirm the password"
+      adminPassword=""
+    else
+    if [ $adminPassword != $adminPassword2 ]; then
+      echo -e "Passwords do not match"
+      adminPassword=""
+    fi fi fi
+  done
+fi
+
+# Make sure the needed files exist:
+if [ $serverType -eq $addServer ]; then
+  while [ ! -e $scriptDir/afs/ -o ! -e $scriptDir/afs/ThisCell -o ! -e $scriptDir/afs/CellServDB -o ! -e $scriptDir/afs/KeyFile -o  ! -e $scriptDir/afs/UserList ]; do
+    echo -e "Needed files in $scriptDir/afs do not exist."
+    echo -e "Copy the following files from $existingServer to the specified locations:"
+    echo -e "- $existingServer:/usr/afs/etc/ThisCell to $machineName:$scriptDir/afs/ThisCell"
+    echo -e "- $existingServer:/usr/afs/etc/CellServDB to $machineName:$scriptDir/afs/CellServDB"
+    echo -e "- $existingServer:/usr/afs/etc/KeyFile to $machineName:$scriptDir/afs/KeyFile"
+    echo -e "- $existingServer:/usr/afs/etc/UserList to $machineName:$scriptDir/afs/UserList"
+    echo -e "- $existingServer:/usr/vice/etc/CellServDB to $machineName:$scriptDir/vice/CellServDB"
+    echo -e "Press Enter when ready"
+    read anykey
+  done
+fi
+if [ $serverType -ne $firstServer ]; then
+  while [ ! -e $scriptDir/vice/ -o  ! -e $scriptDir/vice/CellServDB ]; do
+    echo "Needed file in $scriptDir/vice does not exist."
+    echo -e "Copy the following file from an existing server to the specified location:"
+    echo -e "- CellServDB from $cellName to $machineName:$scriptDir/vice/CellServDB"
+    echo -e "Press Enter when ready"
+    read anykey
+  done
+fi
+echo
+echo -e "You're about to install OpenAFS with the following configuration:"
+echo -e "Machine name: $machineName"
+echo -e "Cell name: $cellName"
+if [ $serverType -eq $firstServer ]; then
+  echo -e "Shortcut cell name: $shortCell"
+fi
+if [ $serverType -ne $notServer ]; then
+  echo -e "Hard drive: $hardDrive"
+  echo -ne "adminPassword: "
+  i=0;
+  while [ $i -lt ${#adminPassword} ]; do
+    echo -ne "*"
+    i=$[i+1]
+  done
+  echo
+fi
+echo -e "Server: $server"
+echo -e "Client: $client"
+if [ $serverType -eq $addServer ]; then
+  echo -e "Existing server: $existingServer"
+fi
+echo -e "Script directory: $scriptDir"
+echo
+if [ -z $noConf ]; then
+  echo -ne "Would you like to continue with the installation? "
+  while [ -z $goAhead ]; do
+    echo -ne "(y/n): "
+    read goAhead
+
+    if [ -z $goAhead ]; then
+      :
+    else 
+    if [ $goAhead = "n" ]; then
+      echo -e "Aborting installation"
+      exit 0
+    else
+    if [ $goAhead != "y" ]; then
+      goAhead=""
+    fi fi fi
+
+  done
+fi
+
+#Start the installation
+
+# the directory on which the hard drive partition will be mounted:
+partition=/vicepa
+#
+#
+# the password for the afs account:
+afsPassword=$adminPassword
+#
+# Make sure the needed files exist:
+if [ $serverType -eq $addServer ]; then
+  if [ ! -e $scriptDir/afs/ ]; then
+    echo "Needed directory $scriptDir/afs does not exist.  Aborting."
+    exit 1
+  fi
+  if [ ! -e $scriptDir/afs/ThisCell ]; then
+    echo "Needed file $scriptDir/afs/ThisCell does not exist.  Aborting."
+    exit 1
+  fi
+  if [ ! -e $scriptDir/afs/CellServDB ]; then
+    echo "Needed file $scriptDir/afs/CellServDB does not exist.  Aborting."
+    exit 1
+  fi
+  if [ ! -e $scriptDir/afs/KeyFile ]; then
+    echo "Needed file $scriptDir/afs/KeyFile does not exist.  Aborting."
+    exit 1
+  fi
+  if [ ! -e $scriptDir/afs/UserList ]; then
+    echo "Needed file $scriptDir/afs/UserList does not exist.  Aborting."
+    exit 1
+  fi
+fi
+if [ $serverType -ne $firstServer ]; then
+  if [ ! -e $scriptDir/vice/ ]; then
+    echo "Needed directory $scriptDir/vice does not exist.  Aborting."
+    exit 1
+  fi
+  if [ ! -e $scriptDir/vice/CellServDB ]; then
+    echo "Needed file $scriptDir/vice/CellServDB does not exist.  Aborting."
+    exit 1
+  fi
+fi
+# Write to the state file
+echo "Install" > $scriptDir/.afs_state
+echo "begin" >> $scriptDir/.afs_state
+#
+#
+#
+if [ $clientType -eq $isClient ]; then
+  echo Configuring /etc/pam.d/login
+  perl $scriptDir/write_pam.pl enable
+  cd /lib/security 
+  echo ln -s pam_afs.so.1 pam_afs.so
+  ln -s pam_afs.so.1 pam_afs.so
+fi
+#
+# Remove files installed by OpenAFS rpms that are intrusive
+echo "Removing troublesome files"
+rm -f /usr/vice/etc/ThisCell
+rm -f /usr/vice/etc/CellServDB
+#
+if [ $serverType -ne $notServer ]; then 
+  mkdir $partition
+  echo Configuring /etc/fstab 
+  perl $scriptDir/write_fstab.pl $hardDrive $partition
+  mount -a
+#
+#
+  echo Starting the BOS server
+  mkdir -p /usr/afs/etc
+  if [ $serverType -eq $addServer ]; then
+    # Move the needed file to /usr/afs/etc
+    echo Copying /usr/afs/etc/ files for additional server
+    cp -f $scriptDir/afs/ThisCell /usr/afs/etc/
+    cp -f $scriptDir/afs/CellServDB /usr/afs/etc/
+    cp -f $scriptDir/afs/KeyFile /usr/afs/etc/
+    cp -f $scriptDir/afs/UserList /usr/afs/etc/
+  fi     
+#
+  if [ $serverType -eq $firstServer ]; then
+
+    echo /usr/afs/bin/bosserver -noauth
+    /usr/afs/bin/bosserver -noauth
+    echo bos setcellname $machineName $cellName -noauth
+    bos setcellname $machineName $cellName -noauth
+    echo bos listhosts $machineName -noauth
+    bos listhosts $machineName -noauth
+    echo bos addkey $machineName -key $afsPassword -kvno 0 -cell $cellName -noauth
+    bos addkey $machineName -key $afsPassword -kvno 0 -cell $cellName -noauth
+    
+    echo bos shutdown $machineName -noauth
+    bos shutdown $machineName -noauth
+    bosserver_process=$(ps -Ao pid,cmd | grep boss)
+    echo kill ${bosserver_process%% /*}
+    kill ${bosserver_process%% /*}
+
+    /usr/afs/bin/kaserver -noauth &
+    echo Configuring kaserver
+    kas create afs -initial_password $afsPassword -cell $cellName -noauth
+    kas examine -name afs -cell $cellName -noauth
+    kas create admin -initial_password $adminPassword -cell $cellName -noauth
+    kas setfields admin -flags admin -cell $cellName -noauth
+    kas examine -name admin -cell $cellName -noauth
+    
+    kaserver_process=$(ps -Ao pid,cmd | grep kaserver)
+    echo kill ${kaserver_process%% /*}
+    kill ${kaserver_process%% /*}
+
+    echo Bootstrapping ptserver
+    echo -e "admin 128/20 1 -204 -204\nsystem:administrators 130/20 -204 -204 -204\n   admin   1\n" | pt_util -p /usr/afs/db/prdb.DB0 -w
+
+  fi
+
+  /usr/afs/bin/bosserver
+
+  if [ $serverType -ne $firstServer ]; then
+    # Define the upclients
+    echo bos create $machineName upclientetc simple "/usr/afs/bin/upclient $existingServer /usr/afs/etc" -cell $cellName -localauth
+    bos create $machineName upclientetc simple "/usr/afs/bin/upclient $existingServer /usr/afs/etc" -cell $cellName -localauth
+    echo bos create $machineName upclientbin simple "/usr/afs/bin/upclient $existingServer -clear /usr/afs/bin" -cell $cellName -localauth
+    bos create $machineName upclientbin simple "/usr/afs/bin/upclient $existingServer -clear /usr/afs/bin" -cell $cellName -localauth
+  fi
+fi
+#
+#
+if [ $serverType -eq $firstServer ]; then
+#
+  echo Starting the Database Server Processes
+#
+  echo bos create -server $machineName -instance kaserver -type simple -cmd /usr/afs/bin/kaserver -cell $cellName -localauth
+  bos create -server $machineName -instance kaserver -type simple -cmd /usr/afs/bin/kaserver -cell $cellName -localauth
+  echo bos create -server $machineName -instance buserver -type simple -cmd /usr/afs/bin/buserver -cell $cellName -localauth
+  bos create -server $machineName -instance buserver -type simple -cmd /usr/afs/bin/buserver -cell $cellName -localauth
+  echo bos create -server $machineName -instance ptserver -type simple -cmd /usr/afs/bin/ptserver -cell $cellName -localauth
+  bos create -server $machineName -instance ptserver -type simple -cmd /usr/afs/bin/ptserver -cell $cellName -localauth
+  echo bos create -server $machineName -instance vlserver -type simple -cmd /usr/afs/bin/vlserver -cell $cellName -localauth
+  bos create -server $machineName -instance vlserver -type simple -cmd /usr/afs/bin/vlserver -cell $cellName -localauth
+#
+  echo bos adduser $machineName admin -cell $cellName -localauth
+  bos adduser $machineName admin -cell $cellName -localauth
+  echo bos restart $machineName -all -cell $cellName -localauth
+  bos restart $machineName -all -cell $cellName -localauth
+#
+fi
+#
+if [ $serverType -ne $notServer ]; then
+  echo Starting the File Server, Volume Server, and Salvager
+#
+  echo bos create $machineName fs fs /usr/afs/bin/fileserver /usr/afs/bin/volserver /usr/afs/bin/salvager -cell $cellName -localauth
+  bos create $machineName fs fs /usr/afs/bin/fileserver /usr/afs/bin/volserver /usr/afs/bin/salvager -cell $cellName -localauth
+# Verify success of fs:
+  echo bos status $machineName fs -long -localauth
+  bos status $machineName fs -long -localauth
+#
+  if [ $serverType -eq $firstServer ]; then
+    # Wait for Ubik to elect a quorum
+    echo Waiting for a quorum election . . .
+    perl $scriptDir/check_udebug.pl $machineName
+    echo vos create $machineName $partition root.afs -cell $cellName -localauth 
+    vos create $machineName $partition root.afs -cell $cellName -localauth
+#
+  else 
+    vos syncvldb $machineName -cell $cellName -verbose -localauth
+    vos syncserv $machineName -cell $cellName -verbose -localauth
+  fi
+fi
+#
+if [ $serverType -eq $firstServer ]; then
+  echo Starting the Server Portion of the Update Server
+#
+  echo bos create $machineName upserver simple "/usr/afs/bin/upserver -crypt /usr/afs/etc -clear /usr/afs/bin" -cell $cellName -localauth
+  bos create $machineName upserver simple "/usr/afs/bin/upserver -crypt /usr/afs/etc -clear /usr/afs/bin" -cell $cellName -localauth
+#
+#
+fi
+#
+# Installing Client Functionality
+#
+echo Defining Cell Membership for Client Processes
+#
+if [ $serverType -eq $notServer ]; then
+  echo $cellName > /usr/vice/etc/ThisCell
+fi
+#
+echo Creating the Client CellServDB File
+
+cd /usr/vice/etc
+if [ $serverType -ne $firstServer ]; then
+    # Move the CellServDB file to /usr/vice/etc
+    cp -f $scriptDir/vice/CellServDB /usr/vice/etc
+fi
+#
+# copy correct afs setup file to etc/sysconfig
+if [ $serverType -eq $notServer ]; then
+  cp -f $scriptDir/afsinit_client /etc/sysconfig/afs
+else
+  cp -f $scriptDir/afsinit_both /etc/sysconfig/afs
+fi
+#
+# Overview: Completing the Installation of the First AFS Machine
+#
+echo Verifying the AFS Initialization Script
+#
+if [ $serverType -ne $notServer ]; then
+  echo bos shutdown $machineName -localauth
+  bos shutdown $machineName -localauth
+  bosserver_process=$(ps -Ao pid,cmd | grep boss)
+  echo kill ${bosserver_process%% /*}
+  kill ${bosserver_process%% /*}
+fi
+
+#
+echo Continuing with Verifying ths AFS Initialization Script
+#
+echo /etc/rc.d/init.d/afs start
+/etc/rc.d/init.d/afs start
+if [ $serverType -ne $notServer ]; then
+  # klog in as admin
+  echo klog admin -password 
+  klog admin -password $adminPassword
+  # verify klog worked correctly:
+  echo tokens
+  tokens
+  # verify each process is running normally:
+  echo bos status $machineName
+  bos status $machineName
+  cd /
+  echo fs checkvolumes
+  fs checkvolumes
+fi
+#
+echo Activating the AFS Initialization Script
+#
+echo /sbin/chkconfig --add afs
+/sbin/chkconfig --add afs
+cd /usr/vice/etc
+rm afs.rc afs.conf
+ln -s /etc/rc.d/init.d/afs afs.rc
+ln -s /etc/sysconfig/afs afs.conf
+#
+if [ $serverType -eq $firstServer ]; then
+  echo Configuring the Top Levels of the AFS Filespace
+#
+  # Wait for Ubik to elect a quorum
+  echo Waiting for a quorum election . . .
+  perl $scriptDir/check_udebug.pl $machineName
+  
+  echo fs setacl /afs system:anyuser rl
+  fs setacl /afs -acl system:anyuser rl
+  echo vos create $machineName $partition root.cell
+  vos create $machineName $partition root.cell
+  echo fs mkmount /afs/$cellName root.cell
+  fs mkmount /afs/$cellName root.cell
+  echo fs setacl /afs/$cellName system:anyuser rl
+  fs setacl /afs/$cellName -acl system:anyuser rl
+  cd /afs
+  ln -s $cellName $shortCell
+  echo fs mkmount /afs/.$cellName root.cell -rw
+  fs mkmount /afs/.$cellName root.cell -rw
+
+# stop the client
+  echo Stopping the client to replicate
+  cd /
+  umount /afs
+  /usr/vice/etc/afsd -shutdown
+  
+  echo vos addsite $machineName $partition root.afs -localauth
+  vos addsite $machineName $partition root.afs -localauth
+  echo vos addsite $machineName $partition root.cell -localauth
+  vos addsite $machineName $partition root.cell -localauth
+  echo vos release root.afs -localauth
+  vos release root.afs -localauth
+  echo vos release root.cell -localauth
+  vos release root.cell -localauth
+
+  /etc/rc.d/init.d/afs stop
+  # start the client again
+  echo Starting client again
+  /etc/rc.d/init.d/afs start
+  cd /afs
+
+  # klog in as admin
+  echo klog admin -password 
+  klog admin -password $adminPassword
+
+  # Wait for Ubik to elect a quorum
+  echo Waiting for a quorum election . . .
+  perl $scriptDir/check_udebug.pl $machineName
+  
+  echo fs examine /afs
+  fs examine /afs
+  echo fs examine /afs/$cellName
+  fs examine /afs/$cellName
+
+#
+#
+fi
+fs checkvolumes
+#
+if [ $clientType -ne $isClient ]; then
+#
+  echo Removing Client Functionality
+#
+  # Install correct config file  
+  cp -f $scriptDir/afsinit_server /etc/sysconfig/afs
+#
+  cd /usr/vice/etc
+  ln -fs /usr/afs/etc/ThisCell ThisCell
+  ln -fs /usr/afs/etc/CellServDB CellServDB
+#
+  /etc/rc.d/init.d/afs stop
+  /etc/rc.d/init.d/afs start
+#
+fi
+# remove the tokens
+unlog
+#
+# Write the done file
+echo "Here is a summary of what was done:<br><ul>" > $scriptDir/done.txt
+if [ $serverType -eq $firstServer ]; then 
+  echo "<li>Configured $machineName as the first server to the cell $cellName</li>" >> $scriptDir/done.txt
+  echo "<li>Created the server processes (vlserver, buserver, kaserver, and ptserver)</li>" >> $scriptDir/done.txt
+  echo "<li>Created /vicepa as a server partition</li>" >> $scriptDir/done.txt
+  echo "<li>Created an admin account</li>" >> $scriptDir/done.txt
+  echo "<li>Mounted a read-write version of root.cell at /afs/.$cellName</li>" >> $scriptDir/done.txt
+fi
+if [ $serverType -eq $addServer ]; then 
+  echo "<li>Configured $machineName as an additional server to the cell $cellName</li>" >> $scriptDir/done.txt
+  echo "<li>Created the update processes, using $existingServer as the first server</li>" >> $scriptDir/done.txt
+  echo "<li>Created /vicepa as a server partition</li>" >> $scriptDir/done.txt
+fi
+if [ $clientType -eq $isClient ]; then 
+  echo "<li>Configured $machineName as a client to the cell $cellName</li>" >> $scriptDir/done.txt
+fi
+  echo "</ul><br>" >> $scriptDir/done.txt
+if [ $serverType -eq $firstServer ]; then 
+  echo "<br>Here are some suggestions about how to get started using your cell:<br><ul>" >> $scriptDir/done.txt
+  echo "<li>Read the <a href=\"http://oss.software.ibm.com/developerworks/opensource/afs/docs.html\">OpenAFS documentation</a></li>" >> $scriptDir/done.txt
+  echo "<li>Create users for your cell</li>" >> $scriptDir/done.txt
+  echo "<li>Create volumes</li>" >> $scriptDir/done.txt
+  echo "<li>Configure other machines to be additional servers for this cell</li>" >> $scriptDir/done.txt
+  echo "<li>Make another partition (i.e. /vicepb) on which to store volumes</li>" >> $scriptDir/done.txt
+  echo "<li>Mount other cells in root.afs</li>" >> $scriptDir/done.txt
+  echo "</ul>" >> $scriptDir/done.txt
+fi
+# Write the state file
+echo "Install" > $scriptDir/.afs_state
+echo "complete" >> $scriptDir/.afs_state
+#
diff --git a/src/tools/install/make_rpm_source b/src/tools/install/make_rpm_source
new file mode 100644 (file)
index 0000000..c138e6f
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# Copyright 2001, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+#
+# packup
+# creates rpm source file containing all the necessary files
+# for the OpenAFS command line tools.  Moves to RPM source dir.
+# 
+# openafs-tools, Version 1.2.2
+#
+# Directory containing installation scripts, etc.
+rootDir=../..
+mainFileDir=..
+rpmSource=/usr/src/redhat/SOURCES/
+#
+mkdir .tmpTarDir
+cd .tmpTarDir
+#
+cp $rootDir/openafs-tools-cmd.README .
+cp $mainFileDir/.afs_state afs_state
+cp $mainFileDir/afsinit_both .
+cp $mainFileDir/afsinit_client .
+cp $mainFileDir/afsinit_server .
+cp $mainFileDir/afs_uninstall .
+cp $mainFileDir/install_afs .
+cp $mainFileDir/write_fstab.pl .
+cp $mainFileDir/write_pam.pl .
+#
+cp $mainFileDir/unpack_cmd .
+#
+tar -cf afs_linux.tar *
+gzip -f afs_linux.tar
+cd ..
+cp .tmpTarDir/afs_linux.tar.gz .
+rm -rf .tmpTarDir
+#
+tar -cf openafs-tools-cmd.tar afs_linux.tar.gz
+rm -f afs_linux.tar.gz
+mv openafs-tools-cmd.tar $rpmSource
+chown nobody $rpmSource/openafs-tools-cmd.tar
+#
+
diff --git a/src/tools/install/openafs-tools-cmd-1.2.2-1.spec b/src/tools/install/openafs-tools-cmd-1.2.2-1.spec
new file mode 100644 (file)
index 0000000..a3ffe7e
--- /dev/null
@@ -0,0 +1,71 @@
+Summary: A program that can install and uninstall OpenAFS for Linux (command line only).
+Name: openafs-tools-cmd
+Version: 1.2.2
+Release: 1
+Copyright: IPL
+Packager: OpenAFS
+Group: Applications/File
+Source: openafs-tools-cmd.tar
+Conflicts: openafs-tools
+Requires: openafs, openafs-kernel, openafs-client, openafs-server
+BuildRoot: /var/tmp/%{name}-buildroot
+
+%description
+This rpm will extract and install the files needed to install and uninstall
+OpenAFS on a Linux system. 
+
+%prep
+%setup -c
+gunzip afs_linux.tar.gz
+tar -xf afs_linux.tar
+
+%build
+chmod 744 unpack_cmd
+
+%install
+rm -rf $RPM_BUILD_ROOT
+./unpack_cmd
+
+%post
+%ifnos Linux
+  echo -e "WARNING: Operating system is not Linux.\n  openafs-tools has only been tested on Red Hat Linux, so proceed with caution."
+%endif
+if [ ! -e /usr/src/redhat ]; then
+  echo -e "WARNING: This operating system may not be Red Hat Linux.\nopenafs-tools has only been tested on Red Hat, so proceed with caution."
+fi
+%ifos Linux
+  ver=$(uname -r) 
+  verdash=${ver%%-*}
+  vermaj=${verdash%.*}
+  vermin=${verdash##*.}
+  if [ $vermaj != "2.2" -a $vermaj != "2.4" ]; then 
+    echo -e "WARNING: Kernel version is not 2.2 or 2.4.\n openafs-tools-client has only been tested on kernel versions 2.2 and 2.4, so proceed with caution."
+  fi
+%endif
+
+%preun
+rm -f /usr/afs/tools/install/*install_output*
+rm -rf /usr/afs/tools/install/afs
+rm -rf /usr/afs/tools/install/vice
+rm -rf /usr/afs/tools/install/done.txt
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%doc openafs-tools-cmd.README
+/usr/afs/tools/openafs-tools-cmd.README
+/usr/afs/tools/install/.afs_state
+/usr/afs/tools/install/afsinit_both
+/usr/afs/tools/install/afsinit_client
+/usr/afs/tools/install/afsinit_server
+/usr/afs/tools/install/afs_uninstall
+/usr/afs/tools/install/install_afs
+/usr/afs/tools/install/check_udebug.pl
+/usr/afs/tools/install/write_fstab.pl
+/usr/afs/tools/install/write_pam.pl
+%dir /usr/afs/tools/install/
+
+
+
+
diff --git a/src/tools/install/unpack_cmd b/src/tools/install/unpack_cmd
new file mode 100644 (file)
index 0000000..6a11181
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# unpack
+# unpacks some of the necessary files for the OpenAFS command line tools.
+# 
+# openafs-tools, Version 1.2.2
+#
+# Copyright 2001, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+#
+# Directory to put all installation scripts, etc.
+buildRoot=/var/tmp/openafs-tools-cmd-buildroot
+rootDir=$buildRoot/usr/afs/tools
+mainFileDir=$rootDir/install
+#
+mkdir -p $mainFileDir/
+#
+cp openafs-tools-cmd.README $rootDir/ 
+cp -f afs_state $mainFileDir/.afs_state
+cp -f afsinit_both $mainFileDir/
+cp -f afsinit_client $mainFileDir/
+cp -f afsinit_server $mainFileDir/
+cp -f afs_uninstall $mainFileDir/
+cp -f install_afs $mainFileDir/
+cp -f check_udebug.pl $mainFileDir/
+cp -f write_fstab.pl $mainFileDir/
+cp -f write_pam.pl $mainFileDir/
+#
+chmod 600 $mainFileDir/.afs_state
+chmod 744 $mainFileDir/afs_uninstall
+chmod 744 $mainFileDir/install_afs
+chmod a+w $mainFileDir
+#
+
+
+
+
diff --git a/src/tools/install/write_fstab.pl b/src/tools/install/write_fstab.pl
new file mode 100644 (file)
index 0000000..258c746
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+#
+# A perl script that will replace the line in /etc/fstab
+# corresponding to the device given by the first argument,
+# with a new line mounting that device to the second
+# argument, or add it if necessary.
+#
+# openafs-tools, Version 1.2.2
+
+# Copyright 2001, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+#
+
+open( FSTAB, "</etc/fstab");
+@fstab = <FSTAB>;
+close(FSTAB);
+
+open( FSTAB, ">/etc/fstab");
+
+$replaced = 0;
+
+foreach $line (@fstab) {
+  @splitline = split(/\s+/, $line);
+  if( $splitline[0] eq "/dev/$ARGV[0]" ) {
+      print FSTAB "/dev/$ARGV[0]\t\t$ARGV[1]\t\t\text2\tdefaults     0  2\n";
+      $replaced = 1;
+  } else {
+      print FSTAB $line;
+  }
+}
+
+if( $replaced == 0 ) {
+    print FSTAB "/dev/$ARGV[0]\t\t$ARGV[1]\t\t\text2\tdefaults     0  2\n";
+}
diff --git a/src/tools/install/write_pam.pl b/src/tools/install/write_pam.pl
new file mode 100644 (file)
index 0000000..8f00c13
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+#
+# A perl script that will enable or disable
+# AFS login on a machine, depending on the
+# first argument to the script.
+#
+# openafs-tools, Version 1.2.2
+
+# Copyright 2001, International Business Machines Corporation and others.
+# All Rights Reserved.
+# 
+# This software has been released under the terms of the IBM Public
+# License.  For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+#
+
+open( LOGIN, "</etc/pam.d/login");
+@login = <LOGIN>;
+close(LOGIN);
+
+open( LOGIN, ">/etc/pam.d/login");
+
+if( $ARGV[0] eq "enable" ) {
+
+    $enabled == 0;
+    
+    foreach $line (@login) {
+       @splitline = split( /\s+/, $line);
+       # only enable if: it's directly before the pwdb line (without the "shadow nullock",
+        #                 it hasn't been enabled yet in this script
+       if( $splitline[2] eq "/lib/security/pam_pwdb.so" && $splitline[3] eq ""  && $enabled == 0 ) {
+           print LOGIN "auth\t   sufficient\t/lib/security/pam_afs.so try_first_pass ignore_root\n";
+           $enabled = 1;
+       } 
+       # If you encounter the line, turn enabled on
+        if( $splitline[2] eq "/lib/scurity/pam_afs.so" ) {
+           $enabled = 1;
+        }    
+       print LOGIN $line;
+    }
+
+} else {
+
+    foreach $line (@login) {
+       @splitline = split( /\s+/, $line);
+       if( $splitline[2] ne "/lib/security/pam_afs.so" ) {
+           print LOGIN $line;
+       }
+       
+    }
+
+}
+
+
diff --git a/src/tools/openafs-tools-cmd.README b/src/tools/openafs-tools-cmd.README
new file mode 100644 (file)
index 0000000..8c87c68
--- /dev/null
@@ -0,0 +1,232 @@
+## OpenAFS Tools Documentation ##
+## A collection of open source programs and interfaces designed ##
+## to ease the configuration and maintenance of OpenAFS. ##
+##
+## Copyright 2001, International Business Machines Corporation and others.
+## All Rights Reserved.
+## 
+## This software has been released under the terms of the IBM Public
+## License.  For details, see the LICENSE file in the top-level source
+## directory or online at http://www.openafs.org/dl/license10.html
+##
+## openafs-tools, Version 1.2.2 ##
+
+####################### TABLE OF CONTENTS ###########################
+
+1) Overview
+2) System configuration requirements
+ a) OS
+ b) OpenAFS
+ c) OpenAFS Tools
+3) Usage
+ a) OpenAFS Installation
+ b) OpenAFS Uninstallation 
+4) Implementation
+ a) OpenAFS Installation
+ b) OpenAFS Uninstallation
+5) Known Problems
+6) Future Expansion
+
+######################## 1) OVERVIEW ################################
+
+    The Tools use shell and Perl scripts.  So far, they has been tested 
+only on Red Hat Linux 6.2 and 7.1 machines, running kernels 2.2 or 2.4. 
+    As of this version, OpenAFS Tools has two functions: 
+installing OpenAFS, and uninstalling OpenAFS.  
+    We hope that you enjoy using and developing these tools, and
+that they enhance the popularity and use of OpenAFS.  If you have
+any questions, comments or suggestions, please send them to the
+OpenAFS mailing lists.  
+
+############# 2) SYSTEM CONFIGURATION REQUIREMENTS ##################
+
+a) OS
+    OpenAFS Tools has been developed and tested on machines running 
+Red Hat Linux 6.2 and 7.1, with kernel version 2.2 or 2.4.  It may 
+or may not run well on other versions of Linux or other kernel 
+versions -- use caution when using them with other setups.  
+
+b) OpenAFS
+    Finally, you need to download and install the OpenAFS 1.2.2 RPMs 
+for Red Hat Linux from http://www.openafs.org.  The files you need 
+are:
+    Red Hat 6.2:
+      openafs-kernel-1.2.2-rh6.2.1.i386.rpm
+      openafs-1.2.2-rh6.2.1.i386.rpm 
+      openafs-client-1.2.2-rh6.2.1.i386.rpm 
+      openafs-server-1.2.2-rh6.2.1.i386.rpm
+    Red Hat 7.1:
+      openafs-kernel-1.2.2-rh7.1.1.i386.rpm
+      openafs-1.2.2-rh7.11..i386.rpm 
+      openafs-client-1.2.2-rh7.1.1.i386.rpm 
+      openafs-server-1.2.2-rh7.1.1.i386.rpm
+Once these are downloaded, install them (using an rpm -i or rpm -U
+command).
+
+c) OpenAFS Tools
+    Now all that's left to do is install the OpenAFS Tools rpm.  The
+file you need is openafs-tools-1.1.1-1.i386.rpm.  Install it using 
+an rpm -i or rpm -U command.  This will create several directories
+and populate your system with necessary files.  The main directories
+created and populated is:
+    /usr/afs/tools/install/
+Now you should be ready to get started.
+
+########################## 3) USAGE #################################
+
+a) OpenAFS Installation
+
+    Execute the /usr/afs/tools/install/install_afs command.
+It can take a variety of arguments to specify how you would like
+to set the machine up.  If you do not specify needed arguments
+on the command line, you will be prompted for them interactively.
+To get a rundown on how to use install_afs, execute:
+  /usr/afs/tools/install/install_afs help
+Once configured correctly, this machine will run the installation 
+program (the same one run by the web interface), and restart your
+computer.
+
+b) OpenAFS Uninstallation 
+
+    The uninstallation program is very simple.  Just run
+  /usr/afs/tools/install/afs_uninstall
+It does not accept any arguments and will not prompt you for
+anything.  Be forewarned, however: this will uninstall OpenAFS from
+your system and delete any information served from that machine in
+OpenAFS filespace.  You should also restart your machine after
+running the command, to avoid potential problems with future OpenAFS
+installations.
+
+##################### 4) IMPLEMENTATION #############################
+
+    This section will focus on the details of the implementation of
+OpenAFS tools.  It will outline the code and file structure of the
+package, and will document the choices made during implementation, so
+that someone working on the code can have a better understanding for
+what's there already.
+
+a) OpenAFS Installation
+
+    The files involved in OpenAFS installation are:
+
+  - Possible AFS configuration files (/etc/sysconfig/afs):
+    /usr/afs/tools/install/afsinit_both
+    /usr/afs/tools/install/afsinit_server
+    /usr/afs/tools/install/afsinit_client
+  - Checking the state of OpenAFS on the system:
+    /usr/afs/tools/install/.afs_state
+  - Command line installation:
+    /usr/afs/tools/install/install_afs
+  - Perl scripts:
+    /usr/afs/tools/install/check_udebug.pl
+    /usr/afs/tools/install/write_fstab.pl
+    /usr/afs/tools/install/write_pam.pl
+
+What follows is a brief summary of the installation process.
+  - Installation starts with the script install_afs.  The first thing
+it does is ensure that the files needed for setting up additional 
+servers and/or clients exist in the appropriate places (see section 
+3.a.i for a description of these files).  Then, after indicating to 
+the state file that installation has begun, it begins installing 
+OpenAFS.
+  - For clients, it then enables Pam Login Authentication using
+the write_pam.pl program to change the /etc/pam.d/login file.
+  - For servers, it will alter the /etc/fstab file via the 
+write_fstab.pl program, mounting the user-specified hard drive to
+the /vicepa directory.
+  - For additional servers, it now copies the required
+files from the /usr/afs/tools/install/afs directory to the
+/usr/afs/etc directory, and defines the upclient processes,
+which will periodically update the server's /usr/afs/bin and
+/usr/afs/etc directories based on those directories on the first
+server in the cell.
+  - A first server must then briefly start up a bosserver with
+the noauth flag in order to create the keyfile and set the cell 
+name.  It immediately shuts down the bosserver when this is down.
+Next, it uses a kaserver with noauth to initialize cell security.
+This involves creating two user accounts: afs and admin.  afs is an
+account for the server processes and will not be needed by the user.
+Currently we use the administrative password for the afs account
+password.  The admin account is now added to the bos server database
+and a pts entry is created as well.  Also, the afs account password
+is added as a key for the server. The kaserver proces is terminated.  
+The pts database is then bootstrapped to add the administrator to it.  
+  - For first servers, a normal bosserver is started.  It then 
+creates the database server processes (kaserver, buserver, ptserver, 
+and vlserver).  
+  - The file server, volume server, and salvager processes are now 
+started for servers.  
+  - Next the root.afs volume is created for first servers, and on
+additional servers the vldb is synced up.
+  - On a first server, the upserver process is then defined.
+  - Next the /usr/vice/etc/ThisCell file is created on a non-server
+machine, and for non-first-servers the /usr/vice/etc/CellServDB file
+is copied from its location at /usr/afs/tools/install/vice.
+  - The correct AFS setup file is copied to /etc/sysconfig/.
+  - Now the bosserver process is killed for server machines.  
+  - The next thing it does is initialize afs (/etc/rc.d/init.d/afs), 
+and for servers it klogs in as admin.
+  - Then it activates the OpenAFS initialization script by running
+/sbin/chkconfig --add afs.  
+  - Next a first server will configure the OpenAFS file space. 
+Before doing this, however, it must first wait until a quorum has 
+been elected.  After the check, the root.cell volume is created, 
+it is mounted at /afs/<cell_name>, and the permissions are set 
+on both it and /afs as read and lookup for any user.  A read-write 
+version of root.cell is mounted at /afs/.<cell_name>.  Replication 
+sites for both root.afs and root.cell are added.
+  - If necessary, client functionality is removed.
+  - Lastly, a done.txt file is written explaining what has been done
+and what comes next, for use by the web interface.  The state file
+is notified that installation is complete, and then the script ends.
+
+b) OpenAFS Uninstallation
+
+    Uninstallation has only two files: the main script and the 
+redirection script.
+  /usr/afs/tools/install/afs_uninstall
+Here is a brief summary of what it does to uninstall OpenAFS:
+  - First it indicates to the state file that uninstallation has 
+begun.
+  - Then it kills whatever bos server processes may be running.  
+  - Next, it deletes everything stored in an AFS partition directory
+( i.e. vicep*).
+  - It deletes the links to any initialization scripts in the startup 
+directories (/etc/rc.d/rc*.d/*afs*)
+  - It removes the PAM afs file, and reconfigures the PAM login file
+to not have integrated AFS logon.  
+  - It deletes the db, etc, local, and logs directories from
+/usr/afs.
+  - Next it removes unnecessary files from /usr/vice/etc. 
+  - Then it deletes everything from the cache (/usr/vice/cache).
+  - Finally, it informs the state file that uninstallation is 
+complete.
+
+##################### 5) KNOWN PROBLEMS #############################
+
+    We have encountered a few problems along the way, and wanted to 
+document them as such.
+  - Be careful when installing something without client 
+functionality.  This seems to require an extra reboot of the 
+machine.  After installing OpenAFS, restart your machine again,
+and that should get it working properly.
+    There very well be some other problems that we haven't 
+yet encountered.  If you encounted such a problem, please send a
+description to openafs-devel@openafs.org
+
+#################### 6) FUTURE EXPANSION ############################
+
+    There is a lot of room for developing this package into something
+very useful, and we would like to make a few suggestions for future
+additions/fixes to the code.
+  - Allow ways to authenticate other than the kaserver, such as krb5.
+  - Find a secure, automatic way to transfer files from a server 
+machine to a machine that is to be set up as an additional server or 
+a client, rather then require the manual tranferral of those files. 
+  - Agree on a standard way to set up the filespace of a cell, as in
+where to put the user volumes, etc., so that this can all be done
+automatically by the scripts.
+  - Port this code to other operating systems to make it more
+widely useful.
+  - Resolve all "Known Problems" (see section 5).
+  - Test, test, test.