From 7e40a1bab4b8759da78f584acb430ea720a5d525 Mon Sep 17 00:00:00 2001 From: Derrick Brashear Date: Sun, 20 Jan 2002 09:34:40 +0000 Subject: [PATCH] STABLE12-functionality-test-suite-20020120 pull this all in in one fell swoop --- Makefile.in | 4 + configure.in | 3 + src/tests/Makefile.in | 380 ++++ src/tests/OpenAFS/Auth-Heimdal.pm | 44 + src/tests/OpenAFS/CMU_copyright.pm | 33 + src/tests/OpenAFS/ConfigUtils.pm | 26 + src/tests/OpenAFS/Dirpath.pm.in | 25 + src/tests/OpenAFS/OS-LINUX.pm | 23 + src/tests/OpenAFS/OS-SOLARIS.pm | 23 + src/tests/OpenAFS/afsconf.pm | 234 +++ src/tests/OpenAFS/bos.pm | 679 +++++++ src/tests/OpenAFS/config.pm | 125 ++ src/tests/OpenAFS/errtrans.pm | 310 ++++ src/tests/OpenAFS/fs.pm | 817 +++++++++ src/tests/OpenAFS/kas.pm | 325 ++++ src/tests/OpenAFS/pts.pm | 306 ++++ src/tests/OpenAFS/util.pm | 356 ++++ src/tests/OpenAFS/vos.pm | 803 +++++++++ src/tests/OpenAFS/wrapper.pm | 729 ++++++++ src/tests/README | 239 +++ src/tests/README.afstools | 2 + src/tests/README.dumptool | 152 ++ src/tests/TEMPLATE | 27 + src/tests/acladdgroup.pl | 41 + src/tests/acladdnegrights.pl | 42 + src/tests/acladdrights.pl | 42 + src/tests/acladduser.pl | 41 + src/tests/aclclearnegrights.pl | 48 + src/tests/aclcopy.pl | 32 + src/tests/aclremovegroup.pl | 52 + src/tests/aclremoveuser.pl | 52 + src/tests/afs-newcell.pl | 294 ++++ src/tests/afs-rmcell.sh | 7 + src/tests/afscp.c | 500 ++++++ src/tests/afscp_callback.c | 156 ++ src/tests/afsdump_dirlist.c | 140 ++ src/tests/afsdump_extract.c | 526 ++++++ src/tests/afsdump_scan.c | 293 +++ src/tests/afsdump_xsed.c | 333 ++++ src/tests/append-over-page.c | 977 ++++++++++ src/tests/append1 | 6 + src/tests/apwd.c | 472 +++++ src/tests/asu.c | 102 ++ src/tests/backuphdr.c | 87 + src/tests/baduniq.pl | 25 + src/tests/baduniq.pl~ | 25 + src/tests/blocks-new-file.c | 81 + src/tests/boot-strap-arla | 17 + src/tests/bosaddhost.pl | 19 + src/tests/bosaddkey.pl | 19 + src/tests/bosadduser.pl | 19 + src/tests/boscreate.pl | 27 + src/tests/bosdelete.pl | 19 + src/tests/bosdeleterunning.pl | 22 + src/tests/bosexec.pl | 26 + src/tests/bosinstall.pl | 26 + src/tests/boslisthosts.pl | 31 + src/tests/boslistkeys.pl | 27 + src/tests/boslistusers.pl | 26 + src/tests/bosremovehost.pl | 30 + src/tests/bosremovekey.pl | 25 + src/tests/bosremoveuser.pl | 26 + src/tests/bosrestartstopped.pl | 27 + src/tests/bossalvagepart.pl | 19 + src/tests/bossalvageserver.pl | 19 + src/tests/bossalvagevolume.pl | 19 + src/tests/bosshutdown.pl | 27 + src/tests/bosstart.pl | 27 + src/tests/bosstatus.pl | 26 + src/tests/bosstop.pl | 27 + src/tests/build-and-run-rcs | 29 + src/tests/build-emacs | 4 + src/tests/build-emacs-j | 4 + src/tests/build-gdb | 4 + src/tests/build-openafs | 10 + src/tests/checkpwd | 3 + src/tests/compare-inum-mp | 8 + src/tests/compare-inums | 4 + src/tests/compare-with-local | 77 + src/tests/copy-and-diff-gnu-mirror | 7 + src/tests/copy-file | 26 + src/tests/creat1 | 5 + src/tests/create-dirs.c | 93 + src/tests/create-files.c | 121 ++ src/tests/create-remove-dirs | 4 + src/tests/create-remove-files | 4 + src/tests/create-remove.c | 143 ++ src/tests/create-stat.c | 151 ++ src/tests/create-symlinks.c | 144 ++ src/tests/dd | 8 + src/tests/deep-tree | 6 + src/tests/deep-tree2 | 12 + src/tests/dir-size-mismatch | 10 + src/tests/dir-tree | 22 + src/tests/directory.c | 254 +++ src/tests/dump.c | 229 +++ src/tests/dumpfmt.h | 150 ++ src/tests/dumpscan.h | 379 ++++ src/tests/dumpscan_errs.et | 37 + src/tests/dumptool.c | 2640 ++++++++++++++++++++++++++++ src/tests/dup2-and-unlog.c | 32 + src/tests/echo-n.c | 18 + src/tests/err.c | 48 + src/tests/err.h | 71 + src/tests/errx.c | 48 + src/tests/exec | 9 + src/tests/exit-wo-close.c | 127 ++ src/tests/extcopyin | 11 + src/tests/extcopyout | 11 + src/tests/fcachesize-dir | 13 + src/tests/fcachesize-file-small | 13 + src/tests/fcachesize-read-file | 14 + src/tests/fcachesize-write-file | 13 + src/tests/fchmod.c | 71 + src/tests/fhbench.c | 337 ++++ src/tests/find-and-cat-netbsd | 5 + src/tests/find-linux | 5 + src/tests/fs-flush | 6 + src/tests/fs-sa-la | 6 + src/tests/fs_lib.c | 848 +++++++++ src/tests/fsx.c | 1054 +++++++++++ src/tests/ga-test.c | 329 ++++ src/tests/generic-build | 18 + src/tests/getdents-and-unlink1 | 9 + src/tests/getdents-and-unlink2 | 9 + src/tests/getdents-and-unlink3 | 9 + src/tests/grind-arla-with-cvs | 52 + src/tests/hardlink1.c | 149 ++ src/tests/hardlink2.c | 71 + src/tests/hardlink3 | 28 + src/tests/hardlink4.c | 99 ++ src/tests/hardlink5 | 11 + src/tests/hello-world.in | 8 + src/tests/int64.c | 407 +++++ src/tests/intNN.h | 155 ++ src/tests/internal.h | 55 + src/tests/intr-read.c | 128 ++ src/tests/intr-read1 | 4 + src/tests/invalidate-file.c | 202 +++ src/tests/kill-softer.c | 191 ++ src/tests/kill-softly.c | 161 ++ src/tests/kotest | 4 + src/tests/large-dir-16384 | 4 + src/tests/large-dir-extra | 7 + src/tests/large-dir.c | 157 ++ src/tests/large-dir2.c | 136 ++ src/tests/large-dir3.c | 124 ++ src/tests/large-filename | 6 + src/tests/ls-afs | 5 + src/tests/make-page.c | 96 + src/tests/many-dirs | 6 + src/tests/many-fetchs | 15 + src/tests/many-files | 4 + src/tests/many-files-with-content | 4 + src/tests/many-stores | 10 + src/tests/many-symlinks | 4 + src/tests/mkdir | 10 + src/tests/mkdir-lnk | 12 + src/tests/mkdir1 | 7 + src/tests/mkdir2.c | 82 + src/tests/mkdir3.c | 100 ++ src/tests/mkm-rmm | 13 + src/tests/mmap-and-read.c | 165 ++ src/tests/mmap-cat.c | 145 ++ src/tests/mmap-shared-write.c | 101 ++ src/tests/mmap-vs-read.c | 172 ++ src/tests/mmap-vs-read2.c | 172 ++ src/tests/mountpoint.in | 9 + src/tests/null-search.c | 150 ++ src/tests/parallel1 | 5 + src/tests/parsedump.c | 258 +++ src/tests/parsetag.c | 174 ++ src/tests/parsevnode.c | 427 +++++ src/tests/parsevol.c | 302 ++++ src/tests/pathname.c | 376 ++++ src/tests/pine.c | 99 ++ src/tests/primitive.c | 165 ++ src/tests/ptsadduser.pl | 17 + src/tests/ptschown.pl | 17 + src/tests/ptscreategroup.pl | 17 + src/tests/ptscreateuser.pl | 17 + src/tests/ptsdeletegroup.pl | 17 + src/tests/ptsdeleteuser.pl | 17 + src/tests/ptsexaminegroup.pl | 27 + src/tests/ptsexamineuser.pl | 24 + src/tests/ptslistmax.pl | 24 + src/tests/ptslistown.pl | 23 + src/tests/ptsmembersgroup.pl | 35 + src/tests/ptsmembersuser.pl | 35 + src/tests/ptsremove.pl | 17 + src/tests/ptssetf.pl | 28 + src/tests/ptssetmax.pl | 17 + src/tests/read-vs-mmap.c | 171 ++ src/tests/read-vs-mmap2.c | 134 ++ src/tests/read-write.c | 147 ++ src/tests/readdir-vs-lstat.c | 102 ++ src/tests/readfile-wo-create | 3 + src/tests/reauth.pl | 12 + src/tests/rename-under-feet.c | 168 ++ src/tests/rename1 | 7 + src/tests/rename2 | 7 + src/tests/rename3 | 9 + src/tests/rename4 | 9 + src/tests/rename5.c | 105 ++ src/tests/rename6.c | 73 + src/tests/repair.c | 366 ++++ src/tests/rewrite-emacs | 10 + src/tests/rm-rf.c | 128 ++ src/tests/run-fsx | 7 + src/tests/run-rcs | 11 + src/tests/run-suite.pl | 233 +++ src/tests/run-tests.in | 417 +++++ src/tests/setgroups | 4 + src/tests/setpag | 4 + src/tests/shallow-tree | 5 + src/tests/stagehdr.c | 150 ++ src/tests/stagehdr.h | 61 + src/tests/still-there-p.c | 89 + src/tests/strange-characters | 7 + src/tests/strange-characters-c.c | 93 + src/tests/strange-other-characters | 5 + src/tests/symlink.c | 72 + src/tests/t.uniq-bad | Bin 0 -> 3588 bytes src/tests/test-front.sh | 10 + src/tests/test-gunzip-gnu-mirror | 14 + src/tests/test-parallel1.c | 100 ++ src/tests/test-parallel2.c | 182 ++ src/tests/test-setgroups.c | 125 ++ src/tests/test-setpag.c | 116 ++ src/tests/too-many-files | 5 + src/tests/touch1 | 4 + src/tests/truncate-files.c | 148 ++ src/tests/truncate.c | 108 ++ src/tests/untar-emacs | 9 + src/tests/untar-openafs | 10 + src/tests/util.c | 164 ++ src/tests/utime-dir.c | 77 + src/tests/utime-file.c | 97 + src/tests/visit-volumes | 6 + src/tests/vosaddsite.pl | 19 + src/tests/vosbackup.pl | 19 + src/tests/voscreate.pl | 20 + src/tests/vosdelentry.pl | 19 + src/tests/vosdump.pl | 19 + src/tests/vosexamine.pl | 32 + src/tests/voslistpart.pl | 26 + src/tests/voslistvldb.pl | 24 + src/tests/voslistvol.pl | 24 + src/tests/voslock.pl | 19 + src/tests/vosmove.pl | 19 + src/tests/vospartinfo.pl | 19 + src/tests/vosrelease.pl | 19 + src/tests/vosremove.pl | 19 + src/tests/vosremsite.pl | 19 + src/tests/vosrename.pl | 19 + src/tests/vosrestore.pl | 19 + src/tests/vossyncserv.pl | 19 + src/tests/vossyncvldb.pl | 19 + src/tests/vosunlock.pl | 19 + src/tests/vosunlockall.pl | 21 + src/tests/voszap.pl | 19 + src/tests/warn.c | 48 + src/tests/warnx.c | 48 + src/tests/write-closed.c | 95 + src/tests/write-closed2.c | 128 ++ src/tests/write-large.c | 96 + src/tests/write-rand.c | 111 ++ src/tests/write-ro | 3 + src/tests/write-ro-file.c | 69 + src/tests/write-ucc.c | 101 ++ src/tests/write1 | 4 + src/tests/write2 | 6 + src/tests/write3.c | 125 ++ src/tests/xf_errs.et | 37 + src/tests/xf_files.c | 200 +++ src/tests/xf_printf.c | 444 +++++ src/tests/xf_profile.c | 184 ++ src/tests/xf_rxcall.c | 260 +++ src/tests/xfiles.c | 219 +++ src/tests/xfiles.h | 88 + 280 files changed, 30391 insertions(+) create mode 100644 src/tests/Makefile.in create mode 100644 src/tests/OpenAFS/Auth-Heimdal.pm create mode 100644 src/tests/OpenAFS/CMU_copyright.pm create mode 100644 src/tests/OpenAFS/ConfigUtils.pm create mode 100644 src/tests/OpenAFS/Dirpath.pm.in create mode 100644 src/tests/OpenAFS/OS-LINUX.pm create mode 100644 src/tests/OpenAFS/OS-SOLARIS.pm create mode 100644 src/tests/OpenAFS/afsconf.pm create mode 100644 src/tests/OpenAFS/bos.pm create mode 100644 src/tests/OpenAFS/config.pm create mode 100644 src/tests/OpenAFS/errtrans.pm create mode 100644 src/tests/OpenAFS/fs.pm create mode 100644 src/tests/OpenAFS/kas.pm create mode 100644 src/tests/OpenAFS/pts.pm create mode 100644 src/tests/OpenAFS/util.pm create mode 100644 src/tests/OpenAFS/vos.pm create mode 100644 src/tests/OpenAFS/wrapper.pm create mode 100644 src/tests/README create mode 100644 src/tests/README.afstools create mode 100644 src/tests/README.dumptool create mode 100644 src/tests/TEMPLATE create mode 100755 src/tests/acladdgroup.pl create mode 100755 src/tests/acladdnegrights.pl create mode 100755 src/tests/acladdrights.pl create mode 100755 src/tests/acladduser.pl create mode 100755 src/tests/aclclearnegrights.pl create mode 100755 src/tests/aclcopy.pl create mode 100755 src/tests/aclremovegroup.pl create mode 100755 src/tests/aclremoveuser.pl create mode 100755 src/tests/afs-newcell.pl create mode 100755 src/tests/afs-rmcell.sh create mode 100644 src/tests/afscp.c create mode 100644 src/tests/afscp_callback.c create mode 100644 src/tests/afsdump_dirlist.c create mode 100644 src/tests/afsdump_extract.c create mode 100644 src/tests/afsdump_scan.c create mode 100644 src/tests/afsdump_xsed.c create mode 100644 src/tests/append-over-page.c create mode 100644 src/tests/append1 create mode 100644 src/tests/apwd.c create mode 100644 src/tests/asu.c create mode 100644 src/tests/backuphdr.c create mode 100755 src/tests/baduniq.pl create mode 100755 src/tests/baduniq.pl~ create mode 100644 src/tests/blocks-new-file.c create mode 100644 src/tests/boot-strap-arla create mode 100755 src/tests/bosaddhost.pl create mode 100755 src/tests/bosaddkey.pl create mode 100755 src/tests/bosadduser.pl create mode 100755 src/tests/boscreate.pl create mode 100755 src/tests/bosdelete.pl create mode 100755 src/tests/bosdeleterunning.pl create mode 100755 src/tests/bosexec.pl create mode 100755 src/tests/bosinstall.pl create mode 100755 src/tests/boslisthosts.pl create mode 100755 src/tests/boslistkeys.pl create mode 100755 src/tests/boslistusers.pl create mode 100755 src/tests/bosremovehost.pl create mode 100755 src/tests/bosremovekey.pl create mode 100755 src/tests/bosremoveuser.pl create mode 100755 src/tests/bosrestartstopped.pl create mode 100755 src/tests/bossalvagepart.pl create mode 100755 src/tests/bossalvageserver.pl create mode 100755 src/tests/bossalvagevolume.pl create mode 100755 src/tests/bosshutdown.pl create mode 100755 src/tests/bosstart.pl create mode 100755 src/tests/bosstatus.pl create mode 100755 src/tests/bosstop.pl create mode 100755 src/tests/build-and-run-rcs create mode 100755 src/tests/build-emacs create mode 100644 src/tests/build-emacs-j create mode 100755 src/tests/build-gdb create mode 100755 src/tests/build-openafs create mode 100755 src/tests/checkpwd create mode 100755 src/tests/compare-inum-mp create mode 100755 src/tests/compare-inums create mode 100755 src/tests/compare-with-local create mode 100755 src/tests/copy-and-diff-gnu-mirror create mode 100755 src/tests/copy-file create mode 100755 src/tests/creat1 create mode 100644 src/tests/create-dirs.c create mode 100644 src/tests/create-files.c create mode 100644 src/tests/create-remove-dirs create mode 100644 src/tests/create-remove-files create mode 100644 src/tests/create-remove.c create mode 100644 src/tests/create-stat.c create mode 100644 src/tests/create-symlinks.c create mode 100755 src/tests/dd create mode 100644 src/tests/deep-tree create mode 100644 src/tests/deep-tree2 create mode 100644 src/tests/dir-size-mismatch create mode 100755 src/tests/dir-tree create mode 100644 src/tests/directory.c create mode 100644 src/tests/dump.c create mode 100644 src/tests/dumpfmt.h create mode 100644 src/tests/dumpscan.h create mode 100644 src/tests/dumpscan_errs.et create mode 100644 src/tests/dumptool.c create mode 100644 src/tests/dup2-and-unlog.c create mode 100644 src/tests/echo-n.c create mode 100644 src/tests/err.c create mode 100644 src/tests/err.h create mode 100644 src/tests/errx.c create mode 100755 src/tests/exec create mode 100644 src/tests/exit-wo-close.c create mode 100755 src/tests/extcopyin create mode 100755 src/tests/extcopyout create mode 100644 src/tests/fcachesize-dir create mode 100644 src/tests/fcachesize-file-small create mode 100644 src/tests/fcachesize-read-file create mode 100644 src/tests/fcachesize-write-file create mode 100644 src/tests/fchmod.c create mode 100644 src/tests/fhbench.c create mode 100644 src/tests/find-and-cat-netbsd create mode 100644 src/tests/find-linux create mode 100644 src/tests/fs-flush create mode 100755 src/tests/fs-sa-la create mode 100644 src/tests/fs_lib.c create mode 100644 src/tests/fsx.c create mode 100644 src/tests/ga-test.c create mode 100755 src/tests/generic-build create mode 100755 src/tests/getdents-and-unlink1 create mode 100755 src/tests/getdents-and-unlink2 create mode 100755 src/tests/getdents-and-unlink3 create mode 100755 src/tests/grind-arla-with-cvs create mode 100644 src/tests/hardlink1.c create mode 100644 src/tests/hardlink2.c create mode 100644 src/tests/hardlink3 create mode 100644 src/tests/hardlink4.c create mode 100644 src/tests/hardlink5 create mode 100644 src/tests/hello-world.in create mode 100644 src/tests/int64.c create mode 100644 src/tests/intNN.h create mode 100644 src/tests/internal.h create mode 100644 src/tests/intr-read.c create mode 100755 src/tests/intr-read1 create mode 100644 src/tests/invalidate-file.c create mode 100644 src/tests/kill-softer.c create mode 100644 src/tests/kill-softly.c create mode 100755 src/tests/kotest create mode 100755 src/tests/large-dir-16384 create mode 100755 src/tests/large-dir-extra create mode 100644 src/tests/large-dir.c create mode 100644 src/tests/large-dir2.c create mode 100644 src/tests/large-dir3.c create mode 100644 src/tests/large-filename create mode 100644 src/tests/ls-afs create mode 100644 src/tests/make-page.c create mode 100644 src/tests/many-dirs create mode 100644 src/tests/many-fetchs create mode 100644 src/tests/many-files create mode 100644 src/tests/many-files-with-content create mode 100644 src/tests/many-stores create mode 100644 src/tests/many-symlinks create mode 100644 src/tests/mkdir create mode 100755 src/tests/mkdir-lnk create mode 100755 src/tests/mkdir1 create mode 100644 src/tests/mkdir2.c create mode 100644 src/tests/mkdir3.c create mode 100755 src/tests/mkm-rmm create mode 100644 src/tests/mmap-and-read.c create mode 100644 src/tests/mmap-cat.c create mode 100644 src/tests/mmap-shared-write.c create mode 100644 src/tests/mmap-vs-read.c create mode 100644 src/tests/mmap-vs-read2.c create mode 100644 src/tests/mountpoint.in create mode 100644 src/tests/null-search.c create mode 100644 src/tests/parallel1 create mode 100644 src/tests/parsedump.c create mode 100644 src/tests/parsetag.c create mode 100644 src/tests/parsevnode.c create mode 100644 src/tests/parsevol.c create mode 100644 src/tests/pathname.c create mode 100644 src/tests/pine.c create mode 100644 src/tests/primitive.c create mode 100755 src/tests/ptsadduser.pl create mode 100755 src/tests/ptschown.pl create mode 100755 src/tests/ptscreategroup.pl create mode 100755 src/tests/ptscreateuser.pl create mode 100755 src/tests/ptsdeletegroup.pl create mode 100755 src/tests/ptsdeleteuser.pl create mode 100755 src/tests/ptsexaminegroup.pl create mode 100755 src/tests/ptsexamineuser.pl create mode 100755 src/tests/ptslistmax.pl create mode 100755 src/tests/ptslistown.pl create mode 100755 src/tests/ptsmembersgroup.pl create mode 100755 src/tests/ptsmembersuser.pl create mode 100755 src/tests/ptsremove.pl create mode 100755 src/tests/ptssetf.pl create mode 100755 src/tests/ptssetmax.pl create mode 100644 src/tests/read-vs-mmap.c create mode 100644 src/tests/read-vs-mmap2.c create mode 100644 src/tests/read-write.c create mode 100644 src/tests/readdir-vs-lstat.c create mode 100755 src/tests/readfile-wo-create create mode 100755 src/tests/reauth.pl create mode 100644 src/tests/rename-under-feet.c create mode 100755 src/tests/rename1 create mode 100644 src/tests/rename2 create mode 100755 src/tests/rename3 create mode 100755 src/tests/rename4 create mode 100644 src/tests/rename5.c create mode 100644 src/tests/rename6.c create mode 100644 src/tests/repair.c create mode 100755 src/tests/rewrite-emacs create mode 100644 src/tests/rm-rf.c create mode 100755 src/tests/run-fsx create mode 100755 src/tests/run-rcs create mode 100755 src/tests/run-suite.pl create mode 100755 src/tests/run-tests.in create mode 100755 src/tests/setgroups create mode 100755 src/tests/setpag create mode 100644 src/tests/shallow-tree create mode 100644 src/tests/stagehdr.c create mode 100644 src/tests/stagehdr.h create mode 100644 src/tests/still-there-p.c create mode 100755 src/tests/strange-characters create mode 100644 src/tests/strange-characters-c.c create mode 100644 src/tests/strange-other-characters create mode 100644 src/tests/symlink.c create mode 100644 src/tests/t.uniq-bad create mode 100755 src/tests/test-front.sh create mode 100755 src/tests/test-gunzip-gnu-mirror create mode 100644 src/tests/test-parallel1.c create mode 100644 src/tests/test-parallel2.c create mode 100644 src/tests/test-setgroups.c create mode 100644 src/tests/test-setpag.c create mode 100644 src/tests/too-many-files create mode 100755 src/tests/touch1 create mode 100644 src/tests/truncate-files.c create mode 100644 src/tests/truncate.c create mode 100755 src/tests/untar-emacs create mode 100755 src/tests/untar-openafs create mode 100644 src/tests/util.c create mode 100644 src/tests/utime-dir.c create mode 100644 src/tests/utime-file.c create mode 100644 src/tests/visit-volumes create mode 100755 src/tests/vosaddsite.pl create mode 100755 src/tests/vosbackup.pl create mode 100755 src/tests/voscreate.pl create mode 100755 src/tests/vosdelentry.pl create mode 100755 src/tests/vosdump.pl create mode 100755 src/tests/vosexamine.pl create mode 100755 src/tests/voslistpart.pl create mode 100755 src/tests/voslistvldb.pl create mode 100755 src/tests/voslistvol.pl create mode 100755 src/tests/voslock.pl create mode 100755 src/tests/vosmove.pl create mode 100755 src/tests/vospartinfo.pl create mode 100755 src/tests/vosrelease.pl create mode 100755 src/tests/vosremove.pl create mode 100755 src/tests/vosremsite.pl create mode 100755 src/tests/vosrename.pl create mode 100755 src/tests/vosrestore.pl create mode 100755 src/tests/vossyncserv.pl create mode 100755 src/tests/vossyncvldb.pl create mode 100755 src/tests/vosunlock.pl create mode 100755 src/tests/vosunlockall.pl create mode 100755 src/tests/voszap.pl create mode 100644 src/tests/warn.c create mode 100644 src/tests/warnx.c create mode 100644 src/tests/write-closed.c create mode 100644 src/tests/write-closed2.c create mode 100644 src/tests/write-large.c create mode 100644 src/tests/write-rand.c create mode 100755 src/tests/write-ro create mode 100644 src/tests/write-ro-file.c create mode 100644 src/tests/write-ucc.c create mode 100755 src/tests/write1 create mode 100755 src/tests/write2 create mode 100644 src/tests/write3.c create mode 100644 src/tests/xf_errs.et create mode 100644 src/tests/xf_files.c create mode 100644 src/tests/xf_printf.c create mode 100644 src/tests/xf_profile.c create mode 100644 src/tests/xf_rxcall.c create mode 100644 src/tests/xfiles.c create mode 100644 src/tests/xfiles.h diff --git a/Makefile.in b/Makefile.in index e959b87a1..3955ed004 100644 --- a/Makefile.in +++ b/Makefile.in @@ -570,6 +570,7 @@ clean2: -${COMPILE_PART1} bucoord ${COMPILE_CLEAN} -${COMPILE_PART1} xstat ${COMPILE_CLEAN} -${COMPILE_PART1} afsmonitor ${COMPILE_CLEAN} + -${COMPILE_PART1} tests ${COMPILE_CLEAN} -${COMPILE_PART1} rxdebug ${COMPILE_CLEAN} -${COMPILE_PART1} libafsrpc ${COMPILE_CLEAN} -${COMPILE_PART1} libafsauthent ${COMPILE_CLEAN} @@ -696,6 +697,9 @@ distclean: clean src/sia/Makefile \ src/sys/Makefile \ src/tbutc/Makefile \ + src/tests/Makefile \ + src/tests/run-tests \ + src/tests/OpenAFS/Dirpath.pm \ src/tsm41/Makefile \ src/tviced/Makefile \ src/ubik/Makefile \ diff --git a/configure.in b/configure.in index 919ac5c77..bca962056 100644 --- a/configure.in +++ b/configure.in @@ -108,6 +108,9 @@ src/sgistuff/Makefile \ src/sia/Makefile \ src/sys/Makefile \ src/tbutc/Makefile \ +src/tests/Makefile \ +src/tests/run-tests \ +src/tests/OpenAFS/Dirpath.pm \ src/tsm41/Makefile \ src/tviced/Makefile \ src/ubik/Makefile \ diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in new file mode 100644 index 000000000..b3d9f0718 --- /dev/null +++ b/src/tests/Makefile.in @@ -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 index 000000000..f578c82df --- /dev/null +++ b/src/tests/OpenAFS/Auth-Heimdal.pm @@ -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 = ; + chomp $cell; + close CELL; + return $cell; +} + +sub getrealm { + my($cell); + open(CELL, "$openafsdirpath->{'afsconfdir'}/ThisCell") + or die "Cannot open $openafsdirpath->{'afsconfdir'}/ThisCell: $!\n"; + $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 index 000000000..8b3b5a058 --- /dev/null +++ b/src/tests/OpenAFS/CMU_copyright.pm @@ -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 index 000000000..ca56d60a7 --- /dev/null +++ b/src/tests/OpenAFS/ConfigUtils.pm @@ -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 index 000000000..32c001cdd --- /dev/null +++ b/src/tests/OpenAFS/Dirpath.pm.in @@ -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 index 000000000..70c7d3825 --- /dev/null +++ b/src/tests/OpenAFS/OS-LINUX.pm @@ -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 index 000000000..3ba26456a --- /dev/null +++ b/src/tests/OpenAFS/OS-SOLARIS.pm @@ -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 index 000000000..86db4605d --- /dev/null +++ b/src/tests/OpenAFS/afsconf.pm @@ -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. 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 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 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 = ); + 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. +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, +I<$cellname> may be any unique prefix of a cell name. The resulting list +contains server hostnames, as found in F. + +=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 () { + $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) 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 () { + 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 = ); + 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'} = ; + 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 index 000000000..9d857928b --- /dev/null +++ b/src/tests/OpenAFS/bos.pm @@ -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 index 000000000..0de0a54e1 --- /dev/null +++ b/src/tests/OpenAFS/config.pm @@ -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 of AFStools +should act, not how it should act upon a particular B. 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 is +set, it will generally be searched before this directory. Normally, this +should be set to F 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. 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 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 index 000000000..48cf96ae3 --- /dev/null +++ b/src/tests/OpenAFS/errtrans.pm @@ -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 index 000000000..40932377a --- /dev/null +++ b/src/tests/OpenAFS/fs.pm @@ -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 index 000000000..376f62a9a --- /dev/null +++ b/src/tests/OpenAFS/kas.pm @@ -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 index 000000000..715b5e1dd --- /dev/null +++ b/src/tests/OpenAFS/pts.pm @@ -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 index 000000000..ec1c52af6 --- /dev/null +++ b/src/tests/OpenAFS/util.pm @@ -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 utilities. The default is 0, +which disables any tracing of activity of B 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 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. 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, 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. + +=item %AFS_Trace - Tracing levels [Private] + +This array contains the tracing levels set with B. + +=item %AFScmd - AFS command locations [Private] + +This array contains paths to the various AFS command binaries, for use +by B 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 index 000000000..3f1ae6a6e --- /dev/null +++ b/src/tests/OpenAFS/vos.pm @@ -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 index 000000000..4e4931f22 --- /dev/null +++ b/src/tests/OpenAFS/wrapper.pm @@ -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, 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 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. + +=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 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), describing the reason for the +failure. + +The I<%options> table may be used to pass any or all of the following +options into B, 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 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, 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 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, 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 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 is given, +it will be used as a regexp to match against the B 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 () { + 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 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 module to catch errors +generated by B 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 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 option, which would pass the +command's STDOUT directly to ours without parsing it. + + [ '', '?' ] + +B 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. + + 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, 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'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 index 000000000..f73299edf --- /dev/null +++ b/src/tests/README @@ -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 index 000000000..d9f5c7fab --- /dev/null +++ b/src/tests/README.afstools @@ -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 index 000000000..69c28ddcb --- /dev/null +++ b/src/tests/README.dumptool @@ -0,0 +1,152 @@ +$Id$ + +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 +. 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 . Shar and enjoy. diff --git a/src/tests/TEMPLATE b/src/tests/TEMPLATE new file mode 100644 index 000000000..644875009 --- /dev/null +++ b/src/tests/TEMPLATE @@ -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 index 000000000..8259c6f24 --- /dev/null +++ b/src/tests/acladdgroup.pl @@ -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 index 000000000..d18db5708 --- /dev/null +++ b/src/tests/acladdnegrights.pl @@ -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 index 000000000..a37a21029 --- /dev/null +++ b/src/tests/acladdrights.pl @@ -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 index 000000000..7e29fa410 --- /dev/null +++ b/src/tests/acladduser.pl @@ -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 index 000000000..738001f74 --- /dev/null +++ b/src/tests/aclclearnegrights.pl @@ -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 index 000000000..dce2f547e --- /dev/null +++ b/src/tests/aclcopy.pl @@ -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 index 000000000..65cb0f44d --- /dev/null +++ b/src/tests/aclremovegroup.pl @@ -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 index 000000000..9124c6d44 --- /dev/null +++ b/src/tests/aclremoveuser.pl @@ -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 index 000000000..91a24283c --- /dev/null +++ b/src/tests/afs-newcell.pl @@ -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 [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 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 option specifies the name of the administrative user. +This user will be given system:administrators and susers permission in +the cell. + +The B option specifies the name of the cell. + +The B option specifies the size of the AFS cache. + +=head1 AUTHOR + +Sam Hartman + +=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 <{'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() { + 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 = ; +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() { +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() { + 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 index 000000000..53f59585c --- /dev/null +++ b/src/tests/afs-rmcell.sh @@ -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 index 000000000..6cb8931ed --- /dev/null +++ b/src/tests/afscp.c @@ -0,0 +1,500 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/*#include */ +#include + +/*#include */ +#include + +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 index 000000000..6d2549d0c --- /dev/null +++ b/src/tests/afscp_callback.c @@ -0,0 +1,156 @@ +#include +#include /*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 index 000000000..78d603757 --- /dev/null +++ b/src/tests/afsdump_dirlist.c @@ -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 +#include +#include +#include + +#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 index 000000000..e92c66e19 --- /dev/null +++ b/src/tests/afsdump_extract.c @@ -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 +#include +#include +#include +#include +#include + +#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 index 000000000..ae95d8b39 --- /dev/null +++ b/src/tests/afsdump_scan.c @@ -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 +#include +#include +#include + +#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 index 000000000..f4f9e0fac --- /dev/null +++ b/src/tests/afsdump_xsed.c @@ -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 +#include +#include +#include +#include + +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 index 000000000..6b875a998 --- /dev/null +++ b/src/tests/append-over-page.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include + +#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 index 000000000..c7dc37357 --- /dev/null +++ b/src/tests/append1 @@ -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 index 000000000..82335ec42 --- /dev/null +++ b/src/tests/apwd.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifndef MAXPATHLEN +#ifdef PATH_MAX +#define MAXPATHLEN PATH_MAX +#else +#define MAXPATHLEN 4096 +#endif +#endif + +RCSID("$Id$"); + +static int verbose_flag; +static FILE *verbose_fp = NULL; + +static int +initial_string (char **buf, size_t *size, size_t new_size) +{ + char *tmp = malloc (new_size); + + if (tmp == NULL) + return -1; + *buf = tmp; + *size = new_size; + return 0; +} + +static int +expand_string (char **buf, size_t *size, size_t new_size) +{ + char *tmp = realloc (*buf, new_size); + + if (tmp == NULL) + return -1; + *buf = tmp; + *size = new_size; + return 0; +} + +/* + * Verify that the dynamically allocated string `buf' of length + * `size', has room for `len' bytes. Returns -1 if realloc fails. + */ + +static int +guarantee_room (char **buf, size_t *size, size_t len) +{ + if (*size > len) + return 0; + + return expand_string (buf, size, min(*size * 2, len)); +} + +static char * +getcwd_classic (char *buf, size_t size) +{ + int dynamic_buf = 0; + struct stat root_sb, dot_sb, dotdot_sb; + char *work_string; + size_t work_length; + char slash_dot_dot[] = "/.."; + char *curp; + char *endp; + DIR *dir = NULL; + + if (initial_string (&work_string, &work_length, MAXPATHLEN) < 0) + return NULL; + + if (buf == NULL) { + dynamic_buf = 1; + if (initial_string (&buf, &size, MAXPATHLEN) < 0) { + free (work_string); + return NULL; + } + } + + endp = curp = buf + size - 1; + + if (lstat (".", &dot_sb) < 0) + goto err_ret; + if (lstat ("/", &root_sb) < 0) + goto err_ret; + strcpy (work_string, ".."); + fprintf (verbose_fp, "\".\" is (%u, %u), \"/\" is (%u, %u)\n", + (unsigned)dot_sb.st_dev, (unsigned)dot_sb.st_ino, + (unsigned)root_sb.st_dev, (unsigned)root_sb.st_ino); + + while (dot_sb.st_dev != root_sb.st_dev + || dot_sb.st_ino != root_sb.st_ino) { + struct dirent *dp; + int found = 0; + int change_dev = 0; + int pattern_len = strlen (work_string); + + if (lstat (work_string, &dotdot_sb) < 0) + goto err_ret; + fprintf (verbose_fp, "\"..\" is (%u, %u)\n", + (unsigned)dotdot_sb.st_dev, (unsigned)dotdot_sb.st_ino); + if (dot_sb.st_dev != dotdot_sb.st_dev) + change_dev = 1; + dir = opendir (work_string); + if (dir == NULL) + goto err_ret; + while ((dp = readdir (dir)) != NULL) { + size_t name_len = strlen (dp->d_name); + + if (change_dev) { + struct stat sb; + + if (guarantee_room (&work_string, &work_length, + pattern_len + name_len + 2) < 0) { + goto err_ret; + } + + strcat (work_string, "/"); + strcat (work_string, dp->d_name); + + if (lstat (work_string, &sb) < 0) { + goto err_ret; + } + if (sb.st_dev == dot_sb.st_dev + && sb.st_ino == dot_sb.st_ino) { + fprintf (verbose_fp, "\"%s\" found\n", work_string); + found = 1; + } + work_string[pattern_len] = '\0'; + } else if (dp->d_ino == dot_sb.st_ino) { + fprintf (verbose_fp, "\"%s\" found\n", dp->d_name); + found = 1; + } + + if (found) { + while (buf + name_len >= curp) { + size_t old_len; + + if (!dynamic_buf) { + errno = ERANGE; + goto err_ret; + } + old_len = endp - curp + 1; + if (expand_string (&buf, &size, size * 2) < 0) + goto err_ret; + memmove (buf + size - old_len, + buf + size / 2 - old_len, + old_len); + endp = buf + size - 1; + curp = endp - old_len + 1; + } + memcpy (curp - name_len, dp->d_name, name_len); + curp[-(name_len + 1)] = '/'; + curp -= name_len + 1; + break; + } + } + closedir (dir); + dir = NULL; + + if (!found) + goto err_ret; + + dot_sb = dotdot_sb; + if (guarantee_room (&work_string, &work_length, + pattern_len + strlen(slash_dot_dot) + 1) < 0) + goto err_ret; + strcat (work_string, slash_dot_dot); + } + if (curp == endp) { + while (buf >= curp) { + if (!dynamic_buf) { + errno = ERANGE; + goto err_ret; + } + if (expand_string (&buf, &size, size * 2) < 0) + goto err_ret; + } + *--curp = '/'; + } + *endp = '\0'; + memmove (buf, curp, endp - curp + 1); + free (work_string); + return buf; + +err_ret: + if (dir) + closedir (dir); + if (dynamic_buf) + free (buf); + free (work_string); + return NULL; +} + +#if linux + +static char * +getcwd_proc (char *buf, size_t size) +{ + int dynamic_buf = 0; + + if (buf == NULL) { + dynamic_buf = 1; + if (initial_string (&buf, &size, MAXPATHLEN) < 0) + return NULL; + } else if (size <= 1) { + errno = ERANGE; + return NULL; + } + + for (;;) { + int ret; + + ret = readlink ("/proc/self/cwd", buf, size); + if (ret == -1) + goto err_ret; + if (buf[0] != '/') { + errno = EINVAL; + goto err_ret; + } + if (buf[ret-1] != '\0' && ret >= size) { + if (!dynamic_buf) { + errno = ERANGE; + goto err_ret; + } + if (expand_string (&buf, &size, size * 2) < 0) + goto err_ret; + } else { + if (buf[ret - 1] != '\0') + buf[ret] = '\0'; + return buf; + } + } +err_ret: + if (dynamic_buf) + free (buf); + return NULL; +} + +#endif /* linux */ + +static int +test_1(char *(*func)(char *, size_t), const char *func_name, int init_size) +{ + char real_buf[2048]; + char buf[2048], *buf2, buf3[4711]; + int i; + int ret = 0; + int three_done = 1; + + if (getcwd (real_buf, sizeof(real_buf)) == NULL) { + fprintf (verbose_fp, "getcwd(buf, %u) failed\n", + (unsigned)sizeof(real_buf)); + ret = 1; + } + if (func (buf, sizeof(buf)) == NULL) { + fprintf (verbose_fp, "%s(buf, %u) failed\n", func_name, + (unsigned)sizeof(buf)); + ret = 1; + } else { + fprintf (verbose_fp, "first *%s*\n", buf); + if (strcmp (real_buf, buf) != 0) { + fprintf (verbose_fp, "first comparison failed: *%s* != *%s*\n", + real_buf, buf); + ret = 1; + } + } + + buf2 = func (NULL, 0); + if (buf2 == NULL) { + fprintf (verbose_fp, "%s(NULL, 0) failed\n", func_name); + ret = 1; + } else { + fprintf (verbose_fp, "second *%s*\n", buf2); + if (strcmp (real_buf, buf2) != 0) { + fprintf (verbose_fp, "second comparison failed: *%s* != *%s*\n", + real_buf, buf2); + ret = 1; + } + free (buf2); + } + + for (i = init_size; i < sizeof(buf3); ++i) { + memset (buf3, '\x01', sizeof(buf3)); + if (func (buf3, i) == NULL) { + if (errno != ERANGE) { + fprintf (verbose_fp, "%s(buf,%u) call failed\n", func_name, i); + three_done = 0; + break; + } + } else { + int j; + + for (j = i; j < sizeof(buf3); ++j) + if (buf3[j] != '\x01') { + fprintf (verbose_fp, "buffer was overwritten at %d\n", j); + three_done = 0; + break; + } + break; + } + } + + if (three_done) { + fprintf (verbose_fp, "third *%s*\n", buf3); + if (strcmp (real_buf, buf3) != 0) { + fprintf (verbose_fp, "third comparison failed: *%s* != *%s*\n", + real_buf, buf3); + ret = 1; + } else if (strlen (buf3) + 1 != i + && strlen (buf3) + 1 >= init_size) { + fprintf (verbose_fp, "wrong len in third call: %d != %d\n", + (unsigned)strlen(buf3) + 1, i); + ret = 1; + } + } else { + ret = 1; + } + + return ret; +} + +static int +test_it(char *(*func)(char *, size_t), const char *name, int init_size) +{ + int ret; + + fprintf (verbose_fp, "testing %s (initial size %d)\n", name, init_size); + ret = test_1 (func, name, init_size); + if (ret) + fprintf (verbose_fp, "FAILED!\n"); + else + fprintf (verbose_fp, "passed\n"); + return ret; +} + +#ifdef linux +#include +#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 index 000000000..d69650de0 --- /dev/null +++ b/src/tests/asu.c @@ -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 +RCSID("$Id$"); +#endif + +#include +#include +#include +#include +#include +#include + + +#include + +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 index 000000000..88c9759c1 --- /dev/null +++ b/src/tests/backuphdr.c @@ -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 + +#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 index 000000000..3477593c0 --- /dev/null +++ b/src/tests/baduniq.pl @@ -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/baduniq.pl~ b/src/tests/baduniq.pl~ new file mode 100755 index 000000000..afc1b7f95 --- /dev/null +++ b/src/tests/baduniq.pl~ @@ -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/service.dump","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 index 000000000..d04a5195d --- /dev/null +++ b/src/tests/blocks-new-file.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include + +#include + +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 index 000000000..beba19764 --- /dev/null +++ b/src/tests/boot-strap-arla @@ -0,0 +1,17 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ;exit 0; fi + +ARLA_RELEASE=${AFSROOT}/stacken.kth.se/ftp/pub/arla/arla-0.34.tar.gz + +mkdir src || exit 1 +mkdir obj || exit 1 + +cd src || exit 1 +gzip -dc $ARLA_RELEASE | tar xf - +cd ../obj || exit 1 +../src/*/configure || exit 1 +make || exit 1 +cd milko || exit 1 +make || exit 1 +exit 0 diff --git a/src/tests/bosaddhost.pl b/src/tests/bosaddhost.pl new file mode 100755 index 000000000..549ecb78b --- /dev/null +++ b/src/tests/bosaddhost.pl @@ -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 index 000000000..6a5e596c3 --- /dev/null +++ b/src/tests/bosaddkey.pl @@ -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 index 000000000..74950422c --- /dev/null +++ b/src/tests/bosadduser.pl @@ -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 index 000000000..9161e9daf --- /dev/null +++ b/src/tests/boscreate.pl @@ -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 index 000000000..6d0819bf9 --- /dev/null +++ b/src/tests/bosdelete.pl @@ -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 index 000000000..db9693053 --- /dev/null +++ b/src/tests/bosdeleterunning.pl @@ -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 index 000000000..37a348798 --- /dev/null +++ b/src/tests/bosexec.pl @@ -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 index 000000000..ddaa7c281 --- /dev/null +++ b/src/tests/bosinstall.pl @@ -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 index 000000000..dfab1ab0a --- /dev/null +++ b/src/tests/boslisthosts.pl @@ -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 index 000000000..77affa4bf --- /dev/null +++ b/src/tests/boslistkeys.pl @@ -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 index 000000000..b9fc7c937 --- /dev/null +++ b/src/tests/boslistusers.pl @@ -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 index 000000000..5a8133e1e --- /dev/null +++ b/src/tests/bosremovehost.pl @@ -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 index 000000000..3c1a923ad --- /dev/null +++ b/src/tests/bosremovekey.pl @@ -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 index 000000000..75cc0140b --- /dev/null +++ b/src/tests/bosremoveuser.pl @@ -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 index 000000000..7b5f59f2e --- /dev/null +++ b/src/tests/bosrestartstopped.pl @@ -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 index 000000000..87cdc539a --- /dev/null +++ b/src/tests/bossalvagepart.pl @@ -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 index 000000000..9b6fcd7dc --- /dev/null +++ b/src/tests/bossalvageserver.pl @@ -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 index 000000000..f3bc1edf9 --- /dev/null +++ b/src/tests/bossalvagevolume.pl @@ -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 index 000000000..a5cff4682 --- /dev/null +++ b/src/tests/bosshutdown.pl @@ -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 index 000000000..2f8d9a55e --- /dev/null +++ b/src/tests/bosstart.pl @@ -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 index 000000000..37428b55c --- /dev/null +++ b/src/tests/bosstatus.pl @@ -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 index 000000000..ff34697da --- /dev/null +++ b/src/tests/bosstop.pl @@ -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 index 000000000..744281f4c --- /dev/null +++ b/src/tests/build-and-run-rcs @@ -0,0 +1,29 @@ +#!/bin/sh +set -x +# $Id$ +##if test "X$FAST" != "X" ; then echo "Not running $0" ; exit 0 ; fi +echo -n pwd before is ' ' +pwd +# +# copied from generic-build because rcs wants to put (hard)links into tar balls. +# +filename=$AFSROOT/stacken.kth.se/ftp/pub/gnu/rcs/rcs-5.7.tar.gz +b=rcs-5.7 +obj=$b-obj +gzip -dc $filename | tar xvf - >&4 2>&1 +mkdir $obj || exit 1 +cd $obj || exit 1 +../$b/configure >&4 || exit 1 +make $MAKEFLAGS || exit 1 +echo -n pwd after is ' ' +pwd +echo row1 > testfile +echo log1 | ./src/ci -u testfile +./src/co -l testfile +echo row2 >> testfile +echo log2 | ./src/ci -u testfile +./src/co -l testfile +echo row3 >> testfile +echo log3 | ./src/ci -u testfile +wc -l testfile | grep '3 testfile' || exit 1 + diff --git a/src/tests/build-emacs b/src/tests/build-emacs new file mode 100755 index 000000000..d5cfb5b2b --- /dev/null +++ b/src/tests/build-emacs @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ; exit 0 ; fi +$SHELL $SHELLVERBOSE $srcdir/generic-build $AFSROOT/stacken.kth.se/ftp/pub/gnu/emacs/emacs-20.7.tar.gz emacs-20.7 diff --git a/src/tests/build-emacs-j b/src/tests/build-emacs-j new file mode 100644 index 000000000..3cac27914 --- /dev/null +++ b/src/tests/build-emacs-j @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ; exit 0 ; fi +env MAKEFLAGS="-j" $SHELL $SHELLVERBOSE $srcdir/generic-build $AFSROOT/stacken.kth.se/ftp/pub/gnu/emacs/emacs-20.7.tar.gz emacs-20.7 diff --git a/src/tests/build-gdb b/src/tests/build-gdb new file mode 100755 index 000000000..f030054a1 --- /dev/null +++ b/src/tests/build-gdb @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ; exit 0 ; fi +$SHELL $SHELLVERBOSE $srcdir/generic-build $AFSROOT/stacken.kth.se/ftp/pub/gnu/gdb/gdb-5.0.tar.gz diff --git a/src/tests/build-openafs b/src/tests/build-openafs new file mode 100755 index 000000000..e8f43c945 --- /dev/null +++ b/src/tests/build-openafs @@ -0,0 +1,10 @@ +#!/bin/sh +# $Id$ +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 index 000000000..502a3ddf2 --- /dev/null +++ b/src/tests/checkpwd @@ -0,0 +1,3 @@ +#!/bin/sh +# $Id$ +$objdir/apwd diff --git a/src/tests/compare-inum-mp b/src/tests/compare-inum-mp new file mode 100755 index 000000000..ce92bcf79 --- /dev/null +++ b/src/tests/compare-inum-mp @@ -0,0 +1,8 @@ +#!/bin/sh +# $Id$ +FS=${FS:-${objdir}/../appl/fs/fs} +${FS} sa . system:anyuser all || exit 1 +${FS} mkm root.cell root.cell || exit 1 +$objdir/readdir-vs-lstat . || exit 1 +$objdir/readdir-vs-lstat root.cell || exit 1 +${FS} rmm root.cell || exit 1 diff --git a/src/tests/compare-inums b/src/tests/compare-inums new file mode 100755 index 000000000..614560d23 --- /dev/null +++ b/src/tests/compare-inums @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ +$objdir/create-files 100 0 || exit 1 +$objdir/readdir-vs-lstat . || exit 1 diff --git a/src/tests/compare-with-local b/src/tests/compare-with-local new file mode 100755 index 000000000..8c7a49567 --- /dev/null +++ b/src/tests/compare-with-local @@ -0,0 +1,77 @@ +#!/bin/sh +# $Id$ +################################################################# +# +# Copy file back and forth between $TMPDIR (defaults to /tmp) +# which is hopefully on local disk or any other well tested +# file system and the filesystem we want to test (in $PWD). +# +################################################################# + +test $SHELLVERBOSE && set $SHELLVERBOSE + +function compare () { + if cmp $1 $2; then + : + else + diff $1 $2 + exit 1 + fi +} + +test $TMPDIR || TMPDIR=/tmp +TMPDIR=$TMPDIR/compare-with-local-$$ +mkdir $TMPDIR || exit 1 + +# Generate test file +cat > $TMPDIR/bar << EOF +This is an arla temporary test file. +You may remove it any time. +Kontrollen blinkar blå. +EOF + +cp $TMPDIR/bar bar +compare $TMPDIR/bar bar +mv bar $TMPDIR/bas +compare $TMPDIR/bar $TMPDIR/bas + # this is for later overwrite test + test -f bar && echo bar should not exist && exit 1 + cp $TMPDIR/bar bar + compare $TMPDIR/bar bar +cat $TMPDIR/bas > bat +compare $TMPDIR/bar bat +cat bat > $TMPDIR/bau +compare $TMPDIR/bar $TMPDIR/bau +mv $TMPDIR/bau bav +compare $TMPDIR/bar bav + # this is for later overwrite test + test -f $TMPDIR/bau && echo $TMPDIR/bau should not exist && exit 1 + cp $TMPDIR/bar $TMPDIR/bau +cp bav $TMPDIR/baw +compare $TMPDIR/bar $TMPDIR/baw + +# If we get so far we can write new files. +# Now test overwrite. + +# Generate test file slightly different +cat > $TMPDIR/bar << EOF +This is an arla temporary test file. +You may remove it any time. +Mera jul. +EOF + +cp $TMPDIR/bar bar +compare $TMPDIR/bar bar +mv bar $TMPDIR/bas +compare $TMPDIR/bar $TMPDIR/bas +cat $TMPDIR/bas > bat +compare $TMPDIR/bar bat +cat bat > $TMPDIR/bau +compare $TMPDIR/bar $TMPDIR/bau +mv $TMPDIR/bau bav +compare $TMPDIR/bar bav +cp bav $TMPDIR/baw +compare $TMPDIR/bar $TMPDIR/baw + +${objdir}/rm-rf $TMPDIR +exit 0 diff --git a/src/tests/copy-and-diff-gnu-mirror b/src/tests/copy-and-diff-gnu-mirror new file mode 100755 index 000000000..3f608a815 --- /dev/null +++ b/src/tests/copy-and-diff-gnu-mirror @@ -0,0 +1,7 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ; exit 0 ; fi +if test "X$LARGE" = "X" ; then echo "Not running large test $0" ; exit 0 ; fi +original=${1-$AFSROOT/stacken.kth.se/ftp/pub} +(cd $original; tar cvf - gnu) 2>&4 | tar xvf - >&4 +find gnu -type f -exec cmp '{}' $original/'{}' \; diff --git a/src/tests/copy-file b/src/tests/copy-file new file mode 100755 index 000000000..ade094666 --- /dev/null +++ b/src/tests/copy-file @@ -0,0 +1,26 @@ +#!/bin/sh +# $Id$ +cat > foo < 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 index 000000000..9864cddb7 --- /dev/null +++ b/src/tests/create-dirs.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#endif + +static int +creat_dirs (int count) +{ + int i; + + for (i = 0; i < count; ++i) { + char num[17]; + int ret; + + snprintf (num, sizeof(num), "%d", i); + + ret = mkdir (num, 0777); + if (ret < 0) + err (1, "mkdir %s", num); + } + return 0; +} + +static void +usage (int ret) +{ + fprintf (stderr, "%s number-of-dirs\n", __progname); + exit (ret); +} + +int +main(int argc, char **argv) +{ + char *ptr; + int count; + + + if (argc != 2) + usage (1); + + count = strtol (argv[1], &ptr, 0); + if (count == 0 && ptr == argv[1]) + errx (1, "'%s' not a number", argv[1]); + + return creat_dirs (count); +} diff --git a/src/tests/create-files.c b/src/tests/create-files.c new file mode 100644 index 000000000..50eca7055 --- /dev/null +++ b/src/tests/create-files.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#undef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#undef min +#define min(a,b) ((a) < (b) ? (a) : (b)) + +#ifdef RCSID +RCSID("$Id$"); +#endif + +static int +creat_files (int count, long startsize) +{ + int i; + long size = 0; + + for (i = 0; i < count; ++i) { + char num[17]; + int fd; + + snprintf (num, sizeof(num), "%d", i); + + fd = open (num, O_WRONLY | O_CREAT | O_EXCL, 0777); + if (fd < 0) + err (1, "open %s", num); + size = startsize; + while (size > 0) { + char buf[8192]; + size_t len; + ssize_t ret; + + len = min(sizeof(buf), size); + + ret = write (fd, buf, len); + if (ret < 0) + err (1, "write to %s", num); + if (ret != len) + errx (1, "short write to %s", num); + size -= ret; + } + if (close (fd) < 0) + err (1, "close %s", num); + } + return 0; +} + +static void +usage (int ret) +{ + fprintf (stderr, "%s number-of-files size-of-files\n", __progname); + exit (ret); +} + +int +main(int argc, char **argv) +{ + char *ptr; + int count; + long size; + + + if (argc != 3) + usage (1); + + count = strtol (argv[1], &ptr, 0); + if (count == 0 && ptr == argv[1]) + errx (1, "'%s' not a number", argv[1]); + + size = strtol (argv[2], &ptr, 0); + if (size == 0 && ptr == argv[2]) + errx (1, "`%s' not a number", argv[2]); + + return creat_files (count, size); +} diff --git a/src/tests/create-remove-dirs b/src/tests/create-remove-dirs new file mode 100644 index 000000000..58175ab63 --- /dev/null +++ b/src/tests/create-remove-dirs @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ; exit 0 ; fi +$objdir/create-remove dir 1000 diff --git a/src/tests/create-remove-files b/src/tests/create-remove-files new file mode 100644 index 000000000..19cb16151 --- /dev/null +++ b/src/tests/create-remove-files @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ; exit 0 ; fi +$objdir/create-remove file 1000 diff --git a/src/tests/create-remove.c b/src/tests/create-remove.c new file mode 100644 index 000000000..8debf07c3 --- /dev/null +++ b/src/tests/create-remove.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#endif + +static int +creat_dir (const char *name) +{ + int ret = mkdir (name, 0777); + if (ret < 0) err (1, "mkdir %s", name); + return 0; +} + +static int +remove_dir (const char *name) +{ + int ret = rmdir (name); + if (ret < 0) err (1, "rmdir %s", name); + return 0; +} + +static int +creat_file (const char *name) +{ + int ret = open (name, O_CREAT|O_RDWR, 0777); + if (ret < 0) err (1, "mkdir %s", name); + close (ret); + return 0; +} + +static int +unlink_file (const char *name) +{ + int ret = unlink (name); + if (ret < 0) err (1, "unlink %s", name); + return 0; +} + + +static void +usage (int ret) +{ + fprintf (stderr, "%s [file|dir] number-of-dirs\n", __progname); + exit (ret); +} + +#ifndef MAXPATHLEN +#ifdef PATH_MAX +#define MAXPATHLEN PATH_MAX +#else +#define MAXPATHLEN 4096 +#endif +#endif + +static int +creat_many (int num, + int (*c) (const char *name), + int (*d) (const char *name)) +{ + char name[MAXPATHLEN]; + + if (num < 0) + errx (1, "not be negative"); + + snprintf (name, sizeof(name), "foo-%d-%d", num, getpid()); + + while (num-- > 0) { + (c) (name); + (d) (name); + } + return 0; +} + + +int +main(int argc, char **argv) +{ + char *ptr; + int count; + + + if (argc != 3) + usage (1); + + count = strtol (argv[2], &ptr, 0); + if (count == 0 && ptr == argv[2]) + errx (1, "'%s' not a number", argv[2]); + + if (strcmp ("file", argv[1]) == 0) + return creat_many (count, creat_file, unlink_file); + else if (strcmp("dir", argv[1]) == 0) + return creat_many (count, creat_dir, remove_dir); + else + errx (1, "unknown type: %s", argv[1]); + return 0; +} diff --git a/src/tests/create-stat.c b/src/tests/create-stat.c new file mode 100644 index 000000000..c9ef14c07 --- /dev/null +++ b/src/tests/create-stat.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct VenusFid { + afs_int32 Cell; + struct AFSFid Fid; +}; + +#ifdef RCSID +RCSID("$Id$"); +#endif + +static void +usage (int ret) +{ + fprintf (stderr, "%s file\n", __progname); + exit (ret); +} + +int +main(int argc, char **argv) +{ + char *file; + int ret; + struct stat sb; + struct stat sb_new; + struct stat sb_old; + struct VenusFid fid; + char *filename; + ino_t afsfileid; + + if (argc != 2) + usage (1); + + file = argv[1]; + + asprintf (&filename, "%s.new", file); + + ret = open (file, O_RDWR, 0600); + if (ret < 0) + err (1, "open"); + close (ret); + + ret = open (filename, O_RDWR|O_CREAT|O_EXCL, 0600); + if (ret < 0) { + unlink(file); + err (1, "open"); + } + close (ret); + + ret = stat (file, &sb); + if (ret < 0) { + unlink(filename); + unlink(file); + err (1, "stat"); + } + + ret = lstat (filename, &sb_new); + if (ret < 0) { + unlink(filename); + unlink(file); + err (1, "stat"); + } + + if (sb.st_ino == sb_new.st_ino) + err (1, "sb.st_ino == sb_new.st_ino"); + + ret = lstat (file, &sb_old); + if (ret < 0) { + unlink(filename); + unlink(file); + err (1, "stat"); + } + + if (sb_old.st_ino == sb_new.st_ino) + err (1, "sb_old.st_ino == sb_new.st_ino"); + if (sb.st_ino == sb_new.st_ino) + err (1, "sb.st_ino == sb_new.st_ino"); + if (sb_old.st_ino != sb.st_ino) + err (1, "sb_old.st_ino != sb.st_ino"); + + ret = fs_getfid (file, &fid); + if (ret) { + unlink(file); + unlink(filename); + err (1, "fs_getfid: %d", ret); + } + + afsfileid = ((fid.Fid.Volume & 0x7FFF) << 16 | (fid.Fid.Vnode & 0xFFFFFFFF)); + if (sb.st_ino != afsfileid) { + unlink(file); + unlink(filename); + errx (1, "sb.st_ino(%ld) != afsfileid(%ld) (%d.%d.%d.%d)", + (long)sb.st_ino, (long)afsfileid, + fid.Cell, fid.Fid.Volume, fid.Fid.Vnode, fid.Fid.Unique); + } + + unlink(filename); + unlink(file); + + return 0; +} diff --git a/src/tests/create-symlinks.c b/src/tests/create-symlinks.c new file mode 100644 index 000000000..4dc022cd3 --- /dev/null +++ b/src/tests/create-symlinks.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#endif + +#define CONTENT_STRING "kaka" + +static FILE *verbose_fp = NULL; + +static int +creat_symlinks (int count) +{ + int ret; + int i; + + fprintf (verbose_fp, "creating:"); + + for (i = 0; i < count; ++i) { + char num[17]; + + fprintf (verbose_fp, " c%d", i); + fflush (verbose_fp); + + snprintf (num, sizeof(num), "%d", i); + + ret = symlink (CONTENT_STRING, num); + if (ret < 0) + err (1, "symlink %s", num); + } + fprintf (verbose_fp, "\n"); + return 0; +} + +#ifndef MAXPATHLEN +#ifdef PATH_MAX +#define MAXPATHLEN PATH_MAX +#else +#define MAXPATHLEN 4096 +#endif +#endif + +static int +verify_contents (int count) +{ + int ret, i; + char file[MAXPATHLEN]; + char content[MAXPATHLEN]; + + fprintf (verbose_fp, "reading:"); + for (i = 0; i < count; i++) { + fprintf (verbose_fp, " r%d", i); + fflush (verbose_fp); + + snprintf (file, sizeof(file), "%d", i); + ret = readlink (file, content, sizeof(content) - 1); + if (ret < 0) + err (1, "readlink: %d", i); + content[ret] = '\0'; + if (strcmp (CONTENT_STRING, content) != 0) + errx (1, "%s != %s", content, CONTENT_STRING); + } + fprintf (verbose_fp, "\n"); + return 0; +} + +static void +usage (int ret) +{ + fprintf (stderr, "%s number-of-symlinks\n", __progname); + exit (ret); +} + +int +main(int argc, char **argv) +{ + char *ptr; + int count; + + + if (argc != 2) + usage (1); + + verbose_fp = fdopen (4, "w"); + if (verbose_fp == NULL) { + verbose_fp = fopen ("/dev/null", "w"); + if (verbose_fp == NULL) + err (1, "fopen"); + } + + count = strtol (argv[1], &ptr, 0); + if (count == 0 && ptr == argv[1]) + errx (1, "'%s' not a number", argv[1]); + + return creat_symlinks (count) || + verify_contents(count); +} diff --git a/src/tests/dd b/src/tests/dd new file mode 100755 index 000000000..9f51153cb --- /dev/null +++ b/src/tests/dd @@ -0,0 +1,8 @@ +#!/bin/sh +# $Id$ +if test -r /dev/zero; then + dd if=/dev/zero of=foo bs=1k count=20 >/dev/null 2>/dev/null || exit 1 + rm foo || exit 1 +else + echo "not running dd (you have no /dev/zero)" +fi diff --git a/src/tests/deep-tree b/src/tests/deep-tree new file mode 100644 index 000000000..cafecd616 --- /dev/null +++ b/src/tests/deep-tree @@ -0,0 +1,6 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ;exit 0; fi + +mkdir foo && ( cd foo && $SHELL $SHELLVERBOSE ${srcdir}/dir-tree 5 "0 1 2 3 4" ) +${objdir}/rm-rf foo diff --git a/src/tests/deep-tree2 b/src/tests/deep-tree2 new file mode 100644 index 000000000..3252e422c --- /dev/null +++ b/src/tests/deep-tree2 @@ -0,0 +1,12 @@ +#!/bin/sh +# $Id$ + +mkdir foo + +b=foo +for a in 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z å ä ö; do + b=$b/$a + mkdir $b +done + +rm -rf foo \ No newline at end of file diff --git a/src/tests/dir-size-mismatch b/src/tests/dir-size-mismatch new file mode 100644 index 000000000..537de1325 --- /dev/null +++ b/src/tests/dir-size-mismatch @@ -0,0 +1,10 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ;exit 0; fi + +for i in `awk 'BEGIN {for(i=0; i < 1000; ++i) printf "%d\n", i}' /dev/null`; do + ln -s hejsan qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq$i +done +find . -name 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq*' -print | xargs rm +ln -s foo bar +rm bar diff --git a/src/tests/dir-tree b/src/tests/dir-tree new file mode 100755 index 000000000..bb680987e --- /dev/null +++ b/src/tests/dir-tree @@ -0,0 +1,22 @@ +#!/bin/sh +# $Id$ + +####################################################### +# +# Make a directory tree of directories +# dir-tree + +# +####################################################### + +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 index 000000000..f27072363 --- /dev/null +++ b/src/tests/directory.c @@ -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 +#include +#include + +#include "dumpscan.h" +#include "dumpscan_errs.h" +#include "xf_errs.h" +#include "dumpfmt.h" +#include "internal.h" + +#include + +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 . + * + * 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 + * + * 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 index 000000000..8d228fd44 --- /dev/null +++ b/src/tests/dump.c @@ -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 index 000000000..766b6977f --- /dev/null +++ b/src/tests/dumpfmt.h @@ -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 index 000000000..a6b3a2442 --- /dev/null +++ b/src/tests/dumpscan.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 index 000000000..22c38c397 --- /dev/null +++ b/src/tests/dumpscan_errs.et @@ -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 index 000000000..5f6e73b9a --- /dev/null +++ b/src/tests/dumptool.c @@ -0,0 +1,2640 @@ +/* + * $Id$ + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#if !defined(PRE_AFS_36) && !defined(RESIDENCY) +#include +#endif /* !defined(PRE_AFS_36) && !defined(RESIDENCY) */ +#include +#include + +#ifdef RESIDENCY +#include +#include +#endif /* RESIDENCY */ + +#include + +/* + * Sigh. Linux blows it again + */ + +#ifdef linux +#include +#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 +#endif /* RESIDENCY */ diff --git a/src/tests/dup2-and-unlog.c b/src/tests/dup2-and-unlog.c new file mode 100644 index 000000000..c9c16b210 --- /dev/null +++ b/src/tests/dup2-and-unlog.c @@ -0,0 +1,32 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +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 index 000000000..7617a1fc2 --- /dev/null +++ b/src/tests/echo-n.c @@ -0,0 +1,18 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +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 index 000000000..cc1b03178 --- /dev/null +++ b/src/tests/err.c @@ -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 +RCSID("$Id$"); +#endif + +#include "err.h" + +void +err(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verr(eval, fmt, ap); + va_end(ap); +} diff --git a/src/tests/err.h b/src/tests/err.h new file mode 100644 index 000000000..e4dc06dee --- /dev/null +++ b/src/tests/err.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __ERR_H__ +#define __ERR_H__ + +#include +#include +#include +#include +#include + +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 index 000000000..da47e4da6 --- /dev/null +++ b/src/tests/errx.c @@ -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 +RCSID("$Id$"); +#endif + +#include "err.h" + +void +errx(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(eval, fmt, ap); + va_end(ap); +} diff --git a/src/tests/exec b/src/tests/exec new file mode 100755 index 000000000..f6535c053 --- /dev/null +++ b/src/tests/exec @@ -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 index 000000000..c2ff56fe0 --- /dev/null +++ b/src/tests/exit-wo-close.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#endif + +static int +child (const char *filename) +{ + int fd; + int ret; + + fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) + err (1, "open %s", filename); + ret = write (fd, "hej", 3); + if (ret != 3) + err (1, "write %s", filename); + return 0; +} + +static int +parent (const char *filename, pid_t child_pid) +{ + int stat; + int ret; + int fd; + struct stat sb; + char buf[3]; + + ret = waitpid (child_pid, &stat, 0); + if (ret < 0) + err (1, "waitpid %u", (unsigned)child_pid); + if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0) + errx (1, "weird child %u", (unsigned)child_pid); + fd = open (filename, O_RDONLY, 0); + if (fd < 0) + err (1, "open %s", filename); + ret = fstat (fd, &sb); + if (ret < 0) + err (1, "fstat %s", filename); + if (sb.st_size != 3) + errx (1, "size of %s = %u != 3", filename, (unsigned)sb.st_size); + ret = read (fd, buf, sizeof(buf)); + if (ret < 0) + err (1, "read %s", filename); + if (ret != 3) + errx (1, "short read from %s", filename); + if (memcmp (buf, "hej", 3) != 0) + errx (1, "bad contents of %s = `%.3s'\n", filename, buf); + close (fd); + return 0; +} + +static int +doit (const char *filename) +{ + pid_t pid; + + pid = fork (); + if (pid < 0) + err (1, "fork"); + + if (pid == 0) + return child (filename); + else + return parent (filename, pid); +} + +int +main(int argc, char **argv) +{ + const char *file = "foo"; + + + if (argc != 2 && argc != 1) + errx (1, "usage: %s [file]", argv[0]); + if (argc == 2) + file = argv[1]; + return doit (file); +} diff --git a/src/tests/extcopyin b/src/tests/extcopyin new file mode 100755 index 000000000..a5f5790a4 --- /dev/null +++ b/src/tests/extcopyin @@ -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 index 000000000..0347dd882 --- /dev/null +++ b/src/tests/extcopyout @@ -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 index 000000000..c9a987902 --- /dev/null +++ b/src/tests/fcachesize-dir @@ -0,0 +1,13 @@ +#!/bin/sh +# $Id$ + +FS=${FS:-${objdir}/../appl/fs/fs} +SIZE1=`$FS getcache -b | awk '{ print $4 ; exit }'` +mkdir foo +SIZE2=`$FS getcache -b | awk '{ print $4 ; exit }'` +test $SIZE2 = `expr $SIZE1 + 2048` || exit 1 +rmdir foo +#SIZE3=`$FS getcache -b | awk '{ print $4 ; exit }'` +#test $SIZE3 = $SIZE1 || exit 1 + +exit 0 diff --git a/src/tests/fcachesize-file-small b/src/tests/fcachesize-file-small new file mode 100644 index 000000000..62800c1a2 --- /dev/null +++ b/src/tests/fcachesize-file-small @@ -0,0 +1,13 @@ +#!/bin/sh +# $Id$ + +FS=${FS:-${objdir}/../appl/fs/fs} +SIZE1=`$FS getcache -b | awk '{ print $4 ; exit }'` +echo foo > foo +SIZE2=`$FS getcache -b | awk '{ print $4 ; exit }'` +test $SIZE2 = `expr $SIZE1 + 4` || exit 1 +rm foo +#SIZE3=`$FS getcache -b | awk '{ print $4 ; exit }'` +#test $SIZE3 = $SIZE1 || exit 1 + +exit 0 diff --git a/src/tests/fcachesize-read-file b/src/tests/fcachesize-read-file new file mode 100644 index 000000000..6dd4b7289 --- /dev/null +++ b/src/tests/fcachesize-read-file @@ -0,0 +1,14 @@ +#!/bin/sh +# $Id$ + +FS=${FS:-${objdir}/../appl/fs/fs} +SIZE1=`$FS getcache | awk '{ print $8 ; exit }'` +SIZE2=`expr $SIZE1 + 4` +if test -w /dev/null; then + dd if=../foo of=/dev/null bs=1k count=$SIZE2 >/dev/null 2>/dev/null || exit 1 + rm ../foo || exit 1 +else + echo "not running dd (you have no /dev/null)" +fi + +exit 0 diff --git a/src/tests/fcachesize-write-file b/src/tests/fcachesize-write-file new file mode 100644 index 000000000..8b60ad20a --- /dev/null +++ b/src/tests/fcachesize-write-file @@ -0,0 +1,13 @@ +#!/bin/sh +# $Id$ + +FS=${FS:-${objdir}/../appl/fs/fs} +SIZE1=`$FS getcache | awk '{ print $8 ; exit }'` +SIZE2=`expr $SIZE1 + 4` +if test -r /dev/zero; then + dd if=/dev/zero of=../foo bs=1k count=$SIZE2 >/dev/null 2>/dev/null || exit 1 +else + echo "not running dd (you have no /dev/zero)" +fi + +exit 0 diff --git a/src/tests/fchmod.c b/src/tests/fchmod.c new file mode 100644 index 000000000..3dbee05af --- /dev/null +++ b/src/tests/fchmod.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include + +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 index 000000000..98b2b4dd6 --- /dev/null +++ b/src/tests/fhbench.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_IOCCOM_H +#include +#endif + +#include + +#include +#include + +#include +#include + +RCSID("$Id$"); + +struct fhb_handle { + char data[512]; +}; + +static int help_flag; +static int num_files; +static int write_file = 0; +static int num_runs = 3; + +static struct agetargs args[] = { + {"num", 'n', aarg_integer, &num_files, "number of files"}, + {"write", 'w', aarg_integer, &write_file, "write num kb"}, + {"runs", 'r', aarg_integer, &num_runs, "number of runs"}, + {"help", 0, aarg_flag, &help_flag, NULL, NULL}, + {NULL, 0, aarg_end, NULL, NULL, NULL} +}; + + +static void +fhb_fhget (char *filename, struct fhb_handle *handle) +{ + int ret = 0; +#if defined(HAVE_GETFH) && defined(HAVE_FHOPEN) + { + fhandle_t fh; + + ret = getfh (filename, &fh); + if (ret) + err (1, "getfh"); + memcpy (handle, &fh, sizeof(fh)); + } +#endif + { + struct ViceIoctl vice_ioctl; + + vice_ioctl.in = NULL; + vice_ioctl.in_size = 0; + + vice_ioctl.out = (caddr_t)handle; + vice_ioctl.out_size = sizeof(*handle); + + ret = pioctl (filename, VIOC_FHGET, &vice_ioctl, 0); + if (ret) + errx (1, "k_pioctl"); + } +} + + +static int +fhb_fhopen (struct fhb_handle *handle, int flags) +{ + int ret; +#if defined(HAVE_GETFH) && defined(HAVE_FHOPEN) + { + fhandle_t fh; + + memcpy (&fh, handle, sizeof(fh)); + ret = fhopen (&fh, flags); + if (ret >= 0) + return ret; + } +#endif + +#ifdef KERBEROS /* really KAFS */ + { + struct ViceIoctl vice_ioctl; + + vice_ioctl.in = (caddr_t)handle; + vice_ioctl.in_size = sizeof(*handle); + + vice_ioctl.out = NULL; + vice_ioctl.out_size = 0; + + ret = k_pioctl (NULL, VIOC_FHOPEN, &vice_ioctl, flags); + if (ret >= 0) + return ret; + } +#endif + errx (1, "fhopen/k_pioctl"); +} + +static void +nop_call (void) +{ +#ifdef KERBEROS /* really KAFS */ + { + struct ViceIoctl vice_ioctl; + char c[8]; + int ret; + + vice_ioctl.in = (caddr_t)&c; + vice_ioctl.in_size = sizeof(c); + + vice_ioctl.out = NULL; + vice_ioctl.out_size = 0; + + ret = k_pioctl (NULL, VIOC_XFSDEBUG, &vice_ioctl, 0); + if (ret < 0) + err (1, "k_pioctl"); + } +#else + { + static first = 1; + if (first) { + warnx ("can't test this"); + first = 0; + } + } +#endif +} + +static void +create_file (int num, struct fhb_handle *handle) +{ + int fd; + char filename[1024]; + + snprintf (filename, sizeof(filename), "file-%d", num); + + fd = open (filename, O_CREAT|O_EXCL|O_RDWR, 0666); + if (fd < 0) + err (1, "open"); + + close (fd); + + fhb_fhget(filename, handle); +} + +char databuf[1024]; + +static void +write_to_file (int fd, int num) +{ + int ret; + while (num > 0) { + ret = write (fd, databuf, sizeof(databuf)); + if (ret != sizeof(databuf)) + err (1, "write"); + num--; + } +} + +static void +fhopen_file (int num, struct fhb_handle *handle) +{ + int fd; + + fd = fhb_fhopen(handle, O_RDWR); + if (fd < 0) + err (1, "open"); + + if (write_file) + write_to_file(fd, write_file); + close(fd); +} + +static void +open_file (int num) +{ + int fd; + char filename[1024]; + + snprintf (filename, sizeof(filename), "file-%d", num); + + fd = open (filename, O_RDWR, 0666); + if (fd < 0) + err (1, "open"); + + if (write_file) + write_to_file(fd, write_file); + + close (fd); +} + +static void +unlink_file (int num) +{ + int ret; + char filename[1024]; + + snprintf (filename, sizeof(filename), "file-%d", num); + + ret = unlink(filename); + if (ret < 0) + err (1, "unlink"); +} + +struct timeval time1, time2; + +static void +starttesting(char *msg) +{ + printf("testing %s...\n", msg); + fflush (stdout); + gettimeofday(&time1, NULL); +} + +static void +endtesting(void) +{ + gettimeofday(&time2, NULL); + timevalsub(&time2, &time1); + printf("timing: %ld.%06ld\n", (long)time2.tv_sec, (long)time2.tv_usec); +} + +static void +usage (int exit_val) +{ + aarg_printusage (args, NULL, "number of files", AARG_GNUSTYLE); + exit (exit_val); +} + +static void +open_bench (int i, struct fhb_handle *handles) +{ + printf ("====== test run %d\n" + "==================\n", + i); + + starttesting ("fhopening files"); + for (i = 0; i < num_files; i++) + fhopen_file (i, &handles[i]); + endtesting (); + + starttesting ("opening files"); + for (i = 0; i < num_files; i++) + open_file (i); + endtesting (); +} + +int +main (int argc, char **argv) +{ + int optind = 0; + int i; + struct fhb_handle *handles; + + + if (agetarg (args, argc, argv, &optind, AARG_GNUSTYLE)) + usage (1); + + if (help_flag) + usage (0); + + if (num_files <= 0) + usage (1); + + if (write_file < 0) + usage (1); + +#ifdef KERBEROS + if (!k_hasafs()) +#endif + errx (1, "no afs kernel module"); + + handles = emalloc (num_files * sizeof(*handles)); + + starttesting ("creating files"); + for (i = 0; i < num_files; i++) + create_file (i, &handles[i]); + endtesting (); + + for (i = 0 ; i < num_runs; i++) + open_bench (i, handles); + + printf ( "==================\n"); + starttesting ("unlink files"); + for (i = 0; i < num_files; i++) + unlink_file (i); + endtesting (); + + printf ( "==================\n"); + starttesting ("nop call"); + for (i = 0; i < num_files; i++) + nop_call (); + endtesting (); + + return 0; +} diff --git a/src/tests/find-and-cat-netbsd b/src/tests/find-and-cat-netbsd new file mode 100644 index 000000000..9048eccc4 --- /dev/null +++ b/src/tests/find-and-cat-netbsd @@ -0,0 +1,5 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ; exit 0 ; fi +netbsd_ftp_mirror=${1-$AFSROOT/stacken.kth.se/ftp/pub/NetBSD/NetBSD-1.4/} +find ${netbsd_ftp_mirror} -type f -exec cat '{}' \; > /dev/null diff --git a/src/tests/find-linux b/src/tests/find-linux new file mode 100644 index 000000000..d34770729 --- /dev/null +++ b/src/tests/find-linux @@ -0,0 +1,5 @@ +#!/bin/sh +# $Id$ +if test "X$FAST" != "X" ; then echo "Not running $0" ; exit 0 ; fi +linux_src=${1-$AFSROOT/pdc.kth.se/src/OS/Linux/} +(cd ${linux_src} ; find . ) >&4 diff --git a/src/tests/fs-flush b/src/tests/fs-flush new file mode 100644 index 000000000..36fe37e7c --- /dev/null +++ b/src/tests/fs-flush @@ -0,0 +1,6 @@ +#!/bin/sh +# $Id$ +FS=${FS:-${objdir}/../appl/fs/fs} +> foobar +${FS} flush +test -f foobar || exit 1 \ No newline at end of file diff --git a/src/tests/fs-sa-la b/src/tests/fs-sa-la new file mode 100755 index 000000000..20f0ccb0c --- /dev/null +++ b/src/tests/fs-sa-la @@ -0,0 +1,6 @@ +#!/bin/sh +# $Id$ +FS=${FS:-${objdir}/../appl/fs/fs} +${FS} sa . kalle-anka-nu rl 2>&4 +${FS} la >&4 2>&4 +exit 0 diff --git a/src/tests/fs_lib.c b/src/tests/fs_lib.c new file mode 100644 index 000000000..04a56b374 --- /dev/null +++ b/src/tests/fs_lib.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 index 000000000..0b67ae8bc --- /dev/null +++ b/src/tests/fsx.c @@ -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 +#include +#if defined(_UWIN) || defined(__linux) +# include +# include +# include +# include +# define MAP_FILE 0 +#else +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..ca3782e8b --- /dev/null +++ b/src/tests/ga-test.c @@ -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 +#endif + +#include + +#include + +#include + +RCSID("$Id$"); + +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 index 000000000..80d91fab0 --- /dev/null +++ b/src/tests/generic-build @@ -0,0 +1,18 @@ +#!/bin/sh +# $Id$ +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 index 000000000..bb640ffac --- /dev/null +++ b/src/tests/getdents-and-unlink1 @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id$ +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 index 000000000..2c2393384 --- /dev/null +++ b/src/tests/getdents-and-unlink2 @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id$ +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 index 000000000..9d04bc385 --- /dev/null +++ b/src/tests/getdents-and-unlink3 @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id$ +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 index 000000000..15134bfe3 --- /dev/null +++ b/src/tests/grind-arla-with-cvs @@ -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 index 000000000..a6f08ef84 --- /dev/null +++ b/src/tests/hardlink1.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..4f5fbd434 --- /dev/null +++ b/src/tests/hardlink2.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..134dcfb8a --- /dev/null +++ b/src/tests/hardlink3 @@ -0,0 +1,28 @@ +#!/bin/sh +# $Id$ + +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 index 000000000..27341397e --- /dev/null +++ b/src/tests/hardlink4.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..3a1ab1b37 --- /dev/null +++ b/src/tests/hardlink5 @@ -0,0 +1,11 @@ +#!/bin/sh +# $Id$ + +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 index 000000000..09a7a5a5d --- /dev/null +++ b/src/tests/hello-world.in @@ -0,0 +1,8 @@ +#!/bin/sh +# $Id$ +cat < 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 index 000000000..4d4a68f7c --- /dev/null +++ b/src/tests/int64.c @@ -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 +#include +#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 index 000000000..964605238 --- /dev/null +++ b/src/tests/intNN.h @@ -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 +#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 index 000000000..04233dbb0 --- /dev/null +++ b/src/tests/internal.h @@ -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 index 000000000..7c2d9dfeb --- /dev/null +++ b/src/tests/intr-read.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#include + +#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 index 000000000..97820ece3 --- /dev/null +++ b/src/tests/intr-read1 @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ +$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 index 000000000..75be38866 --- /dev/null +++ b/src/tests/invalidate-file.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include + +#include + +RCSID("$Id$"); + +#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 index 000000000..d44609d3f --- /dev/null +++ b/src/tests/kill-softer.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..d9a6a4c36 --- /dev/null +++ b/src/tests/kill-softly.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..2e163e3a9 --- /dev/null +++ b/src/tests/kotest @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ + +exec ${objdir}/../lib/ko/kotest diff --git a/src/tests/large-dir-16384 b/src/tests/large-dir-16384 new file mode 100755 index 000000000..a23c56627 --- /dev/null +++ b/src/tests/large-dir-16384 @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ +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 index 000000000..589a2d98e --- /dev/null +++ b/src/tests/large-dir-extra @@ -0,0 +1,7 @@ +#!/bin/sh +# $Id$ +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 index 000000000..13f6cf543 --- /dev/null +++ b/src/tests/large-dir.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..14b9a8266 --- /dev/null +++ b/src/tests/large-dir2.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..a171c8104 --- /dev/null +++ b/src/tests/large-dir3.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..fa9f6f0fb --- /dev/null +++ b/src/tests/large-filename @@ -0,0 +1,6 @@ +#!/bin/sh +# $Id$ + +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 index 000000000..93ae733d0 --- /dev/null +++ b/src/tests/ls-afs @@ -0,0 +1,5 @@ +#!/bin/sh +# $Id$ +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 index 000000000..9a042997d --- /dev/null +++ b/src/tests/make-page.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include + +#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 index 000000000..4e88fb295 --- /dev/null +++ b/src/tests/many-dirs @@ -0,0 +1,6 @@ +#!/bin/sh +# $Id$ + +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 index 000000000..1ac81680f --- /dev/null +++ b/src/tests/many-fetchs @@ -0,0 +1,15 @@ +#!/bin/sh +# $Id$ + +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 index 000000000..6b6ccc8d3 --- /dev/null +++ b/src/tests/many-files @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ + +$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 index 000000000..0c12b82cf --- /dev/null +++ b/src/tests/many-files-with-content @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ + +$objdir/create-files 1000 10 diff --git a/src/tests/many-stores b/src/tests/many-stores new file mode 100644 index 000000000..f64e4ce89 --- /dev/null +++ b/src/tests/many-stores @@ -0,0 +1,10 @@ +#!/bin/sh +# $Id$ + +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 index 000000000..2bf1b6f91 --- /dev/null +++ b/src/tests/many-symlinks @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ + +$objdir/create-symlinks 1000 diff --git a/src/tests/mkdir b/src/tests/mkdir new file mode 100644 index 000000000..bfa7b574b --- /dev/null +++ b/src/tests/mkdir @@ -0,0 +1,10 @@ +#!/bin/sh +# $Id$ +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 index 000000000..f2247a235 --- /dev/null +++ b/src/tests/mkdir-lnk @@ -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 index 000000000..aa6d50270 --- /dev/null +++ b/src/tests/mkdir1 @@ -0,0 +1,7 @@ +#!/bin/sh +# $Id$ +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 index 000000000..4a5272264 --- /dev/null +++ b/src/tests/mkdir2.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..576d4e80b --- /dev/null +++ b/src/tests/mkdir3.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..3b67790ff --- /dev/null +++ b/src/tests/mkm-rmm @@ -0,0 +1,13 @@ +#!/bin/sh +# $Id$ +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 index 000000000..0444ec6c1 --- /dev/null +++ b/src/tests/mmap-and-read.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..3893022dd --- /dev/null +++ b/src/tests/mmap-cat.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#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 index 000000000..0117d6b37 --- /dev/null +++ b/src/tests/mmap-shared-write.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..d491b0ff0 --- /dev/null +++ b/src/tests/mmap-vs-read.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..55e25e47d --- /dev/null +++ b/src/tests/mmap-vs-read2.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..7213d981f --- /dev/null +++ b/src/tests/mountpoint.in @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id$ +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 index 000000000..39afb043f --- /dev/null +++ b/src/tests/null-search.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include + +#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 index 000000000..ec627b778 --- /dev/null +++ b/src/tests/parallel1 @@ -0,0 +1,5 @@ +#!/bin/sh +# $Id$ +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 index 000000000..edf6903b5 --- /dev/null +++ b/src/tests/parsedump.c @@ -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 index 000000000..037ea3838 --- /dev/null +++ b/src/tests/parsetag.c @@ -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 index 000000000..09f86ce1d --- /dev/null +++ b/src/tests/parsevnode.c @@ -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 +#include +#include + +#include "dumpscan.h" +#include "dumpscan_errs.h" +#include "dumpfmt.h" +#include "internal.h" + +#include +#include + +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 index 000000000..86143dd8e --- /dev/null +++ b/src/tests/parsevol.c @@ -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 index 000000000..ee3af28f1 --- /dev/null +++ b/src/tests/pathname.c @@ -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 +#include + +#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 index 000000000..f25e36ac0 --- /dev/null +++ b/src/tests/pine.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#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 index 000000000..95dcac2b3 --- /dev/null +++ b/src/tests/primitive.c @@ -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 +#include +#include +#include +#include + +#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 index 000000000..5218bffc3 --- /dev/null +++ b/src/tests/ptsadduser.pl @@ -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 index 000000000..812eac716 --- /dev/null +++ b/src/tests/ptschown.pl @@ -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 index 000000000..8a904c0db --- /dev/null +++ b/src/tests/ptscreategroup.pl @@ -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 index 000000000..2286fc8a3 --- /dev/null +++ b/src/tests/ptscreateuser.pl @@ -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 index 000000000..11dbbc040 --- /dev/null +++ b/src/tests/ptsdeletegroup.pl @@ -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 index 000000000..f4f2d079e --- /dev/null +++ b/src/tests/ptsdeleteuser.pl @@ -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 index 000000000..4297a5320 --- /dev/null +++ b/src/tests/ptsexaminegroup.pl @@ -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 index 000000000..c869fed7c --- /dev/null +++ b/src/tests/ptsexamineuser.pl @@ -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 index 000000000..dc42ed730 --- /dev/null +++ b/src/tests/ptslistmax.pl @@ -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 index 000000000..0133f9c7c --- /dev/null +++ b/src/tests/ptslistown.pl @@ -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 index 000000000..ecff23c54 --- /dev/null +++ b/src/tests/ptsmembersgroup.pl @@ -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 index 000000000..4172b4e2f --- /dev/null +++ b/src/tests/ptsmembersuser.pl @@ -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 index 000000000..67c165a92 --- /dev/null +++ b/src/tests/ptsremove.pl @@ -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 index 000000000..08c401101 --- /dev/null +++ b/src/tests/ptssetf.pl @@ -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 index 000000000..ab4c456c4 --- /dev/null +++ b/src/tests/ptssetmax.pl @@ -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 index 000000000..4e2cd43f4 --- /dev/null +++ b/src/tests/read-vs-mmap.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..f2dcd3e01 --- /dev/null +++ b/src/tests/read-vs-mmap2.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..22ecf9da9 --- /dev/null +++ b/src/tests/read-write.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..fb07d2fd8 --- /dev/null +++ b/src/tests/readdir-vs-lstat.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..209fd3449 --- /dev/null +++ b/src/tests/readfile-wo-create @@ -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 index 000000000..8ff803981 --- /dev/null +++ b/src/tests/reauth.pl @@ -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 index 000000000..79e359a1b --- /dev/null +++ b/src/tests/rename-under-feet.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#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 index 000000000..d899ae8a8 --- /dev/null +++ b/src/tests/rename1 @@ -0,0 +1,7 @@ +#!/bin/sh +# $Id$ +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 index 000000000..d3fa0ccca --- /dev/null +++ b/src/tests/rename2 @@ -0,0 +1,7 @@ +#!/bin/sh +# $Id$ +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 index 000000000..44481f2e7 --- /dev/null +++ b/src/tests/rename3 @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id$ +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 index 000000000..6948b60cc --- /dev/null +++ b/src/tests/rename4 @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id$ +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 index 000000000..92441cff7 --- /dev/null +++ b/src/tests/rename5.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include + +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 index 000000000..3b6238700 --- /dev/null +++ b/src/tests/rename6.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include + +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 index 000000000..ece84b115 --- /dev/null +++ b/src/tests/repair.c @@ -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 +#include +#include +#include +#include + +#include "dumpscan.h" +#include "dumpscan_errs.h" +#include "dumpfmt.h" + +#include +#include +#include + +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 index 000000000..80b021a1d --- /dev/null +++ b/src/tests/rewrite-emacs @@ -0,0 +1,10 @@ +#!/bin/sh +# $Id$ +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 index 000000000..c8ce4e494 --- /dev/null +++ b/src/tests/rm-rf.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..80febe9d5 --- /dev/null +++ b/src/tests/run-fsx @@ -0,0 +1,7 @@ +#!/bin/sh +# $Id$ +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 100755 index 000000000..10000f64f --- /dev/null +++ b/src/tests/run-rcs @@ -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 index 000000000..d1559d630 --- /dev/null +++ b/src/tests/run-suite.pl @@ -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 [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 option specifies the name of the cell. + +The B 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() { + 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() { +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() { + 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 100755 index 000000000..3e8ba3a21 --- /dev/null +++ b/src/tests/run-tests.in @@ -0,0 +1,417 @@ +#!/bin/sh +# +# $Id$ +# +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$"; 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 index 000000000..58ca72637 --- /dev/null +++ b/src/tests/setgroups @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ + +$objdir/test-setgroups nobody 1>&4 diff --git a/src/tests/setpag b/src/tests/setpag new file mode 100755 index 000000000..eba07e414 --- /dev/null +++ b/src/tests/setpag @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id$ + +$objdir/test-setpag 1>&4 diff --git a/src/tests/shallow-tree b/src/tests/shallow-tree new file mode 100644 index 000000000..1d42261be --- /dev/null +++ b/src/tests/shallow-tree @@ -0,0 +1,5 @@ +#!/bin/sh +# $Id$ + +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 index 000000000..be6342614 --- /dev/null +++ b/src/tests/stagehdr.c @@ -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 +#include +#include +#include + +#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 index 000000000..985fe9e59 --- /dev/null +++ b/src/tests/stagehdr.h @@ -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 index 000000000..90b92cd2a --- /dev/null +++ b/src/tests/still-there-p.c @@ -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 +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include + +#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 index 000000000..fb02f714f --- /dev/null +++ b/src/tests/strange-characters @@ -0,0 +1,7 @@ +#!/bin/sh +# $Id$ +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 index 000000000..ba3419cc5 --- /dev/null +++ b/src/tests/strange-characters-c.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..3986e448d --- /dev/null +++ b/src/tests/strange-other-characters @@ -0,0 +1,5 @@ +#!/bin/sh +# $Id$ +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 index 000000000..f858138e5 --- /dev/null +++ b/src/tests/symlink.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 0000000000000000000000000000000000000000..18484825bc3223a831de75dbfa55376be242cae3 GIT binary patch literal 3588 zcmZSFyiiz)fq{XsOo4&nXkLk4X)@fX&_c2h{y*K&Nh~|X^tRPsEwsvl`Dwl1S0$$70U8+ zN^?^cN=q_xGD|8IGK&?8O7rqE^V0Pgd>O(S*g?v00T&xf?SLqtEFUwFU|NmzL*_mTKhhQLS(0YzwL7%Bc8_2*~^5DEcMqX$$u{4Zh50XF4;EJox;53m`N z4irmCVq5}h`7nZ8KEQ?p3xmeft+8hW7}U=_UGOV>{q_{2Du;jUreBP&v8oolvfIYD zblEYjRUsVuyIwgv9DnWCx*(Xp+w}TgkB+s6R|Ysw%d}U%b7=YJV3ogrEYC~t_h0+t zvd#Mk?|O{dAMgEnUh(#H&sNv_Zz6Us%bFv!Q~1oh+9~;ayLwA=+)MNug{}5Boct|k z=Dj2QleKA!Oi_g1>CE54UpH5LTk<5CVWz>p^7zSa9!#H`-?J5U7pU1WEcb6-XCwFK zmWg@TLP=}mMm*{xM%XB7q?G3 zIE1UDFZW{Yd6;Jsa5kjuO_gM-^@YrTFDCo4i_Sdutf*?=lg(2(S95<~@8rZ>*L!9^ zr^Kph>Ql=f&)l2gy+h=$ue{;amb*tc)mwJ!*Vj+Zk~*D#e`1(kb^Ao+pqNEd3Xhm& zTU9RWx0E;7+N*G8(zcTKOu6Z*DXwLcFX)=zZ*zMm$~^h{w!mpg>jkZpSLQAC3@r=~ zjtO+Xy{BSJQcGk})G}9|hUc#z+*+KfS$Vi7qiMF%1dhqg$!lJ$Y75m7+`lf?UHC`; z!PeX1_hK1*w`zz^yKtxB#O3(?XQW>Ja4Pwswt3gyylET66i$5ax>-5-pqs$vCEsK> z-+CgkA$J{ji`N0K=k2ynj^463{ZOTbt)KaC=_iLBD@5mN_33WSsj|&YkockM7<|n$oo&ZiD`D=F=MOl%5zPx0zOd=< zPm$2ik?ESEM`!e;_-&dHl`@g}3TUrT9rw+Wl4Gy%7Ayv-Esb>fMGDv9C=WIQ}-t z-rAH9_Ti{-QBTHkq09?QB_?@f8lTjg{5NMN)6#=nzg1Sf+F-mzs^N-G6fE|Gj+IhE>#np zw|Mc4?|FM>e%5dM<|8HfoO$7I!A0@Yy!5VrHob2;Ie>RA3)}GkrGu|DPB;1SuH&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 index 000000000..47d5b1a1f --- /dev/null +++ b/src/tests/test-parallel1.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..e18fb2ae0 --- /dev/null +++ b/src/tests/test-parallel2.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..93724dd28 --- /dev/null +++ b/src/tests/test-setgroups.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..36f7268be --- /dev/null +++ b/src/tests/test-setpag.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..717424fa5 --- /dev/null +++ b/src/tests/too-many-files @@ -0,0 +1,5 @@ +#!/bin/sh +# $Id$ +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 index 000000000..61badc5dc --- /dev/null +++ b/src/tests/touch1 @@ -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 index 000000000..53c59de5d --- /dev/null +++ b/src/tests/truncate-files.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..0e41bec0a --- /dev/null +++ b/src/tests/truncate.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include + +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 index 000000000..a74abc1e5 --- /dev/null +++ b/src/tests/untar-emacs @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id$ +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 index 000000000..d2af4e05c --- /dev/null +++ b/src/tests/untar-openafs @@ -0,0 +1,10 @@ +#!/bin/sh +# $Id$ +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 index 000000000..7c9ac4d85 --- /dev/null +++ b/src/tests/util.c @@ -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 + +#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 index 000000000..0eece44f1 --- /dev/null +++ b/src/tests/utime-dir.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 index 000000000..bbbea3350 --- /dev/null +++ b/src/tests/utime-file.c @@ -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 +#endif + +#ifdef RCSID +RCSID("$Id$"); +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +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 index 000000000..6c3b3838b --- /dev/null +++ b/src/tests/visit-volumes @@ -0,0 +1,6 @@ +#!/bin/sh +# $Id$ +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 index 000000000..c23c44690 --- /dev/null +++ b/src/tests/vosaddsite.pl @@ -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 index 000000000..a485829a2 --- /dev/null +++ b/src/tests/vosbackup.pl @@ -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 index 000000000..fd78e9edf --- /dev/null +++ b/src/tests/voscreate.pl @@ -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 index 000000000..9ab71023b --- /dev/null +++ b/src/tests/vosdelentry.pl @@ -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 index 000000000..eabc5a233 --- /dev/null +++ b/src/tests/vosdump.pl @@ -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 index 000000000..a8be8f046 --- /dev/null +++ b/src/tests/vosexamine.pl @@ -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 index 000000000..45c5b0ae1 --- /dev/null +++ b/src/tests/voslistpart.pl @@ -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 index 000000000..3a951ca54 --- /dev/null +++ b/src/tests/voslistvldb.pl @@ -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 index 000000000..f7543fe33 --- /dev/null +++ b/src/tests/voslistvol.pl @@ -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 index 000000000..7f1bec850 --- /dev/null +++ b/src/tests/voslock.pl @@ -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 index 000000000..52405478e --- /dev/null +++ b/src/tests/vosmove.pl @@ -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 index 000000000..701cb35e1 --- /dev/null +++ b/src/tests/vospartinfo.pl @@ -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 index 000000000..479d297df --- /dev/null +++ b/src/tests/vosrelease.pl @@ -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 index 000000000..5fd53e77e --- /dev/null +++ b/src/tests/vosremove.pl @@ -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 index 000000000..c93e2715d --- /dev/null +++ b/src/tests/vosremsite.pl @@ -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 index 000000000..45bdfdbea --- /dev/null +++ b/src/tests/vosrename.pl @@ -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 index 000000000..9ab0d93da --- /dev/null +++ b/src/tests/vosrestore.pl @@ -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 index 000000000..a6ed963cd --- /dev/null +++ b/src/tests/vossyncserv.pl @@ -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 index 000000000..47c4aa96f --- /dev/null +++ b/src/tests/vossyncvldb.pl @@ -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 index 000000000..5dfd1fc88 --- /dev/null +++ b/src/tests/vosunlock.pl @@ -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 index 000000000..6d9c55f84 --- /dev/null +++ b/src/tests/vosunlockall.pl @@ -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 index 000000000..bacce854e --- /dev/null +++ b/src/tests/voszap.pl @@ -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 index 000000000..1ecf4bc42 --- /dev/null +++ b/src/tests/warn.c @@ -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 +RCSID("$Id$"); +#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 index 000000000..8fd138855 --- /dev/null +++ b/src/tests/warnx.c @@ -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 +RCSID("$Id$"); +#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 index 000000000..7941bf922 --- /dev/null +++ b/src/tests/write-closed.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include + +#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 index 000000000..b68374d60 --- /dev/null +++ b/src/tests/write-closed2.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#ifdef HAVE_SYS_IOCCOM_H +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 index 000000000..3d02570e8 --- /dev/null +++ b/src/tests/write-large.c @@ -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 +#endif + +#include + +#include + +#include +#include +#include + + +#include + +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 index 000000000..655eb1188 --- /dev/null +++ b/src/tests/write-rand.c @@ -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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..9be34f001 --- /dev/null +++ b/src/tests/write-ro @@ -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 index 000000000..cdf41bd76 --- /dev/null +++ b/src/tests/write-ro-file.c @@ -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 +#endif + +#include +#include +#include + +#include + +#ifdef RCSID +RCSID("$Id$"); +#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 index 000000000..f94afebc3 --- /dev/null +++ b/src/tests/write-ucc.c @@ -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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 index 000000000..00d386d9b --- /dev/null +++ b/src/tests/write1 @@ -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 index 000000000..90808c637 --- /dev/null +++ b/src/tests/write2 @@ -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 index 000000000..6de1511f9 --- /dev/null +++ b/src/tests/write3.c @@ -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 +#endif + +#include + +#include + +#include +#include +#include + + +#include + +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 index 000000000..03cca8fd1 --- /dev/null +++ b/src/tests/xf_errs.et @@ -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 index 000000000..877e1ae0b --- /dev/null +++ b/src/tests/xf_files.c @@ -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 +#include +#include +#include + +#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 index 000000000..d1060ea2e --- /dev/null +++ b/src/tests/xf_printf.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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 , as follows: + * indicates the base to be used (2-36) + * is nonzero if letter digits should be uppercase + * is the minimum number of digits + * The resulting number is stored in , which must be long enough + * to receive it. The minimum length is 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 = ""; + 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 index 000000000..9f9dd5037 --- /dev/null +++ b/src/tests/xf_profile.c @@ -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 +#include +#include +#include +#include +#include + +#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 index 000000000..957f7abc0 --- /dev/null +++ b/src/tests/xf_rxcall.c @@ -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 +#include +#include +#include +#include +#include +#include + +#include "xfiles.h" +#include "xf_errs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef AFSCONF_CLIENTNAME +#include +#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 index 000000000..6b026f598 --- /dev/null +++ b/src/tests/xfiles.c @@ -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 +#include +#include + +#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 index 000000000..661ac234c --- /dev/null +++ b/src/tests/xfiles.h @@ -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 +#include +#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_ */ -- 2.39.5