commit untracked files ... confusing
authorBdale Garbee <bdale@gag.com>
Wed, 22 Oct 2008 00:27:49 +0000 (02:27 +0200)
committerBdale Garbee <bdale@gag.com>
Wed, 22 Oct 2008 00:27:49 +0000 (02:27 +0200)
374 files changed:
DEVELOPING [new file with mode: 0644]
UPGRADING [new file with mode: 0644]
amplot/amplot.sh [new file with mode: 0644]
changer-src/chg-chio.pl [new file with mode: 0644]
changer-src/chg-chs.sh [new file with mode: 0644]
changer-src/chg-disk.sh [new file with mode: 0644]
changer-src/chg-iomega.pl [new file with mode: 0644]
changer-src/chg-juke.sh [new file with mode: 0755]
changer-src/chg-manual.sh [new file with mode: 0644]
changer-src/chg-mcutil.sh [new file with mode: 0644]
changer-src/chg-mtx.sh [new file with mode: 0644]
changer-src/chg-multi.sh [new file with mode: 0644]
changer-src/chg-null.sh [new file with mode: 0644]
changer-src/chg-rait.sh [new file with mode: 0644]
changer-src/chg-rth.pl [new file with mode: 0644]
changer-src/chg-zd-mtx.sh [new file with mode: 0644]
client-src/patch-system.sh [new file with mode: 0644]
common-src/amaespipe.sh [new file with mode: 0755]
common-src/amanda-sh-lib.sh.in [new file with mode: 0644]
common-src/amcrypt-ossl-asym.sh [new file with mode: 0644]
common-src/amcrypt-ossl.sh [new file with mode: 0644]
common-src/amcrypt.sh [new file with mode: 0755]
common-src/amcryptsimple.pl [new file with mode: 0755]
common-src/amflock-flock.c [new file with mode: 0644]
common-src/amflock-lnlock.c [new file with mode: 0644]
common-src/amflock-lockf.c [new file with mode: 0644]
common-src/amflock-posix.c [new file with mode: 0644]
common-src/amflock-test.c [new file with mode: 0644]
common-src/amflock.h [new file with mode: 0644]
common-src/amgpgcrypt.pl [new file with mode: 0755]
common-src/columnar.c [new file with mode: 0644]
common-src/columnar.h [new file with mode: 0644]
common-src/debug.h [new file with mode: 0644]
common-src/file.h [new file with mode: 0644]
common-src/genversion.h [new file with mode: 0644]
common-src/glib-util.c [new file with mode: 0644]
common-src/glib-util.h [new file with mode: 0644]
common-src/local-security.c [new file with mode: 0644]
common-src/sockaddr-util.c [new file with mode: 0644]
common-src/sockaddr-util.h [new file with mode: 0644]
common-src/svn-info.h [new file with mode: 0644]
common-src/tapelist.h~HEAD [new file with mode: 0644]
common-src/timestamp.c [new file with mode: 0644]
common-src/timestamp.h [new file with mode: 0644]
config/amanda/amplot.m4 [new file with mode: 0644]
config/amanda/bsd-security.m4 [new file with mode: 0644]
config/amanda/bsdtcp-security.m4 [new file with mode: 0644]
config/amanda/bsdudp-security.m4 [new file with mode: 0644]
config/amanda/changer.m4 [new file with mode: 0644]
config/amanda/components.m4 [new file with mode: 0644]
config/amanda/compress.m4 [new file with mode: 0644]
config/amanda/config.m4 [new file with mode: 0644]
config/amanda/debugging.m4 [new file with mode: 0644]
config/amanda/defaults.m4 [new file with mode: 0644]
config/amanda/devprefix.m4 [new file with mode: 0644]
config/amanda/dirs.m4 [new file with mode: 0644]
config/amanda/documentation.m4 [new file with mode: 0644]
config/amanda/dumpers.m4 [new file with mode: 0644]
config/amanda/file-list [new file with mode: 0644]
config/amanda/flags.m4 [new file with mode: 0644]
config/amanda/flock.m4 [new file with mode: 0644]
config/amanda/funcs.m4 [new file with mode: 0644]
config/amanda/getfsent.m4 [new file with mode: 0644]
config/amanda/i18n.m4 [new file with mode: 0644]
config/amanda/ipv6.m4 [new file with mode: 0644]
config/amanda/krb4-security.m4 [new file with mode: 0644]
config/amanda/krb5-security.m4 [new file with mode: 0644]
config/amanda/lfs.m4 [new file with mode: 0644]
config/amanda/libs.m4 [new file with mode: 0644]
config/amanda/net.m4 [new file with mode: 0644]
config/amanda/progs.m4 [new file with mode: 0644]
config/amanda/readdir.m4 [new file with mode: 0644]
config/amanda/readline.m4 [new file with mode: 0644]
config/amanda/rsh-security.m4 [new file with mode: 0644]
config/amanda/s3-device.m4 [new file with mode: 0644]
config/amanda/shmem.m4 [new file with mode: 0644]
config/amanda/socklen_t_equiv.m4 [new file with mode: 0644]
config/amanda/ssh-security.m4 [new file with mode: 0644]
config/amanda/summary.m4 [new file with mode: 0644]
config/amanda/swig.m4 [new file with mode: 0644]
config/amanda/syshacks.m4 [new file with mode: 0644]
config/amanda/tape.m4 [new file with mode: 0644]
config/amanda/types.m4 [new file with mode: 0644]
config/amanda/userid.m4 [new file with mode: 0644]
config/amanda/version.m4 [new file with mode: 0644]
config/automake/file-list [new file with mode: 0644]
config/automake/installperms.am [new file with mode: 0644]
config/automake/precompile.am [new file with mode: 0644]
config/automake/scripts.am [new file with mode: 0644]
config/automake/vars.am [new file with mode: 0644]
config/compile [new file with mode: 0644]
config/gettext-macros/codeset.m4 [new file with mode: 0644]
config/gettext-macros/file-list [new file with mode: 0644]
config/gettext-macros/gettext.m4 [new file with mode: 0644]
config/gettext-macros/glibc2.m4 [new file with mode: 0644]
config/gettext-macros/glibc21.m4 [new file with mode: 0644]
config/gettext-macros/iconv.m4 [new file with mode: 0644]
config/gettext-macros/intdiv0.m4 [new file with mode: 0644]
config/gettext-macros/intmax.m4 [new file with mode: 0644]
config/gettext-macros/inttypes-pri.m4 [new file with mode: 0644]
config/gettext-macros/inttypes.m4 [new file with mode: 0644]
config/gettext-macros/inttypes_h.m4 [new file with mode: 0644]
config/gettext-macros/isc-posix.m4 [new file with mode: 0644]
config/gettext-macros/lcmessage.m4 [new file with mode: 0644]
config/gettext-macros/lib-ld.m4 [new file with mode: 0644]
config/gettext-macros/lib-link.m4 [new file with mode: 0644]
config/gettext-macros/lib-prefix.m4 [new file with mode: 0644]
config/gettext-macros/longdouble.m4 [new file with mode: 0644]
config/gettext-macros/longlong.m4 [new file with mode: 0644]
config/gettext-macros/nls.m4 [new file with mode: 0644]
config/gettext-macros/po.m4 [new file with mode: 0644]
config/gettext-macros/printf-posix.m4 [new file with mode: 0644]
config/gettext-macros/progtest.m4 [new file with mode: 0644]
config/gettext-macros/signed.m4 [new file with mode: 0644]
config/gettext-macros/size_max.m4 [new file with mode: 0644]
config/gettext-macros/stdint_h.m4 [new file with mode: 0644]
config/gettext-macros/uintmax_t.m4 [new file with mode: 0644]
config/gettext-macros/ulonglong.m4 [new file with mode: 0644]
config/gettext-macros/wchar_t.m4 [new file with mode: 0644]
config/gettext-macros/wint_t.m4 [new file with mode: 0644]
config/gettext-macros/xsize.m4 [new file with mode: 0644]
config/gnulib/base64.m4 [new file with mode: 0644]
config/gnulib/file-list [new file with mode: 0644]
config/gnulib/float_h.m4 [new file with mode: 0644]
config/gnulib/fsusage.m4 [new file with mode: 0644]
config/gnulib/gettimeofday.m4 [new file with mode: 0644]
config/gnulib/include_next.m4 [new file with mode: 0644]
config/gnulib/malloc.m4 [new file with mode: 0644]
config/gnulib/mkdtemp.m4 [new file with mode: 0644]
config/gnulib/physmem.m4 [new file with mode: 0644]
config/gnulib/safe-read.m4 [new file with mode: 0644]
config/gnulib/safe-write.m4 [new file with mode: 0644]
config/gnulib/ssize_t.m4 [new file with mode: 0644]
config/gnulib/stdint.m4 [new file with mode: 0644]
config/gnulib/stdio_h.m4 [new file with mode: 0644]
config/gnulib/stdlib_h.m4 [new file with mode: 0644]
config/gnulib/sys_stat_h.m4 [new file with mode: 0644]
config/gnulib/sys_time_h.m4 [new file with mode: 0644]
config/gnulib/tempname.m4 [new file with mode: 0644]
config/gnulib/ulonglong.m4 [new file with mode: 0644]
config/gnulib/unistd_h.m4 [new file with mode: 0644]
config/gnulib/wchar.m4 [new file with mode: 0644]
config/libtool.m4 [new file with mode: 0644]
config/link-warning.h [new file with mode: 0644]
config/macro-archive/ac_define_dir.m4 [new file with mode: 0644]
config/macro-archive/ac_prog_perl_version.m4 [new file with mode: 0644]
config/macro-archive/ac_prog_swig.m4 [new file with mode: 0644]
config/macro-archive/ax_compare_version.m4 [new file with mode: 0644]
config/macro-archive/docbook-dtd.m4 [new file with mode: 0644]
config/macro-archive/docbook-xslt-min.m4 [new file with mode: 0644]
config/macro-archive/docbook-xslt.m4 [new file with mode: 0644]
config/macro-archive/file-list [new file with mode: 0644]
config/macro-archive/xsltproc.m4 [new file with mode: 0644]
config/ylwrap [new file with mode: 0755]
device-src/Makefile.am [new file with mode: 0644]
device-src/Makefile.in [new file with mode: 0644]
device-src/activate-devpay.c [new file with mode: 0644]
device-src/device.c [new file with mode: 0644]
device-src/device.h [new file with mode: 0644]
device-src/null-device.c [new file with mode: 0644]
device-src/null-device.h [new file with mode: 0644]
device-src/property.c [new file with mode: 0644]
device-src/property.h [new file with mode: 0644]
device-src/queueing.c [new file with mode: 0644]
device-src/queueing.h [new file with mode: 0644]
device-src/rait-device.c [new file with mode: 0644]
device-src/rait-device.h [new file with mode: 0644]
device-src/s3-device.c [new file with mode: 0644]
device-src/s3-device.h [new file with mode: 0644]
device-src/s3.c [new file with mode: 0644]
device-src/s3.h [new file with mode: 0644]
device-src/semaphore.c [new file with mode: 0644]
device-src/semaphore.h [new file with mode: 0644]
device-src/tape-aix.c [new file with mode: 0644]
device-src/tape-device.c [new file with mode: 0644]
device-src/tape-device.h [new file with mode: 0644]
device-src/tape-ops.h [new file with mode: 0644]
device-src/tape-posix.c [new file with mode: 0644]
device-src/tape-uware.c [new file with mode: 0644]
device-src/tape-xenix.c [new file with mode: 0644]
device-src/tests/Makefile.am [new file with mode: 0644]
device-src/tests/Makefile.in [new file with mode: 0644]
device-src/tests/device_test.c [new file with mode: 0644]
device-src/tests/queue_test.c [new file with mode: 0644]
device-src/tests/semaphore-test.c [new file with mode: 0644]
device-src/tests/vfs_test.c [new file with mode: 0644]
device-src/vfs-device.c [new file with mode: 0644]
device-src/vfs-device.h [new file with mode: 0644]
dumper-src/amgtar.pl [new file with mode: 0644]
dumper-src/generic-dumper.pl [new file with mode: 0644]
example/DLT-A4.ps [new file with mode: 0644]
example/amanda-client.conf [new file with mode: 0644]
example/inetd.conf.amandaclient [new file with mode: 0644]
example/template.d/README [new file with mode: 0644]
example/template.d/advanced.conf [new file with mode: 0644]
example/template.d/advanced.conf.in [new file with mode: 0644]
example/template.d/amanda-S3.conf [new file with mode: 0644]
example/template.d/amanda-S3.conf.in [new file with mode: 0644]
example/template.d/amanda-harddisk.conf [new file with mode: 0644]
example/template.d/amanda-harddisk.conf.in [new file with mode: 0644]
example/template.d/amanda-single-tape.conf [new file with mode: 0644]
example/template.d/amanda-single-tape.conf.in [new file with mode: 0644]
example/template.d/amanda-tape-changer.conf [new file with mode: 0644]
example/template.d/amanda-tape-changer.conf.in [new file with mode: 0644]
example/template.d/chg-manual.conf [new file with mode: 0644]
example/template.d/dumptypes [new file with mode: 0644]
example/template.d/tapetypes [new file with mode: 0644]
example/xinetd.amandaclient [new file with mode: 0644]
example/xinetd.amandaserver [new file with mode: 0644]
gnulib/base64.c [new file with mode: 0644]
gnulib/base64.h [new file with mode: 0644]
gnulib/float+.h [new file with mode: 0644]
gnulib/float_.h [new file with mode: 0644]
gnulib/fsusage.c [new file with mode: 0644]
gnulib/fsusage.h [new file with mode: 0644]
gnulib/full-read.c [new file with mode: 0644]
gnulib/full-read.h [new file with mode: 0644]
gnulib/full-write.c [new file with mode: 0644]
gnulib/full-write.h [new file with mode: 0644]
gnulib/gettimeofday.c [new file with mode: 0644]
gnulib/malloc.c [new file with mode: 0644]
gnulib/mkdtemp.c [new file with mode: 0644]
gnulib/netinet_in_.h [new file with mode: 0644]
gnulib/physmem.c [new file with mode: 0644]
gnulib/physmem.h [new file with mode: 0644]
gnulib/regenerate/no-error.patch.BACKUP.7723.patch [new file with mode: 0644]
gnulib/regenerate/no-error.patch.LOCAL.7723.patch [new file with mode: 0644]
gnulib/regenerate/no-error.patch.REMOTE.7723.patch [new file with mode: 0644]
gnulib/safe-read.c [new file with mode: 0644]
gnulib/safe-read.h [new file with mode: 0644]
gnulib/safe-write.c [new file with mode: 0644]
gnulib/safe-write.h [new file with mode: 0644]
gnulib/stdint_.h [new file with mode: 0644]
gnulib/stdio_.h [new file with mode: 0644]
gnulib/stdlib_.h [new file with mode: 0644]
gnulib/sys_socket_.h [new file with mode: 0644]
gnulib/sys_stat_.h [new file with mode: 0644]
gnulib/sys_time_.h [new file with mode: 0644]
gnulib/tempname.c [new file with mode: 0644]
gnulib/tempname.h [new file with mode: 0644]
gnulib/unistd_.h [new file with mode: 0644]
gnulib/wchar_.h [new file with mode: 0644]
installcheck/Amanda_Changer.pl [new file with mode: 0644]
installcheck/Amanda_Cmdline.pl [new file with mode: 0644]
installcheck/Amanda_Config.pl [new file with mode: 0644]
installcheck/Amanda_Logfile.pl [new file with mode: 0644]
installcheck/Amanda_Types.pl [new file with mode: 0644]
installcheck/Amconfig.pm.in [new file with mode: 0644]
installcheck/Makefile.am [new file with mode: 0644]
installcheck/Makefile.in [new file with mode: 0644]
installcheck/amcheckdump.pl [new file with mode: 0644]
installcheck/amdevcheck.pl [new file with mode: 0644]
installcheck/amgetconf.pl [new file with mode: 0644]
man/amaddclient.8 [new file with mode: 0644]
man/amaespipe.8.BACKUP.16324.8 [new file with mode: 0644]
man/amaespipe.8.LOCAL.16324.8 [new file with mode: 0644]
man/amaespipe.8.REMOTE.16324.8 [new file with mode: 0644]
man/amanda.css [new file with mode: 0644]
man/amcheckdump.8 [new file with mode: 0644]
man/amcryptsimple.8 [new file with mode: 0644]
man/amdevcheck.8 [new file with mode: 0644]
man/amgpgcrypt.8 [new file with mode: 0644]
man/amserverconfig.8 [new file with mode: 0644]
man/index.php [new file with mode: 0644]
man/xml-source/amaddclient.8.xml [new file with mode: 0644]
man/xml-source/amcheckdump.8.xml [new file with mode: 0644]
man/xml-source/amcryptsimple.8.xml [new file with mode: 0644]
man/xml-source/amdevcheck.8.xml [new file with mode: 0644]
man/xml-source/amgpgcrypt.8.xml [new file with mode: 0644]
man/xml-source/amserverconfig.8.xml [new file with mode: 0644]
man/xslt/html.xsl.in [new file with mode: 0644]
man/xslt/man.xsl.in [new file with mode: 0644]
packaging/Makefile.am [new file with mode: 0644]
packaging/Makefile.in [new file with mode: 0644]
packaging/README [new file with mode: 0644]
packaging/deb/amanda-backup-client.README.Debian [new file with mode: 0644]
packaging/deb/amanda-backup-client.dirs [new file with mode: 0644]
packaging/deb/amanda-backup-client.install [new file with mode: 0644]
packaging/deb/amanda-backup-client.lintian [new file with mode: 0644]
packaging/deb/amanda-backup-client.postinst [new file with mode: 0755]
packaging/deb/amanda-backup-client.postrm [new file with mode: 0755]
packaging/deb/amanda-backup-client.substvars [new file with mode: 0644]
packaging/deb/amanda-backup-server.README.Debian [new file with mode: 0644]
packaging/deb/amanda-backup-server.dirs [new file with mode: 0644]
packaging/deb/amanda-backup-server.install [new file with mode: 0644]
packaging/deb/amanda-backup-server.lintian [new file with mode: 0644]
packaging/deb/amanda-backup-server.postinst [new file with mode: 0755]
packaging/deb/amanda-backup-server.postrm [new file with mode: 0755]
packaging/deb/amanda-backup-server.substvars [new file with mode: 0644]
packaging/deb/buildpkg [new file with mode: 0755]
packaging/deb/changelog [new file with mode: 0644]
packaging/deb/compat [new file with mode: 0644]
packaging/deb/control [new file with mode: 0644]
packaging/deb/copyright [new file with mode: 0644]
packaging/deb/debian-binary [new file with mode: 0644]
packaging/deb/docs [new file with mode: 0644]
packaging/deb/postrm [new file with mode: 0755]
packaging/deb/preinst [new file with mode: 0755]
packaging/deb/rules [new file with mode: 0755]
packaging/deb/watch [new file with mode: 0644]
packaging/rpm/amanda.spec [new file with mode: 0644]
packaging/rpm/buildpkg [new file with mode: 0755]
perl/Amanda/Changer.pm [new file with mode: 0644]
perl/Amanda/Cmdline.c [new file with mode: 0644]
perl/Amanda/Cmdline.pm [new file with mode: 0644]
perl/Amanda/Cmdline.swg [new file with mode: 0644]
perl/Amanda/Config.c [new file with mode: 0644]
perl/Amanda/Config.pm [new file with mode: 0644]
perl/Amanda/Config.swg [new file with mode: 0644]
perl/Amanda/Debug.c [new file with mode: 0644]
perl/Amanda/Debug.pm [new file with mode: 0644]
perl/Amanda/Debug.swg [new file with mode: 0644]
perl/Amanda/Device.c [new file with mode: 0644]
perl/Amanda/Device.pm [new file with mode: 0644]
perl/Amanda/Device.swg [new file with mode: 0644]
perl/Amanda/Logfile.c [new file with mode: 0644]
perl/Amanda/Logfile.pm [new file with mode: 0644]
perl/Amanda/Logfile.swg [new file with mode: 0644]
perl/Amanda/Paths.pm.in [new file with mode: 0644]
perl/Amanda/Tapefile.c [new file with mode: 0644]
perl/Amanda/Tapefile.pm [new file with mode: 0644]
perl/Amanda/Tapefile.swg [new file with mode: 0644]
perl/Amanda/Types.c [new file with mode: 0644]
perl/Amanda/Types.pm [new file with mode: 0644]
perl/Amanda/Types.swg [new file with mode: 0644]
perl/Amanda/Util.c [new file with mode: 0644]
perl/Amanda/Util.pm [new file with mode: 0644]
perl/Amanda/Util.swg [new file with mode: 0644]
perl/Makefile.am [new file with mode: 0644]
perl/Makefile.in [new file with mode: 0644]
perl/amglue/amglue.h [new file with mode: 0644]
perl/amglue/amglue.swg [new file with mode: 0644]
perl/amglue/bigint.c [new file with mode: 0644]
perl/amglue/constants.swg [new file with mode: 0644]
perl/amglue/dumpspecs.swg [new file with mode: 0644]
perl/amglue/exports.swg [new file with mode: 0644]
perl/amglue/ghashtable.c [new file with mode: 0644]
perl/amglue/glib.swg [new file with mode: 0644]
perl/amglue/integers.swg [new file with mode: 0644]
po/Makefile.am [new file with mode: 0755]
po/Makefile.in [new file with mode: 0644]
po/Makevars [new file with mode: 0755]
po/Rules-quot [new file with mode: 0755]
po/boldquot.sed [new file with mode: 0755]
po/en@boldquot.header [new file with mode: 0755]
po/en@quot.header [new file with mode: 0755]
po/insert-header.sin [new file with mode: 0755]
po/quot.sed [new file with mode: 0755]
po/remove-potcdate.sin [new file with mode: 0755]
po/stamp-po [new file with mode: 0644]
server-src/amaddclient.pl [new file with mode: 0755]
server-src/amcheckdb.sh [new file with mode: 0644]
server-src/amcheckdump.pl [new file with mode: 0644]
server-src/amcleanup.sh [new file with mode: 0644]
server-src/amdevcheck.pl [new file with mode: 0644]
server-src/amdump.sh~HEAD [new file with mode: 0644]
server-src/amoverview.pl [new file with mode: 0644]
server-src/amrmtape.sh [new file with mode: 0644]
server-src/amserverconfig.pl [new file with mode: 0755]
server-src/amstatus.pl [new file with mode: 0644]
server-src/amtoc.pl [new file with mode: 0644]
server-src/amverify.sh~HEAD [new file with mode: 0644]
server-src/amverifyrun.sh [new file with mode: 0644]
server-src/taper-disk-port-source.c [new file with mode: 0644]
server-src/taper-disk-port-source.h [new file with mode: 0644]
server-src/taper-file-source.c [new file with mode: 0644]
server-src/taper-file-source.h [new file with mode: 0644]
server-src/taper-mem-port-source.c [new file with mode: 0644]
server-src/taper-mem-port-source.h [new file with mode: 0644]
server-src/taper-port-source.c [new file with mode: 0644]
server-src/taper-port-source.h [new file with mode: 0644]
server-src/taper-source-test.c [new file with mode: 0644]
server-src/taper-source.c [new file with mode: 0644]
server-src/taper-source.h [new file with mode: 0644]

diff --git a/DEVELOPING b/DEVELOPING
new file mode 100644 (file)
index 0000000..8ba7d32
--- /dev/null
@@ -0,0 +1,53 @@
+Notes For Developers
+====================
+
+This document describes a few basic tasks for managing the codebase;
+see http://wiki.zmanda.com/ for more detailed developer-oriented
+documentation.
+
+Adding Gnulib Modules
+---------------------
+
+Edit the clearly marked section in gnulib/regenerate/regenerate,
+then re-run that script as directed below.
+
+Updating Gnulib
+---------------
+
+This should probably be done after most releases, so that we have
+adequate time to uncover any bugs or problems in the new gnulib before
+we make another release.
+
+To update the gnulib files included with Amanda, you'll first need a
+CVS checkout of gnulib; let's call it $GNULIB_CO.  Then, in the root
+of the Amanda source, run
+
+  GNULIB_TOOL=$GNULIB_CO/gnulib-tool ./gnulib/regenerate/regenerate
+
+Use 'svn status' to figure out what changed, and 'svn add' / 'svn rm'
+to inform Subversion.  Then re-run autogen, configure, make, and test
+the result.  If all is well, commit.
+
+Updating Libtool
+----------------
+
+Libtool includes such useful files as config/config.guess.
+Occasionally (probably right after a release), these files should be
+updated.  On a machine with libtool installed, simply run 
+  libtoolize --force --copy
+
+Then use 'svn status' to see what changed, test it out, and commit.
+
+Updating Gettext
+----------------
+
+The gettext library contains a significant number of files.  Assuming
+you have the proper version of gettext installed, these files can be
+updated by running
+
+  po/reautopoint
+
+and then adjusting as appropriate with 'svn add' / 'svn rm', testing,
+and committing.  Note that this script post-processes the results of
+autopoint rather extensively, and will probably need to be adjusted
+for a new version of autopoint.
diff --git a/UPGRADING b/UPGRADING
new file mode 100644 (file)
index 0000000..4e012b7
--- /dev/null
+++ b/UPGRADING
@@ -0,0 +1,69 @@
+Upgrading
+=========
+
+This file describes the process for ugprading Amanda from a previous
+version.  In general, the Amanda development team aims for seamless
+upgrades.  In the rare cases where an upgrade requires other changes
+on your system, they are described in this file.
+
+The file is organized from oldest to newest.  Please follow all of
+the directions, in order, for the range of versions over which you
+are upgrading.
+
+See also http://wiki.zmanda.com/index.php/Version_compatibility for notes
+on the compatibility of various versions of Amanda.
+
+Upgrading from pre-2.4.0
+------------------------
+
+Amanda 2.4.0 has introduced a major incompatibility in the Amanda protocol.
+This means that pre-2.4.0 clients won't interoperate with a 2.4.0 server, nor
+will 2.4.0 clients interoperate with pre-2.4.0 servers. You have to upgrade
+them all at the same time.
+
+To ease the upgrade process Amanda has, from release 2.4.0 on, a configure flag
+(--with-testing) that will cause Amanda to use alternate service names (Amanda-
+test) instead of the standard ones. This allows you to keep using your old
+version of Amanda while you test the new one.
+
+Depending upon the version of Amanda you are upgrading from, Amanda may use a
+different database library to store the backup information, and the new Amanda
+may not be able to read the old Amanda database files. In this case, you will
+want to do something like the following:
+
+Before the upgrade (using the old version of amadmin):
+
+       # cd /var/AMANDA/CONFIG
+       # amadmin CONFIG export > zzz
+       # mkdir backup
+       # mv curinfo* backup
+       
+
+and after the upgrade (using the new version of amadmin):
+
+       # cd /var/AMANDA/CONFIG
+       # amadmin CONFIG import < zzz
+       
+
+and a month :-) after you are happy with the new version:
+
+       # cd /var/AMANDA/CONFIG
+       # rm -rf backup
+       
+
+After 2.4.0, the structure of the directory holding the index files was changed
+to have three levels instead of being flat. This greatly reduces the number of
+files in a given directory, which was a problem for some systems.
+
+The new layout is:
+
+  [indexdir]/hostname/filesystem/YYYYMMDD_L.gz
+
+where hostname and filesystem are "sanitized" versions of the names from
+disklist, i.e. '/' characters are converted to '_' and so on. This new naming
+convention matches the one used for the text formatted database.
+
+A script is available to convert the flat directory structure to the new
+layout:
+
+  http://www.amanda.org/2.4-conv/msg00428.html
diff --git a/amplot/amplot.sh b/amplot/amplot.sh
new file mode 100644 (file)
index 0000000..fe47bcc
--- /dev/null
@@ -0,0 +1,202 @@
+#!@SHELL@
+# Amanda, The Advanced Maryland Automatic Network Disk Archiver
+# Copyright (c) 1992-1998 University of Maryland at College Park
+# All Rights Reserved.
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of U.M. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  U.M. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Author: Olafur Gudumundsson, (ogud@tis.com)  Trusted Information Systems
+# Formerly at:                   Systems Design and Analysis Group
+#                        Computer Science Department
+#                        University of Maryland at College Park
+#
+#      Amplot: a program to generate postscript plots of each nights amanda 
+#      performance 
+# 
+#      Author: Olafur Gudmundsson (ogud@tis.com) 
+#      Creation Date: April 1992 
+#      Last modified: April 1995 
+#      Input: list of amdumps 
+#      Output: Plot of amdump files as either gnuplots on the screen or
+#              Postscript files 
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+confdir=@CONFIG_DIR@
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+# we use a different version of the compression variable than amanda itself.
+COMPRESS=@AMPLOT_COMPRESS@
+
+# Function to check that awk can do command-line variable
+# substitution.  If no, then exit; if yes, set $AVARFLAG
+# to the commandline switch used to introduce a variable. This
+# check used to be performed at build time in configure; it's
+# now performed at runtime.
+test_awk() {
+       local tmpfile result
+       tmpfile=`mktemp /tmp/amplot.XXXXXX`
+       echo 'BEGIN{print i; exit}' > ${tmpfile}
+       result=`$AWK -f ${tmpfile} i=xx | wc -c`
+       if test "$result" -le 1; then
+               result=`$AWK -f ${tmpfile} -v i=xx | wc -c`
+               if test "$result" -le 1; then
+                       echo "$AWK does not support command-line variable assignment; amplot cannot run" >&2
+                       rm -fr $tmpfile
+                       exit 1
+               else
+                       AVARFLAG=-v
+               fi
+       else
+               AVARFLAG=''
+       fi
+
+       rm -fr $tmpfile
+}
+
+# Function to search for gnuplot and ensure it's working.  This
+# first tries the location detected/configured when amanda was built,
+# then tries 'gnuplot', assuming it's in the user's path.  If no
+# working gnuplot executable is found, it exits with an error.  The
+# variable $GNUPLOT is set to the resulting executable.
+find_gnuplot() {
+       if test "x$GNUPLOT" = "x"; then
+               # look for it in the user's PATH
+               GNUPLOT=gnuplot
+       fi
+
+       if ${GNUPLOT} --version 2>/dev/null | grep '^gnuplot' >/dev/null; then
+               : # looks OK
+       else
+               echo "${GNUPLOT} was not found; amplot cannot run"
+               exit 1
+       fi
+}
+
+# check our environment, using functions from above
+test_awk
+find_gnuplot
+
+if [ $# -eq 0 ] ; then
+       _ 'Usage: %s [-c] [-e] [-g] [-l] [-p] [-t hours] <amdump_files.[gz,z,Z]>\n' $0
+       _ '%s generates plot for screen with fixed dimensions\n' $0
+       _ '     -c      Compress the input amdump files after plotting\n'
+       _ '     -e      Extends x (time) axes if needed\n'
+       _ '     -g      Run gnuplot directly no postscript file generated DEFAULT\n'
+       _ '     -l      Landscape mode suitable for printing\n'
+       _ '     -p      Postscript output (color)\n'
+       _ '     -b      The postscipt will be b/w\n'
+       _ '     -t T    Set the right edge of the plot to be T hours\n'
+       exit 1 
+fi
+
+tmp_files="bandw_free disk_alloc dump_idle finished run_queue tape_* title" 
+
+my_plot=$amlibexecdir/amplot.g
+paper=0 
+gnuplot=1
+cmpres=0
+para=""
+maxtime=4
+bw=0
+
+# setting up the parameters to pass to [gn]awk 
+while :; do 
+   case "$1" in
+   -c)  cmpres=1; shift;;
+   -e)  para=$para"$AVARFLAG extend=1 "; shift;;
+   -g)  gnuplot=1; shift;;
+   -l)  paper=1; para=$para"$AVARFLAG paper=1 "; shift;;
+   -p)  gnuplot=0; shift;;
+   -b) bw=1; shift;;
+   -t)  shift
+       if test "$#" -eq 0; then
+           _ '%s: no argument for -t option\n' $0 1>&2
+           exit 5
+       fi
+       maxtime="$1"; shift;;
+   *) break;;
+   esac
+done
+if [ $# -eq 0 ] ; then 
+       _ '%s: no input files\n' $0 1>&2
+       exit 5
+fi
+para=$para"$AVARFLAG maxtime=$maxtime"
+
+if [ $gnuplot  -eq 1 ] ; then
+       my_plot=$my_plot"p"             # use the plot prog that pauses
+       plot=" -geometry 800x700+40+0" 
+       para=$para"$AVARFLAG gnuplot=1 "
+       _ "Displaying graph on the screen, <CR> for next graph"
+
+       if [ "$paper" -eq 1 ] ; then
+               _ '%s: -l requires -p flag at the same time\n' $0 1>&2
+               exit 6 
+       fi
+       if [ "$bw" -eq 1 ] ; then
+               _ '%s: -b requires -p flag at the same time\n' $0 1>&2
+               exit 6 
+       fi
+fi
+
+if [ $bw -eq 1 ]; then
+       para=$para" bw=1"
+fi
+
+list="";               # files to compress at the end
+
+for i in ${1+"$@"}             # for all the input files
+do
+       f="$i";
+       if [ ! -f "$f" ] ; then 
+               f=`ls "$i" "$i".*[zZ] 2>/dev/null`
+       fi
+       if [ -f "$f" ] ; then           # found file 
+                disp=`$AWK -f $amlibexecdir/amcat.awk $AVARFLAG f="$f"`
+               if [ -z "$disp" ] ; then 
+                       _ 'Do not know how to [gz|z]cat this file\n'
+               else
+                       /bin/rm -f $tmp_files 
+                       $disp "$f" | $AWK -f $amlibexecdir/amplot.awk $para
+                       $GNUPLOT $plot $my_plot
+                       if [ $disp = "cat" -a  $cmpres -eq 1 ] ; then
+                               list=$list" "$f
+                       fi
+               fi
+       else                            # check if file has been compressed
+               _ 'No such file %s or %s\n' "$i" "$i.*[zZ]"
+       fi
+done
+
+/bin/rm -f $tmp_files 
+
+if [ "$list" != "" ] ; then            # now compress the files we worked on
+# comment out next line if you do not want compression at the end
+       _ 'Compressing %s\n' "$list"
+       $COMPRESS $list
+fi
+exit 0
diff --git a/changer-src/chg-chio.pl b/changer-src/chg-chio.pl
new file mode 100644 (file)
index 0000000..56bb358
--- /dev/null
@@ -0,0 +1,488 @@
+#! @PERL@ -w
+
+# Catch for sh/csh on systems without #! ability.
+eval '(exit $?0)' && eval 'exec @PERL@ -S $0 ${1+"$@"}'
+        & eval 'exec @PERL@ -S $0 $argv:q'
+                if 0;
+
+# 
+# This changer script controls tape libraries on operating systems that have a
+# chgio program
+#      DSL 7000 on FreeBSD is an example
+#
+# The changer being used is a n tape juke, that can be used with 1, n-1 or n
+# tapes in the juke. The special slot is slot n. The script does not
+# make assumptions about the number of slots, except that the special slot
+# is the highest number. The slot is special in the sense that it contains the
+# the only tape if the juke contains 1 tape and contains no tape if the juke
+# contains n-1 tapes. See getCurrentTape.
+#
+# Furthermore, the script uses drive 0 and assumes that the device is able to
+# figure itself how to move a type from slot m to drive 0 if asked to do so and
+# multiple pickers are present.
+#
+# The numbering of the slots is by the way from 1 to n with slots. The chio
+# program returns the slot numbers numbered from 0 to n-1 however.
+# 
+# This script is built up out of bits and pieces of the other scripts
+# and no credits are claimed. Most notably the chg-rth.pl script was used. That
+# script was written by Erik Frederick, <edf@tyrell.mc.duke.edu>.
+# 
+# Permission to freely use and distribute is granted (by me and was granted by
+# the original authors).
+#
+# Nick Hibma - nick.hibma@jrc.it
+#
+
+require 5.001;
+
+($progname = $0) =~ s#/.*/##;
+
+use English;
+use Getopt::Long;
+
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
+$ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin";
+
+$| = 1;
+
+if (-d "@AMANDA_DBGDIR@") {
+       $logfile = "@AMANDA_DBGDIR@/changer.debug";
+} else {
+       $logfile = "/dev/null";
+}
+die "$progname: cannot open $logfile: $ERRNO\n"
+       unless (open (LOG, ">> $logfile"));
+
+#
+# get the information from the configuration file
+#
+
+$prefix="@prefix@";
+$prefix=$prefix;               # avoid warnings about possible typo
+$exec_prefix="@exec_prefix@";
+$exec_prefix=$exec_prefix;     # Ditto
+$sbindir="@sbindir@";
+if ( "@USE_VERSION_SUFFIXES@" eq "yes" ) {
+    $SUF = "-@VERSION@";
+} else {
+    $SUF = "";
+}
+
+chomp ($tapeDevice = `$sbindir/amgetconf$SUF tapedev 2>&1`);
+die "tapedev not found in amanda.conf"
+       if !$tapeDevice or $tapeDevice eq "" or
+           $tapeDevice =~ m/no such parameter/;
+chomp ($changerDevice = `$sbindir/amgetconf$SUF changerdev 2>&1`);
+chomp $changerDevice;
+die "changerdev not found in amanda.conf"
+       if !$changerDevice or $changerDevice eq "" or
+           $changerDevice =~ m/no such parameter/;
+
+#
+# Initialise a few global variables
+#
+
+@slots = ();
+@drives = ();
+$max_slot = 0;
+$max_drive = 0;
+$nr_tapes = 0;
+
+@dow = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
+@moy = ("Jan", "Feb", "Mar", "Apr", "May", "Jun",
+       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
+
+sub do_time {
+       my (@t);
+       my ($r);
+
+       ###
+       # Get the local time for the value.
+       ###
+
+       @t = localtime (time ());
+
+       ###
+       # Return the result.
+       ###
+
+       $r = sprintf "%s %s %2d %2d:%02d:%02d %4d",
+         $dow[$t[6]],
+         $moy[$t[4]],
+         $t[3],
+         $t[2], $t[1], $t[0],
+         1900 + $t[5];
+
+       return $r;
+}
+
+sub getCurrentTape {
+       print LOG &do_time(), ": enter: getCurrentTape\n";
+
+       #
+       # Determines the slot number for the tape that is currently in the
+       # drive. getTapeParams and getTapeStatus should have been called.
+       # If there is no tape in the drive, no current tape, 0 is returned.
+       #
+
+       my($slot, $i);
+
+       if ( !$drives[0] ) {            # drive empty
+               $i = 0;
+       } elsif ( $nr_tapes == 1 ) {    # one tape -> comes from slot max_slot
+               $i = $max_slot;
+       } else {                        # find first empty slot
+               $i = 0;
+               while ( $i < $#slots and $slots[$i] ) {
+                       $i++
+               }
+               $i++;
+       }
+
+       print LOG &do_time(), ": leave: getCurrentTape: $i\n";
+       return $i;
+}
+
+sub getTapeStatus {
+       print LOG &do_time(), ": enter: getTapeStatus\n";
+
+       #
+       # Sets $nr_tapes, @slots, @drives, $current_tape
+       #
+
+       my($type,$num,$status);
+
+       print LOG &do_time(), ": running: @CHIO@ -f $changerDevice status\n";
+       if ( !(open(FH,"@CHIO@ -f $changerDevice status|")) ) {
+               print "$progname: '@CHIO@ -f $changerDevice status' failed, $!\n";
+               exit(2);
+       }
+
+       #
+       # This routine requires the format of the output of 'chio status' to 
+       # be as follows:
+       #   picker 0: 
+       #   slot 0: <ACCESS>
+       #   slot 1: <ACCESS,FULL>
+       #   slot 2: <ACCESS,FULL>
+       #   (etc.)
+       #   drive 0: <ACCESS,FULL>
+
+
+       @slots=();
+       @drives=();
+
+       while( defined ($line = <FH>) ) {
+               chomp( $line );
+               print LOG &do_time(), ": $line\n";
+               next unless $line =~ m/(\w+)\s+(\d+):\s*<([^>]+)>/;
+               ($type,$num,$status) = ($1,$2,$3);
+               if ( $type =~ m/slot/i ) {
+                       $slots[$num] = ( $status =~ m/full/i ) ? 1 : 0;
+                       if ($slots[ $num ]) { $nr_tapes++ }
+               } elsif ( $type =~ m/drive/i ) {
+                       $drives[$num] = 0;
+                       if (  $status =~ m/full/i ) {
+                               $drives[$num] = 1;
+                               $nr_tapes++;
+                       }
+               } else {
+                       # ignore 'picker', empty ones, etc...
+               }
+       }
+       close(FH);
+
+       if ( $nr_tapes == 0 ) {
+               print "$progname: No tapes in changer!\n";
+               exit(2);
+       }
+
+       $currentTape = &getCurrentTape(); 
+
+       print LOG &do_time(), ": leave: getTapeStatus: $nr_tapes\n";
+       return($nr_tapes);
+}
+
+sub getTapeParams {
+       print LOG &do_time(), ": enter: getTapeParams\n";
+  
+       #
+       # Requests information on the number of slots, pickers and drives
+       # from the changer.
+       #
+
+       my($max_slot,$max_drive,$max_picker);
+  
+       print LOG &do_time(), ": running: @CHIO@ -f $changerDevice params\n";
+       if ( !open(FH,"@CHIO@ -f $changerDevice params|") ) {
+               print "$progname: '@CHIO@ -f $changerDevice params' failed, $!\n";
+               exit(2);
+       }
+  
+       #
+       # the format of the output of 'chio params' should be
+       #  /dev/ch0: 8 slots, 1 drive, 1 picker
+       #  /dev/ch0: current picker: 0
+       #
+
+       $max_slot = 0;
+       $max_picker = -1;
+       $max_drive = 0;
+
+       while( defined ($line = <FH>) ) {
+               chomp $line;
+               print LOG &do_time(), ": $line\n";
+               $max_slot       = $1 if $line =~ m/(\d+) slot/i;
+               $max_drive      = $1 if $line =~ m/(\d+) drive/i;
+               $max_picker     = $1 if $line =~ m/(\d+) picker/i;
+
+       }
+       close(FH);
+       if ( $max_drive == 0 or $max_picker == -1 ) {
+               print "$progname: No drive or picker ? ($max_drive/$max_picker)\n";
+               exit(2);
+       }
+
+       print LOG &do_time(), ": leave: getTapeParams: $max_slot, $max_drive, $max_picker\n";
+       return ($max_slot, $max_drive, $max_picker);
+}
+
+sub testTape {
+       my($tape) = @_;
+
+       #
+       # Check a few parameters to avoid the most serious problems
+       #
+
+       return
+               if $currentTape == $tape;
+
+       if( $slots[$tape-1] == 0 ) {
+               print "<none> $progname: no tape in slot requested\n";
+               exit(1);
+       }
+       if( $tape > $max_slot ) {
+               print $tape," $progname: requested a tape > $max_slot\n";
+               exit(2);
+       }
+       if( $tape < 1 ) {
+               print $tape," $progname: requested a tape < 1\n";
+               exit(2);
+       }
+       return;
+}
+
+sub Load {
+       my($tape) = @_;
+       print LOG &do_time(), ": enter: Load: $tape\n";
+
+       #
+       # Load tape $tape into drive 0
+       #
+
+       print LOG &do_time(), ": running: @CHIO@ -f $changerDevice move slot ", $tape - 1, " drive 0\n";
+       if ( system("@CHIO@ -f $changerDevice move slot ".($tape-1)." drive 0") ) {
+               print "$progname: cannot '@CHIO@ -f $changerDevice move' tape $tape into drive 0\n";
+               exit(2);
+       }
+
+       # wait for tape to load
+       $count = 1800;
+       while ( $count > 0 &&
+               system("$MT $MTF $tapeDevice status > /dev/null 2>&1" ) ) {
+               print LOG &do_time(), ": waiting for tape to load\n";
+               sleep 30;
+               $count -= 30;
+       }
+
+       print LOG &do_time(), ": leave: Load\n";
+}
+
+sub Unload {
+       my($tape) = @_;
+       print LOG &do_time(), ": enter: Unload: $tape\n";
+
+       #
+       # Unload the tape from drive 0 and put it into the slot specified by
+       # $tape.
+       #
+
+       #
+       # Ecrix AutoPAK devices (based on the Spectra Logics 215 changer)
+       # can lock up if you try to move a tape from a drive to an open slot
+       # without first rewinding and ejecting the tape.  This appears to
+       # occur when the operation times out and the ch driver sends a device
+       # or bus reset. Ecrix claims this is about to be fixed with a new
+       # firmware rev but for now it's safest to just explicitly eject
+       # the tape before moving the cartridge.
+       #
+       if ( system ("$MT $MTF $tapeDevice offline") ) {
+               print "$progname: Warning, failed to eject the tape with '$MT $MTF $tapeDevice offline'\n";
+               # NB: not fatal; let chio try it's thing
+       }
+
+       if ( system("@CHIO@ -f $changerDevice move drive 0 slot ".($tape-1)." ") ) {
+               print "$progname: cannot '@CHIO@ -f $changerDevice move' tape $tape from drive 0\n";
+               exit(2);
+       }
+       print LOG &do_time(), ": leave: Unload\n";
+}
+
+sub changeTape {
+       my($tape) = @_;
+       print LOG &do_time(), ": enter: changeTape: $tape\n";
+
+       #
+       # Unload current tape and load a new tape from slot $tape.
+       #
+
+       if ($tape != $currentTape) {
+
+               &testTape($tape);
+
+               if( $currentTape != 0 ) {
+                       &Unload($currentTape);
+               }
+               &Load($tape);
+               $currentTape = $tape;
+       }
+       print LOG &do_time(), ": leave: changeTape\n";
+}
+
+
+#
+# Main program
+#
+
+#
+# Initialise
+#
+
+($max_slot, $max_drive) = &getTapeParams();
+
+$opt_slot = 0;                                 # perl -w fodder
+$opt_info = 0;                                 # perl -w fodder
+$opt_reset = 0;                                        # perl -w fodder
+$opt_eject = 0;                                        # perl -w fodder
+
+GetOptions("slot=s", "info", "reset", "eject"); 
+
+$nr_tapes = &getTapeStatus();
+
+#
+# Before we do anything with the tape changer we'll have to rewind the tape
+#
+
+if (-x "$sbindir/ammt$SUF") {
+       $MT="$sbindir/ammt$SUF";
+       $MTF="-f";
+} elsif (-x "@MT@") {
+       $MT="@MT@";
+       $MTF="@MT_FILE_FLAG@";
+} else {
+       print LOG &do_time(), ": mt program not found\n";
+       print "<none> mt program not found\n";
+       exit(1);
+}
+print LOG &do_time(), ": MT -> $MT $MTF\n";
+
+system ("$MT $MTF $tapeDevice rewind")
+       unless $currentTape == 0;
+
+
+if ( $opt_slot ) {
+       if ( $opt_slot =~ /first/ ) {
+               &changeTape(1);
+               print LOG &do_time(), ": $currentTape $tapeDevice\n";
+               print "$currentTape $tapeDevice\n";
+       }
+       if ( $opt_slot =~ /last/ ) {
+               &changeTape($max_slot);
+               print LOG &do_time(), ": $currentTape $tapeDevice\n";
+               print "$currentTape $tapeDevice\n";
+       }
+       if ( $opt_slot =~ /current/ ) {
+               &changeTape($currentTape);
+               print LOG &do_time(), ": $currentTape $tapeDevice\n";
+               print "$currentTape $tapeDevice\n";
+       }
+       if ( $opt_slot =~ /next/ ) {
+               $tape = $currentTape+1;
+               if ( $tape > $max_slot ) {
+                       $tape = 1;
+               }
+               while ( $slots[$tape-1] == 0 ) {        # there is at least 1 
+                       if ( ++$tape > $max_slot ) {
+                               $tape = 1;
+                       }
+               }
+               &changeTape($tape);
+               print LOG &do_time(), ": $currentTape $tapeDevice\n";
+               print "$currentTape $tapeDevice\n";
+       }
+       if ( $opt_slot =~ /prev/ ) {
+               $tape = $currentTape-1;
+               if ( $tape < 1 ) {
+                       $tape = $max_slot;
+               }
+               while ( $slots[$tape-1] == 0 ) {        # there is at least 1
+                       if ( --$tape < 1 ) {
+                               $tape = $max_slot;
+                       }
+               }
+               &changeTape($tape);
+               print LOG &do_time(), ": $currentTape $tapeDevice\n";
+               print "$currentTape $tapeDevice\n";
+       }
+       if ( $opt_slot =~ /^\d+$/ ) {
+               &changeTape($opt_slot);
+               print LOG &do_time(), ": $currentTape $tapeDevice\n";
+               print "$currentTape $tapeDevice\n";
+       }
+       if ( $opt_slot =~ /advance/ ) {
+               $tape=$currentTape+1;
+               if ( $tape > $max_slot ) {
+                       $tape = 1;
+               }
+               if ( $currentTape ) { 
+                       &Unload($currentTape);
+               }
+               print LOG &do_time(), ": $currentTape $tapeDevice\n";
+               print "$currentTape , /dev/null\n";
+       }
+
+       exit 0;
+}
+
+if ( $opt_info ) {
+       if ( $currentTape == 0 ) {
+               &Load(1);                       # load random tape
+               $currentTape = 1;
+       }
+
+       print LOG &do_time(), ": $currentTape $max_slot 1\n";
+       print "$currentTape $max_slot 1\n";
+       exit 0;
+}
+
+if ( $opt_reset ) {
+       &changeTape(1);
+       print LOG &do_time(), ": $currentTape $tapeDevice\n";
+       print "$currentTape $tapeDevice\n";
+       exit 0;
+}
+
+if ( $opt_eject ) {
+       if ( $currentTape ) { 
+               &Unload($currentTape);
+               print "0 $tapeDevice\n";
+               exit 0;
+       } else {
+               print "$progname: drive was not loaded\n";
+               exit 1;
+       }
+}
+
+print "$progname: No command was received.  Exiting.\n";
+exit 1;
diff --git a/changer-src/chg-chs.sh b/changer-src/chg-chs.sh
new file mode 100644 (file)
index 0000000..8679711
--- /dev/null
@@ -0,0 +1,393 @@
+#!@SHELL@
+#
+# Amanda, The Advanced Maryland Automatic Network Disk Archiver
+# Copyright (c) 1991-1998 University of Maryland at College Park
+# All Rights Reserved.
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of U.M. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  U.M. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Author: James da Silva, Systems Design and Analysis Group
+#                         Computer Science Department
+#                         University of Maryland at College Park
+#
+
+#
+# chg-chs.sh - chs tape changer script
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+pname="chg-chs"
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+if [ -d "@AMANDA_DBGDIR@" ]; then
+       logfile=@AMANDA_DBGDIR@/changer.debug
+else
+       logfile=/dev/null
+fi
+
+CHS=@CHS@
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+       SUF="-@VERSION@"
+else
+       SUF=
+fi
+
+ourconf=`amgetconf$SUF changerfile`
+changerdev=`amgetconf$SUF changerdev`
+if test -n "$changerdev" && test x"$changerdev" != x/dev/null; then
+       CHS="$CHS -f$changerdev"
+fi
+
+# read in some config parameters
+
+if [ \! -f $ourconf ]; then
+       answer=`_ '<none> %s: %s does not exist' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+firstslot=`awk '$1 == "firstslot" {print $2}' $ourconf 2>/dev/null`
+if [ "$firstslot" = "" ]; then
+       answer=`_ '<none> %s: firstslot not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+lastslot=`awk '$1 == "lastslot" {print $2}' $ourconf 2>/dev/null`
+if [ "$lastslot" = "" ]; then
+       answer=`_ '<none> %s: lastslot not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+nslots=`expr $lastslot - $firstslot + 1`
+
+gravity=`awk '$1 == "gravity" {print $2}' $ourconf 2>/dev/null`
+if [ "$gravity" = "" ]; then
+       answer=`_ '<none> %s: gravity not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+needeject=`awk '$1 == "needeject" {print $2}' $ourconf 2>/dev/null`
+if [ "$needeject" = "" ]; then
+       answer=`_ '<none> %s: needeject not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+multieject=`awk '$1 == "multieject" {print $2}' $ourconf 2>/dev/null`
+if [ "$multieject" = "" ]; then
+       echo `_ 'Note -> multieject not specified in %s' "$ourconf"` >> $logfile
+       multieject=0
+fi
+
+ejectdelay=`awk '$1 == "ejectdelay" {print $2}' $ourconf 2>/dev/null`
+if [ "$ejectdelay" = "" ]; then
+       echo `_ 'Note -> ejectdelay not specified in %s' "$ourconf"` >> $logfile
+       ejectdelay=0
+fi
+
+ourstate=`awk '$1 == "statefile" {print $2}' $ourconf 2>/dev/null`
+if [ "$ourstate" = "" ]; then
+       answer=`_ '<none> %s: statefile not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+# read in state: only curslot and curloaded at the present time
+
+curslot=`awk '$1 == "curslot" {print $2}' $ourstate 2>/dev/null`
+if [ "$curslot" = "" ]; then
+       curslot=$firstslot
+fi
+
+curloaded=`awk '$1 == "curloaded" {print $2}' $ourstate 2>/dev/null`
+if [ "$curloaded" = "" ]; then
+       curloaded=0
+fi
+
+
+# process the command-line
+
+# control vars to avoid code duplication: not all shells have functions!
+usage=0
+checkgravity=0
+ejectslot=0
+loadslot=0
+slotempty=0
+
+if [ $# -ge 1 ]; then command=$1; else command="-usage"; fi
+
+case "$command" in
+
+-info) # return basic information about changer
+
+       backwards=`expr 1 - $gravity`
+       answer="$curslot $nslots $backwards"
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 0
+       ;;
+
+-reset) # reset changer
+
+       checkgravity=0
+       loadslot=1
+       newslot=$firstslot
+
+       # XXX put changer-specific reset here, if applicable
+       ;;
+
+-eject) # eject tape if loaded
+
+       checkgravity=0
+       loadslot=0
+       newslot=$curslot
+       ejectslot=1
+
+       if [ $curloaded -eq 0 ]; then
+               answer=`_ '%s %s: slot already empty' "$curslot" "$pname"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 1
+       fi
+       ;;
+
+-slot) # change to slot
+
+       checkgravity=1
+       loadslot=1
+
+       slotparm=$2
+       case "$slotparm" in
+       [0-9]*) 
+               newslot=$slotparm
+               if [ \( $newslot -gt $lastslot \) -o \
+                    \( $newslot -lt $firstslot \) ]; then
+                       answer =`_ '%s %s: no slot %s: legal range is %s ... %s' "$newslot" "$pname" "$newslot" "$firstslot" "$lastslot"`
+                       echo `_ 'Exit ->'` $answer >> $logfile
+                       echo $answer
+                       exit 1
+               fi
+               ;;
+       current)
+               newslot=$curslot
+               ;;
+       first)
+               newslot=$firstslot
+               ;;
+       last)
+               newslot=$lastslot
+               ;;
+       next|advance)
+               newslot=`expr $curslot + 1`
+               if [ $newslot -gt $lastslot ]; then
+                       newslot=$firstslot
+               fi
+               if [ $slotparm = advance ]; then
+                       loadslot=0
+               fi
+               ;;
+       prev)
+               newslot=`expr $curslot - 1`
+               if [ $newslot -lt $firstslot ]; then
+                       newslot=$lastslot
+               fi
+               ;;
+       *)
+               answer=`_ '<none> %s: bad slot name "%s"' "$pname" "$slotparm"`
+               echo `_ 'Exit ->'` "$answer" >> $logfile
+               echo $answer
+               exit 1
+               ;;
+       esac
+       ;;
+*)
+       usage=1
+       ;;
+esac
+
+
+if [ $usage -eq 1 ]; then
+       answer=`_ '<none> usage: %s {-reset | -slot [<slot-number>|current|next|prev|advance]}' "$pname"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+
+# check for legal move
+
+if [ \( $checkgravity -eq 1 \) -a \( $gravity -ne 0 \) ]; then
+       if [ \( $newslot -lt $curslot \) -o \( "$slotparm" = "prev" \) ]
+       then
+               answer=`_ '%s %s: cannot go backwards in gravity stacker' "$newslot" "$pname"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 1
+       fi
+fi
+
+# get tape device name
+
+device=`awk '$1 == "slot" && $2 == '$newslot' {print $3}' $ourconf 2>/dev/null`
+if [ "$device" = "" ]; then
+       answer=`_ '%s %s: slot %s device not specified in %s' "$newslot" "$pname" "$newslot" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+# check if load needs an eject first
+
+if [ \( $needeject -eq 1 \) -a \( $loadslot -eq 1 \) -a \
+     \( $curloaded -eq 1 \) -a \( $newslot -ne $curslot \) ]; then
+       ejectslot=1
+fi
+
+
+if [ $ejectslot -eq 1 ]; then  # eject the tape from the drive
+
+       # XXX put changer-specific load command here, if applicable
+
+       curloaded=0             # unless something goes wrong
+       slotempty=0
+
+       # generically, first check that the device is there
+
+       if [ ! -c $device ]; then
+               answer=`_ '%s %s: %s: not a device file' "$newslot" "$pname" "$device"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 2
+       fi
+
+       # if multiple eject is required, do it now
+       if [ $multieject -eq 1 ]; then
+               loopslot=$curslot
+               while [ $loopslot -lt $newslot ]; do
+                        try_eject_device $device
+                       if [ $? -ne 0 ]; then
+                               answer=`_ '%s %s: %s: unable to change slot %s' "$newslot" "$pname" "$device" "$loopslot"`
+                               echo `_ 'Exit ->'` $answer >> $logfile
+                               echo $answer
+                               exit 2
+                       fi
+                       loopslot=`/usr/bin/expr $loopslot + 1`
+               done
+       fi
+  
+       # second, try to unload the device
+        try_eject_device $device
+       $CHS deselect -d1 -s$curslot >/dev/null 2>&1
+       if [ $? -ne 0 ]; then
+               #
+               # XXX if the changer-specific eject command can distinguish
+               # betweeen "slot empty" and more serious errors, return 1
+               # for the first case, 2 for the second case.  Generically,
+               # we just presume an error signifies an empty slot.
+               #
+               #slotempty=1
+               answer=`_ '<none> %s: tape unload to slot %s failed' "$pname" "$curslot"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 2
+       else
+               sleep $ejectdelay
+       fi
+fi
+
+if [ \( $loadslot -eq 1 \) -a \( \( $curloaded -ne 1 \) -o \( \( $curloaded -eq 1 \) -a \( $newslot -ne $curslot \) \) \) ]; then      # load the tape from the slot
+
+       # XXX put changer-specific load command here, if applicable
+
+       curloaded=1             # unless something goes wrong
+       slotempty=0
+
+       # generically, first check that the device is there
+
+       if [ ! -c $device ]; then
+               answer=`_ '%s %s: %s: not a device file' "$newslot" "$pname" "$device"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 2
+       fi
+
+       $CHS select -s$newslot -d1 >/dev/null 2>&1
+       if [ $? -ne 0 ]; then
+               answer=`_ '<none> %s: tape load from slot %s failed' "$pname" "$newslot"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 2
+       fi
+       sleep 60
+
+       # second, try to rewind the device
+        amdevcheck_status $device
+       if [ $? -ne 0 ]; then
+               #
+               # XXX if the changer-specific load command can distinguish
+               # betweeen "slot empty" and more serious errors, return 1
+               # for the first case, 2 for the second case.  Generically,
+               # we just presume an error signifies an empty slot.
+               #
+               slotempty=1
+               curloaded=0
+       fi
+fi
+
+# update state
+
+echo "# $pname state cache: DO NOT EDIT!"      >  $ourstate
+echo curslot $newslot                          >> $ourstate
+echo curloaded $curloaded                      >> $ourstate
+
+# return slot info
+
+if [ $slotempty -eq 1 ]; then
+       answer=`_ '<none> %s: %s slot is empty' "$pname" "$newslot"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 1
+fi
+
+if [ "$command" = -slot -a "$slotparm" = advance ]; then
+       device=/dev/null
+fi
+
+answer="$newslot $device"
+echo `_ 'Exit ->'` $answer >> $logfile
+echo $answer
+exit 0
diff --git a/changer-src/chg-disk.sh b/changer-src/chg-disk.sh
new file mode 100644 (file)
index 0000000..bdce74a
--- /dev/null
@@ -0,0 +1,319 @@
+#! @SHELL@
+#
+# Amanda, The Advanced Maryland Automatic Network Disk Archiver
+# Copyright (c) 1991-1999 University of Maryland at College Park
+# All Rights Reserved.
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of U.M. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  U.M. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Author: Jean-Christian SIMONETTI, System and Network Engineer
+#                                  Wanadoo Portails
+#                                  Sophia Antipolis, France
+#
+#      This changer script is based on a directory structure like:
+#      slot_root_dir -|
+#                     |- info
+#                     |- data -> slot1
+#                     |- slot1
+#                     |- slot2
+#                     |- ...
+#                     |- slotn
+#      where 'slot_root_dir' is the tapedev 'file:xxx' parameter and 'n'
+#      is the LASTSLOT value of your changerfile config file. If LASTSLOT is
+#      not defined, the value of the tapecycle parameter is used.
+#
+#      To use this driver, just put the line 'tpchanger "chg-disk"' in your
+#      amanda.conf.
+#
+#      Example of use (amanda.conf):
+#      --- cut here ---
+#      tapedev  "file:/BACKUP2/slots/"
+#      changerdev "/dev/null"
+#      changerfile "chg-disk"
+#      tpchanger "chg-disk"
+#      changerfile "/usr/local/amanda/etc/changer"
+#      tapetype HARD-DISK
+#      define tapetype HARD-DISK {
+#          length 12000 mbytes
+#      }
+#      --- cut here ---
+#
+#      Example changerfile (chg-disk.conf):
+#      --- cut here ---
+#      LASTSLOT=12
+#      --- cut here ---
+#
+#      The number of slot is equal to your LASTSLOT or tapecycle.
+#      You must create the slots and data directory.
+#
+
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+    SUF="-@VERSION@"
+else
+    SUF=
+fi
+
+MYNAME=$0
+
+TAPE=`amgetconf$SUF tapedev`
+if test X"$TAPE" = X""; then
+    echo `_ '<none> tapedev not specified in amanda.conf.'`
+    exit 2
+fi
+SLOTDIR=`echo $TAPE | sed 's/^file://'`
+
+isinteger() {
+           # should be exactly one arg
+       [ $# = 1 ]  || return 1
+           # if arg is null, no expr needed
+       [ "${1}" = '' ] && return 1
+           # expr will return 0 on match
+       expr "$1" : '[0-9][0-9]*$' > /dev/null 2>&1
+}
+
+# Need rwx access to the virtual tape itself.
+if ! test -d $SLOTDIR; then
+    echo `_ '<none> Virtual-tape directory %s does not exist.' "$SLOTDIR"`
+    exit 2
+fi
+if ! test -w $SLOTDIR; then
+    echo `_ '<none> Virtual-tape directory %s is not writable.' "$SLOTDIR"`
+    exit 2
+fi
+
+
+# need rwx access to directory of changer file
+CHANGERFILE=`amgetconf$SUF changerfile`
+conf_match=`expr "$CHANGERFILE" : .\*\.conf\$`
+if [ $conf_match -ge 6 ]; then
+        CONFIGFILE=$CHANGERFILE
+        CHANGERFILE=`echo $CHANGERFILE | sed 's/.conf$//g'`
+else
+        CONFIGFILE=$CHANGERFILE.conf
+fi
+
+CFDir=`dirname ${CHANGERFILE}`
+[ -d ${CFDir} -a -r ${CFDir} -a -w ${CFDir} -a -x ${CFDir} ] ||
+       { echo `_ "<none> %s: need 'rwx' access to '%s'" "$MYNAME" "$CFDir"` ; exit 2 ; }
+
+# check or create changer metadata files
+ACCESSFILE=$CHANGERFILE-access
+[ -f $ACCESSFILE -a -r $ACCESSFILE -a -w $ACCESSFILE ] ||
+       echo 0 > $ACCESSFILE ||
+       { echo `_ "<none> %s: could not access or create '%s'" "$MYNAME" "$ACCESSFILE"` ; exit 2; }
+CLEANFILE=$CHANGERFILE-clean
+[ -f $CLEANFILE -a -r $CLEANFILE -a -w $CLEANFILE ] ||
+       echo 0 > $CLEANFILE ||
+       { echo `_ "<none> %s: could not access or create '%s'" "$MYNAME" "$CLEANFILE"` ; exit 2 ; }
+SLOTFILE=$CHANGERFILE-slot
+[ -f $SLOTFILE -a -r $SLOTFILE -a -w $SLOTFILE ] ||
+       echo 0 > $SLOTFILE ||
+       { echo `_ "<none> %s: could not access or create '%s'" "$MYNAME" "$SLOTFILE"` ; exit 2; }
+
+# read and check metadata
+ACCESSCOUNT=`cat $ACCESSFILE`
+isinteger $ACCESSCOUNT || { ACCESSCOUNT=0 ; echo 0 > $ACCESSFILE ; }
+CLEANCOUNT=`cat $CLEANFILE`
+isinteger $CLEANCOUNT || { CLEANCOUNT=0 ; echo 0 > $CLEANFILE ; }
+
+FIRSTSLOT=1
+LASTSLOT=`amgetconf$SUF tapecycle`
+if test -r $CONFIGFILE; then
+    . $CONFIGFILE
+fi
+CURSLOT=0
+CLEANSLOT=$LASTSLOT
+NSLOT=`expr $LASTSLOT - $FIRSTSLOT + 1`
+
+load() {
+  WHICHSLOT=$1;
+  # unload should have been called, but just in case ...
+  [ -h $SLOTDIR/data ] && unload
+  ln -s $SLOTDIR/slot$WHICHSLOT $SLOTDIR/data
+  echo $WHICHSLOT > $SLOTFILE
+}
+
+unload() {
+  rm -f $SLOTDIR/data
+  echo "0" > $SLOTFILE
+}
+
+readstatus() {
+  CURSLOT=`cat $SLOTFILE`
+}
+
+loadslot() {
+  WHICHSLOT=$1
+
+  TYPE=string  # default if not numeric
+  isinteger $WHICHSLOT && TYPE=digit
+
+  readstatus
+  NEWSLOT=0
+  if [ $WHICHSLOT = "current" ]; then
+    if [ $CURSLOT -le 0 ]; then
+      load $FIRSTSLOT
+      echo "$FIRSTSLOT $TAPE"
+      exit 0
+    else
+      echo "$CURSLOT $TAPE"
+      exit 0
+    fi
+  elif [ $WHICHSLOT = "next" -o $WHICHSLOT = "advance" ]; then
+    NEWSLOT=`expr $CURSLOT + 1`
+    [ $NEWSLOT -gt $LASTSLOT ] && NEWSLOT=$FIRSTSLOT
+  elif [ $WHICHSLOT = "prev" ]; then
+      NEWSLOT=`expr $CURSLOT - 1`
+      [ $NEWSLOT -lt $FIRSTSLOT ] && NEWSLOT=$LASTSLOT
+  elif [ $WHICHSLOT = "first" ]; then
+      NEWSLOT=$FIRSTSLOT
+  elif [ $WHICHSLOT = "last" ]; then
+      NEWSLOT=$LASTSLOT
+  elif [ $TYPE = "digit" ]; then
+    if [ $WHICHSLOT -ge $FIRSTSLOT -a $WHICHSLOT -le $LASTSLOT ]; then
+      NEWSLOT=$WHICHSLOT
+    else
+      echo `_ '%s illegal slot' "$WHICHSLOT"`
+      exit 1
+    fi
+  elif [ $WHICHSLOT = "clean" ]; then
+    NEWSLOT=$CLEANSLOT
+  else
+    echo `_ '%s illegal request' "$WHICHSLOT"`
+    exit 1
+  fi
+  if [ $NEWSLOT = $CURSLOT ]; then
+    echo "$CURSLOT $TAPE"
+    exit 0
+  fi
+  if [ $NEWSLOT = $CLEANSLOT ]; then
+    expr ${CLEANCOUNT:=0} + 1 > $CLEANFILE
+    echo 0 > $ACCESSFILE
+  else
+    expr ${ACCESSCOUNT:=0} + 1 > $ACCESSFILE
+    if [ $ACCESSCOUNT -gt $LASTSLOT ]; then
+      $MYNAME -slot clean >/dev/null
+    fi
+  fi
+
+  readstatus
+  if [ $CURSLOT -ne 0 ]; then
+    unload
+  fi
+
+  if [ $WHICHSLOT = "advance" ]; then
+    echo "$NEWSLOT /dev/null"
+    exit 0
+  fi
+  load $NEWSLOT
+  echo "$NEWSLOT $TAPE"
+  exit 0
+}
+
+info() {
+  readstatus
+  echo "$CURSLOT $NSLOT 1"
+  exit 0
+}
+
+reset() {
+  readstatus
+  [ $CURSLOT -gt 0 ] && unload
+  load $FIRSTSLOT
+  echo "$FIRSTSLOT $tape"
+  exit 0
+}
+
+eject() {
+  readstatus
+  if [ $CURSLOT -le 0 ]; then
+    echo `_ '0 Drive was not loaded'`
+    exit 1
+  else
+    unload
+    echo $CURSLOT
+    exit 0
+  fi
+}
+
+
+while [ $# -ge 1 ];do
+  case $1 in
+    -slot)
+           shift
+           loadslot $*
+           ;;
+    -clean)
+           shift
+           loadslot clean
+           ;;
+    -current)
+           shift
+           loadslot current
+           ;;
+    -next)
+           shift
+           loadslot next
+           ;;
+    -advance)
+           shift
+           loadslot advance
+           ;;
+    -prev)
+           shift
+           loadslot prev
+           ;;
+    -first)
+           shift
+           loadslot first
+           ;;
+    -last)
+           shift
+           loadslot last
+           ;;
+    -info)
+           shift
+           info
+           ;;
+    -reset)
+            shift
+            reset
+            ;;
+    -eject)
+            shift
+            eject
+            ;;
+    *)
+       echo `_ '<none> Unknown option %s' "$1"`
+       exit 2
+       ;;
+  esac
+done
+
diff --git a/changer-src/chg-iomega.pl b/changer-src/chg-iomega.pl
new file mode 100644 (file)
index 0000000..56a1329
--- /dev/null
@@ -0,0 +1,290 @@
+#! @PERL@ -w
+
+# Catch for sh/csh on systems without #! ability.
+eval '(exit $?0)' && eval 'exec @PERL@ -S $0 ${1+"$@"}'
+        & eval 'exec @PERL@ -S $0 $argv:q'
+                if 0;
+
+# 
+# This changer script is designed for IOMEGA or JAZZ disks of various sizes
+# as well as any other removable disk media.
+#
+# This is a PURELY MANUAL changer. It requests insertion of disk media via
+# messages on /dev/tty. So it cannot be used via crontab.
+#
+# Make sure you comply with any of the following.
+# - Add statements 
+#         tpchanger "chg-iomega"
+#         tapedev "file:<mount_point_of_removable_disk>"
+#         # (e.g. tapedev "file:/mnt/iomega" )
+#         tapetype IOMEGA      
+#
+#         
+#         define tapetype IOMEGA {
+#             comment "IOMega 250 MB floppys"
+#             length 250 mbytes
+#             filemark 100 kbytes
+#             speed 1 mbytes
+#         }
+#   to your /etc/amanda/<backup_set>/amanda.conf file
+# - Add entry to /etc/fstab to specify mount point of removable disk
+#   and make this disk mountable by any user.
+# - Format all disks, add a "data" sub directory and label all disks
+#   by a call to amlabel.
+# - Be aware that as of version 2.4.4p1, amanda can't handle backups that are
+#   larger than the size of the removable disk media. So make sure
+#   /etc/amanda/<backup_set>/disklist specifies chunks smaller than the 
+#   disk size.
+#
+# This script is built up out of bits and pieces of other scripts, in
+# particular chg-chio.pl. That script was written by 
+# Nick Hibma - nick.hibma@jrc.it
+# 
+# Permission to freely use and distribute is granted (by me and was granted by
+# the original authors).
+#
+# Christoph Pospiech <pospiech@de.ibm.com>
+#
+
+require 5.001;
+
+($progname = $0) =~ s#/.*/##;
+
+use English;
+use Getopt::Long;
+
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
+$ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin";
+
+$| = 1;
+
+if (-d "@AMANDA_DBGDIR@") {
+       $logfile = "@AMANDA_DBGDIR@/changer.debug";
+} else {
+       $logfile = "/dev/null";
+}
+die "$progname: cannot open $logfile: $ERRNO\n"
+       unless (open (LOG, ">> $logfile"));
+
+
+#
+# get the information from the configuration file
+#
+
+$prefix="@prefix@";
+$prefix=$prefix;               # avoid warnings about possible typo
+$exec_prefix="@exec_prefix@";
+$exec_prefix=$exec_prefix;     # Ditto
+$sbindir="@sbindir@";
+if ( "@USE_VERSION_SUFFIXES@" eq "yes" ) {
+    $SUF = "-@VERSION@";
+} else {
+    $SUF = "";
+}
+
+chomp ($tapeDevice = `$sbindir/amgetconf$SUF tapedev 2>&1`);
+die "tapedev not found in amanda.conf"
+       if !$tapeDevice or $tapeDevice eq "" or
+           $tapeDevice =~ m/no such parameter/;
+chomp ($changerDevice = `$sbindir/amgetconf$SUF changerdev 2>&1`);
+chomp $changerDevice;
+die "changerdev not found in amanda.conf"
+       if !$changerDevice or $changerDevice eq "" or
+           $changerDevice =~ m/no such parameter/;
+
+#
+# Initialise a few global variables
+#
+
+$current_label = "";
+#$current_slot = 0;
+$max_slot = 1;
+
+@dow = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
+@moy = ("Jan", "Feb", "Mar", "Apr", "May", "Jun",
+       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
+
+sub do_time {
+       my (@t);
+       my ($r);
+
+       ###
+       # Get the local time for the value.
+       ###
+
+       @t = localtime (time ());
+
+       ###
+       # Return the result.
+       ###
+
+       $r = sprintf "%s %s %2d %2d:%02d:%02d %4d",
+         $dow[$t[6]],
+         $moy[$t[4]],
+         $t[3],
+         $t[2], $t[1], $t[0],
+         1900 + $t[5];
+
+       return $r;
+}
+
+
+sub is_mounted {
+    my $device = shift @_;
+    my ($directory) = ($device =~ m/file\:(.*)$/);
+    if ( -d "$directory/data" ) { return 1;}
+    else {return 0;}
+}
+
+sub request {
+    my $label = shift @_;
+    my $answer;
+    open (TTY, "+</dev/tty") or die "Can't open tty.\n";
+    print TTY "Insert Disk with label $label\n";
+    read TTY,$answer,1;
+    close TTY;
+    return $answer;
+}
+
+sub print_label {
+    my $label = shift @_;
+    open (TTY, "+</dev/tty") or die "Can't open tty.\n";
+    print TTY "The current Disk has label $label\n";
+    close TTY;
+}
+
+sub get_label {
+    my $device = shift @_;
+    my ($directory) = ($device =~ m/file\:(.*)$/);
+    my @dir_list =  glob("$directory/data/*");
+    while ( ($_= shift(@dir_list)) ) {
+       if ( /0+\.([\w\d]+)/ ) {return $1;}
+    }
+    return "no label";
+}
+
+
+sub Load {
+    my $device = shift @_;
+    my ($directory) = ($device =~ m/file\:(.*)$/);
+    my $label;
+    print LOG &do_time(), ": enter: Load $device\n";
+    if ( ! &is_mounted($device) ) {
+       print LOG &do_time(), ": mounting $directory\n";
+       system "mount $directory";
+    }
+    $label = get_label $device;
+    &print_label($label);
+    print LOG &do_time(), ": current label: $label\n";
+    print LOG &do_time(), ": leave: Load\n";
+
+}
+
+sub Unload {
+    my $device = shift @_;
+    my ($directory) = ($device =~ m/file\:(.*)$/);
+    print LOG &do_time(), ": enter: Unload $device\n";
+    if ( &is_mounted($device) ) {
+       print LOG &do_time(), ": ejecting $directory\n";
+       system "eject $directory";
+    }
+    print LOG &do_time(), ": leave: Unload\n";
+}
+
+
+
+#
+# Main program
+#
+
+#
+# Initialise
+#
+
+
+$opt_slot = 0;                                 # perl -w fodder
+$opt_info = 0;                                 # perl -w fodder
+$opt_reset = 0;                                        # perl -w fodder
+$opt_eject = 0;                                        # perl -w fodder
+$opt_search = 0;                                       # perl -w fodder
+$opt_label = 0;                                        # perl -w fodder
+
+GetOptions("slot=s", "info", "reset", "eject", "search=s", "label=s"); 
+
+
+if ( $opt_slot ) {
+    print LOG &do_time(), ": Loading slot $opt_slot requested\n";
+    if ( ! &is_mounted ($tapeDevice) ) {
+       &request ("any");
+       &Load ($tapeDevice);
+    }
+    $current_label = &get_label ($tapeDevice);
+    print LOG &do_time(), ": current label: $current_label\n";
+    print LOG &do_time(), ": 1 $tapeDevice\n";
+    print "1 $tapeDevice\n";
+    exit 0;
+}
+
+if ( $opt_info ) {
+    print LOG &do_time(), ": info requested\n";
+    $current_label = &get_label ($tapeDevice);
+    print LOG &do_time(), ": current label: $current_label\n";
+    print LOG &do_time(), ": 1 $max_slot 1 1\n";
+    print "1 $max_slot 1 1\n";
+    exit 0;
+}
+
+if ( $opt_reset ) {
+    print LOG &do_time(), ": reset requested\n";
+    &Unload ($tapeDevice);
+    &request ("any");
+    &Load ($tapeDevice);
+    $current_label = &get_label ($tapeDevice);
+    print LOG &do_time(), ": current label: $current_label\n";
+    print LOG &do_time(), ": 1 $tapeDevice\n";
+    print "1 $tapeDevice\n";
+    exit 0;
+}
+
+if ( $opt_eject ) {
+    print LOG &do_time(), ": eject requested\n";
+    &Unload ($tapeDevice);
+    print LOG &do_time(), ": 1 $tapeDevice\n";
+    print "1 $tapeDevice\n";
+    exit 0;
+}
+
+if ( $opt_search ) {
+    print LOG &do_time(), ": search label $opt_search requested\n";
+    $retry = 0;
+    $current_label = &get_label ($tapeDevice);
+    print LOG &do_time(), ": current label: $current_label\n";
+    while ( $opt_search ne $current_label && ++$retry < 5) {
+       &Unload ($tapeDevice);
+       &request ($opt_search);
+       &Load ($tapeDevice);
+       $current_label = &get_label ($tapeDevice);
+       print LOG &do_time(), ": search label: $opt_search\n";
+       print LOG &do_time(), ": current label: $current_label\n";
+    }
+    if ( $retry >= 5) {
+       print LOG &do_time(), ": disk not found\n";
+       print "disk not found\n";
+       exit 1;
+    } else {
+       print LOG &do_time(), ": 1 $tapeDevice\n";
+       print "1 $tapeDevice\n";
+       exit 0;
+    }
+}
+
+if ( $opt_label ) {
+    print LOG &do_time(), ": label $opt_label requested\n";
+    # no operation
+    print LOG &do_time(), ": 1 $tapeDevice\n";
+    print "1 $tapeDevice\n";
+    exit 0;
+}
+
+print "$progname: No command was received.  Exiting.\n";
+exit 1;
diff --git a/changer-src/chg-juke.sh b/changer-src/chg-juke.sh
new file mode 100755 (executable)
index 0000000..9e3809b
--- /dev/null
@@ -0,0 +1,267 @@
+#!@SHELL@
+
+# chg-juke
+#
+# This assumes we have possibly rait-striped drives in several
+# jukeboxes, controlled by the Fermilab "juke" package
+#
+# So we could have 3 drives in 3 jukeboxes:
+#   changerscript="chg-juke"
+#   changerfile=/some/file
+#   tapedev="rait:/dev/nst{1,2,3}"
+#   changerdev="myjuke{0,1,2}"
+# Or, if the jukebox has multiple drives:
+#   changerscript="chg-juke"
+#   changerfile=/some/file
+#   tapedev="rait:/dev/nst{1,2,3}"
+#   changerdev="myjuke"
+# We need therefore to generate lists with csh to expand the tapedev 
+# and changerdev, and deal with the possibility that there are several 
+# jukeboxes and several drives in each jukebox involved.
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+
+#
+# debugging...
+#
+if [ -d "@AMANDA_DBGDIR@" ]; then
+       DBGFILE=@AMANDA_DBGDIR@/changer.debug
+else
+       DBGFILE=/dev/null
+fi
+exec 2>$DBGFILE
+echo `_ 'args:'` $0 $* >&2
+set -x 
+
+#
+# the usual config fun
+#
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+        SUF="-@VERSION@";
+else
+       SUF=
+fi
+getconf=$sbindir/amgetconf$SUF
+
+#
+# make sure we can find JUKE later
+#
+JUKE_DIR=/usr/local
+# Fermilab specific
+if [ -f /usr/local/etc/setups.sh ]
+then
+    . /usr/local/etc/setups.sh
+    setup juke
+fi
+
+# add sbin, ucb, and the JUKE_DIR to PATH
+PATH="$PATH:$JUKE_DIR/bin:/usr/sbin:/sbin:/usr/ucb"
+export PATH JUKE_DIR
+
+build_drivelists() {
+    #
+    # figure out which drives are in which jukebox
+    #
+    count=0
+    for juke in $jlist
+    do
+       for d in $dlist
+       do
+           if juke list -j $juke drive $d | grep 'drive [0-9]' >&2
+           then
+               eval "drives_in_$juke=\"\$drives_in_$juke $d\""
+           fi
+       done
+    done
+}
+
+unload_drive_n_clean() {
+
+    #
+    # $1 is whether to clean it
+    #
+    cleanit=$1
+
+    #
+    # if the drive is ONLINE, mt unload it
+    #
+    if amdevcheck_status $tapedev; then
+        try_eject_device $tapedev
+    fi
+
+    #
+    # unload any tapes present, maybe load/unload a cleaning cartridge
+    #
+    for juke in $jlist
+    do
+       eval "jdlist=\"\$drives_in_$juke\""
+       for drive in $jdlist
+       do
+           juke unload -j $juke drive $drive >&2 || true
+           if juke list -j $juke drive $drive | grep '(empty)' >&2
+           then
+               :
+           else
+               echo `_ '%s %s unable to empty preceding tape from drive %s' "$slot" "$tapedev" "$drive"`
+               exit 1
+           fi
+
+           if $cleanit
+            then
+                juke load -j $juke drive $drive clean
+               sleep 120
+                juke unload -j $juke drive $drive
+            fi
+       done
+    done
+}
+
+load_drives() {
+    #
+    # load slots.  If it's a stripe, load several...
+    #
+    for juke in $jlist
+    do
+       eval "jdlist=\"\$drives_in_$juke\""
+       jndrives=`echo $jdlist | wc -w`
+       count=0
+       for drive in $jdlist
+       do
+           rslot=`expr $newslot '*' $jndrives + $count`
+           juke load -j $changerdev drive $drive slot $rslot >&2
+           if juke list -j $changerdev drive $drive | grep '(empty)' >&2
+           then
+               echo `_ '$slot $tapedev unable to load tape into drive' "$slot" "$tapedev"`
+               exit 1
+           fi
+           count=`expr $count + 1`
+       done
+    done
+
+    #
+    # wait for drive(s) to come online
+    #
+    count=0
+    until amdevcheck_status $tapedev; do
+       count=`expr $count + 1`
+       if [ $count -gt 24 ] 
+       then
+           echo `_ '%s %s never came online' "$slot" "$tapedev"`
+           exit 1
+       fi
+       sleep 5
+    done
+}
+
+
+ONLINEREGEX="ONLINE|READY|sense[_ ]key[(]0x0[)]|sense key error = 0|^er=0$"
+
+#
+# get config variables
+#
+changerfile=`$getconf changerfile`
+    tapedev=`$getconf tapedev`
+ changerdev=`$getconf changerdev`
+      dlist=`csh -c "echo $tapedev" | sed -e 's/rait://g' -e 's/tape://g'`
+    ndrives=`echo $dlist | wc -w`
+      jlist=`csh -c "echo $changerdev"`
+     njukes=`echo $jlist | wc -w`
+ totalslots=`for juke in $jlist ; do juke list -j $juke; done | 
+               grep -v '^clean' | 
+               grep 'slot [0-9]' | 
+               wc -l`
+
+if [ $ndrives -gt 1 ]
+then
+   #
+   # if it's a 3 tape stripe and we have 30 actual slots
+   # we only have 10 virtual slots...
+   #
+   totalslots=`expr $totalslots / $ndrives`
+fi
+
+build_drivelists
+
+#
+# get current slot if we have one
+#
+if [ -f "$changerfile" ] 
+then
+    slot="`cat $changerfile`"
+else
+    slot=0
+    echo $slot > $changerfile
+fi
+
+#
+# We treat -reset just like -slot 0
+#
+if [ x$1 = 'x-reset' ]
+then
+    set : -slot 0
+    shift
+fi
+
+case x$1 in
+
+x-slot) 
+
+    #
+    # handle special slots...
+    #
+    case "$2" in
+    current)   newslot=$slot           ; load=true;;
+    next)      newslot=`expr $slot + 1`; load=true;;
+    advance)   newslot=`expr $slot + 1`; load=false;;
+    prev)      newslot=`expr $slot - 1`; load=true;;
+    first)     newslot=0               ; load=true;;
+    last)      newslot=-1              ; load=true;;
+    *)         newslot=$2              ; load=true;;
+    esac
+
+    if [ $newslot = "clean" ]
+    then
+       unload_drive_n_clean true
+    else 
+       if [ 0 -gt $newslot ]
+       then
+           newslot=`expr $totalslots - 1`
+       fi
+
+       if [ $totalslots -le  $newslot ]
+       then
+           newslot=0
+       fi
+
+       echo $newslot > $changerfile
+       slot=$newslot
+
+       if $load
+       then
+           unload_drive_n_clean false
+           load_drives
+       fi
+    fi
+
+    echo $slot $tapedev
+    ;;
+
+x-info)
+    echo $slot $totalslots 1
+    exit 0
+    ;;
+
+x-eject)
+    unload_drive_n_clean false
+    echo $slot $tapedev
+    ;;
+esac
+
+exit $rc
diff --git a/changer-src/chg-manual.sh b/changer-src/chg-manual.sh
new file mode 100644 (file)
index 0000000..d480de9
--- /dev/null
@@ -0,0 +1,323 @@
+#!@SHELL@ 
+#
+# Exit Status:
+# 0 Alles Ok
+# 1 Illegal Request
+# 2 Fatal Error
+#
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+amlibexecdir=@amlibexecdir@
+. ${amlibexecdir}/chg-lib.sh
+
+#
+#      Changer config file (changerfile)
+#
+#      resend_mail=900         # 15 minutes
+#      timeout_mail=604800     # 7 days
+#      request="tty"           # Use the tty to ask the user to change tape.
+#                              # Can't be use by cron
+#      request="email"         # Send an email to ask the user to change tape.
+#      request="tty_email"     # Use the tty if it exist or send an email.
+#                      #Default is "tty_email"
+#       mtx_binary="/path/to/mtx" # path of 'mtx'; default is value discovered by
+#                               # configure
+#
+#
+
+
+if [ -d "@AMANDA_DBGDIR@" ]; then
+       logfile=@AMANDA_DBGDIR@/changer.debug
+else
+       logfile=/dev/null
+fi
+
+myname=$0
+
+EGREP='@EGREP@'
+
+if ! error=`try_find_mt`; then
+    echo <none> $error
+    exit 2
+fi
+
+MAILER=@MAILER@
+ONLINEREGEX="ONLINE|READY|sense[_ ]key[(]0x0[)]|sense key error = 0|^er=0$|, mt_erreg: 0x0|^Current Driver State: at rest$"
+REPORTTO=`amgetconf mailto`
+tape=`amgetconf tapedev`
+
+if [ -z "$tape" ]; then
+  echo `_ '<none> tapedev not specified in amanda.conf.'`
+  exit 2
+fi
+
+ORG=`amgetconf ORG`
+
+firstslot=1
+lastslot=99
+resend_mail=900                # 15 minutes
+timeout_mail=604800    # 7 days
+
+changerfile=`amgetconf changerfile`
+
+conf_match=`expr "$changerfile" : .\*\.conf\$`
+if [ $conf_match -ge 6 ]; then
+        configfile=$changerfile
+        changerfile=`echo $changerfile | sed 's/.conf$//g'`
+else
+        configfile=$changerfile.conf
+fi
+
+cleanfile=$changerfile-clean
+accessfile=$changerfile-access
+slotfile=$changerfile-slot
+[ ! -f $cleanfile ] && echo 0 > $cleanfile
+[ ! -f $accessfile ] && echo 0 > $accessfile
+[ ! -f $slotfile ] && echo $firstslot > $slotfile
+cleancount=`cat $cleanfile`
+accesscount=`cat $accessfile`
+slot=`cat $slotfile`
+
+# define these functions early so that they can be overridden in changerfile.conf
+
+request_tty() {
+       if > /dev/tty; then
+               echo -n `_ 'Insert tape into slot %s and press return' "$1"` > /dev/tty
+               read ANSWER < /dev/tty
+       else
+               echo -n `_ 'no /dev/tty to ask to change tape'`
+               exit 1
+       fi
+}
+
+###
+# If $changerfile exists, source it into this script.  One reason is to
+# override the request() function above which gets called to request
+# that a tape be mounted.  Here is an alternate versions of request()
+# that does things more asynchronous:
+#
+request_email() {
+       # Send E-mail about the mount request and wait for the drive
+       # to go ready by checking the status once a minute.  Repeat
+       # the E-mail once an hour in case it gets lost.
+       timeout=0
+       gtimeout=$timeout_mail
+       while true;do
+           if [ $gtimeout -le 0 ]; then
+               echo -n `_ 'timeout waiting for tape online'`
+               exit 1;
+           fi
+           if [ $timeout -le 0 ]; then
+               msg=`_ 'insert Amanda tape into slot %s (%s)' "$1" "$tape"`
+               subject=`_ '%s AMANDA TAPE MOUNT REQUEST FOR SLOT %s' "$ORG" "$1"`
+               echo "$msg" | $MAILER -s "$subject" $REPORTTO
+               timeout=$resend_mail
+           fi
+            echo `_ '     -> status %s' "$tape"` >> $logfile
+            if amdevcheck_status $tape; then
+               break
+           fi
+           sleep 60
+           timeout=`expr $timeout - 60`
+           gtimeout=`expr $gtimeout - 60`
+       done
+}
+
+request_tty_email() {
+       if > /dev/tty; then
+               echo -n `_ 'Insert tape into slot %s and press return' "$1"` > /dev/tty
+               read ANSWER < /dev/tty
+       else
+               request_email "$1"
+       fi
+}
+
+request() {
+       if [ X"$request" = X"tty" ]; then
+               request_tty "$1"
+       else if [ X"$request" = X"email" ]; then
+               request_email "$1"
+       else
+               request_tty_email "$1"
+       fi
+       fi
+}
+
+# source the changer configuration file (see description, top of file)
+if [ -f $configfile ]; then
+       . $configfile
+fi
+
+# adjust MTX, if necessary
+test -n "${mtx_binary}" && MTX="${mtx_binary}"
+
+# check that MAILER is defined
+if test -z "$MAILER"; then
+    if test x"$request" = x"email" || test x"$request" = x"tty-email"; then
+       answer=`_ "<none> %s: Can't send email because MAILER is not defined" "$myname"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 1
+    fi
+fi
+
+#
+
+eject() { 
+       echo `_ '     -> status %s' "$tape"` >> $logfile
+        if amdevcheck_status $tape; then
+           echo `_ '     -> offline %s' "$tape"` >> $logfile
+            try_eject_device $tape
+           answer="$slot $tape"
+           code=0
+       else
+           answer=`_ '<none> %s: Drive was not loaded' "$myname"`
+           code=1
+       fi
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit $code
+}
+
+#
+
+reset() {
+       echo `_ '     -> status %s' "$tape"` >> $logfile
+        if amdevcheck_status $tape; then
+               answer="$slot $tape"
+       else
+               answer="0 $tape"
+       fi
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 0
+}
+
+# load #
+
+loadslot() {
+       echo `_ '     -> status %s' "$tape"` >> $logfile
+        # amdevcheck returns zero if the tape exists.
+        amdevcheck_status $tape;
+        tape_status=$?
+
+       whichslot=$1
+       case $whichslot in
+       current)
+               load=$slot
+               [ $load -eq 0 ] && load=$firstslot
+               [ $load -gt $lastslot ] && load=$firstslot
+               [ $load -lt $firstslot ] && load=$lastslot
+               ;;
+       next|advance)
+               load=`expr $slot + 1`
+               [ $load -gt $lastslot ] && load=$firstslot
+               ;;
+       prev)
+               load=`expr $slot - 1`
+               [ $load -lt $firstslot ] && load=$lastslot
+               ;;
+       first)
+               load=$firstslot
+               ;;
+       last)
+               load=$lastslot
+               ;;
+       [0-9]|[0-9][0-9])
+               if [ $1 -lt $firstslot -o $1 -gt $lastslot ]; then
+                       answer=`_ '<none> %s: slot must be %s .. %s' "$myname" "firstslot" "$lastslot"`
+                       echo `_ 'Exit ->'` $answer >> $logfile
+                       echo $answer
+                       exit 1
+               fi
+               load=$1
+               ;;
+       *)
+               answer=`_ '<none> %s: illegal slot: %s' "$myname" "$1"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 1
+               ;;
+       esac
+       #
+       if [ $tape_status -eq 0 -a $load = $slot ];then
+               # already loaded
+               answer="$slot $tape"
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 0
+       fi
+
+       expr $accesscount + 1 > $accessfile
+
+       if [ $tape_status -eq 0 ]; then
+               echo `_ "     -> offline %s" "$tape"` >> $logfile
+                try_eject_device $tape
+               tape_status=1
+       fi
+       if [ $whichslot = advance ]; then
+               tape=/dev/null
+       else
+               echo `_ '     -> load   %s' "$load"` >> $logfile
+               while true; do
+                       request $load
+                       echo `_ '     -> status %s' "$tape"` >> $logfile
+                        if amdevcheck_status $tape; then
+                            break;
+                        fi
+               done
+       fi
+       echo $load > $slotfile
+       answer="$load $tape"
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 0
+}
+
+#
+
+info() {
+       echo `_ '     -> status %s' "$tape"` >> $logfile
+        if amdevcheck_status $tape; then
+               answer="$slot $lastslot 1"
+       else
+               answer="0 $lastslot 1"
+       fi
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 0
+}
+
+#
+# main part
+#
+
+echo `gettext "args ->"` "$@" >> $logfile
+while [ $# -ge 1 ];do
+       case $1 in
+       -slot)
+               shift
+               loadslot $*
+               ;;
+       -info)
+               shift
+               info
+               ;;
+       -reset)
+               shift
+               reset
+               ;;
+       -eject)
+               shift
+               eject
+               ;;
+       *)
+               fmt`gettext "<none> %s: Unknown option %s\n"`
+               printf $fmt $myname $1
+               exit 2
+               ;;
+       esac
+done
+
+exit 0
diff --git a/changer-src/chg-mcutil.sh b/changer-src/chg-mcutil.sh
new file mode 100644 (file)
index 0000000..16b56f1
--- /dev/null
@@ -0,0 +1,578 @@
+#!@SHELL@ 
+#
+# Author: Robert Dege
+#
+#
+# version 1.2
+# -----------
+# fixed last_cleaned file so that if it doesn't exist, it gets created with current date, not '0,0'
+# fixed a bug that was reporting the wrong slot # to amcheck
+#
+# version 1.1
+# -----------
+# amverify was failing when using -slot current.  Fixed exit $code from 1 -> 0.
+# removed useless $current variables from movetape() function.
+#
+#
+#
+# Exit Status:
+# 0 Alles Ok
+# 1 Illegal Request
+# 2 Fatal Error
+#
+
+
+#
+# Set Path so that it includes Amanda binaries, and access to tapechanger & drive programs
+#
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+
+#
+# Define Suffix for amanda binaries
+#
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+        SUF="-@VERSION@"
+else
+        SUF=
+fi
+
+#
+# Load configuration data from the config file
+#
+
+ourconf=`amgetconf$SUF changerfile`
+myname=$0
+
+
+if [ ! -f "$ourconf" ]; then
+        code=2
+        echo `_ 'Command Line ->'` $myname $@
+       echo `_ 'Exit(%s): %s not found as listed in amanda.conf' "$code" "$ourconf"` 1>&2
+        exit $code
+fi
+
+
+# grab mcutil info
+tmpval1=`grep ^mcutil $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^mcutil $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+       code=2
+        echo `_ 'Command Line ->'` $myname $@
+       echo `_ 'Exit(%s): mcutil not specified in %s' "$code" "$ourconf"` 1>&2
+       exit $code
+elif [ -z "$tmpval1" ]; then
+       MCUTIL=$tmpval2
+else
+       MCUTIL=$tmpval1
+fi
+
+
+# grab tape info
+tmpval1=`grep ^tape $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^tape $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+       code=2
+        echo `_ 'Command Line ->'` $myname $@
+       echo `_ 'Exit(%s): tape not specified in %s' "$code" "$ourconf"` 1>&2
+       exit $code
+elif [ -z "$tmpval1" ]; then
+       tape=$tmpval2
+else
+       tape=$tmpval1
+fi
+
+
+# grab firstslot info
+tmpval1=`grep ^firstslot $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^firstslot $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+        code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): firstslot not specified in %s' "$code" "$ourconf"` 1>&2
+        exit $code
+elif [ -z "$tmpval1" ]; then
+        firstslot=$tmpval2
+else
+        firstslot=$tmpval1
+fi
+
+
+# grab lastslot info
+tmpval1=`grep ^lastslot $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^lastslot $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+        code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): lastslot not specified in %s' "$code" "$ourconf"` 1>&2
+elif [ -z "$tmpval1" ]; then
+        lastslot=$tmpval2
+else
+        lastslot=$tmpval1
+fi
+
+
+# grab use_cleaning info
+tmpval1=`grep ^use_cleaning $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^use_cleaning $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+        code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): use_cleaning not specified in %s' "$code" "$ourconf"` 1>&2
+        exit $code
+elif [ -z "$tmpval1" ]; then
+        use_cleaning=$tmpval2
+else
+        use_cleaning=$tmpval1
+fi
+
+
+# grab cleanslot info
+tmpval1=`grep ^cleanslot $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^cleanslot $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+        code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): cleanslot not specified in %s' "$code" "$ourconf"` 1>&2
+        exit $code
+elif [ -z "$tmpval1" ]; then
+        cleanslot=$tmpval2
+else
+        cleanslot=$tmpval1
+fi
+
+
+# grab cleansleep info
+tmpval1=`grep ^cleansleep $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^cleansleep $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+       code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): cleansleep not specified in %s' "$code" "$ourconf"` 1>&2
+       exit $code
+elif [ -z "$tmpval1" ]; then
+       cleansleep=$tmpval2
+else
+       cleansleep=$tmpval1
+fi
+
+
+# grab cleanme info
+tmpval1=`grep ^cleanme $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^cleanme $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+       code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): cleanme not specified in %s' "$code" "$ourconf"` 1>&2
+       exit $code
+elif [ -z "$tmpval1" ]; then
+       cleanme=$tmpval2
+else
+       cleanme=$tmpval1
+fi
+
+
+# grab cleanfile info
+tmpval1=`grep ^cleanfile $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^cleanfile $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+        code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): cleanfile not specified in %s' "$code" "$ourconf"` 1>&2
+        exit $code
+elif [ -z "$tmpval1" ]; then
+        cleanfile=$tmpval2
+else
+        cleanfile=$tmpval1
+fi
+
+
+# grab lastfile info
+tmpval1=`grep ^lastfile $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^lastfile $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+       code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): lastfile not specified in %s' "$code" "$ourconf"` 1>&2
+       exit $code
+elif [ -z "$tmpval1" ]; then
+       lastfile=$tmpval2
+else
+       lastfile=$tmpval1
+fi
+
+
+# grab currentslot info
+tmpval1=`grep ^currentslot $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^currentslot $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+       code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): currentslot not specified in %s' "$code" "$ourconf"` 1>&2
+       exit $code
+elif [ -z "$tmpval1" ]; then
+       currentslot=$tmpval2
+else
+       currentslot=$tmpval1
+fi
+
+
+# grab logfile info
+tmpval1=`grep ^logfile $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^logfile $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+       code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): logfile not specified in %s' "$code" "$ourconf"` 1>&2
+       exit $code
+elif [ -z "$tmpval1" ]; then
+       logfile=$tmpval2
+else
+       logfile=$tmpval1
+fi
+
+[ ! -w $logfile ] && logfile=/dev/null
+
+
+# grab slot0source info
+tmpval1=`grep ^slot0source $ourconf | awk -F\  '{print $2}'`
+tmpval2=`grep ^slot0source $ourconf | awk -F= '{print $2}'`
+if [ -z "$tmpval1" ] && [ -z "$tmpval2" ]; then
+       code=2
+        echo `_ 'Command Line ->'` $myname $@
+        echo `_ 'Exit(%s): slot0source not specified in %s' "$code" "$ourconf"` 1>&2
+       exit $code
+elif [ -z "$tmpval1" ]; then
+       slot0source=$tmpval2
+else
+       slot0source=$tmpval1
+fi
+
+
+
+#
+# Verify currentslot contains a value
+#
+if [ ! -f $currentslot ] || [ `cat $currentslot` -lt $firstslot ];then
+   readstatus
+   echo $used > $currentslot
+fi
+
+current=`cat $currentslot`
+
+
+# Start logging to $logfile
+echo "\n\n==== `date` ====" >> $logfile
+echo `_ 'Command Line ->'` $myname $@ >> $logfile
+
+
+#
+# is Use Cleaning activated?
+#
+if [ $use_cleaning -eq 1 ]; then
+   curday=`date +%j`
+   curyear=`date +%Y`
+
+   [ ! -f $cleanfile ] && echo 0 > $cleanfile
+   [ ! -f $lastfile ] && echo $curday,$curyear > $lastfile
+
+
+#
+# Check to see when tape drive was last cleaned
+# output warning message if it's been too long
+# Currently, if it's been more than 45days, then
+# an error message is displayed everytime the
+# script is called, until the clean parameter
+# is run
+#
+   cleaned=`cat $cleanfile`
+   lastcleaned=`cut -d, -f1 $lastfile`
+   yearcleaned=`cut -d, -f2 $lastfile`
+
+  if [ `expr $curday - $lastcleaned`  -lt 0 ];then
+     diffday=`expr $curday - $lastcleaned + 365`
+     diffyear=`expr $curyear - $yearcleaned - 1`
+  else
+     diffday=`expr $curday - $lastcleaned`
+     diffyear=`expr $curyear - $yearcleaned`
+  fi
+
+  if [ $diffday -gt $cleanme ] || [ $diffyear -ge 1 ];then
+     if [ $diffyear -ge 1 ];then
+         echo `_ "Warning, it's been %s year(s) & %s day(s) since you last cleaned the tape drive!" "$diffyear" "$diffday"`
+     else
+         echo `_ "Warning, it's been %s day(s) since you last cleaned the tape drive!" "$diffday"`
+     fi
+  fi
+
+fi
+
+
+#
+# Read if there is a tape in the tape drive
+# If so, determine what slot is the tape from
+#
+readstatus() {
+  echo `_ "querying tape drive....."` >> $logfile
+  used=`expr \`$MCUTIL -e drive | tr = \] | cut -d\] -f2\` - $slot0source`
+  echo `_ " Done"` >> $logfile
+
+  # Give changer a chance to reset itself
+  sleep 3
+}
+
+
+#
+# If tape is in the drive, eject it
+#
+eject() {
+  echo `_ "tape drive eject was called"` >> $logfile
+
+  readstatus 
+
+  if [ $used -ge $firstslot ];then
+    $MCUTIL -m drive slot:$used
+    code=$?
+  else
+    code=1
+  fi
+
+  if [ $code -eq 0 ];then
+    answer=`_ 'Cartridge %s successfully ejected from %s' "$used" "$tape"`
+    echo `_ "Exit(%s): %s" "$code" "$answer"` >> $logfile
+    echo $current $answer      #For amtape output  
+    return $code
+  elif [ $code -eq 1 ];then
+    answer=`_ "No Cartridge in Tape Drive"`
+    echo `_ 'Exit(%s): %s' "$code" "$answer"` >> $logfile
+    echo $current $answer      #For amtape output
+    exit $code
+  else
+    answer=`_ 'Tape abnormally failed'`
+    echo `_ 'Exit(%s): %s' "$code" "$answer"` >> $logfile
+    echo $current $answer      #For amtape output
+    exit $code
+  fi
+}
+
+
+#
+# reset tape drive to a current state.
+# This involves ejecting the current tape (if occupied)
+# and inserting the tape in $firstslot
+#
+reset() {
+  echo `_ 'tape drive reset was called'` >> $logfile
+
+  readstatus
+
+  if [ $used -ge $firstslot ];then
+     eject
+  fi
+
+  res=`$MCUTIL -m slot:$firstslot drive`
+  code=$?
+
+
+  if [ $code -eq 0 ];then
+    echo $firstslot > $currentslot
+    answer=`_ '%s - Tape drive was successfully reset' "$firstslot"`
+  elif [ $code -eq 1 ];then
+    answer=`_ '%s - Tape drive reset failed\nCommand -> %s' "$firstslot" "$res"`
+  else
+    code=2
+    answer=`_ '%s - Tape abnormally failed -> %s' "$firstslot" "$res"`
+  fi
+
+  echo `_ 'Exit(%s): slot %s' "$code" "$answer"` >> $logfile
+  echo $firstslot      #For amtape output 
+  exit $code
+}
+
+
+
+
+#
+# Load a specific cartridge into the changer
+#
+loadslot() {
+  echo `_ "loadslot was called"` >> $logfile
+
+  readstatus
+
+  whichslot=$1
+
+  case $whichslot in
+    current)
+       if [ $current -ge $firstslot ];then
+          load=$current
+       else
+          load=$used
+       fi
+
+       movetape
+       ;;
+    next|advance)
+         [ $used -lt $firstslot ] && used=$current
+
+         load=`expr $used + 1`
+         [ $load -gt $lastslot ] && load=$firstslot
+
+         if [ $whichslot = advance ];then
+            echo $load > $currentslot
+            code=0
+            answer=`_ 'advancing to slot %s' "$load"`
+            echo `_ 'Exit(%s): %s' "$code" "$answer"` >> $logfile
+            echo $load $code
+            exit $code
+         else
+            movetape
+         fi
+         ;;
+    prev)
+         [ $used -lt $firstslot ] && used=$current
+
+         load=`expr $used - 1`
+         [ $load -lt $firstslot ] && load=$lastslot
+         movetape
+         ;;
+    first)
+         load=$firstslot
+         movetape
+         ;;
+    last)
+         load=$lastslot
+         movetape
+         ;;
+    [$firstslot-$lastslot])
+            load=$1
+            movetape
+         ;;
+    clean)
+         if [ use_cleaning -eq 1 ];then
+            current=$cleanslot
+            eject
+            $MCUTIL slot:$cleanslot drive
+            sleep $cleansleep
+            echo "$curday,$curyear" > $lastfile
+            echo `expr $cleaned + 1` > $cleanfile
+            reset
+         else
+            code=1
+            answer=`_ "Cleaning not enabled in config"`
+            echo `_ 'Exit(%s): %s' "$code" "$answer"` >> $logfile
+            echo $cleanslot $answer
+            exit $code
+         fi
+         ;;
+    *)
+       code=1
+       answer=`_ '"%s" invalid menu option' "$whichslot"`
+       echo `_ 'Exit(%s): %s' "$code" "$answer"` >> $logfile
+       echo "$answer"
+       exit $code
+       ;;
+    esac
+}
+
+
+#
+# sub-function that slot calls to actually eject the tape
+# & load in the correct slot cartridge
+#
+movetape() {
+
+    # If the requested slot is already loaded in the tape drive
+    if [ $load -eq $used ]; then
+        code=0
+       answer=`_ 'slot %s is already loaded' "$load"`
+        echo `_ 'Exit(%s): %s' "$code" "$answer"` >> $logfile
+        echo $load $tape       # For amtape output
+        exit $code
+    elif [ $used -ge $firstslot ];then
+       current=$load
+       eject
+    else
+       echo $load $tape        # For amtape output
+    fi
+
+    echo `_ 'Loading slot %s into Tape drive' "$load"` >> $logfile
+    $MCUTIL -m  slot:$load drive
+    code=$?
+
+    if [ $code -eq 0 ];then
+       echo $load > $currentslot
+       answer=`_ 'Cartridge %s successfully loaded in Tape drive' "$load"`
+    else
+       answer=`_ 'Cartridge %s failed to load in Tape drive' "$load"`
+    fi
+    echo `_ 'Exit(%s): %s' "$code" "$answer"` >> $logfile
+    exit $code
+}
+
+
+info() {
+  echo `_ 'tape drive info was called'` >> $logfile
+
+  readstatus
+
+  if [ $used -lt 0 ];then
+    used=0
+  fi
+
+  code=0
+  answer="$used $lastslot 1"
+  echo `_ 'Exit(%s): %s' "$code" "$answer"` >> $logfile
+  echo "$answer"
+  exit $code
+}
+
+
+  case $1 in
+    -slot)
+          shift
+          loadslot $*
+          ;;
+    -device)
+          echo $tape
+          ;;
+    -info)
+           shift
+           info
+           ;;
+    -reset)
+           shift
+           reset
+           ;;
+    -eject)
+           shift
+           eject
+           ;;
+    --help|-help)
+           echo `_ '-slot {current|next|previous|first|last|%s-%s|clean}' "$firstslot" "$lastslot"`
+           echo `_ '   current  - show contents of current slot'`
+           echo `_ '   next     - load tape from next slot'`
+           echo `_ '   previous - load tape from previous slot'`
+           echo `_ '   first    - load tape from first slot'`
+           echo `_ '   last     - load tape from last slot'`
+           echo `_ '   %s - %s  - load tape from slot <slot #>' "$firstslot" "$lastslot"`
+           echo `_ '   clean    - Clean the drive'`
+           echo `_ '-device   : Show current tape device'`
+           echo `_ '-reset    : Reset changer to known state'`
+           echo `_ '-eject    : Eject current tape from drive'`
+           echo `_ '-info     : Output {current slot | # of slots | can changer go backwards}'`
+           echo `_ '-help     : Display this help'`
+           ;;
+    *)
+       echo `_ "<usage> %s -{slot|device|reset|eject|help}" "$myname"`
+       ;;
+ esac
diff --git a/changer-src/chg-mtx.sh b/changer-src/chg-mtx.sh
new file mode 100644 (file)
index 0000000..173f20e
--- /dev/null
@@ -0,0 +1,273 @@
+#!@SHELL@ 
+#
+# Exit Status:
+# 0 Alles Ok
+# 1 Illegal Request
+# 2 Fatal Error
+#
+
+# source utility functions and values from configure
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+amlibexecdir=@amlibexecdir@
+. ${amlibexecdir}/chg-lib.sh
+
+if [ -d "@AMANDA_DBGDIR@" ]; then
+       logfile=@AMANDA_DBGDIR@/changer.debug
+else
+       logfile=/dev/null
+fi
+
+myname=$0
+
+tape=`amgetconf tapedev`
+if [ -z "$tape" ]; then
+  echo "<none> tapedev not specified in amanda.conf";
+  exit 2;
+fi
+
+TAPE=`amgetconf changerdev`; export TAPE # for mtx command
+if [ -z "$TAPE" ]; then
+  echo "<none> changerdev not specified in amanda.conf";
+  exit 2;
+fi
+
+if [ "$tape" = "/dev/null" -o "$TAPE" = "/dev/null" ]; then
+  echo "<none> Both tapedev and changerdev must be specified in config file";
+  exit 2;
+fi
+
+MTX=@MTX@
+
+if [ -x $sbindir/ammt$SUF ]; then
+       MT=$sbindir/ammt$SUF
+       MTF=-f
+elif [ -x "@MT@" ]; then
+       MT=@MT@
+       MTF=@MT_FILE_FLAG@
+else
+       answer="<none> $myname: mt program not found"
+       code=1
+       echo "Exit -> $answer" >> $logfile
+       echo "$answer"
+       exit $code
+fi
+echo MT "->" $MT $MTF >> $logfile
+
+if [ -x $sbindir/amdd$SUF ]; then
+       DD=$sbindir/amdd$SUF
+elif [ -x "@DD@" ]; then
+       DD=@DD@
+else
+       answer="<none> $myname: dd program not found"
+       code=1
+       echo "Exit -> $answer" >> $logfile
+       echo "$answer"
+       exit $code
+fi
+echo DD "->" $DD >> $logfile
+
+firstslot=1
+lastslot=5
+# counted from 1 !!!
+cleanslot=6
+
+changerfile=`amgetconf changerfile`
+
+cleanfile=$changerfile-clean
+accessfile=$changerfile-access
+[ ! -f $cleanfile ] && echo 0 > $cleanfile
+[ ! -f $accessfile ] && echo 0 > $accessfile
+cleancount=`cat $cleanfile`
+accesscount=`cat $accessfile`
+#
+
+readstatus() {
+  used=`$MTX -s |
+    sed -n 's/Drive: No tape Loaded/-1/p;s/Drive: tape \(.\) loaded/\1/p'`
+
+  if [ -z "$used" ]; then
+    used="-1";
+  fi
+}
+
+
+eject() {
+  readstatus 
+  if [ $used -gt 0 ];then
+    $MTX -u $used
+    answer="0 $tape"
+    echo `_ 'Exit ->'` $answer >> $logfile
+    echo $answer
+    exit 0
+  else
+    answer=`_ '<none> %s: Drive was not loaded' "$myname"`     
+    echo `_ 'Exit ->'` $answer >> $logfile
+    echo $answer
+    exit 1
+  fi
+}
+
+reset() {
+  readstatus
+  if [ $used -gt 0 ];then
+    $MTX -u $used
+  fi
+  res=`$MTX -l 1`
+  if [ $? -eq 0 ];then
+    answer="1 $tape"
+    echo `_ 'Exit ->'` $answer >> $logfile
+    echo $answer
+    exit 0
+  else
+    answer="1 $res"
+    echo `_ 'Exit ->'` $answer >> $logfile
+    echo $answer
+    exit 1
+  fi
+}
+#
+#
+loadslot() {
+  readstatus
+  echo "     -> loaded $used" >> $logfile
+  whichslot=$1
+  case $whichslot in
+    current)
+            if [ $used -lt 0 ];then
+              $MTX -l 1
+              used=1
+            fi
+            answer="$used $tape"
+            echo `_ 'Exit ->'` $answer >> $logfile
+            echo $answer
+            exit 0
+            ;;
+    next|advance)
+         load=`expr $used + 1`
+         [ $load -gt $lastslot ] && load=$firstslot
+         ;;
+    prev)
+         load=`expr $used - 1`
+         [ $load -lt $firstslot ] && load=$lastslot
+         ;;
+    first)
+         load=$firstslot
+         ;;
+    last)
+         load=$lastslot
+         ;;
+    [$firstslot-$lastslot])
+         load=$1
+         ;;
+    clean)
+         load=$cleanslot
+         ;;
+    *)
+       answer=`_ '<none> %s: illegal request: "%s"' "$myname" "$whichslot"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 1
+       ;;
+    esac
+
+    if [ $load = $used ]; then
+        answer="$used $tape"
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 0
+    fi
+
+    if [ $load = $cleanslot ]; then
+       expr $cleancount + 1 > $cleanfile
+       echo 0 > $accessfile
+    else
+       expr $accesscount + 1 > $accessfile
+       if [ $accesscount -gt 9 ]; then
+               $myname -slot clean >/dev/null
+       fi
+    fi
+
+    # Slot 6 might contain an ordinary tape rather than a cleaning
+    # tape. A cleaning tape auto-ejects; an ordinary tape does not.
+    # We therefore have to read the status again to check what
+    # actually happened.
+    readstatus
+       
+
+    if [ $used -gt 0 ];then
+      echo "     -> unload $used" >> $logfile
+      res=`$MTX -u $used`
+      status=$?
+      echo "     -> status $status" >> $logfile
+      echo "     -> res    $res" >> $logfile
+      if [ $status -ne 0 ];then
+        answer=`_ '<none> %s: %s' "$myname" "$res"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+      fi
+    fi
+    if [ $whichslot = advance ];then
+      answer="$load /dev/null"
+      echo `_ 'Exit ->'` $answer >> $logfile
+      echo $answer
+      exit 0
+    fi
+    echo `_ '     -> load   %s' "$load"` >> $logfile
+    res=`$MTX -l $load`
+    status=$?
+    echo `_ '     -> status %s' "$status"` >> $logfile
+    echo `_ '     -> result %s' "$res"` >> $logfile
+    if [ $status -eq 0 ];then
+      amdevcheck_status $tape
+      answer="$load $tape"
+      code=0
+    else
+      answer="$load $res"
+      code=2
+    fi
+    echo `_ 'Exit ->'` $answer >> $logfile
+    echo $answer
+    exit $code
+}
+#
+info() {
+  readstatus
+  echo "     -> info   $used" >> $logfile
+  if [ $used -lt 0 ];then
+    used=0
+  fi
+  answer="$used $lastslot 1"
+  echo `_ 'Exit ->'` $answer >> $logfile
+  echo $answer
+  exit 0
+}
+#
+echo Args "->" "$@" >> $logfile
+while [ $# -ge 1 ];do
+  case $1 in
+    -slot)
+          shift
+          loadslot $*
+          ;;
+    -info)
+          shift
+          info
+          ;;
+    -reset)
+           shift
+           reset
+           ;;
+    -eject)
+           shift
+           eject
+           ;;
+    *)
+       answer=`_ '<none> %s: Unknown option %s' "$myname" "$1"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+       ;;
+  esac
+done
diff --git a/changer-src/chg-multi.sh b/changer-src/chg-multi.sh
new file mode 100644 (file)
index 0000000..ddb5301
--- /dev/null
@@ -0,0 +1,421 @@
+#! @SHELL@
+#
+# Amanda, The Advanced Maryland Automatic Network Disk Archiver
+# Copyright (c) 1991-1999 University of Maryland at College Park
+# All Rights Reserved.
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of U.M. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  U.M. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Author: James da Silva, Systems Design and Analysis Group
+#                         Computer Science Department
+#                         University of Maryland at College Park
+#
+
+#
+# chg-multi.sh - generic tape changer script
+#
+
+# source utility functions and values from configure
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+amlibexecdir=@amlibexecdir@
+. ${amlibexecdir}/chg-lib.sh
+
+pname="chg-multi"
+
+if [ -d "@AMANDA_DBGDIR@" ]; then
+       logfile=@AMANDA_DBGDIR@/changer.debug
+else
+       logfile=/dev/null
+fi
+
+echo `_ "arguments ->"` "$@" >> $logfile
+
+ourconf=`amgetconf changerfile`
+
+if ! error=try_find_mt; then
+    echo <none> $error
+    exit 2
+fi
+
+EXPR=expr
+# EXPR=/usr/local/bin/expr # in case you need a more powerful expr...
+
+# read in some config parameters
+
+if [ ! -f "$ourconf" ]; then
+       answer=`_ '<none> %s: %s does not exist' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+firstslot=`awk '$1 == "firstslot" {print $2}' $ourconf 2>/dev/null`
+if [ -z "$firstslot" ]; then
+       answer=`_ '<none> %s: firstslot not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+lastslot=`awk '$1 == "lastslot" {print $2}' $ourconf 2>/dev/null`
+if [ -z "$lastslot" ]; then
+       answer=`_ '<none> %s: lastslot not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+nslots=`$EXPR $lastslot - $firstslot + 1`
+
+gravity=`awk '$1 == "gravity" {print $2}' $ourconf 2>/dev/null`
+if [ -z "$gravity" ]; then
+       answer=`_ '<none> %s: gravity not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+needeject=`awk '$1 == "needeject" {print $2}' $ourconf 2>/dev/null`
+if [ -z "$needeject" ]; then
+       answer=`_ '<none> %s: needeject not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+multieject=`awk '$1 == "multieject" {print $2}' $ourconf 2>/dev/null`
+if [ -z "$multieject" ]; then
+       echo `_ 'Note: setting multieject to a default of zero'` >> $logfile
+       multieject=0
+fi
+
+ejectdelay=`awk '$1 == "ejectdelay" {print $2}' $ourconf 2>/dev/null`
+if [ -z "$ejectdelay" ]; then
+       echo `_ 'Note: setting ejectdelay to a default of zero'` >> $logfile
+       ejectdelay=0
+fi
+
+posteject=`awk '$1 == "posteject" {print $2}' $ourconf 2>/dev/null`
+if [ -z "$posteject" ]; then
+       echo `_ 'Note: setting posteject to a default of "true"'` >> $logfile
+       posteject=true
+fi
+
+ourstate=`awk '$1 == "statefile" {print $2}' $ourconf 2>/dev/null`
+if [ -z "$ourstate" ]; then
+       answer=`_ '<none> %s: statefile not specified in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+# needeject and multieject are incompatible
+if [ $needeject -eq 1 ] && [ $multieject -eq 1 ] ; then
+       answer=`_ '<none> %s: needeject and multieject cannot be both enabled in %s' "$pname" "$ourconf"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+# read in state: only curslot and curloaded at the present time
+
+curslot=`awk '$1 == "curslot" {print $2}' $ourstate 2>/dev/null`
+if [ -z "$curslot" ]; then
+       curslot=$firstslot
+fi
+
+curloaded=`awk '$1 == "curloaded" {print $2}' $ourstate 2>/dev/null`
+if [ -z "$curloaded" ]; then
+       curloaded=0
+fi
+
+
+# process the command-line
+
+# control vars to avoid code duplication: not all shells have functions!
+usage=0
+checkgravity=0
+ejectslot=0
+loadslot=0
+slotempty=0
+ejectonly=0
+
+if [ $# -ge 1 ]; then command=$1; else command="-usage"; fi
+
+case "$command" in
+
+-info) # return basic information about changer
+
+       backwards=`$EXPR 1 - $gravity`
+       answer="$curslot $nslots $backwards"
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 0
+       ;;
+
+-reset) # reset changer. Actually, we only reset changer state. We
+       # trust that the operator has reloaded a stack and reset the
+       # hardware. In most cases, we do not want to actually do
+       # anything: if the operator has done something with the
+       # hardware, we have no way to know what the actual current
+       # slot is. If the hardware state has not changed, and what is
+       # really wanted is to load the first slot, use "slot first"
+       # instead 
+
+       checkgravity=0
+       loadslot=1
+       newslot=$firstslot
+       curslot=$firstslot
+       # XXX put changer-specific reset here, if applicable
+       ;;
+
+-eject) # eject tape if loaded. Note that if multieject is set, this
+        # only can make sense if the position is last and gravity 1
+
+       checkgravity=0
+       loadslot=0
+       newslot=$curslot
+       ejectslot=1
+       ejectonly=1
+       if [ $multieject -eq 1 ] && \
+           ([ $gravity -eq 0 ] || [ $curslot -ne $lastslot ]) ; then 
+               # Can't do this: if we eject, the stacker is going to
+               # load the next tape, and our state will be botched
+               answer=`_ '%s %s: Cannot use -eject with multieject/nogravity/notlastslot' "$curslot" "$pname"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 1
+       fi    
+       if [ $curloaded -eq 0 ]; then
+               answer=`_ '%s %s: slot already empty' "$curslot" "$pname"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 1
+       fi
+       ;;
+
+-slot) # change to slot
+
+       checkgravity=1
+       loadslot=1
+
+       slotparm=$2
+       case "$slotparm" in
+       [0-9]*) 
+               newslot=$slotparm
+               if [ $newslot -gt $lastslot ] || \
+                    [ $newslot -lt $firstslot ] ; then
+                       answer=`_ '%s %s: no slot %s: legal range is %s ... %s' "$newslot" "$pname" "$newslot" "$firstslot" "$lastslot"`
+                       echo `_ 'Exit ->'` $answer >> $logfile
+                       echo $answer
+                       exit 1
+               fi
+               ;;
+       current)
+               newslot=$curslot
+               ;;
+       first)
+               newslot=$firstslot
+               ;;
+       last)
+               newslot=$lastslot
+               ;;
+       next|advance)
+               newslot=`$EXPR $curslot + 1`
+               if [ $newslot -gt $lastslot ]; then
+                       newslot=$firstslot
+               fi
+               if [ $slotparm = advance ]; then
+                       loadslot=0
+               fi
+               ;;
+       prev)
+               newslot=`$EXPR $curslot - 1`
+               if [ $newslot -lt $firstslot ]; then
+                       newslot=$lastslot
+               fi
+               ;;
+       *)
+               answer=`_ '<none> %s: bad slot name "%s"' "$pname" "$slotparm"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 1
+               ;;
+       esac
+       ;;
+*)
+       usage=1
+       ;;
+esac
+
+
+if [ $usage -eq 1 ]; then
+       answer=`_ '<none> usage: %s {-reset | -slot [<slot-number>|current|next|prev|advance] | -info | -eject}' "$pname"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 2
+fi
+
+
+# check for legal move
+
+if [ $checkgravity -eq 1 ] && [ $gravity -ne 0 ] ; then
+       if [ $newslot -lt $curslot ] || [ "$slotparm" = "prev" ] ; then
+               answer=`_ '%s %s: cannot go backwards in gravity stacker' "$newslot" "$pname"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 1
+       fi
+fi
+
+# Do the 'mt offline' style of stacker control if applicable
+if [ $multieject -eq 1 ] && [ $loadslot -eq 1 ] && [ $newslot -ne $curslot ]
+then
+       # XXX put changer-specific load command here, if applicable
+
+       curloaded=0             # unless something goes wrong
+       slotempty=0
+
+       while [ $curslot -ne $newslot ]; do
+           device=`awk '$1 == "slot" && $2 == '$curslot' {print $3}' $ourconf 2>/dev/null`
+           if [ "$device" = "" ]; then
+               answer=`_ '%s %s: slot %s device not specified in %s' "$curslot" "$pname" "$curslot" "$ourconf"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 2
+           fi
+           echo `_ '     -> offline'` "$device" >> $logfile
+            if ! try_eject_device $device; then
+               answer=`_ '%s %s: %s: unable to change to slot %s' "$newslot" "$pname" "$device" "$curslot"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 2
+           fi
+           [ $ejectdelay -gt 0 ] && sleep $ejectdelay
+           echo `_ '     -> running'` $posteject $device >> $logfile
+           $posteject $device >> $logfile 2>&1
+           status=$?
+           if [ $status -ne 0 ]; then
+               answer=`_ '%s %s: %s %s failed: %s' "$newslot" "$pname" "$posteject" "$device" "$status"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 2
+           fi
+           curslot=`$EXPR $curslot + 1`
+           if [ $curslot -gt $lastslot ] ; then
+               curslot=$firstslot
+           fi
+       done
+fi
+
+if [ $ejectonly -eq 1 ] \
+     || ([ $needeject -eq 1 ] \
+           && [ $loadslot -eq 1 ] \
+           && [ $curloaded -eq 1 ] \
+           && [ $newslot -ne $curslot ])
+then
+       # XXX put changer-specific load command here, if applicable
+
+       curloaded=0             # unless something goes wrong
+       slotempty=0
+
+       # try to unload the current device
+       device=`awk '$1 == "slot" && $2 == '$curslot' {print $3}' $ourconf 2>/dev/null`
+       if [ "$device" = "" ]; then
+               answer=`_ '%s %s: slot %s device not specified in %s' "$curslot" "$pname" "$curslot" "$ourconf"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 2
+       fi
+       echo `_ '     -> offline'` $device >> $logfile
+        try_eject_device $device
+       if [ $? -ne 0 ]; then
+               #
+               # XXX if the changer-specific eject command can distinguish
+               # betweeen "slot empty" and more serious errors, return 1
+               # for the first case, 2 for the second case.  Generically,
+               # we just presume an error signifies an empty slot.
+               #
+               slotempty=1
+       else
+               [ $ejectonly -eq 0 ] && [ $ejectdelay -gt 0 ] && sleep $ejectdelay
+               echo `_ '     -> running '` $posteject $device >> $logfile
+               $posteject $device >> $logfile 2>&1
+               status=$?
+               if [ $status -ne 0 ]; then
+                       answer=`_ '%s %s: %s %s failed: %s' "$newslot" "$pname" "$posteject" "$device" "$status"`
+                       echo `_ 'Exit ->'` $answer >> $logfile
+                       echo $answer
+                       exit 2
+               fi
+       fi
+fi
+
+if [ $loadslot -eq 1 ]; then   # load the tape from the slot
+
+       # XXX put changer-specific load command here, if applicable
+
+       curloaded=1             # unless something goes wrong
+       slotempty=0
+       curslot=$newslot
+
+       # try to rewind the device
+       device=`awk '$1 == "slot" && $2 == '$curslot' {print $3}' $ourconf 2>/dev/null`
+       if [ "$device" = "" ]; then
+               answer=`_ '%s %s: slot %s device not specified in %s' "$curslot" "$pname" "$curslot" "$ourconf"`
+               echo `_ 'Exit ->'` $answer >> $logfile
+               echo $answer
+               exit 2
+       fi
+        amdevcheck_status $device
+       if [ $? -ne 0 ]; then
+               #
+               # XXX if the changer-specific load command can distinguish
+               # betweeen "slot empty" and more serious errors, return 1
+               # for the first case, 2 for the second case.  Generically,
+               # we just presume an error signifies an empty slot.
+               #
+               slotempty=1
+               curloaded=0
+       fi
+fi
+
+# update state
+
+echo `_ '# multi-changer state cache: DO NOT EDIT!'` >  $ourstate
+echo curslot $newslot                           >> $ourstate
+echo curloaded $curloaded                       >> $ourstate
+
+# return slot info
+
+if [ $slotempty -eq 1 ]; then
+       answer=`_ '%s %s: slot is empty' "$newslot" "$pname"`
+       echo `_ 'Exit ->'` $answer >> $logfile
+       echo $answer
+       exit 1
+fi
+
+if [ "$command" = -slot -a "$slotparm" = advance ]; then
+       device=/dev/null
+fi
+
+answer="$newslot $device"
+echo `_ 'Exit ->'` $answer >> $logfile
+echo $answer
+exit 0
diff --git a/changer-src/chg-null.sh b/changer-src/chg-null.sh
new file mode 100644 (file)
index 0000000..04ebb47
--- /dev/null
@@ -0,0 +1,101 @@
+#!@SHELL@ 
+#
+# Exit Status:
+# 0 Alles Ok
+# 1 Illegal Request
+# 2 Fatal Error
+#
+
+# try to hit all the possibilities here
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+debugdir=@AMANDA_DBGDIR@
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+if [ -d "$debugdir" ]
+then
+       logfile=$debugdir/changer.debug
+else
+       logfile=/dev/null
+fi
+exec 2> $logfile
+set -x
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+       SUF="-@VERSION@"
+else
+       SUF=
+fi
+
+myname=$0
+
+EGREP='@EGREP@'
+
+firstslot=1
+totalslots=200
+
+changerfile=`amgetconf$SUF changerfile`
+
+tapedev=`amgetconf$SUF tapedev`
+
+cleanfile=$changerfile-clean
+accessfile=$changerfile-access
+slotfile=$changerfile-slot
+[ ! -f $cleanfile ] && echo 0 > $cleanfile
+[ ! -f $accessfile ] && echo 0 > $accessfile
+[ ! -f $slotfile ] && echo $firstslot > $slotfile
+cleancount=`cat $cleanfile`
+accesscount=`cat $accessfile`
+slot=`cat $slotfile`
+
+rc=0
+
+case x$1 in
+
+x-slot) 
+
+    #
+    # handle special slots...
+    #
+    case "$2" in
+    current)   newslot=$slot           ; load=true;;
+    next)      newslot=`expr $slot + 1`; load=true;;
+    advance)   newslot=`expr $slot + 1`; load=false;;
+    prev)      newslot=`expr $slot - 1`; load=true;;
+    first)     newslot=0               ; load=true;;
+    last)      newslot=-1              ; load=true;;
+    *)         newslot=$2              ; load=true;;
+    esac
+
+    if [ 0 -gt $newslot ]
+    then
+       newslot=`expr $totalslots - 1`
+    fi
+
+    if [ $totalslots -le  $newslot ]
+    then
+       newslot=0
+    fi
+    echo $newslot > $changerfile-slot
+    slot=$newslot
+    echo $slot $tapedev
+    ;;
+
+x-info)
+    echo $slot $totalslots 1
+    ;;
+
+x-eject)
+    echo $slot $tapedev
+    ;;
+esac
+
+exit $rc
diff --git a/changer-src/chg-rait.sh b/changer-src/chg-rait.sh
new file mode 100644 (file)
index 0000000..757661f
--- /dev/null
@@ -0,0 +1,217 @@
+#!@SHELL@
+
+# chg-rait
+#
+# This assumes we have rait-striped drives in several
+# other amanda changer configs.
+#
+# so we have a changerfile that lists other changers and
+# changer files.
+#   nchangers=3
+#   tpchanger_1="chg-mtx"
+#   changerdev_1="/dev/mtx1"
+#   changerfile_1="/some/file1"
+#   tapedev_1="/some/dev"
+#   tpchanger_2="chg-mtx"
+#   changerdev_2="/dev/mtx2"
+#   changerfile_2="/some/file2"
+#   tapedev_2="/some/dev"
+#   tpchanger_3="chg-mtx"
+#   changerdev_3="/dev/mtx3"
+#   changerfile_3="/some/file3"
+#   tapedev_3="/some/dev"
+#
+# the tapedev_n entries are only needed if the changer script in question
+# uses tapedev.
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH 
+
+#
+# debugging...
+#
+if [ -d "@AMANDA_DBGDIR@" ]; then
+       DBGFILE=@AMANDA_DBGDIR@/rait-changer.debug
+       KIDDEBUG=@AMANDA_DBGDIR@/changer.debug
+       WORK=@AMANDA_DBGDIR@/chgwork$$
+else
+       DBGFILE=/dev/null
+       KIDDEBUG=/dev/null
+       WORK=/tmp/chgwork$$
+fi
+
+exec 2>$DBGFILE
+echo `_ "arguments: "` $0 $* >&2
+set -x 
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+        SUF="-@VERSION@";
+else
+       SUF=
+fi
+getconf=$sbindir/amgetconf$SUF
+
+
+changerfile=`$getconf changerfile`
+. $changerfile
+
+#
+# get config items that other changers use to put in our
+# fake amanda.conf files.
+#
+org=`$getconf ORG`
+mailto=`$getconf mailto`
+
+#
+# make a working directory (with amanda.conf) for each changer, and start the
+# changer script in background for each one
+#
+
+i=1
+while [ $i -le $nchangers ]
+do
+   eval tpchanger=\$tpchanger_$i
+   eval changerdev=\$changerdev_$i
+   eval changerfile=\$changerfile_$i
+   eval tapedev=\$tapedev_$i
+
+   mkdir -p $WORK/$i
+   cd $WORK/$i
+
+   cat >> amanda.conf <<EOF
+org            "$ORG"
+mailto         "$mailto"
+tpchanger      "$tpchanger"
+changerdev     "$changerdev"
+changerfile    "$changerfile"
+tapedev        "$tapedev"
+
+define tapetype EXABYTE {
+    comment "default tapetype"
+    length 4200 mbytes
+    filemark 48 kbytes
+    speed 474 kbytes                   
+}
+EOF
+
+    (
+       $tpchanger "$@"
+       echo "$?"> exitcode 
+    )  > stdout 2>stderr &
+
+   i=`expr $i + 1`
+done
+
+wait
+
+#
+# once they've all finished, collect up the results
+#
+
+myexit=0
+myslot=-1
+mymax=65536
+myflag=1
+mydev=""
+mysep="{"
+
+case x$1 in
+x-slot|x-reset|x-eject|x-search|x-label)
+
+    #
+    # read slot number and device from each
+    # slot numbers must match(?!), and is our resulting slot number
+    # resulting device is {dev1,dev2,...} from each one
+    #
+    i=1
+    while [ $i -le $nchangers ]
+    do
+       read exitcode < $WORK/$i/exitcode
+       read n dev < $WORK/$i/stdout
+       echo -------------- >&2
+        cat $WORK/$i/stderr >&2
+       cat $KIDDEBUG >&2
+       echo -------------- >&2
+
+       if [ "$exitcode" != 0 ]
+       then
+           myexit=$exitcode
+       fi
+       if [ $myslot = -1 ]
+       then
+           myslot=$n
+       fi
+       if [ $n != $myslot ]
+       then
+            # synch error!
+           myexit=1
+           echo `_ 'stackers are out of synch, issue a reset'` >&2
+       fi
+       mydev="$mydev$mysep$dev"
+       mysep=","
+
+       i=`expr $i + 1`
+    done
+    mydev="rait:$mydev}"
+    echo $myslot $mydev
+    ;;
+x-info)
+    #
+    # read info from each
+    # slot numbers must match(?!), and is our resulting slot number
+    # minimum max slots is our resulting max slots
+    # if any can't go backwards, the aggregate can't either
+    #
+    i=1
+    while [ $i -le $nchangers ]
+    do
+       read exitcode < $WORK/$i/exitcode
+       read n max flag < $WORK/$i/stdout
+       echo -------------- >&2
+        cat $WORK/$i/stderr >&2
+       cat $KIDDEBUG >&2
+       echo -------------- >&2
+
+       if [ "$exitcode" != 0 ]
+       then
+            myexit=$exitcode
+       fi
+       if [ $myslot = -1 ]
+       then
+           myslot=$n
+       fi
+       if [ $n != $myslot ]
+       then
+            # synch error!
+           myexit=1
+           echo `_ 'stackers are out of synch, issue a -reset'` >&2
+       fi
+       if [ $max -lt $mymax ]
+       then
+           mymax=$max
+       fi
+       if [ $flag = 0 ]
+       then
+           myflag=0
+       fi
+       i=`expr $i + 1`
+    done
+    echo $myslot $mymax $myflag
+
+esac
+
+#
+# clean up work directories
+#
+rm -rf $WORK
+
+exit $myexit
diff --git a/changer-src/chg-rth.pl b/changer-src/chg-rth.pl
new file mode 100644 (file)
index 0000000..9f75559
--- /dev/null
@@ -0,0 +1,307 @@
+#!@PERL@
+
+# Catch for sh/csh on systems without #! ability.
+eval '(exit $?0)' && eval 'exec @PERL@ -S $0 ${1+"$@"}'
+       & eval 'exec @PERL@ -S $0 $argv:q'
+               if 0;
+
+# rth-changer - 
+#   A tape changer script for the Robotic Tape Handling system OEM'd
+#   by Andataco (RTH-406) for use with Amanda, the Advanced Maryland
+#   Network Disk Archiver.
+#
+#    Author: Erik Frederick 1/10/97
+#            edf@tyrell.mc.duke.edu
+#
+# This changer script controls the HP c1553 tape drive via a
+# Peripheral Vision Inc. SCSI control subsystem that interprets
+# commands sent on the SCSI bus.  It may work with other tape drives
+# containing the PVI board.
+#
+# Permission to freely use and distribute is granted.
+#
+
+require 5.001;
+
+use Getopt::Long;
+
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
+$ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin";
+
+$pname = "rth-changer";
+
+$prefix="@prefix@";
+$prefix=$prefix;               # avoid warnings about possible typo
+$exec_prefix="@exec_prefix@";
+$exec_prefix=$exec_prefix;     # ditto
+$sbindir="@sbindir@";
+$amlibexecdir="@amlibexecdir@";
+if ("@USE_VERSION_SUFFIXES@" eq "yes") {
+    $suf = "-@VERSION@";
+} else {
+    $suf = "";
+}
+
+if (-x "$sbindir/ammt$SUF") {
+       $MT="$sbindir/ammt$SUF";
+       $MTF="-f";
+} elsif (-x "@MT@") {
+       $MT="@MT@";
+       $MTF="@MT_FILE_FLAG@";
+} else {
+       print "<none> $pname: mt program not found\n";
+       exit(1);
+}
+
+$tapeDevice=`$sbindir/amgetconf$SUF tapedev`;
+die "tapedev not found in amanda.conf"
+       if !$tapeDevice or $tapeDevice eq "" or
+           $tapeDevice =~ m/no such parameter/;
+
+sub getCurrentTape {
+
+  if (!sysopen(RTH, $tapeDevice, 2)) {
+    print "$currentTape $pname: error in opening `$tapeDevice' for getting current tape: $!\n";
+    exit(2);
+  }
+  if (syswrite(RTH, "Rd_ElS", 6) != 6) {
+    print "$currentTape $pname: error in writing `Rd_ElS' to `$tapeDevice': $!\n";
+    exit(2);
+  }
+  if (!close(RTH)) {
+    print "$currentTape $pname: error in closing `$tapeDevice' for getting current tape: $!\n";
+    exit(2);
+  }
+
+  if (!sysopen(RTH, $tapeDevice, 2)) {
+    print "$currentTape $pname: error in opening `$tapeDevice' for getting current tape: $!\n";
+    exit(2);
+  }
+  if (sysread(RTH, $status, 136) != 136) {
+    print "$currentTape $pname: error in reading rth status.\n";
+    exit(2);
+  }
+  if (!close(RTH)) {
+    print "$currentTape $pname: error in closing `$tapeDevice' for getting current tape: $!\n";
+    exit(2);
+  }
+
+  @statusBits=unpack("c*",$status);
+
+  if( ($statusBits[18] == 0x1) || ($statusBits[18]== 0x9)) {
+    return ($statusBits[27]-1);
+  }
+
+  return (0);
+}
+
+
+sub getTapeStatus {
+
+  if (!sysopen(RTH, $tapeDevice, 2)) {
+    print "$currentTape $pname: error in opening `$tapeDevice' for getting tape status: $!\n";
+    exit(2);
+  }
+  if (syswrite(RTH, "Rd_ElS", 6) != 6) {
+    print "$currentTape $pname: error in writing `Rd_ElS' to `$tapeDevice': $!\n";
+    exit(2);
+  }
+  if (!close(RTH)) {
+    print "$currentTape $pname: error in closing `$tapeDevice' for getting tpae status: $!\n";
+    exit(2);
+  }
+
+  if (!sysopen(RTH, $tapeDevice, 2)) {
+    print "$currentTape $pname: error in opening `$tapeDevice' for getting tape status: $!\n";
+    exit(2);
+  }
+  if (sysread(RTH, $status, 136) != 136) {
+    print "$currentTape $pname: error in reading rth status for tape $currentTape.\n";
+    exit(2);
+  }
+  if (!close(RTH)) {
+    print "$currentTape $pname: error in closing `$tapeDevice' for getting tape status: $!\n";
+    exit(2);
+  }
+
+  @statusBits=unpack("c*",$status);
+
+  $curTape=0;
+  for($i=42;$i<187;$i+=16) {
+    if($statusBits[$i] == 0x9) {
+      $slots[$curTape] = 1;
+    }
+    else {
+      $slots[$curTape] = 0;
+    }
+    $curTape++;
+  }
+
+  return (@slots);
+}
+
+sub rthLoad {
+  my($tape) = @_;
+
+  $command = sprintf "GeT%d", $tape;
+  if (!sysopen(RTH, $tapeDevice, 2)) {
+    print "$currentTape $pname: error in opening `$tapeDevice' for loading tape: $!\n";
+    exit(2);
+  }
+  if (syswrite(RTH, $command, 4) != 4) {
+    print "$currentTape $pname: error in loading tape by writing `$command' to `$tapeDevice': $!\n";
+    exit(2);
+  }
+  if (!close (RTH)) {
+    print "$currentTape $pname: error in closing `$tapeDevice' when trying to load tape: $!\n";
+    exit(2);
+  }
+}
+
+sub rthUnload {
+  my($tape) = @_;
+
+  $command = sprintf "PuT%d", $tape;
+  if (!sysopen(RTH, $tapeDevice, 2)) {
+    print "$currentTape $pname: error in opening `$tapeDevice' for unloading tape: $!\n";
+    exit(2);
+  }
+  if (syswrite(RTH, $command, 4) != 4) {
+    print "$currentTape $pname: error in unloading tape by writing `$command' to `$tapeDevice': $!\n";
+    exit(2);
+  }
+  if (!close (RTH)) {
+    print "$currentTape $pname: error in closing `$tapeDevice' when trying to unload tape: $!\n";
+    exit(2);
+  }
+}
+
+sub testTape {
+  my($tape) = @_;
+
+  @slots=getTapeStatus();
+
+  if($currentTape == $tape) {
+    return;
+  }
+
+  if($slots[$tape-1] == 0) {
+    print "<none> $pname: no tape in slot requested\n";
+    exit(1);
+  }
+  if($tape>6) {
+    print $tape," $pname: requested a tape > 6\n";
+    exit(2);
+  }
+  if($tape<1) {
+    print $tape," $pname: requested a tape < 1\n";
+    exit(2);
+  }
+  return;
+}
+
+sub changeTape {
+  my($tape) = @_;
+
+  if($tape==$currentTape) {
+    return;
+  }
+
+  testTape($tape);
+
+  if($currentTape==0) {
+    rthLoad($tape);
+    $currentTape=$tape;
+    return;
+  }
+  else {
+    rthUnload($currentTape);
+    rthLoad($tape);
+    $currentTape=$tape;
+  }
+}
+    
+
+$result = &GetOptions("slot=s", "info", "reset", "eject"); 
+
+system($MT, 'rewind');
+
+$nSlots=6;
+$firstTape=1;
+$lastTape=6;
+$currentTape=getCurrentTape(); 
+
+if($opt_slot) {
+  if($opt_slot =~ /first/) {
+    changeTape(1);
+    print $currentTape, " ", $tapeDevice, "\n";
+  }
+  if($opt_slot =~ /last/) {
+    changeTape(6);
+    print $currentTape, " ", $tapeDevice, "\n";
+  }
+  if($opt_slot =~ /current/) {
+    changeTape($currentTape);
+    print $currentTape, " ", $tapeDevice, "\n";
+  }
+  if($opt_slot =~ /next/) {
+    $tape=$currentTape+1;
+    if ($tape>6) {
+      $tape=1;
+    }
+    changeTape($tape);
+    print $currentTape, " ", $tapeDevice,"\n";
+  }
+  if($opt_slot =~ /prev/) {
+    $tape=$currentTape-1;
+    if($tape<1) {
+      $tape=6;
+    }
+    changeTape($tape);
+    print $currentTape, " ", $tapeDevice,"\n";
+  }
+  if($opt_slot =~ /\d/) {
+    changeTape($opt_slot);
+    print $currentTape, " ", $tapeDevice,"\n";
+  }
+  if($opt_slot =~ /advance/) {
+    $tape=$currentTape+1;
+    if ($tape>6) {
+      $tape=1;
+    }
+    if($currentTape) { 
+      rthUnload($currentTape);
+    }
+    print $currentTape, " ", "/dev/null","\n";
+  }
+
+  exit 0;
+}
+
+if($opt_info) {
+  print $currentTape, " 6 1\n";
+
+  exit 0;
+}
+
+if($opt_reset) {
+  changeTape(1);
+  print $currentTape, " ",$tapeDevice,"\n";
+  exit 0;
+}
+
+if($opt_eject) {
+  if($currentTape) { 
+    rthUnload($currentTape);
+    print "0 ",$tapeDevice,"\n";
+    exit 0;
+  } 
+  else {
+    print "0 $pname: drive was not loaded\n";
+    exit 1;
+  }
+}
+
+print "$pname: No command was received.  Exiting.\n";
+exit 1;
diff --git a/changer-src/chg-zd-mtx.sh b/changer-src/chg-zd-mtx.sh
new file mode 100644 (file)
index 0000000..36236da
--- /dev/null
@@ -0,0 +1,1379 @@
+#!@SHELL@ 
+#
+# Exit Status:
+# 0 Alles Ok
+# 1 Illegal Request
+# 2 Fatal Error
+#
+# Contributed by Eric DOUTRELEAU <Eric.Doutreleau@int-evry.fr>
+# This is supposed to work with Zubkoff/Dandelion version of mtx
+#
+# Modified by Joe Rhett <jrhett@isite.net>
+# to work with MTX 1.2.9 by Eric Lee Green http://mtx.sourceforge.net
+#
+# Modified by Jason Hollinden <jhollind@sammg.com> on 13-Feb-2001
+# to work with MTX 1.2.10, >9 slots, has barcode support, and works with
+# multiple configs at once.
+# NOTE:  Only tested the 2 additions with an ADIC Scalar 100.
+
+################################################################################
+# Here are the things you need to do and know to configure this script:
+#
+#   * Figure out what the robot device name is and what the tape drive
+#     device name is.  They will be different!
+#
+#     You cannot send robot commands to a tape drive and vice versa.
+#     Both should respond to "mtx -f /dev/... inquiry".  Hopefully,
+#     that output will make it obvious which is which.
+#
+#     For instance, here is what mtx has to say about my current robot:
+#
+#       Product Type: Medium Changer
+#       Vendor ID: 'ATL     '
+#       Product ID: 'ACL2640 206     '
+#       Revision: '2A5A'
+#       Attached Changer: No
+#
+#     and here is what it says about a tape drive:
+#
+#       Product Type: Tape Drive
+#       Vendor ID: 'Quantum '
+#       Product ID: 'DLT4000         '
+#       Revision: 'CD50'
+#       Attached Changer: No
+#
+#     Note the "Product Type" value makes it clear which is which.
+#
+#     If it is not obvious, "mf -f /dev/... rewind" should be happy when
+#     talking to a (loaded) tape drive but the changer should give some
+#     kind of error.  Similarly, "mtx -f /dev/... status" should show good
+#     results with the changer but fail with a tape drive device name.
+#
+#     Once you have this figured out, set "changerdev" in amanda.conf
+#     to the changer device and "tapedev" to the tape device.
+#
+#   * Find out what the first and last storage slots are.  Running
+#     "mtx -f /dev/... status" should give you something like this
+#     (although the output will vary widely based on the version of mtx
+#     and the specifics of your robot):
+#
+#        Storage Changer /dev/changer:1 Drives, 9 Slots ( 0 Import/Export )
+#      Data Transfer Element 0:Empty
+#            Storage Element 1:Full :VolumeTag=SR0001
+#            Storage Element 2:Full :VolumeTag=SR0002
+#            Storage Element 3:Full :VolumeTag=SR0003
+#            Storage Element 4:Full :VolumeTag=SR0004
+#            Storage Element 5:Full :VolumeTag=SR0005
+#            Storage Element 6:Full :VolumeTag=SR0006
+#            Storage Element 7:Full :VolumeTag=SR0007
+#            Storage Element 8:Full :VolumeTag=SR0008
+#            Storage Element 9:Full :VolumeTag=SR0009
+#            Storage Element 10 IMPORT/EXPORT:Full :VolumeTag=SR0009
+#
+#     This says the first storage slot (element) is "1" and the last
+#     is "9".  If you allocate the entire robot to Amanda, you do not need
+#     to set the "firstslot" or "lastslot" configuration file variables --
+#     the script will compute these values for you.
+#
+#     You do not have to allocate all of the slots for Amanda use,
+#     but whatever slots you use must be contiguous (i.e. 4 through 9
+#     in the above would be OK but 1, 2, 5, 6, 9 would not).  The one
+#     exception to this is that if one of the slots contains a cleaning
+#     cartridge, it may be in any slot (Amanda will just skip over it if
+#     it is between firstslot and lastslot).
+#
+#   * Speaking of cleaning cartridges, if you have a storage slot dedicated
+#     to one, figure out what slot it is in.  That slot number will go in
+#     the "cleanslot" variable.
+#
+#     Also, decide if you want the changer script to automatically run
+#     the cleaning tape through the drive after every so many mounts,
+#     and how many mounts you want to do between cleanings.  If you
+#     want the script to do this, set the "autoclean" variable to 1 and
+#     the "autocleancount" to the number of mounts between cleanings.
+#     If you do not want to do automatic cleanings (including not having
+#     a cleaning cartridge in the robot), set "autoclean" to 0.
+#
+#     Note that only a count of mounts is used to determine when it is
+#     time to clean.  The script does not try to detect if the drive is
+#     requesting cleaning, or how much the drive was used on a given
+#     mount.
+#
+#   * If you tell Amanda about a cleaning cartridge, whether for automatic
+#     operation or manual (amtape <config> clean), you must also tell
+#     the script how long it takes to run the cleaning cycle.  It is
+#     impossible for the script to determine when the cleaning operation
+#     is done, so the "cleancycle" variable is the number of seconds
+#     the longest cleaning operation takes (you'll just have to figure
+#     this out by watching it a few times, or maybe finding it in a tape
+#     drive hardware manual).  The script will sleep for this length of
+#     time whenever the cleaning tape is referenced.  The default is 120
+#     seconds (two minutes).
+#
+#   * Figure out the drive slot number.  By default, it is set to 0.
+#     In the example above, the tape drive ("Data Transfer Element")
+#     is in slot 0. If your drive slot is not 0, you
+#     need to set the drive slot number with the "driveslot" variable.
+#
+#   * Figure out whether your robot has a barcode reader and whether
+#     your version of mtx supports it.  If you see "VolumeTag" entries
+#     in the "mtx -f /dev/xxx status" output you did above, you have
+#     a reader and mtx can work with it, so you may set the "havereader"
+#     variable to 1.  The default is 0 (do not use a reader).
+#
+#   * Pick any tape to load and then determine if the robot can put it
+#     away directly or whether an "offline" must be done first.
+#
+#     With the tape still mounted and ready, try to put the tape away
+#     with "mtx".  If you get some kind of error, which is the most
+#     common response, try "mt -f /dev/... offline", wait for the drive
+#     to unload and make sure the robot takes no action on its own to
+#     store the tape.  Assuming it does not, try the "mtx" command again
+#     to store the tape.
+#
+#     If you had to issue the "mt -f /dev/... offline" before you could
+#     use "mtx" to store the tape, set the "offline_before_unload"
+#     variable to 1.  If "mtx" unloaded the drive and put the tape away
+#     all by itself, set it to 0.
+#
+#   * Some drives and robots require a small delay between unloading the
+#     tape and instructing the robot to move it back to storage.
+#     For instance, if you try to grab the tape too soon on an ATL robot
+#     with DLT tape drives, it will rip the leader out of the drive and
+#     require sincerely painful hardware maintenance.
+#
+#     If you need a little delay, set the "unloadpause" variable to
+#     the number of seconds to wait before trying to take a tape from
+#     a drive back to storage.  The default is 0.
+#
+#   * Some drives also require a short pause after loading, or the drive
+#     will return an I/O error during a test to see if it's online (which
+#     this script uses "mt rewind" to test).  My drives don't recover from
+#     this, and must be reloaded before they will come online after failing
+#     such a test.  For this reason there is an "initial_poll_delay"
+#     variable which will pause for a certain number of seconds before
+#     looping through the online test for the first time.  The default is 0.
+####
+
+####
+# Now you are ready to set up the variables in the changer configuration
+# file.
+#
+# All variables are in "changerfile".conf where "changerfile" is set
+# in amanda.conf.  For example, if amanda.conf has:
+#
+#      changerfile="/etc/amanda/Dailyset1/CHANGER"
+#    or changerfile="/etc/amanda/Dailyset1/CHANGER.conf"
+#
+# the variables must be in "/etc/amanda/Dailyset1/CHANGER.conf".
+# The ".conf" is appended only if it's not there".
+#
+# If "changerfile" is a relative path, it is relative to the directory
+# that contains amanda.conf.  That also happens to be the directory Amanda
+# makes current before running this script.
+#
+# Here is a commented out example file with all the variables and showing
+# their default value (if any):
+####
+# firstslot=?              #### First storage slot (element) -- required
+# lastslot=?               #### Last storage slot (element) -- required
+# cleanslot=-1             #### Slot with cleaner tape -- default is "-1"
+#                          #### Set negative to indicate no cleaner available
+# driveslot=0              #### Drive slot number.  Defaults to 0
+#                          #### Use the 'Data Transfer Element' you want
+#
+#   # Do you want to clean the drive after a certain number of accesses?
+#   # NOTE - This is unreliable, since 'accesses' aren't 'uses', and we
+#   #        have no reliable way to count this.  A single amcheck could
+#   #        generate as many accesses as slots you have, plus 1.
+#   # ALSO NOTE - many modern tape loaders handle this automatically.
+#
+# autoclean=0              #### Set to '1' or greater to enable
+#
+# autocleancount=99        #### Number of access before a clean.
+#
+# cleancycle=120           #### Time (seconds) to clean drive (default 120)
+#
+# havereader=0             #### If you have a barcode reader, set to 1.
+#
+# offline_before_unload=0   #### Does your robot require an
+#                          #### 'mt offline' before mtx unload?
+#
+# poll_drive_ready=NN      #### Time (seconds) between tests to see if
+#                          #### the tape drive has gone ready (default: 3).
+#
+# max_drive_wait=NN        #### Maximum time (seconds) to wait for the
+#                          #### tape drive to become ready (default: 120).
+#
+# initial_poll_delay=NN            #### initial delay after load before polling for
+#                          #### readiness
+#
+####
+
+####
+# Now it is time to test the setup.  Do all of the following in the
+# directory that contains the amanda.conf file, and do all of it as
+# the Amanda user.
+#
+#   * Run this:
+#
+#       .../chg-zd-mtx -info
+#       echo $?             #### (or "echo $status" if you use csh/tcsh)
+#
+#     You should get a single line from the script like this (the actual
+#     numbers will vary):
+#
+#       5 9 1 1
+#
+#     The first number (5) is the "current" slot.  This may or may not be
+#     the slot actually loaded at the moment (if any).  It is the slot
+#     Amanda will try to use next.
+#
+#     The second number (9) is the number of slots.
+#
+#     The third number will always be "1" and indicates the changer is
+#     capable of going backward.
+#
+#     The fourth number is optional.  If you set $havereader to 1, it
+#     will be "1", otherwise it will not be present.
+#
+#     The exit code ($? or $status) should be zero.
+#
+#   * Run this:
+#
+#       .../chg-zd-mtx -reset
+#       echo $?
+#
+#     The script should output a line like this:
+#
+#       1 /dev/rmt/0mn
+#
+#     The number at the first should match $firstslot.  The device name
+#     after that should be your tape device.
+#
+#     The exit code ($? or $status) should be zero.
+#
+#   * Run this:
+#
+#       .../chg-zd-mtx -slot next
+#       echo $?
+#
+#     The script should output a line like this:
+#
+#       2 /dev/rmt/0mn
+#
+#     The number at the first should be one higher than $firstslot.
+#     The device name after that should be your tape device.
+#
+#     The exit code ($? or $status) should be zero.
+#
+#   * Run this:
+#
+#       .../chg-zd-mtx -slot current
+#       echo $?
+#
+#     Assuming the tape is still loaded from the previous test, the
+#     robot should not move and the script should report the same thing
+#     the previous command did.
+#
+#   * If you continue to run "-slot next" commands, the robot should load
+#     each tape in turn then wrap back around to the first when it
+#     reaches $lasttape.  If $cleanslot is within the $firstslot to
+#     $lastslot range, the script will skip over that entry.
+#
+#   * Finally, try some of the amtape commands and make sure they work:
+#
+#       amtape <config> reset
+#       amtape <config> slot next
+#       amtape <config> slot current
+#
+#   * If you set $havereader non-zero, now would be a good time to create
+#     the initial barcode database:
+#
+#       amtape <config> update
+####
+
+################################################################################
+# To debug this script, first look in @AMANDA_DBGDIR@.  The script
+# uses one of two log files there, depending on what version of Amanda
+# is calling it.  It may be chg-zd-mtx.YYYYMMDD*.debug, or it may be
+# changer.debug.driveN where 'N' is the drive number.
+#
+# If the log file does not help, try running the script, **as the Amanda
+# user**, in the amanda.conf directory with whatever set of args the log
+# said were used when you had a problem.  If nothing else useful shows up
+# in the output, try running the script with the DEBUG environment variable
+# set non-null, e.g.:
+#
+#      env DEBUG=yes .../chg-zd-mtx ...
+################################################################################
+
+# source utility functions and values from configure
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+amlibexecdir=@amlibexecdir@
+. ${amlibexecdir}/chg-lib.sh
+
+test -n "$DEBUG" && set -x
+TMPDIR="@AMANDA_TMPDIR@"
+DBGDIR="@AMANDA_DBGDIR@"
+
+argv0=$0
+myname=`expr "$argv0" : '.*/\(.*\)'`
+
+config=`pwd 2>/dev/null`
+config=`expr "$config" : '.*/\(.*\)'`
+
+###
+# Functions to write a new log file entry and append more log information.
+###
+
+ds=`date '+%H:%M:%S' 2>/dev/null`
+if [ $? -eq 0  -a  -n "$ds" ]; then
+       logprefix=`echo "$ds" | sed 's/./ /g'`
+else
+       logprefix=""
+fi
+
+LogAppend() {
+       if [ -z "$logprefix" ]; then
+               echo "$@" >> $DBGFILE
+       else
+               echo "$logprefix" "$@" >> $DBGFILE
+       fi
+}
+
+Log() {
+       if [ -z "$logprefix" ]; then
+               echo "===" "`date`" "===" >> $DBGFILE
+               echo "$@" >> $DBGFILE
+       else
+               ds=`date '+%H:%M:%S' 2>/dev/null`
+               echo "$ds" "$@" >> $DBGFILE
+       fi
+}
+
+###
+# Common exit function.
+#
+#   $1 = exit code
+#   $2 = slot result
+#   $3 = additional information (error message, tape devive, etc)
+###
+
+internal_call=0
+Exit() {
+       if [ $internal_call -gt 0 ]; then
+               call_type=Return
+       else
+               call_type=Exit
+       fi
+       code=$1
+       shift
+       exit_slot=$1
+       shift
+       exit_answer="$@"
+       Log $call_type "($code) -> $exit_slot $@"
+       echo "$exit_slot" "$@"
+       if [ $call_type = Return ]; then
+               return $code
+       fi
+       amgetconf dbclose.$argv0:$DBGFILE > /dev/null 2>&1
+       exit $code
+}
+
+###
+# Function to run another command and log it.
+###
+
+Run() {
+       Log `_ 'Running: %s' "$*"`
+       rm -f $stdout $stderr
+       "$@" > $stdout 2> $stderr
+       exitcode=$?
+       Log `_ 'Exit code: %s' "$exitcode"`
+       if [ -s $stdout ]
+       then
+               LogAppend Stdout:
+               cat $stdout >> $DBGFILE
+       fi
+       if [ -s $stderr ]
+       then
+               LogAppend Stderr:
+               cat $stderr >> $DBGFILE
+       fi
+       cat $stdout
+       cat $stderr 1>&2
+       return $exitcode
+}
+
+###
+# Return success if the arg is numeric.
+###
+
+IsNumeric() {
+       test -z "$1" && return 1
+       x="`expr "$1" : '\([-0-9][0-9]*\)' 2>/dev/null`"
+       return `expr X"$1" != X"$x"`
+}
+
+###
+# Run $MTX status unless the previous output is still valid.
+###
+
+mtx_status_valid=0
+get_mtx_status() {
+       test -n "$DEBUG" && set -x
+       if [ $mtx_status_valid -ne 0 ]; then
+               return 0
+       fi
+       rm -f $mtx_status
+       Run $MTX status > $mtx_status 2>&1
+       status=$?
+       if [ $status -eq 0 ]; then
+               mtx_status_valid=1
+       fi
+       return $status
+}
+
+###
+# Determine the slot currently loaded.  Set $loadedslot to the slot
+# currently loaded, or "-1", and $loadedbarcode to the corresponding
+# barcode (or nothing).
+###
+
+get_loaded_info() {
+       test -n "$DEBUG" && set -x
+       get_mtx_status
+
+       set x `sed -n '
+/^Data Transfer Element:Empty/                          {
+    s/.*/-1/p
+    q
+}
+/^Data Transfer Element '$driveslot':Empty/             {
+    s/.*/-1/p
+    q
+}
+/^Data Transfer Element:Full (Storage Element \([0-9][0-9]*\) Loaded):VolumeTag *= *\([^     ]*\)/               {
+    s/.*(Storage Element \([0-9][0-9]*\) Loaded):VolumeTag *= *\([^     ]*\)/\1 \2/p
+    q
+}
+/^Data Transfer Element '$driveslot':Full (Storage Element \([0-9][0-9]*\) Loaded):VolumeTag *= *\([^     ]*\)/  {
+    s/.*(Storage Element \([0-9][0-9]*\) Loaded):VolumeTag *= *\([^     ]*\)/\1 \2/p
+    q
+}
+/^Data Transfer Element '$driveslot':Full (Unknown Storage Element Loaded):VolumeTag *= *\([^     ]*\)/        {
+    s/.*:VolumeTag *= *\([^     ]*\)/-2 \1/p
+    q
+}
+/^Data Transfer Element:Full (Storage Element \([0-9][0-9]*\) Loaded)/                           {
+    s/.*(Storage Element \([0-9][0-9]*\) Loaded).*/\1/p
+    q
+}
+/^Data Transfer Element '$driveslot':Full (Storage Element \([0-9][0-9]*\) Loaded)/              {
+    s/.*Storage Element \([0-9][0-9]*\) Loaded.*/\1/p
+    q
+}
+/^Data Transfer Element '$driveslot':Full (Unknown Storage Element Loaded)/    {
+    s/.*/-2/p
+    q
+}
+' < $mtx_status 2>&1`
+       shift                                   # get rid of the "x"
+       loadedslot=$1
+       loadedbarcode=$2
+       if [ -z "$loadedslot" ]; then
+               Exit 2 \
+                   `_ '<none>'` \
+                   "could not determine current slot, are you sure your drive slot is $driveslot"
+               return $?                       # in case we are internal
+       fi
+
+       #Use the current slot if it's empty and we don't know which slot is loaded'
+       if [ $loadedslot -eq -2 ]; then
+               set x `sed -n '
+{
+    /^.*Storage Element '$currentslot':Empty/ {
+       s/.*Storage Element \([0-9][0-9]*\):Empty/\1/p
+        q
+    }
+    /^.*Storage Element '$currentslot':Full/ {
+       s/.*Storage Element \([0-9][0-9]*\):Full/-2/p
+        q
+    }
+    /^.*Storage Element '$currentslot' IMPORT\/EXPORT:Empty/ {
+       s/.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Empty/\1/p
+        q
+    }
+    /^.*Storage Element '$currentslot' IMPORT\/EXPORT:Full/ {
+       s/.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Full/-2/p
+        q
+    }
+}
+' < $mtx_status 2>& 1`
+               shift                           # get rid of the "x"
+               loadedslotx=$1
+               if [ ! -z $loadedslotx ]; then
+                       loadedslot=$loadedslotx
+               fi
+       fi
+
+       #Use the first empty slot if we don't know which slot is loaded'
+       if [ $loadedslot -eq -2 ]; then
+               set x `sed -n '
+{
+    /^.*Storage Element \([0-9][0-9]*\):Empty/ {
+       s/.*Storage Element \([0-9][0-9]*\):Empty/\1/p
+        q
+    }
+    /^.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Empty/ {
+       s/.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Empty/\1/p
+        q
+    }
+}
+' < $mtx_status 2>& 1`
+               shift                           # get rid of the "x"
+               loadedslot=$1
+       fi
+
+       if IsNumeric "$loadedslot" ; then
+               :
+       else
+               Exit 2 \
+                    `_ '<none>'` \
+                    "currently loaded slot ($loadedslot) not numeric"
+               return $?                       # in case we are internal
+       fi
+       Log       `_ 'STATUS   -> currently loaded slot = %s' "$loadedslot"`
+       LogAppend `_ '         -> currently loaded barcode = "%s"' "$loadedbarcode"`
+}
+
+###
+# Get a list of slots between $firstslot and $lastslot, if they are set.
+# If they are not set, set them to the first and last slot seen on the
+# assumption the entire robot is to be used (???).
+###
+
+slot_list=
+get_slot_list() {
+       test -n "$DEBUG" && set -x
+       if [ -n "$slot_list" ]; then
+               return
+       fi
+       get_mtx_status
+       slot_list=`sed -n '
+/^Data Transfer Element:Full (Storage Element \([0-9][0-9]*\) Loaded)/ {
+    s/.*(Storage Element \([0-9][0-9]*\) Loaded).*/\1/p
+}
+/^Data Transfer Element '$driveslot':Full (Storage Element \([0-9][0-9]*\) Loaded)/ {
+    s/.*Storage Element \([0-9][0-9]*\) Loaded.*/\1/p
+}
+/^Data Transfer Element '$driveslot':Full (Unknown Storage Element Loaded)/ {
+    : loop
+    n
+    /^.*Storage Element \([0-9][0-9]*\):Full/ {
+        s/.*Storage Element \([0-9][0-9]*\):Full.*/\1/p
+        b loop
+    }
+    /^.*Storage Element \([0-9][0-9]*\):Empty/ {
+       s/.*Storage Element \([0-9][0-9]*\):Empty/\1/p
+    }
+}
+/^.*Storage Element \([0-9][0-9]*\):Full/ {
+    s/.*Storage Element \([0-9][0-9]*\):Full.*/\1/p
+}
+/^.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Full/ {
+    s/.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Full.*/\1/p
+}
+' < $mtx_status 2>&1 | grep -v "^${cleanslot}\$" | sort -n`
+       slot_list=`echo $slot_list`             # remove the newlines
+       if [ $firstslot -lt 0 -o $lastslot -lt 0 ]; then
+               last=$lastslot
+               for slot in $slot_list; do
+                       if [ $firstslot -lt 0 ]; then
+                               Log `_ 'SLOTLIST -> firstslot set to %s' "$slot"`
+                               firstslot=$slot
+                       fi
+                       if [ $lastslot -lt 0 ]; then
+                               last=$slot
+                       fi
+               done
+               if [ $lastslot -lt 0 -a $last -ge 0 ]; then
+                       Log `_ 'SLOTLIST -> lastslot set to %s' "$last"`
+                       lastslot=$last
+               fi
+               if [ $firstslot -lt 0 ]; then
+                       Exit 2 \
+                            `_ '<none>'` \
+                            `_ 'cannot determine first slot'`
+                       return $?               # in case we are internal
+               elif [ $lastslot -lt 0 ]; then
+                       Exit 2 \
+                            `_ '<none>'` \
+                            `_ 'cannot determine last slot'`
+                       return $?               # in case we are internal
+               fi
+       fi
+       amanda_slot_list=
+       for slot in $slot_list; do
+               if [ $slot -ge $firstslot -a $slot -le $lastslot ]; then
+                       amanda_slot_list="$amanda_slot_list $slot"
+               fi
+       done
+       if [ -z "$amanda_slot_list" ]; then
+               Exit 2 \
+                    `_ '<none>'` \
+                    "no slots available"
+               return $?                       # in case we are internal
+       fi
+       slot_list="$amanda_slot_list"
+}
+
+DBGFILE=`amgetconf dbopen.$argv0 2>/dev/null`
+if [ -z "$DBGFILE" ]
+then
+       DBGFILE=/dev/null                       # will try this again below
+fi
+
+changerfile=`amgetconf changerfile 2>/dev/null`
+if [ -z "$changerfile" ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            "changerfile must be specified in amanda.conf"
+fi
+
+rawtape=`amgetconf tapedev 2>/dev/null`
+if [ -z "$rawtape" ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            "tapedev may not be empty"
+fi
+tape=`tape_device_filename "$rawtape"`
+if [ -z "$tape" ]; then
+        Exit 2 \
+             ` _ '<none>'` \
+             "tapedev $rawtape is not a tape device."
+elif [ $tape = "/dev/null" -o `expr "$tape" : 'null:'` -eq 5 ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            "tapedev ($tape) may not be the null device"
+fi
+# Confusingly, TAPE is the name of the changer device...
+TAPE=`amgetconf changerdev 2>/dev/null`
+if [ -z "$TAPE" ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            "changerdev may not be empty"
+elif [ $TAPE = "/dev/null" ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            "changerdev ($TAPE) may not be the null device"
+fi
+export TAPE                                    # for mtx command
+
+CHANGER=$TAPE 
+export CHANGER                                 # for mtx command
+
+#### Set up the various config files.
+
+conf_match=`expr "$changerfile" : .\*\.conf\$`
+if [ $conf_match -ge 6 ]; then
+       configfile=$changerfile
+       changerfile=`echo $changerfile | sed 's/.conf$//g'`
+else
+       configfile=$changerfile.conf
+fi
+
+if [ ! -e $configfile ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            "configuration file \"$configfile\" doesn't exist"
+fi
+if [ ! -f $configfile ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            "configuration file \"$configfile\" is not a file"
+fi
+
+cleanfile=$changerfile-clean
+accessfile=$changerfile-access
+slotfile=$changerfile-slot
+labelfile=$changerfile-barcodes
+[ ! -s $cleanfile ] && echo 0 > $cleanfile
+[ ! -s $accessfile ] && echo 0 > $accessfile
+[ ! -s $slotfile ] && echo -1 > $slotfile
+[ ! -f $labelfile ] && > $labelfile
+cleancount=`cat $cleanfile`
+accesscount=`cat $accessfile`
+
+test -z "$MT" && Exit 2 "<none>" "No mt command defined"
+test ! -f "$MT" && Exit 2 "<none>" "mt command ($MT) doesn't exist"
+test -z "$MTX" && Exit 2 "<none>" "No mtx command defined"
+test ! -f "$MTX" && Exit 2 "<none>" "mtx command ($MTX) doesn't exist"
+
+#### Dig out of the config file what is needed
+
+varlist=
+varlist="$varlist firstslot"
+varlist="$varlist lastslot"
+varlist="$varlist cleanslot"
+varlist="$varlist cleancycle"
+varlist="$varlist OFFLINE_BEFORE_UNLOAD"       # old name
+varlist="$varlist offline_before_unload"
+varlist="$varlist unloadpause"
+varlist="$varlist AUTOCLEAN"                   # old name
+varlist="$varlist autoclean"
+varlist="$varlist autocleancount"
+varlist="$varlist havereader"
+varlist="$varlist driveslot"
+varlist="$varlist poll_drive_ready"
+varlist="$varlist initial_poll_delay"
+varlist="$varlist max_drive_wait"
+
+for var in $varlist
+do
+       val="`cat $configfile 2>/dev/null | sed -n '
+# Ignore comment lines (anything starting with a #).
+/^[    ]*#/d
+# Find the first var=val line in the file, print the value and quit.
+/^[    ]*'$var'[       ]*=[    ]*\([^  ][^     ]*\).*/ {
+       s/^[    ]*'$var'[       ]*=[    ]*\([^  ][^     ]*\).*/\1/p
+       q
+}
+'`"
+       eval $var=\"$val\"
+done
+
+# Deal with driveslot first so we can get DBGFILE set if we are still
+# using the old amgetconf.
+
+if [ -z "$driveslot" ]; then
+       driveslot=0;
+fi
+
+# Get DBGFILE set if it is not already.
+
+if [ $DBGFILE = /dev/null ]; then
+       if [ -d "$DBGDIR" ]; then
+               DBGFILE=$DBGDIR/changer.debug.drive$driveslot
+       else
+               DBGFILE=/dev/null
+       fi
+       Log `_ '=== Start %s ===' "\`date\`"`
+fi
+if [ -z "$driveslot" ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            `_ 'cannot determine drive slot from %s' "$tape"`
+fi
+
+stdout=$TMPDIR/$myname.1.$$
+stderr=$TMPDIR/$myname.2.$$
+mtx_status=$TMPDIR/$myname.status.$$
+trap "rm -f $stdout $stderr $mtx_status" 0     # exit cleanup
+
+Log `_ 'Using config file %s' "$configfile"`
+
+# Log the argument list.
+
+Log `_ "Arg info:"`
+LogAppend "\$# = $#"
+i=0
+LogAppend "\$$i = \"$argv0\""
+for arg in "$@"; do
+       i=`expr $i + 1`
+       LogAppend "\$$i = \"$arg\""
+done
+
+# Set the default config values for those not in the file.  Log the
+# results and make sure each is valid (numeric).
+
+firstslot=${firstslot:-'-1'}                           # default: mtx status
+lastslot=${lastslot:-'-1'}                             # default: mtx status
+cleanslot=${cleanslot:-'-1'}                           # default: -1
+cleancycle=${cleancycle:-'120'}                                # default: two minutes
+if [ -z "$offline_before_unload" -a -n "$OFFLINE_BEFORE_UNLOAD" ]; then
+       offline_before_unload=$OFFLINE_BEFORE_UNLOAD    # (old name)
+fi
+offline_before_unload=${offline_before_unload:-'0'}    # default: 0
+unloadpause=${unloadpause:-'0'}                                # default: 0
+if [ -z "$autoclean" -a -n "$AUTOCLEAN" ]; then
+       autoclean=$AUTOCLEAN                            # (old name)
+fi
+autoclean=${autoclean:-'0'}                            # default: 0
+autocleancount=${autocleancount:-'99'}                 # default: 99
+havereader=${havereader:-'0'}                          # default: 0
+poll_drive_ready=${poll_drive_ready:-'3'}              # default: three seconds
+initial_poll_delay=${initial_poll_delay:-'0'}          # default: zero zeconds
+max_drive_wait=${max_drive_wait:-'120'}                        # default: two minutes
+
+# check MT and MTX for sanity
+if test "${MTX:0:1}" = "/"; then
+    if ! test -f "${MTX}"; then
+       Exit 2 \
+           `_ '<none>'` \
+           `_ "mtx binary at '%s' not found" "$MTX"`
+    fi
+    if ! test -x "${MTX}"; then
+       Exit 2 \
+           `_ '<none>'` \
+           `_ "mtx binary at '%s' is not executable" "$MTX"`
+    fi
+else
+    # try running it to see if the shell can find it
+    "$MTX" >/dev/null 2>/dev/null
+    if test $? -eq 127 -o $? -eq 126; then
+       Exit 2 \
+           `_ '<none>'` \
+           `_ "Could not run mtx binary at '%s'" "$MTX"`
+    fi
+fi
+
+error=`try_find_mt`
+if test $? -ne 0; then
+    Exit 2 '<none>' $error
+fi
+
+get_slot_list
+
+Log `_ "Config info:"`
+for var in $varlist; do
+       if [ $var = "OFFLINE_BEFORE_UNLOAD" ]; then
+               continue                        # old name
+       elif [ $var = "AUTOCLEAN" ]; then
+               continue                        # old name
+       fi
+       eval val=\"'$'$var\"
+       if [ -z "$val" ]; then
+               Exit 2 \
+                    `_ '<none>'` \
+                    `_ '%s missing in %s' "$var" "$configfile"`
+       fi
+       if IsNumeric "$val" ; then
+               :
+       else
+               Exit 2 \
+                    `_ '<none>'` \
+                    `_ '%s (%s) not numeric in %s' "$var" "$val" "$configfile"`
+       fi
+       LogAppend $var = \"$val\"
+done
+
+# Run the rest of the config file sanity checks.
+
+if [ $firstslot -gt $lastslot ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            `_ 'firstslot (%s) greater than lastslot (%s) in %s' "$firstslot" "$lastslot" "$configfile"`
+fi
+if [ $autoclean -ne 0 -a $cleanslot -lt 0 ]; then
+       Exit 2 \
+            `_ '<none>'` \
+            `_ 'autoclean set but cleanslot not valid (%s)' "$cleanslot"`
+fi
+
+# Set up the current slot
+
+currentslot=`cat $slotfile`
+if IsNumeric "$currentslot" ; then
+       if [ $currentslot -lt $firstslot ]; then
+               Log `_ 'SETUP    -> current slot %s less than %s ... resetting to %s' "$currentslot" "$firstslot" "$firstslot"`
+               currentslot=$firstslot
+       elif [ $currentslot -gt $lastslot ]; then
+               Log `_ 'SETUP    -> current slot %s greater than %s ... resetting to %s' "$currentslot" "$lastslot" "$lastslot"`
+               currentslot=$lastslot
+       fi
+else
+       Log `_ 'SETUP    -> contents of %s (%s) invalid, setting current slot to first slot (%s)' "$slotfile" "$currentslot" "$firstslot"`
+       currentslot=$firstslot
+fi
+
+found_current=0
+first_slot_in_list=-1
+next_slot_after_current=-1
+for slot in $slot_list; do
+       if [ $first_slot_in_list -lt 0 ]; then
+               first_slot_in_list=$slot        # in case $firstslot is missing
+       fi
+       if [ $slot -eq $currentslot ]; then
+               found_current=1
+               break
+       elif [ $slot -gt $currentslot ]; then
+               next_slot_after_current=$slot   # $currentslot is missing
+               break
+       fi
+done
+if [ $found_current -eq 0 ]; then
+       if [ $next_slot_after_current -lt 0 ]; then
+               new_currentslot=$first_slot_in_list
+       else
+               new_currentslot=$next_slot_after_current
+       fi
+       Log `_ 'WARNING  -> current slot %s not available, setting current slot to next slot (%s)' "$currentslot" "$new_currentslot"`
+       currentslot=$new_currentslot
+fi
+
+# More routines.
+
+###
+# Eject the current tape and put it away.
+###
+
+eject() {
+       test -n "$DEBUG" && set -x
+       Log `_ 'EJECT    -> ejecting tape from %s' "$tape"`
+       get_loaded_info 
+       if [ $loadedslot -gt 0 ]; then
+               Log `_ 'EJECT    -> moving tape from drive %s to storage slot %s' "$driveslot" "$loadedslot"`
+               if [ $offline_before_unload -ne 0 ]; then
+                        Run try_eject_device $tape
+               fi
+               sleep $unloadpause
+               result=`Run $MTX unload $loadedslot $driveslot 2>&1`
+               status=$?
+               Log `_ '         -> status %s, result "%s"' "$status" "$result"`
+               mtx_status_valid=0
+               if [ $status -ne 0 ]; then
+                       answer="$result"
+                       code=2
+               else
+                       answer="$rawtape"
+                       code=0
+               fi
+       else
+               answer=`_ 'Drive was not loaded'`
+               code=1
+       fi
+       Exit $code "$loadedslot" "$answer"
+       return $?                               # in case we are internal
+}
+
+###
+# Reset the robot back to the first slot.
+###
+
+reset() {
+       test -n "$DEBUG" && set -x
+       Log `_ 'RESET    -> loading tape from slot %s to drive %s (%s)' "$firstslot" "$driveslot" "$tape"`
+       # Call loadslot without doing it as an internal and let it finish
+       # things up.
+       loadslot $firstslot
+       # NOTREACHED
+       Exit 2 `_ '<none>'` `_ 'reset: should not get here'`
+       return $?                               # in case we are internal
+}
+
+###
+# Unload the current tape (if necessary) and load a new one (unless
+# "advance").  If no tape is loaded, get the value of "current" from
+# $slotfile.
+###
+
+loadslot() {
+       test -n "$DEBUG" && set -x
+       if [ $# -lt 1 ]; then
+               Exit 2 `_ '<none>'` `_ 'Missing -slot argument'`
+               return $?                       # in case we are internal
+       fi
+       whichslot=$1
+       Log `_ 'LOADSLOT -> load drive %s (%s) from slot %s' "$driveslot" "$tape" "$whichslot"`
+
+       numeric=`echo $whichslot | sed 's/[^0-9]//g'`
+       case $whichslot in
+       current|prev|next|advance)
+               find_slot=$currentslot
+               ;;
+       first)
+               find_slot=$firstslot
+               ;;
+       last)
+               find_slot=$lastslot
+               ;;
+       $numeric)
+               find_slot=$numeric
+               ;;
+       clean)
+               find_slot=$cleanslot
+               ;;
+       *)
+               Exit 2 `_ '<none>'` `_ 'Illegal slot: "%s"' "$whichslot"`
+               return $?                       # in case we are internal
+               ;;
+       esac
+
+       # Find the requested slot in the slot list.  By loading the "set"
+       # command with multiple copies, we guarantee that if the slot is
+       # found, we can look both forward and backward without running
+       # off the end.  Putting $cleanslot at the end allows us to find
+       # that slot since it is not in $slot_list.
+       get_slot_list
+       set x $slot_list $slot_list $slot_list $cleanslot
+       shift                                   # get rid of the "x"
+       prev_slot=$1
+       shift
+       while [ $# -gt 0 ]; do
+               if [ $1 -eq $find_slot ]; then
+                       break
+               fi
+               prev_slot=$1
+               shift
+       done
+       if [ $# -le 0 ]; then
+               Exit 2 \
+                    `_ '<none>'` \
+                    `_ 'Cannot find slot %s in slot list (%s)' "$find_slot " "$slot_list"`
+               return $?                       # in case we are internal
+       fi
+
+       # Determine the slot to load.
+       case $whichslot in
+       next|advance)
+               shift
+               loadslot=$1
+               ;;
+       prev)
+               loadslot=$prev_slot
+               ;;
+       *)
+               loadslot=$find_slot
+       esac
+
+       # If the desired slot is already loaded, we are done.  Only update
+       # current slot if this is not the cleaning slot.
+       get_loaded_info
+       if [ $loadslot = $loadedslot ]; then
+               if [ $loadslot -ne $cleanslot ]; then
+                       rm -f $slotfile
+                       echo $loadslot > $slotfile
+               fi
+               Exit 0 "$loadedslot" "$rawtape"
+               return $?                       # in case we are internal
+       fi
+       if [ $loadedslot -eq -2 ]; then
+               Exit 0 "$loadedslot" "$rawtape"
+               return $?                       # in case we are internal
+        fi
+
+       # If we are loading the cleaning tape, bump the cleaning count
+       # and reset the access count.  Otherwise, bump the access count
+       # and see if it is time to do a cleaning.
+       if [ $loadslot = $cleanslot ]; then
+               rm -f $cleanfile $accessfile
+               expr $cleancount + 1 > $cleanfile
+               echo 0 > $accessfile
+       else
+               rm -f $accessfile
+               expr $accesscount + 1 > $accessfile
+               if [ $autoclean -ne 0 -a $accesscount -gt $autocleancount ]
+               then
+                       internal_call=`expr $internal_call + 1`
+                       loadslot clean > /dev/null 2>&1
+                       status=$?
+                       internal_call=`expr $internal_call - 1`
+                       if [ $status -ne 0 ]; then
+                               Exit $status "$loadslot" "$exit_answer"
+                               return $?       # in case we are internal
+                       fi
+
+                       # Slot $cleanslot might contain an ordinary tape
+                       # rather than a cleaning tape.  A cleaning tape
+                       # *MIGHT* auto-eject; an ordinary tape does not.
+                       # We therefore have to read the status again to
+                       # check what actually happened.
+                       mtx_status_valid=0
+                       get_loaded_info
+               fi
+       fi
+
+       # Unload whatever tape is in the drive.
+       internal_call=`expr $internal_call + 1`
+       eject > /dev/null 2>&1
+       status=$?
+       internal_call=`expr $internal_call - 1`
+       if [ $status -gt 1 ]; then
+               Exit $status "$exit_slot" "$exit_answer"
+               return $?                       # in case we are internal
+       fi
+
+       # If we were doing an "advance", we are done.
+       if [ $whichslot = advance ]; then
+               if [ $loadslot -ne $cleanslot ]; then
+                       rm -f $slotfile
+                       echo $loadslot > $slotfile
+               fi
+               Exit 0 "$loadslot" "/dev/null"
+               return $?                       # in case we are internal
+       fi
+
+       # Load the tape, finally!
+       Log `_ "LOADSLOT -> loading tape from slot %s to drive %s (%s)" "$loadslot" "$driveslot" "$tape"`
+       result=`Run $MTX load $loadslot $driveslot 2>&1`
+       status=$?
+       Log `_ '         -> status %s, result "%s"' "$status" "$result"`
+       mtx_status_valid=0
+       if [ $status -ne 0 ]; then
+               Exit 2 "$loadslot" "$result"
+               return $?                       # in case we are internal
+       fi
+
+       ###
+       # Cleaning tapes never go "ready", so instead we just sit here
+       # for "long enough" (as determined empirically by the user),
+       # then return success.
+       ###
+       if [ $loadslot -eq $cleanslot ]; then
+               Run sleep $cleancycle
+               Exit 0 "$loadslot" "$rawtape"
+               return $?                       # in case we are internal
+       fi
+
+       ###
+       # Wait for the drive to go online.
+       ###
+       waittime=0
+       ready=0
+       sleep $initial_poll_delay
+       while [ $waittime -lt $max_drive_wait ]; do
+                amdevcheck_status $tape
+               if [ $? -eq 0 ]; then
+                       ready=1
+                       break
+               fi
+               sleep $poll_drive_ready
+               waittime=`expr $waittime + $poll_drive_ready`
+       done
+       if [ $ready -eq 0 ]; then
+               Exit 2 "$loadslot" `_ 'Drive not ready after %s seconds, rewind said "%s"' "$max_drive_wait" "$result"`
+               return $?                       # in case we are internal
+       fi
+
+       if [ $loadslot -ne $cleanslot ]; then
+               rm -f $slotfile
+               echo $loadslot > $slotfile
+       fi
+       Exit 0 "$loadslot" "$rawtape"
+       return $?                               # in case we are internal
+}
+
+###
+# Return information about how the changer is configured and the current
+# state of the robot.
+###
+
+info() {
+       test -n "$DEBUG" && set -x
+       get_loaded_info
+       get_slot_list
+       Log       `_ 'INFO     -> first slot: %s' "$firstslot"`
+       LogAppend `_ '         -> current slot: %s' "$currentslot"`
+       LogAppend `_ '         -> loaded slot: %s' "$loadedslot"`
+       LogAppend `_ '         -> last slot: %s' "$lastslot"`
+       LogAppend `_ '         -> slot list: %s' "$slot_list"`
+       LogAppend `_ '         -> can go backwards: 1'`
+       LogAppend `_ '         -> havereader: %s' "$havereader"`
+
+        ###
+       # Check if a barcode reader is configured or not.  If so, it
+       # passes the 4th item in the echo back to amtape signifying it
+       # can search based on barcodes.
+       ###
+       reader=
+        if [ $havereader -eq 1 ]; then
+               reader=1
+        fi
+
+       if [ $currentslot -lt $firstslot -o $currentslot -gt $lastslot ]; then
+               currentslot=$firstslot          # what "current" will get
+       fi
+       numslots=`expr $lastslot - $firstslot + 1`
+       Exit 0 "$currentslot" "$numslots 1 $reader"
+       return $?                               # in case we are internal
+}
+
+###
+# Read the labelfile and scan for a particular entry.
+###
+
+read_labelfile() {
+       labelfile_entry_found=0
+       labelfile_label=
+       labelfile_barcode=
+
+       lbl_search=$1
+       bc_search=$2
+
+       line=0
+       while read lbl bc junk; do
+               line=`expr $line + 1`
+               if [ -z "$lbl" -o -z "$bc" -o -n "$junk" ]; then
+                       Log       `_ 'ERROR    -> Line %s malformed: %s %s %s' "$line" "$lbl" "$bc" "$junk"`
+                       LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
+                       Exit 2 \
+                            `_ '<none>'` \
+                            `_ 'Line %s malformed in %s: %s %s %s' "$line" "$labelfile" "$lbl" "$bc" "$junk"`
+                       return $?               # in case we are internal
+               fi
+               if [ $lbl = "$lbl_search" -o $bc = "$bc_search" ]; then
+                       if [ $labelfile_entry_found -ne 0 ]; then
+                               Log       `_ 'ERROR    -> Duplicate entries: %s line %s' "$labelfile" "$line"`
+                               LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
+                               Exit 2 \
+                                    `_ '<none>'` \
+                                    `_ 'Duplicate entries: %s line %s' "$labelfile" "$line"`
+                               return $?       # in case we are internal
+                       fi
+                       labelfile_entry_found=1
+                       labelfile_label=$lbl
+                       labelfile_barcode=$bc
+               fi
+       done
+}
+
+###
+# Adds the label and barcode for the currently loaded tape to the
+# barcode file.  Return an error if the database is messed up.
+###
+
+addlabel() {
+       test -n "$DEBUG" && set -x
+       if [ $# -lt 1 ]; then
+               Exit 2 `_ '<none>'` `_ 'Missing -label argument'`
+               return $?                       # in case we are internal
+       fi
+        tapelabel=$1
+       if [ $havereader -eq 0 ]; then
+               Exit 2 `_ '<none>'` `_ 'Not configured with barcode reader'`
+               return $?                       # in case we are internal
+       fi
+        get_loaded_info
+       if [ $loadedslot -lt 0 ]; then
+               Exit 1 `_ '<none>'` `_ 'No tape currently loaded'`
+               return $?                       # in case we are internal
+       fi
+       if [ -z "$loadedbarcode" ]; then
+               Exit 1 `_ '<none>'` `_ 'No barcode found for tape %s.' $tapelabel`
+               return $?                       # in case we are internal
+       fi
+       Log       `_ 'LABEL    -> Adding label "%s" with barcode "%s" for slot %s into %s' "$tapelabel" "$loadedbarcode" "$loadedslot" "$labelfile"`
+       read_labelfile "$tapelabel" "$loadedbarcode" < $labelfile
+       if [ $labelfile_entry_found -ne 0 ]; then
+               lf_val=
+               if [ "$labelfile_barcode" != "$loadedbarcode" ]; then
+                       lf_type=label
+                       lf_val=$tapelabel
+                       val_type=barcode
+                       old_val=$labelfile_barcode
+                       new_val=$loadedbarcode
+               elif [ "$labelfile_label" != "$tapelabel" ]; then
+                       lf_type=barcode
+                       lf_val=$loadedbarcode
+                       val_type=label
+                       old_val=$labelfile_label
+                       new_val=$tapelabel
+               fi
+               if [ -n "$lf_val" ]; then
+                       LogAppend `_ 'ERROR    -> !!! Label database corrupted !!!'`
+                       LogAppend `_ '         -> "%s" conflicts with new %s "%s" for %s "%s"' "$old_val" "$val_type" "$new_val" "$lf_type" "$lf_val"`
+                       Exit 2 \
+                            `_ '<none>'` \
+                            `_ '%s: "%s" conflicts with new %s "%s" for %s "%s"' "$tapelabel" "$old_val" "$val_type" "$new_val" "$lf_type" "$lf_val"`
+                       return $?               # in case we are internal
+               fi
+               LogAppend `_ "         -> already synced"`
+       else
+               echo "$tapelabel $loadedbarcode" >> $labelfile
+               LogAppend `_ '         -> appended %s entry: %s %s' "$labelfile" "$tapelabel" "$loadedbarcode"`
+       fi
+       Exit 0 "$loadedslot" "$rawtape"
+       return $?                               # in case we are internal
+}
+
+###
+# Look for a label in the barcode file.  If found, locate the slot it's
+# in by looking for the barcode in the mtx output, then load that tape.
+###
+
+searchtape() {
+       test -n "$DEBUG" && set -x
+       if [ $# -lt 1 ]; then
+               Exit 2 `_ '<none>'` `_ 'Missing -search argument'`
+               return $?                       # in case we are internal
+       fi
+        tapelabel=$1
+       if [ $havereader -eq 0 ]; then
+               Exit 2 `_ '<none>'` `_ 'Not configured with barcode reader'`
+               return $?                       # in case we are internal
+       fi
+       Log `_ 'SEARCH   -> Hunting for label "%s"' "$tapelabel"`
+       read_labelfile "$tapelabel" "" < $labelfile
+       if [ $labelfile_entry_found -eq 0 ]; then
+               LogAppend `_ '         -> !!! label "%s" not found in %s !!!' "$tapelabel" "$labelfile"`
+               LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
+               Exit 2 \
+                    `_ '<none>'` \
+                    `_ '%s: label "%s" not found in %s' "$tapelabel" "$tapelabel" "$labelfile"`
+               return $?                       # in case we are internal
+       fi
+       LogAppend `_ '         -> barcode is "%s"' "$labelfile_barcode"`
+       get_mtx_status
+       foundslot=`sed -n '
+/VolumeTag *= *'$labelfile_barcode' *$/                        {
+       s/.*Storage Element \([0-9][0-9]*\).*/\1/p
+       q
+}
+' < $mtx_status`
+       LogAppend `_ '         -> foundslot is %s' "$foundslot"`
+       if [ -z "$foundslot" ]; then
+               LogAppend `_ 'ERROR    -> !!! Could not find slot for barcode "%s"!!!' "$labelfile_barcode"`
+               LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
+               Exit 2 \
+                    `_ '<none>'` \
+                    `_ 'barcode "%s" not found in mtx status output' "$labelfile_barcode"`
+               return $?                       # in case we are internal
+       fi
+       # Call loadslot without doing it as an internal and let it finish
+       # things up.
+       loadslot $foundslot
+       # NOTREACHED
+       Exit 2 `_ '<none>'` `_ 'searchtape: should not get here'`
+       return $?                               # in case we are internal
+}
+
+###
+# Program invocation begins here
+###
+
+if [ $# -lt 1 ]; then
+       Exit 2 `_ '<none>'` `_ 'Usage: %s -command args' "$myname"`
+fi
+cmd=$1
+shift
+case "$cmd" in
+-slot)
+       loadslot "$@"
+       ;;
+-info)
+       info "$@"
+       ;;
+-reset)
+       reset "$@"
+       ;;
+-eject)
+       eject "$@"
+       ;;
+-label) 
+       addlabel "$@"
+       ;;
+-search)
+       searchtape "$@"
+       ;;
+-clean)
+       loadslot clean
+       ;;
+*)
+       Exit 2 `_ '<none>'` `_ 'unknown option: %s' "$cmd"`
+       ;;
+esac
+
+Exit 2 `_ '<none>'` `_ '%s: should not get here' "$myname"`
diff --git a/client-src/patch-system.sh b/client-src/patch-system.sh
new file mode 100644 (file)
index 0000000..fe7f634
--- /dev/null
@@ -0,0 +1,152 @@
+#! @SHELL@
+#
+# patch inetd.conf and services
+# originally by Axel Zinser (fifi@hiss.han.de)
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+       SUF="-@VERSION@"
+else
+       SUF=
+fi
+
+SERVICE_SUFFIX="@SERVICE_SUFFIX@"
+
+USER="@CLIENT_LOGIN@"
+
+INETDCONF=/etc/inetd.conf
+[ ! -f $INETDCONF ] && INETDCONF=/usr/etc/inetd.conf
+
+SERVICES=/etc/services
+[ ! -f $SERVICES ] && SERVICES=/usr/etc/services
+
+ENABLE_AMANDAD=true
+
+case `uname -n` in
+"@DEFAULT_SERVER@" | "@DEFAULT_SERVER@".*)
+    ENABLE_INDEX=true
+    ENABLE_TAPE=true
+    ;;
+*)
+    ENABLE_INDEX=false
+    ENABLE_TAPE=false
+    ;;
+esac
+
+CLIENT_PORT=10080
+KCLIENT_PORT=10081
+INDEX_PORT=10082
+TAPE_PORT=10083
+
+while [ $# != 0 ]; do
+    case "$1" in
+    --service-suffix=*)
+       SERVICE_SUFFIX=`echo $1 | sed -e 's/[^=]*=//'`;;
+    --version-suffix=*)
+       SUF=`echo $1 | sed -e 's/[^=]*=//'`;;
+    --inetd=*)
+        INETDCONF=`echo $1 | sed -e 's/[^=]*=//' -e 's%^$%/dev/null%'`;;
+    --services=*)
+       SERVICES=`echo $1 | sed -e 's/[^=]*=//' -e 's%^$%/dev/null%'`;;
+    --libexecdir=?*)
+       libexecdir=`echo $1 | sed -e 's/[^=]*=//'`;;
+    --user=?*)
+       USER=`echo $1 | sed -e 's/[^=]*=//'`;;
+    --enable-client)
+       ENABLE_AMANDAD=true;;
+    --disable-client)
+       ENABLE_AMANDAD=false;;
+    --enable-index)
+       ENABLE_INDEX=true;;
+    --disable-index)
+       ENABLE_INDEX=false;;
+    --enable-tape)
+       ENABLE_TAPE=true;;
+    --disable-tape)
+       ENABLE_TAPE=false;;
+    --client-port=?*)
+       CLIENT_PORT=`echo $1 | sed -e 's/[^=]*=//'`;;
+    --kclient-port=?*)
+       KCLIENT_PORT=`echo $1 | sed -e 's/[^=]*=//'`;;
+    --index-port=?*)
+       INDEX_PORT=`echo $1 | sed -e 's/[^=]*=//'`;;
+    --tape-port=?*)
+       TAPE_PORT=`echo $1 | sed -e 's/[^=]*=//'`;;
+    --usage | --help | -h)
+       echo `_ 'call this script with zero or more of the following arguments:'`
+       echo `_ '--version-suffix=<suffix>: append to program names [%s]' "$SUF"`
+       echo `_ '--service-suffix=<suffix>: append to service names [%s]' "$SERVICE_SUFFIX"`
+       echo `_ '--libexecdir=<dirname>: where daemons should be looked for [%s]' "$libexecdir"`
+       echo `_ '--inetd=<pathname>: full pathname of inetd.conf [%s]' "$INETDCONF"`
+       echo `_ '--services=<pathname>: full pathname of services [%s]' "$SERVICES"`
+       echo `_ '\tan empty pathname or /dev/null causes that file to be skipped'`
+       echo `_ '--user=<username>: run deamons as this user [%s]' "$USER"`
+       echo `_ '--enable/disable-client: enable/disable amandad [%s]' \`$ENABLE_AMANDAD && echo enabled || echo disabled\``
+       echo `_ '--enable/disable-index: enable/disable index server [%s]' \`$ENABLE_INDEX && echo enabled || echo disabled\``
+       echo `_ '--enable/disable-tape: enable/disable tape server [%s]' \`$ENABLE_TAPE && echo enabled || echo disabled\``
+       echo `_ '--client-port=<num>: amandad port number [%s]' "$CLIENT_PORT"`
+       echo `_ '--kclient-port=<num>: kamandad port number [%s]' "$KCLIENT_PORT"`
+       echo `_ '--index-port=<num>: index server port number [%s]' "$INDEX_PORT"`
+       echo `_ '--tape-port=<num>: tape server port number [%s]' "$TAPE_PORT"`
+       exec true;;
+    *)
+       echo `_ '%s: invalid argument %s.  run with -h for usage\n' "$0" "$1"` >&2
+       exec false;;
+    esac
+    shift
+done
+
+if [ "$SERVICES" = /dev/null ]; then :
+elif [ -f "$SERVICES" ]; then
+       TEMP="$SERVICES.new"
+       {
+           egrep < "$SERVICES" -v "^(amanda|kamanda|amandaidx|amidxtape)${SERVICE_SUFFIX}[     ]"
+           echo "amanda${SERVICE_SUFFIX} ${CLIENT_PORT}/udp"
+           echo "amanda${SERVICE_SUFFIX} ${CLIENT_PORT}/tcp"
+           echo "kamanda${SERVICE_SUFFIX} ${KCLIENT_PORT}/udp"
+           echo "amandaidx${SERVICE_SUFFIX} ${INDEX_PORT}/tcp"
+           echo "amidxtape${SERVICE_SUFFIX} ${TAPE_PORT}/tcp"
+       } > "$TEMP"
+       if diff "$SERVICES" "$TEMP" >/dev/null 2>/dev/null; then
+               echo `_ '%s is up to date' "$SERVICES"`
+       else
+               cp "$TEMP" "$SERVICES" || echo `_ 'cannot patch %s' "$SERVICES"`
+       fi
+       rm -f "$TEMP"
+else
+       echo `_ '%s not found!' "$SERVICES"`
+fi
+if [ "$INETDCONF" = /dev/null ]; then :
+elif [ -f "$INETDCONF" ]; then
+       err=`_ 'warning: %s/amandad%s does not exist' "$libexecdir" "$SUF"`
+       $ENABLE_AMANDAD && test ! -f $libexecdir/amandad$SUF && echo "$err" >&2
+       err=`_ 'warning: %s/amindexd%s does not exist' "$libexecdir" "$SUF"`
+       $ENABLE_INDEX && test ! -f $libexecdir/amindexd$SUF && echo "$err" >&2
+       err=`_ 'warning: %s/amidxtaped%s does not exist' "$libexecdir" "$SUF"`
+       $ENABLE_TAPE && test ! -f $libexecdir/amidxtaped$SUF && echo "$err" >&2
+       TEMP="$INETDCONF.new"
+       {
+           egrep < "$INETDCONF" -v "^(amanda|amandaidx|amidxtape)${SERVICE_SUFFIX}[    ]"
+           $ENABLE_AMANDAD && echo "amanda${SERVICE_SUFFIX}    dgram  udp wait   $USER $libexecdir/amandad$SUF    amandad$SUF"
+           $ENABLE_INDEX && echo "amandaidx${SERVICE_SUFFIX} stream tcp nowait $USER $libexecdir/amindexd$SUF   amindexd$SUF"
+           $ENABLE_TAPE && echo "amidxtape${SERVICE_SUFFIX} stream tcp nowait $USER $libexecdir/amidxtaped$SUF amidxtaped$SUF"
+       } > "$TEMP"
+       if diff "$INETDCONF" "$TEMP" >/dev/null 2>/dev/null; then
+               fmt="%s is up to date\n"
+               printf $fmt $INETDCONF
+       else
+               fmt="cannot patch %s\n"
+               cp "$TEMP" "$INETDCONF" || printf $fmt $INETDCONF
+       fi
+       rm -f "$TEMP"
+else
+       fmt="%s not found!\n"
+       printf $fmt $INETDCONF
+fi
diff --git a/common-src/amaespipe.sh b/common-src/amaespipe.sh
new file mode 100755 (executable)
index 0000000..8d3aa1c
--- /dev/null
@@ -0,0 +1,90 @@
+#! @SHELL@
+#
+# Copyright (c) 2005 Zmanda Inc.  All Rights Reserved.
+# 
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+# 
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+# 
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+# wrapper script to use aespipe
+# based on bz2aespipe distributed by aespipe from 
+# http://loop-aes.sourceforge.net/
+# FILE FORMAT
+# 10 bytes: constant string 'bz2aespipe'
+# 10 bytes: itercountk digits
+# 1 byte: '0' = AES128, '1' = AES192, '2' = AES256
+# 1 byte: '0' = SHA256, '1' = SHA384, '2' = SHA512, '3' = RMD160
+# 24 bytes: random seed string
+# remaining bytes are aespipe encrypted
+
+# These definitions are only used when encrypting.
+# Decryption will autodetect these definitions from archive.
+ENCRYPTION=AES256
+HASHFUNC=SHA256
+ITERCOUNTK=100
+WAITSECONDS=1
+AMANDA_HOME=~@CLIENT_LOGIN@
+GPGKEY="$AMANDA_HOME/.gnupg/am_key.gpg"
+FDNUMBER=3
+
+if test x$1 = x-d ; then
+    # decrypt
+    n=`head -c 10 - | tr -d -c 0-9a-zA-Z`
+    if test x${n} != xbz2aespipe ; then
+        echo `_ 'bz2aespipe: wrong magic - aborted'` >/dev/tty
+        exit 1
+    fi
+    itercountk=`head -c 10 - | tr -d -c 0-9`
+    if test x${itercountk} = x ; then itercountk=0; fi
+    n=`head -c 1 - | tr -d -c 0-9`
+    encryption=AES128
+    if test x${n} = x1 ; then encryption=AES192; fi
+    if test x${n} = x2 ; then encryption=AES256; fi
+    n=`head -c 1 - | tr -d -c 0-9`
+    hashfunc=SHA256
+    if test x${n} = x1 ; then hashfunc=SHA384; fi
+    if test x${n} = x2 ; then hashfunc=SHA512; fi
+    if test x${n} = x3 ; then hashfunc=RMD160; fi
+    seedstr=`head -c 24 - | tr -d -c 0-9a-zA-Z+/`
+    aespipe -K ${GPGKEY} -p ${FDNUMBER} -e ${encryption} -H ${hashfunc} -S ${seedstr} -C ${itercountk} -d
+else
+    # encrypt
+    echo -n bz2aespipe
+    echo ${ITERCOUNTK} | awk '{printf "%10u", $1;}'
+    n=`echo ${ENCRYPTION} | tr -d -c 0-9`
+    aesstr=0
+    if test x${n} = x192 ; then aesstr=1; fi
+    if test x${n} = x256 ; then aesstr=2; fi
+    n=`echo ${HASHFUNC} | tr -d -c 0-9`
+    hashstr=0
+    if test x${n} = x384 ; then hashstr=1; fi
+    if test x${n} = x512 ; then hashstr=2; fi
+    if test x${n} = x160 ; then hashstr=3; fi
+    seedstr=`head -c 18 /dev/urandom | uuencode -m - | head -n 2 | tail -n 1`
+    echo -n ${aesstr}${hashstr}${seedstr}
+    aespipe -K ${GPGKEY} -p ${FDNUMBER} -e ${ENCRYPTION} -H ${HASHFUNC} -S ${seedstr} -C ${ITERCOUNTK} -w ${WAITSECONDS}
+fi
+exit 0
diff --git a/common-src/amanda-sh-lib.sh.in b/common-src/amanda-sh-lib.sh.in
new file mode 100644 (file)
index 0000000..0c82190
--- /dev/null
@@ -0,0 +1,49 @@
+# Shell library containing functions and definitions common to amanda's
+# shell scripts and wrappers.
+
+# Include this file as follows:
+#   prefix="@prefix@"
+#   exec_prefix="@exec_prefix@"
+#   amlibexecdir="@amlibexecdir@"
+#   . "${amlibexecdir}/amanda-sh-lib.sh"
+
+####
+# Configure variables
+
+GREP="@GREP@"
+EGREP="@EGREP@"
+GETTEXT="@GETTEXT@"
+GNUPLOT="@GNUPLOT@"
+GNUTAR="@GNUTAR@"
+STAR="@STAR@"
+SAMBA_CLIENT="@SAMBA_CLIENT@"
+GZIP="@GZIP@"
+SORT="@SORT@"
+MAILER="@MAILER@"
+PERL="@PERL@"
+AWK="@AWK@"
+
+####
+# Set up PATH for finding amanda executables
+
+PATH="@sbindir@:@amlibexecdir@:$PATH"
+
+####
+# Gettext
+
+# use as follows:
+#   echo `_ "%s: '%s' is not executable" "$myname" "$binpath"`
+# NOTE: use a text editor with shell syntax hilighting to avoid
+# quoting errors!
+
+if test -n "$GETTEXT"; then
+    _() {
+           fmt=`$GETTEXT -d amanda "$1"`
+           shift
+           printf "$fmt" $*
+    }
+else
+    _() {
+       printf "$@"
+    }
+fi
diff --git a/common-src/amcrypt-ossl-asym.sh b/common-src/amcrypt-ossl-asym.sh
new file mode 100644 (file)
index 0000000..bec5269
--- /dev/null
@@ -0,0 +1,188 @@
+#!@SHELL@
+#
+# amcrypt-ossl-asym.sh - asymmetric crypto helper using OpenSSL
+# Usage: amcrypt-ossl-asym.sh [-d]
+#
+# Copyright © 2006  Ben Slusky <sluskyb@paranoiacs.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+# 
+# Keys can be generated with the standard OpenSSL commands, e.g.:
+#
+# $ openssl genrsa -aes128 -out backup-privkey.pem 1024
+# Generating RSA private key, 1024 bit long modulus
+# [...]
+# Enter pass phrase for backup-privkey.pem: <ENTER YOUR PASS PHRASE>
+# Verifying - Enter pass phrase for backup-privkey.pem: <ENTER YOUR PASS PHRASE>
+#
+# $ openssl rsa -in backup-privkey.pem -pubout -out backup-pubkey.pem
+# Enter pass phrase for backup-privkey.pem: <ENTER YOUR PASS PHRASE>
+# Writing RSA key
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+# change these as needed
+OPENSSL=                       # whatever's in $PATH
+CIPHER=aes-256-cbc             # see `openssl help` for more ciphers
+AMANDA_HOME=~@CLIENT_LOGIN@
+RANDFILE=$AMANDA_HOME/.rnd
+export RANDFILE
+PASSPHRASE=$AMANDA_HOME/.am_passphrase # optional
+PRIVKEY=$AMANDA_HOME/backup-privkey.pem
+PUBKEY=$AMANDA_HOME/backup-pubkey.pem
+
+# where might openssl be?
+PATH=/bin:/usr/bin:/usr/local/bin:/usr/ssl/bin:/usr/local/ssl/bin:/opt/csw/bin
+export PATH
+MAGIC='AmAnDa+OpEnSsL'
+ME=`basename "$0"`
+WORKDIR="/tmp/.${ME}.$$"
+
+
+# first things first
+if [ -z "${OPENSSL:=`which openssl`}" ]; then
+       echo `_ '%s: %s not found' "${ME}" "openssl"` >&2
+       exit 1
+elif [ ! -x "${OPENSSL}" ]; then
+       echo `_ "%s: can't execute %s (%s)" "${ME}" "openssl" "${OPENSSL}"` >&2
+       exit 1
+fi
+
+if [ -n "${PASSPHRASE}" ]; then
+       # check the openssl version. if it's too old, we have to handle
+       # the pass phrase differently.
+       OSSL_VERSION=`eval \"${OPENSSL}\" version |cut -d\  -f2`
+       case "${OSSL_VERSION}" in
+        ''|0.[0-8].*|0.9.[0-6]*|0.9.7|0.9.7[a-c]*)
+               echo `_ '%s: %s is version %s' "${ME}" "${OPENSSL}" "${OSSL_VERSION}"` >&2
+               echo `_ '%s: Using pass phrase kluge for OpenSSL version >=0.9.7d' "${ME}"` >&2
+               PASS_FROM_STDIN=yes
+               ;;
+       esac
+fi
+
+mkdir -m 700 "${WORKDIR}"
+if [ $? -ne 0 ]; then
+       echo `_ '%s: failed to create temp directory' "${ME}"` >&2
+       exit 1
+fi
+# ignore SIGINT
+trap "" 2
+trap "rm -rf \"${WORKDIR}\"" 0 1 3 15
+
+# we'll need to pad the datastream to a multiple of the cipher block size
+# prior to encryption and decryption. 96 bytes (= 768 bits) should be good
+# for any cipher.
+pad() {
+       perl -pe 'BEGIN { $bs = 96; $/ = \8192 } $nbytes = ($nbytes + length) % $bs; END { print "\0" x ($bs - $nbytes) }'
+}
+
+encrypt() {
+       # generate a random printable cipher key (on one line)
+       echo `"${OPENSSL}" rand -base64 80` >"${WORKDIR}/pass"
+
+       # encrypt the cipher key using the RSA public key
+       "${OPENSSL}" rsautl -encrypt -in "${WORKDIR}/pass" -out "${WORKDIR}/pass.ciphertext" -pubin -inkey "${PUBKEY}" -pkcs
+       [ $? -eq 0 ] || return 1
+
+       # print magic
+       printf "%s" "${MAGIC}"
+
+       # print the encrypted cipher key, preceded by size
+       ls -l "${WORKDIR}/pass.ciphertext" | awk '{ printf("%-10d", $5) }'
+       cat "${WORKDIR}/pass.ciphertext"
+
+       # encrypt data using the cipher key and print
+       pad | "${OPENSSL}" enc "-${CIPHER}" -nopad -e -pass "file:${WORKDIR}/pass" -nosalt
+       [ $? -eq 0 ] || return 1
+}
+
+decrypt() {
+       # read magic
+       magicsize=`printf "%s" "${MAGIC}" | wc -c | sed 's/^ *//'`
+       magic=`dd bs=$magicsize count=1 2>/dev/null`
+       if [ "$magic" != "${MAGIC}" ]; then
+               echo `_ '%s: bad magic' "${ME}"` >&2
+               return 1
+       fi
+
+       # read size of encrypted cipher key
+       n=`dd bs=10 count=1 2>/dev/null`
+       [ $n -gt 0 ] 2>/dev/null
+       if [ $? -ne 0 ]; then
+               echo `_ '%s: bad header' "${ME}"` >&2
+               return 1
+       fi
+
+       # read the encrypted cipher key
+       dd "of=${WORKDIR}/pass.ciphertext" bs=$n count=1 2>/dev/null
+
+       # decrypt the cipher key using the RSA private key
+       if [ "${PASS_FROM_STDIN}" = yes ]; then
+               "${OPENSSL}" rsautl -decrypt -in "${WORKDIR}/pass.ciphertext" -out "${WORKDIR}/pass" -inkey "${PRIVKEY}" -pkcs < "${PASSPHRASE}"
+       else
+               "${OPENSSL}" rsautl -decrypt -in "${WORKDIR}/pass.ciphertext" -out "${WORKDIR}/pass" -inkey "${PRIVKEY}" ${PASSARG} -pkcs 3< "${PASSPHRASE}"
+       fi
+       [ $? -eq 0 ] || return 1
+
+       # use the cipher key to decrypt data
+       pad | "${OPENSSL}" enc "-${CIPHER}" -nopad -d -pass "file:${WORKDIR}/pass" -nosalt
+
+       # N.B.: in the likely event that we're piping to gzip, the above command
+       # may return a spurious error if gzip closes the output stream early.
+       return 0
+}
+
+if [ "$1" = -d ]; then
+       if [ -z "${PRIVKEY}" ]; then
+               echo `_ '%s: must specify private key for decryption' "${ME}"` >&2
+               exit 1
+       elif [ ! -r "${PRIVKEY}" ]; then
+               echo `_ "%s: can't read private key from %s" "${ME}" "${PRIVKEY}"` >&2
+               exit 1
+       fi
+
+       if [ -n "${PASSPHRASE}" -a -e "${PASSPHRASE}" -a -r "${PASSPHRASE}" ]; then
+               PASSARG='-passin fd:3'
+       else
+               PASSPHRASE=/dev/null
+       fi
+
+       decrypt
+       if [ $? -ne 0 ]; then
+               echo `_ '%s: decryption failed' "${ME}"` >&2
+               exit 1
+       fi
+else
+       if [ -z "${PUBKEY}" ]; then
+               echo `_ '%s: must specify public key for encryption' "${ME}"` >&2
+               exit 1
+       elif [ ! -r "${PUBKEY}" ]; then
+               echo `_ "%s: can't read public key from %s" "${ME}" "${PUBKEY}"` >&2
+               exit 1
+       fi
+
+       encrypt
+       if [ $? -ne 0 ]; then
+               echo `_ '%s: encryption failed' "${ME}"` >&2
+               exit 1
+       fi
+fi
diff --git a/common-src/amcrypt-ossl.sh b/common-src/amcrypt-ossl.sh
new file mode 100644 (file)
index 0000000..edab131
--- /dev/null
@@ -0,0 +1,47 @@
+#!@SHELL@
+#
+# amcrypt-ossl.sh - crypto helper using OpenSSL
+# Usage: amcrypt-ossl.sh [-d]
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+# change these as needed
+OPENSSL=                       # whatever's in $PATH
+CIPHER=aes-256-cbc             # see `openssl help` for more ciphers
+AMANDA_HOME=~@CLIENT_LOGIN@
+RANDFILE=$AMANDA_HOME/.rnd
+export RANDFILE
+PASSPHRASE=$AMANDA_HOME/.am_passphrase # required
+
+# where might openssl be?
+PATH=/bin:/usr/bin:/usr/local/bin:/usr/ssl/bin:/usr/local/ssl/bin:/opt/csw/bin
+export PATH
+ME=`basename "$0"`
+
+if [ -z "${OPENSSL:=`which openssl`}" ]; then
+       echo `_ '%s: openssl not found' "${ME}"` >&2
+       exit 1
+elif [ ! -x "${OPENSSL}" ]; then
+       echo `_ "%s: can't execute %s (%s)" "${ME}" "openssl" "${OPENSSL}"` >&2
+       exit 1
+fi
+
+# we'll need to pad the datastream to a multiple of the cipher block size prior
+# to encryption. 96 bytes (= 768 bits) should be good for any cipher.
+pad() {
+       perl -pe 'BEGIN { $bs = 96; $/ = \8192 } $nbytes = ($nbytes + length) % $bs; END { print "\0" x ($bs - $nbytes) }'
+}
+
+if [ "$1" = -d ]; then
+       # decrypt
+       "${OPENSSL}" enc -d "-${CIPHER}" -nopad -salt -pass fd:3 3< "${PASSPHRASE}"
+else
+       # encrypt
+       pad | "${OPENSSL}" enc -e "-${CIPHER}" -nopad -salt -pass fd:3 3< "${PASSPHRASE}"
+fi
+
diff --git a/common-src/amcrypt.sh b/common-src/amcrypt.sh
new file mode 100755 (executable)
index 0000000..82e1ea6
--- /dev/null
@@ -0,0 +1,47 @@
+#!@SHELL@
+#
+# Original wrapper by Paul Bijnens
+#
+# worked by Stefan G. Weichinger
+# to enable gpg-encrypted dumps via aespipe
+# also worked by Matthieu Lochegnies for server-side encryption
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+# add sbin and ucb dirs, as well as csw (blastwave)
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb:/opt/csw/bin"
+export PATH
+
+AMANDA_HOME=~@CLIENT_LOGIN@
+AM_AESPIPE=@sbindir@/amaespipe
+AM_PASSPHRASE=$AMANDA_HOME/.am_passphrase
+
+AESPIPE=`which aespipe`
+
+if [ $? -ne 0 ] ; then
+       echo `_ '%s: %s was not found in %s' "$0" "aespipe" "$PATH"` >&2
+        exit 2
+fi
+
+if [ ! -x $AESPIPE ] ; then
+       echo `_ '%s: %s is not executable' "$0" "aespipe"` >&2
+        exit 2
+fi
+
+if [ ! -x $AM_AESPIPE ] ; then
+        echo `_ '%s: %s was not found' "$0" "$AM_AESPIPE"` >&2
+        exit 2
+fi
+if [ ! -x $AM_AESPIPE ] ; then
+        echo `_ '%s: %s is not executable' "$0" "$AM_AESPIPE"` >&2
+        exit 2
+fi
+
+$AM_AESPIPE "$@" 3< $AM_PASSPHRASE
+
+rc=$?
+exit $rc
diff --git a/common-src/amcryptsimple.pl b/common-src/amcryptsimple.pl
new file mode 100755 (executable)
index 0000000..05e50e5
--- /dev/null
@@ -0,0 +1,141 @@
+#!@PERL@ -w
+#
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+#
+
+
+
+# Run perl.
+eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+         & eval 'exec /usr/bin/perl -S $0 $argv:q'
+                if 0;
+
+use Time::Local;
+
+my $AMANDA='@CLIENT_LOGIN@';
+
+my $ddebug = 1;   # set to 1 to print signal debug to stderr
+
+my $sigint_seen   = 0;
+my $sigpipe_seen  = 0;
+my $sighup_seen   = 0;
+my $sigill_seen   = 0;
+my $sigterm_seen  = 0;
+my $sigsegv_seen  = 0;
+my $sigquit_seen  = 0;
+my $sigfpe_seen   = 0;
+
+$AMANDA_HOME = (getpwnam($AMANDA) )[7] || die "Cannot find $AMANDA home directory\n" ;
+$AM_PASS = "$AMANDA_HOME/.am_passphrase";
+
+unless ( -e $AM_PASS ) {
+  die "secret key $AM_PASS not found\n";
+}
+
+
+$ENV{'PATH'} = '/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin:/opt/csw/bin';
+
+$ENV{'GNUPGHOME'} = "$AMANDA_HOME/.gnupg";
+
+
+sub encrypt() {
+    system "gpg --batch --no-secmem-warning --disable-mdc --symmetric --cipher-algo AES256 --passphrase-fd 3  3<$AM_PASS";
+}
+
+sub decrypt() {
+     system "gpg --batch --quiet --no-mdc-warning --decrypt --passphrase-fd 3  3<$AM_PASS";
+}
+
+sub int_catcher {
+    $sigint_seen = 1;
+}
+
+sub pipe_catcher {
+    $sigpipe_seen = 1;
+}
+
+sub hup_catcher {
+    $sighup_seen = 1;
+}
+
+sub ill_catcher {
+    $sigill_seen = 1;
+}
+
+sub term_catcher {
+    $sigterm_seen = 1;
+}
+
+sub segv_catcher {
+    $sigsegv_seen = 1;
+}
+
+sub quit_catcher {
+    $sigquit_seen = 1;
+}
+
+sub fpe_catcher {
+    $sigfpe_seen = 1;
+}
+
+#main
+
+$SIG{'INT'}   = 'int_catcher';
+$SIG{'PIPE'}  = 'pipe_catcher';
+$SIG{'HUP'}   = 'hup_catcher';
+$SIG{'ILL'}   = 'ill_catcher';
+$SIG{'TERM'}  = 'term_catcher';
+$SIG{'SEGV'}  = 'segv_catcher';
+$SIG{'QUIT'}  = 'quit_catcher';
+$SIG{'FPE'}   = 'FPE_catcher';
+
+
+if ( $#ARGV > 0 ) {
+     die "Usage: $0 [-d]\n";
+}
+
+if ( $#ARGV==0 && $ARGV[0] eq "-d" ) {
+    decrypt();
+}
+else {
+    encrypt();
+}
+
+if ( $ddebug  ) {
+    if ( $sigint_seen )  { print STDERR "strange sigint seen = $sigint_seen\n"; }
+    if ( $sigpipe_seen ) { print STDERR "strange sigpipe seen = $sigpipe_seen\n"; }
+    if ( $sighup_seen )  { print STDERR "strange sighup seen = $sighup_seen\n"; }
+    if ( $sigill_seen )  { print STDERR "strange sigill seen = $sigill_seen\n"; }
+    
+    if ( $sigterm_seen ) { print STDERR "strange sigterm seen = $sigterm_seen\n"; }
+    if ( $sigsegv_seen ) { print STDERR "strange sigsegv seen = $sigsegv_seen\n"; }
+    if ( $sigquit_seen ) { print STDERR "strange sigquit seen = $sigquit_seen\n"; }
+    if ( $sigfpe_seen )  { print STDERR "strange sigfpe seen = $sigfpe_seen\n"; }
+    
+}
+
+$SIG{'INT'}  = 'DEFAULT';
+$SIG{'PIPE'} = 'DEFAULT';
+$SIG{'HUP'}  = 'DEFAULT';
+$SIG{'ILL'}  = 'DEFAULT';
+$SIG{'TERM'} = 'DEFAULT';
+$SIG{'SEGV'} = 'DEFAULT';
+$SIG{'QUIT'} = 'DEFAULT';
+$SIG{'FPE'}  = 'DEFAULT';
+
diff --git a/common-src/amflock-flock.c b/common-src/amflock-flock.c
new file mode 100644 (file)
index 0000000..82001c3
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1998 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+
+/* moved from amflock.c by Dustin J. Mitchell <dustin@zmanda.com> */
+
+#include "amanda.h"
+
+static int
+flock_lock(
+    int        fd,
+    G_GNUC_UNUSED char *resource)
+{
+    return flock(fd, LOCK_EX);
+}
+
+static int
+flock_unlock(
+    int        fd,
+    G_GNUC_UNUSED char *resource)
+{
+    return flock(fd, LOCK_UN);
+}
+
+amflock_impl_t amflock_flock_impl = {
+    flock_lock,
+    flock_lock, /* no read-only support */
+    flock_unlock,
+    "flock"
+};
diff --git a/common-src/amflock-lnlock.c b/common-src/amflock-lnlock.c
new file mode 100644 (file)
index 0000000..142aea3
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1998 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+
+/* moved from amflock.c by Dustin J. Mitchell <dustin@zmanda.com> */
+
+#include "amanda.h"
+
+static int ln_lock(char *res, int op);
+char *_lnlock_dir = AMANDA_TMPDIR; /* amflock-test changes this; it's a constant otherwise */
+
+/* XXX - error checking in this section needs to be tightened up */
+
+/* Delete a lock file.
+*/
+static int
+delete_lock(
+    char *fn)
+{
+       int rc;
+
+       rc = unlink(fn);
+       if (rc != 0 && errno == ENOENT) rc = 0;
+
+       return rc;
+}
+
+/* Create a lock file.
+*/
+static int
+create_lock(
+    char *fn,
+    long pid)
+{
+       int fd;
+       FILE *f;
+       int mask;
+
+       (void)delete_lock(fn);                  /* that's MY file! */
+
+       mask = umask(0027);
+       fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0640);
+       umask(mask);
+       if (fd == -1) return -1;
+
+       if((f = fdopen(fd, "w")) == NULL) {
+           aclose(fd);
+           return -1;
+       }
+       g_fprintf(f, "%ld\n", pid);
+       if (fclose(f) == EOF)
+           return -1;
+       return 0;
+}
+
+/* Read the pid out of a lock file.
+**   -1=error, otherwise pid.
+*/
+static long
+read_lock(
+    char *     fn) /* name of lock file */
+{
+       int save_errno;
+       FILE *f;
+       long pid;
+
+       if ((f = fopen(fn, "r")) == NULL) {
+               return -1;
+       }
+       if (fscanf(f, "%ld", &pid) != 1) {
+               save_errno = errno;
+               afclose(f);
+               errno = save_errno;
+               return -1;
+       }
+       if (fclose(f) != 0) {
+               return -1;
+       }
+       return pid;
+}
+
+/* Link a lock if we can.
+**   0=done, 1=already locked, -1=error.
+*/
+static int
+link_lock(
+    char *     lk,     /* real lock file */
+    char *     tlk)    /* temp lock file */
+{
+       int rc;
+       int serrno;     /* saved errno */
+       struct stat lkstat, tlkstat;
+
+       /* an atomic check and set operation */
+       rc = link(tlk, lk);
+       if (rc == 0) return 0; /* XXX do we trust it? */
+
+       /* link() says it failed - don't beleive it */
+       serrno = errno;
+
+       if (stat(lk, &lkstat) == 0 &&
+           stat(tlk, &tlkstat) == 0 &&
+           lkstat.st_ino == tlkstat.st_ino)
+               return 0;       /* it did work! */
+
+       errno = serrno;
+
+       if (errno == EEXIST) rc = 1;
+
+       return rc;
+}
+
+/* Steal a lock if we can.
+**   0=done; 1=still in use; -1 = error.
+*/
+static int
+steal_lock(
+    char *     fn,     /* name of lock file to steal */
+    long       mypid,  /* my process id */
+    char *     sres)   /* name of steal-resource to lock */
+{
+       long pid;
+       int rc;
+
+       /* prevent a race with another stealer */
+       rc = ln_lock(sres, 1);
+       if (rc != 0) goto error;
+
+       pid = read_lock(fn);
+       if (pid == -1) {
+               if (errno == ENOENT) goto done;
+               goto error;
+       }
+
+       if (pid == mypid) goto steal; /* i'm the locker! */
+
+       /* are they still there ? */
+       rc = kill((pid_t)pid, 0);
+       if (rc != 0) {
+               if (errno == ESRCH) goto steal; /* locker has gone */
+               goto error;
+       }
+
+       rc = ln_lock(sres, 0);
+       if (rc != 0) goto error;
+
+       return 1;
+
+steal:
+       rc = delete_lock(fn);
+       if (rc != 0) goto error;
+
+done:
+       rc = ln_lock(sres, 0);
+       if (rc != 0) goto error;
+
+       return 0;
+
+error:
+       rc = ln_lock(sres, 0);
+
+       return -1;
+}
+
+static int
+ln_lock(
+    char *     res, /* name of resource to lock */
+    int                op)  /* true to lock; false to unlock */
+{
+       long mypid;
+       char *lockfile = NULL;
+       char *tlockfile = NULL;
+       char *mres = NULL;
+       int rc;
+       char pid_str[NUM_STR_SIZE];
+
+       mypid = (long)getpid();
+
+       lockfile = vstralloc(_lnlock_dir, "/am", res, ".lock", NULL);
+
+       if (!op) {
+               /* unlock the resource */
+               assert(read_lock(lockfile) == mypid);
+
+               (void)delete_lock(lockfile);
+               amfree(lockfile);
+               return 0;
+       }
+
+       /* lock the resource */
+
+       g_snprintf(pid_str, SIZEOF(pid_str), "%ld", mypid);
+       tlockfile = vstralloc(_lnlock_dir, "/am", res, ".", pid_str, NULL);
+
+       (void)create_lock(tlockfile, mypid);
+
+       mres = stralloc2(res, ".");
+
+       while(1) {
+               rc = link_lock(lockfile, tlockfile);
+               if (rc == -1) break;
+               if (rc == 0) break;
+
+               rc = steal_lock(lockfile, mypid, mres);
+               if (rc == -1) break;
+               if (rc == 0) continue;
+               sleep(1);
+       }
+
+       (void) delete_lock(tlockfile);
+
+       amfree(mres);
+       amfree(tlockfile);
+       amfree(lockfile);
+
+       return rc;
+}
+
+static int
+lnlock_lock(
+    G_GNUC_UNUSED int fd,
+    char *resource)
+{
+    return ln_lock(resource, 1);
+}
+
+static int
+lnlock_unlock(
+    G_GNUC_UNUSED int fd,
+    char *resource)
+{
+    return ln_lock(resource, 0);
+}
+
+amflock_impl_t amflock_lnlock_impl = {
+    lnlock_lock,
+    lnlock_lock, /* no read-only support */
+    lnlock_unlock,
+    "lnlock"
+};
diff --git a/common-src/amflock-lockf.c b/common-src/amflock-lockf.c
new file mode 100644 (file)
index 0000000..90af1ff
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1998 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+
+/* moved from amflock.c by Dustin J. Mitchell <dustin@zmanda.com> */
+
+#include "amanda.h"
+
+/* XPG4-UNIX (eg, SGI IRIX, DEC DU) has F_ULOCK instead of F_UNLOCK */
+#if defined(F_ULOCK) && !defined(F_UNLOCK)
+#  define F_UNLOCK F_ULOCK
+#endif
+
+static int
+lockf_lock(
+    int        fd,
+    G_GNUC_UNUSED char *resource)
+{
+    return lockf(fd, F_LOCK, (off_t)0);
+}
+
+static int
+lockf_unlock(
+    int        fd,
+    G_GNUC_UNUSED char *resource)
+{
+    off_t pos;
+
+    /* unlock from here on */
+    if (lockf(fd, F_UNLOCK, (off_t)0) == -1) return -1;
+
+    /* unlock from bof to here */
+    pos = lseek(fd, (off_t)0, SEEK_CUR);
+    if (pos == (off_t)-1) {
+       if (errno == ESPIPE) 
+           pos = (off_t)0;
+       else
+           return -1;
+    }
+
+    if (pos > (off_t)0) {
+       if (lockf(fd, F_UNLOCK, -pos) == -1)
+           return -1;
+    }
+
+    return 0;
+}
+
+amflock_impl_t amflock_lockf_impl = {
+    lockf_lock,
+    lockf_lock, /* no read-only support */
+    lockf_unlock,
+    "lockf"
+};
diff --git a/common-src/amflock-posix.c b/common-src/amflock-posix.c
new file mode 100644 (file)
index 0000000..4e2af7b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1998 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+
+/* moved from amflock.c by Dustin J. Mitchell <dustin@zmanda.com> */
+
+#include "amanda.h"
+
+static int
+posix_lock(
+    int        fd,
+    G_GNUC_UNUSED char *resource)
+{
+    struct flock lock;
+
+    lock.l_type = F_WRLCK;
+    lock.l_start = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len = 0; /* to EOF */
+    return fcntl(fd, F_SETLKW, &lock);
+}
+
+static int
+posix_rolock(
+    int        fd,
+    G_GNUC_UNUSED char *resource)
+{
+    struct flock lock;
+
+    lock.l_type = F_RDLCK;
+    lock.l_start = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len = 0; /* to EOF */
+    return fcntl(fd, F_SETLKW, &lock);
+}
+
+static int
+posix_unlock(
+    int        fd,
+    G_GNUC_UNUSED char *resource)
+{
+    struct flock lock;
+
+    lock.l_type = F_UNLCK;
+    lock.l_start = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len = 0; /* to EOF */
+    return fcntl(fd, F_SETLK, &lock);
+}
+
+amflock_impl_t amflock_posix_impl = {
+    posix_lock,
+    posix_rolock,
+    posix_unlock,
+    "posix"
+};
diff --git a/common-src/amflock-test.c b/common-src/amflock-test.c
new file mode 100644 (file)
index 0000000..4becf5c
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1998 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+
+#include "amanda.h"
+
+/* from amflock.c */
+extern amflock_impl_t *amflock_impls[];
+
+int
+main(void)
+{
+    amflock_impl_t **imp = amflock_impls;
+    char *filename = "./amflocktest.file";
+    char *resource = "rez";
+    int fd;
+    int lock_ro;
+
+    /* set lnlock's lock directory to the current directory */
+    extern char *_lnlock_dir;
+    _lnlock_dir = ".";
+
+    while (*imp) {
+       g_fprintf(stderr, _("Testing amflock-%s\n"), (*imp)->impl_name);
+       alarm(5); /* time out after 5 seconds */
+
+       for (lock_ro = 0; lock_ro < 2; lock_ro++) { /* false (0) or true (1) */
+           if (unlink(filename) == -1 && errno != ENOENT) {
+               perror("unlink");
+               return 1;
+           }
+
+           if ((fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600)) == -1) {
+               perror("open");
+               return 1;
+           }
+
+           if (lock_ro) {
+               if ((*imp)->amroflock_impl(fd, resource) != 0) {
+                   perror("amroflock");
+                   return 1;
+               }
+           } else {
+               if ((*imp)->amflock_impl(fd, resource) != 0) {
+                   perror("amflock");
+                   return 1;
+               }
+           }
+
+           if ((*imp)->amfunlock_impl(fd, resource) != 0) {
+               perror("amfunlock");
+               return 1;
+           }
+
+           close(fd); /* ignore error */
+           unlink(filename); /* ignore error */
+       }
+
+       imp++;
+    }
+
+    return 0;
+}
diff --git a/common-src/amflock.h b/common-src/amflock.h
new file mode 100644 (file)
index 0000000..f9d33e1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1999 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+
+/* Moved from amanda.h and amflock.c by Dustin J. Mitchell <dustin@zmanda.com> */
+
+/* Public interface */
+
+/*
+ * Get a file lock (for read/write files).
+ */
+int amflock(int fd, char *resource);
+
+/*
+ * Get a file lock (for read-only files).
+ */
+int amroflock(int fd, char *resource);
+
+/*
+ * Release a file lock.
+ */
+int amfunlock(int fd, char *resource);
+
+/* Implementation interface */
+typedef int (*amflock_fn)(int, char *);
+typedef struct amflock_impl_s {
+    amflock_fn amflock_impl;
+    amflock_fn amroflock_impl;
+    amflock_fn amfunlock_impl;
+    char *impl_name;
+} amflock_impl_t;
diff --git a/common-src/amgpgcrypt.pl b/common-src/amgpgcrypt.pl
new file mode 100755 (executable)
index 0000000..2852670
--- /dev/null
@@ -0,0 +1,80 @@
+#!@PERL@ -w
+#
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+#
+
+# Amanda has problem with gpg mdc(modification detection code) in the binary mode.
+# This program encrypt with mdc disabled.
+# If mdc is required, use --armor option. 
+
+
+
+# Run perl.
+eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+         & eval 'exec /usr/bin/perl -S $0 $argv:q'
+                if 0;
+
+use Time::Local;
+
+my $AMANDA='@CLIENT_LOGIN@';
+my $saw_sigint = 0;
+
+$AMANDA_HOME = (getpwnam($AMANDA) )[7] || die "Cannot find $AMANDA home directory\n" ;
+
+#The following two ($AM_PASS, $AM_PRIV) are needed only for restore/recover
+#They should be protected and stored away during other time.
+$AM_PASS = "$AMANDA_HOME/.am_passphrase";
+$AM_PRIV = "$AMANDA_HOME/.gnupg/secring.gpg";
+
+$ENV{'PATH'} = '/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin:/opt/csw/bin';
+
+$ENV{'GNUPGHOME'} = "$AMANDA_HOME/.gnupg";
+
+sub encrypt() {
+#   system "gpg --armor --encrypt --recipient $AMANDA";
+    system "gpg  --batch --disable-mdc --encrypt --cipher-algo AES256 --recipient $AMANDA";
+}
+
+sub decrypt() {
+     system "gpg --batch --quiet --no-mdc-warning --secret-keyring $AM_PRIV --decrypt --passphrase-fd 3  3<$AM_PASS";
+}
+
+sub my_sig_catcher {
+       $saw_sigint = 1;
+}
+
+#main
+
+
+
+$SIG{'INT'} = 'my_sig_catcher';
+
+
+if ( $#ARGV > 0 ) {
+     die "Usage: $0 [-d]\n";
+}
+
+if ( $#ARGV==0 && $ARGV[0] eq "-d" ) {
+    decrypt();
+}
+else {
+    encrypt();
+}
+
+$SIG{'INT'} = 'DEFAULT';
diff --git a/common-src/columnar.c b/common-src/columnar.c
new file mode 100644 (file)
index 0000000..6a11dd7
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-2000 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ *                        Computer Science Department
+ *                        University of Maryland at College Park
+ */
+/*
+ * Originally living in conffile.c, this stuff supports columnar output in amreport.
+ */
+
+
+#include "amanda.h"
+#include "columnar.h"
+
+ColumnInfo ColumnData[] = {
+    { "HostName",   0, 12, 12, 0, "%-*.*s", "HOSTNAME" },
+    { "Disk",       1, 11, 11, 0, "%-*.*s", "DISK" },
+    { "Level",      1, 1,  1,  0, "%*.*d",  "L" },
+    { "OrigKB",     1, 7,  0,  0, "%*.*lf", "ORIG-KB" },
+    { "OutKB",      1, 7,  0,  0, "%*.*lf", "OUT-KB" },
+    { "Compress",   1, 6,  1,  0, "%*.*lf", "COMP%" },
+    { "DumpTime",   1, 7,  7,  0, "%*.*s",  "MMM:SS" },
+    { "DumpRate",   1, 6,  1,  0, "%*.*lf", "KB/s" },
+    { "TapeTime",   1, 6,  6,  0, "%*.*s",  "MMM:SS" },
+    { "TapeRate",   1, 6,  1,  0, "%*.*lf", "KB/s" },
+    { NULL,         0, 0,  0,  0, NULL,     NULL }
+};
+
+
+int
+ColumnDataCount(void )
+{
+    return (int)(SIZEOF(ColumnData) / SIZEOF(ColumnData[0]));
+}
+
+/* conversion from string to table index
+ */
+int
+StringToColumn(
+    char *s)
+{
+    int cn;
+
+    for (cn=0; ColumnData[cn].Name != NULL; cn++) {
+       if (strcasecmp(s, ColumnData[cn].Name) == 0) {
+           break;
+       }
+    }
+    return cn;
+}
+
+char
+LastChar(
+    char *s)
+{
+    return s[strlen(s)-1];
+}
+
+int
+SetColumnDataFromString(
+    ColumnInfo* ci,
+    char *s,
+    char **errstr)
+{
+    ci = ci;
+
+    /* Convert from a Columnspec string to our internal format
+     * of columspec. The purpose is to provide this string
+     * as configuration paramter in the amanda.conf file or
+     * (maybe) as environment variable.
+     * 
+     * This text should go as comment into the sample amanda.conf
+     *
+     * The format for such a ColumnSpec string s is a ',' seperated
+     * list of triples. Each triple consists of
+     *   -the name of the column (as in ColumnData.Name)
+     *   -prefix before the column
+     *   -the width of the column
+     *       if set to -1 it will be recalculated
+     *  to the maximum length of a line to print.
+     * Example:
+     *         "Disk=1:17,HostName=1:10,OutKB=1:7"
+     * or
+     *         "Disk=1:-1,HostName=1:10,OutKB=1:7"
+     * 
+     * You need only specify those colums that should be changed from
+     * the default. If nothing is specified in the configfile, the
+     * above compiled in values will be in effect, resulting in an
+     * output as it was all the time.
+     *                                                 ElB, 1999-02-24.
+     */
+
+    while (s && *s) {
+       int Space, Width;
+       int cn;
+       char *eon= strchr(s, '=');
+
+       if (eon == NULL) {
+           *errstr = stralloc2(_("invalid columnspec: "), s);
+           return -1;
+       }
+       *eon= '\0';
+       cn=StringToColumn(s);
+       if (ColumnData[cn].Name == NULL) {
+           *errstr = stralloc2(_("invalid column name: "), s);
+           return -1;
+       }
+       if (sscanf(eon+1, "%d:%d", &Space, &Width) != 2) {
+           *errstr = stralloc2(_("invalid format: "), eon + 1);
+           return -1;
+       }
+       ColumnData[cn].Width= Width;
+       ColumnData[cn].PrefixSpace = Space;
+       if (LastChar(ColumnData[cn].Format) == 's') {
+           if (Width < 0)
+               ColumnData[cn].MaxWidth= 1;
+           else
+               if (Width > ColumnData[cn].Precision)
+                   ColumnData[cn].Precision= Width;
+       }
+       else {
+           if (Width < 0) {
+               ColumnData[cn].MaxWidth= 1;
+           }
+           else if (Width < ColumnData[cn].Precision)
+               ColumnData[cn].Precision = Width;
+       }
+       s= strchr(eon+1, ',');
+       if (s != NULL)
+           s++;
+    }
+    return 0;
+}
+
diff --git a/common-src/columnar.h b/common-src/columnar.h
new file mode 100644 (file)
index 0000000..a9f54b8
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-2000 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ *                        Computer Science Department
+ *                        University of Maryland at College Park
+ */
+/*
+ * Originally living in conffile.h, this stuff supports columnar output in amreport.
+ */
+
+#ifndef COLUMNAR_H
+#define COLUMNAR_H
+
+/* for each column we define some values on how to
+ * format this column element
+ */
+typedef struct {
+    char *Name;                /* column name */
+    int PrefixSpace;   /* the blank space to print before this
+                        * column. It is used to get the space
+                        * between the colums
+                        */
+    int Width;         /* the width of the column itself */
+    int Precision;     /* the precision if its a float */
+    int MaxWidth;      /* if set, Width will be recalculated
+                        * to the space needed */
+    char *Format;      /* the printf format string for this
+                        * column element
+                        */
+    char *Title;       /* the title to use for this column */
+} ColumnInfo;
+
+extern ColumnInfo ColumnData[];
+
+int ColumnDataCount(void);
+int StringToColumn(char *s);
+char LastChar(char *s);
+int SetColumnDataFromString(ColumnInfo* ci, char *s, char **errstr); /* (sic) */
+
+#endif /* COLUMNAR_H */
diff --git a/common-src/debug.h b/common-src/debug.h
new file mode 100644 (file)
index 0000000..b3d539e
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1999 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+/*
+ * $Id: debug.h 6789 2007-06-18 20:18:52Z dustin $
+ *
+ * Logging support
+ */
+
+/* this file is included from amanda.h; there is no need to include
+ * it explicitly in source files. */
+
+#ifndef AMANDA_DEBUG_H
+#define AMANDA_DEBUG_H
+
+/*
+ * GENERAL LOGGING
+ */
+
+/* Amanda uses glib's logging facilities.  See
+ *  http://developer.gnome.org/doc/API/2.2/glib/glib-Message-Logging.html
+ *
+ * Note that log output will go to stderr until debug_open is called.
+ *
+ * The error levels are assigned as follows:
+ *  g_error -- errors that should dump core (will not return)
+ *  g_critical -- fatal errors, exiting with exit status in 
+ *    error_exit_status() (will not return)
+ *  g_warning -- non-fatal problems
+ *  g_message -- normal status information
+ *  g_info -- helpful extra details, but not verbose
+ *  g_debug -- debug messages
+ *
+ * g_error and g_critical will respect erroutput_type, potentially
+ * sending the error to the Amanda logfile for this run (see logfile.c).
+ */
+
+/* g_debug was introduced in glib 2.6, so define it here for systems where
+ * it is lacking.  g_info doesn't exist even in glib 2.13, but maybe it will
+ * be invented soon..
+ */
+
+#ifndef g_debug
+#define g_debug(...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, __VA_ARGS__)
+#endif
+
+#ifndef g_info
+#define g_info(...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, __VA_ARGS__)
+#endif
+
+/*
+ * FATAL ERROR HANDLING
+ */
+
+/* for compatibility; these should eventually be substituted throughout
+ * the codebase.  Extra calls to exit() and abort() should be optimized
+ * away, and are there only for stupid compilers. */
+#define errordump(...) do { g_error(__VA_ARGS__); abort(); } while (0)
+#define error(...) do { g_critical(__VA_ARGS__); exit(error_exit_status); } while (0)
+
+/* Additional handling for error and critical messages. */
+typedef enum {
+    /* send message to stderr (for interactive programs) */
+    ERR_INTERACTIVE    = 1 << 0, /* (default) */
+
+    /* log to syslog */
+    ERR_SYSLOG         = 1 << 1,
+
+    /* add an L_FATAL entry in the Amanda logfile for the 
+     * current run */
+    ERR_AMANDALOG      = 1 << 2
+} erroutput_type_t;
+extern erroutput_type_t erroutput_type;
+
+/* The process exit status that will be given when error()
+ * or errordump() is called.
+ */
+extern int error_exit_status;
+
+/* Supply a pointer to the logfile module's logerror(), if
+ * ERR_AMANDALOG is set.
+ *
+ * This function is required because libamanda, which contains
+ * debug.c, is not always linked with the logerror module 
+ * (which only appears in server applications).
+ *
+ * @param logerror_fn: function pointer
+ */
+void set_logerror(void (*logerror_fn)(char *));
+
+/*
+ * DEBUG LOGGING
+ */
+
+/* short names */
+#define dbopen(a)      debug_open(a)
+#define dbreopen(a,b)  debug_reopen(a,b)
+#define dbrename(a,b)  debug_rename(a,b)
+#define dbclose()      debug_close()
+#define dbprintf       debug_printf
+#define dbfd()         debug_fd()
+#define dbfp()         debug_fp()
+#define dbfn()         debug_fn()
+
+/* constants for db(re)open */
+#define DBG_SUBDIR_SERVER  "server"
+#define DBG_SUBDIR_CLIENT  "client"
+#define DBG_SUBDIR_AMANDAD "amandad"
+
+/* Open the debugging log in the given subdirectory.  Once 
+ * this function is called, debug logging is available.
+ *
+ * The debugging file is created in the given subdirectory of the
+ * amanda debugging directory, with a filename based on the current
+ * process name (from get_pname).
+ *
+ * @param subdir: subdirectory in which to create the debug file.
+ * This is usually one of the DBG_SUBDIR_* constants.  
+ */
+void   debug_open(char *subdir);
+
+/* Re-open a previously debug_close()d debug file, given by 
+ * filename, optionally adding a notation as to why it was
+ * reopened.
+ *
+ * @param file: the filename of the debug file to reopen
+ * @param notation: reason for re-opening the file
+ */
+void   debug_reopen(char *file, char *notation);
+
+/* Rename the debugging logfile into a configuration-specific subdirectory
+ * of SUBDIR.  Any existing content of the file will be preserved.
+ *
+ * @param config: configuration name
+ * @param subdir: subdirectory in which to create the debug file.
+ */
+void   debug_rename(char *config, char *subdir);
+
+/* Flush and close the debugging logfile.  Call this function at application
+ * shutdown.
+ */
+void   debug_close(void);
+
+/* Add a message to the debugging logfile.  A newline is not automatically 
+ * added.
+ *
+ * This function is deprecated in favor of glib's g_debug().
+ */
+void   debug_printf(const char *format, ...) G_GNUC_PRINTF(1,2);
+
+/* Get the file descriptor for the debug file
+ *
+ * @returns: the file descriptor
+ */
+int    debug_fd(void);
+
+/* Get the stdio file handle for the debug file.
+ *
+ * @returns: the file handle
+ */
+FILE * debug_fp(void);
+
+/* Get the pathname of the debug file.
+ *
+ * The result should not be freed by the caller.
+ *
+ * @returns: the pathname
+ */
+char * debug_fn(void);
+
+/* Use 'dup2' to send stderr output to the debug file.  This is useful
+ * when launching other applications, where the stderr of those applications
+ * may be necessary for debugging.  It should be called in the child, after
+ * the fork().
+ */
+void debug_dup_stderr_to_debug(void);
+
+/*
+ * PROCESS NAME
+ */
+
+/*
+ * ASSERTIONS
+ */
+
+#ifndef SWIG
+#ifdef ASSERTIONS
+
+/* Like the standard assert(), but call g_error() to log the result properly */
+#define assert(exp)    do {                                            \
+    if (!(exp)) {                                                      \
+       g_error(_("assert: %s is false: file %s, line %d"),             \
+          stringize(exp), __FILE__, __LINE__);                         \
+        g_assert_not_reached();                                                \
+    }                                                                  \
+} while (0)
+
+#else  /* ASSERTIONS */
+
+#define assert(exp) ((void)0)
+
+#endif /* ASSERTIONS */
+#endif /* SWIG */
+
+#endif /* AMANDA_DEBUG_H */
diff --git a/common-src/file.h b/common-src/file.h
new file mode 100644 (file)
index 0000000..98e6f2b
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1997-1998 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: AMANDA core development group.
+ */
+
+extern int    mkpdir(char *file, mode_t mode, uid_t uid, gid_t gid);
+extern int    rmpdir(char *file, char *topdir);
+
+/* Given a pathname, convert it to "canonical form" for this system.  Currently,
+ * this means nothing on POSIX, but means substituting /cygdrive, etc. on Cygwin.
+ *
+ * @param pathname: the pathname to canonicalize
+ * @param result_buf (output): the canonicalize pathname; this should be a buffer of
+ * at least PATH_MAX bytes.
+ */
+void canonicalize_pathname(char *pathname, char *result_buf);
+
+extern char  *sanitise_filename(char *inp);
+char  *old_sanitise_filename(char *inp);
+void    safe_fd(int fd_start, int fd_count);
+void   safe_cd(void);
+void   save_core(void);
+
+/* Get the uid of CLIENT_LOGIN, or -1 if it doesn't exist.  Note that, if
+ * only running a server, CLIENT_LOGIN may legitimately not exist.
+ *
+ * @returns: userid, or -1 if invalid
+ */
+uid_t get_client_uid(void);
+
+/* Get the gid of CLIENT_LOGIN, or -1 if it doesn't exist.  Note that, if
+ * only running a server, CLIENT_LOGIN may legitimately not exist.
+ *
+ * @returns: groupid, or -1 if invalid
+ */
+gid_t get_client_gid(void);
+
+extern /*@only@*/ /*@null@*/ char *debug_agets(const char *c, int l, FILE *file);
+extern /*@only@*/ /*@null@*/ char *debug_areads(const char *c, int l, int fd);
+#define agets(f)             debug_agets(__FILE__,__LINE__,(f))
+#define areads(f)            debug_areads(__FILE__,__LINE__,(f))
+
+ssize_t        areads_dataready(int fd);
+void   areads_relbuf(int fd);
+
+/*
+ * "Safe" close macros.  Close the object then set it to a value that
+ * will cause an error if referenced.
+ *
+ * aclose(fd) -- close a file descriptor and set it to -1.
+ * afclose(f) -- close a stdio file and set it to NULL.
+ * apclose(p) -- close a stdio pipe file and set it to NULL.
+ *
+ * Note: be careful not to do the following:
+ *
+ *  for(fd = low; fd < high; fd++) {
+ *      aclose(fd);
+ *  }
+ *
+ * Since aclose() sets the argument to -1, this will loop forever.
+ * Just copy fd to a temp variable and use that with aclose().
+ *
+ * Aclose() interacts with areads() to inform it to release any buffer
+ * it has outstanding on the file descriptor.
+ */
+
+#define aclose(fd) do {                                                        \
+    if((fd) >= 0) {                                                    \
+       close(fd);                                                      \
+       areads_relbuf(fd);                                              \
+    }                                                                  \
+    (fd) = -1;                                                         \
+} while(0)
+
+#define afclose(f) do {                                                        \
+    if((f) != NULL) {                                                  \
+       fclose(f);                                                      \
+    }                                                                  \
+    (f) = NULL;                                                                \
+} while(0)
+
+#define apclose(p) do {                                                        \
+    if((p) != NULL) {                                                  \
+       pclose(p);                                                      \
+    }                                                                  \
+    (p) = NULL;                                                                \
+} while(0)
+
+
+/* Calls system open(), but takes care of interrupted system calls and
+ * clears the close-on-exec bit. In the failure case, errno is
+ * retained from the final call to open(). */
+extern int robust_open(const char * pathname, int flags, mode_t mode);
+
+/* Same idea but for close. */
+extern int robust_close(int fd);
+
+/* Get the original working directory, at application startup
+ *
+ * @returns: pointer to statically allocated string
+ */
+char *get_original_cwd(void);
diff --git a/common-src/genversion.h b/common-src/genversion.h
new file mode 100644 (file)
index 0000000..316c245
--- /dev/null
@@ -0,0 +1,3 @@
+#define CC "gcc"
+#define BUILT_DATE "Fri Aug 22 14:21:05 EDT 2008"
+#define BUILT_MACH "x86_64-unknown-linux-gnu"
diff --git a/common-src/glib-util.c b/common-src/glib-util.c
new file mode 100644 (file)
index 0000000..ec9728a
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/*
+ * Utilities that aren't quite included in glib
+ *
+ * Author: Dustin J. Mitchell <dustin@zmanda.com>, Ian Turner <ian@zmanda.com>
+ */
+
+#include "amanda.h"
+#include "glib-util.h"
+#include "conffile.h" /* For find_multiplier. */
+
+typedef enum {
+    FLAG_STRING_NAME,
+    FLAG_STRING_SHORT_NAME,
+    FLAG_STRING_NICK
+} FlagString;
+
+static char ** g_flags_to_strv(int value, GType type, FlagString source);
+
+void
+_glib_util_foreach_glue(gpointer data, gpointer func)
+{
+    void (*one_arg_fn)(gpointer) = (void (*)(gpointer))func;
+    one_arg_fn(data);
+}
+
+GValue* g_value_unset_init(GValue* value, GType type) {
+    g_return_val_if_fail(value != NULL, NULL);
+
+    if (G_IS_VALUE(value)) {
+        g_value_unset(value);
+    }
+    g_value_init(value, type);
+    return value;
+}
+
+GValue* g_value_unset_copy(const GValue * from, GValue * to) {
+    g_return_val_if_fail(from != NULL, NULL);
+    g_return_val_if_fail(to != NULL, NULL);
+
+    g_value_unset_init(to, G_VALUE_TYPE(from));
+    g_value_copy(from, to);
+    return to;
+}
+
+void g_list_free_full(GList * list) {
+    GList * cur = list;
+
+    while (cur != NULL) {
+        gpointer data = cur->data;
+        amfree(data);
+        cur = g_list_next(cur);
+    }
+
+    g_list_free(list);
+}
+
+void g_slist_free_full(GSList * list) {
+    GSList * cur = list;
+
+    while (cur != NULL) {
+        gpointer data = cur->data;
+        amfree(data);
+        cur = g_slist_next(cur);
+    }
+
+    g_slist_free(list);
+}
+
+void g_queue_free_full(GQueue * queue) {
+    while (!g_queue_is_empty(queue)) {
+        gpointer data;
+        data = g_queue_pop_head(queue);
+        amfree(data);
+    }
+    g_queue_free(queue);
+}
+
+void g_ptr_array_free_full(GPtrArray * array) {
+    size_t i;
+
+    for (i = 0; i < array->len; i ++) {
+        amfree(g_ptr_array_index(array, i));
+    }
+    g_ptr_array_free(array, TRUE);
+}
+
+gboolean g_value_compare(GValue * a, GValue * b) {
+    if (a == NULL && b == NULL)
+        return TRUE;
+    if (a == NULL || b == NULL)
+        return FALSE;
+    if (G_VALUE_TYPE(a) != G_VALUE_TYPE(b))
+        return FALSE;
+    if (g_value_fits_pointer(a) && g_value_fits_pointer(b)) {
+        return g_value_peek_pointer(a) == g_value_peek_pointer(b);
+    } else {
+        /* Since there is no builtin comparison function, we resort to
+           comparing serialized strings. Yuck. */
+        char * a_str;
+        char * b_str;
+        gboolean rval;
+        a_str = g_strdup_value_contents(a);
+        b_str = g_strdup_value_contents(b);
+        rval = (0 == strcmp(a_str, b_str));
+        amfree(a_str);
+        amfree(b_str);
+        return rval;
+    }
+    
+    g_assert_not_reached();
+}
+
+static gboolean g_value_set_boolean_from_string(GValue * val, char * string) {
+    if (strcasecmp(string, "true") == 0 ||
+        strcasecmp(string, "yes") == 0 ||
+        strcmp(string, "1") == 0) {
+        g_value_set_boolean(val, TRUE);
+    } else if (strcasecmp(string, "false") == 0 ||
+               strcasecmp(string, "no") == 0 ||
+               strcmp(string, "0") == 0) {
+        g_value_set_boolean(val, FALSE);
+    } else {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean g_value_set_int_from_string(GValue * val, char * string) {
+    long int strto_result;
+    char * strto_end;
+    gint64 multiplier;
+    strto_result = strtol(string, &strto_end, 0);
+    multiplier = find_multiplier(strto_end);
+    if (multiplier == G_MAXINT64) {
+        if (strto_result >= 0) {
+            g_value_set_int(val, G_MAXINT);
+        } else {
+            g_value_set_int(val, G_MININT);
+        }
+        return TRUE;
+    } else if (*string == '\0' || multiplier == 0
+               || strto_result < G_MININT / multiplier
+               || strto_result > G_MAXINT / multiplier) {
+        return FALSE;
+    } else { 
+        g_value_set_int(val, (int)(strto_result * multiplier));
+        return TRUE;
+    }
+}
+
+static gboolean g_value_set_uint_from_string(GValue * val, char * string) {
+    unsigned long int strto_result;
+    char * strto_end;
+    guint64 multiplier;
+    strto_result = strtoul(string, &strto_end, 0);
+    multiplier = find_multiplier(strto_end); /* casts */
+    if (multiplier == G_MAXINT64) {
+        g_value_set_uint(val, G_MAXUINT);
+        return TRUE;
+    } else if (multiplier == 0 || *string == '\0' ||
+               strto_result > G_MAXUINT / multiplier) {
+        return FALSE;
+    } else {
+        g_value_set_uint(val, (guint)(strto_result * multiplier));
+        return TRUE;
+    }
+}
+
+static gboolean g_value_set_uint64_from_string(GValue * val, char * string) {
+    unsigned long long int strto_result;
+    char * strto_end;
+    guint64 multiplier;
+    strto_result = strtoull(string, &strto_end, 0);
+    multiplier = find_multiplier(strto_end); /* casts */
+    if (multiplier == G_MAXINT64) {
+        g_value_set_uint64(val, G_MAXUINT64);
+        return TRUE;
+    } else if (multiplier == 0 || *string == '\0' ||
+        strto_result > G_MAXUINT64 / multiplier) {
+        return FALSE;
+    } else {
+        g_value_set_uint64(val, (guint64)(strto_result * multiplier));
+        return TRUE;
+    }
+}
+
+/* Flags can contain multiple values. We assume here that values are like
+ * C identifiers (that is, they match /[A-Za-z_][A-Za-z0-9_]+/), although
+ * that doesn't seem to be a requirement of GLib. With that assumption in
+ * mind, we look for the format "FLAG_1 | FLAG_2 | ... | FLAG_N". */
+static gboolean g_value_set_flags_from_string(GValue * val, char * string) {
+    guint value = 0;
+    char * strtok_saveptr;
+    char * string_copy;
+    char * strtok_first_arg;
+    const char delim[] = " \t,|";
+    GFlagsClass * flags_class;
+    
+    flags_class = (GFlagsClass*) g_type_class_ref(G_VALUE_TYPE(val));
+    g_return_val_if_fail(flags_class != NULL, FALSE);
+    g_return_val_if_fail(G_IS_FLAGS_CLASS(flags_class), FALSE);
+
+    /* Don't let strtok stop on original. */
+    strtok_first_arg = string_copy = strdup(string);
+    
+    for (;;) {
+        GFlagsValue * flag_value;
+        char * token = strtok_r(strtok_first_arg, delim, &strtok_saveptr);
+        strtok_first_arg = NULL;
+
+        if (token == NULL) {
+            break;
+        }
+        
+        flag_value = g_flags_get_value_by_name(flags_class, token);
+        if (flag_value == NULL) {
+            flag_value = g_flags_get_value_by_nick(flags_class, token);
+        }
+        if (flag_value == NULL) {
+            g_fprintf(stderr, _("Invalid flag %s for type %s\n"), token,
+                    g_type_name(G_VALUE_TYPE(val)));
+            continue;
+        }
+
+        value |= flag_value->value;
+    }
+    
+    amfree(string_copy);
+    
+    if (value == 0) {
+        g_fprintf(stderr, _("No valid flags for type %s in string %s\n"),
+                g_type_name(G_VALUE_TYPE(val)), string);
+        return FALSE;
+    }
+    
+    g_value_set_flags(val, value);
+    return TRUE;
+
+}
+
+/* This function really ought not to be part of Amanda. In my (Ian's) opinion,
+   serialization and deserialization should be a part of the GValue
+   interface. But it's not, and here we are. */
+gboolean g_value_set_from_string(GValue * val, char * string) {
+    g_return_val_if_fail(val != NULL, FALSE);
+    g_return_val_if_fail(G_IS_VALUE(val), FALSE);
+
+    if (G_VALUE_HOLDS_BOOLEAN(val)) {
+        return g_value_set_boolean_from_string(val, string);
+    } else if (G_VALUE_HOLDS_INT(val)) {
+        return g_value_set_int_from_string(val, string);
+    } else if (G_VALUE_HOLDS_UINT(val)) {
+        return g_value_set_uint_from_string(val, string);
+    } else if (G_VALUE_HOLDS_UINT64(val)) {
+        return g_value_set_uint64_from_string(val, string);
+    } else if (G_VALUE_HOLDS_STRING(val)) {
+        g_value_set_string(val, string);
+        return TRUE;
+    } else if (G_VALUE_HOLDS_FLAGS(val)) {
+        return g_value_set_flags_from_string(val, string);
+    }
+
+    return TRUE;
+}
+
+gint
+g_compare_strings(
+    gconstpointer a,
+    gconstpointer b)
+{
+    return strcmp((char *)a, (char *)b);
+}
+
+char * g_strjoinv_and_free(char ** strv, const char * seperator) {
+    char * rval = g_strjoinv(seperator, strv);
+    g_strfreev(strv);
+    return rval;
+}
+
+char ** g_flags_name_to_strv(int value, GType type) {
+    return g_flags_to_strv(value, type, FLAG_STRING_NAME);
+}
+
+char ** g_flags_short_name_to_strv(int value, GType type) {
+    return g_flags_to_strv(value, type, FLAG_STRING_SHORT_NAME);
+}
+
+char ** g_flags_nick_to_strv(int value, GType type) {
+    return g_flags_to_strv(value, type, FLAG_STRING_NICK);
+}
+
+static char * get_name_from_value(GFlagsValue * value, FlagString source) {
+    switch (source) {
+    case FLAG_STRING_NAME:
+    case FLAG_STRING_SHORT_NAME:
+        return strdup(value->value_name);
+    case FLAG_STRING_NICK:
+        return strdup(value->value_nick);
+    default:
+        return NULL;
+    }
+}
+
+/* If freed and notfreed have a common prefix that is different from freed,
+   then return that and free freed. Otherwise, return freed. */
+static char * find_common_prefix(char * freed, const char * notfreed) {
+    char * freed_ptr = freed;
+    const char * notfreed_ptr = notfreed;
+
+    if (freed == NULL) {
+        if (notfreed == NULL) {
+            return NULL;
+        } else {
+            return strdup(notfreed);
+        }
+    } else if (notfreed == NULL) {
+        amfree(freed);
+        return strdup("");
+    }
+
+    while (*freed_ptr == *notfreed_ptr) {
+        freed_ptr ++;
+        notfreed_ptr ++;
+    }
+
+    *freed_ptr = '\0';
+    return freed;
+}
+
+static char ** g_flags_to_strv(int value, GType type,
+                               FlagString source) {
+    GPtrArray * rval;
+    GFlagsValue * flagsvalue;
+    char * common_prefix = NULL;
+    int common_prefix_len;
+    GFlagsClass * class;
+
+    g_return_val_if_fail(G_TYPE_IS_FLAGS(type), NULL);
+    g_return_val_if_fail((class = g_type_class_ref(type)) != NULL, NULL);
+    g_return_val_if_fail(G_IS_FLAGS_CLASS(class), NULL);
+        
+    rval = g_ptr_array_new();
+    for (flagsvalue = class->values;
+         flagsvalue->value_name != NULL;
+         flagsvalue ++) {
+        if (source == FLAG_STRING_SHORT_NAME) {
+            common_prefix = find_common_prefix(common_prefix,
+                                               flagsvalue->value_name);
+        }
+                                               
+        if ((flagsvalue->value == 0 && value == 0) ||
+            (flagsvalue->value != 0 && (value & flagsvalue->value))) {
+            g_ptr_array_add(rval, get_name_from_value(flagsvalue, source));
+        }
+    }
+
+    if (source == FLAG_STRING_SHORT_NAME && common_prefix != NULL &&
+        ((common_prefix_len = strlen(common_prefix))) > 0) {
+        char * old;
+        char * new;
+        guint i;
+        for (i = 0; i < rval->len; i ++) {
+            old = g_ptr_array_index(rval, i);
+            new = strdup(old + common_prefix_len);
+            g_ptr_array_index(rval, i) = new;
+            g_free(old);
+        }
+    }
+    
+    g_ptr_array_add(rval, NULL);
+
+    amfree(common_prefix);
+    return (char**)g_ptr_array_free(rval, FALSE);
+}
+
+char * g_english_strjoinv(char ** strv, const char * conjunction) {
+    int length;
+    char * last;
+    char * joined;
+    char * rval;
+    strv = g_strdupv(strv);
+
+    length = g_strv_length(strv);
+    last = strv[length - 1];
+    strv[length - 1] = NULL;
+    
+    joined = g_strjoinv(", ", strv);
+    rval = g_strdup_printf("%s, %s %s", joined, conjunction, last);
+
+    g_free(joined);
+    g_free(last);
+    g_strfreev(strv);
+    return rval;
+}
+
+char * g_english_strjoinv_and_free(char ** strv, const char * conjunction) {
+    char * rval = g_english_strjoinv(strv, conjunction);
+    g_strfreev(strv);
+    return rval;   
+}
+
+#if !(GLIB_CHECK_VERSION(2,6,0))
+guint g_strv_length(gchar ** strv) {
+    int rval = 0;
+
+    if (G_UNLIKELY(strv == NULL))
+        return 0;
+
+    while (*strv != NULL) {
+        rval ++;
+        strv ++;
+    }
+    return rval;
+}
+
+#endif /* GLIB_CHECK_VERSION(2.6.0) */
diff --git a/common-src/glib-util.h b/common-src/glib-util.h
new file mode 100644 (file)
index 0000000..3151d2b
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+/*
+ * Utilities that aren't quite included in glib
+ *
+ * Author: Dustin J. Mitchell <dustin@zmanda.com>, Ian Turner <ian@zmanda.com>
+ */
+
+#ifndef GLIB_UTIL_H
+#define GLIB_UTIL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+/* like g_[s]list_foreach, but with a function taking only
+ * one argument.
+ */
+#define g_list_foreach_nodata(list, func)                              \
+    g_list_foreach((list), _glib_util_foreach_glue, (gpointer)(func));
+#define g_slist_foreach_nodata(list, func)                             \
+    g_slist_foreach((list), _glib_util_foreach_glue, (gpointer)(func));
+void _glib_util_foreach_glue(gpointer data, gpointer func);
+
+/* This function takes a GValue, which may be zero-filled or
+ * initialized. In either case, this function causes the GValue to be
+ * initialized with the given type. Note that this function lacks the
+ * safety of the standard g_value_ functions; it assumes that the
+ * passed value is zeroed or valid.
+ *
+ * Returns its first argument.*/
+GValue* g_value_unset_init(GValue* val, GType type);
+
+/* This does the same thing but also copies the contents of one value
+ * into another. Note that this function lacks the safety of the
+ * standard g_value_ functions; it assumes that the passed value is
+ * zeroed or valid.
+ *
+ * Returns its second (reset) argument.*/
+GValue* g_value_unset_copy(const GValue* from, GValue * to);
+
+/* These functions all take a GLib container, and call free() on all the
+ * pointers in the container before free()ing the container itself. */
+void g_list_free_full(GList * list);
+void g_slist_free_full(GSList * list);
+void g_queue_free_full(GQueue * queue);
+void g_ptr_array_free_full(GPtrArray * array);
+
+/* g_value_compare() does what you expect. It returns TRUE if and
+   only if the two values have the same type and the same value. Note
+   that it will return FALSE if the same value is stored with two
+   different types: For example, a GValue with a UCHAR of 1 and a
+   GValue with a CHAR of 1 will be considered inequal. Also, this is a
+   'shallow' comparison; pointers to distinct but equivalent objects
+   are considered inequal. */
+gboolean g_value_compare(GValue * a, GValue * b);
+
+/* Given a string and a GValue, parse the string and store it in the
+   GValue. The GValue should be pre-initalized to whatever type you want
+   parsed. */
+gboolean g_value_set_from_string(GValue * val, char * string);
+
+/* A GCompareFunc that will sort strings alphabetically (using strcmp) */
+gint g_compare_strings(gconstpointer a, gconstpointer b);
+
+/* These functions all take a Flags class and stringify it. They
+ * return a NULL-terminated array of strings that can be
+ * passed to g_strjoinv(), g_strfreev(), g_strdupv(), and
+ * g_strv_length(). Example output looks like:
+ * - g_flags_name_to_strv() -> "MEDIA_ACCESS_MODE_READ_ONLY"
+ * - g_flags_short_name_to_strv() -> "READ_ONLY"
+ * - g_flags_nick_to_strv() -> "read-only"
+ */
+
+char ** g_flags_name_to_strv(int value, GType type);
+char ** g_flags_short_name_to_strv(int value, GType type);
+char ** g_flags_nick_to_strv(int value, GType type);
+
+/* Just like g_strjoinv, but frees the array as well. */
+char * g_strjoinv_and_free(char ** strv, const char * seperator);
+
+/* Just like g_strjoinv, but joins like an English list. The string would
+ * usually be "and" or "or". */
+char * g_english_strjoinv(char ** strv, const char * conjunction);
+
+/* Just like g_english_strjoinv, but also frees the array. */
+char * g_english_strjoinv_and_free(char ** strv, const char * conjunction);
+
+/* Replacement for built-in functions. */
+#if !(GLIB_CHECK_VERSION(2,6,0))
+guint g_strv_length(gchar ** strv);
+#endif
+
+#endif
+
diff --git a/common-src/local-security.c b/common-src/local-security.c
new file mode 100644 (file)
index 0000000..29a946d
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1999 University of Maryland
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+
+/*
+ * $Id: local-security.c 6512 2007-05-24 17:00:24Z ian $
+ *
+ * local-security.c - security and transport over local or a local-like command.
+ *
+ * XXX still need to check for initial keyword on connect so we can skip
+ * over shell garbage and other stuff that local might want to spew out.
+ */
+
+#include "amanda.h"
+#include "util.h"
+#include "event.h"
+#include "packet.h"
+#include "queue.h"
+#include "security.h"
+#include "security-util.h"
+#include "stream.h"
+#include "version.h"
+
+/*
+ * Number of seconds amandad has to start up
+ */
+#define CONNECT_TIMEOUT 20
+
+/*
+ * Interface functions
+ */
+static void local_connect(const char *, char *(*)(char *, void *),
+                       void (*)(void *, security_handle_t *, security_status_t),
+                       void *, void *);
+
+/*
+ * This is our interface to the outside world.
+ */
+const security_driver_t local_security_driver = {
+    "LOCAL",
+    local_connect,
+    sec_accept,
+    sec_close,
+    stream_sendpkt,
+    stream_recvpkt,
+    stream_recvpkt_cancel,
+    tcpma_stream_server,
+    tcpma_stream_accept,
+    tcpma_stream_client,
+    tcpma_stream_close,
+    sec_stream_auth,
+    sec_stream_id,
+    tcpm_stream_write,
+    tcpm_stream_read,
+    tcpm_stream_read_sync,
+    tcpm_stream_read_cancel,
+    tcpm_close_connection,
+    NULL,
+    NULL
+};
+
+static int newhandle = 1;
+
+/*
+ * Local functions
+ */
+static int runlocal(struct tcp_conn *, const char *, const char *);
+
+
+/*
+ * local version of a security handle allocator.  Logically sets
+ * up a network "connection".
+ */
+static void
+local_connect(
+    const char *       hostname,
+    char *             (*conf_fn)(char *, void *),
+    void               (*fn)(void *, security_handle_t *, security_status_t),
+    void *             arg,
+    void *             datap)
+{
+    struct sec_handle *rh;
+    char *amandad_path=NULL;
+    char *client_username=NULL;
+    char myhostname[MAX_HOSTNAME_LENGTH+1];
+
+    assert(fn != NULL);
+    assert(hostname != NULL);
+
+    auth_debug(1, _("local: local_connect: %s\n"), hostname);
+
+    rh = alloc(SIZEOF(*rh));
+    security_handleinit(&rh->sech, &local_security_driver);
+    rh->hostname = NULL;
+    rh->rs = NULL;
+    rh->ev_timeout = NULL;
+    rh->rc = NULL;
+
+    if (gethostname(myhostname, MAX_HOSTNAME_LENGTH) == -1) {
+       security_seterror(&rh->sech, _("gethostname failed"));
+       (*fn)(arg, &rh->sech, S_ERROR);
+       return;
+    }
+    myhostname[SIZEOF(myhostname)-1] = '\0';
+
+    if (strcmp(hostname, myhostname) != 0 &&
+       match("^localhost(\\.localdomain)?$", hostname) == 0) {
+       security_seterror(&rh->sech,
+           _("%s: is not local"), hostname);
+       (*fn)(arg, &rh->sech, S_ERROR);
+       return;
+    }
+    rh->hostname = stralloc(hostname);
+    rh->rs = tcpma_stream_client(rh, newhandle++);
+
+    if (rh->rs == NULL)
+       goto error;
+
+    amfree(rh->hostname);
+    rh->hostname = stralloc(rh->rs->rc->hostname);
+
+    /*
+     * We need to open a new connection.
+     *
+     * XXX need to eventually limit number of outgoing connections here.
+     */
+    if(conf_fn) {
+       amandad_path    = conf_fn("amandad_path", datap);
+       client_username = conf_fn("client_username", datap);
+    }
+    if(rh->rc->read == -1) {
+       if (runlocal(rh->rs->rc, amandad_path, client_username) < 0) {
+           security_seterror(&rh->sech, _("can't connect to %s: %s"),
+                             hostname, rh->rs->rc->errmsg);
+           goto error;
+       }
+       rh->rc->refcnt++;
+    }
+
+    /*
+     * The socket will be opened async so hosts that are down won't
+     * block everything.  We need to register a write event
+     * so we will know when the socket comes alive.
+     *
+     * Overload rh->rs->ev_read to provide a write event handle.
+     * We also register a timeout.
+     */
+    rh->fn.connect = fn;
+    rh->arg = arg;
+    rh->rs->ev_read = event_register((event_id_t)rh->rs->rc->write, EV_WRITEFD,
+       sec_connect_callback, rh);
+    rh->ev_timeout = event_register((event_id_t)CONNECT_TIMEOUT, EV_TIME,
+       sec_connect_timeout, rh);
+
+    return;
+
+error:
+    (*fn)(arg, &rh->sech, S_ERROR);
+}
+
+/*
+ * Forks a local to the host listed in rc->hostname
+ * Returns negative on error, with an errmsg in rc->errmsg.
+ */
+static int
+runlocal(
+    struct tcp_conn *  rc,
+    const char *       amandad_path,
+    const char *       client_username)
+{
+    int rpipe[2], wpipe[2];
+    char *xamandad_path = (char *)amandad_path;
+
+#ifndef SINGLE_USERID
+    struct passwd *pwd = NULL;
+    uid_t uid = 0;
+    gid_t gid = 0;
+
+    if (getuid() == 0) {
+       if (client_username && strlen(client_username) > 1) {
+           pwd = getpwnam(client_username);
+            if (!pwd) {
+               dbprintf("User '%s' doesn't exist\n", client_username);
+           } else {
+               uid = pwd->pw_uid;
+               gid = pwd->pw_gid;
+           }
+       }
+       if (!pwd) {
+           uid = get_client_uid();
+           gid = get_client_gid();
+       }
+    }
+#endif
+
+    memset(rpipe, -1, SIZEOF(rpipe));
+    memset(wpipe, -1, SIZEOF(wpipe));
+    if (pipe(rpipe) < 0 || pipe(wpipe) < 0) {
+       rc->errmsg = newvstrallocf(rc->errmsg, _("pipe: %s"), strerror(errno));
+       return (-1);
+    }
+
+    switch (rc->pid = fork()) {
+    case -1:
+       rc->errmsg = newvstrallocf(rc->errmsg, _("fork: %s"), strerror(errno));
+       aclose(rpipe[0]);
+       aclose(rpipe[1]);
+       aclose(wpipe[0]);
+       aclose(wpipe[1]);
+       return (-1);
+    case 0:
+       dup2(wpipe[0], 0);
+       dup2(rpipe[1], 1);
+       break;
+    default:
+       rc->read = rpipe[0];
+       aclose(rpipe[1]);
+       rc->write = wpipe[1];
+       aclose(wpipe[0]);
+       return (0);
+    }
+
+    safe_fd(-1, 0);
+
+    if(!xamandad_path || strlen(xamandad_path) <= 1) 
+       xamandad_path = vstralloc(amlibexecdir, "/", "amandad",
+                                versionsuffix(), NULL);
+
+#ifndef SINGLE_USERID
+    if (uid != 0)
+       setreuid(uid, uid);
+    if (gid != 0)
+       setregid(gid, gid);
+#endif
+
+    execlp(xamandad_path, xamandad_path,
+          "-auth=local", "amdump", "amindexd", "amidxtaped", (char *)NULL);
+    error(_("error: couldn't exec %s: %s"), xamandad_path, strerror(errno));
+
+    /* should never go here, shut up compiler warning */
+    return(-1);
+}
diff --git a/common-src/sockaddr-util.c b/common-src/sockaddr-util.c
new file mode 100644 (file)
index 0000000..ffc6ca2
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2005 Zmanda Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ *
+ * Author: Dustin J. Mitchell <dustin@zmanda.com>
+ */
+/*
+ * Utility routines for handling sockaddrs
+ */
+
+#include "sockaddr-util.h"
+
+void
+dump_sockaddr(
+    sockaddr_union *sa)
+{
+#ifdef WORKING_IPV6
+    char ipstr[INET6_ADDRSTRLEN];
+#else
+    char ipstr[INET_ADDRSTRLEN];
+#endif
+    int port;
+
+    port = SU_GET_PORT(sa);
+#ifdef WORKING_IPV6
+    if (SU_GET_FAMILY(sa) == AF_INET6) {
+       inet_ntop(AF_INET6, &sa->sin6.sin6_addr, ipstr, sizeof(ipstr));
+       dbprintf("(sockaddr_in6 *)%p = { %d, %d, %s }\n",
+                sa,
+                SU_GET_FAMILY(sa),
+                port,
+                ipstr);
+    } else
+#endif
+    {
+       inet_ntop(AF_INET, &sa->sin.sin_addr.s_addr, ipstr, sizeof(ipstr));
+       dbprintf("(sockaddr_in *)%p = { %d, %d, %s }\n",
+                sa,
+                SU_GET_FAMILY(sa),
+                port,
+                ipstr);
+    }
+}
+
+
+#ifdef WORKING_IPV6
+static char mystr_sockaddr[INET6_ADDRSTRLEN + 20];
+#else
+static char mystr_sockaddr[INET_ADDRSTRLEN + 20];
+#endif
+
+char *
+str_sockaddr(
+    sockaddr_union *sa)
+{
+#ifdef WORKING_IPV6
+    char ipstr[INET6_ADDRSTRLEN];
+#else
+    char ipstr[INET_ADDRSTRLEN];
+#endif
+    int port;
+
+    port = SU_GET_PORT(sa);
+#ifdef WORKING_IPV6
+    if ( SU_GET_FAMILY(sa) == AF_INET6) {
+       inet_ntop(AF_INET6, &sa->sin6.sin6_addr, ipstr, sizeof(ipstr));
+    } else
+#endif
+    {
+       inet_ntop(AF_INET, &sa->sin.sin_addr.s_addr, ipstr, sizeof(ipstr));
+    }
+    g_snprintf(mystr_sockaddr,sizeof(mystr_sockaddr),"%s.%d", ipstr, port);
+    mystr_sockaddr[sizeof(mystr_sockaddr)-1] = '\0';
+
+    return mystr_sockaddr;
+}
+
+/* Unmap a V4MAPPED IPv6 address into its equivalent IPv4 address.  The location
+ * TMP is used to store the rewritten address, if necessary.  Returns a pointer
+ * to the unmapped address.
+ */
+#if defined(WORKING_IPV6) && defined(IN6_IS_ADDR_V4MAPPED)
+static sockaddr_union *
+unmap_v4mapped(
+    sockaddr_union *sa,
+    sockaddr_union *tmp)
+{
+    if (SU_GET_FAMILY(sa) == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) {
+       SU_INIT(tmp, AF_INET);
+       SU_SET_PORT(tmp, SU_GET_PORT(sa));
+       /* extract the v4 address from byte 12 of the v6 address */
+       memcpy(&tmp->sin.sin_addr.s_addr,
+              &sa->sin6.sin6_addr.s6_addr[12],
+              sizeof(struct in_addr));
+       return tmp;
+    }
+
+    return sa;
+}
+#else
+/* nothing to do if no IPv6 */
+#define unmap_v4mapped(sa, tmp) ((void)tmp, sa)
+#endif
+
+int
+cmp_sockaddr(
+    sockaddr_union *ss1,
+    sockaddr_union *ss2,
+    int addr_only)
+{
+    sockaddr_union tmp1, tmp2;
+
+    /* if addresses are v4mapped, "unmap" them */
+    ss1 = unmap_v4mapped(ss1, &tmp1);
+    ss2 = unmap_v4mapped(ss2, &tmp2);
+
+    if (SU_GET_FAMILY(ss1) == SU_GET_FAMILY(ss2)) {
+        if (addr_only) {
+#ifdef WORKING_IPV6
+            if(SU_GET_FAMILY(ss1) == AF_INET6)
+                return memcmp(
+                    &ss1->sin6.sin6_addr,
+                    &ss2->sin6.sin6_addr,
+                    sizeof(ss1->sin6.sin6_addr));
+            else
+#endif
+                return memcmp(
+                    &ss1->sin.sin_addr,
+                    &ss2->sin.sin_addr,
+                    sizeof(ss1->sin.sin_addr));
+        } else {
+            return memcmp(ss1, ss2, SS_LEN(ss1));
+        }
+    } else {
+        /* compare families to give a total order */
+        if (SU_GET_FAMILY(ss1) < SU_GET_FAMILY(ss2))
+            return -1;
+        else
+            return 1;
+    }
+}
+
diff --git a/common-src/sockaddr-util.h b/common-src/sockaddr-util.h
new file mode 100644 (file)
index 0000000..977c4f9
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2005 Zmanda Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ *
+ * Author: Dustin J. Mitchell <dustin@zmanda.com>
+ */
+/*
+ * Utility routines for handling sockaddrs
+ */
+
+#ifndef SOCKADDR_UTIL_H
+#define        SOCKADDR_UTIL_H
+
+#include "amanda.h"
+
+/* Dump a sockaddr_union using dbprintf
+ *
+ * @param sa: the sockaddr to dump
+ */
+void   dump_sockaddr(sockaddr_union *  sa);
+
+/* Convert a sockaddr_union to a string.
+ *
+ * NOTE: this function is not threadsafe!
+ *
+ * @param sa: the sockaddr_union to dump
+ * @returns: pointer to statically allocated string
+ */
+char *  str_sockaddr(sockaddr_union *sa);
+
+/* Compare two sockaddr_union objects, optionally comparing
+ * only the address (and thus ignoring port, flow info, etc.).
+ *
+ * @param su1: one sockaddr_union to compare
+ * @param su2: the other sockaddr_union to compare
+ * @param addr_only: if true, ignore port, flow info, etc.
+ * @returns: -1, 0, or 1 for <, ==, >, respectively
+ */
+int     cmp_sockaddr(sockaddr_union *su1,
+                    sockaddr_union *su2,
+                    int addr_only);
+
+/* Copy a sockaddr object.
+ *
+ * @param dest: destination
+ * @param src: source
+ */
+#define copy_sockaddr(dest, src) memcpy((dest), (src), SS_LEN((src)))
+
+/* The "best" address family we support.
+ */
+/* AF_NATIVE */
+#ifdef WORKING_IPV6
+#define AF_NATIVE AF_INET6
+#else
+#define AF_NATIVE AF_INET
+#endif
+
+/* Get the family for a sockaddr_union.
+ *
+ * @param su: the sockaddr_union to examine
+ */
+#define SU_GET_FAMILY(su) ((su)->sa.sa_family)
+/* Calculate the length of the data in a sockaddr_union.
+ *
+ * @param su: the sockaddr_union to examine
+ * @returns: length of the data in the object
+ */
+/* SS_LEN(su) */
+#ifdef WORKING_IPV6
+# define SS_LEN(su) (SU_GET_FAMILY(su)==AF_INET6? sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in))
+#else
+# define SS_LEN(su) (sizeof(struct sockaddr_in))
+#endif
+
+/* Initialize a sockaddr_union to all zeroes (as directed by RFC),
+ * and set its address family as specified
+ *
+ * @param su: sockaddr_union object to initialize
+ * @param family: an AF_* constant
+ */
+/* SU_INIT(su, family) */
+#define SU_INIT(su, family) do { \
+    memset((su), 0, sizeof(*(su))); \
+    (su)->sa.sa_family = (family); \
+} while (0);
+
+/* set a sockaddr_union to the family-appropriate equivalent of
+ * INADDR_ANY -- a wildcard address and port.  Call SU_INIT(su)
+ * first to initialize the object and set the family.
+ *
+ * @param su: the sockaddr_union to set
+ */
+/* SU_SET_INADDR_ANY(su) */
+#ifdef WORKING_IPV6
+#define SU_SET_INADDR_ANY(su) do { \
+    switch (SU_GET_FAMILY(su)) { \
+        case AF_INET6: \
+            (su)->sin6.sin6_flowinfo = 0; \
+            (su)->sin6.sin6_addr = in6addr_any; \
+            break; \
+        case AF_INET: \
+            (su)->sin.sin_addr.s_addr = INADDR_ANY; \
+            break; \
+    } \
+} while (0);
+#else
+#define SU_SET_INADDR_ANY(su) do { \
+    (su)->sin.sin_addr.s_addr = INADDR_ANY; \
+} while (0);
+#endif
+
+/* Set the port in a sockaddr_union that already has an family
+ *
+ * @param su: the sockaddr_union to manipulate
+ * @param port: the port to insert (in host byte order)
+ */
+/* SU_SET_PORT(su, port) */
+#ifdef WORKING_IPV6
+#define SU_SET_PORT(su, port) \
+switch (SU_GET_FAMILY(su)) { \
+    case AF_INET: \
+        (su)->sin.sin_port = (in_port_t)htons((port)); \
+        break; \
+    case AF_INET6: \
+        (su)->sin6.sin6_port = (in_port_t)htons((port)); \
+        break; \
+    default: assert(0); \
+}
+#else
+#define SU_SET_PORT(su, port) \
+        (su)->sin.sin_port = (in_port_t)htons((port));
+#endif
+
+/* Get the port in a sockaddr_union object
+ *
+ * @param su: the sockaddr_union to manipulate
+ * @return: the port, in host byte horder
+ */
+/* SU_GET_PORT(su) */
+#ifdef WORKING_IPV6
+#define SU_GET_PORT(su) (ntohs(SU_GET_FAMILY(su) == AF_INET6? (su)->sin6.sin6_port:(su)->sin.sin_port))
+#else
+#define SU_GET_PORT(su) (ntohs((su)->sin.sin_port))
+#endif
+
+#endif /* SOCKADDR_UTIL_H */
diff --git a/common-src/svn-info.h b/common-src/svn-info.h
new file mode 100644 (file)
index 0000000..5357aaf
--- /dev/null
@@ -0,0 +1,2 @@
+#define BUILT_REV "1266"
+#define BUILT_BRANCH "amanda-260"
diff --git a/common-src/tapelist.h~HEAD b/common-src/tapelist.h~HEAD
new file mode 100644 (file)
index 0000000..e6b58e2
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1998 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+/*
+ * $Id: tapelist.h,v 1.2 2006/05/25 01:47:12 johnfranks Exp $
+ *
+ */
+
+#ifndef TAPELIST_H
+#define TAPELIST_H
+
+#include "amanda.h"
+
+/* XXX This looks like a lot of other things, apart from the string
+ * marshalling and unmarshalling.  Things like the EXTRACT_LIST in amrecover's
+ * innards are functionally similar, so there's probably a lot of opportunity
+ * to pare down extraneous code here by mushing things like that in.  Rainy
+ * day project, perhaps.
+ */
+
+typedef struct tapelist_s {
+    struct tapelist_s *next;
+    char *label;
+    int isafile; /* set to 1 and make *label the path to the file */
+    off_t *files;
+    int numfiles;
+} tapelist_t;
+
+int num_entries(tapelist_t *tapelist);
+tapelist_t *append_to_tapelist(tapelist_t *tapelist, char *label,
+                                       off_t file, int isafile);
+char *marshal_tapelist(tapelist_t *tapelist, int escape);
+tapelist_t *unmarshal_tapelist_str(char *tapelist_str);
+char *escape_label(char *label);
+char *unescape_label(char *label);
+void free_tapelist(tapelist_t *tapelist);
+void dump_tapelist(tapelist_t *);
+#endif /* !TAPELIST_H */
diff --git a/common-src/timestamp.c b/common-src/timestamp.c
new file mode 100644 (file)
index 0000000..dfeec75
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1999 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+
+#include "timestamp.h"
+#include "conffile.h"
+#include <glib.h>
+
+/*
+ * Construct a datestamp (YYYYMMDD) from a time_t.
+ */
+char * get_datestamp_from_time(time_t when) {
+    struct tm *tm;
+    
+    if(when == (time_t)0) {
+       when = time((time_t *)NULL);
+    }
+    
+    tm = localtime(&when);
+    return g_strdup_printf("%04d%02d%02d",
+                           tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
+}
+
+/*
+ * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t.
+ */
+char * get_timestamp_from_time(time_t when) {
+    struct tm *tm;
+
+    if(when == (time_t)0) {
+       when = time((time_t *)NULL);
+    } 
+
+    tm = localtime(&when);
+    return g_strdup_printf("%04d%02d%02d%02d%02d%02d",
+                           tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
+                           tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+char * get_proper_stamp_from_time(time_t when) {
+    if (getconf_boolean(CNF_USETIMESTAMPS)) {
+        return get_timestamp_from_time(when);
+    } else {
+        return get_datestamp_from_time(when);
+    }
+}
+
+time_state_t get_timestamp_state(char * timestamp) {
+    if (timestamp == NULL || *timestamp == '\0') {
+        return TIME_STATE_REPLACE;
+    } else if (strcmp(timestamp, "X") == 0) {
+        return TIME_STATE_UNDEF;
+    } else {
+        return TIME_STATE_SET;
+    }
+}
+
+char * get_undef_timestamp(void) {
+    return strdup("X");
+}
diff --git a/common-src/timestamp.h b/common-src/timestamp.h
new file mode 100644 (file)
index 0000000..81a3b9e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1999 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: the Amanda Development Team.  Its members are listed in a
+ * file named AUTHORS, in the root directory of this distribution.
+ */
+/*
+ * $Id$
+ *
+ * Date and time utility functions
+ */
+
+#ifndef TIMESTAMP_H
+#define TIMESTAMP_H
+
+#include "amanda.h"
+
+/* These functions do the opposite; they formats a time_t for
+   network or media storage. The return value is allocated with
+   malloc(). If time == 0, then these functions will use the current
+   time. */
+char * get_timestamp_from_time(time_t time);
+char * get_datestamp_from_time(time_t time);
+char * get_proper_stamp_from_time(time_t time);
+
+typedef enum {
+    TIME_STATE_REPLACE,
+    TIME_STATE_UNDEF,
+    TIME_STATE_SET
+} time_state_t;
+
+/* Returns the state of a timestamp. */
+time_state_t get_timestamp_state(char * timestamp);
+
+/* Returns a "X" timestamp. */
+char * get_undef_timestamp(void);
+
+#endif /* TIMESTAMP_H */
+
diff --git a/config/amanda/amplot.m4 b/config/amanda/amplot.m4
new file mode 100644 (file)
index 0000000..fba1884
--- /dev/null
@@ -0,0 +1,56 @@
+# OVERVIEW
+#
+#   'amplot' is largely pieced together by the instantiation phase of 
+#   configure; that is handled here.
+
+# SYNOPSIS
+#
+#   AMANDA_SETUP_AMPLOT
+#
+# DESCRIPTION
+#
+#   Check for the requirements for amplot, and set the Automake conditional
+#   WANT_AMPLOT appropriately.  If amplot is to be built, then also set up
+#   the required substitutions to build it correctly.
+#
+AC_DEFUN([AMANDA_SETUP_AMPLOT],
+[
+    AC_REQUIRE([AMANDA_PROG_GNUPLOT])
+    AC_REQUIRE([AMANDA_PROG_PCAT])
+    AC_REQUIRE([AMANDA_PROG_COMPRESS])
+    AC_REQUIRE([AMANDA_PROG_GZIP])
+    AC_REQUIRE([AC_PROG_AWK])
+
+    if test "x$GNUPLOT" != "x"; then
+       WANT_AMPLOT=true
+
+       # variable substitutions for amcat.awk
+       if test "$PCAT"; then
+           AMPLOT_CAT_PACK="if(o==\"z\")print \"$PCAT\"; else"
+       else
+           AMPLOT_CAT_PACK=
+       fi
+       if test "$COMPRESS"; then
+           AMPLOT_COMPRESS=$COMPRESS
+           AMPLOT_CAT_COMPRESS="if(o==\"Z\")print \"$COMPRESS -dc\"; else"
+       else
+           AMPLOT_CAT_COMPRESS=
+       fi
+       if test "$GZIP"; then
+           AMPLOT_COMPRESS=$GZIP
+           AMPLOT_CAT_GZIP="if(o==\"gz\")print \"$GZIP -dc\"; else"
+       else
+           AMPLOT_CAT_GZIP=
+       fi
+
+       AC_SUBST(AMPLOT_COMPRESS)
+       AC_SUBST(AMPLOT_CAT_GZIP)
+       AC_SUBST(AMPLOT_CAT_COMPRESS)
+       AC_SUBST(AMPLOT_CAT_PACK)
+    else
+       WANT_AMPLOT=false
+       AMANDA_MSG_WARN([Not building 'amplot', because gnuplot was not found])
+    fi
+
+    AM_CONDITIONAL(WANT_AMPLOT, test x"$WANT_AMPLOT" = x"true")
+])
diff --git a/config/amanda/bsd-security.m4 b/config/amanda/bsd-security.m4
new file mode 100644 (file)
index 0000000..a376707
--- /dev/null
@@ -0,0 +1,58 @@
+# SYNOPSIS
+#
+#   AMANDA_BSD_SECURITY
+#
+# OVERVIEW
+#
+#   Handle configuration for BSD security, implementing the 
+#   --without-bsd-security option.  Also supplies the --without-amandahosts
+#   option to use .rhosts instead of .amandahosts
+#
+#   Note that the defaults for *both* of these options are "yes", unlike
+#   the remainder of the security implementations.
+#
+#   Defines BSD_SECURITY, and sets AM_CONDITIONAL WANT_BSD_SECURITY,
+#   if the user has selected this mechanism.  Also defines USE_AMANDAHOSTS
+#   unless the user has specified --without-amandahosts.
+#
+AC_DEFUN([AMANDA_BSD_SECURITY],
+[
+    BSD_SECURITY="yes"
+    AC_ARG_WITH(bsd-security,
+        AS_HELP_STRING([--without-bsd-security],
+                [do not include BSD authentication]),
+        [
+            case "$withval" in
+                n | no) BSD_SECURITY=no ;;
+                y |  ye | yes) ;;
+                *) AC_MSG_ERROR([*** You must not supply an argument to --without-bsd-security.])
+                    ;;
+            esac
+        ],
+    )
+
+    USE_AMANDAHOSTS=yes
+    AC_ARG_WITH(amandahosts,
+        AS_HELP_STRING([ --without-amandahosts],
+            [use ".rhosts" instead of ".amandahosts"]),
+        [
+            case "$withval" in
+                n | no ) USE_AMANDAHOSTS="no" ;;
+                y |  ye | yes) : ;;
+                *) AC_MSG_ERROR([*** You must not supply an argument to --without-amandahosts option.])
+                  ;;
+            esac
+        ]
+    )
+
+    if test "x$BSD_SECURITY" = "xyes"; then
+        AC_DEFINE(BSD_SECURITY,1,
+            [Define to use BSD .rhosts/.amandahosts security. ])
+        if test "x$USE_AMANDAHOSTS" = "xyes"; then
+            AC_DEFINE(USE_AMANDAHOSTS,1,
+                [Define if you want to use the ".amandahosts" for BSD security. ])
+        fi
+    fi
+
+    AM_CONDITIONAL(WANT_BSD_SECURITY, test x"$BSD_SECURITY" = x"yes")
+])
diff --git a/config/amanda/bsdtcp-security.m4 b/config/amanda/bsdtcp-security.m4
new file mode 100644 (file)
index 0000000..044415b
--- /dev/null
@@ -0,0 +1,34 @@
+# SYNOPSIS
+#
+#   AMANDA_BSDTCP_SECURITY
+#
+# OVERVIEW
+#
+#   Handle configuration for BSDTCP security, implementing the 
+#   --with-bsdtcp-security option.
+#
+#   Defines BSDTCP_SECURITY, and sets AM_CONDITIONAL WANT_BSDTCP_SECURITY,
+#   if the user has selected this mechanism.
+#
+AC_DEFUN([AMANDA_BSDTCP_SECURITY],
+[
+    BSDTCP_SECURITY="no"
+    AC_ARG_WITH(bsdtcp-security,
+        AS_HELP_STRING([--with-bsdtcp-security],
+                [include BSDTCP authentication]),
+        [
+            case "$withval" in
+                n | no) : ;;
+                y |  ye | yes) BSDTCP_SECURITY=yes ;;
+                *) AC_MSG_ERROR([*** You must not supply an argument to --with-bsdtcp-security.])
+              ;;
+            esac
+        ],
+    )
+
+    if test "x$BSDTCP_SECURITY" = "xyes"; then
+        AC_DEFINE(BSDTCP_SECURITY,1,
+            [Define if BSDTCP transport should be enabled.])
+    fi
+    AM_CONDITIONAL(WANT_BSDTCP_SECURITY, test x"$BSDTCP_SECURITY" = x"yes")
+])
diff --git a/config/amanda/bsdudp-security.m4 b/config/amanda/bsdudp-security.m4
new file mode 100644 (file)
index 0000000..1422bb7
--- /dev/null
@@ -0,0 +1,34 @@
+# SYNOPSIS
+#
+#   AMANDA_BSDUDP_SECURITY
+#
+# OVERVIEW
+#
+#   Handle configuration for BSDUDP security, implementing the 
+#   --with-bsdudp-security option.
+#
+#   Defines BSDUDP_SECURITY, and sets AM_CONDITIONAL WANT_BSDUDP_SECURITY,
+#   if the user has selected this mechanism.
+#
+AC_DEFUN([AMANDA_BSDUDP_SECURITY],
+[
+    BSDUDP_SECURITY="no"
+    AC_ARG_WITH(bsdudp-security,
+        AS_HELP_STRING([--with-bsdudp-security],
+                [include BSDUDP authentication]),
+        [
+            case "$withval" in
+                n | no) : ;;
+                y |  ye | yes) BSDUDP_SECURITY=yes ;;
+                *) AC_MSG_ERROR([*** You must not supply an argument to --with-bsdudp-security.])
+              ;;
+            esac
+        ],
+    )
+
+    if test "x$BSDUDP_SECURITY" = "xyes"; then
+        AC_DEFINE(BSDUDP_SECURITY,1,
+            [Define if BSDUDP transport should be enabled.])
+    fi
+    AM_CONDITIONAL(WANT_BSDUDP_SECURITY, test x"$BSDUDP_SECURITY" = x"yes")
+])
diff --git a/config/amanda/changer.m4 b/config/amanda/changer.m4
new file mode 100644 (file)
index 0000000..23c3ae3
--- /dev/null
@@ -0,0 +1,274 @@
+# SYNOPSIS
+#
+#   AMANDA_SETUP_CHANGER
+#
+# OVERVIEW
+#
+#   Set up for changers.  This first checks the availability of several
+#   changer-related headers, then, based on those results, tries to 
+#   compile some test programs for each supported changer API.  It finishes
+#   by defining a series of AM_CONDITIONALS which are all used in
+#   changer-src/Makefile.am.
+#
+#   The macro also searches for chio, chs, mtx, and mcutil, which are used
+#   from various shell scripts in the changer-src/ directory.
+#
+AC_DEFUN([AMANDA_SETUP_CHANGER], [
+    AC_REQUIRE([AMANDA_PROG_CHIO])
+    AC_REQUIRE([AMANDA_PROG_CHS])
+    AC_REQUIRE([AMANDA_PROG_MTX])
+    AC_REQUIRE([AMANDA_PROG_MCUTIL])
+
+    AC_CHECK_HEADERS( \
+       camlib.h \
+       chio.h \
+       linux/chio.h \
+       scsi/sg.h \
+       scsi/scsi_ioctl.h \
+       sys/chio.h \
+       sys/dsreq.h \
+       sys/mtio.h \
+       sys/scarray.h \
+       sys/gscdds.h \
+       sys/scsi.h \
+       sys/scsiio.h \
+       sys/scsi/impl/uscsi.h \
+       sys/scsi/scsi/ioctl.h \
+       )
+
+    #
+    # chio support
+    #
+    if test x"$ac_cv_header_sys_scsi_h" = x"yes"; then
+       AC_CACHE_CHECK([for HP/UX-like scsi changer support],
+           amanda_cv_hpux_scsi_chio,
+           [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/scsi.h>
+    ]], [[
+           static struct element_addresses changer_info;
+           int i = SIOC_ELEMENT_ADDRESSES;
+           int j = SIOC_ELEMENT_STATUS;
+           int k = SIOC_MOVE_MEDIUM;
+    ]])],[amanda_cv_hpux_scsi_chio=yes],[amanda_cv_hpux_scsi_chio=no])])
+       if test x"$amanda_cv_hpux_scsi_chio" = x"yes"; then
+           WANT_SCSI_HPUX=yes
+           WANT_CHG_SCSI=yes
+       fi
+    fi
+
+    #
+    # Linux SCSI based on ioctl
+    #
+    if test x"$ac_cv_header_sys_mtio_h" = x"yes" &&
+       test x"$ac_cv_header_scsi_scsi_ioctl_h" = x"yes"; then 
+           AC_CACHE_CHECK([for Linux like scsi support (ioctl)],
+           amanda_cv_linux_scsi,
+           [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <scsi/scsi_ioctl.h>
+#include <sys/mtio.h>
+    ]], [[
+           int device;
+           char *Command;
+           ioctl(device, SCSI_IOCTL_SEND_COMMAND, Command);
+    ]])],[amanda_cv_linux_scsi=yes],[amanda_cv_linux_scsi=no])])
+    fi
+
+    #
+    # Linux SCSI based on sg
+    #
+    if test x"$ac_cv_header_sys_mtio_h" = x"yes" &&
+       test x"$ac_cv_header_scsi_sg_h" = x"yes"; then 
+           AC_CACHE_CHECK([for Linux like scsi support (sg)],
+           amanda_cv_linux_sg_scsi,
+           [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <scsi/sg.h>
+#include <sys/mtio.h>
+    ]], [[
+           int device;
+           struct sg_header *psg_header;
+           char *buffer;
+           write(device, buffer, 1);
+    ]])],[amanda_cv_linux_sg_scsi=yes],[amanda_cv_linux_sg_scsi=no])])
+    fi
+
+    if test x"$amanda_cv_linux_scsi" = x"yes" ||
+     test x"$amanda_cv_linux_sg_scsi" = x"yes";then
+           WANT_SCSI_LINUX=yes
+           WANT_CHG_SCSI=yes
+    fi
+
+    #
+    # HP-UX SCSI
+    #
+    if test x"$ac_cv_header_sys_mtio_h" = x"yes" &&
+       test x"$ac_cv_header_sys_scsi_h" = x"yes"; then 
+           AC_CACHE_CHECK([for HP-UX like scsi support],
+           amanda_cv_hpux_scsi,
+           [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/scsi.h>
+#include <sys/mtio.h>
+    ]], [[
+           int device;
+           char *Command;
+           ioctl(device, SIOC_IO, Command);
+    ]])],[amanda_cv_hpux_scsi=yes],[amanda_cv_hpux_scsi=no])])
+           if test x"$amanda_cv_hpux_scsi" = x"yes";then
+                   WANT_SCSI_HPUX_NEW=yes
+                   WANT_CHG_SCSI=yes
+                   WANT_CHG_SCSI_CHIO=yes
+           fi
+    fi
+
+    #
+    # IRIX SCSI
+    #
+    if test x"$ac_cv_header_sys_mtio_h" = x"yes" &&
+       test x"$ac_cv_header_sys_dsreq_h" = x"yes"; then 
+           AC_CACHE_CHECK([for Irix like scsi support],
+           amanda_cv_irix_scsi,
+           [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/dsreq.h>
+#include <sys/mtio.h>
+    ]], [[
+           int device=1;
+           char Command;
+           ioctl(device, DS_ENTER, &Command);
+    ]])],[amanda_cv_irix_scsi=yes],[amanda_cv_irix_scsi=no])])
+           if test x"$amanda_cv_irix_scsi" = x"yes";then
+                   WANT_SCSI_IRIX=yes
+                   WANT_CHG_SCSI=yes
+           fi
+    fi
+
+    #
+    # Solaris  SCSI
+    #
+    if test x"$ac_cv_header_sys_mtio_h" = x"yes" &&
+       test x"$ac_cv_header_sys_scsi_impl_uscsi_h" = x"yes"; then 
+           AC_CACHE_CHECK([for Solaris-like scsi support],
+           amanda_cv_solaris_scsi,
+           [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/scsi/impl/uscsi.h>
+#include <sys/mtio.h>
+    ]], [[
+           int device;
+           char *Command;
+           ioctl(device, USCSICMD, Command);
+    ]])],[amanda_cv_solaris_scsi=yes],[amanda_cv_solaris_scsi=no])])
+           if test x"$amanda_cv_solaris_scsi" = x"yes";then
+                   WANT_SCSI_SOLARIS=yes
+                   WANT_CHG_SCSI=yes
+           fi
+    fi
+
+    #
+    # AIX SCSI
+    #
+    if test x"$ac_cv_header_sys_tape_h" = x"yes" &&
+       test x"$ac_cv_header_sys_scarray_h" = x"yes" &&
+       test x"$ac_cv_header_sys_gscdds_h" = x"yes"; then 
+           AC_CACHE_CHECK([for AIX like scsi support],
+           amanda_cv_aix_scsi,
+           [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/scarray.h>
+#include <sys/tape.h>
+    ]], [[
+           int device;
+           char *Command;
+           ioctl(device, STIOCMD, Command);
+    ]])],[amanda_cv_aix_scsi=yes],[amanda_cv_aix_scsi=no])])
+           if test x"$amanda_cv_aix_scsi" = x"yes";then
+                   WANT_SCSI_AIX=yes
+                   WANT_CHG_SCSI=yes
+           fi
+    fi
+    #
+    # BSD CAM SCSI
+    #
+    if test x"$ac_cv_header_cam_cam_h" = x"yes";then
+           AC_CACHE_CHECK([for CAM like scsi support],
+           amanda_cv_cam_scsi,
+           [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+# include <fcntl.h>
+# include <cam/cam.h>
+# include <cam/cam_ccb.h>
+# include <cam/scsi/scsi_message.h>
+# include <cam/scsi/scsi_pass.h>
+# include <camlib.h>
+    ]], [[
+           struct cam_device *curdev;
+
+           curdev = cam_open_pass("", O_RDWR, NULL);
+    ]])],[amanda_cv_cam_scsi=yes],[amanda_cv_cam_scsi=no])])
+           if test x"$amanda_cv_cam_scsi" = x"yes";then
+                   WANT_SCSI_CAM=yes
+                   WANT_CHG_SCSI=yes
+                   AC_CHECK_LIB(cam,main)
+           fi
+    fi
+
+
+    #
+    # BSD SCSI
+    #
+    if test x"$ac_cv_header_sys_mtio_h" = x"yes" &&
+       test x"$ac_cv_header_sys_scsiio_h" = x"yes"; then
+       AC_CACHE_CHECK([for BSD like scsi support],
+       amanda_cv_bsd_scsi,
+       [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/scsiio.h>
+#include <sys/mtio.h>
+    ]], [[
+       int device=1;
+       char Command;
+       ioctl(device, SCIOCCOMMAND, &Command);
+    ]])],[amanda_cv_bsd_scsi=yes],[amanda_cv_bsd_scsi=no])])
+       if test x"$amanda_cv_bsd_scsi" = x"yes";then
+          WANT_SCSI_BSD=yes
+          WANT_CHG_SCSI=yes
+       fi
+    fi
+
+    # Do not build chg-scsi-chio if we cannot find the needed support
+    # include files for the SCSI interfaces
+    # chio.h and sys/chio.h are chio based systems
+    if test x"$ac_cv_header_chio_h" = x"yes" ||
+       test x"$ac_cv_header_linux_chio_h" = x"yes" ||
+       test x"$ac_cv_header_sys_chio_h" = x"yes"; then
+       # chg-scsi does not support FreeBSD 3.0's chio.h; it became backward
+       # incompatible with the introduction of camlib.h
+       if test x"$ac_cv_header_camlib_h" != x"yes"; then
+        WANT_SCSI_CHIO=yes
+        # prefer to use chg-scsi, unless we already have a driver for that,
+        # in which case set it up as chg-scsi-chio.
+        if test x"$WANT_CHG_SCSI" = x"no"; then
+          WANT_CHG_SCSI=yes
+        else
+          WANT_CHG_SCSI_CHIO=yes
+        fi
+       fi
+    fi
+
+    # scsi-based implementations
+    AM_CONDITIONAL(WANT_CHG_SCSI, test x"$WANT_CHG_SCSI" = x"yes")
+    AM_CONDITIONAL(WANT_SCSI_LINUX, test x"$WANT_SCSI_LINUX" = x"yes")
+    AM_CONDITIONAL(WANT_SCSI_HPUX_NEW, test x"$WANT_SCSI_HPUX_NEW" = x"yes")
+    AM_CONDITIONAL(WANT_SCSI_IRIX, test x"$WANT_SCSI_IRIX" = x"yes")
+    AM_CONDITIONAL(WANT_SCSI_SOLARIS, test x"$WANT_SCSI_SOLARIS" = x"yes")
+    AM_CONDITIONAL(WANT_SCSI_AIX, test x"$WANT_SCSI_AIX" = x"yes")
+    AM_CONDITIONAL(WANT_SCSI_CAM, test x"$WANT_SCSI_CAM" = x"yes")
+    AM_CONDITIONAL(WANT_SCSI_BSD, test x"$WANT_SCSI_BSD" = x"yes")
+
+    # scsi-chio-based implementations
+    AM_CONDITIONAL(WANT_CHG_SCSI_CHIO, test x"$WANT_CHG_SCSI_CHIO" = x"yes")
+    AM_CONDITIONAL(WANT_SCSI_HPUX, test x"$WANT_SCSI_HPUX" = x"yes")
+    AM_CONDITIONAL(WANT_SCSI_CHIO, test x"$WANT_SCSI_CHIO" = x"yes")
+])
diff --git a/config/amanda/components.m4 b/config/amanda/components.m4
new file mode 100644 (file)
index 0000000..8c7b902
--- /dev/null
@@ -0,0 +1,177 @@
+# SYNOPSIS
+#
+#   AMANDA_CHECK_COMPONENTS
+#
+# OVERVIEW
+#
+#   Defines --without-client, --without-server, --without-restore, and 
+#   --without-amrecover, and checks the results.
+#
+#   Sets the AM_CONDITIONALs WANT_CLIENT, WANT_SERVER, WANT_RESTORE, 
+#   and WANT_RECOVER.
+#   
+#   AM_CONDITIONAL WANT_TAPE is set if either server or restore support is
+#   being built.
+#
+AC_DEFUN([AMANDA_CHECK_COMPONENTS], [
+    AC_REQUIRE([AMANDA_WITHOUT_SERVER])
+    AC_REQUIRE([AMANDA_WITHOUT_CLIENT])
+    AC_REQUIRE([AMANDA_WITHOUT_RESTORE])
+    AC_REQUIRE([AMANDA_WITHOUT_AMRECOVER])
+    AC_REQUIRE([AMANDA_WITH_CLIENT_ONLY]) dnl deprecated
+    AC_REQUIRE([AMANDA_WITH_SERVER_ONLY]) dnl deprecated
+
+    # detect invalid combinations of components
+    if ! ${WANT_SERVER-true} && ${WANT_RESTORE-true}; then
+        AC_MSG_ERROR([--without-server requires --without-restore])
+    fi
+    if ! ${WANT_CLIENT-true} && ${WANT_RECOVER-true}; then
+        AC_MSG_ERROR([--without-client requires --without-amrecover])
+    fi
+
+    AM_CONDITIONAL(WANT_CLIENT, $WANT_CLIENT)
+    AM_CONDITIONAL(WANT_RESTORE, $WANT_RESTORE)
+    AM_CONDITIONAL(WANT_SERVER, $WANT_SERVER)
+    AM_CONDITIONAL(WANT_RECOVER, $WANT_RECOVER)
+
+    AM_CONDITIONAL(WANT_TAPE, $WANT_SERVER || $WANT_RESTORE)
+])
+
+
+# SYNOPSIS
+#
+#   AMANDA_WITHOUT_SERVER
+#
+# OVERVIEW
+#
+#   Add option --without-server, and set WANT_SERVER to true or false, 
+#   accordingly.
+#
+AC_DEFUN([AMANDA_WITHOUT_SERVER], [
+    WANT_SERVER=true
+    AC_ARG_WITH(server,
+       AS_HELP_STRING([--without-server], [do not build server stuff (set --without-restore)]), [
+           case "$withval" in
+           y | ye | yes) WANT_SERVER=true;;
+           n | no) WANT_SERVER=false;;
+           *) AC_MSG_ERROR([You must not supply an argument to the --without-server option.]) ;;
+           esac
+    ])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITHOUT_CLIENT
+#
+# OVERVIEW
+#
+#   Add option --without-client, and set WANT_CLIENT to true or false, 
+#   accordingly.
+#
+AC_DEFUN([AMANDA_WITHOUT_CLIENT], [
+    WANT_CLIENT=true
+    AC_ARG_WITH(client,
+       AS_HELP_STRING([--without-client], [do not build client stuff]), [
+           case "$withval" in
+           y | ye | yes) WANT_CLIENT=true;;
+           n | no) WANT_CLIENT=false;;
+           *) AC_MSG_ERROR([You must not supply an argument to the --without-client option.]) ;;
+           esac
+    ])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITHOUT_RESTORE
+#
+# OVERVIEW
+#
+#   Add option --without-restore, and set WANT_RESTORE to true or false, 
+#   accordingly.
+#
+AC_DEFUN([AMANDA_WITHOUT_RESTORE], [
+    AC_REQUIRE([AMANDA_WITHOUT_SERVER])
+    WANT_RESTORE=${WANT_SERVER-true}
+    AC_ARG_WITH(restore,
+       AS_HELP_STRING([--without-restore], [do not build amrestore nor amidxtaped]), [
+           case "$withval" in
+           y | ye | yes) WANT_RESTORE=true;;
+           n | no) WANT_RESTORE=false;;
+           *) AC_MSG_ERROR([You must not supply an argument to --with-restore option.]) ;;
+           esac
+    ])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITHOUT_AMRECOVER
+#
+# OVERVIEW
+#
+#   Add option --without-amrecover, and set WANT_RECOVER (not WANT_AMRECOVER) to
+#   true or false, accordingly.
+#
+AC_DEFUN([AMANDA_WITHOUT_AMRECOVER], [
+    AC_REQUIRE([AMANDA_WITHOUT_CLIENT])
+    WANT_RECOVER=${WANT_CLIENT-true}
+    AC_ARG_WITH(amrecover,
+       AS_HELP_STRING([--without-amrecover],
+                      [do not build amrecover]), [
+           case "$withval" in
+           y | ye | yes) WANT_RECOVER=false;;
+           n | no) WANT_RECOVER=false;;
+           *) AC_MSG_ERROR([You must not supply an argument to --with-amrecover option.]) ;;
+           esac
+       ])
+])
+
+## deprecated --with-* options
+
+AC_DEFUN([AMANDA_WITH_CLIENT_ONLY], [
+    AC_ARG_WITH(client-only,
+       AS_HELP_STRING([--with-client-only], [deprecated: use --without-server]),
+       [   AC_MSG_ERROR([--with-client-only is deprecated, use --without-server instead.])
+       ])
+],)
+
+AC_DEFUN([AMANDA_WITH_SERVER_ONLY], [
+    AC_ARG_WITH(server-only,
+       AS_HELP_STRING([--with-server-only], [deprecated: use --without-client]),
+       [   AC_MSG_ERROR([--with-server-only is deprecated, use --without-client instead.])
+       ],)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_SHOW_COMPONENTS_SUMMARY
+#
+# OVERVIEW
+#
+#   Show a summary of the settings from this file.
+#
+AC_DEFUN([AMANDA_SHOW_COMPONENTS_SUMMARY],
+[
+    components=''
+    if $WANT_SERVER; then
+       components="$components server";
+    else 
+       components="$components (no server)";
+    fi
+    if $WANT_RESTORE; then
+       components="$components restore";
+    else 
+       components="$components (no restore)";
+    fi
+    if $WANT_CLIENT; then
+       components="$components client";
+    else 
+       components="$components (no client)";
+    fi
+    if $WANT_RECOVER; then
+       components="$components amrecover";
+    else 
+       components="$components (no amrecover)";
+    fi
+
+    echo "Amanda Components: $components"
+])
diff --git a/config/amanda/compress.m4 b/config/amanda/compress.m4
new file mode 100644 (file)
index 0000000..1fb47ec
--- /dev/null
@@ -0,0 +1,71 @@
+# SYNOPSIS
+#
+#   AMANDA_CHECK_COMPRESSION
+#
+# OVERVIEW
+#
+#   Find a suitable compression program and define the following:
+#
+#    - COMPRESS_PATH
+#    - COMPRESS_SUFFIX
+#    - COMPRESS_FAST_OPT
+#    - COMPRESS_BEST_OPT
+#    - UNCOMPRESS_PATH
+#    - UNCOMPRESS_OPT
+#    - HAVE_GZIP
+#
+AC_DEFUN([AMANDA_CHECK_COMPRESSION],
+[
+    AC_REQUIRE([AMANDA_PROG_CAT])
+    AC_REQUIRE([AMANDA_PROG_COMPRESS])
+    AC_REQUIRE([AMANDA_PROG_GZIP])
+
+    if test "$GZIP"; then
+       AC_DEFINE(HAVE_GZIP,1,
+           [Define if Amanda is using the gzip program. ])
+       COMPRESS_PATH="$GZIP"
+       COMPRESS_SUFFIX=".gz"
+       COMPRESS_FAST_OPT="--fast"
+       COMPRESS_BEST_OPT="--best"
+       UNCOMPRESS_PATH="$GZIP"
+       UNCOMPRESS_OPT="-dc"
+    else
+       if test "$COMPRESS"; then
+           COMPRESS_PATH="$COMPRESS"
+           COMPRESS_SUFFIX=".Z"
+           COMPRESS_FAST_OPT="-f"
+           COMPRESS_BEST_OPT="-f"
+           UNCOMPRESS_PATH="$COMPRESS"
+           UNCOMPRESS_OPT="-dc"
+       else
+           # If we have to use cat, we don't define COMPRESS_FAST_OPT,
+           # COMPRESS_BEST_OPT, or UNCOMPRESS_OPT as "" since cat will look
+           # look for a file by the name of "".
+           # XXX is the above true? --dustin
+
+           AMANDA_MSG_WARN([Cannot find either gzip or compress.  Using cat.])
+           COMPRESS_PATH="$CAT"
+           COMPRESS_SUFFIX=""
+           COMPRESS_FAST_OPT=""
+           COMPRESS_BEST_OPT=""
+           UNCOMPRESS_PATH="$CAT"
+           UNCOMPRESS_OPT=""
+       fi
+    fi
+
+    AC_DEFINE_UNQUOTED(COMPRESS_PATH,"$COMPRESS_PATH",
+       [Define to the exact path to the gzip or the compress program. ])
+    AC_DEFINE_UNQUOTED(COMPRESS_SUFFIX,"$COMPRESS_SUFFIX",
+       [Define to the suffix for the COMPRESS_PATH compression program. ])
+    AC_DEFINE_UNQUOTED(COMPRESS_FAST_OPT,"$COMPRESS_FAST_OPT",
+       [Define as the command line option for fast compression. ])
+    AC_DEFINE_UNQUOTED(COMPRESS_BEST_OPT,"$COMPRESS_BEST_OPT",
+       [Define as the command line option for best compression. ])
+    AC_DEFINE_UNQUOTED(UNCOMPRESS_PATH,"$UNCOMPRESS_PATH",
+       [Define as the exact path to the gzip or compress command. ])
+    AC_DEFINE_UNQUOTED(UNCOMPRESS_OPT,"$UNCOMPRESS_OPT",
+       [Define as any optional arguments to get UNCOMPRESS_PATH to uncompress. ])
+
+    # Empty GZIP so that make dist works.
+    GZIP=
+])
diff --git a/config/amanda/config.m4 b/config/amanda/config.m4
new file mode 100644 (file)
index 0000000..fedf4bb
--- /dev/null
@@ -0,0 +1,58 @@
+# SYNOPSIS
+#
+#   AMANDA_CONFIG_LCOAL
+#
+# OVERVIEW
+#
+#   Invoke ./config.local, if it exists
+#
+AC_DEFUN([AMANDA_CONFIG_LOCAL],
+[
+    if test -f config.local; then
+       echo "running local script ./config.local"
+       . ./config.local
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_GET_SVN_INFO
+#
+# OVERVIEW
+#
+#   If the build is in a Subversion working copy, and if an svn client
+#   is available, then update common-src/svn-info.h to reflect the current
+#   revision and branch.
+#
+#   If these things are not available, then the file is not updated, and
+#   any previous contents are used.  If the file does not exist, it is
+#   created.
+#
+AC_DEFUN([AMANDA_GET_SVN_INFO],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_REQUIRE([AMANDA_PROG_GREP])
+
+    AC_PATH_PROG(SVN, svn,, $LOCSYSPATH)
+    AC_MSG_CHECKING([Subversion revision information])
+    if test -d $srcdir/.svn && test -n "$SVN" && (cd $srcdir > /dev/null ; $SVN info . ) > conftemp.svn; then
+       rev=`$GREP Revision: conftemp.svn|cut -d: -f 2|cut -c2-`
+       url=`$GREP URL: conftemp.svn|cut -d: -f 2-|cut -c2-`
+       ( echo '#define BUILT_REV "'$rev'"'
+         echo '#define BUILT_BRANCH "'`basename "$url"`'"'
+       ) > common-src/svn-info.h
+
+       AC_MSG_RESULT([updated])
+    else
+       # Makefiles will be upset if the file doesn't exist, so double-check
+       if test -f common-src/svn-info.h; then
+           : # all good
+           AC_MSG_RESULT([not changed])
+       else
+           echo '/* no information available */' > common-src/svn-info.h
+           AC_MSG_RESULT([not available])
+       fi
+    fi
+
+    rm -f conftemp.svn
+])
diff --git a/config/amanda/debugging.m4 b/config/amanda/debugging.m4
new file mode 100644 (file)
index 0000000..4a499dc
--- /dev/null
@@ -0,0 +1,148 @@
+# SYNOPSIS
+#
+#   AMANDA_WITH_ASSERTIONS
+#
+# OVERVIEW
+#
+#   Handles the --with-assertions flag.  Defines ASSERTIONS if the flag is given.
+#
+AC_DEFUN([AMANDA_WITH_ASSERTIONS],
+[
+    AC_ARG_WITH(assertions,
+        AS_HELP_STRING([--with-assertions],
+            [compile assertions into code]),
+        [
+            case "$withval" in
+                n | no) : ;;
+                y |  ye | yes)
+                    AC_DEFINE(ASSERTIONS,1,
+                        [Define if you want assertion checking. ])
+                  ;;
+                *) AC_MSG_ERROR([*** You must not supply an argument to --with-assertions option.])
+                  ;;
+            esac
+        ]
+    )
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_DEBUGGING
+#
+# OVERVIEW
+#
+#   Handles the --with[out]-debugging flag.  If debugging is not disabled, then define
+#   DEBUG_CODE, and define and substitute AMANDA_DBGDIR to either the location the
+#   user gave, or AMANDA_TMPDIR.
+#
+AC_DEFUN([AMANDA_WITH_DEBUGGING],
+[
+    AC_REQUIRE([AMANDA_WITH_TMPDIR])
+    AC_ARG_WITH(debugging,
+        AS_HELP_STRING([--with-debugging=DIR]
+            [put debug logs in DIR (default same as --with-tmpdir)]), 
+        [ debugging="$withval" ],
+       [ debugging="yes" ]
+    )
+
+    case "$debugging" in
+        n | no) AC_MSG_ERROR([Amanda no longer supports building with debugging disabled]);;
+        y | ye | yes) AMANDA_DBGDIR="$AMANDA_TMPDIR";;
+        *) AMANDA_DBGDIR="$debugging";;
+    esac
+
+    # evaluate any extra variables in the directory
+    AC_DEFINE_DIR([AMANDA_DBGDIR], [AMANDA_DBGDIR],
+       [Location of Amanda directories and files. ])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_GLIBC_BACKTRACE
+#
+# OVERVIEW
+#
+#   Check for glibc's backtrace support, and define HAVE_GLIBC_BACKTRACE if it is present.
+AC_DEFUN([AMANDA_GLIBC_BACKTRACE],
+[
+    AC_CHECK_HEADER([execinfo.h], [
+       AC_CHECK_FUNC([backtrace_symbols_fd], [
+           AC_DEFINE(HAVE_GLIBC_BACKTRACE, 1,
+               [Define this if glibc's backtrace functionality (execinfo.h) is present])
+       ])
+    ])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_DEBUG_DAYS
+#
+# OVERVIEW
+#
+#   Handles the --with-debug-days flag.  Defines and substitutes AMANDA_DEBUG_DAYS.
+#
+AC_DEFUN([AMANDA_WITH_DEBUG_DAYS],
+[
+    AC_ARG_WITH(debug_days,
+        AS_HELP_STRING([--with-debug-days=NN],
+            [number of days to keep debugging files (default: 4)]),
+        [
+            debug_days="$withval"
+        ], [
+            debug_days="yes"
+        ]
+    )
+    case "$debug_days" in
+        n | no) 
+            AMANDA_DEBUG_DAYS=0 ;;
+        y |  ye | yes) 
+            AMANDA_DEBUG_DAYS=4 ;;
+        [[0-9]] | [[0-9]][[0-9]] | [[0-9]][[0-9]][[0-9]]) 
+            AMANDA_DEBUG_DAYS="$debug_days" ;;
+        *) AC_MSG_ERROR([*** --with-debug-days value not numeric or out of range.])
+          ;;
+    esac
+    AC_DEFINE_UNQUOTED(AMANDA_DEBUG_DAYS,$AMANDA_DEBUG_DAYS,
+        [Number of days to keep debugging files. ])
+    AC_SUBST(AMANDA_DEBUG_DAYS)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_TESTING
+#
+# OVERVIEW
+#
+#   Handles the --with-testing flag.  Defines and substitutes SERVICE_SUFFIX, and
+#   defines AMANDA_SERVICE_NAME and KAMANDA_SERVICE_NAME.
+#
+AC_DEFUN([AMANDA_WITH_TESTING],
+[
+    AC_ARG_WITH(testing,
+        AS_HELP_STRING([--with-testing@<:@=SUFFIX@:>@],
+            [use alternate service names with suffix (default 'test')]),
+        [
+            TESTING="$withval"
+        ], [
+            TESTING="no"
+        ]
+    )
+    case "$TESTING" in
+        n | no) SERVICE_SUFFIX="";;
+        y |  ye | yes) SERVICE_SUFFIX="-test";;
+        *) SERVICE_SUFFIX="-$TESTING";;
+    esac
+
+    AMANDA_SERVICE_NAME="amanda$SERVICE_SUFFIX"
+    KAMANDA_SERVICE_NAME="kamanda$SERVICE_SUFFIX"
+
+    AC_SUBST(SERVICE_SUFFIX)
+    AC_DEFINE_UNQUOTED(SERVICE_SUFFIX, "$SERVICE_SUFFIX",
+        [A suffix that will be appended to service names.
+     * Useful for testing in parallel with a working version. ])
+    AC_DEFINE_UNQUOTED(AMANDA_SERVICE_NAME,  "$AMANDA_SERVICE_NAME", 
+        [The name for the Amanda service. ])
+    AC_DEFINE_UNQUOTED(KAMANDA_SERVICE_NAME, "$KAMANDA_SERVICE_NAME", 
+        [The name for the Kerberized Amanda service. ])
+])
+
diff --git a/config/amanda/defaults.m4 b/config/amanda/defaults.m4
new file mode 100644 (file)
index 0000000..a28931b
--- /dev/null
@@ -0,0 +1,138 @@
+# SYNOPSIS
+#
+#   Get default settings for various configuration and command-line options:
+#      --with-index-server
+#          define and substitute DEFAULT_SERVER
+#      --with-config
+#          define and substitute DEFAULT_CONFIG
+#      --with-tape-server
+#          define and substitute DEFAULT_TAPE_SERVER
+#      --with-tape-device
+#          define and substitute DEFAULT_TAPE_DEVICE; substitue EXAMPLE_TAPEDEV
+#      --with-changer-device
+#          define and substitute DEFAULT_CHANGER_DEVICE
+#      --with-amandates
+#          define and substitute DEFAULT_AMANDATES_FILE
+#
+AC_DEFUN([AMANDA_SETUP_DEFAULTS],
+[
+    AC_ARG_WITH(index-server,
+       AS_HELP_STRING([--with-index-server=HOST],
+           [default amanda index server (default: `uname -n`)]),
+       [
+           case "$withval" in
+           "" | y | ye | yes | n | no)
+               AC_MSG_ERROR([*** You must supply an argument to the --with-index-server option.])
+             ;;
+           *) DEFAULT_SERVER="$withval"
+             ;;
+           esac
+       ],
+       : ${DEFAULT_SERVER=`uname -n`}
+    )
+    AC_DEFINE_UNQUOTED(DEFAULT_SERVER,"$DEFAULT_SERVER",
+       [This is the default Amanda index server.])
+    AC_SUBST(DEFAULT_SERVER)
+
+    AC_ARG_WITH(config,
+       AS_HELP_STRING([--with-config=CONFIG],
+           [default amanda configuration (default: DailySet1)]),
+       [
+           case "$withval" in
+           "" | y | ye | yes | n | no)
+               AC_MSG_ERROR([*** You must supply an argument to the --with-config option.])
+             ;;
+           *) DEFAULT_CONFIG="$withval"
+             ;;
+           esac
+       ],
+       : ${DEFAULT_CONFIG=DailySet1}
+    )
+    AC_DEFINE_UNQUOTED(DEFAULT_CONFIG,"$DEFAULT_CONFIG",
+       [This is the default Amanda configuration.])
+    AC_SUBST(DEFAULT_CONFIG)
+
+    AC_ARG_WITH(tape-server,
+       AS_HELP_STRING([--with-tape-server=HOST],
+           [default tape server for restore (default: same as index-server)]),
+       [
+           case "$withval" in
+           "" | y | ye | yes | n | no)
+               AC_MSG_ERROR([*** You must supply an argument to the --with-tape-server option.])
+             ;;
+           *) DEFAULT_TAPE_SERVER="$withval"
+             ;;
+           esac
+       ],
+       : ${DEFAULT_TAPE_SERVER=$DEFAULT_SERVER}
+    )
+    AC_DEFINE_UNQUOTED(DEFAULT_TAPE_SERVER,"$DEFAULT_TAPE_SERVER",
+       [This is the default restoring Amanda tape server. ])
+    AC_SUBST(DEFAULT_TAPE_SERVER)
+
+    AC_ARG_WITH(tape-device,
+       AS_HELP_STRING([--with-tape-device=DEVICE],
+           [default device on restore tape server]),
+       [
+           case "$withval" in
+           "" | y | ye | yes | n | no)
+               AC_MSG_ERROR([*** You must supply an argument to the --with-tape-device option.])
+             ;;
+           *) DEFAULT_TAPE_DEVICE="$withval"
+             ;;
+           esac
+       ]
+    )
+
+    AC_DEFINE_UNQUOTED(DEFAULT_TAPE_DEVICE,"$DEFAULT_TAPE_DEVICE",
+       [This is the default no-rewinding tape device. ])
+    AC_SUBST(DEFAULT_TAPE_DEVICE)
+
+    if test "${DEFAULT_TAPE_DEVICE+set}" = "set"; then
+       EXAMPLE_TAPEDEV="$DEFAULT_TAPE_DEVICE"
+    else
+       EXAMPLE_TAPEDEV="tape:/dev/YOUR-TAPE-DEVICE-HERE"
+    fi
+    AC_SUBST(EXAMPLE_TAPEDEV)
+
+    AC_ARG_WITH(changer-device,
+       AS_HELP_STRING([--with-changer-device=DEV],
+           [default tape changer device (default: /dev/ch0)]),
+       [
+           case "$withval" in
+           "" | y | ye | yes | n | no)
+               AC_MSG_ERROR([*** You must supply an argument to the --with-changer-device option.])
+             ;;
+           *) DEFAULT_CHANGER_DEVICE="$withval"
+             ;;
+           esac
+       ]
+    )
+
+    if test -z "$DEFAULT_CHANGER_DEVICE"; then
+       DEFAULT_CHANGER_DEVICE=/dev/null
+       if test -f /dev/ch0; then
+           DEFAULT_CHANGER_DEVICE=/dev/ch0
+       fi
+    fi
+
+    AC_DEFINE_UNQUOTED(DEFAULT_CHANGER_DEVICE,"$DEFAULT_CHANGER_DEVICE",
+       [This is the default changer device. ])
+    AC_SUBST(DEFAULT_CHANGER_DEVICE)
+
+    AC_ARG_WITH(amandates,
+        AS_HELP_STRING([--with-amandates],
+            [default location for 'amandates' (default: $localstatedir/amanda/amandates)]),
+           [
+           case "$withval" in
+               n | no) AC_MSG_ERROR([*** --without-amandates is not allowed.]);;
+               y |  ye | yes) amandates='$localstatedir/amanda/amandates' ;;
+               *) amandates="$withval";;
+           esac
+           ],
+           [amandates='$localstatedir/amanda/amandates']
+    )
+
+    AC_DEFINE_DIR([DEFAULT_AMANDATES_FILE], [amandates],
+        [Default location for 'amandates'])
+])
diff --git a/config/amanda/devprefix.m4 b/config/amanda/devprefix.m4
new file mode 100644 (file)
index 0000000..6231dbf
--- /dev/null
@@ -0,0 +1,115 @@
+# SYNOPSIS
+#
+#   AMANDA_CHECK_DEVICE_PREFIXES
+#
+# DESCRIPTION
+#
+#   Check for the prefixes used for particular devices.
+#
+#   Defines DEV_PREFIX and RDEV_PREFIX to the appropriate prefixes.
+#
+AC_DEFUN([AMANDA_CHECK_DEVICE_PREFIXES],
+[
+    # disk device prefixes
+    AC_MSG_CHECKING(disk device prefixes)
+
+    # Use df to find the mount point for the root filesystem.  Use
+    # the positional parameters to find the particular line from df
+    # that contains the root paritition.  We put it in a subshell so
+    # that the original positional parameters are not messed with.
+    dfline=`(
+       df / | while read line; do
+           set -- $line
+           dnl @S|@ means $ to m4
+           while test @S|@# -gt 0; do
+               if test "x@S|@1" = "x/"; then
+                   echo $line
+                   break 2
+               fi
+               shift
+           done
+       done
+    ) | sed 's/(//' | sed 's/)//' `
+
+    # Search for the mount point by using expr to find the parameter
+    # with dev in it.
+    mount=`(
+       set -- $dfline
+       dnl @S|@ means $ to m4
+       while test @S|@# -gt 0; do
+           if expr "@S|@1" : '.*dev' >/dev/null 2>&1; then
+               echo @S|@1
+               break
+           fi
+           shift
+       done
+    )`
+
+    # get any system-specific configuration information
+    case "$target" in
+       *-hp-*)
+           CLIENT_SCRIPTS_OPT=amhpfixdevs
+           case $mount in
+               /dev/vg*)
+                   AMANDA_MSG_WARN([Run amhpfixdevs on HP-UX systems using /dev/vg??.])
+                   ;;
+           esac
+           ;;
+       *-sni-sysv4)
+           DEV_PREFIX=/dev/dsk/
+           RDEV_PREFIX=/dev/rdsk/
+           CLIENT_SCRIPTS_OPT=amsinixfixdevs
+           if ! test -d /dev/dsk; then
+               AMANDA_MSG_WARN([Run amsinixfixdevs on Sinix systems using VxFS.])
+           fi
+           ;;
+       *-sco3.2v4*)
+           DEV_PREFIX=/dev/
+           RDEV_PREFIX=/dev/
+           ;;
+       *)
+           CLIENT_SCRIPTS_OPT=
+           ;;
+    esac
+
+    if test "$DEV_PREFIX" && test "$RDEV_PREFIX"; then
+       AC_MSG_RESULT((predefined) $DEV_PREFIX - $RDEV_PREFIX)
+    else
+       if test -d /dev/dsk; then
+           DEV_PREFIX=/dev/dsk/
+           if test -d /dev/rdsk; then
+               RDEV_PREFIX=/dev/rdsk/
+           else
+               RDEV_PREFIX=/dev/dsk/
+           fi
+       elif test -d /dev; then
+           DEV_PREFIX=/dev/
+
+           # Some systems, notably Linux, do not have raw disk devices
+           # names.  Check this by trying to see if a raw disk device name
+           # exists using the normal raw device path prepended to the
+           # mount point of the root filesystem.
+           if test "$mount"; then
+               dev_name="/dev/r`basename $mount`"
+               if test -b $dev_name -o -c $dev_name; then
+                   RDEV_PREFIX=/dev/r
+               else
+                   RDEV_PREFIX=/dev/
+               fi
+           else
+               RDEV_PREFIX=/dev/r
+           fi
+       else
+           # just fake it..
+           DEV_PREFIX=/
+           RDEV_PREFIX=/
+       fi
+       AC_MSG_RESULT($DEV_PREFIX - $RDEV_PREFIX)
+    fi
+
+    AC_DEFINE_UNQUOTED(DEV_PREFIX,"${DEV_PREFIX}",
+       [Define as the prefix for disk devices, commonly /dev/ or /dev/dsk/ ])
+    AC_DEFINE_UNQUOTED(RDEV_PREFIX,"${RDEV_PREFIX}",
+       [Define as the prefix for raw disk devices, commonly /dev/r or /dev/rdsk/ ])
+    AC_SUBST(CLIENT_SCRIPTS_OPT)
+])
diff --git a/config/amanda/dirs.m4 b/config/amanda/dirs.m4
new file mode 100644 (file)
index 0000000..ee9c58c
--- /dev/null
@@ -0,0 +1,266 @@
+# SYNOPSIS
+#
+#   AMANDA_WITH_DUMPERDIR
+#
+# OVERVIEW
+#
+#   Define and substitute DUMPER_DIR with the result.
+#
+AC_DEFUN([AMANDA_WITH_DUMPERDIR],
+[
+    AC_ARG_WITH(dumperdir,
+       AS_HELP_STRING([--with-dumperdir=DIR],
+           [where we install the dumpers (default: exec_prefix/dumper)]),
+       [
+            AMANDA_MSG_WARN([--with-dumperdir is no longer used.])
+       ]
+    )
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_CONFIGDIR
+#
+# OVERVIEW
+#
+#   Allow user to specify the dumperdir, defaulting to ${exec_prefix}/dumper.
+#   Define and substitute DUMPER_DIR with the result.
+#
+AC_DEFUN([AMANDA_WITH_CONFIGDIR],
+[
+    AC_ARG_WITH(configdir,
+       AS_HELP_STRING([--with-configdir=DIR],
+           [runtime config files in DIR @<:@sysconfdir/amanda@:>@]),
+       [
+           case "$withval" in
+           "" | y | ye | yes | n | no)
+               AC_MSG_ERROR([*** You must supply an argument to the --with-configdir option.])
+             ;;
+           *) CONFIG_DIR="$withval"
+             ;;
+           esac
+       ], [
+           : ${CONFIG_DIR='${sysconfdir}/amanda'} # (variable will be evaluated below)
+       ]
+    )
+    AC_DEFINE_DIR([CONFIG_DIR], [CONFIG_DIR],
+      [The directory in which configuration directories should be created. ])
+])
+
+## deprecated --with-*dir options
+
+AC_DEFUN([AMANDA_WITH_INDEXDIR],
+[
+    AC_ARG_WITH(indexdir,
+       AS_HELP_STRING([--with-indexdir], [deprecated: use indexdir in amanda.conf]),
+       [   AC_MSG_ERROR([*** --with-indexdir is deprecated; use indexdir in amanda.conf instead.])
+       ],)
+])
+
+AC_DEFUN([AMANDA_WITH_DBDIR],
+[
+    AC_ARG_WITH(dbdir,
+       AS_HELP_STRING([--with-dbdir], [deprecated: use infofile in amanda.conf]),
+       [   AC_MSG_ERROR([*** --with-dbdir is deprecated; use infofile in amanda.conf instead.])
+       ],)
+])
+
+AC_DEFUN([AMANDA_WITH_LOGDIR],
+[
+    AC_ARG_WITH(logdir,
+       AS_HELP_STRING([--with-logdir], [deprecated: use logfile in amanda.conf]),
+       [   AC_MSG_ERROR([*** --with-logdir is deprecated; use logfile in amanda.conf instead.])
+       ],)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_GNUTAR_LISTDIR
+#
+# OVERVIEW
+#
+#   Implements --with-gnutar-listdir.  Defines GNUTAR_LISTED_INCREMENTAL_DIR to the
+#   value given or $localstatedir/amanda/gnutar-lists by default.  Any $xxxdir variables
+#   are fully evaluated in the value.
+#
+AC_DEFUN([AMANDA_WITH_GNUTAR_LISTDIR], 
+[
+    AC_ARG_WITH(gnutar-listdir,
+       AS_HELP_STRING([--with-gnutar-listdir=DIR],
+        [put gnutar directory lists in DIR (default: localstatedir/amanda/gnutar-lists)]),
+       [
+            case "$withval" in
+                n | no) GNUTAR_LISTDIR= ;;
+                y | ye | yes) GNUTAR_LISTDIR='${localstatedir}/amanda/gnutar-lists' ;;
+                *) GNUTAR_LISTDIR="$withval" ;;
+            esac
+        ], [
+            GNUTAR_LISTDIR='${localstatedir}/amanda/gnutar-lists'
+        ]
+    )
+
+    # substitute $prefix, etc. if necessary
+    AC_DEFINE_DIR([GNUTAR_LISTED_INCREMENTAL_DIR], [GNUTAR_LISTDIR],
+       [The directory in which GNU tar should store directory lists for incrementals. ])
+    
+    # handle deprecated option
+    AC_ARG_WITH(gnutar-listed-incremental,
+        AS_HELP_STRING([--with-gnutar-listed-incremental], 
+            [deprecated; use --with-gnutar-listdir]),
+        [
+            AC_MSG_ERROR([*** The gnutar-listed-incremental option is deprecated; use --with-gnutar-listdir instead])
+        ]
+    )
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_TMPDIR
+#
+# OVERVIEW
+#
+#   Implement --with-tmpdir.  Defines and substitutes AMANDA_TMPDIR.
+#
+AC_DEFUN([AMANDA_WITH_TMPDIR],
+[
+    AC_ARG_WITH(tmpdir,
+        AS_HELP_STRING([--with-tmpdir],
+            [directory for temporary and debugging files (default: /tmp/amanda)]),
+        [
+            tmpdir="$withval"
+        ], [
+            tmpdir=yes
+        ]
+    )
+
+    case "$tmpdir" in
+        n | no) AC_MSG_ERROR([*** --without-tmpdir is not allowed.]);;
+        y |  ye | yes) AMANDA_TMPDIR="/tmp/amanda";;
+        *) AMANDA_TMPDIR="$tmpdir";;
+    esac
+
+    AC_DEFINE_DIR([AMANDA_TMPDIR], [AMANDA_TMPDIR],
+        [The directory in which Amanda should create temporary files. ])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_EXPAND_DIRS
+#
+# OVERVIEW
+#
+#   Expand any variable references in the following variables, then define them:
+#   - bindir
+#   - sbindir
+#   - libexecdir
+#   - mandir
+#
+#   Also defines the following directories and expands any variable references:
+#   - amlibdir = --with-amlibdir or ${libdir}/amanda
+#   - amlibexecdir = --with-amlibexecdir or ${libexecdir}/amanda
+#   - amincludedir = ${includedir}/amanda
+#   - amperldir = --with-amperldir or `perl -V:installsitearch`
+#   - DUMPER_DIR = ${amlibexecdir}/application
+#
+AC_DEFUN([AMANDA_EXPAND_DIRS],
+[
+    AC_REQUIRE([AMANDA_PROG_PERL])
+
+    AC_DEFINE_DIR([bindir], [bindir],
+        [Directory in which user binaries should be installed. ])
+
+    AC_DEFINE_DIR([sbindir], [sbindir],
+        [Directory in which administrator binaries should be installed. ])
+
+    AC_DEFINE_DIR([libexecdir], [libexecdir], 
+        [Directory in which internal binaries should be installed. ])
+
+    AC_DEFINE_DIR([mandir], [mandir],
+        [Directory in which man-pages should be installed])
+
+
+    # amanda-specific directories
+    AMLIBDIR=$libdir/amanda
+    AC_ARG_WITH(amlibdir,
+       AS_HELP_STRING([--with-amlibdir[[[[[=PATH]]]]]],
+               [Where library are installed, default: $libdir/amanda])
+       AS_HELP_STRING([--without-amlibdir],
+               [Library are installed in $libdir]),
+       [
+           case "$withval" in
+               n | no) AMLIBDIR=$libdir ;;
+               y | ye | yes) AMLIBDIR=$libdir/amanda ;;
+               *) AMLIBDIR=$withval ;;
+           esac
+       ]
+    )
+    AC_DEFINE_DIR([amlibdir], [AMLIBDIR],
+       [Directory in which Amanda libraries should be installed])
+
+    AMLIBEXECDIR=$libexecdir/amanda
+    AC_ARG_WITH(amlibexecdir,
+       AS_HELP_STRING([--with-amlibexecdir[[[[[=PATH]]]]]],
+               [Where amanda own programs are installed, default: $libexecdir/amanda])
+       AS_HELP_STRING([--without-amlibexecdir],
+               [Amanda own programs are installed in $libexecdir]),
+       [
+           case "$withval" in
+               n | no) AMLIBEXECDIR=$libexecdir ;;
+               y | ye | yes) AMLIBEXECDIR=$libexecdir/amanda ;;
+               *) AMLIBEXECDIR=$withval ;;
+           esac
+       ]
+    )
+    AC_DEFINE_DIR([amlibexecdir], [AMLIBEXECDIR],
+       [Directory in which Amanda own programs should be installed])
+
+    amincludedir="${includedir}/amanda"
+    AC_DEFINE_DIR([amincludedir], [amincludedir],
+       [Directory in which Amanda header files should be installed])
+
+    AC_ARG_WITH(amperldir,
+       AS_HELP_STRING([--with-amperldir[[[[[=PATH]]]]]],
+               [Where amanda's perl modules are installed; default: installsitelib])
+       AS_HELP_STRING([--without-amperldir],
+               [Install amanda's perl modules in $amlibdir/perl]),
+       [
+           case "$withval" in
+               y | ye | yes) AMPERLLIB=DEFAULT ;;
+               n | no) AMPERLLIB=$amlibdir/perl ;;
+               *) AMPERLLIB=$withval ;;
+           esac
+       ], [
+           AMPERLLIB=DEFAULT
+       ]
+    )
+    # apply the default if no value was given.
+    if test x"$AMPERLLIB" = x"DEFAULT"; then
+       eval `$PERL -V:installsitelib`
+       AMPERLLIB=$installsitelib
+    fi
+    AC_DEFINE_DIR([amperldir], [AMPERLLIB],
+       [Directory in which perl modules should be installed])
+
+    DUMPER_DIR='${amlibexecdir}/application'
+    AC_DEFINE_DIR([DUMPER_DIR],[DUMPER_DIR],
+           [Directory in which dumper interfaces should be installed and searched. ])
+    # TODO: rename to APPLICATION_DIR, add to Amanda::Paths and 'amgtconf build.APPLICATION_DIR'
+])
+
+# SYNOPSIS
+#
+#   AMANDA_SHOW_DIRS_SUMMARY
+#
+# OVERVIEW
+#
+#   Show a summary of the settings from this file.
+#
+AC_DEFUN([AMANDA_SHOW_DIRS_SUMMARY],
+[
+    echo "Directories:"
+    echo "  Perl modules (amperldir): $amperldir"
+    echo "  Dumper: $DUMPER_DIR"
+    echo "  Configuration: $CONFIG_DIR"
+    echo "  GNU Tar lists: $GNUTAR_LISTED_INCREMENTAL_DIR"
+    echo "  Temporary: $AMANDA_TMPDIR"
+])
diff --git a/config/amanda/documentation.m4 b/config/amanda/documentation.m4
new file mode 100644 (file)
index 0000000..af8a023
--- /dev/null
@@ -0,0 +1,64 @@
+# OVERVIEW
+#
+#   Configuration for the docbook-based manpages.
+#
+#   We require XSLTPROC, as well as specific versions of Docbook and the
+#   Docbook DTD.
+
+AC_DEFUN([AMANDA_SETUP_DOCUMENTATION],
+[
+    AC_ARG_ENABLE(manpage-build,
+    AS_HELP_STRING([--enable-manpage-build],
+                  [Build the manpages from their XML source (shipped manpages are usually sufficient)]),
+       [ ENABLE_MANPAGE_BUILD=$enableval ],
+       [ ENABLE_MANPAGE_BUILD=no ])
+
+    # and ensure that everything docbook-related is OK if we'll be using it
+    if test "x$ENABLE_MANPAGE_BUILD" = "xyes"; then
+       DOC_BUILD_DATE=`date '+%d-%m-%Y'`
+
+       AC_PROG_XSLTPROC([--nonet])
+       AC_CHECK_DOCBOOK_XSLT([1.72.0])
+       AC_CHECK_DOCBOOK_XSLT_MIN([1.72.0])
+       AC_CHECK_DOCBOOK_DTD([4.1.2])
+       AC_CHECK_DOCBOOK_DTD([4.2])
+
+       if test -z "$XSLTPROC"; then
+           AC_MSG_ERROR([Cannot build manpages: 'xsltproc' was not found.])
+       fi
+
+       # if the 'current' Docbook revision is good enough, use that; otherwise,
+       # if 1.72.0 is available, use that.
+       XSLREL=current
+       if test "x$DOCBOOK_XSLT_CURRENT_VERSION" = "xno"; then
+           if test "x$HAVE_DOCBOOK_XSLT_1_72_0" = "xno"; then
+               AC_MSG_ERROR([Cannot build manpages: docbook version 1.72.0 or higher required.])
+           else
+               XSLREL=1.72.0
+           fi
+       fi
+
+       # disable validation if the correct DTDs are not available
+       if test "x$HAVE_DOCBOOK_DTD_4_1_2" = "xno" || test "x$HAVE_DOCBOOK_DTD_4_2" = "xno"; then
+           AMANDA_MSG_WARN([Docbook DTD versions 4.1.2 and 4.2 are required for manpage validation; disabling validation])
+           XSLTPROC_FLAGS="$XSLTPROC_FLAGS --novalid"
+       fi
+    fi
+
+    AM_CONDITIONAL(ENABLE_MANPAGE_BUILD, test "x$ENABLE_MANPAGE_BUILD" = "xyes")
+    AC_SUBST(XSLREL)
+    AC_SUBST(DOC_BUILD_DATE)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_SHOW_DOCUMENTATION_SUMMARY
+#
+# OVERVIEW
+#
+#   Show a summary of the settings from this file.
+#
+AC_DEFUN([AMANDA_SHOW_DOCUMENTATION_SUMMARY],
+[
+    echo "Build documentation:" $ENABLE_MANPAGE_BUILD
+])
diff --git a/config/amanda/dumpers.m4 b/config/amanda/dumpers.m4
new file mode 100644 (file)
index 0000000..9c455c6
--- /dev/null
@@ -0,0 +1,398 @@
+# OVERVIEW
+#
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_GNUTAR
+#
+# OVERVIEW
+#
+#   Search for a GNU 'tar' binary, placing the result in the precious 
+#   variable GNUTAR.  The discovered binary is tested to ensure it's really
+#   GNU tar.
+#
+#   Also handle --with-gnutar
+#
+AC_DEFUN([AMANDA_PROG_GNUTAR],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+
+    # call with
+    AC_ARG_WITH(gnutar,
+       AS_HELP_STRING([--with-gnutar=PROG],
+                      [use PROG as GNU 'tar']),
+       [
+           # check withval
+           case "$withval" in
+               /*) GNUTAR="$withval";;
+               y|ye|yes) :;;
+               n|no) GNUTAR=no ;;
+               *)  AC_MSG_ERROR([*** You must supply a full pathname to --with-gnutar]);;
+           esac
+           # done
+       ]
+    )
+
+    if test "x$GNUTAR" = "xno"; then
+       GNUTAR=
+    else
+       for gnutar_name in gtar gnutar tar; do
+           AC_PATH_PROGS(GNUTAR, $gnutar_name, , $LOCSYSPATH)
+           if test -n "$GNUTAR"; then
+             case "`\"$GNUTAR\" --version 2>&1`" in
+              *GNU*tar* | *Free*paxutils* )
+                           # OK, it is GNU tar
+                           break
+                           ;;
+              *)
+                           # warning..
+                           AMANDA_MSG_WARN([$GNUTAR is not GNU tar, so it will not be used.])
+                           # reset the cache for GNUTAR so AC_PATH_PROGS will search again
+                           GNUTAR=''
+                           unset ac_cv_path_GNUTAR
+                           ;;
+             esac
+           fi
+       done
+    fi
+
+    if test "x$GNUTAR" != "x"; then
+       # define unquoted
+       AC_DEFINE_UNQUOTED(GNUTAR, "$GNUTAR", [Location of the GNU 'tar' binary])
+    fi
+    AC_ARG_VAR(GNUTAR, [Location of the GNU 'tar' binary])
+    AC_SUBST(GNUTAR)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_SAMBA_CLIENT
+#
+# OVERVIEW
+#
+#   Search for a samba client (smbclient) binary, placing the result in
+#   the variable SAMBA_CLIENT.  The discovered binary is tested to determine an
+#   internally significant version number, stored in SAMBA_VERSION.  The version
+#   serves only to differentiate versions of Samba which Amanada must treat 
+#   differently, and has no relation to the actual Samba version number.
+#
+#   Automake conditional 'WANT_SAMBA' is set if a samba client is discovered.
+#
+#   Also handles --with-smbclient and (deprecated) --with-samba-user
+#
+AC_DEFUN([AMANDA_PROG_SAMBA_CLIENT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+
+    AC_ARG_WITH(smbclient,
+       AS_HELP_STRING([--with-smbclient=PROG],
+                      [use PROG as 'smbclient']),
+       [
+           case "$withval" in
+               /*) SAMBA_CLIENT="$withval";;
+               y|ye|yes) :;;
+               n|no) SAMBA_CLIENT=no ;;
+               *)  AC_MSG_ERROR([*** You must supply a full pathname to --with-smbclient]);;
+           esac
+       ]
+    )
+
+    AC_ARG_WITH(samba-user,
+       AS_HELP_STRING([--with-samba-user],
+                      [deprecated; place username in 'amandapass']),
+       [ AC_MSG_ERROR([--with-samba-user is no longer supported; place username in 'amandapass']) ]
+    )
+
+    if test "x$SAMBA_CLIENT" != "xno"; then
+      AC_PATH_PROG(SAMBA_CLIENT,smbclient,,$LOCSYSPATH)
+      smbversion=0
+      if test ! -z "$SAMBA_CLIENT"; then
+        case "`\"$SAMBA_CLIENT\" '\\\\not.a.host.name\\notashare' -U nosuchuser -N -Tx /dev/null 2>&1`" in
+        *"Unknown host"*)
+                     smbversion=1
+                     ;;
+        *"Connection to not.a.host.name failed"*)
+                     smbversion=2
+                     ;;
+        *)
+                     AMANDA_MSG_WARN([$SAMBA_CLIENT does not seem to be smbclient, so it will not be used.])
+                     SAMBA_CLIENT=
+                     ;;
+        esac
+        if test -n "$SAMBA_CLIENT"; then
+         AC_DEFINE_UNQUOTED(SAMBA_CLIENT,"$SAMBA_CLIENT",
+                 [Define the location of smbclient for backing up Samba PC clients. ])
+         AC_DEFINE_UNQUOTED(SAMBA_VERSION, $smbversion,
+                 [Not the actual samba version, just a number that should be increased whenever we start to rely on a new samba feature. ])
+        fi
+      fi
+    fi
+
+    AM_CONDITIONAL(WANT_SAMBA, test -n "$SAMBA_CLIENT")
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_VDUMP_VRESTORE
+#
+# DESCRIPTION
+#
+#   Search for 'vdump' and 'vrestore', setting and AC_DEFINE-ing VDUMP and 
+#   VRESTORE if they are found.
+#
+AC_DEFUN([AMANDA_PROG_VDUMP_VRESTORE],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+
+    AC_PATH_PROG(VDUMP,vdump,,$SYSLOCPATH)
+    AC_PATH_PROG(VRESTORE,vrestore,,$SYSLOCPATH)
+    if test "$VDUMP" -a "$VRESTORE"; then
+       AC_DEFINE_UNQUOTED(VDUMP,"$VDUMP",[Define the location of the vdump program. ])
+       AC_DEFINE_UNQUOTED(VRESTORE,"$VRESTORE",[Define the location of the vrestore program. ])
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_VXDUMP_VXRESTORE
+#
+# DESCRIPTION
+#
+#   Search for 'vxdump' and 'vxrestore', setting and AC_DEFINE-ing VXDUMP
+#   and VXRESTORE if they are found.
+#
+#   In addition to the standard paths, this macro will search in
+#   /usr/lib/fs/vxfs.
+#
+AC_DEFUN([AMANDA_PROG_VXDUMP_VXRESTORE],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+
+    AC_PATH_PROG(VXDUMP,vxdump,,$SYSLOCPATH:/usr/lib/fs/vxfs)
+    AC_PATH_PROG(VXRESTORE,vxrestore,,$SYSLOCPATH:/usr/lib/fs/vxfs)
+    if test "$VXDUMP" -a "$VXRESTORE"; then
+       AC_DEFINE_UNQUOTED(VXDUMP,"$VXDUMP",
+[Define the location of the vxdump program on HPUX and SINIX hosts or on
+ * other hosts where the Veritas filesystem (vxfs) has been installed. ])
+       AC_DEFINE_UNQUOTED(VXRESTORE,"$VXRESTORE",
+[Define the location of the vxrestore program on HPUX and SINIX hosts or on
+ * other hosts where the Veritas filesystem (vxfs) has been installed. ])
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_XFSDUMP_XFSRESTORE
+#
+# DESCRIPTION
+#
+#   Search for 'xfsdump' and 'xfsrestore', setting and AC_DEFINE-ing XFSDUMP
+#   and XFSRESTORE if they are found.
+#
+AC_DEFUN([AMANDA_PROG_XFSDUMP_XFSRESTORE],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+
+    AC_PATH_PROGS(XFSDUMP,xfsdump,,$SYSLOCPATH)
+    AC_PATH_PROGS(XFSRESTORE,xfsrestore,,$SYSLOCPATH)
+    if test "$XFSDUMP" -a "$XFSRESTORE"; then
+       AC_DEFINE_UNQUOTED(XFSDUMP,"$XFSDUMP",
+               [Define the location of the xfsdump program on Irix hosts. ])
+       AC_DEFINE_UNQUOTED(XFSRESTORE,"$XFSRESTORE",
+               [Define the location of the xfsrestore program on Irix hosts. ])
+       AMANDA_MSG_WARN([[xfsdump causes the setuid-root rundump program to be enabled.  To disable it, just #undef XFSDUMP in config/config.h]])
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_DUMP_RESTORE
+#
+# DESCRIPTION
+#
+#   Search for compatible dump and restore binaries.  The exact name of
+#   the binaries we search for depends on the target system.  If working
+#   binaries are found, DUMP and RESTORE are defined to their full paths.
+#
+#   DUMP_RETURNS is defined if the system's 'dump' returns 1 on success.
+#
+#   HAVE_DUMP_ESTIMATE is defined to the dump flag which enables estimates.
+#
+#   The --with-honor-nodump flag is processed, and the result of the test is
+#   positive, then HAVE_HONOR_NODUMP is defined.
+#
+AC_DEFUN([AMANDA_PROG_DUMP_RESTORE],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_REQUIRE([AMANDA_PROG_GREP])
+
+    # Set the order of dump programs to look for.  Finding the proper file
+    # system dumping program is problematic.  Some systems, notably HP-UX
+    # and AIX, have both the backup and dump programs.  HP-UX can't use the
+    # the backup program while AIX systems can't use the dump program.  So
+    # a variable is set up here to specify the order of dump programs to
+    # search for on the system.
+    DUMP_PROGRAMS="ufsdump dump backup"
+    dump_returns_1=
+    case "$target" in
+       *-dg-*)
+           DUMP_PROGRAMS="dump "$DUMP_PROGRAMS
+           dump_returns_1=yes
+           ;;
+      *-ibm-aix*)
+           DUMP_PROGRAMS="backup "$DUMP_PROGRAMS
+           AC_DEFINE(AIX_BACKUP,1,
+               [Is DUMP the AIX program 'backup'?])
+           ;;
+      *-ultrix*)
+           dump_returns_1=yes
+           ;;
+    esac
+
+    if test -n "$dump_returns_1"; then
+      AC_DEFINE(DUMP_RETURNS_1,1,
+       [Define this if this system's dump exits with 1 as a success code. ])
+    fi
+
+    AC_PATH_PROGS(DUMP,$DUMP_PROGRAMS,,$SYSLOCPATH)
+    AC_PATH_PROGS(RESTORE,ufsrestore restore,,$SYSLOCPATH)
+    
+    # newer versions of GNU tar include a program named 'backup' which
+    # does *not* implement the expected 'dump' interface.  Detect that here
+    # and pretend we never saw it.
+    if test -n "$DUMP"; then
+      if test "`basename $DUMP`" = "backup"; then
+        backup_gnutar=`$DUMP --version | $GREP "GNU tar"`
+        if test $? -eq 0; then
+          DUMP=
+        fi
+      fi
+    fi
+    
+    if test "$DUMP" -a "$RESTORE"; then
+       AC_DEFINE_UNQUOTED(DUMP,"$DUMP",
+           [Define the location of the ufsdump, backup, or dump program. ])
+       AC_DEFINE_UNQUOTED(RESTORE,"$RESTORE",
+           [Define the location of the ufsrestore or restore program. ])
+
+       # check for an estimate flag
+       if test -x $DUMP; then
+           AC_CACHE_CHECK(
+               [whether $DUMP supports -E or -S for estimates],
+               amanda_cv_dump_estimate,
+               [
+                   case "$DUMP" in
+                   *dump)
+                       AC_TRY_COMMAND($DUMP 9Ef /dev/null /dev/null/invalid/fs 2>&1
+                           | $GREP -v Dumping
+                           | $GREP -v Date
+                           | $GREP -v Label >conftest.d-E 2>&1)
+                       cat conftest.d-E >&AS_MESSAGE_LOG_FD()
+                       AC_TRY_COMMAND($DUMP 9Sf /dev/null /dev/null/invalid/fs 2>&1
+                           | $GREP -v Dumping
+                           | $GREP -v Date
+                           | $GREP -v Label >conftest.d-S 2>&1)
+                       cat conftest.d-S >&AS_MESSAGE_LOG_FD()
+                       AC_TRY_COMMAND($DUMP 9f /dev/null /dev/null/invalid/fs 2>&1
+                           | $GREP -v Dumping
+                           | $GREP -v Date
+                           | $GREP -v Label >conftest.d 2>&1)
+                       cat conftest.d >&AS_MESSAGE_LOG_FD()
+                       if AC_TRY_COMMAND(cmp conftest.d-E conftest.d 1>&2); then
+                           amanda_cv_dump_estimate=E
+                       elif AC_TRY_COMMAND(cmp conftest.d-S conftest.d 1>&2); then
+                           amanda_cv_dump_estimate=S
+                       else
+                           amanda_cv_dump_estimate=no
+                       fi
+                       rm -f conftest.d conftest.d-E conftest.d-S
+                     ;;
+                   *) amanda_cv_dump_estimate=no
+                     ;;
+                   esac
+               ])
+       else
+           AMANDA_MSG_WARN([$DUMP is not executable, cannot run -E/-S test])
+           amanda_cv_dump_estimate=no
+       fi
+       if test "x$amanda_cv_dump_estimate" != xno; then
+           AC_DEFINE_UNQUOTED(HAVE_DUMP_ESTIMATE, "$amanda_cv_dump_estimate",
+               [Define to the string that enables dump estimates. ])
+       fi
+
+       AC_ARG_WITH(dump-honor-nodump,
+           AS_HELP_STRING([--with-dump-honor-nodump],
+               [if dump supports -h, use it for level0s too]),
+       [
+           if test -x $DUMP; then
+               AC_CACHE_CHECK(
+                 [whether $DUMP supports -h (honor nodump flag)],
+                 amanda_cv_honor_nodump,
+                 [
+                   case "$DUMP" in
+                   *dump)
+                       AC_TRY_COMMAND($DUMP 9hf 0 /dev/null /dev/null/invalid/fs 2>&1
+                           | $GREP -v Dumping
+                           | $GREP -v Date
+                           | $GREP -v Label >conftest.d-h 2>&1)
+                       cat conftest.d-h >&AS_MESSAGE_LOG_FD()
+                       AC_TRY_COMMAND($DUMP 9f /dev/null /dev/null/invalid/fs 2>&1
+                           | $GREP -v Dumping
+                           | $GREP -v Date
+                           | $GREP -v Label >conftest.d 2>&1)
+                       cat conftest.d >&AS_MESSAGE_LOG_FD()
+                       if AC_TRY_COMMAND(diff conftest.d-h conftest.d 1>&2); then
+                           amanda_cv_honor_nodump=yes
+                       else
+                           amanda_cv_honor_nodump=no
+                       fi
+                       rm -f conftest.d conftest.d-h
+                     ;;
+                   *) amanda_cv_honor_nodump=no
+                     ;;
+                   esac
+                 ])
+           else
+               AMANDA_MSG_WARN([$DUMP is not executable, cannot run -h test])
+               amanda_cv_honor_nodump=no
+           fi
+           if test "x$amanda_cv_honor_nodump" = xyes; then
+               AC_DEFINE(HAVE_HONOR_NODUMP,1,
+                   [Define this if dump accepts -h for honoring nodump. ])
+           fi
+       ])
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_CHECK_USE_RUNDUMP
+#
+# DESCRIPTION
+#
+#   Decide if the 'rundump' setuid-root wrapper should be used to invoke
+#   dump.  If so, USE_RUNDUMP is #defined.
+#
+AC_DEFUN([AMANDA_CHECK_USE_RUNDUMP], [
+    USE_RUNDUMP=no
+
+    # some systems require rundump unconditionally
+    case "$target" in
+        *-ultrix*) USE_RUNDUMP=yes ;;
+        *-dg-*) USE_RUNDUMP=yes ;;
+    esac
+
+    AC_ARG_WITH(rundump,
+        AS_HELP_STRING([--with-rundump], [use rundump, a setuid-root wrapper, to invoke dump]), [
+        case "$withval" in
+            n | no) USE_RUNDUMP=no ;;
+            y | ye | yes) USE_RUNDUMP=yes ;;
+            *) AC_MSG_ERROR([You must not supply an argument to --with-rundump option.]);;
+        esac
+        ])
+
+    if test x"$USE_RUNDUMP" = x"yes"; then
+        AC_DEFINE(USE_RUNDUMP,1,
+            [Define to invoke rundump (setuid-root) instead of DUMP program directly. ])
+    fi
+])
diff --git a/config/amanda/file-list b/config/amanda/file-list
new file mode 100644 (file)
index 0000000..7e929ac
--- /dev/null
@@ -0,0 +1,41 @@
+## this file is automatically generated by autogen
+EXTRA_DIST += amanda/amplot.m4
+EXTRA_DIST += amanda/bsd-security.m4
+EXTRA_DIST += amanda/bsdtcp-security.m4
+EXTRA_DIST += amanda/bsdudp-security.m4
+EXTRA_DIST += amanda/changer.m4
+EXTRA_DIST += amanda/components.m4
+EXTRA_DIST += amanda/compress.m4
+EXTRA_DIST += amanda/config.m4
+EXTRA_DIST += amanda/debugging.m4
+EXTRA_DIST += amanda/defaults.m4
+EXTRA_DIST += amanda/devprefix.m4
+EXTRA_DIST += amanda/dirs.m4
+EXTRA_DIST += amanda/documentation.m4
+EXTRA_DIST += amanda/dumpers.m4
+EXTRA_DIST += amanda/flags.m4
+EXTRA_DIST += amanda/flock.m4
+EXTRA_DIST += amanda/funcs.m4
+EXTRA_DIST += amanda/getfsent.m4
+EXTRA_DIST += amanda/i18n.m4
+EXTRA_DIST += amanda/ipv6.m4
+EXTRA_DIST += amanda/krb4-security.m4
+EXTRA_DIST += amanda/krb5-security.m4
+EXTRA_DIST += amanda/lfs.m4
+EXTRA_DIST += amanda/libs.m4
+EXTRA_DIST += amanda/net.m4
+EXTRA_DIST += amanda/progs.m4
+EXTRA_DIST += amanda/readdir.m4
+EXTRA_DIST += amanda/readline.m4
+EXTRA_DIST += amanda/rsh-security.m4
+EXTRA_DIST += amanda/s3-device.m4
+EXTRA_DIST += amanda/shmem.m4
+EXTRA_DIST += amanda/socklen_t_equiv.m4
+EXTRA_DIST += amanda/ssh-security.m4
+EXTRA_DIST += amanda/summary.m4
+EXTRA_DIST += amanda/swig.m4
+EXTRA_DIST += amanda/syshacks.m4
+EXTRA_DIST += amanda/tape.m4
+EXTRA_DIST += amanda/types.m4
+EXTRA_DIST += amanda/userid.m4
+EXTRA_DIST += amanda/version.m4
diff --git a/config/amanda/flags.m4 b/config/amanda/flags.m4
new file mode 100644 (file)
index 0000000..ba20da9
--- /dev/null
@@ -0,0 +1,301 @@
+# OVERVIEW/BACKGROUND
+#
+#   This file manages flags in CFLAGS, CPPFLAGS, LDFLAGS, and LIBS.
+#
+#   Flags can come from two several sources:
+#    - entry to ./configure or on the configure command line (they are
+#      `precious' variables)
+#    - added by autoconf tests during the execution of configure
+#
+#   Although Automake supports overriding variables when invoking 'make',
+#   we don't support it (mostly because autoconf doesn't).  Instead, users
+#   should specify such variables when invoking ./configure.
+#
+#   CFLAGS are a little bit more complicated: Amanda has two categories,
+#   mandatory CFLAGS, which should be used everywhere, and warning CFLAGS,
+#   which are only used on Amanda code (not gnulib or yacc-generated code).
+#   To accomplish this, mandatory CFLAGS go directl into CFLAGS, while
+#   warwnings go in AMANDA_WARNING_CFLAGS; these are then added to 
+#   AM_CFLAGS by the Makefiles.
+
+# SYNOPSIS
+#
+#   AMANDA_INIT_FLAGS()
+#
+# DESCRIPTION
+#
+#   Process variables given by the user on the command line,
+#   either as environment variables:
+#      CPPFLAGS=-Dfoo ./configure ...
+#   as assignments in the configure command line:
+#      ./configure LIBS=-lfoo ...
+#   or with the deprecated flags --with-cflags, --with-includes, and
+#   --with-libraries
+#
+AC_DEFUN([AMANDA_INIT_FLAGS],
+[
+    # support deprecated ./configure flags to set various compiler flags
+
+    AC_ARG_WITH(cflags,
+       AS_HELP_STRING([--with-cflags=FLAGS],
+                      [deprecated; use ./configure CFLAGS=... ]),
+       [
+           case "$withval" in
+           "" | y | ye | yes | n | no)
+               AC_MSG_ERROR([*** You must supply an argument to the --with-cflags option.])
+               ;;
+           esac
+
+           CFLAGS="$withval"
+       ])
+
+    AC_ARG_WITH(includes,
+       AS_HELP_STRING([--with-includes=INCLUDE-DIRS],
+                      [deprecated; use ./configure CPPFLAGS='-I.. -I..']),
+       [
+           case "$withval" in
+           "" | y | ye | yes | n | no)
+               AC_MSG_ERROR([*** You must supply an argument to the --with-includes option.])
+             ;;
+           esac
+
+           for dir in $withval; do
+               if test -d "$dir"; then
+                   CPPFLAGS="$CPPFLAGS -I$dir"
+               else
+                   AMANDA_MSG_WARN([Include directory $dir does not exist.])
+               fi
+           done
+       ])
+
+    AC_ARG_WITH(libraries,
+       AS_HELP_STRING([--with-libraries=LIBRARY-DIRS],
+                      [deprecated; use ./configure LDFLAGS='-L.. -L..' (add -R on Solaris, NetBSD)]),
+       [
+           case "$withval" in
+           "" | y | ye | yes | n | no)
+               AC_MSG_ERROR([*** You must supply an argument to the --with-libraries option.])
+             ;;
+           esac
+
+           for dir in $withval; do
+               if test -d "$dir"; then
+                   case "$target" in
+                     *-solaris2*,*-netbsd*)
+                           LDFLAGS="$LDFLAGS -R$dir"
+                           ;;
+                   esac
+                   LDFLAGS="$LDFLAGS -L$dir"
+               else
+                   AMANDA_MSG_WARN([Library directory $dir does not exist.])
+               fi
+           done
+       ])
+
+    # Warn for just about everything
+    AMANDA_TEST_GCC_WARNING_FLAG(-Wall, [
+       AMANDA_ADD_WARNING_CFLAG(-Wall)
+    ])
+    
+    # And add any extra warnings too
+    AMANDA_TEST_GCC_WARNING_FLAG(-Wextra, [
+       AMANDA_ADD_WARNING_CFLAG(-Wextra)
+    ], [
+       AMANDA_TEST_GCC_WARNING_FLAG(-W, [
+           AMANDA_ADD_WARNING_CFLAG(-W)
+       ])
+    ])
+    AC_SUBST([AMANDA_WARNING_CFLAGS])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_STATIC_FLAGS(new_flags)
+#
+# DESCRIPTION
+#
+#   Set AMANDA_STATIC_LDFLAGS to -static if --enable-static-binary
+#
+AC_DEFUN([AMANDA_STATIC_FLAGS],
+[
+    AC_ARG_ENABLE(static-binary,
+       AS_HELP_STRING([--enable-static-binary],
+                      [To build statically linked binaries]),
+       [
+           case "$withval" in
+           "" | y | ye | yes)
+               AMANDA_STATIC_LDFLAGS=-static
+               if test x"$enable_static" = x"no"; then
+                       AC_MSG_ERROR([*** --enable-static-binary is incompatible with --disable-static])
+               fi
+               ;;
+           *n | no)
+               AMANDA_STATIC_LDFLAGS=
+               ;;
+           esac
+       ])
+    AC_SUBST([AMANDA_STATIC_LDFLAGS])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_ADD_CFLAGS(new_flags)
+#
+# DESCRIPTION
+#
+#   Add 'new_flags' to CFLAGS.
+#
+#   'new_flags' will be enclosed in double quotes in the resulting
+#   shell assignment.
+#
+AC_DEFUN([AMANDA_ADD_CFLAGS],
+    [CFLAGS="$CFLAGS $1"]
+)
+
+# SYNOPSIS
+#
+#   AMANDA_ADD_CPPFLAGS(new_flags)
+#
+# DESCRIPTION
+#
+#   Add 'new_flags' to CPPFLAGS.
+#
+#   'new_flags' will be enclosed in double quotes in the resulting
+#   shell assignment.
+#
+AC_DEFUN([AMANDA_ADD_CPPFLAGS],
+    [CPPFLAGS="$CPPFLAGS $1"]
+)
+
+# SYNOPSIS
+#
+#   AMANDA_ADD_LDFLAGS(new_flags)
+#
+# DESCRIPTION
+#
+#   Add 'new_flags' to LDFLAGS.
+#
+#   'new_flags' will be enclosed in double quotes in the resulting
+#   shell assignment.
+#
+AC_DEFUN([AMANDA_ADD_LDFLAGS],
+    [LDFLAGS="$LDFLAGS $1"]
+)
+
+# SYNOPSIS
+#
+#   AMANDA_ADD_LIBS(new_flags)
+#
+# DESCRIPTION
+#
+#   Add 'new_flags' to LIBS.
+#
+#   'new_flags' will be enclosed in double quotes in the resulting
+#   shell assignment.
+#
+AC_DEFUN([AMANDA_ADD_LIBS],
+    [LIBS="$1 $LIBS"]
+)
+
+# SYNOPSIS
+#
+#   AMANDA_ADD_WARNING_CFLAG(flag)
+#
+# DESCRIPTION
+#
+#   Add 'flag' to AMANDA_WARNING_CFLAGS
+#
+AC_DEFUN([AMANDA_ADD_WARNING_CFLAG],
+    [AMANDA_WARNING_CFLAGS="$AMANDA_WARNING_CFLAGS $1"]
+)
+
+# SYNOPSIS
+#
+#   AMANDA_ENABLE_GCC_WARNING(warning)
+#
+# OVERVIEW
+#
+#   Enable warning 'warning' by adding flag -W'warning' to 
+#   AMANDA_WARNING_CFLAGS.
+#
+AC_DEFUN([AMANDA_ENABLE_GCC_WARNING],
+[
+    AMANDA_TEST_GCC_WARNING_FLAG(-W$1,
+    [
+       AMANDA_ADD_WARNING_CFLAG(-W$1)
+    ])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_DISABLE_GCC_WARNING(warning)
+#
+# OVERVIEW
+#
+#   Disable warning 'warning' by adding flag -Wno-'warning' to 
+#   AMANDA_WARNING_CFLAGS.
+#
+AC_DEFUN([AMANDA_DISABLE_GCC_WARNING],
+[
+    # test for -W'warning', then add the 'no-' version.
+    AMANDA_TEST_GCC_WARNING_FLAG(-W$1,
+    [
+       AMANDA_ADD_WARNING_CFLAG(-Wno-$1)
+    ])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_TEST_GCC_WARNING_FLAG(flag, action-if-found, action-if-not-found)
+#
+# OVERVIEW
+#
+#   See if CC is gcc, and if gcc -v --help contains the given flag.  If so,
+#   run action-if-found; otherwise, run action-if-not-found.
+#
+#   Intended for internal use in this file.
+#
+AC_DEFUN([AMANDA_TEST_GCC_WARNING_FLAG],
+[
+    AC_REQUIRE([AC_PROG_CC])
+    AC_REQUIRE([AC_PROG_EGREP])
+    AC_MSG_CHECKING(for gcc flag $1)
+    if test "x$GCC" = "xyes"; then
+       changequote(,)dnl
+       $CC -v --help 2>&1 | $EGREP -- '[^[:alnum:]]$1[^[:alnum:]-]' 2>&1 > /dev/null
+       changequote([,])dnl
+       if test $? -eq 0; then
+           found_warning=yes
+           AC_MSG_RESULT(yes)
+       else
+           found_warning=no
+           AC_MSG_RESULT(no)
+       fi
+    else
+       found_warning=no
+       AC_MSG_RESULT(no (not using gcc))
+    fi
+
+    if test x"$found_warning" = x"yes"; then
+       ifelse($2, [], [:], $2)
+    else
+       ifelse($3, [], [:], $3)
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_SHOW_FLAGS_SUMMARY
+#
+# OVERVIEW
+#
+#   Show a summary of the flags with which Amanda was configured
+#
+AC_DEFUN([AMANDA_SHOW_FLAGS_SUMMARY],
+[
+    echo "Compiler Flags:"
+    echo "  CFLAGS: ${CFLAGS-(none)}"
+    echo "  CPPFLAGS: ${CPPFLAGS-(none)}"
+    echo "  LDFLAGS: ${LDFLAGS-(none)}"
+    echo "  LIBS: ${LIBS-(none)}"
+])
diff --git a/config/amanda/flock.m4 b/config/amanda/flock.m4
new file mode 100644 (file)
index 0000000..9850a5b
--- /dev/null
@@ -0,0 +1,145 @@
+# SYNOPSIS
+#
+#   AMANDA_SETUP_FILE_LOCKING
+#
+# OVERVIEW
+#
+#   Set up file locking support.  Four types of locking are available:
+#     USE_POSIX_FCNTL - use fcntl().  The full job.
+#     USE_FLOCK       - use flock().  Does just as well.
+#     USE_LOCKF       - use lockf().  Only handles advisory, exclusive,
+#                       blocking file locks as used by Amanda.
+#     USE_LNLOCK      - Home brew exclusive, blocking file lock.
+#     <none>          - No locking available.  User beware!
+#   One of given symbols are defined if the method is discovered to
+#   be available; the methods are searched in the above order.
+#
+AC_DEFUN([AMANDA_SETUP_FILE_LOCKING],
+[
+    AC_CHECK_HEADERS(
+        fcntl.h \
+        sys/fcntl.h \
+       sys/types.h \
+       sys/file.h \
+       unistd.h \
+    )
+
+    # find a working file-locking mechanism.
+    # Note: these all use AC_TRY_LINK to make sure that we can compile
+    # and link each variant.  They do not try to test the variants --
+    # that is left to runtime.
+    WORKING_FILE_LOCK="no"
+
+    # check POSIX locking
+    AC_CACHE_CHECK(
+       [whether POSIX locking (with fcntl(2)) is available],
+       amanda_cv_posix_filelocking,
+       [
+           AC_TRY_LINK([
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+           ], [
+           struct flock lock;
+
+           lock.l_type = F_RDLCK;
+           lock.l_start = 0;
+           lock.l_whence = SEEK_CUR;
+           lock.l_len = 0;
+           return fcntl(1, F_SETLK, &lock);
+           ], [
+       amanda_cv_posix_filelocking="yes"
+           ],[
+       amanda_cv_posix_filelocking="no"
+           ])
+       ])
+    if test "x$amanda_cv_posix_filelocking" = xyes; then
+       AC_DEFINE(WANT_AMFLOCK_POSIX,1,[Define to use POSIX (fcntl()) for file locking])
+       WANT_AMFLOCK_POSIX="yes"
+       WORKING_FILE_LOCK="yes"
+    fi
+    AM_CONDITIONAL(WANT_AMFLOCK_POSIX, test x"$WANT_AMFLOCK_POSIX" = x"yes")
+
+    # check flock-based (BSD) locking
+    AC_CACHE_CHECK(
+       [whether flock locking is available],
+       amanda_cv_flock_filelocking,
+       [
+           AC_TRY_LINK([
+#if HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif
+           ], [
+           return flock(1, LOCK_SH);
+           ], [
+       amanda_cv_flock_filelocking="yes"
+           ],[
+       amanda_cv_flock_filelocking="no"
+           ])
+       ])
+    if test "x$amanda_cv_flock_filelocking" = xyes; then
+       AC_DEFINE(WANT_AMFLOCK_FLOCK,1,[Define to use flock(2) for file locking])
+       WANT_AMFLOCK_FLOCK="yes"
+       WORKING_FILE_LOCK="yes"
+    fi
+    AM_CONDITIONAL(WANT_AMFLOCK_FLOCK, test x"$WANT_AMFLOCK_FLOCK" = x"yes")
+
+    # check lockf-based (SVR2, SVR3, SVR4) locking
+    AC_CACHE_CHECK(
+       [whether lockf(3) locking is available],
+       amanda_cv_lockf_filelocking,
+       [
+           AC_TRY_LINK([
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+           ], [
+           return lockf(1, F_LOCK, 0);
+           ], [
+       amanda_cv_lockf_filelocking="yes"
+           ],[
+       amanda_cv_lockf_filelocking="no"
+           ])
+       ])
+    if test "x$amanda_cv_lockf_filelocking" = xyes; then
+       AC_DEFINE(WANT_AMFLOCK_LOCKF,1,[Define to use lockf(3) for file locking.])
+       WANT_AMFLOCK_LOCKF="yes"
+       WORKING_FILE_LOCK="yes"
+    fi
+    AM_CONDITIONAL(WANT_AMFLOCK_LOCKF, test x"$WANT_AMFLOCK_LOCKF" = x"yes")
+
+    # check our homebrew hardlink-based locking (requires hardlinks)
+    AC_CACHE_CHECK(
+       [whether link(2) is available for locking],
+       amanda_cv_lnlock_filelocking,
+       [
+           AC_TRY_LINK([
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+           ], [
+           return link("/tmp/foo", "/tmp/bar");
+           ], [
+       amanda_cv_lnlock_filelocking="yes"
+           ],[
+       amanda_cv_lnlock_filelocking="no"
+           ])
+       ])
+    if test "x$amanda_cv_lnlock_filelocking" = xyes; then
+       AC_DEFINE(WANT_AMFLOCK_LNLOCK,1,[Define to use link(2) to emulate file locking.])
+       WANT_AMFLOCK_LNLOCK="yes"
+       WORKING_FILE_LOCK="yes"
+    fi
+    AM_CONDITIONAL(WANT_AMFLOCK_LNLOCK, test x"$WANT_AMFLOCK_LNLOCK" = x"yes")
+
+    if test x"$WORKING_FILE_LOCK" = "no"; then
+       # this shouldn't happen, and is *bad* if it does
+       AC_MSG_ERROR([*** No working file locking capability found!])
+    fi
+])
diff --git a/config/amanda/funcs.m4 b/config/amanda/funcs.m4
new file mode 100644 (file)
index 0000000..862bac8
--- /dev/null
@@ -0,0 +1,266 @@
+# SYNOPSIS
+#
+#   AMANDA_FUNC_SELECT_ARG_TYPE
+# 
+# OVERVIEW
+#
+#   Figure out the select() argument type.  DEFINEs SELECT_ARG_TYPE.
+#
+AC_DEFUN([AMANDA_FUNC_SELECT_ARG_TYPE],
+    [
+       AC_REQUIRE([AC_HEADER_TIME])
+       AC_CHECK_HEADERS(
+           sys/time.h \
+           sys/types.h \
+           sys/select.h \
+           sys/socket.h \
+           unistd.h \
+       )
+
+       AC_CACHE_CHECK(
+           [for select() argument type],
+           amanda_cv_select_arg_type,
+           [
+               rm -f conftest.c
+               cat <<EOF >conftest.$ac_ext
+#include "confdefs.h"
+#ifdef TIME_WITH_SYS_TIME
+#  include <sys/time.h>
+#  include <time.h>
+#else
+#  ifdef HAVE_SYS_TIME_H
+#    include <sys/time.h>
+#  else
+#    include <time.h>
+#  endif
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#  include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+int main()
+{
+#ifdef FD_SET_POINTER
+       (void)select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, 0);
+#else
+       (void)select(0, (int *) 0, (int *) 0, (int *) 0, 0);
+#endif
+       return 0;
+}
+EOF
+
+               # Figure out the select argument type by first trying to
+               # compile with the fd_set argument.  If the compile fails,
+               # then we know to use the int.  If it suceeds, then try to
+               # use the int.  If the int fails, then use fd_set.  If
+               # both suceeed, then do a line count on the number of
+               # lines that the compiler spit out, assuming that the
+               # compile outputing more lines had more errors.
+               amanda_cv_select_arg_type=no
+               select_compile="${CC-cc} -c $CFLAGS $CPPFLAGS"
+               $select_compile -DFD_SET_POINTER conftest.$ac_ext 1>conftest.fd_set 2>&1
+               if test $? -ne 0; then
+                   amanda_cv_select_arg_type=int
+               fi
+               if test "$amanda_cv_select_arg_type" = no; then
+                   $select_compile conftest.$ac_ext 1>conftest.int 2>&1
+                   if test $? -ne 0; then
+                       amanda_cv_select_arg_type=fd_set
+                   fi
+               fi
+               if test "$amanda_cv_select_arg_type" = no; then
+                   wc_fdset=`wc -l <conftest.fd_set`
+                   wc_int=`wc -l <conftest.int`
+                   if test "$wc_fdset" -le "$wc_int"; then
+                       amanda_cv_select_arg_type=fd_set
+                   else
+                       amanda_cv_select_arg_type=int
+                   fi
+               fi
+               rm -f conftest*
+           ]
+       )
+       AC_DEFINE_UNQUOTED(SELECT_ARG_TYPE,$amanda_cv_select_arg_type,[Define to type of select arguments. ])
+    ]
+)
+
+# SYNOPSIS
+#
+#   AMANDA_FUNC_SETSOCKOPT_SO_SNDTIMEO
+#
+# OVERVIEW
+#
+#   Check if setsockopt can use the SO_SNDTIMEO option.
+#   This defines HAVE_SO_SNDTIMEO if setsockopt works with SO_SNDTIMEO.
+#
+AC_DEFUN([AMANDA_FUNC_SETSOCKOPT_SO_SNDTIMEO],
+    [
+       AC_REQUIRE([AC_HEADER_TIME])
+       AC_CHECK_HEADERS(
+           time.h
+           sys/time.h
+       )
+
+       AC_CACHE_CHECK(
+           [for setsockopt SO_SNDTIMEO option],
+           amanda_cv_setsockopt_SO_SNDTIMEO,
+           [
+               AC_TRY_RUN(
+                   [
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifdef TIME_WITH_SYS_TIME
+#  include <sys/time.h>
+#  include <time.h>
+#else
+#  ifdef HAVE_SYS_TIME_H
+#    include <sys/time.h>
+#  else
+#    include <time.h>
+#  endif
+#endif
+
+main() {
+#ifdef SO_SNDTIMEO
+    int sock = socket(AF_INET, SOCK_STREAM, 0);
+    struct timeval timeout;
+    timeout.tv_sec = 1;
+    timeout.tv_usec = 0;
+    return (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
+             (void *)&timeout, sizeof(timeout)));
+#else
+    return -1;
+#endif
+}
+                   ],
+                   amanda_cv_setsockopt_SO_SNDTIMEO=yes,
+                   amanda_cv_setsockopt_SO_SNDTIMEO=no,
+                   amanda_cv_setsockopt_SO_SNDTIMEO=no
+               )
+           ]
+       )
+       if test "$amanda_cv_setsockopt_SO_SNDTIMEO" = yes; then
+           AC_DEFINE(HAVE_SO_SNDTIMEO,1,[Define if SO_SNDTIMEO is available. ])
+       fi
+    ]
+)
+
+# SYNOPSIS
+#
+#   AMANDA_FUNC_GETTIMEOFDAY_ARGS
+#
+# OVERVIEW
+#
+#   Check for the one or two argument version of gettimeofday.  DEFINEs
+#   HAVE_TWO_ARG_GETTIMEOFDAY if the two argument version is present.
+#
+AC_DEFUN([AMANDA_FUNC_GETTIMEOFDAY_ARGS],
+    [
+       AC_REQUIRE([AC_HEADER_TIME])
+       AC_CHECK_HEADERS(
+           time.h
+           sys/time.h
+       )
+
+       AC_CACHE_CHECK(
+           [for gettimeofday number of arguments],
+           amanda_cv_gettimeofday_args,
+           [
+               AC_TRY_COMPILE(
+                   [
+#ifdef TIME_WITH_SYS_TIME
+#  include <sys/time.h>
+#  include <time.h>
+#else
+#  ifdef HAVE_SYS_TIME_H
+#    include <sys/time.h>
+#  else
+#    include <time.h>
+#  endif
+#endif
+                   ],
+                   [
+                       struct timeval val;
+                       struct timezone zone;
+                       gettimeofday(&val, &zone);
+                   ],
+                   amanda_cv_gettimeofday_args=2,
+                   amanda_cv_gettimeofday_args=1
+               )
+           ]
+       )
+       if test "$amanda_cv_gettimeofday_args" = 2; then
+           AC_DEFINE(HAVE_TWO_ARG_GETTIMEOFDAY,1,[Define if gettimeofday takes two arguments. ])
+       fi
+    ]
+)
+
+# SYNOPSIS
+#
+#   ICE_CHECK_DECL (FUNCTION, HEADER-FILE...)
+#
+# OVERVIEW
+#
+#   If FUNCTION is available, define `HAVE_FUNCTION'.  If it is declared
+#   in one of the headers named in the whitespace-separated list 
+#   HEADER_FILE, define `HAVE_FUNCTION_DECL` (in all capitals).
+#
+AC_DEFUN([ICE_CHECK_DECL],
+[
+ice_have_$1=no
+AC_CHECK_FUNCS($1, ice_have_$1=yes)
+if test "${ice_have_$1}" = yes; then
+AC_MSG_CHECKING(for $1 declaration in $2)
+AC_CACHE_VAL(ice_cv_have_$1_decl,
+[
+ice_cv_have_$1_decl=no
+changequote(,)dnl
+ice_re_params='[a-zA-Z_][a-zA-Z0-9_]*'
+ice_re_word='(^|[^a-zA-Z0-9_])'
+changequote([,])dnl
+for header in $2; do
+# Check for ordinary declaration
+AC_EGREP_HEADER([${ice_re_word}$1[     ]*\(], $header, 
+       ice_cv_have_$1_decl=yes)
+if test "$ice_cv_have_$1_decl" = yes; then
+       break
+fi
+# Check for "fixed" declaration like "getpid _PARAMS((int))"
+AC_EGREP_HEADER([${ice_re_word}$1[     ]*$ice_re_params\(\(], $header, 
+       ice_cv_have_$1_decl=yes)
+if test "$ice_cv_have_$1_decl" = yes; then
+       break
+fi
+done
+])
+AC_MSG_RESULT($ice_cv_have_$1_decl)
+if test "$ice_cv_have_$1_decl" = yes; then
+AC_DEFINE_UNQUOTED([HAVE_]translit($1,[a-z],[A-Z])[_DECL],1,[Define if $1 is declared. ])
+fi
+fi
+])dnl
+
+# SYNOPSIS
+#
+#   AMANDA_FUNC_SETPGID
+#
+# OVERVIEW
+#
+#   Search for the function HAVE_SETPGID, and run an ICE_CHECK_DECL on it if so.
+#
+AC_DEFUN([AMANDA_FUNC_SETPGID],
+[
+    AC_CHECK_FUNC(setpgid, [
+       AC_DEFINE(HAVE_SETPGID,1,[Define if setpgid() is available. ])
+       ICE_CHECK_DECL(setpgid,sys/types.h unistd.h)
+    ])
+])
diff --git a/config/amanda/getfsent.m4 b/config/amanda/getfsent.m4
new file mode 100644 (file)
index 0000000..a45d75e
--- /dev/null
@@ -0,0 +1,19 @@
+# SYNOPSIS
+#
+#   AMANDA_SETUP_GETFSENT
+#
+# OVERVIEW
+#
+#   Checks for support for client-src/getfsent.c
+#
+AC_DEFUN([AMANDA_SETUP_GETFSENT], [
+    AC_CHECK_HEADERS(
+       fstab.h \
+       mntent.h \
+       mnttab.h \
+       sys/vfstab.h \
+    )
+
+    AC_CHECK_FUNCS(endmntent)
+    AC_CHECK_FUNCS(setmntent)
+])
diff --git a/config/amanda/i18n.m4 b/config/amanda/i18n.m4
new file mode 100644 (file)
index 0000000..fc55d70
--- /dev/null
@@ -0,0 +1,26 @@
+# SYNOPSIS
+#
+#   AMANDA_SETUP_I18N
+#
+# OVERVIEW
+#
+#   Set up Amanda's internationalization support.  Note that configure.in
+#   itself must contain (not indented):
+#
+#   AM_GNU_GETTEXT_VERSION([0.15])
+#   AM_GNU_GETTEXT([external])
+#
+AC_DEFUN([AMANDA_SETUP_I18N], [
+    # FreeBSD needs to link libxpg4
+    AC_CHECK_LIB(xpg4, setlocale)
+
+    # ------------------------------------------------------------------
+    # All list of languages for which a translation exist. Each
+    #  language is separated by a space.
+    # ------------------------------------------------------------------
+    ALL_LINGUAS=""
+
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(MSGFMT, msgfmt,,$LOCSYSPATH)
+    AC_PATH_PROG(GETTEXT,gettext,,$LOCSYSPATH)
+])
diff --git a/config/amanda/ipv6.m4 b/config/amanda/ipv6.m4
new file mode 100644 (file)
index 0000000..c3c1776
--- /dev/null
@@ -0,0 +1,151 @@
+#
+# Checks to see if there's a sockaddr_storage structure
+#
+# usage:
+#
+#      AMANDA_SOCKADDR_STORAGE
+#
+# results:
+#
+#      HAVE_SOCKADDR_STORAGE (defined)
+#
+AC_DEFUN([AMANDA_SOCKADDR_STORAGE],
+[
+    AC_CACHE_CHECK([if sockaddr_storage struct exists],
+       ac_cv_has_sockaddr_storage,
+    [
+       AC_TRY_COMPILE([
+#      include <sys/types.h>
+#      include <sys/socket.h>],
+       [u_int i = sizeof (struct sockaddr_storage)],
+       ac_cv_has_sockaddr_storage=yes,
+       ac_cv_has_sockaddr_storage=no)
+    ])
+
+    if test $ac_cv_has_sockaddr_storage = yes ; then
+       AC_DEFINE(HAVE_SOCKADDR_STORAGE,1,
+           [struct sockaddr_storage exists])
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_CHECK_IPV6
+#
+# DESCRIPTION
+#
+#   Determine if this system has basic IPv6 support.  This 
+#   addresse general availability (defining WORKING_IPV6 if
+#   there's some amount of compatibility there), as well as
+#   searching for specific functionality by requiring the other
+#   macros in this file.
+#   
+AC_DEFUN([AMANDA_CHECK_IPV6],
+[
+    AC_REQUIRE([AMANDA_SOCKADDR_STORAGE])
+
+    WORKING_IPV6=no
+    AC_ARG_WITH(ipv6,
+       AS_HELP_STRING([--with-ipv6],
+                      [enable IPv6 support (default if IPv6 is found)])
+       AS_HELP_STRING([--without-ipv6],
+                      [disable IPv6]),
+       [
+           case "$withval" in
+           y | ye | yes) amanda_with_ipv6=yes;;
+           n | no) amanda_with_ipv6=no;;
+           *)
+               AC_MSG_ERROR([*** You must not supply an argument to --with-ipv6 option.])
+             ;;
+           esac
+       ], [
+           amanda_with_ipv6=maybe
+       ]
+    )
+
+    if test x"$amanda_with_ipv6" = x"yes" ||
+       test x"$amanda_with_ipv6" = x"maybe" ; then
+       AC_CACHE_CHECK([for working IPv6],
+                      amanda_cv_working_ipv6,
+       [
+           case "$target" in
+               *-pc-cygwin) amanda_cv_working_ipv6=no;;
+               *)
+                   AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+#include <sys/socket.h>
+#include <errno.h>
+
+main()
+{
+   int aa;
+   aa = socket(AF_INET6, SOCK_STREAM, 0);
+   if (aa > 0) return 0;
+   return aa;
+}]])],
+    [ amanda_cv_working_ipv6=yes ],
+    [ amanda_cv_working_ipv6=no ],
+    [ amanda_cv_working_ipv6=yes ]
+               )
+           esac
+       ])
+
+       if test "$amanda_cv_working_ipv6" = yes; then
+           WORKING_IPV6=yes
+           AC_DEFINE(WORKING_IPV6,1,
+               [Target system has functional IPv6 support])
+       else
+           # error out only if the user specifically requested support
+           if test x"$amanda_with_ipv6" = x"yes"; then
+               AC_MSG_ERROR([IPv6 support was requested, but it is not working.])
+           fi
+       fi
+    fi
+])
+
+#
+# Checks to see if there's a sockaddr_storage structure
+#
+# usage:
+#
+#      AC_SOCKADDR_STORAGE
+#
+# results:
+#
+#      HAVE_SOCKADDR_STORAGE (defined)
+#
+AC_DEFUN([AC_SOCKADDR_STORAGE],
+    [AC_MSG_CHECKING(if sockaddr_storage struct exists)
+    AC_CACHE_VAL(ac_cv_has_sockaddr_storage,
+       AC_TRY_COMPILE([
+#      include <sys/types.h>
+#      include <sys/socket.h>],
+       [u_int i = sizeof (struct sockaddr_storage)],
+       ac_cv_has_sockaddr_storage=yes,
+       ac_cv_has_sockaddr_storage=no))
+    AC_MSG_RESULT($ac_cv_has_sockaddr_storage)
+    if test $ac_cv_has_sockaddr_storage = yes ; then
+           AC_DEFINE(HAVE_SOCKADDR_STORAGE,1,[if struct sockaddr_storage exists])
+    fi])
+
+# SYNOPSIS
+#
+#   AMANDA_SHOW_IPV6_SUMMARY
+#
+# OVERVIEW
+#
+#   Show a summary of the settings from this file.
+#
+AC_DEFUN([AMANDA_SHOW_IPV6_SUMMARY],
+[
+    echo "Working IPv6:" $WORKING_IPV6
+])
diff --git a/config/amanda/krb4-security.m4 b/config/amanda/krb4-security.m4
new file mode 100644 (file)
index 0000000..68f5416
--- /dev/null
@@ -0,0 +1,234 @@
+# SYNOPSIS
+#
+#   AMANDA_KRB4_SECURITY
+#
+# OVERVIEW
+#
+#   Handle configuration for KRB4 security, implementing the --with-krb4-security
+#   option.  If libraries are found, they are added to the relevant compiler flags.
+#
+#   Defines KRB4_SECURITY, and sets AM_CONDITIONAL WANT_KRB4_SECURITY,
+#   if the user has selected this mechanism.  Also, the following parameters
+#   are taken from options and defined:
+#
+#    - SERVER_HOST_PRINCIPAL
+#    - SERVER_HOST_INSTANCE
+#    - SERVER_HOST_KEY_FILE
+#    - CLIENT_HOST_PRINCIPAL
+#    - CLIENT_HOST_INSTANCE
+#    - CLIENT_HOST_KEY_FILE
+#    - TICKET_LIFETIME
+#
+AC_DEFUN([AMANDA_KRB4_SECURITY],
+[
+    # Specify --with-krb4-security if Kerberos software is in somewhere
+    # other than the listed KRB4_SPOTS.  We only compile kerberos support in
+    # if the right files are there.
+
+    : ${KRB4_SPOTS="/usr/kerberos /usr/cygnus /usr /opt/kerberos"}
+
+    KRB4_SECURITY="no"
+    AC_ARG_WITH(krb4-security,
+        AS_HELP_STRING([--with-krb4-security=DIR],
+            [Location of Kerberos software @<:@/usr/kerberos /usr/cygnus /usr /opt/kerberos@:>@]),
+        [
+            case "$withval" in
+                n | no) ;;
+                y | ye | yes) KRB4_SECURITY="yes" ;;
+                *) KRB4_SPOTS="$KRB4_SECURITY"
+                   KRB4_SECURITY="yes"
+                   ;;
+            esac
+        ],
+    )
+
+    # check the remaining, subsidiary options
+
+    AC_MSG_CHECKING([host principal])
+    AC_ARG_WITH(server-principal,
+        AS_HELP_STRING([ --with-server-principal=ARG],
+            [server host principal ("amanda")]),
+        [
+            case "$withval" in
+                "" | y | ye | yes | n | no)
+                    AC_MSG_ERROR([*** You must supply an argument to the --with-server-principal option.])
+                  ;;
+                *) SERVER_HOST_PRINCIPAL="$withval" ;;
+            esac
+        ],
+        [ : ${SERVER_HOST_PRINCIPAL="amanda"} ]
+    )
+    AC_MSG_RESULT($SERVER_HOST_PRINCIPAL)
+
+    AC_MSG_CHECKING([server host instance])
+    AC_ARG_WITH(server-instance,
+        AS_HELP_STRING([ --with-server-instance=ARG],
+            [server host instance ("amanda")]),
+        [
+            case "$withval" in
+                "" | y | ye | yes | n | no)
+                    AC_MSG_ERROR([*** You must supply an argument to the --with-server-instance option.])
+                  ;;
+                *) SERVER_HOST_INSTANCE="$withval" ;;
+            esac
+        ],
+        [ : ${SERVER_HOST_INSTANCE="amanda"} ]
+    )
+    AC_MSG_RESULT($SERVER_HOST_INSTANCE)
+
+    AC_MSG_CHECKING([server host key file])
+    AC_ARG_WITH(server-keyfile,
+        AS_HELP_STRING([ --with-server-keyfile=ARG],
+            [server host key file ("/.amanda")]),
+        [
+            case "$withval" in
+                "" | y | ye | yes | n | no)
+                    AC_MSG_ERROR([*** You must supply an argument to the --with-server-keyfile option.])
+                  ;;
+                *) SERVER_HOST_KEY_FILE="$withval" ;;
+            esac
+        ],
+        [ : ${SERVER_HOST_KEY_FILE="/.amanda"} ]
+    )
+    AC_MSG_RESULT($SERVER_HOST_KEY_FILE)
+
+    AC_MSG_CHECKING(client host principle)
+    AC_ARG_WITH(client-principal,
+        AS_HELP_STRING([ --with-client-principal=ARG],
+            [client host principle ("rcmd")]),
+        [
+            case "$withval" in
+                "" | y | ye | yes | n | no)
+                    AC_MSG_ERROR([*** You must supply an argument to the --with-client-principal option.])
+                  ;;
+                *) CLIENT_HOST_PRINCIPAL="$withval" ;;
+            esac
+        ],
+        [ : ${CLIENT_HOST_PRINCIPAL="rcmd"} ]
+    )
+    AC_MSG_RESULT($CLIENT_HOST_PRINCIPAL)
+
+    AC_MSG_CHECKING([client host instance])
+    AC_ARG_WITH(client-instance,
+        AS_HELP_STRING([ --with-client-instance=ARG],
+            [client host instance (HOSTNAME_INSTANCE)]),
+        [
+            case "$withval" in
+                "" | y | ye | yes | n | no)
+                    AC_MSG_ERROR([*** You must supply an argument to the --with-client-instance option.])
+                  ;;
+                *) CLIENT_HOST_INSTANCE="$withval" ;;
+            esac
+        ],
+        [ : ${CLIENT_HOST_INSTANCE=HOSTNAME_INSTANCE} ]
+    )
+    AC_MSG_RESULT($CLIENT_HOST_INSTANCE)
+
+    AC_MSG_CHECKING([client host key file])
+    AC_ARG_WITH(client-keyfile,
+        AS_HELP_STRING([ --with-client-keyfile=ARG],
+            [client host key file (KEYFILE)]),
+        [
+            case "$withval" in
+                "" | y | ye | yes | n | no)
+                    AC_MSG_ERROR([*** You must supply an argument to the --with-client-keyfile option.])
+                  ;;
+                *) CLIENT_HOST_KEY_FILE="$withval" ;;
+            esac
+        ],
+        [ : ${CLIENT_HOST_KEY_FILE=KEYFILE} ]
+    )
+    # Assume it's either KEYFILE (defined in krb.h), or a string filename...
+    if test "x$CLIENT_HOST_KEY_FILE" != "xKEYFILE"; then
+      # add quotes
+      CLIENT_HOST_KEY_FILE="\"$CLIENT_HOST_KEY_FILE\""
+    fi
+    AC_MSG_RESULT($CLIENT_HOST_KEY_FILE)
+
+    AC_MSG_CHECKING([ticket lifetime])
+    AC_ARG_WITH(ticket-lifetime,
+        AS_HELP_STRING([ --ticket-lifetime],
+            [ticket lifetime (128)]),
+        [
+            case "$withval" in
+            "" | y | ye | yes | n | no)
+                AC_MSG_ERROR([*** You must supply an argument to the --with-ticket-lifetime option.])
+              ;;
+            *) TICKET_LIFETIME="$withval" ;;
+            esac
+        ],
+        [ : ${TICKET_LIFETIME=128} ]
+    )
+    AC_MSG_RESULT($TICKET_LIFETIME)
+
+
+    if test "x${KRB4_SECURITY}" = "xyes"; then
+        AC_MSG_CHECKING(for Kerberos and Amanda kerberos4 bits)
+        found="no"
+        for dir in $KRB4_SPOTS; do
+            if test \( -f ${dir}/lib/libkrb.a -o -f ${dir}/lib/libkrb.so \) -a \( -f ${dir}/lib/libdes.a -o -f ${dir}/lib/libdes.so \) ; then
+                #
+                # This is the original Kerberos 4.
+                #
+                AC_MSG_RESULT(found in $dir)
+                found="yes"
+
+                #
+                # This handles BSD/OS.
+                #
+                if test -d $dir/include/kerberosIV ; then
+                    AMANDA_ADD_CPPFLAGS([-I$dir/include/kerberosIV])
+                else
+                    AMANDA_ADD_CPPFLAGS([-I$dir/include])
+                fi
+                AMANDA_ADD_LDFLAGS([-L$dir/lib])
+                AMANDA_ADD_LIBS([-lkrb -ldes])
+                if test -f ${dir}/lib/libcom_err.a; then
+                    AMANDA_ADD_LIBS([-lcom_err])
+                fi
+                break
+            elif test \( -f ${dir}/lib/libkrb4.a -o -f ${dir}/lib/libkrb4.so \) &&
+                 test \( -f ${dir}/lib/libcrypto.a -o -f ${dir}/lib/libcrypto.so \) &&
+                 test \( -f ${dir}/lib/libdes425.a -o -f ${dir}/lib/libdes425.so \) ; then
+                #
+                # This is Kerberos 5 with Kerberos 4 back-support.
+                #
+                AC_MSG_RESULT(found in $dir)
+                found="yes"
+                AMANDA_ADD_CPPFLAGS([-I$dir/include -I$dir/include/kerberosIV])
+                AMANDA_ADD_LDFLAGS([-L$dir/lib])
+                if test \( -f ${dir}/lib/libkrb5.a -o -f ${dir}/lib/libkrb5.so \) &&
+                   test \( -f ${dir}/lib/libcom_err.a -o -f ${dir}/lib/libcom_err.so \) ; then
+                    AMANDA_ADD_LIBS([-lkrb4 -lkrb5 -lcrypto -ldes425 -lcom_err])
+                else
+                    AMANDA_ADD_LIBS([-lkrb4 -lcrypto -ldes425])
+                fi
+                break
+            fi
+        done
+
+        if test "x$found" = "xno" ; then
+            AC_MSG_RESULT(no libraries found)
+            AMANDA_MSG_WARN([No Kerberos IV libraries were found on your system; disabling krb4-security])
+            KRB4_SECURITY="no"
+        else
+            AC_DEFINE(KRB4_SECURITY, 1, 
+                [Enable Kerberos IV security.])
+            AC_DEFINE_UNQUOTED(SERVER_HOST_PRINCIPAL,"$SERVER_HOST_PRINCIPAL",
+                    [The Kerberos server principal. ])
+            AC_DEFINE_UNQUOTED(SERVER_HOST_INSTANCE,"$SERVER_HOST_INSTANCE",
+                    [The Kerberos server instance. ])
+            AC_DEFINE_UNQUOTED(SERVER_HOST_KEY_FILE,"$SERVER_HOST_KEY_FILE",
+                    [The Kerberos server key file. ])
+            AC_DEFINE_UNQUOTED(CLIENT_HOST_PRINCIPAL,"$CLIENT_HOST_PRINCIPAL",
+                    [The Kerberos client host principal. ])
+            AC_DEFINE_UNQUOTED(CLIENT_HOST_INSTANCE,$CLIENT_HOST_INSTANCE,
+                    [The Kerberos client host instance. ])
+            AC_DEFINE_UNQUOTED(CLIENT_HOST_KEY_FILE,$CLIENT_HOST_KEY_FILE,
+                    [The Kerberos client host key file. ])
+            AC_DEFINE_UNQUOTED(TICKET_LIFETIME,$TICKET_LIFETIME,
+                    [The Kerberos ticket lifetime. ])
+        fi
+    fi
+    AM_CONDITIONAL(WANT_KRB4_SECURITY, test x"$KRB4_SECURITY" = x"yes")
+])
diff --git a/config/amanda/krb5-security.m4 b/config/amanda/krb5-security.m4
new file mode 100644 (file)
index 0000000..1cf0d7a
--- /dev/null
@@ -0,0 +1,105 @@
+# SYNOPSIS
+#
+#   AMANDA_KRB5_SECURITY
+#
+# OVERVIEW
+#
+#   Handle configuration for KRB5 security, implementing the --with-krb5-security
+#   option.  If libraries are found, they are added to the relevant compiler flags.
+#
+#   Defines KRB5_SECURITY, and sets AM_CONDITIONAL WANT_KRB5_SECURITY,
+#   if the user has selected this mechanism.  Also, the following parameters
+#   are taken from options and defined:
+#
+#    - SERVER_HOST_PRINCIPAL
+#    - SERVER_HOST_INSTANCE
+#    - SERVER_HOST_KEY_FILE
+#    - CLIENT_HOST_PRINCIPAL
+#    - CLIENT_HOST_INSTANCE
+#    - CLIENT_HOST_KEY_FILE
+#    - TICKET_LIFETIME
+#
+AC_DEFUN([AMANDA_KRB5_SECURITY],
+[
+    # Specify --with-krb5-security if Kerberos software is in somewhere
+    # other than the listed KRB5_SPOTS.  We only compile kerberos support in
+    # if the right files are there.
+
+    KRB5_SECURITY="no"
+    : ${KRB5_SPOTS="/usr/kerberos /usr/cygnus /usr /opt/kerberos"}
+
+    AC_ARG_WITH(krb5-security,
+        AS_HELP_STRING([--with-krb5-security=DIR],
+            [Location of Kerberos V software @<:@/usr/kerberos /usr/cygnus /usr /opt/kerberos@:>@]),
+        [
+            case "$withval" in
+                n | no) KRB5_SECURITY=no ;;
+                y | ye | yes) KRB5_SECURITY=yes ;;
+                *) KRB5_SPOTS="$KRB5_SECURITY"
+                   KRB5_SECURITY=yes
+                   ;;
+            esac
+        ]
+    )
+
+    if test "x$KRB5_SECURITY" = "xyes"; then
+        # if found, force the static versions of these libs (.a) by linking directly
+        # with the .a files.  I don't know how to get -R dependancies checked
+        # in autoconf at this time. -kashmir
+        AC_MSG_CHECKING(for Kerberos V libraries)
+        KRB5_DIR_FOUND=""
+        for dir in $KRB5_SPOTS; do
+          for lib in lib lib64; do
+            k5libdir=${dir}/${lib}
+            if test \( -f ${k5libdir}/libkrb5.a -o -f ${k5libdir}/libkrb5.so \) -a \( -f ${k5libdir}/libgssapi_krb5.so -o -f ${k5libdir}/libgssapi_krb5.a \) -a \( -f ${k5libdir}/libcom_err.a -o -f ${k5libdir}/libcom_err.so \); then
+                if test -f ${k5libdir}/libk5crypto.a -o -f ${k5libdir}/libk5crypto.so; then
+                    K5CRYPTO=-lk5crypto
+                elif test -f ${k5libdir}/libcrypto.a -o -f ${k5libdir}/libcrypto.so; then
+                    K5CRYPTO=-lcrypto
+                else
+                    K5CRYPTO=""
+                fi
+                if test -f ${k5libdir}/libkrb5support.a -o -f ${k5libdir}/libkrb5support.so; then
+                    K5SUPPORT=-lkrb5support
+                else
+                    K5SUPPORT=""
+                fi
+                KRB5_DIR_FOUND=$dir
+                KRB5_LIBDIR_FOUND=$k5libdir
+                AMANDA_ADD_LIBS([-lgssapi_krb5 -lkrb5 $K5CRYPTO $K5SUPPORT -lcom_err])
+                break
+            elif test \( -f ${k5libdir}/libkrb5.a -o -f ${k5libdir}/libkrb5.so \) -a \( -f ${k5libdir}/libasn1.a -o -f ${k5libdir}/libasn1.so \) -a \( -f ${k5libdir}/libgssapi.a -o -f ${k5libdir}/libgssapi.so \); then
+                AMANDA_ADD_LIBS([-lgssapi -lkrb5 -lasn1])
+                AMANDA_ADD_CPPFLAGS([-DKRB5_HEIMDAL_INCLUDES])
+                break
+            fi
+          done
+        done
+
+        if test "$KRB5_DIR_FOUND"; then
+            AC_MSG_RESULT(found in $KRB5_DIR_FOUND)
+            #
+            # some OS's, such as NetBSD, stick krb5 includes out of the way...
+            # should probably just use autoconf to look for various include
+            # options and set them, but don't quite want to do that until I've
+            # dug into it a bit more.
+            #
+            if test -d "$KRB5_DIR_FOUND/krb5" ; then
+                AMANDA_ADD_CPPFLAGS([-I$KRB5_DIR_FOUND/include/krb5])
+            else
+                AMANDA_ADD_CPPFLAGS([-I$KRB5_DIR_FOUND/include])
+            fi
+                AC_CHECK_LIB(krb5support,main)
+            AMANDA_ADD_LDFLAGS([-L$KRB5_LIBDIR_FOUND])
+
+            AC_DEFINE(KRB5_SECURITY,1,
+                [Define if Kerberos 5 security is to be enabled. ])
+        else
+            AC_MSG_RESULT(no krb5 system libraries found)
+            AC_MSG_ERROR([No Kerberos V libraries were found on your system; krb5-security cannot be enabled])
+            KRB5_SECURITY="no"
+        fi
+    fi
+
+    AM_CONDITIONAL(WANT_KRB5_SECURITY, test x"$KRB5_SECURITY" = x"yes")
+])
diff --git a/config/amanda/lfs.m4 b/config/amanda/lfs.m4
new file mode 100644 (file)
index 0000000..0de6a66
--- /dev/null
@@ -0,0 +1,75 @@
+# SYNOPSIS
+#
+#   AMANDA_SETUP_LFS
+#
+# OVERVIEW
+#
+#   Set up for large file suport on this system.  Besides adding compiler flags,
+#   defines NEED_RESETOFS if the tape device's offset must be reset before it reaches
+#   2GB (a Linux kernel bug in systems without LFS support).
+#
+AC_DEFUN([AMANDA_SETUP_LFS],
+[
+    AC_REQUIRE([AMANDA_PROG_GETCONF])
+    AC_REQUIRE([AC_SYS_LARGEFILE])
+
+    # we use 'getconf', if it exists, to get the relevant
+    # compiler flags.
+    GETCONF_LFS="LFS"
+    case "$target" in
+        *-hp-*) GETCONF_LFS="XBS5_ILP32_OFFBIG" ;;
+        *-ibm-aix*) GETCONF_LFS="XBS5_ILP32_OFFBIG" ;;
+    esac
+
+    # Checks for compilers, typedefs, structures, and compiler characteristics.
+    # Check for large file compilation environment.
+    NEED_RESETOFS=yes
+    AC_CACHE_CHECK([for large file compilation CFLAGS],
+        amanda_cv_LFS_CFLAGS,
+        [
+        amanda_cv_LFS_CFLAGS=
+        if test "$GETCONF"; then
+            if $GETCONF ${GETCONF_LFS}_CFLAGS >/dev/null 2>&1; then
+                amanda_cv_LFS_CFLAGS=`$GETCONF ${GETCONF_LFS}_CFLAGS 2>/dev/null`
+                NEED_RESETOFS=no
+            fi
+        fi
+        ]
+    )
+    AMANDA_ADD_CFLAGS([$amanda_cv_LFS_CFLAGS])
+
+    AC_CACHE_CHECK(
+        [for large file compilation LDFLAGS],
+        amanda_cv_LFS_LDFLAGS,
+        [
+        amanda_cv_LFS_LDFLAGS=
+        if test "$GETCONF"; then
+            if $GETCONF ${GETCONF_LFS}_LDFLAGS >/dev/null 2>&1; then
+                amanda_cv_LFS_LDFLAGS=`$GETCONF ${GETCONF_LFS}_LDFLAGS 2>/dev/null`
+                NEED_RESETOFS=no
+            fi
+        fi
+        ]
+    )
+    AMANDA_ADD_LDFLAGS([$amanda_cv_LFS_LDFLAGS])
+
+    AC_CACHE_CHECK(
+        [for large file compilation LIBS],
+        amanda_cv_LFS_LIBS,
+        [
+        amanda_cv_LFS_LIBS=
+        if test "$GETCONF"; then
+            if $GETCONF ${GETCONF_LFS}_LIBS >/dev/null 2>&1; then
+                amanda_cv_LFS_LIBS=`$GETCONF ${GETCONF_LFS}_LIBS 2>/dev/null`
+                NEED_RESETOFS=no
+            fi
+        fi
+        ]
+    )
+    AMANDA_ADD_LIBS([$amanda_cv_LFS_LIBS])
+
+    if test x"$NEED_RESETOFS" = x"yes"; then
+        AC_DEFINE(NEED_RESETOFS,1,
+            [Define if we have to reset tape offsets when reaching 2GB. ])
+    fi
+])
diff --git a/config/amanda/libs.m4 b/config/amanda/libs.m4
new file mode 100644 (file)
index 0000000..4bf2bc2
--- /dev/null
@@ -0,0 +1,377 @@
+# OVERVIEW
+#
+#   This file contains macros that search for specific libraries that are
+#   required or utilized by Amanda.
+
+# SYNOPSIS
+#
+#   AMANDA_CHECK_LIBCURL
+#
+# OVERVIEW
+#
+#   Check for LIBCURL support.  Sets the shell variable HAVE_CURL to "yes" or
+#   "no" depending on the result of the test.  If CURL is found, the necessary
+#   compiler flags are added, and a few other type checks are performed.
+#
+#   Note that libcurl itself defines a number of useful symbols as well; see
+#   the libcurl distribution for details.
+#
+AC_DEFUN([AMANDA_CHECK_LIBCURL], [
+    case "$target" in
+        sparc-sun-solaris2.10) # Solaris 10
+        # curl is not in the LD_LIBRARY_PATH on Solaris 10, so we search
+        # for it in a few common paths; we then extract the -L flags and
+        # translate them to -R flags, as required by the runtime linker.
+        AC_PATH_PROG(CURL_CONFIG, curl-config, [], $LOCSYSPATH:/opt/csw/bin:/usr/local/bin:/opt/local/bin)
+        if test -n "$CURL_CONFIG"; then
+            curlflags=`$CURL_CONFIG --libs 2>/dev/null`
+            for flag in curlflags; do
+                case $flag in
+                    -L*) LDFLAGS="$LDFLAGS "`echo "x$flag" | sed -e 's/^x-L/-R/'`;;
+                esac
+            done
+        fi
+        ;;
+    esac
+
+    LIBCURL_CHECK_CONFIG(yes, 7.10.0, HAVE_CURL=yes, HAVE_CURL=no)
+    if test x"$HAVE_CURL" = x"yes"; then
+       AMANDA_ADD_LIBS($LIBCURL)
+       AMANDA_ADD_CPPFLAGS($LIBCURL_CPPFLAGS)
+
+       AMANDA_CHECK_TYPE([curl_off_t], [off_t], [curl/curl.h])
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_CHECK_HMAC
+#
+# OVERVIEW
+#
+#   Check for HMAC support in -lcrypto.  If found, the shell
+#   variable HAVE_HMAC will be set to 'yes'.  The appropriate one of
+#   HAVE_OPENSSL_HMAC_H, HAVE_CRYPTO_HMAC_H, and HAVE_HMAC_H are also
+#   defined via AC_CHECK_HEADERS.
+#
+AC_DEFUN([AMANDA_CHECK_HMAC], [
+    HAVE_HMAC=yes
+    AC_CHECK_LIB([crypto], [HMAC_CTX_init], [], [HAVE_HMAC=no])
+
+    found_hmac_h=no
+    AC_CHECK_HEADERS([openssl/hmac.h crypto/hmac.h hmac.h],
+                   [found_hmac_h=yes; break])
+    if test x"$found_hmac_h" != x"yes"; then
+       HAVE_HMAC=no
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_CHECK_NET_LIBS
+#
+# OVERIVEW
+#
+#   Check for the libraries we'll need to use sockets, etc.
+#
+AC_DEFUN([AMANDA_CHECK_NET_LIBS], [
+    # Make sure we don't use -lnsl and -lsun on Irix systems.
+    case "$target" in
+       *sgi-irix*)
+                           AC_CHECK_LIB(socket,main)
+                           ;;
+       *)
+                           AC_CHECK_LIB(resolv,main)
+                           AC_CHECK_LIB(nsl,main)
+                           AC_CHECK_LIB(socket,main)
+                           AC_CHECK_LIB(sun,main)
+                           ;;
+    esac
+])
+
+# SYNOPSIS
+#
+#   AMANDA_CHECK_GLIB
+#
+# OVERVIEW
+#
+#   Search for glib.  This is basically a wrapper for AM_PATH_GLIB_2_0, with
+#   the addition of system-specific configuration to convince Amanda to compile
+#   "out of the box" on more boxes.
+#
+AC_DEFUN([AMANDA_CHECK_GLIB], [
+    # search for pkg-config, which the glib configuration uses, adding a few
+    # system-specific search paths.
+    AC_PATH_PROG(PKG_CONFIG, pkg-config, [], $LOCSYSPATH:/opt/csw/bin:/usr/local/bin:/opt/local/bin)
+
+    case "$target" in
+       sparc-sun-solaris2.8) # Solaris 8
+           # give the linker a runtime search path; pkg-config doesn't supply this.
+           # Users could also specify this with LD_LIBRARY_PATH to both ./configure
+           # and make.  Adding this support here makes straight './configure; make'
+           # "just work" on Solaris 8
+           if test -n "$PKG_CONFIG"; then
+               glib_R_flag=`$PKG_CONFIG glib-2.0 --libs-only-L 2>/dev/null | sed -e 's/-L/-R/g'`
+               LDFLAGS="$LDFLAGS $glib_R_flag"
+           fi
+           ;;
+    esac
+
+    AM_PATH_GLIB_2_0(2.2.0,,[
+       AC_MSG_ERROR(glib not found or too old; See http://wiki.zmanda.com/index.php/Installation for help)
+    ], gmodule gobject gthread)
+    AMANDA_ADD_CFLAGS($GLIB_CFLAGS)
+    AMANDA_ADD_CPPFLAGS($GLIB_CPPFLAGS)
+    AMANDA_ADD_LIBS($GLIB_LIBS)
+])
+
+# LIBCURL_CHECK_CONFIG is from the libcurl
+# distribution and licensed under the BSD license:
+# Copyright (c) 1996 - 2007, Daniel Stenberg, <daniel@haxx.se>.
+#
+# All rights reserved.
+#
+# Permission to use, copy, modify, and distribute this software for any purpose
+# with or without fee is hereby granted, provided that the above copyright
+# notice and this permission notice appear in all copies.
+#
+# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION],
+#                       [ACTION-IF-YES], [ACTION-IF-NO])
+# ----------------------------------------------------------
+#      David Shaw <dshaw@jabberwocky.com>   May-09-2006
+#
+# Checks for libcurl.  DEFAULT-ACTION is the string yes or no to
+# specify whether to default to --with-libcurl or --without-libcurl.
+# If not supplied, DEFAULT-ACTION is yes.  MINIMUM-VERSION is the
+# minimum version of libcurl to accept.  Pass the version as a regular
+# version number like 7.10.1. If not supplied, any version is
+# accepted.  ACTION-IF-YES is a list of shell commands to run if
+# libcurl was successfully found and passed the various tests.
+# ACTION-IF-NO is a list of shell commands that are run otherwise.
+# Note that using --without-libcurl does run ACTION-IF-NO.
+#
+# This macro #defines HAVE_LIBCURL if a working libcurl setup is
+# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary
+# values.  Other useful defines are LIBCURL_FEATURE_xxx where xxx are
+# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy
+# where yyy are the various protocols supported by libcurl.  Both xxx
+# and yyy are capitalized.  See the list of AH_TEMPLATEs at the top of
+# the macro for the complete list of possible defines.  Shell
+# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also
+# defined to 'yes' for those features and protocols that were found.
+# Note that xxx and yyy keep the same capitalization as in the
+# curl-config list (e.g. it's "HTTP" and not "http").
+#
+# Users may override the detected values by doing something like:
+# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure
+#
+# For the sake of sanity, this macro assumes that any libcurl that is
+# found is after version 7.7.2, the first version that included the
+# curl-config script.  Note that it is very important for people
+# packaging binary versions of libcurl to include this script!
+# Without curl-config, we can only guess what protocols are available,
+# or use curl_version_info to figure it out at runtime.
+
+AC_DEFUN([LIBCURL_CHECK_CONFIG],
+[
+  AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL])
+  AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4])
+  AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6])
+  AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz])
+  AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS])
+  AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN])
+  AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI])
+  AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM])
+
+  AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
+
+  AC_ARG_WITH(libcurl,
+     AC_HELP_STRING([--with-libcurl=DIR],[look for the curl library in DIR]),
+     [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])])
+
+  if test "$_libcurl_with" != "no" ; then
+
+     AC_PROG_AWK
+
+     _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'"
+
+     _libcurl_try_link=yes
+
+     if test -d "$_libcurl_with" ; then
+        LIBCURL_CPPFLAGS="-I$withval/include"
+        _libcurl_ldflags="-L$withval/lib"
+        AC_PATH_PROG([_libcurl_config],[curl-config],["$withval/bin"],["$withval/bin"])
+     else
+        AC_PATH_PROG([_libcurl_config],[curl-config])
+     fi
+
+     if test x$_libcurl_config != "x" ; then
+        AC_CACHE_CHECK([for the version of libcurl],
+           [libcurl_cv_lib_curl_version],
+           [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
+
+        _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
+        _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
+
+        if test $_libcurl_wanted -gt 0 ; then
+           AC_CACHE_CHECK([for libcurl >= version $2],
+              [libcurl_cv_lib_version_ok],
+              [
+              if test $_libcurl_version -ge $_libcurl_wanted ; then
+                 libcurl_cv_lib_version_ok=yes
+              else
+                 libcurl_cv_lib_version_ok=no
+              fi
+              ])
+        fi
+
+        if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
+           if test x"$LIBCURL_CPPFLAGS" = "x" ; then
+              LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
+           fi
+           if test x"$LIBCURL" = "x" ; then
+              LIBCURL=`$_libcurl_config --libs`
+
+              # This is so silly, but Apple actually has a bug in their
+              # curl-config script.  Fixed in Tiger, but there are still
+              # lots of Panther installs around.
+              case "${host}" in
+                 powerpc-apple-darwin7*)
+                    LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
+                 ;;
+              esac
+           fi
+
+           # All curl-config scripts support --feature
+           _libcurl_features=`$_libcurl_config --feature`
+
+           # Is it modern enough to have --protocols? (7.12.4)
+           if test $_libcurl_version -ge 461828 ; then
+              _libcurl_protocols=`$_libcurl_config --protocols`
+           fi
+        else
+           _libcurl_try_link=no
+        fi
+
+        unset _libcurl_wanted
+     fi
+
+     if test $_libcurl_try_link = yes ; then
+
+        # we didn't find curl-config, so let's see if the user-supplied
+        # link line (or failing that, "-lcurl") is enough.
+        LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
+
+        AC_CACHE_CHECK([whether libcurl is usable],
+           [libcurl_cv_lib_curl_usable],
+           [
+           _libcurl_save_cppflags=$CPPFLAGS
+           CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
+           _libcurl_save_libs=$LIBS
+           LIBS="$LIBCURL $LIBS"
+
+           AC_LINK_IFELSE(AC_LANG_PROGRAM([#include <curl/curl.h>],[
+/* Try and use a few common options to force a failure if we are
+   missing symbols or can't link. */
+int x;
+curl_easy_setopt(NULL,CURLOPT_URL,NULL);
+x=CURL_ERROR_SIZE;
+x=CURLOPT_WRITEFUNCTION;
+x=CURLOPT_FILE;
+x=CURLOPT_ERRORBUFFER;
+x=CURLOPT_STDERR;
+x=CURLOPT_VERBOSE;
+]),libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
+
+           CPPFLAGS=$_libcurl_save_cppflags
+           LIBS=$_libcurl_save_libs
+           unset _libcurl_save_cppflags
+           unset _libcurl_save_libs
+           ])
+
+        if test $libcurl_cv_lib_curl_usable = yes ; then
+
+           # Does curl_free() exist in this version of libcurl?
+           # If not, fake it with free()
+
+           _libcurl_save_cppflags=$CPPFLAGS
+           CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+           _libcurl_save_libs=$LIBS
+           LIBS="$LIBS $LIBCURL"
+
+           AC_CHECK_FUNC(curl_free,,
+              AC_DEFINE(curl_free,free,
+                [Define curl_free() as free() if our version of curl lacks curl_free.]))
+
+           CPPFLAGS=$_libcurl_save_cppflags
+           LIBS=$_libcurl_save_libs
+           unset _libcurl_save_cppflags
+           unset _libcurl_save_libs
+
+           AC_DEFINE(HAVE_LIBCURL,1,
+             [Define to 1 if you have a functional curl library.])
+           AC_SUBST(LIBCURL_CPPFLAGS)
+           AC_SUBST(LIBCURL)
+
+           for _libcurl_feature in $_libcurl_features ; do
+              AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
+              eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
+           done
+
+           if test "x$_libcurl_protocols" = "x" ; then
+
+              # We don't have --protocols, so just assume that all
+              # protocols are available
+              _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT"
+
+              if test x$libcurl_feature_SSL = xyes ; then
+                 _libcurl_protocols="$_libcurl_protocols HTTPS"
+
+                 # FTPS wasn't standards-compliant until version
+                 # 7.11.0
+                 if test $_libcurl_version -ge 461568; then
+                    _libcurl_protocols="$_libcurl_protocols FTPS"
+                 fi
+              fi
+           fi
+
+           for _libcurl_protocol in $_libcurl_protocols ; do
+              AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
+              eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
+           done
+        else
+           unset LIBCURL
+           unset LIBCURL_CPPFLAGS
+        fi
+     fi
+
+     unset _libcurl_try_link
+     unset _libcurl_version_parse
+     unset _libcurl_config
+     unset _libcurl_feature
+     unset _libcurl_features
+     unset _libcurl_protocol
+     unset _libcurl_protocols
+     unset _libcurl_version
+     unset _libcurl_ldflags
+  fi
+
+  if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then
+     # This is the IF-NO path
+     ifelse([$4],,:,[$4])
+  else
+     # This is the IF-YES path
+     ifelse([$3],,:,[$3])
+  fi
+
+  unset _libcurl_with
+])dnl
+
diff --git a/config/amanda/net.m4 b/config/amanda/net.m4
new file mode 100644 (file)
index 0000000..f2c1805
--- /dev/null
@@ -0,0 +1,167 @@
+# OVERVIEW
+#
+#   Networking-related macros
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_FQDN
+#
+# OVERVIEW
+#
+#   Check for --with-fqdn, and DEFINE USE_FQDN if given.
+#
+AC_DEFUN([AMANDA_WITH_FQDN], [
+    AC_ARG_WITH(fqdn,
+       AS_HELP_STRING([--with-fqdn],
+                      [use FQDN's to backup multiple networks]),
+       [ USE_FQDN=$withval ], [ USE_FQDN=no ])
+
+    case "$USE_FQDN" in
+    n | no) : ;;
+    y |  ye | yes) 
+       AC_DEFINE(USE_FQDN,1,
+           [Define for backups being done on a multiple networks and FQDNs are used. ])
+      ;;
+    *) AC_MSG_ERROR([You must not supply an argument to --with-fqdn option.])
+      ;;
+    esac
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_REUSEPORTS
+#
+# OVERVIEW
+#
+#   Check for --with-reuseports, and DEFINE USE_REUSEADDR if given.
+#
+AC_DEFUN([AMANDA_WITH_REUSEPORTS], [
+    AC_ARG_WITH(reuseports,
+       AS_HELP_STRING([--without-reuseaddr],
+                      [Don't reuse network connections until full timeout period]),
+       [ case "$withval" in
+           y | ye | yes) USE_REUSEADDR=no;;
+           n | no) USE_REUSEADDR=yes;;
+           *) AC_MSG_ERROR([You must not supply an argument to --without-reuseports]);;
+         esac
+       ],
+       [ USE_REUSEADDR=yes; ])
+    if test x"$USE_REUSEADDR" = x"yes"; then
+       AC_DEFINE(USE_REUSEADDR,1,
+               [Define to set SO_REUSEADDR on network connections.])
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_PORTRANGES
+#
+# OVERVIEW
+#
+#   Implement --with-low-tcpportrange, --with-tcpportrange, and --with-udpportrange.
+#   Results are DEFINED in LOW_TCPPORTRANGE, TCPPORTRANGE, and UDPPORTRANGE, 
+#   respectively.
+#
+AC_DEFUN([AMANDA_WITH_PORTRANGES], [
+    AC_ARG_WITH(low-tcpportrange,
+       AS_HELP_STRING([--with-low-tcpportrange=low/high],
+           [bind reserved TCP server sockets to ports within this range (default: unlimited)]),
+       [ LOW_TCPPORTRANGE="$withval" ],
+       [ LOW_TCPPORTRANGE=unlimited ])
+     
+    if test x"$LOW_TCPPORTRANGE" != x"unlimited"; then
+       if test x`echo "$LOW_TCPPORTRANGE" | sed 's/[[0-9]][[0-9]]*,[[0-9]][[0-9]]*//'` != x""; then
+           AC_MSG_ERROR([--with-low-tcpportrange requires two comma-separated positive numbers])
+       fi
+       min_low_tcp_port=`echo "$LOW_TCPPORTRANGE" | sed 's/,.*//'`
+       max_low_tcp_port=`echo "$LOW_TCPPORTRANGE" | sed 's/.*,//'`
+       if test $min_low_tcp_port -gt $max_low_tcp_port; then
+           AC_MSG_ERROR([the second TCP port number must be greater than the first in --with-low-tcpportrange])
+       fi
+       if test $min_low_tcp_port -lt 512; then
+           AMANDA_MSG_WARN([the low TCP port range should be 512 or greater in --with-low-tcpportrange])
+       fi
+       if test $max_low_tcp_port -ge 1024; then
+           AMANDA_MSG_WARN([the low TCP port range should be less than 1024 in --with-low-tcpportrange])
+       fi
+       AC_DEFINE_UNQUOTED(LOW_TCPPORTRANGE,$LOW_TCPPORTRANGE,
+   [A comma-separated list of two integers, determining the minimum and maximum
+ * reserved TCP port numbers sockets should be bound to. (mainly for amrecover) ])
+    fi
+
+    AC_ARG_WITH(tcpportrange,
+       AS_HELP_STRING([--with-tcpportrange=low/high],
+           [bind unreserved TCP server sockets to ports within this range (default: unlimited)]),
+       [ TCPPORTRANGE="$withval" ],
+       [ TCPPORTRANGE="unlimited" ])
+
+    if test x"$TCPPORTRANGE" != x"unlimited"; then
+       if test x`echo "$TCPPORTRANGE" | sed 's/[[0-9]][[0-9]]*,[[0-9]][[0-9]]*//'` != x""; then
+           AC_MSG_ERROR([--with-tcpportrange requires two comma-separated positive numbers])
+       fi
+       min_tcp_port=`echo "$TCPPORTRANGE" | sed 's/,.*//'`
+       max_tcp_port=`echo "$TCPPORTRANGE" | sed 's/.*,//'`
+       if test $min_tcp_port -gt $max_tcp_port; then
+           AC_MSG_ERROR([the second TCP port number must be greater than the first in --with-tcpportrange])
+       fi
+       if test $min_tcp_port -lt 1024; then
+           AMANDA_MSG_WARN([the TCP port range should be 1024 or greater in --with-tcpportrange])
+       fi
+       if test $max_tcp_port -ge 65536; then
+           AMANDA_MSG_WARN([the TCP port range should be less than 65536 in --with-tcpportrange])
+       fi
+       AC_DEFINE_UNQUOTED(TCPPORTRANGE,$TCPPORTRANGE,
+  [A comma-separated list of two integers, determining the minimum and
+ * maximum unreserved TCP port numbers sockets should be bound to. ])
+    fi
+
+    AC_ARG_WITH(udpportrange,
+       AS_HELP_STRING([--with-udpportrange=low/high],
+           [bind reserved UDP server sockets to ports within this range (default: unlimited)]),
+       [ UDPPORTRANGE="$withval" ],
+       [ UDPPORTRANGE="unlimited" ])
+    if test x"$UDPPORTRANGE" != x"unlimited"; then
+       if test x`echo "$UDPPORTRANGE" | sed 's/[[0-9]][[0-9]]*,[[0-9]][[0-9]]*//'` != x""; then
+           AC_MSG_ERROR([--with-udpportrange requires two comma-separated positive numbers])
+       fi
+       min_udp_port=`echo "$UDPPORTRANGE" | sed 's/,.*//'`
+       max_udp_port=`echo "$UDPPORTRANGE" | sed 's/.*,//'`
+       if test $min_udp_port -gt $max_udp_port; then
+           AC_MSG_ERROR([the second UDP port number must be greater than the first in --with-udpportrange])
+       fi
+       if test $max_udp_port -ge 1024; then
+           AMANDA_MSG_WARN([the UDP port range should be less than 1025 in --with-udpportrange])
+       fi
+       if test $min_udp_port -le 0; then
+           AMANDA_MSG_WARN([the UDP port range should be greater than 0 in --with-udpportrange])
+       fi
+       AC_DEFINE_UNQUOTED(UDPPORTRANGE,$UDPPORTRANGE,
+  [A comma-separated list of two integers, determining the minimum and
+ * maximum reserved UDP port numbers sockets should be bound to. ])
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_BUFFERED_DUMP
+#
+# OVERVIEW
+#
+#   Implement --with-buffered-dump, and DEFINEs DUMPER_SOCKET_BUFFERING if the option
+#   is given.
+#
+AC_DEFUN([AMANDA_WITH_BUFFERED_DUMP], [
+    AC_ARG_WITH(buffered-dump,
+       AS_HELP_STRING([--with-buffered-dump],
+           [buffer the dumping sockets on the server for speed]),
+       [ DUMPER_SOCKET_BUFFERING=$withval ],
+       [ DUMPER_SOCKET_BUFFERING=no ])
+    case "$DUMPER_SOCKET_BUFFERING" in
+    n | no) ;;
+    y | ye | yes)
+       AC_DEFINE(DUMPER_SOCKET_BUFFERING,1,
+           [Define if dumper should buffer the sockets for faster throughput. ])
+      ;;
+    *) AC_MSG_ERROR([You must not supply an argument to --with-buffered-dump.]) ;;
+    esac
+])
diff --git a/config/amanda/progs.m4 b/config/amanda/progs.m4
new file mode 100644 (file)
index 0000000..79babba
--- /dev/null
@@ -0,0 +1,392 @@
+# OVERVIEW
+#
+#   Code to handle searches for programs Amanda needs.
+#
+#   Because Amanda uses a customized search path, many macros which are standard
+#   in autoconf have been wrapped here.  Where this is the only change, the description
+#   of those macros has been omitted.
+#
+#   All of these macros indicate their requirements using AC_REQUIRE, so the order in
+#   which they are called in configure.in is inconsequential.
+
+# SYNOPSIS
+#
+#   AMANDA_INIT_PROGS
+#
+# OVERVIEW
+#
+#   Set up some amanda-specific path directories.  This should be AC_REQUIRE()d by
+#   any macros which need to search for a program.
+#
+#   SYSPATH is a list of likely system locations for a file, while
+#   LOCPATH is a list of likely local locations.  The two are combined
+#   in different orders in SYSLOCPATH and LOCSYSPATH.
+#
+AC_DEFUN([AMANDA_INIT_PROGS],
+[
+    SYSPATH="/bin:/usr/bin:/sbin:/usr/sbin:/opt/SUNWspro/bin:/usr/ucb:/usr/sfw/bin:/usr/bsd:/etc:/usr/etc"
+    # expand prefix or exec_prefix in LOCPATH
+    LOCPATH=`(
+       test "x$prefix" = xNONE && prefix=$ac_default_prefix
+       test "x$exec_prefix" = xNONE && exec_prefix=${prefix}
+       eval echo "$libexecdir:$PATH:/usr/local/sbin:/usr/local/bin:/usr/ccs/bin"
+    )`
+    SYSLOCPATH="$SYSPATH:$LOCPATH"
+    LOCSYSPATH="$LOCPATH:$SYSPATH"
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_LINT
+#
+# OVERVIEW
+#
+#   Find a lint binary (either lint or splint) and record its name in AMLINT.
+#   Set up appropriate flags for the discovered binary in AMLINTFLAGS
+#
+AC_DEFUN([AMANDA_PROG_LINT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_REQUIRE([AMANDA_PROG_GREP])
+
+    AC_PATH_PROG(AMLINT,lint,,/opt/SUNWspro/bin:$SYSLOCPATH)
+    if test ! -z "$AMLINT"; then
+      $AMLINT -flags 2>&1 | $GREP -- '-errfmt=' > /dev/null
+      if test $? -eq 0; then
+       AMLINTFLAGS="-n -s -u -m -x"
+       AMLINTFLAGS="$AMLINTFLAGS -errchk=%all"
+       AMLINTFLAGS="$AMLINTFLAGS -errfmt=macro"
+       AMLINTFLAGS="$AMLINTFLAGS -errhdr=no%/usr/include"
+       AMLINTFLAGS="$AMLINTFLAGS -errhdr=%user"
+       AMLINTFLAGS="$AMLINTFLAGS -errsecurity=extended"
+       AMLINTFLAGS="$AMLINTFLAGS -errtags=yes"
+       AMLINTFLAGS="$AMLINTFLAGS -Ncheck=%all"
+       AMLINTFLAGS="$AMLINTFLAGS -Nlevel=2"
+       AMLINTFLAGS="$AMLINTFLAGS -erroff=E_ASGN_NEVER_USED"
+       AMLINTFLAGS="$AMLINTFLAGS,E_ASGN_RESET"
+       AMLINTFLAGS="$AMLINTFLAGS,E_CAST_INT_CONST_TO_SMALL_INT"
+       AMLINTFLAGS="$AMLINTFLAGS,E_CAST_INT_TO_SMALL_INT"
+       AMLINTFLAGS="$AMLINTFLAGS,E_CAST_UINT_TO_SIGNED_INT"
+       AMLINTFLAGS="$AMLINTFLAGS,E_CONSTANT_CONDITION"
+       AMLINTFLAGS="$AMLINTFLAGS,E_ENUM_UNUSE"
+       AMLINTFLAGS="$AMLINTFLAGS,E_EXPR_NULL_EFFECT"
+       AMLINTFLAGS="$AMLINTFLAGS,E_FUNC_RET_ALWAYS_IGNOR"
+       AMLINTFLAGS="$AMLINTFLAGS,E_FUNC_RET_MAYBE_IGNORED"
+       AMLINTFLAGS="$AMLINTFLAGS,E_H_C_CHECK0"
+       AMLINTFLAGS="$AMLINTFLAGS,E_H_C_CHECK1"
+       AMLINTFLAGS="$AMLINTFLAGS,E_H_C_CHECK2"
+       AMLINTFLAGS="$AMLINTFLAGS,E_INCL_MNUSD"
+       AMLINTFLAGS="$AMLINTFLAGS,E_INCL_NUSD"
+       AMLINTFLAGS="$AMLINTFLAGS,E_MCR_NODIFF"
+       AMLINTFLAGS="$AMLINTFLAGS,E_NAME_MULTIPLY_DEF"
+       AMLINTFLAGS="$AMLINTFLAGS,E_P_REF_NULL_PSBL"
+       AMLINTFLAGS="$AMLINTFLAGS,E_P_REF_SUSP"
+       AMLINTFLAGS="$AMLINTFLAGS,E_PTRDIFF_OVERFLOW"
+       AMLINTFLAGS="$AMLINTFLAGS,E_P_USE_NULL_PSBL"
+       AMLINTFLAGS="$AMLINTFLAGS,E_P_USE_SUSP"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_ACCESS_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_CHDIR_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_CHMOD_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_CREAT_WITHOUT_EXCL"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_EXEC_PATH"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_EXEC_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_FOPEN_MODE"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_GETENV_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_MKDIR_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_PRINTF_VAR_FMT"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_RAND_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_SCANF_VAR_FMT"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_SELECT_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_SHELL_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_STRNCPY_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_UMASK_WARN"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SEC_USE_AFTER_STAT"
+       AMLINTFLAGS="$AMLINTFLAGS,E_SIGN_EXTENSION_PSBL"
+       AMLINTFLAGS="$AMLINTFLAGS,E_TYPEDEF_UNUSE"
+       AMLINTFLAGS="$AMLINTFLAGS,E_UNCAL_F"
+      else
+       AMLINTFLAGS=""
+      fi
+    else
+      AC_PATH_PROG(AMLINT,splint,,$SYSLOCPATH)
+      if test ! -z "$AMLINT"; then
+       AMLINT="splint"
+      else
+       AMLINT='echo "Error: LINT is not installed" ; false'
+      fi
+      AMLINTFLAGS='+show-scan +unixlib -weak -globs +usedef +usereleased +impouts -paramimptemp -varuse -warnposix -redef -preproc -fixedformalarray -retval -unrecog -usevarargs -formatcode'
+    fi
+    AC_SUBST(AMLINTFLAGS)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_GNUPLOT
+#
+# OVERVIEW
+#
+#   Search for a 'gnuplot' binary, placing the result in the precious 
+#   variable GNUPLOT.  Also accepts --with-gnuplot to indicate the location
+#   of the binary.
+#
+AC_DEFUN([AMANDA_PROG_GNUPLOT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+
+    AC_ARG_WITH(gnuplot,
+    AS_HELP_STRING([--with-gnuplot=PATH],
+                  [use gnuplot executable at PATH in amplot]),
+       [
+           case "$withval" in
+               y | ye | yes) : ;;
+               n | no) GNUPLOT= ;;
+               *) GNUPLOT="$withval" ;;
+           esac
+       ])
+    AC_PATH_PROG(GNUPLOT,gnuplot,,$LOCSYSPATH)
+
+    AC_ARG_VAR(GNUPLOT, [Location of the 'gnuplot' binary])
+    AC_SUBST(GNUPLOT)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_PRINT
+#
+# OVERVIEW
+#
+#   Search for a binary for printing, usually either 'lp' or 'lpr', and put its
+#   path in PRINT, as well as defining it in LPRCMD in config.h.
+#
+#   LPRFLAG is defined in config.h as the appropriate command-line flag to use 
+#   to select a printer; either -P or -d.
+#
+AC_DEFUN([AMANDA_PROG_PRINT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+
+    AC_PATH_PROGS(PRINT, lpr lp)
+    if test ! -z "$PRINT"; then
+       AC_DEFINE_UNQUOTED(LPRCMD, "$PRINT",
+               [Command for starting printing jobs. ])
+
+       AC_CACHE_CHECK([which flag to use to select a printer],
+           amanda_cv_printer_flag, [
+           amanda_cv_printer_flag=$PRINTER_FLAG
+           case "$PRINT" in
+               lpr|*/lpr) amanda_cv_printer_flag="-P";;
+               lp|*/lp) amanda_cv_printer_flag="-d";;
+           esac
+       ])
+       if test ! -z "$amanda_cv_printer_flag"; then
+           AC_DEFINE_UNQUOTED(LPRFLAG, "$amanda_cv_printer_flag",
+                   [LPRCMD switch for specifying a printer name. ])
+       else
+           AMANDA_MSG_WARN([WARNING: amanda will always print to the default printer])
+       fi
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_GNUPLOT
+#
+# OVERVIEW
+#
+#   Search for a 'gnuplot' binary, placing the result in the precious 
+#   variable GNUPLOT.  Also accepts --with-gnuplot to indicate the location
+#   of the binary.
+#
+AC_DEFUN([AMANDA_PROG_GNUPLOT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+
+    AC_ARG_WITH(gnuplot,
+    AS_HELP_STRING([--with-gnuplot=PATH],
+                  [use gnuplot executable at PATH in amplot]),
+       [
+           case "$withval" in
+               y | ye | yes) : ;;
+               n | no) GNUPLOT=no ;;
+               *) GNUPLOT="$withval" ;;
+           esac
+       ])
+    if test "x$GNUPLOT" = "xno"; then
+       GNUPLOT=
+    else
+       AC_PATH_PROG(GNUPLOT,gnuplot,,$LOCSYSPATH)
+    fi
+
+    AC_ARG_VAR(GNUPLOT, [Location of the 'gnuplot' binary])
+    AC_SUBST(GNUPLOT)
+])
+
+## simple macros needing no description; some add AC_DEFINE_UNQUOTED
+
+AC_DEFUN([AMANDA_PROG_GREP],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(GREP,grep,grep,$LOCSYSPATH)
+    AC_DEFINE_UNQUOTED(GREP,"$GREP",
+           [Define the location of the grep program. ])
+])
+
+AC_DEFUN([AMANDA_PROG_CAT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(CAT,cat,cat,$LOCSYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_COMPRESS],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(COMPRESS,compress,,$LOCSYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_DD],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(DD,dd,,$LOCSYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_GETCONF],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(GETCONF,getconf,,$SYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_GZIP],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(GZIP,gzip,,$LOCSYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_SORT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_REQUIRE([AMANDA_CHECK_COMPONENTS])
+
+    AC_PATH_PROG(SORT,sort,NONE,$LOCSYSPATH)
+
+    # sort is only needed in the server build
+    if test x"$SORT" = x"NONE" && $WANT_SERVER; then
+        AC_MSG_ERROR([Set SORT to the path of the sort program.])
+    fi
+
+    AC_DEFINE_UNQUOTED(SORT_PATH,"$SORT",
+           [Define to the exact path to the sort program. ])
+])
+
+AC_DEFUN([AMANDA_PROG_MAILER],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROGS(MAILER,Mail mailx mail,NONE)
+    if test x"$MAILER" = x"NONE"; then
+        AMANDA_MSG_WARN([WARNING: Amanda cannot send mail reports without a mailer.])
+    else
+        AC_DEFINE_UNQUOTED(MAILER,"$MAILER",
+                [A program that understands -s "subject" user < message_file])
+    fi
+])
+
+# SYNOPSIS
+#
+#   AMANDA_PROG_MT
+#
+# OVERVIEW
+#   
+#   Find and SUBST 'mt', and additionally calculate the proper flag to use
+#   to identify the tape device (usually -f) and DEFINE and SUBST that value
+#   as MT_FILE_FLAG.
+#
+AC_DEFUN([AMANDA_PROG_MT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(MT,mt,mt,$LOCSYSPATH)
+
+    case "$target" in
+       *-hp-*) MT_FILE_FLAG="-t" ;;
+       *) MT_FILE_FLAG="-f" ;;
+    esac
+
+    AC_SUBST(MT_FILE_FLAG)
+    AC_DEFINE_UNQUOTED(MT_FILE_FLAG, "$MT_FILE_FLAG",
+  [The switch to be used when invoking mt to specify the
+ * tape device. ])
+])
+
+
+AC_DEFUN([AMANDA_PROG_CHIO],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(CHIO,chio,chio,$LOCSYSPATH)
+])
+
+
+AC_DEFUN([AMANDA_PROG_CHS],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(CHS,chs,chs,$LOCSYSPATH)
+])
+
+
+AC_DEFUN([AMANDA_PROG_MTX],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(MTX,mtx,mtx,$LOCSYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_MCUTIL],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(MCUTIL,mcutil,mcutil,$LOCSYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_PCAT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(PCAT,pcat,,$LOCSYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_PERL],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROGS(PERL,perl5 perl,,$LOCSYSPATH)
+    AC_ARG_VAR([PERL], [Path to the 'perl' binary])
+    AC_PROG_PERL_VERSION([5.6.0], [], [
+       AC_MSG_ERROR([Amanda requires at least perl 5.6.0])
+    ])
+])
+
+AC_DEFUN([AMANDA_PROG_SWIG],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROGS(SWIG,swig,,$LOCSYSPATH)
+    AC_ARG_VAR([SWIG], [Path to the 'swig' binary (developers only)])
+    AC_PROG_SWIG([1.3.28])
+])
+
+AC_DEFUN([AMANDA_PROG_AR],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(AR,ar,,$LOCSYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_BASH],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(BASH,bash,,$SYSPATH)
+])
+
+AC_DEFUN([AMANDA_PROG_SSH],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROGS(SSH, ssh, , $LOCSYSPATH)
+    AC_DEFINE_UNQUOTED(SSH, "$SSH", [Path to the SSH binary])
+])
+
+AC_DEFUN([AMANDA_PROG_GETTEXT],
+[
+    AC_REQUIRE([AMANDA_INIT_PROGS])
+    AC_PATH_PROG(GETTEXT,gettext,,$LOCSYSPATH)
+])
diff --git a/config/amanda/readdir.m4 b/config/amanda/readdir.m4
new file mode 100644 (file)
index 0000000..4db19c7
--- /dev/null
@@ -0,0 +1,32 @@
+# SYNOPSIS
+#
+#   AMANDA_CHECK_READDIR
+#
+# OVERVIEW
+#
+#   Check for one of the readdir variants, as well as the dirent headers.
+#   See common-src/util.c and amanda.h for the use of these symbols.
+#
+AC_DEFUN([AMANDA_CHECK_READDIR], [
+    AC_HEADER_DIRENT
+
+    # include the dirent headers as described in the autoconf documentation.
+    AC_CHECK_DECLS([readdir, readdir_r, readdir64, readdir64_r],,,[
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+    ])
+])
diff --git a/config/amanda/readline.m4 b/config/amanda/readline.m4
new file mode 100644 (file)
index 0000000..dbf8be5
--- /dev/null
@@ -0,0 +1,75 @@
+# SYNOPSIS
+#
+#   AMANDA_CHECK_READLINE
+#
+# OVERVIEW
+#
+#   Check for readline support.  Defines HAVE_READLINE if readline
+#   is available, and also checks for a number of readline headers and
+#   adds readline libraries to READLINE_LIBS.
+#
+#   See common-src/util.{c,h}.
+#
+AC_DEFUN([AMANDA_CHECK_READLINE], [
+    AC_ARG_WITH(readline,
+    dnl no initial space here, so the results line up properly
+AS_HELP_STRING([--with-readline], [require readline support (for amrecover)])
+AS_HELP_STRING([--without-readline], [don't search for readline]),
+        [ 
+            case "$withval" in
+                y | ye | yes | n | no) : ;;
+                *) AC_MSG_ERROR([*** --with-readline does not take a value])
+            esac
+            want_readline="$withval"
+        ], [
+            want_readline="maybe" # meaning "only if we can find it"
+        ])
+
+    # unless the user said "no", look for readline.
+    if test x"$want_readline" != x"no"; then
+        # we need a tgetent() somewhere..
+        proceed="false"
+        AC_CHECK_LIB(termcap, tgetent, [
+            READLINE_LIBS="-ltermcap"
+            proceed="true"
+        ], [
+            AC_CHECK_LIB(curses, tgetent, [
+                READLINE_LIBS="-lcurses"
+                proceed="true"
+            ], [
+                AC_CHECK_LIB(ncurses, tgetent, [
+                    READLINE_LIBS="-lncurses"
+                    proceed="true"
+                ])
+            ])
+        ])
+
+        if $proceed; then
+            proceed="false"
+            AC_CHECK_HEADERS( history.h readline.h readline/history.h readline/readline.h, [
+                # found at least one of the headers, so we can proceed.
+                proceed="true"
+            ])
+        fi
+
+        if $proceed; then
+            proceed="false"
+            AC_CHECK_LIB(readline,readline, [
+                READLINE_LIBS="-lreadline $READLINE_LIBS"
+                proceed="true"
+            ],,$READLINE_LIBS)
+        fi
+
+        if $proceed; then
+            # we have readline!
+            AC_DEFINE(HAVE_READLINE, 1, [System has readline support (headers and libraries)])
+        else
+            # no readline.  if the user *really* wanted it, bail out.
+            if test x"$want_readline" = x"yes"; then
+                AC_MSG_ERROR([*** No readline implementation found.  Try using --with-libraries and --with-includes])
+            fi
+            READLINE_LIBS=""
+        fi
+    fi
+    AC_SUBST(READLINE_LIBS)
+])
diff --git a/config/amanda/rsh-security.m4 b/config/amanda/rsh-security.m4
new file mode 100644 (file)
index 0000000..891d50f
--- /dev/null
@@ -0,0 +1,32 @@
+# SYNOPSIS
+#
+#   AMANDA_RSH_SECURITY
+#
+# OVERVIEW
+#
+#   Handle configuration for RSH security, implementing the --with-rsh-security
+#   option and checking for the relevant programs and options.
+#
+AC_DEFUN([AMANDA_RSH_SECURITY],
+[
+    RSH_SECURITY=no
+    AC_ARG_WITH(rsh-security,
+        AS_HELP_STRING([--with-rsh-security], 
+                [include RSH authentication]),
+        [
+            case "$withval" in
+                n | no) : ;;
+                y |  ye | yes) RSH_SECURITY=yes ;;
+                *) AC_MSG_ERROR([*** You must not supply an argument to --with-rsh-security.])
+              ;;
+            esac
+        ],
+    )
+
+    if test "x$RSH_SECURITY" = "xyes"; then
+        AC_DEFINE(RSH_SECURITY,1,
+                [Define if RSH transport should be enabled. ])
+    fi
+    AM_CONDITIONAL(WANT_RSH_SECURITY, test x"$RSH_SECURITY" = x"yes")
+])
+
diff --git a/config/amanda/s3-device.m4 b/config/amanda/s3-device.m4
new file mode 100644 (file)
index 0000000..1aa37cb
--- /dev/null
@@ -0,0 +1,65 @@
+# SYNOPSIS
+#
+#   AMANDA_S3_DEVICE
+#
+# OVERVIEW
+#
+#   Perform the necessary checks for the S3 Device.  If the S3 device should be built,
+#   WANT_S3_DEVICE is DEFINEd and set up as an AM_CONDITIONAL.
+#
+#   The subsidiary DevPay support, if enabled, defines and AM_CONDITIONALizes
+#   WANT_DEVPAY.
+#
+AC_DEFUN([AMANDA_S3_DEVICE], [
+    AC_REQUIRE([AMANDA_CHECK_LIBCURL])
+    AC_REQUIRE([AMANDA_CHECK_HMAC])
+
+    AC_ARG_ENABLE([s3-device],
+       AS_HELP_STRING([--disable-s3-device],
+                      [disable the S3 device]),
+       [ WANT_S3_DEVICE=$enableval ], [ WANT_S3_DEVICE=maybe ])
+
+    AC_MSG_CHECKING([whether to include the Amazon S3 device])
+    # if the user didn't specify 'no', then check for support
+    if test x"$WANT_S3_DEVICE" != x"no"; then
+       if test x"$HAVE_CURL" = x"yes" -a x"$HAVE_HMAC" = x"yes"; then
+           WANT_S3_DEVICE=yes
+       else
+           # no support -- if the user explicitly enabled the device,
+           # then this is an error
+           if test x"$WANT_S3_DEVICE" = x"yes"; then
+               AC_MSG_RESULT(no)
+               AC_MSG_ERROR([Cannot build the Amazon S3 device: one or more prerequisites are missing.])
+           else
+               WANT_S3_DEVICE=no
+           fi
+       fi
+    fi
+    AC_MSG_RESULT($WANT_S3_DEVICE)
+
+    AM_CONDITIONAL([WANT_S3_DEVICE], [test x"$WANT_S3_DEVICE" = x"yes"])
+
+    # Now handle any setup for S3, if we want it.
+    if test x"$WANT_S3_DEVICE" = x"yes"; then
+       AC_DEFINE(WANT_S3_DEVICE, [], [Compile Amazon S3 driver])
+    fi
+                         
+
+    AC_ARG_ENABLE([devpay],
+                 AS_HELP_STRING([--enable-devpay],
+                                [Use devpay authentication for Amazon S3 driver]),
+                 [WANT_DEVPAY=$enableval], [WANT_DEVPAY=no])
+
+    AC_MSG_CHECKING([whether to include the Amazon S3 device's DevPay support])
+    if test x"$WANT_DEVPAY" = x"yes"; then
+       if test x"$WANT_S3_DEVICE" != x"yes"; then
+           AC_MSG_RESULT(no)
+           AC_MSG_ERROR([DevPay support requires the S3 device (--enable-s3-device)])
+       fi
+
+       AC_DEFINE([WANT_DEVPAY], [], [Compile Amazon DevPay support])
+    fi
+    AC_MSG_RESULT($WANT_DEVPAY)
+
+    AM_CONDITIONAL([WANT_DEVPAY], [test "$WANT_DEVPAY" = "yes"])
+])
diff --git a/config/amanda/shmem.m4 b/config/amanda/shmem.m4
new file mode 100644 (file)
index 0000000..d620e5d
--- /dev/null
@@ -0,0 +1,130 @@
+# SYNOPSIS
+#
+#   AMANDA_FUNC_SHM_ARG_TYPE
+#
+# OVERVIEW
+#
+#   Determine the type of the second argument to shmdt/shmat, defining
+#   that type (without the *) in SHM_ARG_TYPE.
+#
+AC_DEFUN([AMANDA_FUNC_SHM_ARG_TYPE], [
+       AC_CHECK_HEADERS(
+           sys/types.h \
+           sys/ipc.h \
+           sys/shm.h \
+       )
+
+       AC_CACHE_CHECK(
+           [for shmdt() argument type],
+           amanda_cv_shmdt_arg_type,
+           [
+               if test "$ac_cv_func_shmget" = yes; then
+                   cat <<EOF >conftest.$ac_ext
+#include "confdefs.h"
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_IPC_H
+# include <sys/ipc.h>
+#endif
+#ifdef HAVE_SYS_SHM_H
+# include <sys/shm.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" void *shmat(int, void *, int);
+#else
+void *shmat();
+#endif
+
+int main()
+{
+    int i;
+    return 0;
+}
+EOF
+                   ${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext >/dev/null 2>/dev/null
+                   if test $? = 0; then
+                       amanda_cv_shmdt_arg_type=void
+                   else
+                       amanda_cv_shmdt_arg_type=char
+                   fi
+                   rm -f conftest*
+               else
+                   amanda_cv_shmdt_arg_type=nothing
+               fi
+           ]
+       )
+       AC_DEFINE_UNQUOTED(SHM_ARG_TYPE,$amanda_cv_shmdt_arg_type,
+           [Define to type of shmget() function argument. ])
+    ]
+)
+
+# SYNOPSIS
+#
+#   AMANDA_CHECK_SHMEM
+#
+# OVERVIEW
+#
+#   Check for shared memory support; checks for the --with-mmap option,
+#   and then ensures that the proper compilation infrastructure is in place
+#   for either mmap or shared memory support.
+#
+#   Defines several HAVE_*_DECL symbols via ICE_CHECK_DECL, as well as 
+#   HAVE_SYSVSHM if shared memory support is discovered.
+#
+AC_DEFUN([AMANDA_CHECK_SHMEM],
+[
+    AC_REQUIRE([AC_HEADER_STDC])
+    AC_ARG_WITH(mmap,
+       AS_HELP_STRING([--with-mmap],
+           [force use of mmap instead of shared memory support]),
+       [
+           case "$FORCE_MMAP" in
+               y | ye | yes | n | no) : ;;
+               *) AC_MSG_ERROR([*** You must not supply an argument to --with-mmap.]) ;;
+           esac
+           FORCE_MMAP=$withval
+       ],
+       [ : ${FORCE_MMAP=no} ]
+    )
+
+
+    AC_CHECK_HEADERS(\
+           sys/shm.h \
+           sys/mman.h \
+    )
+
+    AC_FUNC_MMAP
+
+    AC_CHECK_FUNCS(shmget,
+       [
+           AMANDA_FUNC_SHM_ARG_TYPE
+           case "$FORCE_MMAP" in
+           n | no)
+               AC_DEFINE(HAVE_SYSVSHM,1,
+                   [Define if SysV shared-memory functions are available. ])
+             ;;
+           esac
+       ]
+    )
+    ICE_CHECK_DECL(shmat,sys/types.h sys/ipc.h sys/shm.h)
+    ICE_CHECK_DECL(shmctl,sys/types.h sys/ipc.h sys/shm.h)
+    ICE_CHECK_DECL(shmdt,sys/types.h sys/ipc.h sys/shm.h)
+    ICE_CHECK_DECL(shmget,sys/types.h sys/ipc.h sys/shm.h)
+
+    if test "x$ac_cv_func_mmap_fixed_mapped" != xyes; then
+       case "$FORCE_MMAP" in
+       n | no)
+           if test "x$ac_cv_func_shmget" != xyes; then
+               AMANDA_MSG_WARN([Neither shmget() nor mmap() found. This system will not support the Amanda server.])
+               NO_SERVER_MODE=true
+           fi
+         ;;
+       y | ye | yes)
+           AMANDA_MSG_WARN([--with-mmap used on a system with no mmap() support.  This system will not support the Amanda server.])
+           NO_SERVER_MODE=true
+         ;;
+       esac
+    fi
+])
diff --git a/config/amanda/socklen_t_equiv.m4 b/config/amanda/socklen_t_equiv.m4
new file mode 100644 (file)
index 0000000..1d95d3b
--- /dev/null
@@ -0,0 +1,48 @@
+# SYNOPSIS
+#
+#   AMANDA_SOCKLEN_T_EQUIV
+#
+# OVERVIEW
+#
+#   Find a type which will work like socklen_t should.  Unfortunately, 
+#   HP/UX systems define socklen_t, but use int * as the result parameter
+#   for socket functions returning a socket length.
+#
+#   This check defines a type socklen_t_equiv which is of the appropriate
+#   size to be used with socket functions.
+#
+AC_DEFUN([AMANDA_SOCKLEN_T_EQUIV],
+[
+      ## lifted from config/gnulib/socklen.m4
+      AC_REQUIRE([gl_HEADER_SYS_SOCKET])dnl
+      AC_MSG_CHECKING([for socklen_t equivalent])
+      AC_CACHE_VAL([gl_cv_socklen_t_equiv],
+       [# Systems have either "struct sockaddr *" or
+        # "void *" as the second argument to getpeername
+        gl_cv_socklen_t_equiv=
+        for arg2 in "struct sockaddr" void; do
+          for t in socklen_t int size_t "unsigned int" "long int" "unsigned long int"; do
+            AC_TRY_COMPILE(
+              [#include <sys/types.h>
+               #include <sys/socket.h>
+
+               int getpeername (int, $arg2 *, $t *);],
+              [$t len;
+               getpeername (0, 0, &len);],
+              [gl_cv_socklen_t_equiv="$t"])
+            test "$gl_cv_socklen_t_equiv" != "" && break
+          done
+          test "$gl_cv_socklen_t_equiv" != "" && break
+        done
+      ])
+      ## end lifting from config/gnulib/socklen.m4
+      # fallback if the check fails
+      if test "$gl_cv_socklen_t_equiv" = ""; then
+       gl_cv_socklen_t_equiv=socklen_t
+      fi
+      AC_MSG_RESULT([$gl_cv_socklen_t_equiv])
+
+      AC_DEFINE_UNQUOTED([socklen_t_equiv], [$gl_cv_socklen_t_equiv],
+       [type to use for socket length parameters; use instead of socklen_t])
+])
+
diff --git a/config/amanda/ssh-security.m4 b/config/amanda/ssh-security.m4
new file mode 100644 (file)
index 0000000..9fd8d97
--- /dev/null
@@ -0,0 +1,71 @@
+# SYNOPSIS
+#
+#   AMANDA_SSH_SECURITY
+#
+# OVERVIEW
+#
+#   Handle configuration for SSH security, implementing the --with-ssh-security
+#   option and checking for the relevant programs and options.
+#
+AC_DEFUN([AMANDA_SSH_SECURITY],
+[
+    SSH_SECURITY=no
+    AC_ARG_WITH(ssh-security,
+        AS_HELP_STRING([--with-ssh-security], 
+                [include SSH authentication]),
+        [
+            case "$withval" in
+                n | no) : ;;
+                y |  ye | yes) SSH_SECURITY=yes ;;
+                *) AC_MSG_ERROR([*** You must not supply an argument to --with-ssh-security.])
+              ;;
+            esac
+        ],
+    )
+
+    if test "x$SSH_SECURITY" = "xyes"; then
+        # find the SSH binary
+        AC_PATH_PROGS(SSH, ssh, , $LOCSYSPATH)
+
+        # see what options we should use
+        AC_ARG_WITH(ssh-options,
+            AS_HELP_STRING([ --with-ssh-options=@<:@OPTIONS@:>@],
+               [Use these ssh options for ssh security; the default should work]),
+            [ SSH_OPTIONS="$withval" ],
+            [ SSH_OPTIONS='' ]
+        )
+
+        case "$SSH_OPTIONS" in
+            y | ye | yes | n | no)
+                AC_MSG_ERROR([*** You must supply an argument to --with-ssh-options.]);;
+            *) : ;;
+        esac
+
+        AC_MSG_CHECKING([SSH options])
+        # if we didn't get SSH options from the user, figure them out for ourselves
+        if test -z "$SSH_OPTIONS"; then
+            case `$SSH -V 2>&1` in
+                OpenSSH*) SSH_OPTIONS='-x -o BatchMode=yes -o PreferredAuthentications=publickey';;
+                *) SSH_OPTIONS='-x -o BatchMode=yes' ;;
+            esac
+        fi
+
+        # now convert that to a comma-separated list of C strings
+        eval "set dummy ${SSH_OPTIONS}"; shift
+        SSH_OPTIONS=''
+       for i in "${@}"; do 
+           quoted="\"`echo "$i" | sed -e 's/\"/\\\"/'`\""
+           SSH_OPTIONS="${SSH_OPTIONS}${SSH_OPTIONS:+, }$quoted"; 
+       done
+        AC_MSG_RESULT($SSH_OPTIONS)
+
+        # finally, make the various outputs for all of this
+        AC_DEFINE(SSH_SECURITY,1,
+                [Define if SSH transport should be enabled. ])
+        AC_DEFINE_UNQUOTED(SSH, "$SSH", 
+                [Path to the SSH binary])
+        AC_DEFINE_UNQUOTED(SSH_OPTIONS, $SSH_OPTIONS, 
+                [Arguments to ssh])
+    fi
+    AM_CONDITIONAL(WANT_SSH_SECURITY, test x"$SSH_SECURITY" = x"yes")
+])
diff --git a/config/amanda/summary.m4 b/config/amanda/summary.m4
new file mode 100644 (file)
index 0000000..105373c
--- /dev/null
@@ -0,0 +1,71 @@
+# OVERVIEW/BACKGROUND
+#
+#   This file creates an end-of-run summary of the Amanda configuration.
+#
+
+# SYNOPSIS
+#
+#   AMANDA_INIT_SUMMARY()
+#
+# DESCRIPTION
+#
+#   Set up for producing a summary.  This should be called early in the configure
+#   process
+#
+AC_DEFUN([AMANDA_INIT_SUMMARY],
+[
+    # initialize warnings file
+    rm -f config.warnings
+])
+
+# SYNOPSIS
+#
+#   AMANDA_MSG_WARN()
+#
+# DESCRIPTION
+#
+#   Like AC_MSG_WARN, but also adds the message to the summary
+#
+AC_DEFUN([AMANDA_MSG_WARN], [
+    AC_MSG_WARN([$1])
+    AMANDA_ADD_WARNING([$1])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_ADD_WARNING_QUOTED(warning-text) #if text already quoted
+#   AMANDA_ADD_WARNING(warning-text)        #if text not quoted
+#
+# DESCRIPTION
+#
+#   Add the given text to the warnings summary
+#
+AC_DEFUN([AMANDA_ADD_WARNING_QUOTED], [
+    cat <<AAW_EOF >>config.warnings
+$1
+AAW_EOF])
+
+AC_DEFUN([AMANDA_ADD_WARNING], [
+AMANDA_ADD_WARNING_QUOTED([_AS_QUOTE([$1])])
+])
+
+# SYNOPSIS
+#
+#   AMANDA_SHOW_SUMMARY()
+#
+# DESCRIPTION
+#
+#   Output the configuration summary.
+#
+AC_DEFUN([AMANDA_SHOW_SUMMARY], [
+    AMANDA_SHOW_FLAGS_SUMMARY
+    AMANDA_SHOW_COMPONENTS_SUMMARY
+    AMANDA_SHOW_IPV6_SUMMARY
+    AMANDA_SHOW_DOCUMENTATION_SUMMARY
+    AMANDA_SHOW_DIRS_SUMMARY
+    if test -f config.warnings; then
+       echo "WARNINGS:"
+       cat config.warnings | sed -e 's/^/  /g'
+       rm config.warnings
+    fi
+])
diff --git a/config/amanda/swig.m4 b/config/amanda/swig.m4
new file mode 100644 (file)
index 0000000..dadfc89
--- /dev/null
@@ -0,0 +1,76 @@
+# OVERVIEW
+#
+#   Set up for building SWIG bindings.  Note that shipped tarballs contain pre-built
+#   SWIG bindings, so there should be no need for SWIG on non-developer machines.
+# SYNOPSIS
+#
+#   Find perl and SWIG, and substitute PERL_INC, the -I command that will lead the compiler
+#   to perl.h and friends.
+#
+#   Supports --with-perlextlibs, for adding extra LIBS declarations to perl extensions.
+#
+AC_DEFUN([AMANDA_SETUP_SWIG],
+[
+    AC_REQUIRE([AMANDA_PROG_SWIG])
+    AC_REQUIRE([AMANDA_PROG_PERL])
+
+    # If we want cygwin to copy ddl to modules directory.
+    WANT_CYGWIN_COPY_PERL_DLL="false"
+
+    # get the include path for building perl extensions
+    PERL_INC=`$PERL -MExtUtils::Embed -e perl_inc`
+    AC_SUBST(PERL_INC)
+
+    if test x"$enable_shared" = x"no"; then
+       AC_MSG_ERROR([*** Amanda cannot be compiled without shared-library support (do not use --disable-shared)])
+    fi
+
+    case "$target" in
+       *freebsd@<:@123456@:>@*) # up to and including FreeBSD 6.*
+           # Before 7.0, FreeBSD systems don't include a DT_NEEDS segment in
+           # libgthread to automatically pull in the desired threading library.
+           # Instead, they assume that any application linking against
+           # libgthread will pull in the threading library.  This is fine for
+           # Amanda C applications, but for Perl applications this assumption
+           # means that the perl binary would pull in the threading library.
+           # But perl is compiled without threading by default.  
+           #
+           # Specifically, this occurs on any FreeBSD using gcc-3.*: the linking
+           # decision is made in gcc's spec files, which were changed in
+           # gcc-4.0.  For a more in-depth discussion, see
+           #  http://wiki.zmanda.com/index.php/Installation/OS_Specific_Notes/Installing_Amanda_on_FreeBSD
+           #
+           # The easiest solution for the "default" case is to link all perl
+           # extension libraries against the threading library, so it is loaded
+           # when perl loads the extension library.  The default threading
+           # library in FreeBSD is libpthread.  The below default will work on
+           # such a FreeBSD system, but ports maintainers and those with
+           # different configurations may need to override this value with
+           # --with-perlextlibs.
+           #
+           # We can't use -pthread because gcc on FreeBSD ignores -pthread in
+           # combination with -shared.  See
+           #   http://lists.freebsd.org/pipermail/freebsd-stable/2006-June/026229.html
+
+           PERLEXTLIBS="-lpthread"
+           ;;
+       *-pc-cygwin)
+           # When need -lperl and the '-L' where it is located,
+           # we don't want the DynaLoader.a
+           PERLEXTLIBS=`perl -MExtUtils::Embed -e ldopts | sed -e 's/^.*-L/-L/'`
+           WANT_CYGWIN_COPY_PERL_DLL="true";
+           ;;
+    esac
+    AM_CONDITIONAL(WANT_CYGWIN_COPY_PERL_DLL,$WANT_CYGWIN_COPY_PERL_DLL)
+
+    AC_ARG_WITH(perlextlibs,
+       AC_HELP_STRING([--with-perlextlibs=libs],[extra LIBS for Perl extensions]),
+       [
+           case "$withval" in
+               y|ye|yes) AC_MSG_ERROR([*** You must specify a value for --with-perlextlibs]);;
+               n|no) PERLEXTLIBS='';;
+               *) PERLEXTLIBS="$withval" ;;
+           esac
+       ])
+    AC_SUBST(PERLEXTLIBS)
+])
diff --git a/config/amanda/syshacks.m4 b/config/amanda/syshacks.m4
new file mode 100644 (file)
index 0000000..c3e9935
--- /dev/null
@@ -0,0 +1,108 @@
+# SYNOPSIS
+#
+#   AMANDA_SYSHACKS
+#
+# OVERVIEW
+#
+#   This macro encapsulates any system-specific hacks required to make Amanda
+#   compile that don't fit neatly into any other macro.  It is implemented as a 
+#   big 'case' statement based on the canonical target architecture.
+#
+#   It also serves as a list of the "supported" architectures, represented by 
+#   case statements with empty bodies.  If no architecture matches, the user
+#   is presented with a warning.
+#
+AC_DEFUN([AMANDA_SYSHACKS], [
+    AC_REQUIRE([AC_CANONICAL_TARGET])
+    case "$target" in
+       *-dec-osf*)
+                   ;;
+       *-dg-*)
+                   ;;
+       *-netbsd*)
+                   ;;
+       *-freebsd*)
+                   ;;
+       *-openbsd*)
+                   ;;
+       *-hp-*)
+                   case "$CC" in
+                       *gcc*)
+                           AMANDA_ADD_CPPFLAGS([-D__STDC_EXT__])
+                           ;;
+                       *cc*)
+                           AMANDA_ADD_CFLAGS([-Ae])
+                           ;;
+                   esac
+                   ;;
+       *-ibm-aix*)
+                   ;;
+       m88k-motorola-sysv4)
+                   ;;
+       *-nextstep3)
+                   ;;
+       *-pc-bsdi*)
+                   ;;
+       *-pc-linux-*)
+                   ;;
+       *-redhat-linux-*)
+                   ;;
+       *-suse-linux-*)
+                   ;;
+       x86_64-*-linux-*)
+                   ;;
+       alpha*-*-linux-*)
+                   ;;
+       sparc*-*-linux-*)
+                   ;;
+       powerpc-*-linux-*)
+                   ;;
+        *-sgi-irix3*)
+                   # The old cc won't work!
+                   if test "x$GCC" != "xyes"; then
+                       AC_MSG_ERROR([The old SGI IRIX compiler ($CC) will not compile Amanda; use CC=gcc])
+                   fi
+                   ;;
+        *-sgi-irix4*)
+                   ;;
+        *-sgi-irix5*)
+                   ;;
+        *-sgi-irix6*)
+                   ;;
+        *-solaris2*)
+                   ;;
+        *-sun-sunos4.1*)
+                   ;;
+        *-ultrix*)
+                   ;;
+        *-sysv4.2uw2*)
+                   ;;
+        *-sco3.2v5*)
+                   ;;
+        i386-pc-isc4*)
+                   ;;
+        *-sni-sysv4)
+                   ;;
+        *-pc-cygwin)
+                   AC_DEFINE(IGNORE_TAR_ERRORS,1,[Define on Cygwin. ])
+                   # Cygwin needs PATH to find cygwin1.dll
+                   AC_DEFINE(NEED_PATH_ENV,1,[Define on Cygwin. ])
+                   AC_DEFINE(IGNORE_FSTAB,1,[Define on Cygwin. ])
+                   AMANDA_ADD_LDFLAGS([-Wl,-enable-runtime-pseudo-reloc -no-undefined])
+                   ;;
+        *-apple-darwin7*) # MacOS X 10.3.* (Panther)
+                   ;;
+        *-apple-darwin8*) # MacOS X 10.4.* (Tiger)
+                   ;;
+      *)
+               AMANDA_ADD_WARNING(
+[*****
+This machine, target type $target, is not known to be fully supported
+by this configure script.  If the installation of Amanda on this system
+succeeds or needed any patches, please email amanda-hackers@amanda.org
+with the patches or an indication of the sucess or failure of the
+Amanda installation on your system.
+*****])
+                   ;;
+    esac
+])
diff --git a/config/amanda/tape.m4 b/config/amanda/tape.m4
new file mode 100644 (file)
index 0000000..d08f27a
--- /dev/null
@@ -0,0 +1,198 @@
+# SYNOPSIS
+#
+#   AMANDA_WITH_MAXTAPEBLOCKSIZE
+#
+# OVERVIEW
+#
+#   Implement the --with-maxtapeblocksize option, and DEFINE and SUBST the
+#   result in MAX_TAPE_BLOCk_KB and MAXTAPEBLOCKSIZE, respectively.
+#
+AC_DEFUN([AMANDA_WITH_MAXTAPEBLOCKSIZE], [
+    AC_ARG_WITH(maxtapeblocksize,
+       AS_HELP_STRING([--with-maxtapeblocksize=kb],
+           [Maximum size of a tape block (default: 32)]),
+       [ MAXTAPEBLOCKSIZE="$withval" ],
+       [ MAXTAPEBLOCKSIZE=32 ]
+    )
+
+    AC_DEFINE_UNQUOTED(MAX_TAPE_BLOCK_KB,($MAXTAPEBLOCKSIZE),
+       [Maximum size of a tape block in KBytes.])
+    AC_SUBST(MAXTAPEBLOCKSIZE)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_TAPE_DEVICE
+#
+# OVERVIEW
+#
+#   Set up for the 'tape' device.  One of the conditionals WANT_TAPE_XENIX,
+#   WANT_TAPE_AIX, WANT_TAPE_UWARE, and WANT_TAPE_POSIX will be true; the
+#   corresponding symbols are also DEFINEd.  Finally, WANT_TAPE_DEVICE is
+#   defined nad AM_CONDITIONAL'd if the tape device should be supported (if
+#   at least one of the backends is available).
+#
+#   If 'struct mtget' fields mt_flags, mt_fileno, mt_blkno, mt_dsreg, and 
+#   mt_erreg, the corresponding HAVE_MT_* is DEFINEd.
+#
+#   Not that most of the checks in this section correspond to the older
+#   tapeio (in tape-src/), rather than the new tape device.
+#
+AC_DEFUN([AMANDA_TAPE_DEVICE], [
+    AC_CHECK_HEADERS( \
+       linux/zftape.h \
+       sys/tape.h \
+       sys/mtio.h \
+       )
+
+    # check for MTIOCTOP, an indicator of POSIX tape support
+    AC_CACHE_CHECK([for MTIOCTOP], amanda_cv_HAVE_MTIOCTOP,[
+       AC_TRY_COMPILE([
+#ifdef HAVE_SYS_TAPE_H
+# include <sys/tape.h>
+#endif
+#ifdef HAVE_SYS_MTIO_H
+# include <sys/mtio.h>
+#endif
+#ifndef MTIOCTOP
+#error MTIOCTOP not defined
+#endif
+           ],
+           [ int dummy = 0; ],
+           amanda_cv_HAVE_MTIOCTOP=yes,
+           amanda_cv_HAVE_MTIOCTOP=no,
+           amanda_cv_HAVE_MTIOCTOP=no)]
+
+       HAVE_MTIOCTOP=$amanda_cv_HAVE_MTIOCTOP
+    )
+
+    # decide which tape device to compile (arranged in such a way that
+    # only one actually gets compiled)
+    case "$target" in
+      *-ibm-aix*) aix_tapeio=yes ;;
+      *-sysv4.2uw2*) uware_tapeio=yes ;;
+      *-sco3.2v5*) xenix_tapeio=yes ;;
+      i386-pc-isc4*) xenix_tapeio=yes ;;
+    esac
+
+    # maybe we have no tape device at all (e.g., Mac OS X)?
+    if test -n "$xenix_tapeio" ||
+       test -n "$aix_tapeio" ||
+       test -n "$uware_tapeio" ||
+       test -n "$HAVE_MTIOCTOP"; then
+       want_tape_device=yes
+       AC_DEFINE(WANT_TAPE_DEVICE, 1, [Define if the tape-device will be built])
+    fi
+
+    AM_CONDITIONAL(WANT_TAPE_XENIX, test -n "$xenix_tapeio")
+    AM_CONDITIONAL(WANT_TAPE_AIX, test -n "$aix_tapeio")
+    AM_CONDITIONAL(WANT_TAPE_UWARE, test -n "$uware_tapeio")
+    AM_CONDITIONAL(WANT_TAPE_POSIX, test -n "$HAVE_MTIOCTOP")
+    AM_CONDITIONAL(WANT_TAPE_DEVICE, test -n "$want_tape_device")
+
+    if test -n "$xenix_tapeio"; then
+      AC_DEFINE(WANT_TAPE_XENIX,1,[Define on XENIX/ISC. ])
+    fi
+
+    if test -n "$aix_tapeio"; then
+      AC_DEFINE(WANT_TAPE_AIX,1,[Define on AIX. ])
+    fi
+
+    if test -n "$uware_tapeio"; then
+      AC_DEFINE(WANT_TAPE_UWARE,1,[Define on UnixWare. ])
+    fi
+
+    #
+    # Check for various "mt status" related structure elements.
+    #
+    AC_MSG_CHECKING([for mt_flags mtget structure element])
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mtio.h>
+       ]], [[
+           struct mtget buf;
+           long ds;
+
+           ds = buf.mt_flags;
+       ]])],[
+           AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_MT_FLAGS,1,
+               [Define if the mtget structure has an mt_flags field])
+       ],[
+           AC_MSG_RESULT(no)
+       ])
+
+    AC_MSG_CHECKING([for mt_fileno mtget structure element])
+    mt_fileno_result="found"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mtio.h>
+       ]], [[
+           struct mtget buf;
+           long ds;
+
+           ds = buf.mt_fileno;
+       ]])],[
+           AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_MT_FILENO,1,
+               [Define if the mtget structure has an mt_fileno field])
+       ],[
+           AC_MSG_RESULT(no)
+       ])
+
+    AC_MSG_CHECKING(for mt_blkno mtget structure element)
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mtio.h>
+       ]], [[
+           struct mtget buf;
+           long ds;
+
+           ds = buf.mt_blkno;
+       ]])],[
+           AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_MT_BLKNO,1,
+               [Define if the mtget structure has an mt_blkno field])
+       ],[
+           AC_MSG_RESULT(no)
+       ])
+
+    AC_MSG_CHECKING(for mt_dsreg mtget structure element)
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mtio.h>
+       ]], [[
+           struct mtget buf;
+           long ds;
+
+           ds = buf.mt_dsreg;
+       ]])],[
+           AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_MT_DSREG,1,
+               [Define if the mtget structure has an mt_dsreg field])
+       ],[
+           AC_MSG_RESULT(no)
+       ])
+
+    AC_MSG_CHECKING(for mt_erreg mtget structure element)
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mtio.h>
+       ]], [[
+           struct mtget buf;
+           long ds;
+
+           ds = buf.mt_erreg;
+       ]])],[
+           AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_MT_ERREG,1,
+               [Define if the mtget structure has an mt_erreg field])
+       ],[
+           AC_MSG_RESULT(no)
+       ])
+])
diff --git a/config/amanda/types.m4 b/config/amanda/types.m4
new file mode 100644 (file)
index 0000000..ff9e852
--- /dev/null
@@ -0,0 +1,188 @@
+# SYNOPSIS
+#
+#   AMANDA_CHECK_TYPE(type, replacement-type, header)
+#
+# OVERVIEW
+# 
+#   Like AC_CHECK_TYPE, where action-if-not-found DEFINEs $1 to $2.
+#
+#   'header' must be a single header name, or blank to use the default
+#   headers.
+#
+AC_DEFUN([AMANDA_CHECK_TYPE], [
+    AC_REQUIRE([AC_HEADER_STDC])
+    AC_CHECK_TYPE($1, [], [
+       AC_DEFINE($1, $2, [Type for $1, if it is not defined by the system])
+    ], ifelse($3, [], [], [
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#include <$3>
+       ])
+    )
+])
+#
+# SYNOPSIS
+#
+#   AMANDA_TYPE_PID_T
+#
+# OVERVIEW
+#
+#   Check whether pid_t is a long, int, or short.  DEFINE PRINTF_PID_T to the
+#   corresponding printf format.
+#
+AC_DEFUN([AMANDA_TYPE_PID_T], [
+       AC_REQUIRE([AC_HEADER_STDC])
+       AC_REQUIRE([AC_TYPE_PID_T])
+       AC_CACHE_CHECK([for pid_t type], amanda_cv_pid_type,
+           [
+               amanda_cv_pid_type=unknown
+               if test "$ac_cv_type_pid_t" = no; then
+                   amanda_cv_pid_type=int
+               fi
+               for TEST_amanda_cv_pid_type in long short int; do
+                   if test $amanda_cv_pid_type = unknown; then
+                       AC_EGREP_CPP(typedef.*${TEST_amanda_cv_pid_type}.*pid_t,
+                           [
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+                           ],
+                       amanda_cv_pid_type=$TEST_amanda_cv_pid_type)
+                   fi
+                   if test $amanda_cv_pid_type = unknown; then
+                       AC_EGREP_CPP(ZZZZ.*${TEST_amanda_cv_pid_type},
+                           [
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+                               ZZZZ pid_t
+                       ],
+                       amanda_cv_pid_type=$TEST_amanda_cv_pid_type)
+                   fi
+               done
+               if test $amanda_cv_pid_type = unknown; then
+                   amanda_cv_pid_type=int
+               fi
+           ]
+       )
+       case $amanda_cv_pid_type in
+           int)        AC_DEFINE_UNQUOTED(PRINTF_PID_T,"%d",[Define to printf formatting string to print a PID. ]) ;;
+           long)       AC_DEFINE_UNQUOTED(PRINTF_PID_T,"%ld") ;;
+           short)      AC_DEFINE_UNQUOTED(PRINTF_PID_T,"%d") ;;
+       esac
+    ]
+)
+
+# SYNOPSIS
+#
+#   CF_WAIT
+#
+# OVERVIEW
+#
+# Test for the presence of <sys/wait.h>, 'union wait', arg-type of 'wait()'.
+# by T.E.Dickey" , Jim Spath <jspath@mail.bcpl.lib.md.us>
+#
+#   DEFINEs WAIT_USES_UNION if 'union wait' is found.  Note that many systems
+#   support *both* 'union wait' and 'int' using a transparent union.
+#
+#   Original comments:
+#
+#     FIXME: These tests should have been in autoconf 1.11!
+#
+#     Note that we cannot simply grep for 'union wait' in the wait.h file,
+#     because some Posix systems turn this on only when a BSD variable is
+#     defined. Since I'm trying to do without special defines, I'll live
+#     with the default behavior of the include-file.
+#
+#     I do _2_ compile checks, because we may have union-wait, but the
+#     prototype for 'wait()' may want an int.
+#
+#     Don't use HAVE_UNION_WAIT, because the autoconf documentation implies
+#     that if we've got union-wait, we'll automatically use it.
+#
+# Garrett Wollman adds:
+#      The tests described above don't quite do the right thing,
+#      since some systems have hacks which allow `union wait' to
+#      still work even though `int' is preferred (and generates
+#      fewer warnings).  Since all of these systems use prototypes,
+#      we can use the prototype of wait(2) to disambiguate them.
+#
+# Alexandre Oliva adds:
+#     A single compile check is enough.  If we don't have union wait,
+#     it's obvious that the test will fail, and that we must use int.
+#     If we do, the prototype (on STDC systems) and WIFEXITED will tell
+#     whether we're supposed to be using union wait instead of int.
+#
+AC_DEFUN([CF_WAIT], [
+    AC_REQUIRE([AC_TYPE_PID_T])
+    AC_HAVE_HEADERS(sys/wait.h wait.h)
+    AC_CACHE_CHECK([whether wait uses union wait], [cf_cv_arg_union_wait], [
+        AC_TRY_COMPILE([
+#include <sys/types.h>
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#else
+# if HAVE_WAIT_H
+#  include <wait.h>
+# endif
+#endif
+
+#ifdef __STDC__
+pid_t wait(union wait *);
+#endif
+], [
+  union wait x; int i;
+  wait(&x); i = WIFEXITED(x)
+], [cf_cv_arg_union_wait=yes], [cf_cv_arg_union_wait=no])])
+    if test $cf_cv_arg_union_wait = yes; then
+           AC_DEFINE(WAIT_USES_UNION,1,
+               [Defined if wait() puts the status in a union wait instead of int. ])
+    fi
+])
+
+# SYNOPSIS
+#
+#   CF_WAIT_INT
+#
+# OVERVIEW
+#
+# Test for the presence of <sys/wait.h>, 'union wait', arg-type of 'wait()'.
+# by T.E.Dickey" , Jim Spath <jspath@mail.bcpl.lib.md.us>
+#
+#   DEFINEs WAIT_USES_INT if an int result type is found.
+#
+AC_DEFUN([CF_WAIT_INT], [
+    AC_REQUIRE([AC_TYPE_PID_T])
+    AC_HAVE_HEADERS(sys/wait.h wait.h)
+    AC_CACHE_CHECK([whether wait uses int], [cf_cv_arg_int], [
+        AC_TRY_COMPILE([
+#include <sys/types.h>
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#else
+# if HAVE_WAIT_H
+#  include <wait.h>
+# endif
+#endif
+
+#ifdef __STDC__
+pid_t wait(int *);
+#endif
+], [
+  int x; int i;
+  wait(&x); i = WIFEXITED(x)
+], [cf_cv_arg_int=yes], [cf_cv_arg_int=no])])
+if test $cf_cv_arg_int = yes; then
+        AC_DEFINE(WAIT_USES_INT,1,
+           [Defined if wait() puts the status in a int instead of a union wait. ])
+fi
+])
+
diff --git a/config/amanda/userid.m4 b/config/amanda/userid.m4
new file mode 100644 (file)
index 0000000..8ef15c8
--- /dev/null
@@ -0,0 +1,187 @@
+# SYNOPSIS
+#
+#   AMANDA_DISABLE_INSTALLPERMS
+#
+# OVERVIEW
+#
+#   Handle the --disable-installperms option, which disables all post-install
+#   chown/chmod operations.  This is useful when packaging, as most packaging
+#   systems build as non-root, and apply permissions in the post-install step of
+#   the package itself.
+#
+AC_DEFUN([AMANDA_DISABLE_INSTALLPERMS],
+[
+    WANT_INSTALLPERMS=yes
+    AC_ARG_ENABLE(installperms,
+        AS_HELP_STRING([--disable-installperms],
+                [do not modify ownership and permissions on installed files]),
+        [ WANT_INSTALLPERMS="$enableval" ],
+        [ WANT_INSTALLPERMS="yes" ]
+    )
+    AM_CONDITIONAL(WANT_INSTALLPERMS, test x"$WANT_INSTALLPERMS" = x"yes")
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_FORCE_UID
+#
+# OVERVIEW
+#
+#   Handle the --without-force-id option, which disables userid checks for
+#   all Amanda applications.  Defines CHECK_USERID *unless* this option is
+#   given.
+#
+AC_DEFUN([AMANDA_WITH_FORCE_UID],
+[
+    AC_ARG_WITH(force-uid,
+        AS_HELP_STRING([--without-force-uid],
+                [do not check userids when running programs]),
+        CHECK_USERID="$withval",
+        : ${CHECK_USERID=yes}
+    )
+    case "$CHECK_USERID" in
+        y | ye | yes) 
+            AC_DEFINE(CHECK_USERID, 1,
+                [Define to force to another user on client machines. ])
+          ;;
+        n | no) :
+          ;;
+        *)
+            AC_MSG_ERROR([*** You must not supply an argument to --with-force-uid option.])
+    esac
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_USER
+#
+# OVERVIEW
+#
+#   Handle the --with-user option, which sets the userid Amanda expects to run
+#   under.  Defines and substitutes CLIENT_LOGIN.
+#
+AC_DEFUN([AMANDA_WITH_USER],
+[
+    AC_ARG_WITH(user,
+        AS_HELP_STRING([--with-user=USER],
+                [force execution to USER on client systems (REQUIRED)]),
+        [
+            case "$withval" in
+                "" | y | ye | yes | n | no)
+                    AC_MSG_ERROR([*** You must supply an argument to the --with-user option.])
+                  ;;
+                *) 
+                    CLIENT_LOGIN="$withval"
+                  ;;
+            esac
+        ], [
+            AMANDA_MSG_WARN([[no user specified (--with-user) -- using 'amanda']])
+           CLIENT_LOGIN=amanda
+        ]
+    )
+
+    AC_DEFINE_UNQUOTED(CLIENT_LOGIN,"$CLIENT_LOGIN",
+        [Define as a the user to force to on client machines. ])
+    AC_SUBST(CLIENT_LOGIN)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_GROUP
+#
+# OVERVIEW
+#
+#   Handle the --with-group option, which sets the groupid Amanda expects to run
+#   under.  Substitutes (but does not define) SETUID_GROUP.
+#
+AC_DEFUN([AMANDA_WITH_GROUP],
+[
+    AC_ARG_WITH(group,
+        AS_HELP_STRING([--with-group=GROUP],
+            [group allowed to execute setuid-root programs (REQUIRED)]),
+        [
+            case "$withval" in
+                "" | y | ye | yes | n | no)
+                    AC_MSG_ERROR([*** You must supply an argument to the --with-group option.])
+                  ;;
+                *) SETUID_GROUP="$withval"
+                  ;;
+            esac
+        ], [
+            AMANDA_MSG_WARN([[no group specified (--with-group) -- using 'backup']])
+           CLIENT_LOGIN=backup
+        ]
+    )
+    AC_SUBST(SETUID_GROUP)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_OWNER
+#
+# OVERVIEW
+#
+#   Handle the --with-owner option, which sets the userid the 'make install' process
+#   will use.  Substitutes and defines BINARY_OWNER.
+#
+AC_DEFUN([AMANDA_WITH_OWNER],
+[
+    AC_REQUIRE([AMANDA_WITH_USER])
+    AC_ARG_WITH(owner,
+        AS_HELP_STRING([--with-owner=USER]
+            [force ownership of installed files to USER (default same as --with-user)]),
+        [
+            case "$withval" in
+            "" | y | ye | yes | n | no)
+                AC_MSG_ERROR([*** You must supply an argument to the --with-owner option.])
+              ;;
+            *) BINARY_OWNER="$withval"
+              ;;
+            esac
+        ], [
+            BINARY_OWNER="$CLIENT_LOGIN"
+        ]
+    )
+    AC_DEFINE_UNQUOTED(BINARY_OWNER,"$BINARY_OWNER",
+        [Define as the user who owns installed binaries. ])
+    AC_SUBST(BINARY_OWNER)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_SINGLE_USERID
+#
+# OVERVIEW
+#
+#   Check if this system is one on which clients should be built setuid, 
+#   Sets up AM_CONDITIONAL/define WANT_SETUID_CLIENT and defines 
+#   SINGLE_USERID if either the system requires it or the user specified it.
+#
+AC_DEFUN([AMANDA_WITH_SINGLE_USERID],
+[
+    SINGLE_USERID=${SINGLE_USERID:-no}
+    WANT_SETUID_CLIENT=${WANT_SETUID_CLIENT:-true}
+
+    AC_ARG_WITH(single-userid,
+        AS_HELP_STRING([--with-single-userid]
+            [force amanda to run as a single userid (for testing)]),
+        [   SINGLE_USERID=$withval ])
+
+    case "$target" in
+        *-pc-cygwin)
+            WANT_SETUID_CLIENT=false
+           SINGLE_USERID=yes
+            ;;
+    esac
+
+    if test x"$WANT_SETUID_CLIENT" = x"true"; then
+        AC_DEFINE(WANT_SETUID_CLIENT,1,
+            [Define if clients should be built setuid-root])
+    fi
+    AM_CONDITIONAL(WANT_SETUID_CLIENT, test x"$WANT_SETUID_CLIENT" = x"true")
+
+    if test x"$SINGLE_USERID" = x"yes"; then
+        AC_DEFINE(SINGLE_USERID, 1,
+           [Define if all of Amanda will run as a single userid (e.g., on Cygwin or for installchecks)])
+    fi
+])
diff --git a/config/amanda/version.m4 b/config/amanda/version.m4
new file mode 100644 (file)
index 0000000..f1ecb8a
--- /dev/null
@@ -0,0 +1,115 @@
+# Amanda version handling macros
+
+# SYNOPSIS
+#
+#   AMANDA_SNAPSHOT_STAMP
+#
+# DESCRIPTION
+#
+#   If srcdir contains a file named SNAPSHOT, with a line matching
+#      Snapshot Date: [0-9]*
+#   then set add the date to VERSION and set 
+#   SNAPSHOT_STAMP=SNAPSHOT.
+#
+AC_DEFUN([AMANDA_SNAPSHOT_STAMP],
+[
+    if test -f "$srcdir/SNAPSHOT"; then
+      cat < "$srcdir/SNAPSHOT"
+    changequote(,)
+      snapdate=`sed -n '/^Snapshot Date: \([0-9]*\)/ s//\1/p' < $srcdir/SNAPSHOT`
+    changequote([,])
+      test -z "$snapdate" || VERSION="$VERSION-$snapdate"
+      SNAPSHOT_STAMP=SNAPSHOT
+    else
+      SNAPSHOT_STAMP=
+    fi
+    AC_SUBST(SNAPSHOT_STAMP)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_SPLIT_VERSION
+#
+# DESCRIPTION
+#
+#   Set the version number of this release of Amanda from the VERSION
+#   string, which is set in AM_INIT_AUTOMAKE.  Sets VERSION_MAJOR,
+#   VERSION_MINOR, VERSION_PATCH, and VERSION_COMMENT to the 
+#   corresponding components of VERSION, and VERSION_SUFFIX to a
+#   version-specific filename suffix.
+#
+AC_DEFUN([AMANDA_SPLIT_VERSION],
+[
+    changequote(,)
+    VERSION_MAJOR=`expr "$VERSION" : '\([0-9]*\)'`
+    VERSION_MINOR=`expr "$VERSION" : '[0-9]*\.\([0-9]*\)'`
+    VERSION_PATCH=`expr "$VERSION" : '[0-9]*\.[0-9]*\.\([0-9]*\)'`
+    VERSION_COMMENT=\"`expr "$VERSION" : '[0-9]*\.[0-9]*\.[0-9]*\(.*\)'`\"
+    changequote([,])
+
+    VERSION_SUFFIX="$VERSION"
+    AC_SUBST(VERSION_MAJOR)
+    AC_SUBST(VERSION_MINOR)
+    AC_SUBST(VERSION_PATCH)
+    AC_SUBST(VERSION_COMMENT)
+    AC_SUBST(VERSION_SUFFIX)
+])
+
+# SYNOPSIS
+#
+#   AMANDA_WITH_SUFFIXES
+#
+# DESCRIPTION
+#
+#   Implement the --with-suffixes option.  If it is given, then set
+#   program_transform_name appropriately and AC_DEFINE USE_VERSION_SUFFIXES to 1.
+#   USE_VERSION_SUFFIXES is substituted with the value 'no' or 'yes'.
+#
+AC_DEFUN([AMANDA_WITH_SUFFIXES],
+[
+    AC_ARG_WITH(suffixes,
+       [  --with-suffixes        install binaries with version string appended to name],
+       USE_VERSION_SUFFIXES=$withval,
+       : ${USE_VERSION_SUFFIXES=no}
+    )
+
+    case "$USE_VERSION_SUFFIXES" in
+    y | ye | yes) USE_VERSION_SUFFIXES=yes
+       AC_DEFINE(USE_VERSION_SUFFIXES, 1,
+           [Define to have programs use version suffixes when calling other programs.])
+
+       program_suffix="-$VERSION_SUFFIX"
+       # This is from the output of configure.in.
+       if test "x$program_transform_name" = xs,x,x,; then
+           program_transform_name=
+       else
+           # Double any \ or $.  echo might interpret backslashes.
+           cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+           program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+           rm -f conftestsed
+       fi
+       test "x$program_prefix" != xNONE &&
+           program_transform_name="s,^,${program_prefix},; $program_transform_name"
+       # Use a double $ so make ignores it.
+       test "x$program_suffix" != xNONE &&
+           program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+       # sed with no file args requires a program.
+       test "x$program_transform_name" = "" && program_transform_name="xs,x,x,"
+       # Remove empty command
+       cat <<\EOF_SED > conftestsed
+s,\;\;,\;,g; s,\; \$,,g; s,\;$,,g
+EOF_SED
+       program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+       rm -f conftestsed
+      ;;
+    n | no) USE_VERSION_SUFFIXES=no
+      ;;
+    *) AC_MSG_ERROR([*** You must not supply an argument to --with-suffixes option.])
+      ;;
+    esac
+
+    AC_SUBST(USE_VERSION_SUFFIXES)
+])
diff --git a/config/automake/file-list b/config/automake/file-list
new file mode 100644 (file)
index 0000000..7038942
--- /dev/null
@@ -0,0 +1,5 @@
+## this file is automatically generated by autogen
+EXTRA_DIST += automake/installperms.am
+EXTRA_DIST += automake/precompile.am
+EXTRA_DIST += automake/scripts.am
+EXTRA_DIST += automake/vars.am
diff --git a/config/automake/installperms.am b/config/automake/installperms.am
new file mode 100644 (file)
index 0000000..245345b
--- /dev/null
@@ -0,0 +1,91 @@
+# vim:ft=automake
+#
+# Adjust post-install permissions settings.  This rule works off two
+# specially-formatted variables, INSTALLPERMS_exec and INSTALLPERMS_data. 
+# Each is a whitespace-separated list of commands, all of which are either
+# a variable assignment or a filename.  Three variables are available:
+#
+#  - dest= sets the destination directory to e.g., $(sbindir)
+#  - chown= controls changes in ownership; value is first argument to chown
+#  - chmod= controls changes in permissions; value is first argument to chmod
+#
+# As a special case, chown=amanda is taken as equivalent to 
+# chown=$(BINARY_OWNER):$(SETUID_GROUP), which may otherwise have problems with
+# whitespace in the user/group names.
+# 
+# when a filename is seen, the currently active variables are applied.
+#
+# Note that scripts are data, not executables!
+#
+# EXAMPLE
+#
+# sbin_PROGRAMS = foo bar bing
+# libexec_PROGRAMS = pro gram
+# sbin_SCRIPTS = sk ript
+# INSTALLPERMS_exec = \
+#      dest=$(sbindir) chown=amanda chmod= \
+#              foo bar \
+#      chmod=u+s,o-rwx \
+#              bing
+#      dest=$(libexecdir) chmod= \
+#              $(libexec_PROGRAMS)
+# INSTALLPERMS_data = \
+#      dest=$(sbindir) chown=amanda chmod= \
+#              $(sbin_SCRIPTS)
+#
+# This whole operation is not required when making builds for packaging,
+# and can be disabled with --disable-installperms, via the WANT_INSTALLPERMS
+# AM_CONDITIONAL.
+
+# sed expression to strip leading directories from a filename; this converts e.g.,
+# src/foo/bar.so to bar.so.
+strip_leading_dirs=s|^.*/||
+
+if WANT_INSTALLPERMS
+installperms-exec:
+       @installperms="$(INSTALLPERMS_exec)"; \
+       test -n "$$installperms" && echo "Setting installation permissions on executables"; \
+       dest=; chown=; chmod=; \
+       for cmd in $$installperms; do \
+           case "$$cmd" in \
+               chown=amanda) \
+                       echo "  ($$cmd)"; chown="$(BINARY_OWNER):$(SETUID_GROUP)";; \
+               dest=*|chown=*|chmod=*) \
+                       echo "  ($$cmd)"; eval $$cmd;; \
+               *)  pa="$(DESTDIR)$$dest"/`echo "$$cmd"|sed '$(strip_leading_dirs)'|sed '$(transform)'`; \
+                   if test -n "$$chown"; then \
+                       echo chown "$$chown" "$$pa"; \
+                       chown "$$chown" "$$pa" || exit 1; \
+                   fi; \
+                   if test -n "$$chmod"; then \
+                       echo chmod "$$chmod" "$$pa"; \
+                       chmod "$$chmod" "$$pa" || exit 1; \
+                   fi; \
+           esac; \
+       done
+
+installperms-data:
+       @installperms="$(INSTALLPERMS_data)"; \
+       test -n "$$installperms" && echo "Setting installation permissions on data"; \
+       dest=; chown=; chmod=; \
+       for cmd in $$installperms; do \
+           case "$$cmd" in \
+               chown=amanda) \
+                       echo "  ($$cmd)"; chown="$(BINARY_OWNER):$(SETUID_GROUP)";; \
+               dest=*|chown=*|chmod=*) \
+                       echo "  ($$cmd)"; eval $$cmd;; \
+               *)  pa="$(DESTDIR)$$dest"/`echo "$$cmd"|sed '$(strip_leading_dirs)'|sed '$(transform)'`; \
+                   if test -n "$$chown"; then \
+                       echo chown "$$chown" "$$pa"; \
+                       chown "$$chown" "$$pa" || exit 1; \
+                   fi; \
+                   if test -n "$$chmod"; then \
+                       echo chmod "$$chmod" "$$pa"; \
+                       chmod "$$chmod" "$$pa" || exit 1; \
+                   fi; \
+           esac; \
+       done
+
+install-exec-hook: installperms-exec
+install-data-hook: installperms-data
+endif
diff --git a/config/automake/precompile.am b/config/automake/precompile.am
new file mode 100644 (file)
index 0000000..36444d9
--- /dev/null
@@ -0,0 +1,11 @@
+# vim:ft=automake
+
+# A rule to make precompiler output from C files.  This is not used during
+# ordinary builds, but but can very useful in debugging problems on strange
+# architectures.  With this rule, we can ask users to 'make foo.i' and send
+# the result to us.
+#
+# It touches some automake internals ($COMPILE), but since it's not
+# build-critical, that's OK.
+%.i : %.c
+       $(COMPILE) -E -o $@ $<
diff --git a/config/automake/scripts.am b/config/automake/scripts.am
new file mode 100644 (file)
index 0000000..129df49
--- /dev/null
@@ -0,0 +1,141 @@
+# vim:ft=automake
+# Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+# 
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License version 2.1 as 
+# published by the Free Software Foundation.
+# 
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+# 
+# Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+# SYNOPSIS:
+#
+# Automake magic to handle the various tasks of building scripts.  Scripts can
+# be built down to extensionless executables (e.g., foo.pl -> foo), or to 
+# files with the usual extension (foo-lib.sh.in -> foo.sh).
+#
+# Files which support it are syntax-checked when the user invokes 'make check'.
+#
+# All *target* filenames must be listed in SCRIPTS_SHELL, SCRIPTS_PERL, and 
+# SCRIPTS_AWK to support 'make check', 'make dist', and 'make distclean'.
+#
+# USAGE:
+#
+#   include $(top_srcdir)/config/automake/vars.am
+#   include $(top_srcdir)/config/automake/scripts.am
+#   ...
+#   SCRIPTS_PERL = fooscript barscript perl-lib.pl perlmod.pm
+#   SCRIPTS_SHELL = shell1 shell2 sh-lib.sh
+#   SCRIPTS_AWK = talk balk chalk awk-lib.awk
+#
+# with the corresponding files in the repository:
+#
+#   fooscript.pl barscript.pl perl-lib.pl.in perlmod.pm.in
+#   shell1.sh shell2.sh sh-lib.sh.in
+#   talk.awk balk.awk chalk.awk awk-lib.awk.in
+#
+# by default, all shell and perl scripts are syntax checked.  If this is
+# a problem (for example, perl scripts depending on Amanda extension 
+# modules), then assign to CHECK_{PERL,SHELL} the list of files you wish
+# to be checked (which can be empty).
+#
+# To add extra flags to the perl checks (e.g., to add new -I flags), set
+# CHECK_PERL_FLAGS.
+
+# Implementation note:
+#
+# This file uses config.status to substitute @foo@ in those scripts while
+# converting them. It also adds the executable bits (a+x) to extensionless
+# files.  The substitution works even though the files are not listed in 
+# configure.in
+
+# Perl
+%: %.pl $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+       chmod a+x $@
+
+%.pl: %.pl.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+%.pm: %.pm.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+# Shell
+%: %.sh $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+       chmod a+x $@
+
+%.sh: %.sh.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+# Awk
+%: %.awk $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+       chmod a+x $@
+
+%.awk: %.awk.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+# config.status leaves config.log files around
+CLEANFILES += config.log
+
+# and we'll need to clean up our generated files for distclean
+DISTCLEANFILES += $(SCRIPTS_SHELL) $(SCRIPTS_PERL) $(SCRIPTS_AWK)
+
+# syntax-check perl scripts on 'make check'
+check-perl: $(CHECK_PERL)
+       @CHECK_PERL="$(CHECK_PERL)"; \
+       if test -n "$(PERL)"; then \
+               for perlobj in $$CHECK_PERL; do \
+                       $(PERL) $(CHECK_PERL_FLAGS) -c -w -T $$perlobj || exit 1; \
+               done; \
+       fi
+check-local: check-perl
+
+# syntax-check shell scripts on 'make check'
+CHECK_SHELL = $(SCRIPTS_SHELL)
+check-shell: $(CHECK_SHELL)
+       @CHECK_SHELL="$(CHECK_SHELL)"; \
+       if test -n "$$CHECK_SHELL"; then \
+               if test -n "$(BASH)"; then \
+                       for shobj in $$CHECK_SHELL; do \
+                               if $(BASH) -n $$shobj; then \
+                                       echo "$$shobj syntax OK"; \
+                               else \
+                                       echo "$$shobj syntax error"; \
+                                       exit 1; \
+                               fi; \
+                       done; \
+               else \
+                       echo "No 'bash' available -- cannot syntax-check shell scripts"; \
+               fi; \
+       fi
+check-local: check-shell
+
+# make sure that the sources for all shell and perl scripts get included
+# in the distribution
+dist-scripts:
+       SCRIPTS_PERL="$(SCRIPTS_PERL)"; SCRIPTS_SHELL="$(SCRIPTS_SHELL)"; SCRIPTS_AWK="$(SCRIPTS_AWK)"; \
+       for script in $$SCRIPTS_PERL; do \
+               test -f $(srcdir)/$${script}.pl && { cp -p $(srcdir)/$${script}.pl $(distdir)/ || exit 1; } \
+       done; \
+       for script in $$SCRIPTS_SHELL; do \
+               test -f $(srcdir)/$${script}.sh && { cp -p $(srcdir)/$${script}.sh $(distdir)/ || exit 1; } \
+       done; \
+       for script in $$SCRIPTS_AWK; do \
+               test -f $(srcdir)/$${script}.awk && { cp -p $(srcdir)/$${script}.awk $(distdir)/ || exit 1; } \
+       done; \
+       for script in $$SCRIPTS_SHELL $$SCRIPTS_PERL $$SCRIPTS_AWK; do \
+               test -f $(srcdir)/$${script}.in && { cp -p $(srcdir)/$${script}.in $(distdir)/ || exit 1; } \
+       done; \
+       true
+dist-hook: dist-scripts
diff --git a/config/automake/vars.am b/config/automake/vars.am
new file mode 100644 (file)
index 0000000..88aa8a8
--- /dev/null
@@ -0,0 +1,32 @@
+# vim:ft=automake
+# Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+# 
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License version 2.1 as 
+# published by the Free Software Foundation.
+# 
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+# 
+# Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+# simple include file to pre-define variables which are then +='d by other
+# scripts in this directory.
+
+SUFFIXES =
+
+EXTRA_DIST =
+
+BUILT_SOURCES =
+
+MOSTLYCLEANFILES =
+CLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES = 
diff --git a/config/compile b/config/compile
new file mode 100644 (file)
index 0000000..80b645b
--- /dev/null
@@ -0,0 +1,140 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2004-09-10.20
+
+# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit 0
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit 0
+    ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+       # configure might choose to run compile as `compile cc -o foo foo.c'.
+       # So we strip `-o arg' only if arg is an object.
+       eat=1
+       case $2 in
+         *.o | *.obj)
+           ofile=$2
+           ;;
+         *)
+           set x "$@" -o "$2"
+           shift
+           ;;
+       esac
+       ;;
+      *.c)
+       cfile=$1
+       set x "$@" "$1"
+       shift
+       ;;
+      *)
+       set x "$@" "$1"
+       shift
+       ;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no `-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # `.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  mv "$cofile" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/config/gettext-macros/codeset.m4 b/config/gettext-macros/codeset.m4
new file mode 100644 (file)
index 0000000..a6e67ec
--- /dev/null
@@ -0,0 +1,21 @@
+# codeset.m4 serial AM1 (gettext-0.10.40)
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_LANGINFO_CODESET],
+[
+  AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset,
+    [AC_TRY_LINK([#include <langinfo.h>],
+      [char* cs = nl_langinfo(CODESET);],
+      am_cv_langinfo_codeset=yes,
+      am_cv_langinfo_codeset=no)
+    ])
+  if test $am_cv_langinfo_codeset = yes; then
+    AC_DEFINE(HAVE_LANGINFO_CODESET, 1,
+      [Define if you have <langinfo.h> and nl_langinfo(CODESET).])
+  fi
+])
diff --git a/config/gettext-macros/file-list b/config/gettext-macros/file-list
new file mode 100644 (file)
index 0000000..60ef11b
--- /dev/null
@@ -0,0 +1,30 @@
+## this file is automatically generated by autogen
+EXTRA_DIST += gettext-macros/codeset.m4
+EXTRA_DIST += gettext-macros/gettext.m4
+EXTRA_DIST += gettext-macros/glibc21.m4
+EXTRA_DIST += gettext-macros/glibc2.m4
+EXTRA_DIST += gettext-macros/iconv.m4
+EXTRA_DIST += gettext-macros/intdiv0.m4
+EXTRA_DIST += gettext-macros/intmax.m4
+EXTRA_DIST += gettext-macros/inttypes_h.m4
+EXTRA_DIST += gettext-macros/inttypes.m4
+EXTRA_DIST += gettext-macros/inttypes-pri.m4
+EXTRA_DIST += gettext-macros/isc-posix.m4
+EXTRA_DIST += gettext-macros/lcmessage.m4
+EXTRA_DIST += gettext-macros/lib-ld.m4
+EXTRA_DIST += gettext-macros/lib-link.m4
+EXTRA_DIST += gettext-macros/lib-prefix.m4
+EXTRA_DIST += gettext-macros/longdouble.m4
+EXTRA_DIST += gettext-macros/longlong.m4
+EXTRA_DIST += gettext-macros/nls.m4
+EXTRA_DIST += gettext-macros/po.m4
+EXTRA_DIST += gettext-macros/printf-posix.m4
+EXTRA_DIST += gettext-macros/progtest.m4
+EXTRA_DIST += gettext-macros/signed.m4
+EXTRA_DIST += gettext-macros/size_max.m4
+EXTRA_DIST += gettext-macros/stdint_h.m4
+EXTRA_DIST += gettext-macros/uintmax_t.m4
+EXTRA_DIST += gettext-macros/ulonglong.m4
+EXTRA_DIST += gettext-macros/wchar_t.m4
+EXTRA_DIST += gettext-macros/wint_t.m4
+EXTRA_DIST += gettext-macros/xsize.m4
diff --git a/config/gettext-macros/gettext.m4 b/config/gettext-macros/gettext.m4
new file mode 100644 (file)
index 0000000..fdcaecc
--- /dev/null
@@ -0,0 +1,631 @@
+# gettext.m4 serial 53 (gettext-0.15)
+dnl Copyright (C) 1995-2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl   Bruno Haible <haible@clisp.cons.org>, 2000-2005.
+
+dnl Macro to add for using GNU gettext.
+
+dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]).
+dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The
+dnl    default (if it is not specified or empty) is 'no-libtool'.
+dnl    INTLSYMBOL should be 'external' for packages with no intl directory,
+dnl    and 'no-libtool' or 'use-libtool' for packages with an intl directory.
+dnl    If INTLSYMBOL is 'use-libtool', then a libtool library
+dnl    $(top_builddir)/intl/libintl.la will be created (shared and/or static,
+dnl    depending on --{enable,disable}-{shared,static} and on the presence of
+dnl    AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library
+dnl    $(top_builddir)/intl/libintl.a will be created.
+dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext
+dnl    implementations (in libc or libintl) without the ngettext() function
+dnl    will be ignored.  If NEEDSYMBOL is specified and is
+dnl    'need-formatstring-macros', then GNU gettext implementations that don't
+dnl    support the ISO C 99 <inttypes.h> formatstring macros will be ignored.
+dnl INTLDIR is used to find the intl libraries.  If empty,
+dnl    the value `$(top_builddir)/intl/' is used.
+dnl
+dnl The result of the configuration is one of three cases:
+dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled
+dnl    and used.
+dnl    Catalog format: GNU --> install in $(datadir)
+dnl    Catalog extension: .mo after installation, .gmo in source tree
+dnl 2) GNU gettext has been found in the system's C library.
+dnl    Catalog format: GNU --> install in $(datadir)
+dnl    Catalog extension: .mo after installation, .gmo in source tree
+dnl 3) No internationalization, always use English msgid.
+dnl    Catalog format: none
+dnl    Catalog extension: none
+dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur.
+dnl The use of .gmo is historical (it was needed to avoid overwriting the
+dnl GNU format catalogs when building on a platform with an X/Open gettext),
+dnl but we keep it in order not to force irrelevant filename changes on the
+dnl maintainers.
+dnl
+AC_DEFUN([AM_GNU_GETTEXT],
+[
+  dnl Argument checking.
+  ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], ,
+    [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT
+])])])])])
+  ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], ,
+    [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT
+])])])])
+  define([gt_included_intl], ifelse([$1], [external], [no], [yes]))
+  define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], []))
+
+  AC_REQUIRE([AM_PO_SUBDIRS])dnl
+  ifelse(gt_included_intl, yes, [
+    AC_REQUIRE([AM_INTL_SUBDIR])dnl
+  ])
+
+  dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+
+  dnl Sometimes libintl requires libiconv, so first search for libiconv.
+  dnl Ideally we would do this search only after the
+  dnl      if test "$USE_NLS" = "yes"; then
+  dnl        if test "$gt_cv_func_gnugettext_libc" != "yes"; then
+  dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT
+  dnl the configure script would need to contain the same shell code
+  dnl again, outside any 'if'. There are two solutions:
+  dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'.
+  dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE.
+  dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not
+  dnl documented, we avoid it.
+  ifelse(gt_included_intl, yes, , [
+    AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
+  ])
+
+  dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation.
+  gt_INTL_MACOSX
+
+  dnl Set USE_NLS.
+  AC_REQUIRE([AM_NLS])
+
+  ifelse(gt_included_intl, yes, [
+    BUILD_INCLUDED_LIBINTL=no
+    USE_INCLUDED_LIBINTL=no
+  ])
+  LIBINTL=
+  LTLIBINTL=
+  POSUB=
+
+  dnl If we use NLS figure out what method
+  if test "$USE_NLS" = "yes"; then
+    gt_use_preinstalled_gnugettext=no
+    ifelse(gt_included_intl, yes, [
+      AC_MSG_CHECKING([whether included gettext is requested])
+      AC_ARG_WITH(included-gettext,
+        [  --with-included-gettext use the GNU gettext library included here],
+        nls_cv_force_use_gnu_gettext=$withval,
+        nls_cv_force_use_gnu_gettext=no)
+      AC_MSG_RESULT($nls_cv_force_use_gnu_gettext)
+
+      nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext"
+      if test "$nls_cv_force_use_gnu_gettext" != "yes"; then
+    ])
+        dnl User does not insist on using GNU NLS library.  Figure out what
+        dnl to use.  If GNU gettext is available we use this.  Else we have
+        dnl to fall back to GNU NLS library.
+
+        dnl Add a version number to the cache macros.
+        define([gt_api_version], ifelse([$2], [need-formatstring-macros], 3, ifelse([$2], [need-ngettext], 2, 1)))
+        define([gt_cv_func_gnugettext_libc], [gt_cv_func_gnugettext]gt_api_version[_libc])
+        define([gt_cv_func_gnugettext_libintl], [gt_cv_func_gnugettext]gt_api_version[_libintl])
+
+        AC_CACHE_CHECK([for GNU gettext in libc], gt_cv_func_gnugettext_libc,
+         [AC_TRY_LINK([#include <libintl.h>
+]ifelse([$2], [need-formatstring-macros],
+[[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION
+#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1)
+#endif
+typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1];
+]], [])[extern int _nl_msg_cat_cntr;
+extern int *_nl_domain_bindings;],
+            [bindtextdomain ("", "");
+return * gettext ("")]ifelse([$2], [need-ngettext], [ + * ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_domain_bindings],
+            gt_cv_func_gnugettext_libc=yes,
+            gt_cv_func_gnugettext_libc=no)])
+
+        if test "$gt_cv_func_gnugettext_libc" != "yes"; then
+          dnl Sometimes libintl requires libiconv, so first search for libiconv.
+          ifelse(gt_included_intl, yes, , [
+            AM_ICONV_LINK
+          ])
+          dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL
+          dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv])
+          dnl because that would add "-liconv" to LIBINTL and LTLIBINTL
+          dnl even if libiconv doesn't exist.
+          AC_LIB_LINKFLAGS_BODY([intl])
+          AC_CACHE_CHECK([for GNU gettext in libintl],
+            gt_cv_func_gnugettext_libintl,
+           [gt_save_CPPFLAGS="$CPPFLAGS"
+            CPPFLAGS="$CPPFLAGS $INCINTL"
+            gt_save_LIBS="$LIBS"
+            LIBS="$LIBS $LIBINTL"
+            dnl Now see whether libintl exists and does not depend on libiconv.
+            AC_TRY_LINK([#include <libintl.h>
+]ifelse([$2], [need-formatstring-macros],
+[[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION
+#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1)
+#endif
+typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1];
+]], [])[extern int _nl_msg_cat_cntr;
+extern
+#ifdef __cplusplus
+"C"
+#endif
+const char *_nl_expand_alias (const char *);],
+              [bindtextdomain ("", "");
+return * gettext ("")]ifelse([$2], [need-ngettext], [ + * ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias ("")],
+              gt_cv_func_gnugettext_libintl=yes,
+              gt_cv_func_gnugettext_libintl=no)
+            dnl Now see whether libintl exists and depends on libiconv.
+            if test "$gt_cv_func_gnugettext_libintl" != yes && test -n "$LIBICONV"; then
+              LIBS="$LIBS $LIBICONV"
+              AC_TRY_LINK([#include <libintl.h>
+]ifelse([$2], [need-formatstring-macros],
+[[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION
+#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1)
+#endif
+typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1];
+]], [])[extern int _nl_msg_cat_cntr;
+extern
+#ifdef __cplusplus
+"C"
+#endif
+const char *_nl_expand_alias (const char *);],
+                [bindtextdomain ("", "");
+return * gettext ("")]ifelse([$2], [need-ngettext], [ + * ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias ("")],
+               [LIBINTL="$LIBINTL $LIBICONV"
+                LTLIBINTL="$LTLIBINTL $LTLIBICONV"
+                gt_cv_func_gnugettext_libintl=yes
+               ])
+            fi
+            CPPFLAGS="$gt_save_CPPFLAGS"
+            LIBS="$gt_save_LIBS"])
+        fi
+
+        dnl If an already present or preinstalled GNU gettext() is found,
+        dnl use it.  But if this macro is used in GNU gettext, and GNU
+        dnl gettext is already preinstalled in libintl, we update this
+        dnl libintl.  (Cf. the install rule in intl/Makefile.in.)
+        if test "$gt_cv_func_gnugettext_libc" = "yes" \
+           || { test "$gt_cv_func_gnugettext_libintl" = "yes" \
+                && test "$PACKAGE" != gettext-runtime \
+                && test "$PACKAGE" != gettext-tools; }; then
+          gt_use_preinstalled_gnugettext=yes
+        else
+          dnl Reset the values set by searching for libintl.
+          LIBINTL=
+          LTLIBINTL=
+          INCINTL=
+        fi
+
+    ifelse(gt_included_intl, yes, [
+        if test "$gt_use_preinstalled_gnugettext" != "yes"; then
+          dnl GNU gettext is not found in the C library.
+          dnl Fall back on included GNU gettext library.
+          nls_cv_use_gnu_gettext=yes
+        fi
+      fi
+
+      if test "$nls_cv_use_gnu_gettext" = "yes"; then
+        dnl Mark actions used to generate GNU NLS library.
+        BUILD_INCLUDED_LIBINTL=yes
+        USE_INCLUDED_LIBINTL=yes
+        LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD"
+        LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD"
+        LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'`
+      fi
+
+      CATOBJEXT=
+      if test "$gt_use_preinstalled_gnugettext" = "yes" \
+         || test "$nls_cv_use_gnu_gettext" = "yes"; then
+        dnl Mark actions to use GNU gettext tools.
+        CATOBJEXT=.gmo
+      fi
+    ])
+
+    if test -n "$INTL_MACOSX_LIBS"; then
+      if test "$gt_use_preinstalled_gnugettext" = "yes" \
+         || test "$nls_cv_use_gnu_gettext" = "yes"; then
+        dnl Some extra flags are needed during linking.
+        LIBINTL="$LIBINTL $INTL_MACOSX_LIBS"
+        LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS"
+      fi
+    fi
+
+    if test "$gt_use_preinstalled_gnugettext" = "yes" \
+       || test "$nls_cv_use_gnu_gettext" = "yes"; then
+      AC_DEFINE(ENABLE_NLS, 1,
+        [Define to 1 if translation of program messages to the user's native language
+   is requested.])
+    else
+      USE_NLS=no
+    fi
+  fi
+
+  AC_MSG_CHECKING([whether to use NLS])
+  AC_MSG_RESULT([$USE_NLS])
+  if test "$USE_NLS" = "yes"; then
+    AC_MSG_CHECKING([where the gettext function comes from])
+    if test "$gt_use_preinstalled_gnugettext" = "yes"; then
+      if test "$gt_cv_func_gnugettext_libintl" = "yes"; then
+        gt_source="external libintl"
+      else
+        gt_source="libc"
+      fi
+    else
+      gt_source="included intl directory"
+    fi
+    AC_MSG_RESULT([$gt_source])
+  fi
+
+  if test "$USE_NLS" = "yes"; then
+
+    if test "$gt_use_preinstalled_gnugettext" = "yes"; then
+      if test "$gt_cv_func_gnugettext_libintl" = "yes"; then
+        AC_MSG_CHECKING([how to link with libintl])
+        AC_MSG_RESULT([$LIBINTL])
+        AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL])
+      fi
+
+      dnl For backward compatibility. Some packages may be using this.
+      AC_DEFINE(HAVE_GETTEXT, 1,
+       [Define if the GNU gettext() function is already present or preinstalled.])
+      AC_DEFINE(HAVE_DCGETTEXT, 1,
+       [Define if the GNU dcgettext() function is already present or preinstalled.])
+    fi
+
+    dnl We need to process the po/ directory.
+    POSUB=po
+  fi
+
+  ifelse(gt_included_intl, yes, [
+    dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL
+    dnl to 'yes' because some of the testsuite requires it.
+    if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then
+      BUILD_INCLUDED_LIBINTL=yes
+    fi
+
+    dnl Make all variables we use known to autoconf.
+    AC_SUBST(BUILD_INCLUDED_LIBINTL)
+    AC_SUBST(USE_INCLUDED_LIBINTL)
+    AC_SUBST(CATOBJEXT)
+
+    dnl For backward compatibility. Some configure.ins may be using this.
+    nls_cv_header_intl=
+    nls_cv_header_libgt=
+
+    dnl For backward compatibility. Some Makefiles may be using this.
+    DATADIRNAME=share
+    AC_SUBST(DATADIRNAME)
+
+    dnl For backward compatibility. Some Makefiles may be using this.
+    INSTOBJEXT=.mo
+    AC_SUBST(INSTOBJEXT)
+
+    dnl For backward compatibility. Some Makefiles may be using this.
+    GENCAT=gencat
+    AC_SUBST(GENCAT)
+
+    dnl For backward compatibility. Some Makefiles may be using this.
+    INTLOBJS=
+    if test "$USE_INCLUDED_LIBINTL" = yes; then
+      INTLOBJS="\$(GETTOBJS)"
+    fi
+    AC_SUBST(INTLOBJS)
+
+    dnl Enable libtool support if the surrounding package wishes it.
+    INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix
+    AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX)
+  ])
+
+  dnl For backward compatibility. Some Makefiles may be using this.
+  INTLLIBS="$LIBINTL"
+  AC_SUBST(INTLLIBS)
+
+  dnl Make all documented variables known to autoconf.
+  AC_SUBST(LIBINTL)
+  AC_SUBST(LTLIBINTL)
+  AC_SUBST(POSUB)
+])
+
+
+dnl Checks for all prerequisites of the intl subdirectory,
+dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS,
+dnl            USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL.
+AC_DEFUN([AM_INTL_SUBDIR],
+[
+  AC_REQUIRE([AC_PROG_INSTALL])dnl
+  AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake
+  AC_REQUIRE([AC_PROG_CC])dnl
+  AC_REQUIRE([AC_CANONICAL_HOST])dnl
+  AC_REQUIRE([gt_GLIBC2])dnl
+  AC_REQUIRE([AC_PROG_RANLIB])dnl
+  AC_REQUIRE([gl_VISIBILITY])dnl
+  AC_REQUIRE([gt_INTL_SUBDIR_CORE])dnl
+  AC_REQUIRE([bh_C_SIGNED])dnl
+  AC_REQUIRE([gl_AC_TYPE_LONG_LONG])dnl
+  AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl
+  AC_REQUIRE([gt_TYPE_WCHAR_T])dnl
+  AC_REQUIRE([gt_TYPE_WINT_T])dnl
+  AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+  AC_REQUIRE([gt_TYPE_INTMAX_T])
+  AC_REQUIRE([gt_PRINTF_POSIX])
+  AC_REQUIRE([gl_GLIBC21])dnl
+  AC_REQUIRE([gl_XSIZE])dnl
+  AC_REQUIRE([gt_INTL_MACOSX])dnl
+
+  AC_CHECK_TYPE([ptrdiff_t], ,
+    [AC_DEFINE([ptrdiff_t], [long],
+       [Define as the type of the result of subtracting two pointers, if the system doesn't define it.])
+    ])
+  AC_CHECK_HEADERS([stddef.h stdlib.h string.h])
+  AC_CHECK_FUNCS([asprintf fwprintf putenv setenv setlocale snprintf wcslen])
+
+  dnl Use the _snprintf function only if it is declared (because on NetBSD it
+  dnl is defined as a weak alias of snprintf; we prefer to use the latter).
+  gt_CHECK_DECL(_snprintf, [#include <stdio.h>])
+  gt_CHECK_DECL(_snwprintf, [#include <stdio.h>])
+
+  dnl Use the *_unlocked functions only if they are declared.
+  dnl (because some of them were defined without being declared in Solaris
+  dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built
+  dnl on Solaris 2.5.1 to run on Solaris 2.6).
+  dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13.
+  gt_CHECK_DECL(getc_unlocked, [#include <stdio.h>])
+
+  case $gt_cv_func_printf_posix in
+    *yes) HAVE_POSIX_PRINTF=1 ;;
+    *) HAVE_POSIX_PRINTF=0 ;;
+  esac
+  AC_SUBST([HAVE_POSIX_PRINTF])
+  if test "$ac_cv_func_asprintf" = yes; then
+    HAVE_ASPRINTF=1
+  else
+    HAVE_ASPRINTF=0
+  fi
+  AC_SUBST([HAVE_ASPRINTF])
+  if test "$ac_cv_func_snprintf" = yes; then
+    HAVE_SNPRINTF=1
+  else
+    HAVE_SNPRINTF=0
+  fi
+  AC_SUBST([HAVE_SNPRINTF])
+  if test "$ac_cv_func_wprintf" = yes; then
+    HAVE_WPRINTF=1
+  else
+    HAVE_WPRINTF=0
+  fi
+  AC_SUBST([HAVE_WPRINTF])
+
+  AM_LANGINFO_CODESET
+  gt_LC_MESSAGES
+
+  dnl Compilation on mingw and Cygwin needs special Makefile rules, because
+  dnl 1. when we install a shared library, we must arrange to export
+  dnl    auxiliary pointer variables for every exported variable,
+  dnl 2. when we install a shared library and a static library simultaneously,
+  dnl    the include file specifies __declspec(dllimport) and therefore we
+  dnl    must arrange to define the auxiliary pointer variables for the
+  dnl    exported variables _also_ in the static library.
+  if test "$enable_shared" = yes; then
+    case "$host_os" in
+      cygwin*) is_woe32dll=yes ;;
+      *) is_woe32dll=no ;;
+    esac
+  else
+    is_woe32dll=no
+  fi
+  WOE32DLL=$is_woe32dll
+  AC_SUBST([WOE32DLL])
+
+  dnl Rename some macros and functions used for locking.
+  AH_BOTTOM([
+#define __libc_lock_t                   gl_lock_t
+#define __libc_lock_define              gl_lock_define
+#define __libc_lock_define_initialized  gl_lock_define_initialized
+#define __libc_lock_init                gl_lock_init
+#define __libc_lock_lock                gl_lock_lock
+#define __libc_lock_unlock              gl_lock_unlock
+#define __libc_lock_recursive_t                   gl_recursive_lock_t
+#define __libc_lock_define_recursive              gl_recursive_lock_define
+#define __libc_lock_define_initialized_recursive  gl_recursive_lock_define_initialized
+#define __libc_lock_init_recursive                gl_recursive_lock_init
+#define __libc_lock_lock_recursive                gl_recursive_lock_lock
+#define __libc_lock_unlock_recursive              gl_recursive_lock_unlock
+#define glthread_in_use  libintl_thread_in_use
+#define glthread_lock_init     libintl_lock_init
+#define glthread_lock_lock     libintl_lock_lock
+#define glthread_lock_unlock   libintl_lock_unlock
+#define glthread_lock_destroy  libintl_lock_destroy
+#define glthread_rwlock_init     libintl_rwlock_init
+#define glthread_rwlock_rdlock   libintl_rwlock_rdlock
+#define glthread_rwlock_wrlock   libintl_rwlock_wrlock
+#define glthread_rwlock_unlock   libintl_rwlock_unlock
+#define glthread_rwlock_destroy  libintl_rwlock_destroy
+#define glthread_recursive_lock_init     libintl_recursive_lock_init
+#define glthread_recursive_lock_lock     libintl_recursive_lock_lock
+#define glthread_recursive_lock_unlock   libintl_recursive_lock_unlock
+#define glthread_recursive_lock_destroy  libintl_recursive_lock_destroy
+#define glthread_once                 libintl_once
+#define glthread_once_call            libintl_once_call
+#define glthread_once_singlethreaded  libintl_once_singlethreaded
+])
+])
+
+
+dnl Checks for the core files of the intl subdirectory:
+dnl   dcigettext.c
+dnl   eval-plural.h
+dnl   explodename.c
+dnl   finddomain.c
+dnl   gettextP.h
+dnl   gmo.h
+dnl   hash-string.h hash-string.c
+dnl   l10nflist.c
+dnl   libgnuintl.h.in (except the *printf stuff)
+dnl   loadinfo.h
+dnl   loadmsgcat.c
+dnl   localealias.c
+dnl   log.c
+dnl   plural-exp.h plural-exp.c
+dnl   plural.y
+dnl Used by libglocale.
+AC_DEFUN([gt_INTL_SUBDIR_CORE],
+[
+  AC_REQUIRE([AC_C_INLINE])dnl
+  AC_REQUIRE([AC_TYPE_SIZE_T])dnl
+  AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+  AC_REQUIRE([AC_FUNC_ALLOCA])dnl
+  AC_REQUIRE([AC_FUNC_MMAP])dnl
+  AC_REQUIRE([gt_INTDIV0])dnl
+  AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])dnl
+  AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])dnl
+  AC_REQUIRE([gt_INTTYPES_PRI])dnl
+  AC_REQUIRE([gl_LOCK])dnl
+
+  AC_TRY_LINK(
+    [int foo (int a) { a = __builtin_expect (a, 10); return a == 10 ? 0 : 1; }],
+    [],
+    [AC_DEFINE([HAVE_BUILTIN_EXPECT], 1,
+       [Define to 1 if the compiler understands __builtin_expect.])])
+
+  AC_CHECK_HEADERS([argz.h limits.h unistd.h sys/param.h])
+  AC_CHECK_FUNCS([getcwd getegid geteuid getgid getuid mempcpy munmap \
+    stpcpy strcasecmp strdup strtoul tsearch argz_count argz_stringify \
+    argz_next __fsetlocking])
+
+  dnl Use the *_unlocked functions only if they are declared.
+  dnl (because some of them were defined without being declared in Solaris
+  dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built
+  dnl on Solaris 2.5.1 to run on Solaris 2.6).
+  dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13.
+  gt_CHECK_DECL(feof_unlocked, [#include <stdio.h>])
+  gt_CHECK_DECL(fgets_unlocked, [#include <stdio.h>])
+
+  AM_ICONV
+
+  dnl glibc >= 2.4 has a NL_LOCALE_NAME macro when _GNU_SOURCE is defined,
+  dnl and a _NL_LOCALE_NAME macro always.
+  AC_CACHE_CHECK([for NL_LOCALE_NAME macro], gt_cv_nl_locale_name,
+    [AC_TRY_LINK([#include <langinfo.h>
+#include <locale.h>],
+      [char* cs = nl_langinfo(_NL_LOCALE_NAME(LC_MESSAGES));],
+      gt_cv_nl_locale_name=yes,
+      gt_cv_nl_locale_name=no)
+    ])
+  if test $gt_cv_nl_locale_name = yes; then
+    AC_DEFINE(HAVE_NL_LOCALE_NAME, 1,
+      [Define if you have <langinfo.h> and it defines the NL_LOCALE_NAME macro if _GNU_SOURCE is defined.])
+  fi
+
+  dnl intl/plural.c is generated from intl/plural.y. It requires bison,
+  dnl because plural.y uses bison specific features. It requires at least
+  dnl bison-1.26 because earlier versions generate a plural.c that doesn't
+  dnl compile.
+  dnl bison is only needed for the maintainer (who touches plural.y). But in
+  dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put
+  dnl the rule in general Makefile. Now, some people carelessly touch the
+  dnl files or have a broken "make" program, hence the plural.c rule will
+  dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not
+  dnl present or too old.
+  AC_CHECK_PROGS([INTLBISON], [bison])
+  if test -z "$INTLBISON"; then
+    ac_verc_fail=yes
+  else
+    dnl Found it, now check the version.
+    AC_MSG_CHECKING([version of bison])
+changequote(<<,>>)dnl
+    ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'`
+    case $ac_prog_version in
+      '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+      1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*)
+changequote([,])dnl
+         ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
+      *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+    esac
+    AC_MSG_RESULT([$ac_prog_version])
+  fi
+  if test $ac_verc_fail = yes; then
+    INTLBISON=:
+  fi
+])
+
+
+dnl Checks for special options needed on MacOS X.
+dnl Defines INTL_MACOSX_LIBS.
+AC_DEFUN([gt_INTL_MACOSX],
+[
+  dnl Check for API introduced in MacOS X 10.2.
+  AC_CACHE_CHECK([for CFPreferencesCopyAppValue],
+    gt_cv_func_CFPreferencesCopyAppValue,
+    [gt_save_LIBS="$LIBS"
+     LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation"
+     AC_TRY_LINK([#include <CoreFoundation/CFPreferences.h>],
+       [CFPreferencesCopyAppValue(NULL, NULL)],
+       [gt_cv_func_CFPreferencesCopyAppValue=yes],
+       [gt_cv_func_CFPreferencesCopyAppValue=no])
+     LIBS="$gt_save_LIBS"])
+  if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then
+    AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], 1,
+      [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.])
+  fi
+  dnl Check for API introduced in MacOS X 10.3.
+  AC_CACHE_CHECK([for CFLocaleCopyCurrent], gt_cv_func_CFLocaleCopyCurrent,
+    [gt_save_LIBS="$LIBS"
+     LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation"
+     AC_TRY_LINK([#include <CoreFoundation/CFLocale.h>], [CFLocaleCopyCurrent();],
+       [gt_cv_func_CFLocaleCopyCurrent=yes],
+       [gt_cv_func_CFLocaleCopyCurrent=no])
+     LIBS="$gt_save_LIBS"])
+  if test $gt_cv_func_CFLocaleCopyCurrent = yes; then
+    AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], 1,
+      [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.])
+  fi
+  INTL_MACOSX_LIBS=
+  if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then
+    INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation"
+  fi
+  AC_SUBST([INTL_MACOSX_LIBS])
+])
+
+
+dnl gt_CHECK_DECL(FUNC, INCLUDES)
+dnl Check whether a function is declared.
+AC_DEFUN([gt_CHECK_DECL],
+[
+  AC_CACHE_CHECK([whether $1 is declared], ac_cv_have_decl_$1,
+    [AC_TRY_COMPILE([$2], [
+#ifndef $1
+  char *p = (char *) $1;
+#endif
+], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)])
+  if test $ac_cv_have_decl_$1 = yes; then
+    gt_value=1
+  else
+    gt_value=0
+  fi
+  AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value],
+    [Define to 1 if you have the declaration of `$1', and to 0 if you don't.])
+])
+
+
+dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version])
+AC_DEFUN([AM_GNU_GETTEXT_VERSION], [])
diff --git a/config/gettext-macros/glibc2.m4 b/config/gettext-macros/glibc2.m4
new file mode 100644 (file)
index 0000000..e8f5bfe
--- /dev/null
@@ -0,0 +1,30 @@
+# glibc2.m4 serial 1
+dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Test for the GNU C Library, version 2.0 or newer.
+# From Bruno Haible.
+
+AC_DEFUN([gt_GLIBC2],
+  [
+    AC_CACHE_CHECK(whether we are using the GNU C Library 2 or newer,
+      ac_cv_gnu_library_2,
+      [AC_EGREP_CPP([Lucky GNU user],
+       [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ >= 2)
+  Lucky GNU user
+ #endif
+#endif
+       ],
+       ac_cv_gnu_library_2=yes,
+       ac_cv_gnu_library_2=no)
+      ]
+    )
+    AC_SUBST(GLIBC2)
+    GLIBC2="$ac_cv_gnu_library_2"
+  ]
+)
diff --git a/config/gettext-macros/glibc21.m4 b/config/gettext-macros/glibc21.m4
new file mode 100644 (file)
index 0000000..d95fd98
--- /dev/null
@@ -0,0 +1,30 @@
+# glibc21.m4 serial 3
+dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Test for the GNU C Library, version 2.1 or newer.
+# From Bruno Haible.
+
+AC_DEFUN([gl_GLIBC21],
+  [
+    AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer,
+      ac_cv_gnu_library_2_1,
+      [AC_EGREP_CPP([Lucky GNU user],
+       [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2)
+  Lucky GNU user
+ #endif
+#endif
+       ],
+       ac_cv_gnu_library_2_1=yes,
+       ac_cv_gnu_library_2_1=no)
+      ]
+    )
+    AC_SUBST(GLIBC21)
+    GLIBC21="$ac_cv_gnu_library_2_1"
+  ]
+)
diff --git a/config/gettext-macros/iconv.m4 b/config/gettext-macros/iconv.m4
new file mode 100644 (file)
index 0000000..654c415
--- /dev/null
@@ -0,0 +1,101 @@
+# iconv.m4 serial AM4 (gettext-0.11.3)
+dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_ICONV_LINKFLAGS_BODY],
+[
+  dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([iconv])
+])
+
+AC_DEFUN([AM_ICONV_LINK],
+[
+  dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+  dnl those with the standalone portable GNU libiconv installed).
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
+
+  dnl Add $INCICONV to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed libiconv and not disabled its use
+  dnl via --without-libiconv-prefix, he wants to use it. The first
+  dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed.
+  am_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV])
+
+  AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
+    am_cv_func_iconv="no, consider installing GNU libiconv"
+    am_cv_lib_iconv=no
+    AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+      [iconv_t cd = iconv_open("","");
+       iconv(cd,NULL,NULL,NULL,NULL);
+       iconv_close(cd);],
+      am_cv_func_iconv=yes)
+    if test "$am_cv_func_iconv" != yes; then
+      am_save_LIBS="$LIBS"
+      LIBS="$LIBS $LIBICONV"
+      AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+        [iconv_t cd = iconv_open("","");
+         iconv(cd,NULL,NULL,NULL,NULL);
+         iconv_close(cd);],
+        am_cv_lib_iconv=yes
+        am_cv_func_iconv=yes)
+      LIBS="$am_save_LIBS"
+    fi
+  ])
+  if test "$am_cv_func_iconv" = yes; then
+    AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
+  fi
+  if test "$am_cv_lib_iconv" = yes; then
+    AC_MSG_CHECKING([how to link with libiconv])
+    AC_MSG_RESULT([$LIBICONV])
+  else
+    dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV
+    dnl either.
+    CPPFLAGS="$am_save_CPPFLAGS"
+    LIBICONV=
+    LTLIBICONV=
+  fi
+  AC_SUBST(LIBICONV)
+  AC_SUBST(LTLIBICONV)
+])
+
+AC_DEFUN([AM_ICONV],
+[
+  AM_ICONV_LINK
+  if test "$am_cv_func_iconv" = yes; then
+    AC_MSG_CHECKING([for iconv declaration])
+    AC_CACHE_VAL(am_cv_proto_iconv, [
+      AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
+      am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
+    am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+    AC_MSG_RESULT([$]{ac_t:-
+         }[$]am_cv_proto_iconv)
+    AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
+      [Define as const if the declaration of iconv() needs const.])
+  fi
+])
diff --git a/config/gettext-macros/intdiv0.m4 b/config/gettext-macros/intdiv0.m4
new file mode 100644 (file)
index 0000000..b8d7817
--- /dev/null
@@ -0,0 +1,70 @@
+# intdiv0.m4 serial 1 (gettext-0.11.3)
+dnl Copyright (C) 2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([gt_INTDIV0],
+[
+  AC_REQUIRE([AC_PROG_CC])dnl
+  AC_REQUIRE([AC_CANONICAL_HOST])dnl
+
+  AC_CACHE_CHECK([whether integer division by zero raises SIGFPE],
+    gt_cv_int_divbyzero_sigfpe,
+    [
+      AC_TRY_RUN([
+#include <stdlib.h>
+#include <signal.h>
+
+static void
+#ifdef __cplusplus
+sigfpe_handler (int sig)
+#else
+sigfpe_handler (sig) int sig;
+#endif
+{
+  /* Exit with code 0 if SIGFPE, with code 1 if any other signal.  */
+  exit (sig != SIGFPE);
+}
+
+int x = 1;
+int y = 0;
+int z;
+int nan;
+
+int main ()
+{
+  signal (SIGFPE, sigfpe_handler);
+/* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP.  */
+#if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP)
+  signal (SIGTRAP, sigfpe_handler);
+#endif
+/* Linux/SPARC yields signal SIGILL.  */
+#if defined (__sparc__) && defined (__linux__)
+  signal (SIGILL, sigfpe_handler);
+#endif
+
+  z = x / y;
+  nan = y / y;
+  exit (1);
+}
+], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no,
+        [
+          # Guess based on the CPU.
+          case "$host_cpu" in
+            alpha* | i[34567]86 | m68k | s390*)
+              gt_cv_int_divbyzero_sigfpe="guessing yes";;
+            *)
+              gt_cv_int_divbyzero_sigfpe="guessing no";;
+          esac
+        ])
+    ])
+  case "$gt_cv_int_divbyzero_sigfpe" in
+    *yes) value=1;;
+    *) value=0;;
+  esac
+  AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value,
+    [Define if integer division by zero raises signal SIGFPE.])
+])
diff --git a/config/gettext-macros/intmax.m4 b/config/gettext-macros/intmax.m4
new file mode 100644 (file)
index 0000000..d99c999
--- /dev/null
@@ -0,0 +1,30 @@
+# intmax.m4 serial 2 (gettext-0.14.2)
+dnl Copyright (C) 2002-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether the system has the 'intmax_t' type, but don't attempt to
+dnl find a replacement if it is lacking.
+
+AC_DEFUN([gt_TYPE_INTMAX_T],
+[
+  AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+  AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+  AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t,
+    [AC_TRY_COMPILE([
+#include <stddef.h>
+#include <stdlib.h>
+#if HAVE_STDINT_H_WITH_UINTMAX
+#include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H_WITH_UINTMAX
+#include <inttypes.h>
+#endif
+], [intmax_t x = -1;], gt_cv_c_intmax_t=yes, gt_cv_c_intmax_t=no)])
+  if test $gt_cv_c_intmax_t = yes; then
+    AC_DEFINE(HAVE_INTMAX_T, 1,
+      [Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>.])
+  fi
+])
diff --git a/config/gettext-macros/inttypes-pri.m4 b/config/gettext-macros/inttypes-pri.m4
new file mode 100644 (file)
index 0000000..a3df331
--- /dev/null
@@ -0,0 +1,30 @@
+# inttypes-pri.m4 serial 2 (gettext-0.15)
+dnl Copyright (C) 1997-2002, 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+# Define PRI_MACROS_BROKEN if <inttypes.h> exists and defines the PRI*
+# macros to non-string values.  This is the case on AIX 4.3.3.
+
+AC_DEFUN([gt_INTTYPES_PRI],
+[
+  AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+  if test $gl_cv_header_inttypes_h = yes; then
+    AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken],
+      gt_cv_inttypes_pri_broken,
+      [
+        AC_TRY_COMPILE([#include <inttypes.h>
+#ifdef PRId32
+char *p = PRId32;
+#endif
+], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes)
+      ])
+  fi
+  if test "$gt_cv_inttypes_pri_broken" = yes; then
+    AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1,
+      [Define if <inttypes.h> exists and defines unusable PRI* macros.])
+  fi
+])
diff --git a/config/gettext-macros/inttypes.m4 b/config/gettext-macros/inttypes.m4
new file mode 100644 (file)
index 0000000..779bcea
--- /dev/null
@@ -0,0 +1,25 @@
+# inttypes.m4 serial 1 (gettext-0.11.4)
+dnl Copyright (C) 1997-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_INTTYPES_H if <inttypes.h> exists and doesn't clash with
+# <sys/types.h>.
+
+AC_DEFUN([gt_HEADER_INTTYPES_H],
+[
+  AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h,
+  [
+    AC_TRY_COMPILE(
+      [#include <sys/types.h>
+#include <inttypes.h>],
+      [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no)
+  ])
+  if test $gt_cv_header_inttypes_h = yes; then
+    AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1,
+      [Define if <inttypes.h> exists and doesn't clash with <sys/types.h>.])
+  fi
+])
diff --git a/config/gettext-macros/inttypes_h.m4 b/config/gettext-macros/inttypes_h.m4
new file mode 100644 (file)
index 0000000..a5d075d
--- /dev/null
@@ -0,0 +1,26 @@
+# inttypes_h.m4 serial 6
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_INTTYPES_H_WITH_UINTMAX if <inttypes.h> exists,
+# doesn't clash with <sys/types.h>, and declares uintmax_t.
+
+AC_DEFUN([gl_AC_HEADER_INTTYPES_H],
+[
+  AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h,
+  [AC_TRY_COMPILE(
+    [#include <sys/types.h>
+#include <inttypes.h>],
+    [uintmax_t i = (uintmax_t) -1;],
+    gl_cv_header_inttypes_h=yes,
+    gl_cv_header_inttypes_h=no)])
+  if test $gl_cv_header_inttypes_h = yes; then
+    AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1,
+      [Define if <inttypes.h> exists, doesn't clash with <sys/types.h>,
+       and declares uintmax_t. ])
+  fi
+])
diff --git a/config/gettext-macros/isc-posix.m4 b/config/gettext-macros/isc-posix.m4
new file mode 100644 (file)
index 0000000..74dc8f2
--- /dev/null
@@ -0,0 +1,24 @@
+# isc-posix.m4 serial 2 (gettext-0.11.2)
+dnl Copyright (C) 1995-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# This file is not needed with autoconf-2.53 and newer.  Remove it in 2005.
+
+# This test replaces the one in autoconf.
+# Currently this macro should have the same name as the autoconf macro
+# because gettext's gettext.m4 (distributed in the automake package)
+# still uses it.  Otherwise, the use in gettext.m4 makes autoheader
+# give these diagnostics:
+#   configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX
+#   configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX
+
+undefine([AC_ISC_POSIX])
+
+AC_DEFUN([AC_ISC_POSIX],
+  [
+    dnl This test replaces the obsolescent AC_ISC_POSIX kludge.
+    AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"])
+  ]
+)
diff --git a/config/gettext-macros/lcmessage.m4 b/config/gettext-macros/lcmessage.m4
new file mode 100644 (file)
index 0000000..19aa77e
--- /dev/null
@@ -0,0 +1,30 @@
+# lcmessage.m4 serial 4 (gettext-0.14.2)
+dnl Copyright (C) 1995-2002, 2004-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1995.
+
+# Check whether LC_MESSAGES is available in <locale.h>.
+
+AC_DEFUN([gt_LC_MESSAGES],
+[
+  AC_CACHE_CHECK([for LC_MESSAGES], gt_cv_val_LC_MESSAGES,
+    [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES],
+       gt_cv_val_LC_MESSAGES=yes, gt_cv_val_LC_MESSAGES=no)])
+  if test $gt_cv_val_LC_MESSAGES = yes; then
+    AC_DEFINE(HAVE_LC_MESSAGES, 1,
+      [Define if your <locale.h> file defines LC_MESSAGES.])
+  fi
+])
diff --git a/config/gettext-macros/lib-ld.m4 b/config/gettext-macros/lib-ld.m4
new file mode 100644 (file)
index 0000000..96c4e2c
--- /dev/null
@@ -0,0 +1,110 @@
+# lib-ld.m4 serial 3 (gettext-0.13)
+dnl Copyright (C) 1996-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Subroutines of libtool.m4,
+dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision
+dnl with libtool.m4.
+
+dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no.
+AC_DEFUN([AC_LIB_PROG_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  acl_cv_prog_gnu_ld=yes ;;
+*)
+  acl_cv_prog_gnu_ld=no ;;
+esac])
+with_gnu_ld=$acl_cv_prog_gnu_ld
+])
+
+dnl From libtool-1.4. Sets the variable LD.
+AC_DEFUN([AC_LIB_PROG_LD],
+[AC_ARG_WITH(gnu-ld,
+[  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by GCC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]* | [A-Za-z]:[\\/]*)]
+      [re_direlt='/[^/][^/]*/\.\./']
+      # Canonicalize the path of ld
+      ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(acl_cv_path_LD,
+[if test -z "$LD"; then
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      acl_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break ;;
+      *)
+       test "$with_gnu_ld" != yes && break ;;
+      esac
+    fi
+  done
+  IFS="$ac_save_ifs"
+else
+  acl_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$acl_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_LIB_PROG_LD_GNU
+])
diff --git a/config/gettext-macros/lib-link.m4 b/config/gettext-macros/lib-link.m4
new file mode 100644 (file)
index 0000000..9292919
--- /dev/null
@@ -0,0 +1,630 @@
+# lib-link.m4 serial 8 (gettext-0.15)
+dnl Copyright (C) 2001-2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_PREREQ(2.50)
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  define([Name],[translit([$1],[./-], [___])])
+  define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                               [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+    AC_LIB_LINKFLAGS_BODY([$1], [$2])
+    ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+    ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+    ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+  ])
+  LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+  LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+  INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+  dnl results of this search when this library appears as a dependency.
+  HAVE_LIB[]NAME=yes
+  undefine([Name])
+  undefine([NAME])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode)
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. If found, it
+dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and
+dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  define([Name],[translit([$1],[./-], [___])])
+  define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                               [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+
+  dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+  dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed lib[]Name and not disabled its use
+  dnl via --without-lib[]Name-prefix, he wants to use it.
+  ac_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+  AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+    ac_save_LIBS="$LIBS"
+    LIBS="$LIBS $LIB[]NAME"
+    AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no])
+    LIBS="$ac_save_LIBS"
+  ])
+  if test "$ac_cv_lib[]Name" = yes; then
+    HAVE_LIB[]NAME=yes
+    AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.])
+    AC_MSG_CHECKING([how to link with lib[]$1])
+    AC_MSG_RESULT([$LIB[]NAME])
+  else
+    HAVE_LIB[]NAME=no
+    dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+    dnl $INC[]NAME either.
+    CPPFLAGS="$ac_save_CPPFLAGS"
+    LIB[]NAME=
+    LTLIB[]NAME=
+  fi
+  AC_SUBST([HAVE_LIB]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  undefine([Name])
+  undefine([NAME])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator,
+dnl hardcode_direct, hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+  dnl Tell automake >= 1.10 to complain if config.rpath is missing.
+  m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
+  AC_REQUIRE([AC_PROG_CC])                dnl we use $CC, $GCC, $LDFLAGS
+  AC_REQUIRE([AC_LIB_PROG_LD])            dnl we use $LD, $with_gnu_ld
+  AC_REQUIRE([AC_CANONICAL_HOST])         dnl we use $host
+  AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+  AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [
+    CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+    ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+    . ./conftest.sh
+    rm -f ./conftest.sh
+    acl_cv_rpath=done
+  ])
+  wl="$acl_cv_wl"
+  libext="$acl_cv_libext"
+  shlibext="$acl_cv_shlibext"
+  hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+  hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+  hardcode_direct="$acl_cv_hardcode_direct"
+  hardcode_minus_L="$acl_cv_hardcode_minus_L"
+  dnl Determine whether the user wants rpath handling at all.
+  AC_ARG_ENABLE(rpath,
+    [  --disable-rpath         do not hardcode runtime library paths],
+    :, enable_rpath=yes)
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                               [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_LIB_ARG_WITH([lib$1-prefix],
+[  --with-lib$1-prefix[=DIR]  search for lib$1 in DIR/include and DIR/lib
+  --without-lib$1-prefix     don't search for lib$1 in includedir and libdir],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/$acl_libdirstem"
+      fi
+    fi
+])
+  dnl Search the library and its dependencies in $additional_libdir and
+  dnl $LDFLAGS. Using breadth-first-seach.
+  LIB[]NAME=
+  LTLIB[]NAME=
+  INC[]NAME=
+  rpathdirs=
+  ltrpathdirs=
+  names_already_handled=
+  names_next_round='$1 $2'
+  while test -n "$names_next_round"; do
+    names_this_round="$names_next_round"
+    names_next_round=
+    for name in $names_this_round; do
+      already_handled=
+      for n in $names_already_handled; do
+        if test "$n" = "$name"; then
+          already_handled=yes
+          break
+        fi
+      done
+      if test -z "$already_handled"; then
+        names_already_handled="$names_already_handled $name"
+        dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+        dnl or AC_LIB_HAVE_LINKFLAGS call.
+        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+        eval value=\"\$HAVE_LIB$uppername\"
+        if test -n "$value"; then
+          if test "$value" = yes; then
+            eval value=\"\$LIB$uppername\"
+            test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+            eval value=\"\$LTLIB$uppername\"
+            test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+          else
+            dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+            dnl that this library doesn't exist. So just drop it.
+            :
+          fi
+        else
+          dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+          dnl and the already constructed $LIBNAME/$LTLIBNAME.
+          found_dir=
+          found_la=
+          found_so=
+          found_a=
+          if test $use_additional = yes; then
+            if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+              found_dir="$additional_libdir"
+              found_so="$additional_libdir/lib$name.$shlibext"
+              if test -f "$additional_libdir/lib$name.la"; then
+                found_la="$additional_libdir/lib$name.la"
+              fi
+            else
+              if test -f "$additional_libdir/lib$name.$libext"; then
+                found_dir="$additional_libdir"
+                found_a="$additional_libdir/lib$name.$libext"
+                if test -f "$additional_libdir/lib$name.la"; then
+                  found_la="$additional_libdir/lib$name.la"
+                fi
+              fi
+            fi
+          fi
+          if test "X$found_dir" = "X"; then
+            for x in $LDFLAGS $LTLIB[]NAME; do
+              AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+              case "$x" in
+                -L*)
+                  dir=`echo "X$x" | sed -e 's/^X-L//'`
+                  if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+                    found_dir="$dir"
+                    found_so="$dir/lib$name.$shlibext"
+                    if test -f "$dir/lib$name.la"; then
+                      found_la="$dir/lib$name.la"
+                    fi
+                  else
+                    if test -f "$dir/lib$name.$libext"; then
+                      found_dir="$dir"
+                      found_a="$dir/lib$name.$libext"
+                      if test -f "$dir/lib$name.la"; then
+                        found_la="$dir/lib$name.la"
+                      fi
+                    fi
+                  fi
+                  ;;
+              esac
+              if test "X$found_dir" != "X"; then
+                break
+              fi
+            done
+          fi
+          if test "X$found_dir" != "X"; then
+            dnl Found the library.
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+            if test "X$found_so" != "X"; then
+              dnl Linking with a shared library. We attempt to hardcode its
+              dnl directory into the executable's runpath, unless it's the
+              dnl standard /usr/lib.
+              if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then
+                dnl No hardcoding is needed.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+              else
+                dnl Use an explicit option to hardcode DIR into the resulting
+                dnl binary.
+                dnl Potentially add DIR to ltrpathdirs.
+                dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                haveit=
+                for x in $ltrpathdirs; do
+                  if test "X$x" = "X$found_dir"; then
+                    haveit=yes
+                    break
+                  fi
+                done
+                if test -z "$haveit"; then
+                  ltrpathdirs="$ltrpathdirs $found_dir"
+                fi
+                dnl The hardcoding into $LIBNAME is system dependent.
+                if test "$hardcode_direct" = yes; then
+                  dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+                  dnl resulting binary.
+                  LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                else
+                  if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+                    dnl Use an explicit option to hardcode DIR into the resulting
+                    dnl binary.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    dnl Potentially add DIR to rpathdirs.
+                    dnl The rpathdirs will be appended to $LIBNAME at the end.
+                    haveit=
+                    for x in $rpathdirs; do
+                      if test "X$x" = "X$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      rpathdirs="$rpathdirs $found_dir"
+                    fi
+                  else
+                    dnl Rely on "-L$found_dir".
+                    dnl But don't add it if it's already contained in the LDFLAGS
+                    dnl or the already constructed $LIBNAME
+                    haveit=
+                    for x in $LDFLAGS $LIB[]NAME; do
+                      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                      if test "X$x" = "X-L$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+                    fi
+                    if test "$hardcode_minus_L" != no; then
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    else
+                      dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH
+                      dnl here, because this doesn't fit in flags passed to the
+                      dnl compiler. So give up. No hardcoding. This affects only
+                      dnl very old systems.
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+                    fi
+                  fi
+                fi
+              fi
+            else
+              if test "X$found_a" != "X"; then
+                dnl Linking with a static library.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+              else
+                dnl We shouldn't come here, but anyway it's good to have a
+                dnl fallback.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+              fi
+            fi
+            dnl Assume the include files are nearby.
+            additional_includedir=
+            case "$found_dir" in
+              */$acl_libdirstem | */$acl_libdirstem/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'`
+                additional_includedir="$basedir/include"
+                ;;
+            esac
+            if test "X$additional_includedir" != "X"; then
+              dnl Potentially add $additional_includedir to $INCNAME.
+              dnl But don't add it
+              dnl   1. if it's the standard /usr/include,
+              dnl   2. if it's /usr/local/include and we are using GCC on Linux,
+              dnl   3. if it's already present in $CPPFLAGS or the already
+              dnl      constructed $INCNAME,
+              dnl   4. if it doesn't exist as a directory.
+              if test "X$additional_includedir" != "X/usr/include"; then
+                haveit=
+                if test "X$additional_includedir" = "X/usr/local/include"; then
+                  if test -n "$GCC"; then
+                    case $host_os in
+                      linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                    esac
+                  fi
+                fi
+                if test -z "$haveit"; then
+                  for x in $CPPFLAGS $INC[]NAME; do
+                    AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                    if test "X$x" = "X-I$additional_includedir"; then
+                      haveit=yes
+                      break
+                    fi
+                  done
+                  if test -z "$haveit"; then
+                    if test -d "$additional_includedir"; then
+                      dnl Really add $additional_includedir to $INCNAME.
+                      INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+                    fi
+                  fi
+                fi
+              fi
+            fi
+            dnl Look for dependencies.
+            if test -n "$found_la"; then
+              dnl Read the .la file. It defines the variables
+              dnl dlname, library_names, old_library, dependency_libs, current,
+              dnl age, revision, installed, dlopen, dlpreopen, libdir.
+              save_libdir="$libdir"
+              case "$found_la" in
+                */* | *\\*) . "$found_la" ;;
+                *) . "./$found_la" ;;
+              esac
+              libdir="$save_libdir"
+              dnl We use only dependency_libs.
+              for dep in $dependency_libs; do
+                case "$dep" in
+                  -L*)
+                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                    dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+                    dnl But don't add it
+                    dnl   1. if it's the standard /usr/lib,
+                    dnl   2. if it's /usr/local/lib and we are using GCC on Linux,
+                    dnl   3. if it's already present in $LDFLAGS or the already
+                    dnl      constructed $LIBNAME,
+                    dnl   4. if it doesn't exist as a directory.
+                    if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+                      haveit=
+                      if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+                        if test -n "$GCC"; then
+                          case $host_os in
+                            linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                          esac
+                        fi
+                      fi
+                      if test -z "$haveit"; then
+                        haveit=
+                        for x in $LDFLAGS $LIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LIBNAME.
+                            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                        haveit=
+                        for x in $LDFLAGS $LTLIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LTLIBNAME.
+                            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                      fi
+                    fi
+                    ;;
+                  -R*)
+                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
+                    if test "$enable_rpath" != no; then
+                      dnl Potentially add DIR to rpathdirs.
+                      dnl The rpathdirs will be appended to $LIBNAME at the end.
+                      haveit=
+                      for x in $rpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        rpathdirs="$rpathdirs $dir"
+                      fi
+                      dnl Potentially add DIR to ltrpathdirs.
+                      dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                      haveit=
+                      for x in $ltrpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        ltrpathdirs="$ltrpathdirs $dir"
+                      fi
+                    fi
+                    ;;
+                  -l*)
+                    dnl Handle this in the next round.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    ;;
+                  *.la)
+                    dnl Handle this in the next round. Throw away the .la's
+                    dnl directory; it is already contained in a preceding -L
+                    dnl option.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+                    ;;
+                  *)
+                    dnl Most likely an immediate library name.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+                    LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+                    ;;
+                esac
+              done
+            fi
+          else
+            dnl Didn't find the library; assume it is in the system directories
+            dnl known to the linker and runtime loader. (All the system
+            dnl directories known to the linker should also be known to the
+            dnl runtime loader, otherwise the system is severely misconfigured.)
+            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+          fi
+        fi
+      fi
+    done
+  done
+  if test "X$rpathdirs" != "X"; then
+    if test -n "$hardcode_libdir_separator"; then
+      dnl Weird platform: only the last -rpath option counts, the user must
+      dnl pass all path elements in one option. We can arrange that for a
+      dnl single library, but not when more than one $LIBNAMEs are used.
+      alldirs=
+      for found_dir in $rpathdirs; do
+        alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+      done
+      dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl.
+      acl_save_libdir="$libdir"
+      libdir="$alldirs"
+      eval flag=\"$hardcode_libdir_flag_spec\"
+      libdir="$acl_save_libdir"
+      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+    else
+      dnl The -rpath options are cumulative.
+      for found_dir in $rpathdirs; do
+        acl_save_libdir="$libdir"
+        libdir="$found_dir"
+        eval flag=\"$hardcode_libdir_flag_spec\"
+        libdir="$acl_save_libdir"
+        LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+      done
+    fi
+  fi
+  if test "X$ltrpathdirs" != "X"; then
+    dnl When using libtool, the option that works for both libraries and
+    dnl executables is -R. The -R options are cumulative.
+    for found_dir in $ltrpathdirs; do
+      LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+    done
+  fi
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+  for element in [$2]; do
+    haveit=
+    for x in $[$1]; do
+      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+      if test "X$x" = "X$element"; then
+        haveit=yes
+        break
+      fi
+    done
+    if test -z "$haveit"; then
+      [$1]="${[$1]}${[$1]:+ }$element"
+    fi
+  done
+])
+
+dnl For those cases where a variable contains several -L and -l options
+dnl referring to unknown libraries and directories, this macro determines the
+dnl necessary additional linker options for the runtime path.
+dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL])
+dnl sets LDADDVAR to linker options needed together with LIBSVALUE.
+dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed,
+dnl otherwise linking without libtool is assumed.
+AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS],
+[
+  AC_REQUIRE([AC_LIB_RPATH])
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  $1=
+  if test "$enable_rpath" != no; then
+    if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+      dnl Use an explicit option to hardcode directories into the resulting
+      dnl binary.
+      rpathdirs=
+      next=
+      for opt in $2; do
+        if test -n "$next"; then
+          dir="$next"
+          dnl No need to hardcode the standard /usr/lib.
+          if test "X$dir" != "X/usr/$acl_libdirstem"; then
+            rpathdirs="$rpathdirs $dir"
+          fi
+          next=
+        else
+          case $opt in
+            -L) next=yes ;;
+            -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'`
+                 dnl No need to hardcode the standard /usr/lib.
+                 if test "X$dir" != "X/usr/$acl_libdirstem"; then
+                   rpathdirs="$rpathdirs $dir"
+                 fi
+                 next= ;;
+            *) next= ;;
+          esac
+        fi
+      done
+      if test "X$rpathdirs" != "X"; then
+        if test -n ""$3""; then
+          dnl libtool is used for linking. Use -R options.
+          for dir in $rpathdirs; do
+            $1="${$1}${$1:+ }-R$dir"
+          done
+        else
+          dnl The linker is used for linking directly.
+          if test -n "$hardcode_libdir_separator"; then
+            dnl Weird platform: only the last -rpath option counts, the user
+            dnl must pass all path elements in one option.
+            alldirs=
+            for dir in $rpathdirs; do
+              alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$dir"
+            done
+            acl_save_libdir="$libdir"
+            libdir="$alldirs"
+            eval flag=\"$hardcode_libdir_flag_spec\"
+            libdir="$acl_save_libdir"
+            $1="$flag"
+          else
+            dnl The -rpath options are cumulative.
+            for dir in $rpathdirs; do
+              acl_save_libdir="$libdir"
+              libdir="$dir"
+              eval flag=\"$hardcode_libdir_flag_spec\"
+              libdir="$acl_save_libdir"
+              $1="${$1}${$1:+ }$flag"
+            done
+          fi
+        fi
+      fi
+    fi
+  fi
+  AC_SUBST([$1])
+])
diff --git a/config/gettext-macros/lib-prefix.m4 b/config/gettext-macros/lib-prefix.m4
new file mode 100644 (file)
index 0000000..a8684e1
--- /dev/null
@@ -0,0 +1,185 @@
+# lib-prefix.m4 serial 5 (gettext-0.15)
+dnl Copyright (C) 2001-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
+dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
+dnl require excessive bracketing.
+ifdef([AC_HELP_STRING],
+[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
+[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
+
+dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
+dnl to access previously installed libraries. The basic assumption is that
+dnl a user will want packages to use other packages he previously installed
+dnl with the same --prefix option.
+dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
+dnl libraries, but is otherwise very convenient.
+AC_DEFUN([AC_LIB_PREFIX],
+[
+  AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_LIB_ARG_WITH([lib-prefix],
+[  --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+  --without-lib-prefix    don't search for libraries in includedir and libdir],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/$acl_libdirstem"
+      fi
+    fi
+])
+  if test $use_additional = yes; then
+    dnl Potentially add $additional_includedir to $CPPFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/include,
+    dnl   2. if it's already present in $CPPFLAGS,
+    dnl   3. if it's /usr/local/include and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_includedir" != "X/usr/include"; then
+      haveit=
+      for x in $CPPFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-I$additional_includedir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_includedir" = "X/usr/local/include"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_includedir"; then
+            dnl Really add $additional_includedir to $CPPFLAGS.
+            CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
+          fi
+        fi
+      fi
+    fi
+    dnl Potentially add $additional_libdir to $LDFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/lib,
+    dnl   2. if it's already present in $LDFLAGS,
+    dnl   3. if it's /usr/local/lib and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+      haveit=
+      for x in $LDFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-L$additional_libdir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux*) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_libdir"; then
+            dnl Really add $additional_libdir to $LDFLAGS.
+            LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
+          fi
+        fi
+      fi
+    fi
+  fi
+])
+
+dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
+dnl acl_final_exec_prefix, containing the values to which $prefix and
+dnl $exec_prefix will expand at the end of the configure script.
+AC_DEFUN([AC_LIB_PREPARE_PREFIX],
+[
+  dnl Unfortunately, prefix and exec_prefix get only finally determined
+  dnl at the end of configure.
+  if test "X$prefix" = "XNONE"; then
+    acl_final_prefix="$ac_default_prefix"
+  else
+    acl_final_prefix="$prefix"
+  fi
+  if test "X$exec_prefix" = "XNONE"; then
+    acl_final_exec_prefix='${prefix}'
+  else
+    acl_final_exec_prefix="$exec_prefix"
+  fi
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
+  prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
+dnl variables prefix and exec_prefix bound to the values they will have
+dnl at the end of the configure script.
+AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
+[
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  $1
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing
+dnl the basename of the libdir, either "lib" or "lib64".
+AC_DEFUN([AC_LIB_PREPARE_MULTILIB],
+[
+  dnl There is no formal standard regarding lib and lib64. The current
+  dnl practice is that on a system supporting 32-bit and 64-bit instruction
+  dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit
+  dnl libraries go under $prefix/lib. We determine the compiler's default
+  dnl mode by looking at the compiler's library search path. If at least
+  dnl of its elements ends in /lib64 or points to a directory whose absolute
+  dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the
+  dnl default, namely "lib".
+  acl_libdirstem=lib
+  searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
+  if test -n "$searchpath"; then
+    acl_save_IFS="${IFS=       }"; IFS=":"
+    for searchdir in $searchpath; do
+      if test -d "$searchdir"; then
+        case "$searchdir" in
+          */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
+          *) searchdir=`cd "$searchdir" && pwd`
+             case "$searchdir" in
+               */lib64 ) acl_libdirstem=lib64 ;;
+             esac ;;
+        esac
+      fi
+    done
+    IFS="$acl_save_IFS"
+  fi
+])
diff --git a/config/gettext-macros/longdouble.m4 b/config/gettext-macros/longdouble.m4
new file mode 100644 (file)
index 0000000..25590f4
--- /dev/null
@@ -0,0 +1,31 @@
+# longdouble.m4 serial 2 (gettext-0.15)
+dnl Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether the compiler supports the 'long double' type.
+dnl Prerequisite: AC_PROG_CC
+
+dnl This file is only needed in autoconf <= 2.59.  Newer versions of autoconf
+dnl have a macro AC_TYPE_LONG_DOUBLE with identical semantics.
+
+AC_DEFUN([gt_TYPE_LONGDOUBLE],
+[
+  AC_CACHE_CHECK([for long double], gt_cv_c_long_double,
+    [if test "$GCC" = yes; then
+       gt_cv_c_long_double=yes
+     else
+       AC_TRY_COMPILE([
+         /* The Stardent Vistra knows sizeof(long double), but does not support it.  */
+         long double foo = 0.0;
+         /* On Ultrix 4.3 cc, long double is 4 and double is 8.  */
+         int array [2*(sizeof(long double) >= sizeof(double)) - 1];
+         ], ,
+         gt_cv_c_long_double=yes, gt_cv_c_long_double=no)
+     fi])
+  if test $gt_cv_c_long_double = yes; then
+    AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.])
+  fi
+])
diff --git a/config/gettext-macros/longlong.m4 b/config/gettext-macros/longlong.m4
new file mode 100644 (file)
index 0000000..7b399e0
--- /dev/null
@@ -0,0 +1,23 @@
+# longlong.m4 serial 5
+dnl Copyright (C) 1999-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_LONG_LONG if 'long long' works.
+
+AC_DEFUN([gl_AC_TYPE_LONG_LONG],
+[
+  AC_CACHE_CHECK([for long long], ac_cv_type_long_long,
+  [AC_TRY_LINK([long long ll = 1LL; int i = 63;],
+    [long long llmax = (long long) -1;
+     return ll << i | ll >> i | llmax / ll | llmax % ll;],
+    ac_cv_type_long_long=yes,
+    ac_cv_type_long_long=no)])
+  if test $ac_cv_type_long_long = yes; then
+    AC_DEFINE(HAVE_LONG_LONG, 1,
+      [Define if you have the 'long long' type.])
+  fi
+])
diff --git a/config/gettext-macros/nls.m4 b/config/gettext-macros/nls.m4
new file mode 100644 (file)
index 0000000..7967cc2
--- /dev/null
@@ -0,0 +1,31 @@
+# nls.m4 serial 3 (gettext-0.15)
+dnl Copyright (C) 1995-2003, 2005-2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl   Bruno Haible <haible@clisp.cons.org>, 2000-2003.
+
+AC_PREREQ(2.50)
+
+AC_DEFUN([AM_NLS],
+[
+  AC_MSG_CHECKING([whether NLS is requested])
+  dnl Default is enabled NLS
+  AC_ARG_ENABLE(nls,
+    [  --disable-nls           do not use Native Language Support],
+    USE_NLS=$enableval, USE_NLS=yes)
+  AC_MSG_RESULT($USE_NLS)
+  AC_SUBST(USE_NLS)
+])
diff --git a/config/gettext-macros/po.m4 b/config/gettext-macros/po.m4
new file mode 100644 (file)
index 0000000..00133ef
--- /dev/null
@@ -0,0 +1,428 @@
+# po.m4 serial 13 (gettext-0.15)
+dnl Copyright (C) 1995-2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl   Bruno Haible <haible@clisp.cons.org>, 2000-2003.
+
+AC_PREREQ(2.50)
+
+dnl Checks for all prerequisites of the po subdirectory.
+AC_DEFUN([AM_PO_SUBDIRS],
+[
+  AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+  AC_REQUIRE([AC_PROG_INSTALL])dnl
+  AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake
+  AC_REQUIRE([AM_NLS])dnl
+
+  dnl Perform the following tests also if --disable-nls has been given,
+  dnl because they are needed for "make dist" to work.
+
+  dnl Search for GNU msgfmt in the PATH.
+  dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions.
+  dnl The second test excludes FreeBSD msgfmt.
+  AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+    [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 &&
+     (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)],
+    :)
+  AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+
+  dnl Test whether it is GNU msgfmt >= 0.15.
+changequote(,)dnl
+  case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
+    '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;;
+    *) MSGFMT_015=$MSGFMT ;;
+  esac
+changequote([,])dnl
+  AC_SUBST([MSGFMT_015])
+changequote(,)dnl
+  case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
+    '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;;
+    *) GMSGFMT_015=$GMSGFMT ;;
+  esac
+changequote([,])dnl
+  AC_SUBST([GMSGFMT_015])
+
+  dnl Search for GNU xgettext 0.12 or newer in the PATH.
+  dnl The first test excludes Solaris xgettext and early GNU xgettext versions.
+  dnl The second test excludes FreeBSD xgettext.
+  AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+    [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 &&
+     (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)],
+    :)
+  dnl Remove leftover from FreeBSD xgettext call.
+  rm -f messages.po
+
+  dnl Test whether it is GNU xgettext >= 0.15.
+changequote(,)dnl
+  case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
+    '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;;
+    *) XGETTEXT_015=$XGETTEXT ;;
+  esac
+changequote([,])dnl
+  AC_SUBST([XGETTEXT_015])
+
+  dnl Search for GNU msgmerge 0.11 or newer in the PATH.
+  AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge,
+    [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :)
+
+  dnl Installation directories.
+  dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we
+  dnl have to define it here, so that it can be used in po/Makefile.
+  test -n "$localedir" || localedir='${datadir}/locale'
+  AC_SUBST([localedir])
+
+  AC_CONFIG_COMMANDS([po-directories], [[
+    for ac_file in $CONFIG_FILES; do
+      # Support "outfile[:infile[:infile...]]"
+      case "$ac_file" in
+        *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+      esac
+      # PO directories have a Makefile.in generated from Makefile.in.in.
+      case "$ac_file" in */Makefile.in)
+        # Adjust a relative srcdir.
+        ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
+        ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
+        ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
+        # In autoconf-2.13 it is called $ac_given_srcdir.
+        # In autoconf-2.50 it is called $srcdir.
+        test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
+        case "$ac_given_srcdir" in
+          .)  top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
+          /*) top_srcdir="$ac_given_srcdir" ;;
+          *)  top_srcdir="$ac_dots$ac_given_srcdir" ;;
+        esac
+        # Treat a directory as a PO directory if and only if it has a
+        # POTFILES.in file. This allows packages to have multiple PO
+        # directories under different names or in different locations.
+        if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then
+          rm -f "$ac_dir/POTFILES"
+          test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES"
+          cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[  ]*\$/d" -e "s,.*,     $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES"
+          POMAKEFILEDEPS="POTFILES.in"
+          # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend
+          # on $ac_dir but don't depend on user-specified configuration
+          # parameters.
+          if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
+            # The LINGUAS file contains the set of available languages.
+            if test -n "$OBSOLETE_ALL_LINGUAS"; then
+              test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
+            fi
+            ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
+            # Hide the ALL_LINGUAS assigment from automake < 1.5.
+            eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
+            POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
+          else
+            # The set of available languages was given in configure.in.
+            # Hide the ALL_LINGUAS assigment from automake < 1.5.
+            eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS'
+          fi
+          # Compute POFILES
+          # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po)
+          # Compute UPDATEPOFILES
+          # as      $(foreach lang, $(ALL_LINGUAS), $(lang).po-update)
+          # Compute DUMMYPOFILES
+          # as      $(foreach lang, $(ALL_LINGUAS), $(lang).nop)
+          # Compute GMOFILES
+          # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo)
+          case "$ac_given_srcdir" in
+            .) srcdirpre= ;;
+            *) srcdirpre='$(srcdir)/' ;;
+          esac
+          POFILES=
+          UPDATEPOFILES=
+          DUMMYPOFILES=
+          GMOFILES=
+          for lang in $ALL_LINGUAS; do
+            POFILES="$POFILES $srcdirpre$lang.po"
+            UPDATEPOFILES="$UPDATEPOFILES $lang.po-update"
+            DUMMYPOFILES="$DUMMYPOFILES $lang.nop"
+            GMOFILES="$GMOFILES $srcdirpre$lang.gmo"
+          done
+          # CATALOGS depends on both $ac_dir and the user's LINGUAS
+          # environment variable.
+          INST_LINGUAS=
+          if test -n "$ALL_LINGUAS"; then
+            for presentlang in $ALL_LINGUAS; do
+              useit=no
+              if test "%UNSET%" != "$LINGUAS"; then
+                desiredlanguages="$LINGUAS"
+              else
+                desiredlanguages="$ALL_LINGUAS"
+              fi
+              for desiredlang in $desiredlanguages; do
+                # Use the presentlang catalog if desiredlang is
+                #   a. equal to presentlang, or
+                #   b. a variant of presentlang (because in this case,
+                #      presentlang can be used as a fallback for messages
+                #      which are not translated in the desiredlang catalog).
+                case "$desiredlang" in
+                  "$presentlang"*) useit=yes;;
+                esac
+              done
+              if test $useit = yes; then
+                INST_LINGUAS="$INST_LINGUAS $presentlang"
+              fi
+            done
+          fi
+          CATALOGS=
+          if test -n "$INST_LINGUAS"; then
+            for lang in $INST_LINGUAS; do
+              CATALOGS="$CATALOGS $lang.gmo"
+            done
+          fi
+          test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile"
+          sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile"
+          for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do
+            if test -f "$f"; then
+              case "$f" in
+                *.orig | *.bak | *~) ;;
+                *) cat "$f" >> "$ac_dir/Makefile" ;;
+              esac
+            fi
+          done
+        fi
+        ;;
+      esac
+    done]],
+   [# Capture the value of obsolete ALL_LINGUAS because we need it to compute
+    # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it
+    # from automake < 1.5.
+    eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"'
+    # Capture the value of LINGUAS because we need it to compute CATALOGS.
+    LINGUAS="${LINGUAS-%UNSET%}"
+   ])
+])
+
+dnl Postprocesses a Makefile in a directory containing PO files.
+AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE],
+[
+  # When this code is run, in config.status, two variables have already been
+  # set:
+  # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in,
+  # - LINGUAS is the value of the environment variable LINGUAS at configure
+  #   time.
+
+changequote(,)dnl
+  # Adjust a relative srcdir.
+  ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
+  ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
+  ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
+  # In autoconf-2.13 it is called $ac_given_srcdir.
+  # In autoconf-2.50 it is called $srcdir.
+  test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
+  case "$ac_given_srcdir" in
+    .)  top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
+    /*) top_srcdir="$ac_given_srcdir" ;;
+    *)  top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  # Find a way to echo strings without interpreting backslash.
+  if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then
+    gt_echo='echo'
+  else
+    if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then
+      gt_echo='printf %s\n'
+    else
+      echo_func () {
+        cat <<EOT
+$*
+EOT
+      }
+      gt_echo='echo_func'
+    fi
+  fi
+
+  # A sed script that extracts the value of VARIABLE from a Makefile.
+  sed_x_variable='
+# Test if the hold space is empty.
+x
+s/P/P/
+x
+ta
+# Yes it was empty. Look if we have the expected variable definition.
+/^[     ]*VARIABLE[     ]*=/{
+  # Seen the first line of the variable definition.
+  s/^[  ]*VARIABLE[     ]*=//
+  ba
+}
+bd
+:a
+# Here we are processing a line from the variable definition.
+# Remove comment, more precisely replace it with a space.
+s/#.*$/ /
+# See if the line ends in a backslash.
+tb
+:b
+s/\\$//
+# Print the line, without the trailing backslash.
+p
+tc
+# There was no trailing backslash. The end of the variable definition is
+# reached. Clear the hold space.
+s/^.*$//
+x
+bd
+:c
+# A trailing backslash means that the variable definition continues in the
+# next line. Put a nonempty string into the hold space to indicate this.
+s/^.*$/P/
+x
+:d
+'
+changequote([,])dnl
+
+  # Set POTFILES to the value of the Makefile variable POTFILES.
+  sed_x_POTFILES=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/POTFILES/g'`
+  POTFILES=`sed -n -e "$sed_x_POTFILES" < "$ac_file"`
+  # Compute POTFILES_DEPS as
+  #   $(foreach file, $(POTFILES), $(top_srcdir)/$(file))
+  POTFILES_DEPS=
+  for file in $POTFILES; do
+    POTFILES_DEPS="$POTFILES_DEPS "'$(top_srcdir)/'"$file"
+  done
+  POMAKEFILEDEPS=""
+
+  if test -n "$OBSOLETE_ALL_LINGUAS"; then
+    test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
+  fi
+  if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
+    # The LINGUAS file contains the set of available languages.
+    ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
+    POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
+  else
+    # Set ALL_LINGUAS to the value of the Makefile variable LINGUAS.
+    sed_x_LINGUAS=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/LINGUAS/g'`
+    ALL_LINGUAS_=`sed -n -e "$sed_x_LINGUAS" < "$ac_file"`
+  fi
+  # Hide the ALL_LINGUAS assigment from automake < 1.5.
+  eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
+  # Compute POFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po)
+  # Compute UPDATEPOFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(lang).po-update)
+  # Compute DUMMYPOFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(lang).nop)
+  # Compute GMOFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo)
+  # Compute PROPERTIESFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).properties)
+  # Compute CLASSFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).class)
+  # Compute QMFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).qm)
+  # Compute MSGFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg)
+  # Compute RESOURCESDLLFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll)
+  case "$ac_given_srcdir" in
+    .) srcdirpre= ;;
+    *) srcdirpre='$(srcdir)/' ;;
+  esac
+  POFILES=
+  UPDATEPOFILES=
+  DUMMYPOFILES=
+  GMOFILES=
+  PROPERTIESFILES=
+  CLASSFILES=
+  QMFILES=
+  MSGFILES=
+  RESOURCESDLLFILES=
+  for lang in $ALL_LINGUAS; do
+    POFILES="$POFILES $srcdirpre$lang.po"
+    UPDATEPOFILES="$UPDATEPOFILES $lang.po-update"
+    DUMMYPOFILES="$DUMMYPOFILES $lang.nop"
+    GMOFILES="$GMOFILES $srcdirpre$lang.gmo"
+    PROPERTIESFILES="$PROPERTIESFILES \$(top_srcdir)/\$(DOMAIN)_$lang.properties"
+    CLASSFILES="$CLASSFILES \$(top_srcdir)/\$(DOMAIN)_$lang.class"
+    QMFILES="$QMFILES $srcdirpre$lang.qm"
+    frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+    MSGFILES="$MSGFILES $srcdirpre$frobbedlang.msg"
+    frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
+    RESOURCESDLLFILES="$RESOURCESDLLFILES $srcdirpre$frobbedlang/\$(DOMAIN).resources.dll"
+  done
+  # CATALOGS depends on both $ac_dir and the user's LINGUAS
+  # environment variable.
+  INST_LINGUAS=
+  if test -n "$ALL_LINGUAS"; then
+    for presentlang in $ALL_LINGUAS; do
+      useit=no
+      if test "%UNSET%" != "$LINGUAS"; then
+        desiredlanguages="$LINGUAS"
+      else
+        desiredlanguages="$ALL_LINGUAS"
+      fi
+      for desiredlang in $desiredlanguages; do
+        # Use the presentlang catalog if desiredlang is
+        #   a. equal to presentlang, or
+        #   b. a variant of presentlang (because in this case,
+        #      presentlang can be used as a fallback for messages
+        #      which are not translated in the desiredlang catalog).
+        case "$desiredlang" in
+          "$presentlang"*) useit=yes;;
+        esac
+      done
+      if test $useit = yes; then
+        INST_LINGUAS="$INST_LINGUAS $presentlang"
+      fi
+    done
+  fi
+  CATALOGS=
+  JAVACATALOGS=
+  QTCATALOGS=
+  TCLCATALOGS=
+  CSHARPCATALOGS=
+  if test -n "$INST_LINGUAS"; then
+    for lang in $INST_LINGUAS; do
+      CATALOGS="$CATALOGS $lang.gmo"
+      JAVACATALOGS="$JAVACATALOGS \$(DOMAIN)_$lang.properties"
+      QTCATALOGS="$QTCATALOGS $lang.qm"
+      frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+      TCLCATALOGS="$TCLCATALOGS $frobbedlang.msg"
+      frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
+      CSHARPCATALOGS="$CSHARPCATALOGS $frobbedlang/\$(DOMAIN).resources.dll"
+    done
+  fi
+
+  sed -e "s|@POTFILES_DEPS@|$POTFILES_DEPS|g" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@PROPERTIESFILES@|$PROPERTIESFILES|g" -e "s|@CLASSFILES@|$CLASSFILES|g" -e "s|@QMFILES@|$QMFILES|g" -e "s|@MSGFILES@|$MSGFILES|g" -e "s|@RESOURCESDLLFILES@|$RESOURCESDLLFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@JAVACATALOGS@|$JAVACATALOGS|g" -e "s|@QTCATALOGS@|$QTCATALOGS|g" -e "s|@TCLCATALOGS@|$TCLCATALOGS|g" -e "s|@CSHARPCATALOGS@|$CSHARPCATALOGS|g" -e 's,^#distdir:,distdir:,' < "$ac_file" > "$ac_file.tmp"
+  if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then
+    # Add dependencies that cannot be formulated as a simple suffix rule.
+    for lang in $ALL_LINGUAS; do
+      frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+      cat >> "$ac_file.tmp" <<EOF
+$frobbedlang.msg: $lang.po
+       @echo "\$(MSGFMT) -c --tcl -d \$(srcdir) -l $lang $srcdirpre$lang.po"; \
+       \$(MSGFMT) -c --tcl -d "\$(srcdir)" -l $lang $srcdirpre$lang.po || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; }
+EOF
+    done
+  fi
+  if grep -l '@CSHARPCATALOGS@' "$ac_file" > /dev/null; then
+    # Add dependencies that cannot be formulated as a simple suffix rule.
+    for lang in $ALL_LINGUAS; do
+      frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
+      cat >> "$ac_file.tmp" <<EOF
+$frobbedlang/\$(DOMAIN).resources.dll: $lang.po
+       @echo "\$(MSGFMT) -c --csharp -d \$(srcdir) -l $lang $srcdirpre$lang.po -r \$(DOMAIN)"; \
+       \$(MSGFMT) -c --csharp -d "\$(srcdir)" -l $lang $srcdirpre$lang.po -r "\$(DOMAIN)" || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; }
+EOF
+    done
+  fi
+  if test -n "$POMAKEFILEDEPS"; then
+    cat >> "$ac_file.tmp" <<EOF
+Makefile: $POMAKEFILEDEPS
+EOF
+  fi
+  mv "$ac_file.tmp" "$ac_file"
+])
diff --git a/config/gettext-macros/printf-posix.m4 b/config/gettext-macros/printf-posix.m4
new file mode 100644 (file)
index 0000000..af10170
--- /dev/null
@@ -0,0 +1,44 @@
+# printf-posix.m4 serial 2 (gettext-0.13.1)
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether the printf() function supports POSIX/XSI format strings with
+dnl positions.
+
+AC_DEFUN([gt_PRINTF_POSIX],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_CACHE_CHECK([whether printf() supports POSIX/XSI format strings],
+    gt_cv_func_printf_posix,
+    [
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <string.h>
+/* The string "%2$d %1$d", with dollar characters protected from the shell's
+   dollar expansion (possibly an autoconf bug).  */
+static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' };
+static char buf[100];
+int main ()
+{
+  sprintf (buf, format, 33, 55);
+  return (strcmp (buf, "55 33") != 0);
+}], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no,
+      [
+        AC_EGREP_CPP(notposix, [
+#if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__
+  notposix
+#endif
+        ], gt_cv_func_printf_posix="guessing no",
+           gt_cv_func_printf_posix="guessing yes")
+      ])
+    ])
+  case $gt_cv_func_printf_posix in
+    *yes)
+      AC_DEFINE(HAVE_POSIX_PRINTF, 1,
+        [Define if your printf() function supports format strings with positions.])
+      ;;
+  esac
+])
diff --git a/config/gettext-macros/progtest.m4 b/config/gettext-macros/progtest.m4
new file mode 100644 (file)
index 0000000..a56365c
--- /dev/null
@@ -0,0 +1,92 @@
+# progtest.m4 serial 4 (gettext-0.14.2)
+dnl Copyright (C) 1996-2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+AC_PREREQ(2.50)
+
+# Search path for a program which passes the given test.
+
+dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
+dnl   TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
+AC_DEFUN([AM_PATH_PROG_WITH_TEST],
+[
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+  ac_executable_p="test -x"
+else
+  ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "$2", so it can be a program name with args.
+set dummy $2; ac_word=[$]2
+AC_MSG_CHECKING([for $ac_word])
+AC_CACHE_VAL(ac_cv_path_$1,
+[case "[$]$1" in
+  [[\\/]]* | ?:[[\\/]]*)
+    ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
+    ;;
+  *)
+    ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in ifelse([$5], , $PATH, [$5]); do
+      IFS="$ac_save_IFS"
+      test -z "$ac_dir" && ac_dir=.
+      for ac_exec_ext in '' $ac_executable_extensions; do
+        if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+          echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD
+          if [$3]; then
+            ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext"
+            break 2
+          fi
+        fi
+      done
+    done
+    IFS="$ac_save_IFS"
+dnl If no 4th arg is given, leave the cache variable unset,
+dnl so AC_PATH_PROGS will keep looking.
+ifelse([$4], , , [  test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
+])dnl
+    ;;
+esac])dnl
+$1="$ac_cv_path_$1"
+if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then
+  AC_MSG_RESULT([$]$1)
+else
+  AC_MSG_RESULT(no)
+fi
+AC_SUBST($1)dnl
+])
diff --git a/config/gettext-macros/signed.m4 b/config/gettext-macros/signed.m4
new file mode 100644 (file)
index 0000000..048f593
--- /dev/null
@@ -0,0 +1,17 @@
+# signed.m4 serial 1 (gettext-0.10.40)
+dnl Copyright (C) 2001-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([bh_C_SIGNED],
+[
+  AC_CACHE_CHECK([for signed], bh_cv_c_signed,
+   [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)])
+  if test $bh_cv_c_signed = no; then
+    AC_DEFINE(signed, ,
+              [Define to empty if the C compiler doesn't support this keyword.])
+  fi
+])
diff --git a/config/gettext-macros/size_max.m4 b/config/gettext-macros/size_max.m4
new file mode 100644 (file)
index 0000000..029e471
--- /dev/null
@@ -0,0 +1,60 @@
+# size_max.m4 serial 4
+dnl Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([gl_SIZE_MAX],
+[
+  AC_CHECK_HEADERS(stdint.h)
+  dnl First test whether the system already has SIZE_MAX.
+  AC_MSG_CHECKING([for SIZE_MAX])
+  result=
+  AC_EGREP_CPP([Found it], [
+#include <limits.h>
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef SIZE_MAX
+Found it
+#endif
+], result=yes)
+  if test -z "$result"; then
+    dnl Define it ourselves. Here we assume that the type 'size_t' is not wider
+    dnl than the type 'unsigned long'. Try hard to find a definition that can
+    dnl be used in a preprocessor #if, i.e. doesn't contain a cast.
+    _AC_COMPUTE_INT([sizeof (size_t) * CHAR_BIT - 1], size_t_bits_minus_1,
+      [#include <stddef.h>
+#include <limits.h>], size_t_bits_minus_1=)
+    _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint,
+      [#include <stddef.h>], fits_in_uint=)
+    if test -n "$size_t_bits_minus_1" && test -n "$fits_in_uint"; then
+      if test $fits_in_uint = 1; then
+        dnl Even though SIZE_MAX fits in an unsigned int, it must be of type
+        dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'.
+        AC_TRY_COMPILE([#include <stddef.h>
+          extern size_t foo;
+          extern unsigned long foo;
+          ], [], fits_in_uint=0)
+      fi
+      dnl We cannot use 'expr' to simplify this expression, because 'expr'
+      dnl works only with 'long' integers in the host environment, while we
+      dnl might be cross-compiling from a 32-bit platform to a 64-bit platform.
+      if test $fits_in_uint = 1; then
+        result="(((1U << $size_t_bits_minus_1) - 1) * 2 + 1)"
+      else
+        result="(((1UL << $size_t_bits_minus_1) - 1) * 2 + 1)"
+      fi
+    else
+      dnl Shouldn't happen, but who knows...
+      result='((size_t)~(size_t)0)'
+    fi
+  fi
+  AC_MSG_RESULT([$result])
+  if test "$result" != yes; then
+    AC_DEFINE_UNQUOTED([SIZE_MAX], [$result],
+      [Define as the maximum value of type 'size_t', if the system doesn't define it.])
+  fi
+])
diff --git a/config/gettext-macros/stdint_h.m4 b/config/gettext-macros/stdint_h.m4
new file mode 100644 (file)
index 0000000..3355f35
--- /dev/null
@@ -0,0 +1,26 @@
+# stdint_h.m4 serial 5
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_STDINT_H_WITH_UINTMAX if <stdint.h> exists,
+# doesn't clash with <sys/types.h>, and declares uintmax_t.
+
+AC_DEFUN([gl_AC_HEADER_STDINT_H],
+[
+  AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h,
+  [AC_TRY_COMPILE(
+    [#include <sys/types.h>
+#include <stdint.h>],
+    [uintmax_t i = (uintmax_t) -1;],
+    gl_cv_header_stdint_h=yes,
+    gl_cv_header_stdint_h=no)])
+  if test $gl_cv_header_stdint_h = yes; then
+    AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1,
+      [Define if <stdint.h> exists, doesn't clash with <sys/types.h>,
+       and declares uintmax_t. ])
+  fi
+])
diff --git a/config/gettext-macros/uintmax_t.m4 b/config/gettext-macros/uintmax_t.m4
new file mode 100644 (file)
index 0000000..bf83ed7
--- /dev/null
@@ -0,0 +1,30 @@
+# uintmax_t.m4 serial 9
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+AC_PREREQ(2.13)
+
+# Define uintmax_t to 'unsigned long' or 'unsigned long long'
+# if it is not already defined in <stdint.h> or <inttypes.h>.
+
+AC_DEFUN([gl_AC_TYPE_UINTMAX_T],
+[
+  AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+  AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+  if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then
+    AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG])
+    test $ac_cv_type_unsigned_long_long = yes \
+      && ac_type='unsigned long long' \
+      || ac_type='unsigned long'
+    AC_DEFINE_UNQUOTED(uintmax_t, $ac_type,
+      [Define to unsigned long or unsigned long long
+       if <stdint.h> and <inttypes.h> don't define.])
+  else
+    AC_DEFINE(HAVE_UINTMAX_T, 1,
+      [Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>.])
+  fi
+])
diff --git a/config/gettext-macros/ulonglong.m4 b/config/gettext-macros/ulonglong.m4
new file mode 100644 (file)
index 0000000..dee10cc
--- /dev/null
@@ -0,0 +1,23 @@
+# ulonglong.m4 serial 4
+dnl Copyright (C) 1999-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_UNSIGNED_LONG_LONG if 'unsigned long long' works.
+
+AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG],
+[
+  AC_CACHE_CHECK([for unsigned long long], ac_cv_type_unsigned_long_long,
+  [AC_TRY_LINK([unsigned long long ull = 1ULL; int i = 63;],
+    [unsigned long long ullmax = (unsigned long long) -1;
+     return ull << i | ull >> i | ullmax / ull | ullmax % ull;],
+    ac_cv_type_unsigned_long_long=yes,
+    ac_cv_type_unsigned_long_long=no)])
+  if test $ac_cv_type_unsigned_long_long = yes; then
+    AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1,
+      [Define if you have the 'unsigned long long' type.])
+  fi
+])
diff --git a/config/gettext-macros/wchar_t.m4 b/config/gettext-macros/wchar_t.m4
new file mode 100644 (file)
index 0000000..cde2129
--- /dev/null
@@ -0,0 +1,20 @@
+# wchar_t.m4 serial 1 (gettext-0.12)
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether <stddef.h> has the 'wchar_t' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_WCHAR_T],
+[
+  AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t,
+    [AC_TRY_COMPILE([#include <stddef.h>
+       wchar_t foo = (wchar_t)'\0';], ,
+       gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)])
+  if test $gt_cv_c_wchar_t = yes; then
+    AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.])
+  fi
+])
diff --git a/config/gettext-macros/wint_t.m4 b/config/gettext-macros/wint_t.m4
new file mode 100644 (file)
index 0000000..b8fff9c
--- /dev/null
@@ -0,0 +1,20 @@
+# wint_t.m4 serial 1 (gettext-0.12)
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether <wchar.h> has the 'wint_t' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_WINT_T],
+[
+  AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t,
+    [AC_TRY_COMPILE([#include <wchar.h>
+       wint_t foo = (wchar_t)'\0';], ,
+       gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)])
+  if test $gt_cv_c_wint_t = yes; then
+    AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.])
+  fi
+])
diff --git a/config/gettext-macros/xsize.m4 b/config/gettext-macros/xsize.m4
new file mode 100644 (file)
index 0000000..85bb721
--- /dev/null
@@ -0,0 +1,13 @@
+# xsize.m4 serial 3
+dnl Copyright (C) 2003-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_XSIZE],
+[
+  dnl Prerequisites of lib/xsize.h.
+  AC_REQUIRE([gl_SIZE_MAX])
+  AC_REQUIRE([AC_C_INLINE])
+  AC_CHECK_HEADERS(stdint.h)
+])
diff --git a/config/gnulib/base64.m4 b/config/gnulib/base64.m4
new file mode 100644 (file)
index 0000000..24801ef
--- /dev/null
@@ -0,0 +1,16 @@
+# base64.m4 serial 3
+dnl Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_BASE64],
+[
+  gl_PREREQ_BASE64
+])
+
+# Prerequisites of lib/base64.c.
+AC_DEFUN([gl_PREREQ_BASE64], [
+  AC_REQUIRE([AC_C_INLINE])
+  AC_REQUIRE([AC_C_RESTRICT])
+])
diff --git a/config/gnulib/file-list b/config/gnulib/file-list
new file mode 100644 (file)
index 0000000..f2c14fc
--- /dev/null
@@ -0,0 +1,55 @@
+## this file is automatically generated by autogen
+EXTRA_DIST += gnulib/absolute-header.m4
+EXTRA_DIST += gnulib/alloca.m4
+EXTRA_DIST += gnulib/arpa_inet_h.m4
+EXTRA_DIST += gnulib/base64.m4
+EXTRA_DIST += gnulib/eoverflow.m4
+EXTRA_DIST += gnulib/extensions.m4
+EXTRA_DIST += gnulib/float_h.m4
+EXTRA_DIST += gnulib/fsusage.m4
+EXTRA_DIST += gnulib/getaddrinfo.m4
+EXTRA_DIST += gnulib/gettimeofday.m4
+EXTRA_DIST += gnulib/gnulib-cache.m4
+EXTRA_DIST += gnulib/gnulib-common.m4
+EXTRA_DIST += gnulib/gnulib-comp.m4
+EXTRA_DIST += gnulib/gnulib-tool.m4
+EXTRA_DIST += gnulib/include_next.m4
+EXTRA_DIST += gnulib/inet_ntop.m4
+EXTRA_DIST += gnulib/intmax_t.m4
+EXTRA_DIST += gnulib/inttypes_h.m4
+EXTRA_DIST += gnulib/lib-ld.m4
+EXTRA_DIST += gnulib/lib-link.m4
+EXTRA_DIST += gnulib/lib-prefix.m4
+EXTRA_DIST += gnulib/lock.m4
+EXTRA_DIST += gnulib/longlong.m4
+EXTRA_DIST += gnulib/malloc.m4
+EXTRA_DIST += gnulib/mkdtemp.m4
+EXTRA_DIST += gnulib/netinet_in_h.m4
+EXTRA_DIST += gnulib/onceonly_2_57.m4
+EXTRA_DIST += gnulib/physmem.m4
+EXTRA_DIST += gnulib/safe-read.m4
+EXTRA_DIST += gnulib/safe-write.m4
+EXTRA_DIST += gnulib/size_max.m4
+EXTRA_DIST += gnulib/snprintf.m4
+EXTRA_DIST += gnulib/socklen.m4
+EXTRA_DIST += gnulib/sockpfaf.m4
+EXTRA_DIST += gnulib/ssize_t.m4
+EXTRA_DIST += gnulib/stdbool.m4
+EXTRA_DIST += gnulib/stdint_h.m4
+EXTRA_DIST += gnulib/stdint.m4
+EXTRA_DIST += gnulib/stdio_h.m4
+EXTRA_DIST += gnulib/stdlib_h.m4
+EXTRA_DIST += gnulib/strdup.m4
+EXTRA_DIST += gnulib/string_h.m4
+EXTRA_DIST += gnulib/sys_socket_h.m4
+EXTRA_DIST += gnulib/sys_stat_h.m4
+EXTRA_DIST += gnulib/sys_time_h.m4
+EXTRA_DIST += gnulib/tempname.m4
+EXTRA_DIST += gnulib/ulonglong.m4
+EXTRA_DIST += gnulib/unistd_h.m4
+EXTRA_DIST += gnulib/vasnprintf.m4
+EXTRA_DIST += gnulib/visibility.m4
+EXTRA_DIST += gnulib/wchar.m4
+EXTRA_DIST += gnulib/wchar_t.m4
+EXTRA_DIST += gnulib/wint_t.m4
+EXTRA_DIST += gnulib/xsize.m4
diff --git a/config/gnulib/float_h.m4 b/config/gnulib/float_h.m4
new file mode 100644 (file)
index 0000000..1b1ad10
--- /dev/null
@@ -0,0 +1,19 @@
+# float_h.m4 serial 2
+dnl Copyright (C) 2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FLOAT_H],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  FLOAT_H=
+  case "$host_os" in
+    beos*)
+      FLOAT_H=float.h
+      gl_CHECK_NEXT_HEADERS([float.h])
+      ;;
+  esac
+  AC_SUBST([FLOAT_H])
+])
diff --git a/config/gnulib/fsusage.m4 b/config/gnulib/fsusage.m4
new file mode 100644 (file)
index 0000000..18eedbc
--- /dev/null
@@ -0,0 +1,269 @@
+#serial 23
+# Obtaining file system usage information.
+
+# Copyright (C) 1997, 1998, 2000, 2001, 2003-2007 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Jim Meyering.
+
+AC_DEFUN([gl_FSUSAGE],
+[
+  AC_CHECK_HEADERS_ONCE(sys/param.h)
+  AC_CHECK_HEADERS_ONCE(sys/vfs.h sys/fs_types.h)
+  AC_CHECK_HEADERS(sys/mount.h, [], [],
+    [AC_INCLUDES_DEFAULT
+     [#if HAVE_SYS_PARAM_H
+       #include <sys/param.h>
+      #endif]])
+  gl_FILE_SYSTEM_USAGE([gl_cv_fs_space=yes], [gl_cv_fs_space=no])
+  if test $gl_cv_fs_space = yes; then
+    AC_LIBOBJ(fsusage)
+    gl_PREREQ_FSUSAGE_EXTRA
+  fi
+])
+
+# Try to determine how a program can obtain file system usage information.
+# If successful, define the appropriate symbol (see fsusage.c) and
+# execute ACTION-IF-FOUND.  Otherwise, execute ACTION-IF-NOT-FOUND.
+#
+# gl_FILE_SYSTEM_USAGE([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+
+AC_DEFUN([gl_FILE_SYSTEM_USAGE],
+[
+
+AC_MSG_NOTICE([checking how to get file system space usage])
+ac_fsusage_space=no
+
+# Perform only the link test since it seems there are no variants of the
+# statvfs function.  This check is more than just AC_CHECK_FUNCS(statvfs)
+# because that got a false positive on SCO OSR5.  Adding the declaration
+# of a `struct statvfs' causes this test to fail (as it should) on such
+# systems.  That system is reported to work fine with STAT_STATFS4 which
+# is what it gets when this test fails.
+if test $ac_fsusage_space = no; then
+  # SVR4
+  AC_CACHE_CHECK([for statvfs function (SVR4)], fu_cv_sys_stat_statvfs,
+                [AC_TRY_LINK([#include <sys/types.h>
+#if defined __GLIBC__ && !defined __BEOS__
+Do not use statvfs on systems with GNU libc, because that function stats
+all preceding entries in /proc/mounts, and that makes df hang if even
+one of the corresponding file systems is hard-mounted, but not available.
+statvfs in GNU libc on BeOS operates differently: it only makes a system
+call.
+#endif
+
+#ifdef __osf__
+"Do not use Tru64's statvfs implementation"
+#endif
+
+#include <sys/statvfs.h>],
+                             [struct statvfs fsd; statvfs (0, &fsd);],
+                             fu_cv_sys_stat_statvfs=yes,
+                             fu_cv_sys_stat_statvfs=no)])
+  if test $fu_cv_sys_stat_statvfs = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE(STAT_STATVFS, 1,
+             [  Define if there is a function named statvfs.  (SVR4)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+  # DEC Alpha running OSF/1
+  AC_MSG_CHECKING([for 3-argument statfs function (DEC OSF/1)])
+  AC_CACHE_VAL(fu_cv_sys_stat_statfs3_osf1,
+  [AC_TRY_RUN([
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+  int
+  main ()
+  {
+    struct statfs fsd;
+    fsd.f_fsize = 0;
+    return statfs (".", &fsd, sizeof (struct statfs)) != 0;
+  }],
+  fu_cv_sys_stat_statfs3_osf1=yes,
+  fu_cv_sys_stat_statfs3_osf1=no,
+  fu_cv_sys_stat_statfs3_osf1=no)])
+  AC_MSG_RESULT($fu_cv_sys_stat_statfs3_osf1)
+  if test $fu_cv_sys_stat_statfs3_osf1 = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE(STAT_STATFS3_OSF1, 1,
+             [   Define if  statfs takes 3 args.  (DEC Alpha running OSF/1)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+# AIX
+  AC_MSG_CHECKING([for two-argument statfs with statfs.bsize dnl
+member (AIX, 4.3BSD)])
+  AC_CACHE_VAL(fu_cv_sys_stat_statfs2_bsize,
+  [AC_TRY_RUN([
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+  int
+  main ()
+  {
+  struct statfs fsd;
+  fsd.f_bsize = 0;
+  return statfs (".", &fsd) != 0;
+  }],
+  fu_cv_sys_stat_statfs2_bsize=yes,
+  fu_cv_sys_stat_statfs2_bsize=no,
+  fu_cv_sys_stat_statfs2_bsize=no)])
+  AC_MSG_RESULT($fu_cv_sys_stat_statfs2_bsize)
+  if test $fu_cv_sys_stat_statfs2_bsize = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE(STAT_STATFS2_BSIZE, 1,
+[  Define if statfs takes 2 args and struct statfs has a field named f_bsize.
+   (4.3BSD, SunOS 4, HP-UX, AIX PS/2)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+# SVR3
+  AC_MSG_CHECKING([for four-argument statfs (AIX-3.2.5, SVR3)])
+  AC_CACHE_VAL(fu_cv_sys_stat_statfs4,
+  [AC_TRY_RUN([#include <sys/types.h>
+#include <sys/statfs.h>
+  int
+  main ()
+  {
+  struct statfs fsd;
+  return statfs (".", &fsd, sizeof fsd, 0) != 0;
+  }],
+    fu_cv_sys_stat_statfs4=yes,
+    fu_cv_sys_stat_statfs4=no,
+    fu_cv_sys_stat_statfs4=no)])
+  AC_MSG_RESULT($fu_cv_sys_stat_statfs4)
+  if test $fu_cv_sys_stat_statfs4 = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE(STAT_STATFS4, 1,
+             [  Define if statfs takes 4 args.  (SVR3, Dynix, Irix, Dolphin)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+# 4.4BSD and NetBSD
+  AC_MSG_CHECKING([for two-argument statfs with statfs.fsize dnl
+member (4.4BSD and NetBSD)])
+  AC_CACHE_VAL(fu_cv_sys_stat_statfs2_fsize,
+  [AC_TRY_RUN([#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+  int
+  main ()
+  {
+  struct statfs fsd;
+  fsd.f_fsize = 0;
+  return statfs (".", &fsd) != 0;
+  }],
+  fu_cv_sys_stat_statfs2_fsize=yes,
+  fu_cv_sys_stat_statfs2_fsize=no,
+  fu_cv_sys_stat_statfs2_fsize=no)])
+  AC_MSG_RESULT($fu_cv_sys_stat_statfs2_fsize)
+  if test $fu_cv_sys_stat_statfs2_fsize = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE(STAT_STATFS2_FSIZE, 1,
+[  Define if statfs takes 2 args and struct statfs has a field named f_fsize.
+   (4.4BSD, NetBSD)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+  # Ultrix
+  AC_MSG_CHECKING([for two-argument statfs with struct fs_data (Ultrix)])
+  AC_CACHE_VAL(fu_cv_sys_stat_fs_data,
+  [AC_TRY_RUN([#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_FS_TYPES_H
+#include <sys/fs_types.h>
+#endif
+  int
+  main ()
+  {
+  struct fs_data fsd;
+  /* Ultrix's statfs returns 1 for success,
+     0 for not mounted, -1 for failure.  */
+  return statfs (".", &fsd) != 1;
+  }],
+  fu_cv_sys_stat_fs_data=yes,
+  fu_cv_sys_stat_fs_data=no,
+  fu_cv_sys_stat_fs_data=no)])
+  AC_MSG_RESULT($fu_cv_sys_stat_fs_data)
+  if test $fu_cv_sys_stat_fs_data = yes; then
+    ac_fsusage_space=yes
+    AC_DEFINE(STAT_STATFS2_FS_DATA, 1,
+[  Define if statfs takes 2 args and the second argument has
+   type struct fs_data.  (Ultrix)])
+  fi
+fi
+
+if test $ac_fsusage_space = no; then
+  # SVR2
+  AC_TRY_CPP([#include <sys/filsys.h>
+    ],
+    AC_DEFINE(STAT_READ_FILSYS, 1,
+      [Define if there is no specific function for reading file systems usage
+       information and you have the <sys/filsys.h> header file.  (SVR2)])
+    ac_fsusage_space=yes)
+fi
+
+AS_IF([test $ac_fsusage_space = yes], [$1], [$2])
+
+])
+
+
+# Check for SunOS statfs brokenness wrt partitions 2GB and larger.
+# If <sys/vfs.h> exists and struct statfs has a member named f_spare,
+# enable the work-around code in fsusage.c.
+AC_DEFUN([gl_STATFS_TRUNCATES],
+[
+  AC_MSG_CHECKING([for statfs that truncates block counts])
+  AC_CACHE_VAL(fu_cv_sys_truncating_statfs,
+  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#if !defined(sun) && !defined(__sun)
+choke -- this is a workaround for a Sun-specific problem
+#endif
+#include <sys/types.h>
+#include <sys/vfs.h>]],
+    [[struct statfs t; long c = *(t.f_spare);
+      if (c) return 0;]])],
+    [fu_cv_sys_truncating_statfs=yes],
+    [fu_cv_sys_truncating_statfs=no])])
+  if test $fu_cv_sys_truncating_statfs = yes; then
+    AC_DEFINE(STATFS_TRUNCATES_BLOCK_COUNTS, 1,
+      [Define if the block counts reported by statfs may be truncated to 2GB
+       and the correct values may be stored in the f_spare array.
+       (SunOS 4.1.2, 4.1.3, and 4.1.3_U1 are reported to have this problem.
+       SunOS 4.1.1 seems not to be affected.)])
+  fi
+  AC_MSG_RESULT($fu_cv_sys_truncating_statfs)
+])
+
+
+# Prerequisites of lib/fsusage.c not done by gl_FILE_SYSTEM_USAGE.
+AC_DEFUN([gl_PREREQ_FSUSAGE_EXTRA],
+[
+  AC_CHECK_HEADERS(dustat.h sys/fs/s5param.h sys/filsys.h sys/statfs.h)
+  gl_STATFS_TRUNCATES
+])
diff --git a/config/gnulib/gettimeofday.m4 b/config/gnulib/gettimeofday.m4
new file mode 100644 (file)
index 0000000..b9bbb10
--- /dev/null
@@ -0,0 +1,101 @@
+#serial 11
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Jim Meyering.
+
+AC_DEFUN([gl_FUNC_GETTIMEOFDAY],
+[
+  AC_REQUIRE([AC_C_RESTRICT])
+  AC_REQUIRE([gl_HEADER_SYS_TIME_H])
+  AC_CHECK_FUNCS_ONCE([gettimeofday])
+
+  AC_CACHE_CHECK([for gettimeofday with POSIX signature],
+    [gl_cv_func_gettimeofday_posix_signature],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+         [[#include <sys/time.h>
+           struct timeval c;
+         ]],
+         [[
+           int (*f) (struct timeval *restrict, void *restrict) = gettimeofday;
+           int x = f (&c, 0);
+           return !(x | c.tv_sec | c.tv_usec);
+         ]])],
+       [gl_cv_func_gettimeofday_posix_signature=yes],
+       [gl_cv_func_gettimeofday_posix_signature=no])])
+
+  gl_FUNC_GETTIMEOFDAY_CLOBBER
+
+  if test $gl_cv_func_gettimeofday_posix_signature != yes; then
+    REPLACE_GETTIMEOFDAY=1
+    SYS_TIME_H=sys/time.h
+    if test $gl_cv_func_gettimeofday_clobber != yes; then
+      AC_LIBOBJ(gettimeofday)
+      gl_PREREQ_GETTIMEOFDAY
+    fi
+  fi
+])
+
+
+dnl See if gettimeofday clobbers the static buffer that localtime uses
+dnl for its return value.  The gettimeofday function from Mac OS X 10.0.4
+dnl (i.e., Darwin 1.3.7) has this problem.
+dnl
+dnl If it does, then arrange to use gettimeofday and localtime only via
+dnl the wrapper functions that work around the problem.
+
+AC_DEFUN([gl_FUNC_GETTIMEOFDAY_CLOBBER],
+[
+ AC_REQUIRE([gl_HEADER_SYS_TIME_H])
+
+ AC_CACHE_CHECK([whether gettimeofday clobbers localtime buffer],
+  [gl_cv_func_gettimeofday_clobber],
+  [AC_RUN_IFELSE(
+     [AC_LANG_PROGRAM(
+       [[#include <string.h>
+         #include <sys/time.h>
+         #include <time.h>
+         #include <stdlib.h>
+       ]],
+       [[
+         time_t t = 0;
+         struct tm *lt;
+         struct tm saved_lt;
+         struct timeval tv;
+         lt = localtime (&t);
+         saved_lt = *lt;
+         gettimeofday (&tv, NULL);
+         return memcmp (lt, &saved_lt, sizeof (struct tm)) != 0;
+       ]])],
+     [gl_cv_func_gettimeofday_clobber=no],
+     [gl_cv_func_gettimeofday_clobber=yes],
+     dnl When crosscompiling, assume it is broken.
+     [gl_cv_func_gettimeofday_clobber=yes])])
+
+ if test $gl_cv_func_gettimeofday_clobber = yes; then
+   REPLACE_GETTIMEOFDAY=1
+   SYS_TIME_H=sys/time.h
+   gl_GETTIMEOFDAY_REPLACE_LOCALTIME
+   AC_DEFINE([GETTIMEOFDAY_CLOBBERS_LOCALTIME], 1,
+     [Define if gettimeofday clobbers the localtime buffer.])
+ fi
+])
+
+AC_DEFUN([gl_GETTIMEOFDAY_REPLACE_LOCALTIME], [
+  AC_LIBOBJ(gettimeofday)
+  gl_PREREQ_GETTIMEOFDAY
+  AC_DEFINE([gmtime], [rpl_gmtime],
+    [Define to rpl_gmtime if the replacement function should be used.])
+  AC_DEFINE([localtime], [rpl_localtime],
+    [Define to rpl_localtime if the replacement function should be used.])
+])
+
+# Prerequisites of lib/gettimeofday.c.
+AC_DEFUN([gl_PREREQ_GETTIMEOFDAY], [
+  AC_CHECK_HEADERS([sys/timeb.h])
+  AC_CHECK_FUNCS([_ftime])
+])
diff --git a/config/gnulib/include_next.m4 b/config/gnulib/include_next.m4
new file mode 100644 (file)
index 0000000..7ce472b
--- /dev/null
@@ -0,0 +1,107 @@
+# include_next.m4 serial 4
+dnl Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert and Derek Price.
+
+AC_DEFUN([gl_INCLUDE_NEXT],
+[
+  AC_LANG_PREPROC_REQUIRE()
+  AC_CACHE_CHECK([whether the preprocessor supports include_next],
+    [gl_cv_have_include_next],
+    [rm -rf conftestd1 conftestd2
+     mkdir conftestd1 conftestd2
+     cat <<EOF > conftestd1/conftest.h
+#define DEFINED_IN_CONFTESTD1
+#include_next <conftest.h>
+#ifdef DEFINED_IN_CONFTESTD2
+int foo;
+#else
+#error "include_next doesn't work"
+#endif
+EOF
+     cat <<EOF > conftestd2/conftest.h
+#ifndef DEFINED_IN_CONFTESTD1
+#error "include_next test doesn't work"
+#endif
+#define DEFINED_IN_CONFTESTD2
+EOF
+     save_CPPFLAGS="$CPPFLAGS"
+     CPPFLAGS="$CPPFLAGS -Iconftestd1 -Iconftestd2"
+     AC_COMPILE_IFELSE([#include <conftest.h>],
+       [gl_cv_have_include_next=yes],
+       [gl_cv_have_include_next=no])
+     CPPFLAGS="$save_CPPFLAGS"
+     rm -rf conftestd1 conftestd2
+    ])
+  if test $gl_cv_have_include_next = yes; then
+
+    dnl FIXME: Remove HAVE_INCLUDE_NEXT and update everything that uses it
+    dnl to use @INCLUDE_NEXT@ instead.
+    AC_DEFINE([HAVE_INCLUDE_NEXT], 1,
+             [Define if your compiler supports the #include_next directive.])
+
+    INCLUDE_NEXT=include_next
+  else
+    INCLUDE_NEXT=include
+  fi
+  AC_SUBST([INCLUDE_NEXT])
+])
+
+# gl_CHECK_NEXT_HEADERS(HEADER1 HEADER2 ...)
+# ------------------------------------------
+# For each arg foo.h, if #include_next works, define NEXT_FOO_H to be
+# '<foo.h>'; otherwise define it to be
+# '"///usr/include/foo.h"', or whatever other absolute file name is suitable.
+# That way, a header file with the following line:
+#      #@INCLUDE_NEXT@ @NEXT_FOO_H@
+# behaves (after sed substitution) as if it contained
+#      #include_next <foo.h>
+# even if the compiler does not support include_next.
+# The three "///" are to pacify Sun C 5.8, which otherwise would say
+# "warning: #include of /usr/include/... may be non-portable".
+# Use `""', not `<>', so that the /// cannot be confused with a C99 comment.
+AC_DEFUN([gl_CHECK_NEXT_HEADERS],
+[
+  AC_REQUIRE([gl_INCLUDE_NEXT])
+  AC_CHECK_HEADERS_ONCE([$1])
+
+  AC_FOREACH([gl_HEADER_NAME], [$1],
+    [AS_VAR_PUSHDEF([gl_next_header],
+                   [gl_cv_next_]m4_quote(m4_defn([gl_HEADER_NAME])))
+     if test $gl_cv_have_include_next = yes; then
+       AS_VAR_SET([gl_next_header], ['<'gl_HEADER_NAME'>'])
+     else
+       AC_CACHE_CHECK(
+        [absolute name of <]m4_quote(m4_defn([gl_HEADER_NAME]))[>],
+        m4_quote(m4_defn([gl_next_header])),
+        [AS_VAR_PUSHDEF([gl_header_exists],
+                        [ac_cv_header_]m4_quote(m4_defn([gl_HEADER_NAME])))
+         if test AS_VAR_GET(gl_header_exists) = yes; then
+           AC_LANG_CONFTEST(
+             [AC_LANG_SOURCE(
+                [[#include <]]m4_dquote(m4_defn([gl_HEADER_NAME]))[[>]]
+              )])
+           dnl eval is necessary to expand ac_cpp.
+           dnl Ultrix and Pyramid sh refuse to redirect output of eval,
+           dnl so use subshell.
+           AS_VAR_SET([gl_next_header],
+             ['"'`(eval "$ac_cpp conftest.$ac_ext") 2>&AS_MESSAGE_LOG_FD |
+              sed -n '\#/]m4_quote(m4_defn([gl_HEADER_NAME]))[#{
+                s#.*"\(.*/]m4_quote(m4_defn([gl_HEADER_NAME]))[\)".*#\1#
+                s#^/[^/]#//&#
+                p
+                q
+              }'`'"'])
+         else
+           AS_VAR_SET([gl_next_header], ['<'gl_HEADER_NAME'>'])
+         fi
+         AS_VAR_POPDEF([gl_header_exists])])
+     fi
+     AC_SUBST(
+       AS_TR_CPP([NEXT_]m4_quote(m4_defn([gl_HEADER_NAME]))),
+       [AS_VAR_GET([gl_next_header])])
+     AS_VAR_POPDEF([gl_next_header])])
+])
diff --git a/config/gnulib/malloc.m4 b/config/gnulib/malloc.m4
new file mode 100644 (file)
index 0000000..764f2a9
--- /dev/null
@@ -0,0 +1,41 @@
+# malloc.m4 serial 8
+dnl Copyright (C) 2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# gl_FUNC_MALLOC_POSIX
+# --------------------
+# Test whether 'malloc' is POSIX compliant (sets errno to ENOMEM when it
+# fails), and replace malloc if it is not.
+AC_DEFUN([gl_FUNC_MALLOC_POSIX],
+[
+  AC_REQUIRE([gl_CHECK_MALLOC_POSIX])
+  if test $gl_cv_func_malloc_posix = yes; then
+    HAVE_MALLOC_POSIX=1
+    AC_DEFINE([HAVE_MALLOC_POSIX], 1,
+      [Define if the 'malloc' function is POSIX compliant.])
+  else
+    AC_LIBOBJ([malloc])
+    HAVE_MALLOC_POSIX=0
+  fi
+  AC_SUBST([HAVE_MALLOC_POSIX])
+])
+
+# Test whether malloc, realloc, calloc are POSIX compliant,
+# Set gl_cv_func_malloc_posix to yes or no accordingly.
+AC_DEFUN([gl_CHECK_MALLOC_POSIX],
+[
+  AC_CACHE_CHECK([whether malloc, realloc, calloc are POSIX compliant],
+    [gl_cv_func_malloc_posix],
+    [
+      dnl It is too dangerous to try to allocate a large amount of memory:
+      dnl some systems go to their knees when you do that. So assume that
+      dnl all Unix implementations of the function are POSIX compliant.
+      AC_TRY_COMPILE([],
+        [#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+         choke me
+         #endif
+        ], [gl_cv_func_malloc_posix=yes], [gl_cv_func_malloc_posix=no])
+    ])
+])
diff --git a/config/gnulib/mkdtemp.m4 b/config/gnulib/mkdtemp.m4
new file mode 100644 (file)
index 0000000..0eeafbc
--- /dev/null
@@ -0,0 +1,20 @@
+# mkdtemp.m4 serial 5
+dnl Copyright (C) 2001-2003, 2006-2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gt_FUNC_MKDTEMP],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_REPLACE_FUNCS(mkdtemp)
+  if test $ac_cv_func_mkdtemp = no; then
+    HAVE_MKDTEMP=0
+    gl_PREREQ_MKDTEMP
+  fi
+])
+
+# Prerequisites of lib/mkdtemp.c
+AC_DEFUN([gl_PREREQ_MKDTEMP],
+[:
+])
diff --git a/config/gnulib/physmem.m4 b/config/gnulib/physmem.m4
new file mode 100644 (file)
index 0000000..456bb37
--- /dev/null
@@ -0,0 +1,39 @@
+# physmem.m4 serial 7
+dnl Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Check for the external symbol, _system_configuration,
+# a struct with member `physmem'.
+AC_DEFUN([gl_SYS__SYSTEM_CONFIGURATION],
+  [AC_CACHE_CHECK(for external symbol _system_configuration,
+                 gl_cv_var__system_configuration,
+    [AC_LINK_IFELSE([AC_LANG_PROGRAM(
+                     [[#include <sys/systemcfg.h>
+                     ]],
+                     [double x = _system_configuration.physmem;
+                      if (x > 0.0) return 0;])],
+      [gl_cv_var__system_configuration=yes],
+      [gl_cv_var__system_configuration=no])])
+
+    if test $gl_cv_var__system_configuration = yes; then
+      AC_DEFINE(HAVE__SYSTEM_CONFIGURATION, 1,
+               [Define to 1 if you have the external variable,
+               _system_configuration with a member named physmem.])
+    fi
+  ]
+)
+
+AC_DEFUN([gl_PHYSMEM],
+[
+  AC_LIBOBJ([physmem])
+
+  # Prerequisites of lib/physmem.c.
+  AC_CHECK_HEADERS([sys/pstat.h sys/sysmp.h sys/sysinfo.h \
+    machine/hal_sysinfo.h sys/table.h sys/param.h sys/sysctl.h \
+    sys/systemcfg.h],,, [AC_INCLUDES_DEFAULT])
+
+  AC_CHECK_FUNCS(pstat_getstatic pstat_getdynamic sysmp getsysinfo sysctl table)
+  AC_REQUIRE([gl_SYS__SYSTEM_CONFIGURATION])
+])
diff --git a/config/gnulib/safe-read.m4 b/config/gnulib/safe-read.m4
new file mode 100644 (file)
index 0000000..7a89d0a
--- /dev/null
@@ -0,0 +1,18 @@
+# safe-read.m4 serial 5
+dnl Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_SAFE_READ],
+[
+  AC_LIBOBJ([safe-read])
+
+  gl_PREREQ_SAFE_READ
+])
+
+# Prerequisites of lib/safe-read.c.
+AC_DEFUN([gl_PREREQ_SAFE_READ],
+[
+  AC_REQUIRE([gt_TYPE_SSIZE_T])
+])
diff --git a/config/gnulib/safe-write.m4 b/config/gnulib/safe-write.m4
new file mode 100644 (file)
index 0000000..db119ff
--- /dev/null
@@ -0,0 +1,18 @@
+# safe-write.m4 serial 3
+dnl Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_SAFE_WRITE],
+[
+  AC_LIBOBJ([safe-write])
+
+  gl_PREREQ_SAFE_WRITE
+])
+
+# Prerequisites of lib/safe-write.c.
+AC_DEFUN([gl_PREREQ_SAFE_WRITE],
+[
+  gl_PREREQ_SAFE_READ
+])
diff --git a/config/gnulib/ssize_t.m4 b/config/gnulib/ssize_t.m4
new file mode 100644 (file)
index 0000000..4eaef93
--- /dev/null
@@ -0,0 +1,21 @@
+# ssize_t.m4 serial 4 (gettext-0.15)
+dnl Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether ssize_t is defined.
+
+AC_DEFUN([gt_TYPE_SSIZE_T],
+[
+  AC_CACHE_CHECK([for ssize_t], [gt_cv_ssize_t],
+    [AC_TRY_COMPILE([#include <sys/types.h>],
+       [int x = sizeof (ssize_t *) + sizeof (ssize_t);
+        return !x;],
+       [gt_cv_ssize_t=yes], [gt_cv_ssize_t=no])])
+  if test $gt_cv_ssize_t = no; then
+    AC_DEFINE([ssize_t], [int],
+              [Define as a signed type of the same size as size_t.])
+  fi
+])
diff --git a/config/gnulib/stdint.m4 b/config/gnulib/stdint.m4
new file mode 100644 (file)
index 0000000..03bb093
--- /dev/null
@@ -0,0 +1,395 @@
+# stdint.m4 serial 28
+dnl Copyright (C) 2001-2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert and Bruno Haible.
+dnl Test whether <stdint.h> is supported or must be substituted.
+
+AC_DEFUN([gl_STDINT_H],
+[
+  AC_PREREQ(2.59)dnl
+
+  dnl Check for long long int and unsigned long long int.
+  AC_REQUIRE([AC_TYPE_LONG_LONG_INT])
+  if test $ac_cv_type_long_long_int = yes; then
+    HAVE_LONG_LONG_INT=1
+  else
+    HAVE_LONG_LONG_INT=0
+  fi
+  AC_SUBST([HAVE_LONG_LONG_INT])
+  AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT])
+  if test $ac_cv_type_unsigned_long_long_int = yes; then
+    HAVE_UNSIGNED_LONG_LONG_INT=1
+  else
+    HAVE_UNSIGNED_LONG_LONG_INT=0
+  fi
+  AC_SUBST([HAVE_UNSIGNED_LONG_LONG_INT])
+
+  dnl Check for <inttypes.h>.
+  dnl AC_INCLUDES_DEFAULT defines $ac_cv_header_inttypes_h.
+  if test $ac_cv_header_inttypes_h = yes; then
+    HAVE_INTTYPES_H=1
+  else
+    HAVE_INTTYPES_H=0
+  fi
+  AC_SUBST([HAVE_INTTYPES_H])
+
+  dnl Check for <sys/types.h>.
+  dnl AC_INCLUDES_DEFAULT defines $ac_cv_header_sys_types_h.
+  if test $ac_cv_header_sys_types_h = yes; then
+    HAVE_SYS_TYPES_H=1
+  else
+    HAVE_SYS_TYPES_H=0
+  fi
+  AC_SUBST([HAVE_SYS_TYPES_H])
+
+  gl_CHECK_NEXT_HEADERS([stdint.h])
+  if test $ac_cv_header_stdint_h = yes; then
+    HAVE_STDINT_H=1
+  else
+    HAVE_STDINT_H=0
+  fi
+  AC_SUBST([HAVE_STDINT_H])
+
+  dnl Now see whether we need a substitute <stdint.h>.
+  if test $ac_cv_header_stdint_h = yes; then
+    AC_CACHE_CHECK([whether stdint.h conforms to C99],
+      [gl_cv_header_working_stdint_h],
+      [gl_cv_header_working_stdint_h=no
+       AC_COMPILE_IFELSE([
+         AC_LANG_PROGRAM([[
+#define __STDC_LIMIT_MACROS 1 /* to make it work also in C++ mode */
+#define __STDC_CONSTANT_MACROS 1 /* to make it work also in C++ mode */
+#define _GL_JUST_INCLUDE_SYSTEM_STDINT_H 1 /* work if build isn't clean */
+#include <stdint.h>
+/* Dragonfly defines WCHAR_MIN, WCHAR_MAX only in <wchar.h>.  */
+#if !(defined WCHAR_MIN && defined WCHAR_MAX)
+#error "WCHAR_MIN, WCHAR_MAX not defined in <stdint.h>"
+#endif
+]
+gl_STDINT_INCLUDES
+[
+#ifdef INT8_MAX
+int8_t a1 = INT8_MAX;
+int8_t a1min = INT8_MIN;
+#endif
+#ifdef INT16_MAX
+int16_t a2 = INT16_MAX;
+int16_t a2min = INT16_MIN;
+#endif
+#ifdef INT32_MAX
+int32_t a3 = INT32_MAX;
+int32_t a3min = INT32_MIN;
+#endif
+#ifdef INT64_MAX
+int64_t a4 = INT64_MAX;
+int64_t a4min = INT64_MIN;
+#endif
+#ifdef UINT8_MAX
+uint8_t b1 = UINT8_MAX;
+#else
+typedef int b1[(unsigned char) -1 != 255 ? 1 : -1];
+#endif
+#ifdef UINT16_MAX
+uint16_t b2 = UINT16_MAX;
+#endif
+#ifdef UINT32_MAX
+uint32_t b3 = UINT32_MAX;
+#endif
+#ifdef UINT64_MAX
+uint64_t b4 = UINT64_MAX;
+#endif
+int_least8_t c1 = INT8_C (0x7f);
+int_least8_t c1max = INT_LEAST8_MAX;
+int_least8_t c1min = INT_LEAST8_MIN;
+int_least16_t c2 = INT16_C (0x7fff);
+int_least16_t c2max = INT_LEAST16_MAX;
+int_least16_t c2min = INT_LEAST16_MIN;
+int_least32_t c3 = INT32_C (0x7fffffff);
+int_least32_t c3max = INT_LEAST32_MAX;
+int_least32_t c3min = INT_LEAST32_MIN;
+int_least64_t c4 = INT64_C (0x7fffffffffffffff);
+int_least64_t c4max = INT_LEAST64_MAX;
+int_least64_t c4min = INT_LEAST64_MIN;
+uint_least8_t d1 = UINT8_C (0xff);
+uint_least8_t d1max = UINT_LEAST8_MAX;
+uint_least16_t d2 = UINT16_C (0xffff);
+uint_least16_t d2max = UINT_LEAST16_MAX;
+uint_least32_t d3 = UINT32_C (0xffffffff);
+uint_least32_t d3max = UINT_LEAST32_MAX;
+uint_least64_t d4 = UINT64_C (0xffffffffffffffff);
+uint_least64_t d4max = UINT_LEAST64_MAX;
+int_fast8_t e1 = INT_FAST8_MAX;
+int_fast8_t e1min = INT_FAST8_MIN;
+int_fast16_t e2 = INT_FAST16_MAX;
+int_fast16_t e2min = INT_FAST16_MIN;
+int_fast32_t e3 = INT_FAST32_MAX;
+int_fast32_t e3min = INT_FAST32_MIN;
+int_fast64_t e4 = INT_FAST64_MAX;
+int_fast64_t e4min = INT_FAST64_MIN;
+uint_fast8_t f1 = UINT_FAST8_MAX;
+uint_fast16_t f2 = UINT_FAST16_MAX;
+uint_fast32_t f3 = UINT_FAST32_MAX;
+uint_fast64_t f4 = UINT_FAST64_MAX;
+#ifdef INTPTR_MAX
+intptr_t g = INTPTR_MAX;
+intptr_t gmin = INTPTR_MIN;
+#endif
+#ifdef UINTPTR_MAX
+uintptr_t h = UINTPTR_MAX;
+#endif
+intmax_t i = INTMAX_MAX;
+uintmax_t j = UINTMAX_MAX;
+
+#include <limits.h> /* for CHAR_BIT */
+#define TYPE_MINIMUM(t) \
+  ((t) ((t) 0 < (t) -1 ? (t) 0 : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
+#define TYPE_MAXIMUM(t) \
+  ((t) ((t) 0 < (t) -1 ? (t) -1 : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
+struct s {
+  int check_PTRDIFF:
+      PTRDIFF_MIN == TYPE_MINIMUM (ptrdiff_t)
+      && PTRDIFF_MAX == TYPE_MAXIMUM (ptrdiff_t)
+      ? 1 : -1;
+  /* Detect bug in FreeBSD 6.0 / ia64.  */
+  int check_SIG_ATOMIC:
+      SIG_ATOMIC_MIN == TYPE_MINIMUM (sig_atomic_t)
+      && SIG_ATOMIC_MAX == TYPE_MAXIMUM (sig_atomic_t)
+      ? 1 : -1;
+  int check_SIZE: SIZE_MAX == TYPE_MAXIMUM (size_t) ? 1 : -1;
+  int check_WCHAR:
+      WCHAR_MIN == TYPE_MINIMUM (wchar_t)
+      && WCHAR_MAX == TYPE_MAXIMUM (wchar_t)
+      ? 1 : -1;
+  /* Detect bug in mingw.  */
+  int check_WINT:
+      WINT_MIN == TYPE_MINIMUM (wint_t)
+      && WINT_MAX == TYPE_MAXIMUM (wint_t)
+      ? 1 : -1;
+
+  /* Detect bugs in glibc 2.4 and Solaris 10 stdint.h, among others.  */
+  int check_UINT8_C:
+        (-1 < UINT8_C (0)) == (-1 < (uint_least8_t) 0) ? 1 : -1;
+  int check_UINT16_C:
+        (-1 < UINT16_C (0)) == (-1 < (uint_least16_t) 0) ? 1 : -1;
+
+  /* Detect bugs in OpenBSD 3.9 stdint.h.  */
+#ifdef UINT8_MAX
+  int check_uint8: (uint8_t) -1 == UINT8_MAX ? 1 : -1;
+#endif
+#ifdef UINT16_MAX
+  int check_uint16: (uint16_t) -1 == UINT16_MAX ? 1 : -1;
+#endif
+#ifdef UINT32_MAX
+  int check_uint32: (uint32_t) -1 == UINT32_MAX ? 1 : -1;
+#endif
+#ifdef UINT64_MAX
+  int check_uint64: (uint64_t) -1 == UINT64_MAX ? 1 : -1;
+#endif
+  int check_uint_least8: (uint_least8_t) -1 == UINT_LEAST8_MAX ? 1 : -1;
+  int check_uint_least16: (uint_least16_t) -1 == UINT_LEAST16_MAX ? 1 : -1;
+  int check_uint_least32: (uint_least32_t) -1 == UINT_LEAST32_MAX ? 1 : -1;
+  int check_uint_least64: (uint_least64_t) -1 == UINT_LEAST64_MAX ? 1 : -1;
+  int check_uint_fast8: (uint_fast8_t) -1 == UINT_FAST8_MAX ? 1 : -1;
+  int check_uint_fast16: (uint_fast16_t) -1 == UINT_FAST16_MAX ? 1 : -1;
+  int check_uint_fast32: (uint_fast32_t) -1 == UINT_FAST32_MAX ? 1 : -1;
+  int check_uint_fast64: (uint_fast64_t) -1 == UINT_FAST64_MAX ? 1 : -1;
+  int check_uintptr: (uintptr_t) -1 == UINTPTR_MAX ? 1 : -1;
+  int check_uintmax: (uintmax_t) -1 == UINTMAX_MAX ? 1 : -1;
+  int check_size: (size_t) -1 == SIZE_MAX ? 1 : -1;
+};
+         ]])],
+         [gl_cv_header_working_stdint_h=yes])])
+  fi
+  if test "$gl_cv_header_working_stdint_h" = yes; then
+    STDINT_H=
+  else
+    dnl Check for <sys/inttypes.h>, and for
+    dnl <sys/bitypes.h> (used in Linux libc4 >= 4.6.7 and libc5).
+    AC_CHECK_HEADERS([sys/inttypes.h sys/bitypes.h])
+    if test $ac_cv_header_sys_inttypes_h = yes; then
+      HAVE_SYS_INTTYPES_H=1
+    else
+      HAVE_SYS_INTTYPES_H=0
+    fi
+    AC_SUBST([HAVE_SYS_INTTYPES_H])
+    if test $ac_cv_header_sys_bitypes_h = yes; then
+      HAVE_SYS_BITYPES_H=1
+    else
+      HAVE_SYS_BITYPES_H=0
+    fi
+    AC_SUBST([HAVE_SYS_BITYPES_H])
+
+    dnl Check for <wchar.h> (missing in Linux uClibc when built without wide
+    dnl character support).
+    AC_CHECK_HEADERS_ONCE([wchar.h])
+
+    gl_STDINT_TYPE_PROPERTIES
+    STDINT_H=stdint.h
+  fi
+  AC_SUBST(STDINT_H)
+])
+
+dnl gl_STDINT_BITSIZEOF(TYPES, INCLUDES)
+dnl Determine the size of each of the given types in bits.
+AC_DEFUN([gl_STDINT_BITSIZEOF],
+[
+  dnl Use a shell loop, to avoid bloating configure, and
+  dnl - extra AH_TEMPLATE calls, so that autoheader knows what to put into
+  dnl   config.h.in,
+  dnl - extra AC_SUBST calls, so that the right substitutions are made.
+  AC_FOREACH([gltype], [$1],
+    [AH_TEMPLATE([BITSIZEOF_]translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]),
+       [Define to the number of bits in type ']gltype['.])])
+  for gltype in $1 ; do
+    AC_CACHE_CHECK([for bit size of $gltype], [gl_cv_bitsizeof_${gltype}],
+      [AC_COMPUTE_INT([result], [sizeof ($gltype) * CHAR_BIT],
+         [$2
+#include <limits.h>], [result=unknown])
+       eval gl_cv_bitsizeof_${gltype}=\$result
+      ])
+    eval result=\$gl_cv_bitsizeof_${gltype}
+    if test $result = unknown; then
+      dnl Use a nonempty default, because some compilers, such as IRIX 5 cc,
+      dnl do a syntax check even on unused #if conditions and give an error
+      dnl on valid C code like this:
+      dnl   #if 0
+      dnl   # if  > 32
+      dnl   # endif
+      dnl   #endif
+      result=0
+    fi
+    GLTYPE=`echo "$gltype" | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`
+    AC_DEFINE_UNQUOTED([BITSIZEOF_${GLTYPE}], [$result])
+    eval BITSIZEOF_${GLTYPE}=\$result
+  done
+  AC_FOREACH([gltype], [$1],
+    [AC_SUBST([BITSIZEOF_]translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]))])
+])
+
+dnl gl_CHECK_TYPES_SIGNED(TYPES, INCLUDES)
+dnl Determine the signedness of each of the given types.
+dnl Define HAVE_SIGNED_TYPE if type is signed.
+AC_DEFUN([gl_CHECK_TYPES_SIGNED],
+[
+  dnl Use a shell loop, to avoid bloating configure, and
+  dnl - extra AH_TEMPLATE calls, so that autoheader knows what to put into
+  dnl   config.h.in,
+  dnl - extra AC_SUBST calls, so that the right substitutions are made.
+  AC_FOREACH([gltype], [$1],
+    [AH_TEMPLATE([HAVE_SIGNED_]translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]),
+       [Define to 1 if ']gltype[' is a signed integer type.])])
+  for gltype in $1 ; do
+    AC_CACHE_CHECK([whether $gltype is signed], [gl_cv_type_${gltype}_signed],
+      [AC_COMPILE_IFELSE(
+         [AC_LANG_PROGRAM([$2[
+            int verify[2 * (($gltype) -1 < ($gltype) 0) - 1];]])],
+         result=yes, result=no)
+       eval gl_cv_type_${gltype}_signed=\$result
+      ])
+    eval result=\$gl_cv_type_${gltype}_signed
+    GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`
+    if test "$result" = yes; then
+      AC_DEFINE_UNQUOTED([HAVE_SIGNED_${GLTYPE}], 1)
+      eval HAVE_SIGNED_${GLTYPE}=1
+    else
+      eval HAVE_SIGNED_${GLTYPE}=0
+    fi
+  done
+  AC_FOREACH([gltype], [$1],
+    [AC_SUBST([HAVE_SIGNED_]translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]))])
+])
+
+dnl gl_INTEGER_TYPE_SUFFIX(TYPES, INCLUDES)
+dnl Determine the suffix to use for integer constants of the given types.
+dnl Define t_SUFFIX for each such type.
+AC_DEFUN([gl_INTEGER_TYPE_SUFFIX],
+[
+  dnl Use a shell loop, to avoid bloating configure, and
+  dnl - extra AH_TEMPLATE calls, so that autoheader knows what to put into
+  dnl   config.h.in,
+  dnl - extra AC_SUBST calls, so that the right substitutions are made.
+  AC_FOREACH([gltype], [$1],
+    [AH_TEMPLATE(translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_])[_SUFFIX],
+       [Define to l, ll, u, ul, ull, etc., as suitable for
+        constants of type ']gltype['.])])
+  for gltype in $1 ; do
+    AC_CACHE_CHECK([for $gltype integer literal suffix],
+      [gl_cv_type_${gltype}_suffix],
+      [eval gl_cv_type_${gltype}_suffix=no
+       eval result=\$gl_cv_type_${gltype}_signed
+       if test "$result" = yes; then
+         glsufu=
+       else
+         glsufu=u
+       fi
+       for glsuf in "$glsufu" ${glsufu}l ${glsufu}ll ${glsufu}i64; do
+         case $glsuf in
+           '')  gltype1='int';;
+           l)  gltype1='long int';;
+           ll) gltype1='long long int';;
+           i64)        gltype1='__int64';;
+           u)  gltype1='unsigned int';;
+           ul) gltype1='unsigned long int';;
+           ull)        gltype1='unsigned long long int';;
+           ui64)gltype1='unsigned __int64';;
+         esac
+         AC_COMPILE_IFELSE(
+           [AC_LANG_PROGRAM([$2
+              extern $gltype foo;
+              extern $gltype1 foo;])],
+           [eval gl_cv_type_${gltype}_suffix=\$glsuf])
+         eval result=\$gl_cv_type_${gltype}_suffix
+         test "$result" != no && break
+       done])
+    GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`
+    eval result=\$gl_cv_type_${gltype}_suffix
+    test "$result" = no && result=
+    eval ${GLTYPE}_SUFFIX=\$result
+    AC_DEFINE_UNQUOTED([${GLTYPE}_SUFFIX], $result)
+  done
+  AC_FOREACH([gltype], [$1],
+    [AC_SUBST(translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_])[_SUFFIX])])
+])
+
+dnl gl_STDINT_INCLUDES
+AC_DEFUN([gl_STDINT_INCLUDES],
+[[
+  /* BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
+     included before <wchar.h>.  */
+  #include <stddef.h>
+  #include <signal.h>
+  #if HAVE_WCHAR_H
+  # include <stdio.h>
+  # include <time.h>
+  # include <wchar.h>
+  #endif
+]])
+
+dnl gl_STDINT_TYPE_PROPERTIES
+dnl Compute HAVE_SIGNED_t, BITSIZEOF_t and t_SUFFIX, for all the types t
+dnl of interest to stdint_.h.
+AC_DEFUN([gl_STDINT_TYPE_PROPERTIES],
+[
+  gl_STDINT_BITSIZEOF([ptrdiff_t sig_atomic_t size_t wchar_t wint_t],
+    [gl_STDINT_INCLUDES])
+  gl_CHECK_TYPES_SIGNED([sig_atomic_t wchar_t wint_t],
+    [gl_STDINT_INCLUDES])
+  gl_cv_type_ptrdiff_t_signed=yes
+  gl_cv_type_size_t_signed=no
+  gl_INTEGER_TYPE_SUFFIX([ptrdiff_t sig_atomic_t size_t wchar_t wint_t],
+    [gl_STDINT_INCLUDES])
+])
+
+dnl Autoconf >= 2.61 has AC_COMPUTE_INT built-in.
+dnl Remove this when we can assume autoconf >= 2.61.
+m4_ifdef([AC_COMPUTE_INT], [], [
+  AC_DEFUN([AC_COMPUTE_INT], [_AC_COMPUTE_INT([$2],[$1],[$3],[$4])])
+])
+
+# Hey Emacs!
+# Local Variables:
+# indent-tabs-mode: nil
+# End:
diff --git a/config/gnulib/stdio_h.m4 b/config/gnulib/stdio_h.m4
new file mode 100644 (file)
index 0000000..b9a6998
--- /dev/null
@@ -0,0 +1,82 @@
+# stdio_h.m4 serial 7
+dnl Copyright (C) 2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_STDIO_H],
+[
+  AC_REQUIRE([gl_STDIO_H_DEFAULTS])
+  gl_CHECK_NEXT_HEADERS([stdio.h])
+])
+
+AC_DEFUN([gl_STDIO_MODULE_INDICATOR],
+[
+  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
+  AC_REQUIRE([gl_STDIO_H_DEFAULTS])
+  GNULIB_[]m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./-],[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])=1
+])
+
+AC_DEFUN([gl_STDIO_H_DEFAULTS],
+[
+  GNULIB_FPRINTF_POSIX=0;  AC_SUBST([GNULIB_FPRINTF_POSIX])
+  GNULIB_PRINTF_POSIX=0;   AC_SUBST([GNULIB_PRINTF_POSIX])
+  GNULIB_SNPRINTF=0;       AC_SUBST([GNULIB_SNPRINTF])
+  GNULIB_SPRINTF_POSIX=0;  AC_SUBST([GNULIB_SPRINTF_POSIX])
+  GNULIB_VFPRINTF_POSIX=0; AC_SUBST([GNULIB_VFPRINTF_POSIX])
+  GNULIB_VPRINTF_POSIX=0;  AC_SUBST([GNULIB_VPRINTF_POSIX])
+  GNULIB_VSNPRINTF=0;      AC_SUBST([GNULIB_VSNPRINTF])
+  GNULIB_VSPRINTF_POSIX=0; AC_SUBST([GNULIB_VSPRINTF_POSIX])
+  GNULIB_VASPRINTF=0;      AC_SUBST([GNULIB_VASPRINTF])
+  GNULIB_FSEEK=0;          AC_SUBST([GNULIB_FSEEK])
+  GNULIB_FSEEKO=0;         AC_SUBST([GNULIB_FSEEKO])
+  GNULIB_FTELL=0;          AC_SUBST([GNULIB_FTELL])
+  GNULIB_FTELLO=0;         AC_SUBST([GNULIB_FTELLO])
+  GNULIB_FFLUSH=0;         AC_SUBST([GNULIB_FFLUSH])
+  GNULIB_GETDELIM=0;       AC_SUBST([GNULIB_GETDELIM])
+  GNULIB_GETLINE=0;        AC_SUBST([GNULIB_GETLINE])
+  dnl Assume proper GNU behavior unless another module says otherwise.
+  REPLACE_FPRINTF=0;       AC_SUBST([REPLACE_FPRINTF])
+  REPLACE_VFPRINTF=0;      AC_SUBST([REPLACE_VFPRINTF])
+  REPLACE_PRINTF=0;        AC_SUBST([REPLACE_PRINTF])
+  REPLACE_VPRINTF=0;       AC_SUBST([REPLACE_VPRINTF])
+  REPLACE_SNPRINTF=0;      AC_SUBST([REPLACE_SNPRINTF])
+  HAVE_DECL_SNPRINTF=1;    AC_SUBST([HAVE_DECL_SNPRINTF])
+  REPLACE_VSNPRINTF=0;     AC_SUBST([REPLACE_VSNPRINTF])
+  HAVE_DECL_VSNPRINTF=1;   AC_SUBST([HAVE_DECL_VSNPRINTF])
+  REPLACE_SPRINTF=0;       AC_SUBST([REPLACE_SPRINTF])
+  REPLACE_VSPRINTF=0;      AC_SUBST([REPLACE_VSPRINTF])
+  HAVE_VASPRINTF=1;        AC_SUBST([HAVE_VASPRINTF])
+  REPLACE_VASPRINTF=0;     AC_SUBST([REPLACE_VASPRINTF])
+  HAVE_FSEEKO=1;           AC_SUBST([HAVE_FSEEKO])
+  REPLACE_FSEEKO=0;        AC_SUBST([REPLACE_FSEEKO])
+  REPLACE_FSEEK=0;         AC_SUBST([REPLACE_FSEEK])
+  HAVE_FTELLO=1;           AC_SUBST([HAVE_FTELLO])
+  REPLACE_FTELLO=0;        AC_SUBST([REPLACE_FTELLO])
+  REPLACE_FTELL=0;         AC_SUBST([REPLACE_FTELL])
+  REPLACE_FFLUSH=0;        AC_SUBST([REPLACE_FFLUSH])
+  HAVE_DECL_GETDELIM=1;    AC_SUBST([HAVE_DECL_GETDELIM])
+  HAVE_DECL_GETLINE=1;     AC_SUBST([HAVE_DECL_GETLINE])
+  REPLACE_GETLINE=0;       AC_SUBST([REPLACE_GETLINE])
+])
+
+dnl Code shared by fseeko and ftello.  Determine if large files are supported,
+dnl but stdin does not start as a large file by default.
+AC_DEFUN([gl_STDIN_LARGE_OFFSET],
+  [
+    AC_CACHE_CHECK([whether stdin defaults to large file offsets],
+      [gl_cv_var_stdin_large_offset],
+      [AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <stdio.h>],
+[#if defined __SL64 && defined __SCLE /* cygwin */
+  /* Cygwin 1.5.24 and earlier fail to put stdin in 64-bit mode, making
+     fseeko/ftello needlessly fail.  This bug was fixed at the same time
+     that cygwin started exporting asnprintf (cygwin 1.7.0), so we use
+     that as a link-time test for cross-compiles rather than building
+     a runtime test.  */
+  size_t s;
+  if (asnprintf (NULL, &s, ""))
+    return 0;
+#endif])],
+       [gl_cv_var_stdin_large_offset=yes],
+       [gl_cv_var_stdin_large_offset=no])])
+])
diff --git a/config/gnulib/stdlib_h.m4 b/config/gnulib/stdlib_h.m4
new file mode 100644 (file)
index 0000000..ea9286e
--- /dev/null
@@ -0,0 +1,35 @@
+# stdlib_h.m4 serial 3
+dnl Copyright (C) 2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_STDLIB_H],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  gl_CHECK_NEXT_HEADERS([stdlib.h])
+])
+
+AC_DEFUN([gl_STDLIB_MODULE_INDICATOR],
+[
+  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  GNULIB_[]m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./-],[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])=1
+])
+
+AC_DEFUN([gl_STDLIB_H_DEFAULTS],
+[
+  GNULIB_MALLOC_POSIX=0;  AC_SUBST([GNULIB_MALLOC_POSIX])
+  GNULIB_REALLOC_POSIX=0; AC_SUBST([GNULIB_REALLOC_POSIX])
+  GNULIB_CALLOC_POSIX=0;  AC_SUBST([GNULIB_CALLOC_POSIX])
+  GNULIB_GETSUBOPT=0;     AC_SUBST([GNULIB_GETSUBOPT])
+  GNULIB_MKDTEMP=0;       AC_SUBST([GNULIB_MKDTEMP])
+  GNULIB_MKSTEMP=0;       AC_SUBST([GNULIB_MKSTEMP])
+  dnl Assume proper GNU behavior unless another module says otherwise.
+  HAVE_CALLOC_POSIX=1;    AC_SUBST([HAVE_CALLOC_POSIX])
+  HAVE_GETSUBOPT=1;       AC_SUBST([HAVE_GETSUBOPT])
+  HAVE_MALLOC_POSIX=1;    AC_SUBST([HAVE_MALLOC_POSIX])
+  HAVE_MKDTEMP=1;         AC_SUBST([HAVE_MKDTEMP])
+  HAVE_REALLOC_POSIX=1;   AC_SUBST([HAVE_REALLOC_POSIX])
+  REPLACE_MKSTEMP=0;      AC_SUBST([REPLACE_MKSTEMP])
+])
diff --git a/config/gnulib/sys_stat_h.m4 b/config/gnulib/sys_stat_h.m4
new file mode 100644 (file)
index 0000000..1bc08a1
--- /dev/null
@@ -0,0 +1,48 @@
+# sys_stat_h.m4 serial 6   -*- Autoconf -*-
+dnl Copyright (C) 2006-2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Eric Blake.
+dnl Test whether <sys/stat.h> contains lstat and mkdir or must be substituted.
+
+AC_DEFUN([gl_HEADER_SYS_STAT_H],
+[
+  dnl Check for lstat.  Systems that lack it (mingw) also lack symlinks, so
+  dnl stat is a good replacement.
+  AC_CHECK_FUNCS_ONCE([lstat])
+  if test $ac_cv_func_lstat = yes; then
+    HAVE_LSTAT=1
+  else
+    HAVE_LSTAT=0
+  fi
+  AC_SUBST([HAVE_LSTAT])
+
+  dnl Check for mkdir.  Mingw has _mkdir(name) in the nonstandard <io.h>
+  dnl instead.
+  AC_CHECK_DECLS([mkdir],
+    [],
+    [AC_CHECK_HEADERS([io.h])],
+    [#include <sys/stat.h>])
+  if test $ac_cv_have_decl_mkdir = yes; then
+    HAVE_DECL_MKDIR=1
+  else
+    HAVE_DECL_MKDIR=0
+  fi
+  AC_SUBST([HAVE_DECL_MKDIR])
+  if test "$ac_cv_header_io_h" = yes; then
+    HAVE_IO_H=1
+  else
+    HAVE_IO_H=0
+  fi
+  AC_SUBST([HAVE_IO_H])
+  AC_REQUIRE([AC_C_INLINE])
+
+  dnl Check for broken stat macros.
+  AC_REQUIRE([AC_HEADER_STAT])
+
+  gl_CHECK_NEXT_HEADERS([sys/stat.h])
+  SYS_STAT_H='sys/stat.h'
+  AC_SUBST([SYS_STAT_H])
+]) # gl_HEADER_SYS_STAT_H
diff --git a/config/gnulib/sys_time_h.m4 b/config/gnulib/sys_time_h.m4
new file mode 100644 (file)
index 0000000..13ac576
--- /dev/null
@@ -0,0 +1,57 @@
+# Configure a replacement for <sys/time.h>.
+
+# Copyright (C) 2007 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Paul Eggert and Martin Lambers.
+
+AC_DEFUN([gl_HEADER_SYS_TIME_H],
+[
+  dnl Use AC_REQUIRE here, so that the REPLACE_GETTIMEOFDAY=0 statement
+  dnl below is expanded once only, before all REPLACE_GETTIMEOFDAY=1
+  dnl statements that occur in other macros.
+  AC_REQUIRE([gl_HEADER_SYS_TIME_H_BODY])
+])
+
+AC_DEFUN([gl_HEADER_SYS_TIME_H_BODY],
+[
+  AC_REQUIRE([AC_C_RESTRICT])
+  gl_CHECK_NEXT_HEADERS([sys/time.h])
+
+  if test $ac_cv_header_sys_time_h = yes; then
+    HAVE_SYS_TIME_H=1
+  else
+    HAVE_SYS_TIME_H=0
+  fi
+  AC_SUBST([HAVE_SYS_TIME_H])
+
+  AC_CACHE_CHECK([for struct timeval], [gl_cv_sys_struct_timeval],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+         [[#if HAVE_SYS_TIME_H
+            #include <sys/time.h>
+           #endif
+           #include <time.h>
+         ]],
+         [[static struct timeval x; x.tv_sec = x.tv_usec;]])],
+       [gl_cv_sys_struct_timeval=yes],
+       [gl_cv_sys_struct_timeval=no])])
+  if test $gl_cv_sys_struct_timeval = yes; then
+    HAVE_STRUCT_TIMEVAL=1
+  else
+    HAVE_STRUCT_TIMEVAL=0
+  fi
+  AC_SUBST([HAVE_STRUCT_TIMEVAL])
+
+  dnl Assume POSIX behavior unless another module says otherwise.
+  REPLACE_GETTIMEOFDAY=0
+  AC_SUBST([REPLACE_GETTIMEOFDAY])
+  if test $HAVE_SYS_TIME_H = 0 || test $HAVE_STRUCT_TIMEVAL = 0; then
+    SYS_TIME_H=sys/time.h
+  else
+    SYS_TIME_H=
+  fi
+  AC_SUBST([SYS_TIME_H])
+])
diff --git a/config/gnulib/tempname.m4 b/config/gnulib/tempname.m4
new file mode 100644 (file)
index 0000000..4c44d37
--- /dev/null
@@ -0,0 +1,22 @@
+#serial 3
+
+# Copyright (C) 2006-2007 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# glibc provides __gen_tempname as a wrapper for mk[ds]temp.  Expose
+# it as a public API, and provide it on systems that are lacking.
+AC_DEFUN([gl_FUNC_GEN_TEMPNAME],
+[
+  AC_REQUIRE([AC_SYS_LARGEFILE])
+
+  AC_LIBOBJ([tempname])
+  gl_PREREQ_TEMPNAME
+])
+
+# Prerequisites of lib/tempname.c.
+AC_DEFUN([gl_PREREQ_TEMPNAME],
+[
+  :
+])
diff --git a/config/gnulib/ulonglong.m4 b/config/gnulib/ulonglong.m4
new file mode 100644 (file)
index 0000000..9fae98e
--- /dev/null
@@ -0,0 +1,48 @@
+# ulonglong.m4 serial 6
+dnl Copyright (C) 1999-2006 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works.
+# This fixes a bug in Autoconf 2.60, but can be removed once we
+# assume 2.61 everywhere.
+
+# Note: If the type 'unsigned long long int' exists but is only 32 bits
+# large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT
+# will not be defined. In this case you can treat 'unsigned long long int'
+# like 'unsigned long int'.
+
+AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT],
+[
+  AC_CACHE_CHECK([for unsigned long long int],
+    [ac_cv_type_unsigned_long_long_int],
+    [AC_LINK_IFELSE(
+       [AC_LANG_PROGRAM(
+         [[unsigned long long int ull = 18446744073709551615ULL;
+           typedef int a[(18446744073709551615ULL <= (unsigned long long int) -1
+                          ? 1 : -1)];
+          int i = 63;]],
+         [[unsigned long long int ullmax = 18446744073709551615ull;
+           return (ull << 63 | ull >> 63 | ull << i | ull >> i
+                   | ullmax / ull | ullmax % ull);]])],
+       [ac_cv_type_unsigned_long_long_int=yes],
+       [ac_cv_type_unsigned_long_long_int=no])])
+  if test $ac_cv_type_unsigned_long_long_int = yes; then
+    AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], 1,
+      [Define to 1 if the system has the type `unsigned long long int'.])
+  fi
+])
+
+# This macro is obsolescent and should go away soon.
+AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG],
+[
+  AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT])
+  ac_cv_type_unsigned_long_long=$ac_cv_type_unsigned_long_long_int
+  if test $ac_cv_type_unsigned_long_long = yes; then
+    AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1,
+      [Define if you have the 'unsigned long long' type.])
+  fi
+])
diff --git a/config/gnulib/unistd_h.m4 b/config/gnulib/unistd_h.m4
new file mode 100644 (file)
index 0000000..b12f84e
--- /dev/null
@@ -0,0 +1,56 @@
+# unistd_h.m4 serial 9
+dnl Copyright (C) 2006-2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Written by Simon Josefsson, Bruno Haible.
+
+AC_DEFUN([gl_UNISTD_H],
+[
+  dnl Use AC_REQUIRE here, so that the default behavior below is expanded
+  dnl once only, before all statements that occur in other macros.
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+
+  gl_CHECK_NEXT_HEADERS([unistd.h])
+
+  AC_CHECK_HEADERS_ONCE([unistd.h])
+  if test $ac_cv_header_unistd_h = yes; then
+    HAVE_UNISTD_H=1
+  else
+    HAVE_UNISTD_H=0
+  fi
+  AC_SUBST([HAVE_UNISTD_H])
+])
+
+AC_DEFUN([gl_UNISTD_MODULE_INDICATOR],
+[
+  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  GNULIB_[]m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./-],[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])=1
+])
+
+AC_DEFUN([gl_UNISTD_H_DEFAULTS],
+[
+  GNULIB_CHOWN=0;         AC_SUBST([GNULIB_CHOWN])
+  GNULIB_DUP2=0;          AC_SUBST([GNULIB_DUP2])
+  GNULIB_FCHDIR=0;        AC_SUBST([GNULIB_FCHDIR])
+  GNULIB_FTRUNCATE=0;     AC_SUBST([GNULIB_FTRUNCATE])
+  GNULIB_GETCWD=0;        AC_SUBST([GNULIB_GETCWD])
+  GNULIB_GETLOGIN_R=0;    AC_SUBST([GNULIB_GETLOGIN_R])
+  GNULIB_LCHOWN=0;        AC_SUBST([GNULIB_LCHOWN])
+  GNULIB_LSEEK=0;         AC_SUBST([GNULIB_LSEEK])
+  GNULIB_READLINK=0;      AC_SUBST([GNULIB_READLINK])
+  GNULIB_SLEEP=0;         AC_SUBST([GNULIB_SLEEP])
+  dnl Assume proper GNU behavior unless another module says otherwise.
+  HAVE_DUP2=1;            AC_SUBST([HAVE_DUP2])
+  HAVE_FTRUNCATE=1;       AC_SUBST([HAVE_FTRUNCATE])
+  HAVE_READLINK=1;        AC_SUBST([HAVE_READLINK])
+  HAVE_SLEEP=1;           AC_SUBST([HAVE_SLEEP])
+  HAVE_DECL_GETLOGIN_R=1; AC_SUBST([HAVE_DECL_GETLOGIN_R])
+  REPLACE_CHOWN=0;        AC_SUBST([REPLACE_CHOWN])
+  REPLACE_FCHDIR=0;       AC_SUBST([REPLACE_FCHDIR])
+  REPLACE_GETCWD=0;       AC_SUBST([REPLACE_GETCWD])
+  REPLACE_LCHOWN=0;       AC_SUBST([REPLACE_LCHOWN])
+  REPLACE_LSEEK=0;        AC_SUBST([REPLACE_LSEEK])
+])
diff --git a/config/gnulib/wchar.m4 b/config/gnulib/wchar.m4
new file mode 100644 (file)
index 0000000..70b1248
--- /dev/null
@@ -0,0 +1,54 @@
+dnl A placeholder for ISO C99 <wchar.h>, for platforms that have issues.
+
+dnl Copyright (C) 2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Written by Eric Blake.
+
+# wchar.m4 serial 4
+
+AC_DEFUN([gl_WCHAR_H],
+[
+  AC_REQUIRE([gl_WCHAR_H_DEFAULTS])
+  AC_CACHE_CHECK([whether <wchar.h> is standalone],
+    [gl_cv_header_wchar_h_standalone],
+    [AC_COMPILE_IFELSE([[#include <wchar.h>
+wchar_t w;]],
+      [gl_cv_header_wchar_h_standalone=yes],
+      [gl_cv_header_wchar_h_standalone=no])])
+  if test $gl_cv_header_wchar_h_standalone != yes; then
+    WCHAR_H=wchar.h
+  fi
+
+  dnl Prepare for creating substitute <wchar.h>.
+  dnl Do it always: WCHAR_H may be empty here but can be set later.
+  dnl Check for <wchar.h> (missing in Linux uClibc when built without wide
+  dnl character support).
+  AC_CHECK_HEADERS_ONCE([wchar.h])
+  if test $ac_cv_header_wchar_h = yes; then
+    HAVE_WCHAR_H=1
+  else
+    HAVE_WCHAR_H=0
+  fi
+  AC_SUBST([HAVE_WCHAR_H])
+  gl_CHECK_NEXT_HEADERS([wchar.h])
+])
+
+AC_DEFUN([gl_WCHAR_MODULE_INDICATOR],
+[
+  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
+  AC_REQUIRE([gl_WCHAR_H_DEFAULTS])
+  GNULIB_[]m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./-],[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])=1
+])
+
+AC_DEFUN([gl_WCHAR_H_DEFAULTS],
+[
+  GNULIB_WCWIDTH=0; AC_SUBST([GNULIB_WCWIDTH])
+  dnl Assume proper GNU behavior unless another module says otherwise.
+  HAVE_DECL_WCWIDTH=1; AC_SUBST([HAVE_DECL_WCWIDTH])
+  REPLACE_WCWIDTH=0;   AC_SUBST([REPLACE_WCWIDTH])
+  WCHAR_H=
+  AC_SUBST([WCHAR_H])
+])
diff --git a/config/libtool.m4 b/config/libtool.m4
new file mode 100644 (file)
index 0000000..285a567
--- /dev/null
@@ -0,0 +1,6214 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+## Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
+## Free Software Foundation, Inc.
+## Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+##
+## This file is free software; the Free Software Foundation gives
+## unlimited permission to copy and/or distribute it, with or without
+## modifications, as long as this notice is preserved.
+
+# serial 47 AC_PROG_LIBTOOL
+
+
+# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+# -----------------------------------------------------------
+# If this macro is not defined by Autoconf, define it here.
+m4_ifdef([AC_PROVIDE_IFELSE],
+         [],
+         [m4_define([AC_PROVIDE_IFELSE],
+                [m4_ifdef([AC_PROVIDE_$1],
+                          [$2], [$3])])])
+
+
+# AC_PROG_LIBTOOL
+# ---------------
+AC_DEFUN([AC_PROG_LIBTOOL],
+[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+  AC_PROVIDE_IFELSE([AC_PROG_CXX],
+    [AC_LIBTOOL_CXX],
+    [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+  ])])
+dnl And a similar setup for Fortran 77 support
+  AC_PROVIDE_IFELSE([AC_PROG_F77],
+    [AC_LIBTOOL_F77],
+    [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77
+])])
+
+dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+  AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+    [AC_LIBTOOL_GCJ],
+    [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+      [AC_LIBTOOL_GCJ],
+      [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+       [AC_LIBTOOL_GCJ],
+      [ifdef([AC_PROG_GCJ],
+            [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([A][M_PROG_GCJ],
+            [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([LT_AC_PROG_GCJ],
+            [define([LT_AC_PROG_GCJ],
+               defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])])
+])])# AC_PROG_LIBTOOL
+
+
+# _AC_PROG_LIBTOOL
+# ----------------
+AC_DEFUN([_AC_PROG_LIBTOOL],
+[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Prevent multiple expansion
+define([AC_PROG_LIBTOOL], [])
+])# _AC_PROG_LIBTOOL
+
+
+# AC_LIBTOOL_SETUP
+# ----------------
+AC_DEFUN([AC_LIBTOOL_SETUP],
+[AC_PREREQ(2.50)dnl
+AC_REQUIRE([AC_ENABLE_SHARED])dnl
+AC_REQUIRE([AC_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_LD])dnl
+AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
+AC_REQUIRE([AC_PROG_NM])dnl
+
+AC_REQUIRE([AC_PROG_LN_S])dnl
+AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+AC_REQUIRE([AC_OBJEXT])dnl
+AC_REQUIRE([AC_EXEEXT])dnl
+dnl
+
+AC_LIBTOOL_SYS_MAX_CMD_LEN
+AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+AC_LIBTOOL_OBJDIR
+
+AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+_LT_AC_PROG_ECHO_BACKSLASH
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
+
+# Same as above, but do not quote variable references.
+[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g']
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+AC_CHECK_TOOL(AR, ar, false)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(STRIP, strip, :)
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
+    ;;
+  *)
+    old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    AC_PATH_MAGIC
+  fi
+  ;;
+esac
+
+AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+enable_win32_dll=yes, enable_win32_dll=no)
+
+AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+       [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+AC_ARG_WITH([pic],
+    [AC_HELP_STRING([--with-pic],
+       [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [pic_mode="$withval"],
+    [pic_mode=default])
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+AC_LIBTOOL_LANG_C_CONFIG
+_LT_AC_TAGCONFIG
+])# AC_LIBTOOL_SETUP
+
+
+# _LT_AC_SYS_COMPILER
+# -------------------
+AC_DEFUN([_LT_AC_SYS_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_AC_SYS_COMPILER
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+AC_DEFUN([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+])
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+AC_DEFUN([_LT_COMPILER_BOILERPLATE],
+[ac_outfile=conftest.$ac_objext
+printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+AC_DEFUN([_LT_LINKER_BOILERPLATE],
+[ac_outfile=conftest.$ac_objext
+printf "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_LINKER_BOILERPLATE
+
+
+# _LT_AC_SYS_LIBPATH_AIX
+# ----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
+[AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_AC_SYS_LIBPATH_AIX
+
+
+# _LT_AC_SHELL_INIT(ARG)
+# ----------------------
+AC_DEFUN([_LT_AC_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+            [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+        [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_AC_SHELL_INIT
+
+
+# _LT_AC_PROG_ECHO_BACKSLASH
+# --------------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
+[_LT_AC_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+  # Remove one level of quotation (which was required for Make).
+  ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+  ;;
+esac
+
+echo=${ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X[$]1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell.
+  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+fi
+
+if test "X[$]1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+[$]*
+EOF
+  exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+  for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+    # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+    if (echo_test_string=`eval $cmd`) 2>/dev/null &&
+       echo_test_string=`eval $cmd` &&
+       (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+    then
+      break
+    fi
+  done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+   echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+   test "X$echo_testing_string" = "X$echo_test_string"; then
+  :
+else
+  # The Solaris, AIX, and Digital Unix default echo programs unquote
+  # backslashes.  This makes it impossible to quote backslashes using
+  #   echo "$something" | sed 's/\\/\\\\/g'
+  #
+  # So, first we look for a working echo in the user's PATH.
+
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for dir in $PATH /usr/ucb; do
+    IFS="$lt_save_ifs"
+    if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+       test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      echo="$dir/echo"
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  if test "X$echo" = Xecho; then
+    # We didn't find a better echo, so look for alternatives.
+    if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      # This shell has a builtin print -r that does the trick.
+      echo='print -r'
+    elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+        test "X$CONFIG_SHELL" != X/bin/ksh; then
+      # If we have ksh, try running configure again with it.
+      ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+      export ORIGINAL_CONFIG_SHELL
+      CONFIG_SHELL=/bin/ksh
+      export CONFIG_SHELL
+      exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+    else
+      # Try using printf.
+      echo='printf %s\n'
+      if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+        echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+        test "X$echo_testing_string" = "X$echo_test_string"; then
+       # Cool, printf works
+       :
+      elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+          test "X$echo_testing_string" = 'X\t' &&
+          echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+          test "X$echo_testing_string" = "X$echo_test_string"; then
+       CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+       export CONFIG_SHELL
+       SHELL="$CONFIG_SHELL"
+       export SHELL
+       echo="$CONFIG_SHELL [$]0 --fallback-echo"
+      elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+          test "X$echo_testing_string" = 'X\t' &&
+          echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+          test "X$echo_testing_string" = "X$echo_test_string"; then
+       echo="$CONFIG_SHELL [$]0 --fallback-echo"
+      else
+       # maybe with a smaller string...
+       prev=:
+
+       for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+         if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+         then
+           break
+         fi
+         prev="$cmd"
+       done
+
+       if test "$prev" != 'sed 50q "[$]0"'; then
+         echo_test_string=`eval $prev`
+         export echo_test_string
+         exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+       else
+         # Oops.  We lost completely, so just stick with echo.
+         echo=echo
+       fi
+      fi
+    fi
+  fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+   ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+fi
+
+AC_SUBST(ECHO)
+])])# _LT_AC_PROG_ECHO_BACKSLASH
+
+
+# _LT_AC_LOCK
+# -----------
+AC_DEFUN([_LT_AC_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+       [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *ELF-32*)
+      HPUX_IA64_MODE="32"
+      ;;
+    *ELF-64*)
+      HPUX_IA64_MODE="64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+   if test "$lt_cv_prog_gnu_ld" = yes; then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -melf32bsmip"
+      ;;
+    *N32*)
+      LD="${LD-ld} -melf32bmipn32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -melf64bmip"
+      ;;
+    esac
+   else
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+   fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *32-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_i386"
+          ;;
+        ppc64-*linux*|powerpc64-*linux*)
+          LD="${LD-ld} -m elf32ppclinux"
+          ;;
+        s390x-*linux*)
+          LD="${LD-ld} -m elf_s390"
+          ;;
+        sparc64-*linux*)
+          LD="${LD-ld} -m elf32_sparc"
+          ;;
+      esac
+      ;;
+    *64-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        ppc*-*linux*|powerpc*-*linux*)
+          LD="${LD-ld} -m elf64ppc"
+          ;;
+        s390*-*linux*)
+          LD="${LD-ld} -m elf64_s390"
+          ;;
+        sparc*-*linux*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+  ])
+esac
+
+need_locks="$enable_libtool_lock"
+
+])# _LT_AC_LOCK
+
+
+# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#              [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
+[AC_REQUIRE([LT_AC_PROG_SED])
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+  ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $echo "X$_lt_compiler_boilerplate" | $Xsed >conftest.exp
+     $SED '/^$/d' conftest.err >conftest.er2
+     if test ! -s conftest.err || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $rm conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$5], , :, [$5])
+else
+    ifelse([$6], , :, [$6])
+fi
+])# AC_LIBTOOL_COMPILER_OPTION
+
+
+# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                          [ACTION-SUCCESS], [ACTION-FAILURE])
+# ------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
+[AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   printf "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $echo "X$_lt_linker_boilerplate" | $Xsed > conftest.exp
+       $SED '/^$/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $rm conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$4], , :, [$4])
+else
+    ifelse([$5], , :, [$5])
+fi
+])# AC_LIBTOOL_LINKER_OPTION
+
+
+# AC_LIBTOOL_SYS_MAX_CMD_LEN
+# --------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
+[# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536      # usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  *)
+    # If test is not a shell built-in, we'll probably end up computing a
+    # maximum length that is only half of the actual maximum length, but
+    # we can't tell.
+    SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+    while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+              = "XX$teststring") >/dev/null 2>&1 &&
+           new_result=`expr "X$teststring" : ".*" 2>&1` &&
+           lt_cv_sys_max_cmd_len=$new_result &&
+           test $i != 17 # 1/2 MB should be enough
+    do
+      i=`expr $i + 1`
+      teststring=$teststring$teststring
+    done
+    teststring=
+    # Add a significant safety factor because C++ compilers can tack on massive
+    # amounts of additional arguments before passing them to the linker.
+    # It appears as though 1/2 is a usable value.
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+])# AC_LIBTOOL_SYS_MAX_CMD_LEN
+
+
+# _LT_AC_CHECK_DLFCN
+# --------------------
+AC_DEFUN([_LT_AC_CHECK_DLFCN],
+[AC_CHECK_HEADERS(dlfcn.h)dnl
+])# _LT_AC_CHECK_DLFCN
+
+
+# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                           ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ------------------------------------------------------------------
+AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL          RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL                DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL                0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW         DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW       RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW     DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW     0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+
+    exit (status);
+}]
+EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_unknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_AC_TRY_DLOPEN_SELF
+
+
+# AC_LIBTOOL_DLOPEN_SELF
+# -------------------
+AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+   ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+   ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+   ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+         [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+           [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
+       [AC_CHECK_FUNC([dlopen],
+             [lt_cv_dlopen="dlopen"],
+         [AC_CHECK_LIB([dl], [dlopen],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+           [AC_CHECK_LIB([svld], [dlopen],
+                 [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+             [AC_CHECK_LIB([dld], [dld_link],
+                   [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
+             ])
+           ])
+         ])
+       ])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+         lt_cv_dlopen_self, [dnl
+         _LT_AC_TRY_DLOPEN_SELF(
+           lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+           lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      LDFLAGS="$LDFLAGS $link_static_flag"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+         lt_cv_dlopen_self_static, [dnl
+         _LT_AC_TRY_DLOPEN_SELF(
+           lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+           lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+])# AC_LIBTOOL_DLOPEN_SELF
+
+
+# AC_LIBTOOL_PROG_CC_C_O([TAGNAME])
+# ---------------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler
+AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $rm -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $echo "X$_lt_compiler_boilerplate" | $Xsed > out/conftest.exp
+     $SED '/^$/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.err || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $rm conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+   $rm out/* && rmdir out
+   cd ..
+   rmdir conftest
+   $rm conftest*
+])
+])# AC_LIBTOOL_PROG_CC_C_O
+
+
+# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME])
+# -----------------------------------------
+# Check to see if we can do hard links to lock some files if needed
+AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS],
+[AC_REQUIRE([_LT_AC_LOCK])dnl
+
+hard_links="nottested"
+if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AMANDA_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS
+
+
+# AC_LIBTOOL_OBJDIR
+# -----------------
+AC_DEFUN([AC_LIBTOOL_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+])# AC_LIBTOOL_OBJDIR
+
+
+# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME])
+# ----------------------------------------------
+# Check hardcoding attributes.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_AC_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
+   test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \
+   test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existant directories.
+  if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_AC_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_AC_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_AC_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH
+
+
+# AC_LIBTOOL_SYS_LIB_STRIP
+# ------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP],
+[striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+   darwin*)
+       if test -n "$STRIP" ; then
+         striplib="$STRIP -x"
+         AC_MSG_RESULT([yes])
+       else
+  AC_MSG_RESULT([no])
+fi
+       ;;
+   *)
+  AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+])# AC_LIBTOOL_SYS_LIB_STRIP
+
+
+# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
+[AC_MSG_CHECKING([dynamic linker characteristics])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix4* | aix5*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+          echo ' yes '
+          echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+       :
+      else
+       can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $rm \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+  if test "$GCC" = yes; then
+    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+  else
+    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+  fi
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+kfreebsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[123]]*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  *) # from 3.2 on
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+   hppa*64*)
+     shrext_cmds='.sl'
+     hardcode_into_libs=yes
+     dynamic_linker="$host_os dld.sl"
+     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     soname_spec='${libname}${release}${shared_ext}$major'
+     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+     ;;
+   *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+       if test "$lt_cv_prog_gnu_ld" = yes; then
+               version_type=linux
+       else
+               version_type=irix
+       fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,   ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+knetbsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+nto-qnx*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+openbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+    *)                         need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+       shlibpath_overrides_runpath=no
+       ;;
+      *)
+       shlibpath_overrides_runpath=yes
+       ;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+sco3.2v5*)
+  version_type=osf
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      export_dynamic_flag_spec='${wl}-Blargedynsym'
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+
+
+# _LT_AC_TAGCONFIG
+# ----------------
+AC_DEFUN([_LT_AC_TAGCONFIG],
+[AC_ARG_WITH([tags],
+    [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
+        [include additional configurations @<:@automatic@:>@])],
+    [tagnames="$withval"])
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+  if test ! -f "${ofile}"; then
+    AMANDA_MSG_WARN([output file `$ofile' does not exist])
+  fi
+
+  if test -z "$LTCC"; then
+    eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+    if test -z "$LTCC"; then
+      AMANDA_MSG_WARN([output file `$ofile' does not look like a libtool script])
+    else
+      AMANDA_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+    fi
+  fi
+
+  # Extract list of available tagged configurations in $ofile.
+  # Note that this assumes the entire list is on one line.
+  available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+  lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+  for tagname in $tagnames; do
+    IFS="$lt_save_ifs"
+    # Check whether tagname contains only valid characters
+    case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in
+    "") ;;
+    *)  AC_MSG_ERROR([invalid tag name: $tagname])
+       ;;
+    esac
+
+    if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+    then
+      AC_MSG_ERROR([tag name \"$tagname\" already exists])
+    fi
+
+    # Update the list of available tags.
+    if test -n "$tagname"; then
+      echo appending configuration tag \"$tagname\" to $ofile
+
+      case $tagname in
+      CXX)
+       if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+           ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+           (test "X$CXX" != "Xg++"))) ; then
+         AC_LIBTOOL_LANG_CXX_CONFIG
+       else
+         tagname=""
+       fi
+       ;;
+
+      F77)
+       if test -n "$F77" && test "X$F77" != "Xno"; then
+         AC_LIBTOOL_LANG_F77_CONFIG
+       else
+         tagname=""
+       fi
+       ;;
+
+      GCJ)
+       if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+         AC_LIBTOOL_LANG_GCJ_CONFIG
+       else
+         tagname=""
+       fi
+       ;;
+
+      RC)
+       AC_LIBTOOL_LANG_RC_CONFIG
+       ;;
+
+      *)
+       AC_MSG_ERROR([Unsupported tag name: $tagname])
+       ;;
+      esac
+
+      # Append the new tag name to the list of available tags.
+      if test -n "$tagname" ; then
+      available_tags="$available_tags $tagname"
+    fi
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  # Now substitute the updated list of available tags.
+  if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+    mv "${ofile}T" "$ofile"
+    chmod +x "$ofile"
+  else
+    rm -f "${ofile}T"
+    AC_MSG_ERROR([unable to update list of available tagged configurations.])
+  fi
+fi
+])# _LT_AC_TAGCONFIG
+
+
+# AC_LIBTOOL_DLOPEN
+# -----------------
+# enable checks for dlopen support
+AC_DEFUN([AC_LIBTOOL_DLOPEN],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_DLOPEN
+
+
+# AC_LIBTOOL_WIN32_DLL
+# --------------------
+# declare package support for building win32 DLLs
+AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_WIN32_DLL
+
+
+# AC_ENABLE_SHARED([DEFAULT])
+# ---------------------------
+# implement the --enable-shared flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_SHARED],
+[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([shared],
+    [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+       [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_shared=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]AC_ENABLE_SHARED_DEFAULT)
+])# AC_ENABLE_SHARED
+
+
+# AC_DISABLE_SHARED
+# -----------------
+#- set the default shared flag to --disable-shared
+AC_DEFUN([AC_DISABLE_SHARED],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)
+])# AC_DISABLE_SHARED
+
+
+# AC_ENABLE_STATIC([DEFAULT])
+# ---------------------------
+# implement the --enable-static flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_STATIC],
+[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([static],
+    [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+       [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_static=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]AC_ENABLE_STATIC_DEFAULT)
+])# AC_ENABLE_STATIC
+
+
+# AC_DISABLE_STATIC
+# -----------------
+# set the default static flag to --disable-static
+AC_DEFUN([AC_DISABLE_STATIC],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)
+])# AC_DISABLE_STATIC
+
+
+# AC_ENABLE_FAST_INSTALL([DEFAULT])
+# ---------------------------------
+# implement the --enable-fast-install flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([fast-install],
+    [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_fast_install=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT)
+])# AC_ENABLE_FAST_INSTALL
+
+
+# AC_DISABLE_FAST_INSTALL
+# -----------------------
+# set the default to --disable-fast-install
+AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)
+])# AC_DISABLE_FAST_INSTALL
+
+
+# AC_LIBTOOL_PICMODE([MODE])
+# --------------------------
+# implement the --with-pic flag
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+AC_DEFUN([AC_LIBTOOL_PICMODE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+pic_mode=ifelse($#,1,$1,default)
+])# AC_LIBTOOL_PICMODE
+
+
+# AC_PROG_EGREP
+# -------------
+# This is predefined starting with Autoconf 2.54, so this conditional
+# definition can be removed once we require Autoconf 2.54 or later.
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+   [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])])
+
+
+# AC_PATH_TOOL_PREFIX
+# -------------------
+# find a file program which can recognise shared library
+AC_DEFUN([AC_PATH_TOOL_PREFIX],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="ifelse([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+       case $deplibs_check_method in
+       "file_magic "*)
+         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+           $EGREP "$file_magic_regex" > /dev/null; then
+           :
+         else
+           cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+         fi ;;
+       esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+])# AC_PATH_TOOL_PREFIX
+
+
+# AC_PATH_MAGIC
+# -------------
+# find a file program which can recognise a shared library
+AC_DEFUN([AC_PATH_MAGIC],
+[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# AC_PATH_MAGIC
+
+
+# AC_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AC_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+    [AC_HELP_STRING([--with-gnu-ld],
+       [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])
+AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break
+       ;;
+      *)
+       test "$with_gnu_ld" != yes && break
+       ;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_PROG_LD_GNU
+])# AC_PROG_LD
+
+
+# AC_PROG_LD_GNU
+# --------------
+AC_DEFUN([AC_PROG_LD_GNU],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AC_PROG_LD_GNU
+
+
+# AC_PROG_LD_RELOAD_FLAG
+# ----------------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$CC -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+])# AC_PROG_LD_RELOAD_FLAG
+
+
+# AC_DEPLIBS_CHECK_METHOD
+# -----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+[AC_CACHE_CHECK([how to recognise dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+  lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | kfreebsd*-gnu | dragonfly*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+nto-qnx*)
+  lt_cv_deplibs_check_method=unknown
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sco3.2v5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+])# AC_DEPLIBS_CHECK_METHOD
+
+
+# AC_PROG_NM
+# ----------
+# find the pathname to a BSD-compatible name lister
+AC_DEFUN([AC_PROG_NM],
+[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    tmp_nm="$ac_dir/${ac_tool_prefix}nm"
+    if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      # Tru64's nm complains that /dev/null is an invalid object file
+      case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+      */dev/null* | *'Invalid file or object type'*)
+       lt_cv_path_NM="$tmp_nm -B"
+       break
+        ;;
+      *)
+       case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+       */dev/null*)
+         lt_cv_path_NM="$tmp_nm -p"
+         break
+         ;;
+       *)
+         lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+         continue # so that we can try to find one that supports BSD flags
+         ;;
+       esac
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+  test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi])
+NM="$lt_cv_path_NM"
+])# AC_PROG_NM
+
+
+# AC_CHECK_LIBM
+# -------------
+# check for math library
+AC_DEFUN([AC_CHECK_LIBM],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+])# AC_CHECK_LIBM
+
+
+# AC_LIBLTDL_CONVENIENCE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl convenience library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-convenience to the configure arguments.  Note that
+# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+# it is assumed to be `libltdl'.  LIBLTDL will be prefixed with
+# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/'
+# (note the single quotes!).  If your package is not flat and you're not
+# using automake, define top_builddir and top_srcdir appropriately in
+# the Makefiles.
+AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  case $enable_ltdl_convenience in
+  no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+  "") enable_ltdl_convenience=yes
+      ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+  esac
+  LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+  LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_CONVENIENCE
+
+
+# AC_LIBLTDL_INSTALLABLE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl installable library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-install to the configure arguments.  Note that
+# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+# and an installed libltdl is not found, it is assumed to be `libltdl'.
+# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with
+# '${top_srcdir}/' (note the single quotes!).  If your package is not
+# flat and you're not using automake, define top_builddir and top_srcdir
+# appropriately in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  AC_CHECK_LIB(ltdl, lt_dlinit,
+  [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+  [if test x"$enable_ltdl_install" = xno; then
+     AMANDA_MSG_WARN([libltdl not installed, but installation disabled])
+   else
+     enable_ltdl_install=yes
+   fi
+  ])
+  if test x"$enable_ltdl_install" = x"yes"; then
+    ac_configure_args="$ac_configure_args --enable-ltdl-install"
+    LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+    LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  else
+    ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+    LIBLTDL="-lltdl"
+    LTDLINCL=
+  fi
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_INSTALLABLE
+
+
+# AC_LIBTOOL_CXX
+# --------------
+# enable support for C++ libraries
+AC_DEFUN([AC_LIBTOOL_CXX],
+[AC_REQUIRE([_LT_AC_LANG_CXX])
+])# AC_LIBTOOL_CXX
+
+
+# _LT_AC_LANG_CXX
+# ---------------
+AC_DEFUN([_LT_AC_LANG_CXX],
+[AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
+])# _LT_AC_LANG_CXX
+
+# _LT_AC_PROG_CXXCPP
+# ---------------
+AC_DEFUN([_LT_AC_PROG_CXXCPP],
+[
+AC_REQUIRE([AC_PROG_CXX])
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+fi
+])# _LT_AC_PROG_CXXCPP
+
+# AC_LIBTOOL_F77
+# --------------
+# enable support for Fortran 77 libraries
+AC_DEFUN([AC_LIBTOOL_F77],
+[AC_REQUIRE([_LT_AC_LANG_F77])
+])# AC_LIBTOOL_F77
+
+
+# _LT_AC_LANG_F77
+# ---------------
+AC_DEFUN([_LT_AC_LANG_F77],
+[AC_REQUIRE([AC_PROG_F77])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77])
+])# _LT_AC_LANG_F77
+
+
+# AC_LIBTOOL_GCJ
+# --------------
+# enable support for GCJ libraries
+AC_DEFUN([AC_LIBTOOL_GCJ],
+[AC_REQUIRE([_LT_AC_LANG_GCJ])
+])# AC_LIBTOOL_GCJ
+
+
+# _LT_AC_LANG_GCJ
+# ---------------
+AC_DEFUN([_LT_AC_LANG_GCJ],
+[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+    [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+      [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+        [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+          [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
+])# _LT_AC_LANG_GCJ
+
+
+# AC_LIBTOOL_RC
+# --------------
+# enable support for Windows resource files
+AC_DEFUN([AC_LIBTOOL_RC],
+[AC_REQUIRE([LT_AC_PROG_RC])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC])
+])# AC_LIBTOOL_RC
+
+
+# AC_LIBTOOL_LANG_C_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG])
+AC_DEFUN([_LT_AC_LANG_C_CONFIG],
+[lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}\n'
+
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+#
+# Check for any special shared library compilation flags.
+#
+_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)=
+if test "$GCC" = no; then
+  case $host_os in
+  sco3.2v5*)
+    _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf'
+    ;;
+  esac
+fi
+if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then
+  AMANDA_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries])
+  if echo "$old_CC $old_CFLAGS " | grep "[[    ]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[        ]]" >/dev/null; then :
+  else
+    AMANDA_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure])
+    _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no
+  fi
+fi
+
+
+#
+# Check to make sure the static flag actually works.
+#
+AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works],
+  _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+  $_LT_AC_TAGVAR(lt_prog_compiler_static, $1),
+  [],
+  [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+# Report which librarie types wil actually be built
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case $host_os in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+
+aix4* | aix5*)
+  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+    test "$enable_shared" = yes && enable_static=no
+  fi
+    ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_C_CONFIG
+
+
+# AC_LIBTOOL_LANG_CXX_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
+AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
+[AC_LANG_PUSH(C++)
+AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Dependencies to place before and after the object being linked:
+_LT_AC_TAGVAR(predep_objects, $1)=
+_LT_AC_TAGVAR(postdep_objects, $1)=
+_LT_AC_TAGVAR(predeps, $1)=
+_LT_AC_TAGVAR(postdeps, $1)=
+_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+  lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+  unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+  lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+  unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+else
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+fi
+
+if test "$GXX" = yes; then
+  # Set up default GNU C++ configuration
+
+  AC_PROG_LD
+
+  # Check if GNU C++ uses GNU ld as the underlying linker, since the
+  # archiving commands below assume that GNU ld is being used.
+  if test "$with_gnu_ld" = yes; then
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+    #     investigate it a little bit more. (MM)
+    wlarc='${wl}'
+
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+       grep 'no-whole-archive' > /dev/null; then
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    with_gnu_ld=no
+    wlarc=
+
+    # A generic and very simple default shared library creation
+    # command for GNU C++ for the case where it uses the native
+    # linker, instead of GNU ld.  If possible, this setting should
+    # overridden to take advantage of the native linker features on
+    # the platform it is being used on.
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+  fi
+
+  # Commands to make compiler produce verbose output that lists
+  # what "hidden" libraries, object files and flags are used when
+  # linking a shared library.
+  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+  GXX=no
+  with_gnu_ld=no
+  wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+case $host_os in
+  aix3*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  aix4* | aix5*)
+    if test "$host_cpu" = ia64; then
+      # On IA64, the linker does run time linking by default, so we don't
+      # have to do anything special.
+      aix_use_runtimelinking=no
+      exp_sym_flag='-Bexport'
+      no_entry_flag=""
+    else
+      aix_use_runtimelinking=no
+
+      # Test if we are trying to use run time linking or normal
+      # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+      # need to do runtime linking.
+      case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+       for ld_flag in $LDFLAGS; do
+         case $ld_flag in
+         *-brtl*)
+           aix_use_runtimelinking=yes
+           break
+           ;;
+         esac
+       done
+      esac
+
+      exp_sym_flag='-bexport'
+      no_entry_flag='-bnoentry'
+    fi
+
+    # When large executables or shared objects are built, AIX ld can
+    # have problems creating the table of contents.  If linking a library
+    # or program results in "error TOC overflow" add -mminimal-toc to
+    # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+    # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+    _LT_AC_TAGVAR(archive_cmds, $1)=''
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+    if test "$GXX" = yes; then
+      case $host_os in aix4.[[012]]|aix4.[[012]].*)
+      # We only want to do this on AIX 4.2 and lower, the check
+      # below for broken collect2 doesn't work under 4.3+
+       collect2name=`${CC} -print-prog-name=collect2`
+       if test -f "$collect2name" && \
+          strings "$collect2name" | grep resolve_lib_name >/dev/null
+       then
+         # We have reworked collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+       else
+         # We have old collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+         # It fails to find uninstalled libraries when the uninstalled
+         # path is not listed in the libpath.  Setting hardcode_minus_L
+         # to unsupported forces relinking
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+       fi
+      esac
+      shared_flag='-shared'
+      if test "$aix_use_runtimelinking" = yes; then
+       shared_flag="$shared_flag "'${wl}-G'
+      fi
+    else
+      # not using gcc
+      if test "$host_cpu" = ia64; then
+       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+       # chokes on -Wl,-G. The following line is correct:
+       shared_flag='-G'
+      else
+       if test "$aix_use_runtimelinking" = yes; then
+         shared_flag='${wl}-G'
+       else
+         shared_flag='${wl}-bM:SRE'
+       fi
+      fi
+    fi
+
+    # It seems that -bexpall does not export symbols beginning with
+    # underscore (_), so it is better to generate a list of symbols to export.
+    _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+    if test "$aix_use_runtimelinking" = yes; then
+      # Warning - without using the other runtime loading flags (-brtl),
+      # -berok will link without error, but may produce a broken library.
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+      # Determine the default libpath from the value encoded in an empty executable.
+      _LT_AC_SYS_LIBPATH_AIX
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+     else
+      if test "$host_cpu" = ia64; then
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+      else
+       # Determine the default libpath from the value encoded in an empty executable.
+       _LT_AC_SYS_LIBPATH_AIX
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+       # Warning - without using the other run time loading flags,
+       # -berok will link without error, but may produce a broken library.
+       _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+       # -bexpall does not export symbols beginning with underscore (_)
+       _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+       # Exported symbols can be pulled into shared objects from archives
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+       _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+       # This is similar to how AIX traditionally builds its shared libraries.
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+      fi
+    fi
+    ;;
+  chorus*)
+    case $cc_basename in
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+
+
+  cygwin* | mingw* | pw32*)
+    # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+    # as there is no search path for DLLs.
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+    _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+    _LT_AC_TAGVAR(always_export_symbols, $1)=no
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+    if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+      # If the export-symbols file already is a .def file (1st line
+      # is EXPORTS), use it as is; otherwise, prepend...
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+       cp $export_symbols $output_objdir/$soname.def;
+      else
+       echo EXPORTS > $output_objdir/$soname.def;
+       cat $export_symbols >> $output_objdir/$soname.def;
+      fi~
+      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
+  ;;
+      darwin* | rhapsody*)
+        case $host_os in
+        rhapsody* | darwin1.[[012]])
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+         ;;
+       *) # Darwin 1.3 on
+         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+         else
+           case ${MACOSX_DEPLOYMENT_TARGET} in
+             10.[[012]])
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+               ;;
+             10.*)
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+               ;;
+           esac
+         fi
+         ;;
+        esac
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+    if test "$GXX" = yes ; then
+      lt_int_apple_cc_single_mod=no
+      output_verbose_link_cmd='echo'
+      if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then
+       lt_int_apple_cc_single_mod=yes
+      fi
+      if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      else
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+        fi
+        _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+        # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+          if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          else
+            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          fi
+            _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      else
+      case $cc_basename in
+        xlc*)
+         output_verbose_link_cmd='echo'
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+          _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          ;;
+       *)
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+          ;;
+      esac
+      fi
+        ;;
+
+  dgux*)
+    case $cc_basename in
+      ec++*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      ghcx*)
+       # Green Hills C++ Compiler
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  freebsd[[12]]*)
+    # C++ shared libraries reported to be fairly broken before switch to ELF
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  freebsd-elf*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    ;;
+  freebsd* | kfreebsd*-gnu | dragonfly*)
+    # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+    # conventions
+    _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+    ;;
+  gnu*)
+    ;;
+  hpux9*)
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                               # but as the default
+                               # location of the library.
+
+    case $cc_basename in
+    CC*)
+      # FIXME: insert proper C++ library support
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    aCC*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      #
+      # There doesn't appear to be a way to prevent this compiler from
+      # explicitly linking system object files so we need to strip them
+      # from the output so that they don't get included in the library
+      # dependencies.
+      output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+      ;;
+    *)
+      if test "$GXX" = yes; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+        # FIXME: insert proper C++ library support
+        _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+    ;;
+  hpux10*|hpux11*)
+    if test $with_gnu_ld = no; then
+      case $host_cpu in
+      hppa*64*)
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+        ;;
+      ia64*)
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+        ;;
+      *)
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        ;;
+      esac
+    fi
+    case $host_cpu in
+    hppa*64*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+    ia64*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                                             # but as the default
+                                             # location of the library.
+      ;;
+    *)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                                             # but as the default
+                                             # location of the library.
+      ;;
+    esac
+
+    case $cc_basename in
+      CC*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      aCC*)
+       case $host_cpu in
+       hppa*64*|ia64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+         ;;
+       esac
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+      *)
+       if test "$GXX" = yes; then
+         if test $with_gnu_ld = no; then
+           case $host_cpu in
+           ia64*|hppa*64*)
+             _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+             ;;
+           *)
+             _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+             ;;
+           esac
+         fi
+       else
+         # FIXME: insert proper C++ library support
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+    esac
+    ;;
+  irix5* | irix6*)
+    case $cc_basename in
+      CC*)
+       # SGI C++
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+       # Archives containing C++ object files must be created using
+       # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+       # necessary to make sure instantiated templates are included
+       # in the archive.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+       ;;
+      *)
+       if test "$GXX" = yes; then
+         if test "$with_gnu_ld" = no; then
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+         else
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+         fi
+       fi
+       _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+       ;;
+    esac
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+    ;;
+  linux*)
+    case $cc_basename in
+      KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+       # KCC will only create a shared library if the output file
+       # ends with ".so" (or ".sl" for HP-UX), so rename the library
+       # to its proper name (with version) after linking.
+       _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+       # Archives containing C++ object files must be created using
+       # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+       ;;
+      icpc*)
+       # Intel C++
+       with_gnu_ld=yes
+       # version 8.0 and above of icpc choke on multiply defined symbols
+       # if we add $predep_objects and $postdep_objects, however 7.1 and
+       # earlier do not add the objects themselves.
+       case `$CC -V 2>&1` in
+       *"Version 7."*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         ;;
+       *)  # Version 8.0 or newer
+         tmp_idyn=
+         case $host_cpu in
+           ia64*) tmp_idyn=' -i_dynamic';;
+         esac
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         ;;
+       esac
+       _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+       ;;
+      pgCC*)
+        # Portland Group C++ compiler
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+        ;;
+      cxx*)
+       # Compaq C++
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+       runpath_var=LD_RUN_PATH
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+    esac
+    ;;
+  lynxos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  m88k*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  mvs*)
+    case $cc_basename in
+      cxx*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  netbsd*)
+    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    fi
+    # Workaround some broken pre-1.5 toolchains
+    output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+    ;;
+  openbsd2*)
+    # C++ shared libraries are fairly broken
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  openbsd*)
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+    if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    fi
+    output_verbose_link_cmd='echo'
+    ;;
+  osf3*)
+    case $cc_basename in
+      KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+       # KCC will only create a shared library if the output file
+       # ends with ".so" (or ".sl" for HP-UX), so rename the library
+       # to its proper name (with version) after linking.
+       _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Archives containing C++ object files must be created using
+       # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+
+       ;;
+      RCC*)
+       # Rational C++ 2.4.1
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      cxx*)
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+      *)
+       if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+         # Commands to make compiler produce verbose output that lists
+         # what "hidden" libraries, object files and flags are used when
+         # linking a shared library.
+         output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+       else
+         # FIXME: insert proper C++ library support
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+    esac
+    ;;
+  osf4* | osf5*)
+    case $cc_basename in
+      KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+       # KCC will only create a shared library if the output file
+       # ends with ".so" (or ".sl" for HP-UX), so rename the library
+       # to its proper name (with version) after linking.
+       _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Archives containing C++ object files must be created using
+       # the KAI C++ compiler.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
+       ;;
+      RCC*)
+       # Rational C++ 2.4.1
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      cxx*)
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+         echo "-hidden">> $lib.exp~
+         $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp  `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~
+         $rm $lib.exp'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+      *)
+       if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+         # Commands to make compiler produce verbose output that lists
+         # what "hidden" libraries, object files and flags are used when
+         # linking a shared library.
+         output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+       else
+         # FIXME: insert proper C++ library support
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+    esac
+    ;;
+  psos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  sco*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    case $cc_basename in
+      CC*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  sunos4*)
+    case $cc_basename in
+      CC*)
+       # Sun C++ 4.x
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      lcc*)
+       # Lucid
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  solaris*)
+    case $cc_basename in
+      CC*)
+       # Sun C++ 4.2, 5.x and Centerline C++
+        _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes
+       _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+       $CC -G${allow_undefined_flag}  ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+       case $host_os in
+         solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+         *)
+           # The C++ compiler is used as linker so we must use $wl
+           # flag to pass the commands to the underlying system
+           # linker. We must also pass each convience library through
+           # to the system linker between allextract/defaultextract.
+           # The C++ compiler will combine linker options so we
+           # cannot just pass the convience library names through
+           # without $wl.
+           # Supported since Solaris 2.6 (maybe 2.5.1?)
+           _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract'
+           ;;
+       esac
+       _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+       output_verbose_link_cmd='echo'
+
+       # Archives containing C++ object files must be created using
+       # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+       # necessary to make sure instantiated templates are included
+       # in the archive.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+       ;;
+      gcx*)
+       # Green Hills C++ Compiler
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+       # The C++ compiler must be used to create the archive.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+       ;;
+      *)
+       # GNU C++ compiler with Solaris linker
+       if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+         _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+         if $CC --version | grep -v '^2\.7' > /dev/null; then
+           if $CC -v --help 2>/dev/null | grep -- -shared  > /dev/null 2> /dev/null; then
+             _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+              _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+             # Commands to make compiler produce verbose output that lists
+             # what "hidden" libraries, object files and flags are used when
+             # linking a shared library.
+             output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+              _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           else
+             _LT_AC_TAGVAR(archive_cmds, $1)='$CC ${wl}-G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+              _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $CC ${wl}-G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+             # Commands to make compiler produce verbose output that lists
+             # what "hidden" libraries, object files and flags are used when
+             # linking a shared library.
+             output_verbose_link_cmd="$CC ${wl}-G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+              _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-Bstatic'
+           fi
+         else
+           # g++ 2.7 appears to require `-G' NOT `-shared' on this
+           # platform.
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+           _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+         fi
+
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+       fi
+       ;;
+    esac
+    ;;
+  sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    ;;
+  tandem*)
+    case $cc_basename in
+      NCC*)
+       # NonStop-UX NCC 3.20
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  vxworks*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  *)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+esac
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$GXX"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+AC_LIBTOOL_POSTDEP_PREDEP($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+])# AC_LIBTOOL_LANG_CXX_CONFIG
+
+# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+# ------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+ifelse([$1],[],[cat > conftest.$ac_ext <<EOF
+int a;
+void foo (void) { a = 0; }
+EOF
+],[$1],[CXX],[cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+EOF
+],[$1],[F77],[cat > conftest.$ac_ext <<EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+EOF
+],[$1],[GCJ],[cat > conftest.$ac_ext <<EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  # The `*' in the case matches for architectures that use `case' in
+  # $output_verbose_cmd can trigger glob expansion during the loop
+  # eval without this substitution.
+  output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
+
+  for p in `eval $output_verbose_link_cmd`; do
+    case $p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" \
+         || test $p = "-R"; then
+        prev=$p
+        continue
+       else
+        prev=
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+        case $p in
+        -L* | -R*)
+          # Internal compiler library paths should come after those
+          # provided the user.  The postdeps already come after the
+          # user supplied libs so there is no need to process them.
+          if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+            _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+          else
+            _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+          fi
+          ;;
+        # The "-l" case would never come before the object being
+        # linked, so don't bother handling this case.
+        esac
+       else
+        if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then
+          _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}"
+        else
+          _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}"
+        fi
+       fi
+       ;;
+
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+        pre_test_object_deps_done=yes
+        continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+        if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then
+          _LT_AC_TAGVAR(predep_objects, $1)="$p"
+        else
+          _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p"
+        fi
+       else
+        if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then
+          _LT_AC_TAGVAR(postdep_objects, $1)="$p"
+        else
+          _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p"
+        fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$rm -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+ifelse([$1],[CXX],
+[case $host_os in
+solaris*)
+  case $cc_basename in
+  CC*)
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    _LT_AC_TAGVAR(postdeps,$1)='-lCstd -lCrun'
+    ;;
+  esac
+esac
+])
+
+case " $_LT_AC_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+])# AC_LIBTOOL_POSTDEP_PREDEP
+
+# AC_LIBTOOL_LANG_F77_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)])
+AC_DEFUN([_LT_AC_LANG_F77_CONFIG],
+[AC_REQUIRE([AC_PROG_F77])
+AC_LANG_PUSH(Fortran 77)
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="      subroutine t\n      return\n      end\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="      program t\n      end\n"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case $host_os in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+aix4* | aix5*)
+  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+    test "$enable_shared" = yes && enable_static=no
+  fi
+  ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$G77"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_F77_CONFIG
+
+
+# AC_LIBTOOL_LANG_GCJ_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)])
+AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_GCJ_CONFIG
+
+
+# AC_LIBTOOL_LANG_RC_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the Windows resource compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)])
+AC_DEFUN([_LT_AC_LANG_RC_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_RC_CONFIG
+
+
+# AC_LIBTOOL_CONFIG([TAGNAME])
+# ----------------------------
+# If TAGNAME is not passed, then create an initial libtool script
+# with a default configuration from the untagged config vars.  Otherwise
+# add code to config.status for appending the configuration named by
+# TAGNAME from the matching tagged config vars.
+AC_DEFUN([AC_LIBTOOL_CONFIG],
+[# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
+  # Now quote all the things that may contain metacharacters while being
+  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+  # variables and quote the copies for generation of the libtool script.
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    old_postinstall_cmds old_postuninstall_cmds \
+    _LT_AC_TAGVAR(compiler, $1) \
+    _LT_AC_TAGVAR(CC, $1) \
+    _LT_AC_TAGVAR(LD, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \
+    _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \
+    _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \
+    _LT_AC_TAGVAR(old_archive_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \
+    _LT_AC_TAGVAR(predep_objects, $1) \
+    _LT_AC_TAGVAR(postdep_objects, $1) \
+    _LT_AC_TAGVAR(predeps, $1) \
+    _LT_AC_TAGVAR(postdeps, $1) \
+    _LT_AC_TAGVAR(compiler_lib_search_path, $1) \
+    _LT_AC_TAGVAR(archive_cmds, $1) \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(postinstall_cmds, $1) \
+    _LT_AC_TAGVAR(postuninstall_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \
+    _LT_AC_TAGVAR(allow_undefined_flag, $1) \
+    _LT_AC_TAGVAR(no_undefined_flag, $1) \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \
+    _LT_AC_TAGVAR(hardcode_automatic, $1) \
+    _LT_AC_TAGVAR(module_cmds, $1) \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
+    _LT_AC_TAGVAR(exclude_expsyms, $1) \
+    _LT_AC_TAGVAR(include_expsyms, $1); do
+
+    case $var in
+    _LT_AC_TAGVAR(old_archive_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(module_cmds, $1) | \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case $lt_echo in
+  *'\[$]0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'`
+    ;;
+  esac
+
+ifelse([$1], [],
+  [cfgfile="${ofile}T"
+  trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+  $rm -f "$cfgfile"
+  AC_MSG_NOTICE([creating $ofile])],
+  [cfgfile="$ofile"])
+
+  cat <<__EOF__ >> "$cfgfile"
+ifelse([$1], [],
+[#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e 1s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG],
+[# ### BEGIN LIBTOOL TAG CONFIG: $tagname])
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# A language-specific compiler.
+CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
+
+# Is the compiler the GNU C compiler?
+with_gcc=$_LT_AC_TAGVAR(GCC, $1)
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_[]_LT_AC_TAGVAR(LD, $1)
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1)
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1)
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1)
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1)
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1)
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1)
+archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1)
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1)
+module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1)
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1)
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1)
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1)
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1)
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1)
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1)
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1)
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1)
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1)
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1)
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1)
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1)
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1)
+
+# Symbols that must always be exported.
+include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1)
+
+ifelse([$1],[],
+[# ### END LIBTOOL CONFIG],
+[# ### END LIBTOOL TAG CONFIG: $tagname])
+
+__EOF__
+
+ifelse([$1],[], [
+  case $host_os in
+  aix3*)
+    cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+EOF
+    ;;
+  esac
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" || \
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+])
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+])# AC_LIBTOOL_CONFIG
+
+
+# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+
+_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI
+
+
+# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+# ---------------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
+[AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_NM])
+AC_REQUIRE([AC_OBJEXT])
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*) # Its linker distinguishes data from code symbols
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+  lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  ;;
+linux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDGIRSTW]]'
+    lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+    lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris* | sysv5*)
+  symcode='[[BDRT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[     ]]\($symcode$symcode*\)[[       ]][[    ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+       mv -f "$nlist"T "$nlist"
+      else
+       rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if grep ' nm_test_var$' "$nlist" >/dev/null; then
+       if grep ' nm_test_func$' "$nlist" >/dev/null; then
+         cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+         # Now generate the symbol file.
+         eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+         cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+  const char *name;
+  lt_ptr_t address;
+}
+lt_preloaded_symbols[[]] =
+{
+EOF
+         $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+         cat <<\EOF >> conftest.$ac_ext
+  {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+         # Now try linking the two files.
+         mv conftest.$ac_objext conftstm.$ac_objext
+         lt_save_LIBS="$LIBS"
+         lt_save_CFLAGS="$CFLAGS"
+         LIBS="conftstm.$ac_objext"
+         CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+         if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+           pipe_works=yes
+         fi
+         LIBS="$lt_save_LIBS"
+         CFLAGS="$lt_save_CFLAGS"
+       else
+         echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+       fi
+      else
+       echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -f conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+
+
+# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME])
+# ---------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],
+[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+ ifelse([$1],[CXX],[
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | os2* | pw32*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix4* | aix5*)
+       # All AIX code is PIC.
+       if test "$host_cpu" = ia64; then
+         # AIX 5 now supports IA64 processor
+         _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       else
+         _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+       fi
+       ;;
+      chorus*)
+       case $cc_basename in
+       cxch68*)
+         # Green Hills C++ Compiler
+         # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+         ;;
+       esac
+       ;;
+       darwin*)
+         # PIC is the default on this platform
+         # Common symbols not allowed in MH_DYLIB files
+         case $cc_basename in
+           xlc*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           ;;
+         esac
+       ;;
+      dgux*)
+       case $cc_basename in
+         ec++*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         ghcx*)
+           # Green Hills C++ Compiler
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      freebsd* | kfreebsd*-gnu | dragonfly*)
+       # FreeBSD uses GNU C++
+       ;;
+      hpux9* | hpux10* | hpux11*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+           if test "$host_cpu" != ia64; then
+             _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+           fi
+           ;;
+         aCC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+           case $host_cpu in
+           hppa*64*|ia64*)
+             # +Z the default
+             ;;
+           *)
+             _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+             ;;
+           esac
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      irix5* | irix6* | nonstopux*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           # CC pic flag -KPIC is the default.
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      linux*)
+       case $cc_basename in
+         KCC*)
+           # KAI C++ Compiler
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+           ;;
+         icpc* | ecpc*)
+           # Intel C++
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           ;;
+         pgCC*)
+           # Portland Group C++ compiler.
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         cxx*)
+           # Compaq C++
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      lynxos*)
+       ;;
+      m88k*)
+       ;;
+      mvs*)
+       case $cc_basename in
+         cxx*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      netbsd*)
+       ;;
+      osf3* | osf4* | osf5*)
+       case $cc_basename in
+         KCC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           ;;
+         RCC*)
+           # Rational C++ 2.4.1
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         cxx*)
+           # Digital/Compaq C++
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      psos*)
+       ;;
+      sco*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      solaris*)
+       case $cc_basename in
+         CC*)
+           # Sun C++ 4.2, 5.x and Centerline C++
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+           ;;
+         gcx*)
+           # Green Hills C++ Compiler
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+           ;;
+         *)
+           if $CC -v --help 2>/dev/null | grep -- -static  > /dev/null 2> /dev/null; then
+             _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           else
+             # GCC with Sun linker
+             _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+             _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-Bstatic'
+            fi
+           ;;
+       esac
+       ;;
+      sunos4*)
+       case $cc_basename in
+         CC*)
+           # Sun C++ 4.x
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         lcc*)
+           # Lucid
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      tandem*)
+       case $cc_basename in
+         NCC*)
+           # NonStop-UX NCC 3.20
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      unixware*)
+       ;;
+      vxworks*)
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+       ;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
+
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+      darwin*)
+        # PIC is the default on this platform
+        # Common symbols not allowed in MH_DYLIB files
+       case $cc_basename in
+         xlc*)
+         _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+         _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         ;;
+       esac
+       ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+       ;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    newsos6)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    linux*)
+      case $cc_basename in
+      icc* | ecc*)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      pgcc* | pgf77* | pgf90* | pgf95*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+       # which looks to be a dead project)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      esac
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    sco3.2v5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn'
+      ;;
+
+    solaris*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95*)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    unicos*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works],
+    _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1),
+    [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+])
+
+
+# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME])
+# ------------------------------------
+# See if the linker supports building shared libraries.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
+[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ifelse([$1],[CXX],[
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  case $host_os in
+  aix4* | aix5*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+  ;;
+  cygwin* | mingw*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  *)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  esac
+],[
+  runpath_var=
+  _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+  _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_AC_TAGVAR(archive_cmds, $1)=
+  _LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+  _LT_AC_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+  _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+  _LT_AC_TAGVAR(module_cmds, $1)=
+  _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(always_export_symbols, $1)=no
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_AC_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_"
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  extract_expsyms_cmds=
+  # Just being paranoid about ensuring that cc_basename is set.
+  _LT_CC_BASENAME([$compiler])
+  case $host_os in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      else
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>/dev/null` in
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+      fi
+      ;;
+
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+
+      # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we can't use
+      # them.
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+       # support --undefined.  This deserves some investigation.  FIXME
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=no
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+       # If the export-symbols file already is a .def file (1st line
+       # is EXPORTS), use it as is; otherwise, prepend...
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+         cp $export_symbols $output_objdir/$soname.def;
+       else
+         echo EXPORTS > $output_objdir/$soname.def;
+         cat $export_symbols >> $output_objdir/$soname.def;
+       fi~
+       $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000  ${wl}--out-implib,$lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    linux*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       tmp_addflag=
+       case $cc_basename,$host_cpu in
+       pgcc*)                          # Portland Group C compiler
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag'
+         ;;
+       pgf77* | pgf90* | pgf95*)       # Portland Group f77 and f90 compilers
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag -Mnomain' ;;
+       ecc*,ia64* | icc*,ia64*)                # Intel C compiler on ia64
+         tmp_addflag=' -i_dynamic' ;;
+       efc*,ia64* | ifort*,ia64*)      # Intel Fortran compiler on ia64
+         tmp_addflag=' -i_dynamic -nofor_main' ;;
+       ifc* | ifort*)                  # Intel Fortran compiler
+         tmp_addflag=' -nofor_main' ;;
+       esac
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+       if test $supports_anon_versioning = yes; then
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+  cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+  $echo "local: *; };" >> $output_objdir/$libname.ver~
+         $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+       fi
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+       wlarc=
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris* | sysv5*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sunos4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$link_static_flag"; then
+       # Neither direct hardcoding nor static linking is supported with a
+       # broken collect2.
+       _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+       # On IA64, the linker does run time linking by default, so we don't
+       # have to do anything special.
+       aix_use_runtimelinking=no
+       exp_sym_flag='-Bexport'
+       no_entry_flag=""
+      else
+       # If we're using GNU nm, then we don't want the "-C" option.
+       # -C means demangle to AIX nm, but means don't demangle with GNU nm
+       if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+         _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+       else
+         _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+       fi
+       aix_use_runtimelinking=no
+
+       # Test if we are trying to use run time linking or normal
+       # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+       # need to do runtime linking.
+       case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+         for ld_flag in $LDFLAGS; do
+         if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+           aix_use_runtimelinking=yes
+           break
+         fi
+         done
+       esac
+
+       exp_sym_flag='-bexport'
+       no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_AC_TAGVAR(archive_cmds, $1)=''
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+      if test "$GCC" = yes; then
+       case $host_os in aix4.[[012]]|aix4.[[012]].*)
+       # We only want to do this on AIX 4.2 and lower, the check
+       # below for broken collect2 doesn't work under 4.3+
+         collect2name=`${CC} -print-prog-name=collect2`
+         if test -f "$collect2name" && \
+          strings "$collect2name" | grep resolve_lib_name >/dev/null
+         then
+         # We have reworked collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+         else
+         # We have old collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+         # It fails to find uninstalled libraries when the uninstalled
+         # path is not listed in the libpath.  Setting hardcode_minus_L
+         # to unsupported forces relinking
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+         fi
+       esac
+       shared_flag='-shared'
+       if test "$aix_use_runtimelinking" = yes; then
+         shared_flag="$shared_flag "'${wl}-G'
+       fi
+      else
+       # not using gcc
+       if test "$host_cpu" = ia64; then
+       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+       # chokes on -Wl,-G. The following line is correct:
+         shared_flag='-G'
+       else
+       if test "$aix_use_runtimelinking" = yes; then
+           shared_flag='${wl}-G'
+         else
+           shared_flag='${wl}-bM:SRE'
+       fi
+       fi
+      fi
+
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+       # Warning - without using the other runtime loading flags (-brtl),
+       # -berok will link without error, but may produce a broken library.
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+       # Determine the default libpath from the value encoded in an empty executable.
+       _LT_AC_SYS_LIBPATH_AIX
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+       else
+       if test "$host_cpu" = ia64; then
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+       else
+        # Determine the default libpath from the value encoded in an empty executable.
+        _LT_AC_SYS_LIBPATH_AIX
+        _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+         # Warning - without using the other run time loading flags,
+         # -berok will link without error, but may produce a broken library.
+         _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+         # -bexpall does not export symbols beginning with underscore (_)
+         _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+         # Exported symbols can be pulled into shared objects from archives
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+         # This is similar to how AIX traditionally builds its shared libraries.
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+       fi
+      fi
+      ;;
+
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      # see comment about different semantics on the GNU ld section
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    bsdi[[45]]*)
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
+      # FIXME: Should let the user specify the lib program.
+      _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs'
+      _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    darwin* | rhapsody*)
+      case $host_os in
+        rhapsody* | darwin1.[[012]])
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+         ;;
+       *) # Darwin 1.3 on
+         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+         else
+           case ${MACOSX_DEPLOYMENT_TARGET} in
+             10.[[012]])
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+               ;;
+             10.*)
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+               ;;
+           esac
+         fi
+         ;;
+      esac
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+    if test "$GCC" = yes ; then
+       output_verbose_link_cmd='echo'
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    else
+      case $cc_basename in
+        xlc*)
+         output_verbose_link_cmd='echo'
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+         _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          ;;
+       *)
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+          ;;
+      esac
+    fi
+      ;;
+
+    dgux*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    freebsd1*)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | kfreebsd*-gnu | dragonfly*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10* | hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+       case $host_cpu in
+       hppa*64*|ia64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       esac
+      else
+       case $host_cpu in
+       hppa*64*|ia64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+         ;;
+       esac
+      fi
+      if test "$with_gnu_ld" = no; then
+       case $host_cpu in
+       hppa*64*)
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no
+         _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+         ;;
+       ia64*)
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no
+         _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+
+         # hardcode_minus_L: Not really in the search PATH,
+         # but as the default location of the library.
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         ;;
+       *)
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+         _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+         # hardcode_minus_L: Not really in the search PATH,
+         # but as the default location of the library.
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         ;;
+       esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    openbsd*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      else
+       case $host_os in
+        openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+          _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+          _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+          ;;
+        *)
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+          _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+          ;;
+       esac
+      fi
+      ;;
+
+    os2*)
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)     # as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+       $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
+
+       # Both c and cxx compiler support -rpath directly
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    sco3.2v5*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var=LD_RUN_PATH
+      hardcode_runpath_var=yes
+      ;;
+
+    solaris*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+      if test "x$archive_cmds" = "x"; then
+        if test "$GCC" = yes; then
+         wlarc='${wl}'
+         if $CC -v --help 2>/dev/null | grep -- -shared  > /dev/null 2> /dev/null; then
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+           _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+           $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+         else
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC ${wl}-G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+           _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+           $CC ${wl}-G ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+          fi
+        else
+         wlarc=''
+          _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+         $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+          _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+       fi
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+       # The compiler driver will combine linker options so we
+       # cannot just pass the convience library names through
+       # without $wl, iff we do not link with $LD.
+       # Luckily, gcc supports the same syntax we need for Sun Studio.
+       # Supported since Solaris 2.6 (maybe 2.5.1?)
+       case $wlarc in
+       '')
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
+       *)
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
+       esac ;;
+      esac
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+       # Use $CC to link under sequent, because it throws in some extra .o
+       # files that make .init and .fini sections work.
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+       sni)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+       ;;
+       siemens)
+         ## LD is ld it makes a PLAMLIB
+         ## CC just makes a GrossModule.
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no
+        ;;
+       motorola)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+       ;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+       runpath_var=LD_RUN_PATH
+       hardcode_runpath_var=yes
+       _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4.2uw2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      hardcode_runpath_var=yes
+      runpath_var=LD_RUN_PATH
+      ;;
+
+   sysv5OpenUNIX8* | sysv5UnixWare7* |  sysv5uw[[78]]* | unixware7*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text'
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      runpath_var='LD_RUN_PATH'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv5*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+      # $CC -shared without GNU ld will not create a library from C++
+      # object files and a static libstdc++, better avoid it by now
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+      ;;
+
+    uts4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+  fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_AC_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+      $rm conftest*
+      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1)
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+        if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
+        then
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+        else
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+        fi
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $rm conftest*
+      AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)])
+      ;;
+    esac
+  fi
+  ;;
+esac
+])# AC_LIBTOOL_PROG_LD_SHLIBS
+
+
+# _LT_AC_FILE_LTDLL_C
+# -------------------
+# Be careful that the start marker always follows a newline.
+AC_DEFUN([_LT_AC_FILE_LTDLL_C], [
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# #  ifdef __CYGWIN32__
+# #    define __CYGWIN__ __CYGWIN32__
+# #  endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+#   __hDllInstance_base = hInst;
+#   return TRUE;
+# }
+# /* ltdll.c ends here */
+])# _LT_AC_FILE_LTDLL_C
+
+
+# _LT_AC_TAGVAR(VARNAME, [TAGNAME])
+# ---------------------------------
+AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])])
+
+
+# old names
+AC_DEFUN([AM_PROG_LIBTOOL],   [AC_PROG_LIBTOOL])
+AC_DEFUN([AM_ENABLE_SHARED],  [AC_ENABLE_SHARED($@)])
+AC_DEFUN([AM_ENABLE_STATIC],  [AC_ENABLE_STATIC($@)])
+AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+AC_DEFUN([AM_PROG_LD],        [AC_PROG_LD])
+AC_DEFUN([AM_PROG_NM],        [AC_PROG_NM])
+
+# This is just to silence aclocal about the macro not being used
+ifelse([AC_DISABLE_FAST_INSTALL])
+
+AC_DEFUN([LT_AC_PROG_GCJ],
+[AC_CHECK_TOOL(GCJ, gcj, no)
+  test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+  AC_SUBST(GCJFLAGS)
+])
+
+AC_DEFUN([LT_AC_PROG_RC],
+[AC_CHECK_TOOL(RC, windres, no)
+])
+
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+# LT_AC_PROG_SED
+# --------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+AC_DEFUN([LT_AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_MSG_RESULT([$SED])
+])
diff --git a/config/link-warning.h b/config/link-warning.h
new file mode 100644 (file)
index 0000000..fda0194
--- /dev/null
@@ -0,0 +1,28 @@
+/* GL_LINK_WARNING("literal string") arranges to emit the literal string as
+   a linker warning on most glibc systems.
+   We use a linker warning rather than a preprocessor warning, because
+   #warning cannot be used inside macros.  */
+#ifndef GL_LINK_WARNING
+  /* This works on platforms with GNU ld and ELF object format.
+     Testing __GLIBC__ is sufficient for asserting that GNU ld is in use.
+     Testing __ELF__ guarantees the ELF object format.
+     Testing __GNUC__ is necessary for the compound expression syntax.  */
+# if defined __GLIBC__ && defined __ELF__ && defined __GNUC__
+#  define GL_LINK_WARNING(message) \
+     GL_LINK_WARNING1 (__FILE__, __LINE__, message)
+#  define GL_LINK_WARNING1(file, line, message) \
+     GL_LINK_WARNING2 (file, line, message)  /* macroexpand file and line */
+#  define GL_LINK_WARNING2(file, line, message) \
+     GL_LINK_WARNING3 (file ":" #line ": warning: " message)
+#  define GL_LINK_WARNING3(message) \
+     ({ static const char warning[sizeof (message)]            \
+          __attribute__ ((__unused__,                          \
+                          __section__ (".gnu.warning"),                \
+                          __aligned__ (1)))                    \
+          = message "\n";                                      \
+        (void)0;                                               \
+     })
+# else
+#  define GL_LINK_WARNING(message) ((void) 0)
+# endif
+#endif
diff --git a/config/macro-archive/ac_define_dir.m4 b/config/macro-archive/ac_define_dir.m4
new file mode 100644 (file)
index 0000000..f3d8734
--- /dev/null
@@ -0,0 +1,47 @@
+##### http://autoconf-archive.cryp.to/ac_define_dir.html
+#
+# SYNOPSIS
+#
+#   AC_DEFINE_DIR(VARNAME, DIR [, DESCRIPTION])
+#
+# DESCRIPTION
+#
+#   This macro sets VARNAME to the expansion of the DIR variable,
+#   taking care of fixing up ${prefix} and such.
+#
+#   VARNAME is then offered as both an output variable and a C
+#   preprocessor symbol.
+#
+#   Example:
+#
+#      AC_DEFINE_DIR([DATADIR], [datadir], [Where data are placed to.])
+#
+# LAST MODIFICATION
+#
+#   2006-10-13
+#
+# COPYLEFT
+#
+#   Copyright (c) 2006 Stepan Kasal <kasal@ucw.cz>
+#   Copyright (c) 2006 Andreas Schwab <schwab@suse.de>
+#   Copyright (c) 2006 Guido U. Draheim <guidod@gmx.de>
+#   Copyright (c) 2006 Alexandre Oliva
+#
+#   Copying and distribution of this file, with or without
+#   modification, are permitted in any medium without royalty provided
+#   the copyright notice and this notice are preserved.
+
+AC_DEFUN([AC_DEFINE_DIR], [
+  prefix_NONE=
+  exec_prefix_NONE=
+  test "x$prefix" = xNONE && prefix_NONE=yes && prefix=$ac_default_prefix
+  test "x$exec_prefix" = xNONE && exec_prefix_NONE=yes && exec_prefix=$prefix
+dnl In Autoconf 2.60, ${datadir} refers to ${datarootdir}, which in turn
+dnl refers to ${prefix}.  Thus we have to use `eval' twice.
+  eval ac_define_dir="\"[$]$2\""
+  eval ac_define_dir="\"$ac_define_dir\""
+  AC_SUBST($1, "$ac_define_dir")
+  AC_DEFINE_UNQUOTED($1, "$ac_define_dir", [$3])
+  test "$prefix_NONE" && prefix=NONE
+  test "$exec_prefix_NONE" && exec_prefix=NONE
+])
diff --git a/config/macro-archive/ac_prog_perl_version.m4 b/config/macro-archive/ac_prog_perl_version.m4
new file mode 100644 (file)
index 0000000..886765d
--- /dev/null
@@ -0,0 +1,59 @@
+##### http://autoconf-archive.cryp.to/ac_prog_perl_version.html
+#
+# SYNOPSIS
+#
+#   AC_PROG_PERL_VERSION(VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+#   Makes sure that perl supports the version indicated. If true the
+#   shell commands in ACTION-IF-TRUE are executed. If not the shell
+#   commands in ACTION-IF-FALSE are run. Note if $PERL is not set (for
+#   example by running AC_CHECK_PROG or AC_PATH_PROG),
+#   AC_CHECK_PROG(PERL, perl, perl) will be run.
+#
+#   Example:
+#
+#     AC_PROG_PERL_VERSION(5.6.0)
+#
+#   This will check to make sure that the perl you have supports at
+#   least version 5.6.0.
+#
+# LAST MODIFICATION
+#
+#   2002-09-25
+#
+# COPYLEFT
+#
+#   Copyright (c) 2002 Dean Povey <povey@wedgetail.com>
+#
+#   Copying and distribution of this file, with or without
+#   modification, are permitted in any medium without royalty provided
+#   the copyright notice and this notice are preserved.
+
+AC_DEFUN([AC_PROG_PERL_VERSION],[dnl
+# Make sure we have perl
+if test -z "$PERL"; then
+AC_CHECK_PROG(PERL,perl,perl)
+fi
+
+# Check if version of Perl is sufficient
+ac_perl_version="$1"
+
+if test "x$PERL" != "x"; then
+  AC_MSG_CHECKING(for perl version greater than or equal to $ac_perl_version)
+  # NB: It would be nice to log the error if there is one, but we cannot rely
+  # on autoconf internals
+  $PERL -e "use $ac_perl_version;" > /dev/null 2>&1
+  if test $? -ne 0; then
+    AC_MSG_RESULT(no);
+    $3
+  else
+    AC_MSG_RESULT(ok);
+    $2
+  fi
+else
+  AC_MSG_WARN(could not find perl)
+fi
+])dnl
+
diff --git a/config/macro-archive/ac_prog_swig.m4 b/config/macro-archive/ac_prog_swig.m4
new file mode 100644 (file)
index 0000000..20520b2
--- /dev/null
@@ -0,0 +1,124 @@
+# Modified by Dustin J. Mitchell, Zmanda, Inc. as follows:
+#  - remove warnings -- Amanda tarballs ship pre-swigged, so users
+#    need not be alarmed if they don't have SWIG.
+#
+##### http://autoconf-archive.cryp.to/ac_pkg_swig.html
+#
+# SYNOPSIS
+#
+#   AC_PROG_SWIG([major.minor.micro])
+#
+# DESCRIPTION
+#
+#   This macro searches for a SWIG installation on your system. If
+#   found you should call SWIG via $(SWIG). You can use the optional
+#   first argument to check if the version of the available SWIG is
+#   greater than or equal to the value of the argument. It should have
+#   the format: N[.N[.N]] (N is a number between 0 and 999. Only the
+#   first N is mandatory.)
+#
+#   If the version argument is given (e.g. 1.3.17), AC_PROG_SWIG checks
+#   that the swig package is this version number or higher.
+#
+#   In configure.in, use as:
+#
+#     AC_PROG_SWIG(1.3.17)
+#     SWIG_ENABLE_CXX
+#     SWIG_MULTI_MODULE_SUPPORT
+#     SWIG_PYTHON
+#
+# LAST MODIFICATION
+#
+#   2006-10-22
+#
+# COPYLEFT
+#
+#   Copyright (c) 2006 Sebastian Huber <sebastian-huber@web.de>
+#   Copyright (c) 2006 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
+#   Copyright (c) 2006 Rafael Laboissiere <rafael@laboissiere.net>
+#   Copyright (c) 2006 Andrew Collier <colliera@ukzn.ac.za>
+#
+#   This program is free software; you can redistribute it and/or
+#   modify it under the terms of the GNU General Public License as
+#   published by the Free Software Foundation; either version 2 of the
+#   License, or (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+#   General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+#   02111-1307, USA.
+#
+#   As a special exception, the respective Autoconf Macro's copyright
+#   owner gives unlimited permission to copy, distribute and modify the
+#   configure scripts that are the output of Autoconf when processing
+#   the Macro. You need not follow the terms of the GNU General Public
+#   License when using or distributing such scripts, even though
+#   portions of the text of the Macro appear in them. The GNU General
+#   Public License (GPL) does govern all other use of the material that
+#   constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the
+#   Autoconf Macro released by the Autoconf Macro Archive. When you
+#   make and distribute a modified version of the Autoconf Macro, you
+#   may extend this special exception to the GPL to apply to your
+#   modified version as well.
+
+AC_DEFUN([AC_PROG_SWIG],[
+        AC_PATH_PROG([SWIG],[swig])
+        if test -z "$SWIG" ; then
+                SWIG='echo "Error: SWIG is not installed. You should look at http://www.swig.org" ; false'
+        elif test -n "$1" ; then
+                AC_MSG_CHECKING([for SWIG version])
+                [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
+                AC_MSG_RESULT([$swig_version])
+                if test -n "$swig_version" ; then
+                        # Calculate the required version number components
+                        [required=$1]
+                        [required_major=`echo $required | sed 's/[^0-9].*//'`]
+                        if test -z "$required_major" ; then
+                                [required_major=0]
+                        fi
+                        [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
+                        [required_minor=`echo $required | sed 's/[^0-9].*//'`]
+                        if test -z "$required_minor" ; then
+                                [required_minor=0]
+                        fi
+                        [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
+                        [required_patch=`echo $required | sed 's/[^0-9].*//'`]
+                        if test -z "$required_patch" ; then
+                                [required_patch=0]
+                        fi
+                        # Calculate the available version number components
+                        [available=$swig_version]
+                        [available_major=`echo $available | sed 's/[^0-9].*//'`]
+                        if test -z "$available_major" ; then
+                                [available_major=0]
+                        fi
+                        [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+                        [available_minor=`echo $available | sed 's/[^0-9].*//'`]
+                        if test -z "$available_minor" ; then
+                                [available_minor=0]
+                        fi
+                        [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+                        [available_patch=`echo $available | sed 's/[^0-9].*//'`]
+                        if test -z "$available_patch" ; then
+                                [available_patch=0]
+                        fi
+                        if test $available_major -ne $required_major \
+                                -o $available_minor -ne $required_minor \
+                                -o $available_patch -lt $required_patch ; then
+                                SWIG='echo "Error: SWIG version >= $1 is required.  You have '"$swig_version"'.  You should look at http://www.swig.org" ; false'
+                        else
+                                SWIG_LIB=`$SWIG -swiglib`
+                        fi
+                else
+                        SWIG='echo "Error: Cannot determine SWIG version.  You should look at http://www.swig.org" ; false'
+                fi
+        fi
+        AC_SUBST([SWIG_LIB])
+])
diff --git a/config/macro-archive/ax_compare_version.m4 b/config/macro-archive/ax_compare_version.m4
new file mode 100644 (file)
index 0000000..a7581b4
--- /dev/null
@@ -0,0 +1,201 @@
+##### http://autoconf-archive.cryp.to/ax_compare_version.html
+#
+# SYNOPSIS
+#
+#   AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+#   This macro compares two version strings. It is used heavily in the
+#   macro _AX_PATH_BDB for library checking. Due to the various number
+#   of minor-version numbers that can exist, and the fact that string
+#   comparisons are not compatible with numeric comparisons, this is
+#   not necessarily trivial to do in a autoconf script. This macro
+#   makes doing these comparisons easy.
+#
+#   The six basic comparisons are available, as well as checking
+#   equality limited to a certain number of minor-version levels.
+#
+#   The operator OP determines what type of comparison to do, and can
+#   be one of:
+#
+#    eq  - equal (test A == B)
+#    ne  - not equal (test A != B)
+#    le  - less than or equal (test A <= B)
+#    ge  - greater than or equal (test A >= B)
+#    lt  - less than (test A < B)
+#    gt  - greater than (test A > B)
+#
+#   Additionally, the eq and ne operator can have a number after it to
+#   limit the test to that number of minor versions.
+#
+#    eq0 - equal up to the length of the shorter version
+#    ne0 - not equal up to the length of the shorter version
+#    eqN - equal up to N sub-version levels
+#    neN - not equal up to N sub-version levels
+#
+#   When the condition is true, shell commands ACTION-IF-TRUE are run,
+#   otherwise shell commands ACTION-IF-FALSE are run. The environment
+#   variable 'ax_compare_version' is always set to either 'true' or
+#   'false' as well.
+#
+#   Examples:
+#
+#     AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8])
+#     AX_COMPARE_VERSION([3.15],[lt],[3.15.8])
+#
+#   would both be true.
+#
+#     AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8])
+#     AX_COMPARE_VERSION([3.15],[gt],[3.15.8])
+#
+#   would both be false.
+#
+#     AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8])
+#
+#   would be true because it is only comparing two minor versions.
+#
+#     AX_COMPARE_VERSION([3.15.7],[eq0],[3.15])
+#
+#   would be true because it is only comparing the lesser number of
+#   minor versions of the two values.
+#
+#   Note: The characters that separate the version numbers do not
+#   matter. An empty string is the same as version 0. OP is evaluated
+#   by autoconf, not configure, so must be a string, not a variable.
+#
+#   The author would like to acknowledge Guido Draheim whose advice
+#   about the m4_case and m4_ifvaln functions make this macro only
+#   include the portions necessary to perform the specific comparison
+#   specified by the OP argument in the final configure script.
+#
+# LAST MODIFICATION
+#
+#   2004-03-01
+#
+# COPYLEFT
+#
+#   Copyright (c) 2004 Tim Toolan <toolan@ele.uri.edu>
+#
+#   This program is free software; you can redistribute it and/or
+#   modify it under the terms of the GNU General Public License as
+#   published by the Free Software Foundation; either version 2 of the
+#   License, or (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+#   General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+#   02111-1307, USA.
+#
+#   As a special exception, the respective Autoconf Macro's copyright
+#   owner gives unlimited permission to copy, distribute and modify the
+#   configure scripts that are the output of Autoconf when processing
+#   the Macro. You need not follow the terms of the GNU General Public
+#   License when using or distributing such scripts, even though
+#   portions of the text of the Macro appear in them. The GNU General
+#   Public License (GPL) does govern all other use of the material that
+#   constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the
+#   Autoconf Macro released by the Autoconf Macro Archive. When you
+#   make and distribute a modified version of the Autoconf Macro, you
+#   may extend this special exception to the GPL to apply to your
+#   modified version as well.
+
+dnl #########################################################################
+AC_DEFUN([AX_COMPARE_VERSION], [
+  # Used to indicate true or false condition
+  ax_compare_version=false
+
+  # Convert the two version strings to be compared into a format that
+  # allows a simple string comparison.  The end result is that a version
+  # string of the form 1.12.5-r617 will be converted to the form
+  # 0001001200050617.  In other words, each number is zero padded to four
+  # digits, and non digits are removed.
+  AS_VAR_PUSHDEF([A],[ax_compare_version_A])
+  A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+                     -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/[[^0-9]]//g'`
+
+  AS_VAR_PUSHDEF([B],[ax_compare_version_B])
+  B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+                     -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/[[^0-9]]//g'`
+
+  dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary
+  dnl # then the first line is used to determine if the condition is true.
+  dnl # The sed right after the echo is to remove any indented white space.
+  m4_case(m4_tolower($2),
+  [lt],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+  ],
+  [gt],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+  ],
+  [le],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+  ],
+  [ge],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+  ],[
+    dnl Split the operator from the subversion count if present.
+    m4_bmatch(m4_substr($2,2),
+    [0],[
+      # A count of zero means use the length of the shorter version.
+      # Determine the number of characters in A and B.
+      ax_compare_version_len_A=`echo "$A" | awk '{print(length)}'`
+      ax_compare_version_len_B=`echo "$B" | awk '{print(length)}'`
+
+      # Set A to no more than B's length and B to no more than A's length.
+      A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
+      B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
+    ],
+    [[0-9]+],[
+      # A count greater than zero means use only that many subversions
+      A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+      B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+    ],
+    [.+],[
+      AC_WARNING(
+        [illegal OP numeric parameter: $2])
+    ],[])
+
+    # Pad zeros at end of numbers to make same length.
+    ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`"
+    B="$B`echo $A | sed 's/./0/g'`"
+    A="$ax_compare_version_tmp_A"
+
+    # Check for equality or inequality as necessary.
+    m4_case(m4_tolower(m4_substr($2,0,2)),
+    [eq],[
+      test "x$A" = "x$B" && ax_compare_version=true
+    ],
+    [ne],[
+      test "x$A" != "x$B" && ax_compare_version=true
+    ],[
+      AC_WARNING([illegal OP parameter: $2])
+    ])
+  ])
+
+  AS_VAR_POPDEF([A])dnl
+  AS_VAR_POPDEF([B])dnl
+
+  dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE.
+  if test "$ax_compare_version" = "true" ; then
+    m4_ifvaln([$4],[$4],[:])dnl
+    m4_ifvaln([$5],[else $5])dnl
+  fi
+]) dnl AX_COMPARE_VERSION
diff --git a/config/macro-archive/docbook-dtd.m4 b/config/macro-archive/docbook-dtd.m4
new file mode 100644 (file)
index 0000000..935b169
--- /dev/null
@@ -0,0 +1,112 @@
+##### http://autoconf-archive.cryp.to/ac_check_docbook_dtd.html
+#
+# SYNOPSIS
+#
+#   AC_CHECK_DOCBOOK_DTD([dtd-version])
+#
+# DESCRIPTION
+#
+#   Check for access to a docbook DTD of a particular revision.
+#
+#   This macro can be used for multiple versions within the same script.
+#
+#   Input:
+#    $1 is the version of docbook to search for; default 'current'
+#   Output:
+#    $HAVE_DOCBOOK_DTD_VERS will be set to 'yes' or 'no' depending
+#    on the results of the test, where VERS is $1, with '_' substituted
+#    for '.'  $HAVE_DOCBOOK_DTD will also be set to the same value.
+#
+#   Example:
+#    AC_CHECK_DOCBOOK_DTD(4.3)
+#    if test "x$HAVE_DOCBOOK_DTD_4_3" = "xyes"; then
+#      ..
+#
+# LAST MODIFICATION
+#
+#   2007-06-28
+#
+# AUTHOR
+#
+#   Dustin J. Mitchell <dustin@zmanda.com>
+#
+# COPYRIGHT
+#
+#   Copyright (c) 2007 Zmanda Inc.  All Rights Reserved.
+#  
+#   This program is free software; you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License version 2 as published
+#   by the Free Software Foundation.
+#  
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#   for more details.
+#  
+#   You should have received a copy of the GNU General Public License along
+#   with this program; if not, write to the Free Software Foundation, Inc.,
+#   59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#   This special exception to the GPL applies to versions of the
+#   Autoconf Macro released by the Autoconf Macro Archive. When you
+#   make and distribute a modified version of the Autoconf Macro, you
+#   may extend this special exception to the GPL to apply to your
+#   modified version as well.
+#
+#   Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+#   Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+AC_DEFUN([AC_CHECK_DOCBOOK_DTD],
+[
+    AC_REQUIRE([AC_PROG_XSLTPROC])
+
+    dnl define a temporary variable for the version, so this macro can be
+    dnl used with multiple versions
+    define([_VERS], $1)
+    ifelse(_VERS, [], [define([_VERS], [current])])
+
+    dnl define variable names ending in _VERS which will actually have the
+    dnl version number as a suffix
+    define([ac_cv_docbook_dtd_VERS], patsubst([ac_cv_docbook_dtd_]_VERS, [\.], [_]))
+    define([HAVE_DOCBOOK_DTD_VERS], patsubst([HAVE_DOCBOOK_DTD_]_VERS, [\.], [_]))
+
+    AC_CACHE_CHECK([for Docbook DTD version ]_VERS, [ac_cv_docbook_dtd_VERS],
+    [
+       ac_cv_docbook_dtd_VERS=no
+       if test -n "$XSLTPROC"; then
+           MY_XSLTPROC_FLAGS=`echo "" $XSLTPROC_FLAGS|sed -e s/--novalid//g`
+           cat <<EOF >conftest.xml
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V[]_VERS//EN" "http://www.oasis-open.org/docbook/xml/_VERS/docbookx.dtd">
+<book id="empty">
+</book>
+EOF
+           echo "Trying '$XSLTPROC $MY_XSLTPROC_FLAGS conftest.xml'" >&AS_MESSAGE_LOG_FD
+           echo "conftest.xml:" >&AS_MESSAGE_LOG_FD
+           echo "====" >&AS_MESSAGE_LOG_FD
+           cat conftest.xml >&AS_MESSAGE_LOG_FD
+           echo "====" >&AS_MESSAGE_LOG_FD
+
+           $XSLTPROC $MY_XSLTPROC_FLAGS conftest.xml >conftest.out 2>&1
+           if test "$?" = 0 -o "$?" = 5; then
+               # failing to load the DTD is just a warning, so check for it in the output.
+               if grep 'warning: failed to load external entity' conftest.out >/dev/null 2>&1; then
+                   : # no good..
+               else
+                   ac_cv_docbook_dtd_VERS=yes
+               fi
+           fi
+           cat conftest.out >&AS_MESSAGE_LOG_FD
+
+           rm -f conftest.xml conftest.out
+       fi
+    ])
+
+    HAVE_DOCBOOK_DTD_VERS="$ac_cv_docbook_dtd_VERS"
+    HAVE_DOCBOOK_DTD="$HAVE_DOCBOOK_DTD_VERS"
+
+    dnl clean up m4 namespace
+    undefine([_VERS])
+    undefine([ac_cv_docbook_dtd_VERS])
+    undefine([HAVE_DOCBOOK_DTD_VERS])
+])
diff --git a/config/macro-archive/docbook-xslt-min.m4 b/config/macro-archive/docbook-xslt-min.m4
new file mode 100644 (file)
index 0000000..e92c848
--- /dev/null
@@ -0,0 +1,108 @@
+##### http://autoconf-archive.cryp.to/ac_check_docbook_xslt_min.html
+#
+# SYNOPSIS
+#
+#   AC_CHECK_DOCBOOK_XSLT_MIN(min-xslt-version)
+#
+# DESCRIPTION
+#
+#   Check that the 'current' version of docbook is at least version 
+#   min-xslt-version.
+#
+#   If the test is successful, $DOCBOOK_XSLT_CURRENT_VERSION will be set to the
+#   current docbook version; if not, it will be set to 'no'.
+#
+#   Example:
+#    AC_CHECK_DOCBOOK_XSLT_MIN(1.72.0)
+#    if test "x$DOCBOOK_XSLT_CURRENT_VERSION" = "xno"; then
+#      ..
+#
+# LAST MODIFICATION
+#
+#   2007-06-28
+#
+# AUTHOR
+#
+#   Dustin J. Mitchell <dustin@zmanda.com>
+#
+# COPYRIGHT
+#
+#   Copyright (c) 2007 Zmanda Inc.  All Rights Reserved.
+#  
+#   This program is free software; you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License version 2 as published
+#   by the Free Software Foundation.
+#  
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#   for more details.
+#  
+#   You should have received a copy of the GNU General Public License along
+#   with this program; if not, write to the Free Software Foundation, Inc.,
+#   59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#   This special exception to the GPL applies to versions of the
+#   Autoconf Macro released by the Autoconf Macro Archive. When you
+#   make and distribute a modified version of the Autoconf Macro, you
+#   may extend this special exception to the GPL to apply to your
+#   modified version as well.
+#
+#   Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+#   Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+AC_DEFUN([AC_CHECK_DOCBOOK_XSLT_MIN],
+[
+    AC_REQUIRE([AC_PROG_XSLTPROC])
+
+    AC_CACHE_CHECK([for current Docbook XSLT version], [ac_cv_docbook_xslt_current_version],
+    [
+       ac_cv_docbook_xslt_current_version=no
+
+       if test -n "$XSLTPROC"; then
+           cat >conftest.xsl <<EOF
+               <xsl:stylesheet
+                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                   xmlns:fm="http://freshmeat.net/projects/freshmeat-submit/"
+                   version="1.0">
+                   <xsl:output method="text"/>
+                   <xsl:template match="fm:project/fm:Version">
+                       <xsl:value-of select="." />
+                   </xsl:template>
+                   <!-- do nothing with any other text -->
+                   <xsl:template match="text()"/>
+               </xsl:stylesheet>
+EOF
+           echo "Trying '$XSLTPROC $XSLTPROC_FLAGS http://docbook.sourceforge.net/release/xsl/current/VERSION' with input:" >&AS_MESSAGE_LOG_FD
+           echo "====" >&AS_MESSAGE_LOG_FD
+           cat conftest.xsl >&AS_MESSAGE_LOG_FD
+           echo "====" >&AS_MESSAGE_LOG_FD
+
+           ac_cv_docbook_xslt_current_version=`$XSLTPROC $XSLTPROC_FLAGS conftest.xsl http://docbook.sourceforge.net/release/xsl/current/VERSION 2>&AS_MESSAGE_LOG_FD`
+
+           if test "$?" != 0; then
+               ac_cv_docbook_xslt_current_version='no'
+           fi
+
+           rm conftest.xsl
+       fi
+    ])
+
+    DOCBOOK_XSLT_CURRENT_VERSION="$ac_cv_docbook_xslt_current_version"
+    AC_MSG_CHECKING([whether Docbook XSLT version is $1 or newer])
+
+    if test x"$DOCBOOK_XSLT_CURRENT_VERSION" = x"no"; then
+       AC_MSG_RESULT([no])
+    else
+       AX_COMPARE_VERSION([$DOCBOOK_XSLT_CURRENT_VERSION], [lt], [$1], [
+           # version is less than required, so mark it as "no"
+           DOCBOOK_XSLT_CURRENT_VERSION=no
+       ])
+
+       if test x"$DOCBOOK_XSLT_CURRENT_VERSION" = x"no"; then
+           AC_MSG_RESULT([no])
+       else
+           AC_MSG_RESULT([yes ($DOCBOOK_XSLT_CURRENT_VERSION)])
+       fi
+    fi
+])
diff --git a/config/macro-archive/docbook-xslt.m4 b/config/macro-archive/docbook-xslt.m4
new file mode 100644 (file)
index 0000000..ab4b6ce
--- /dev/null
@@ -0,0 +1,93 @@
+##### http://autoconf-archive.cryp.to/ac_check_docbook_xslt.html
+#
+# SYNOPSIS
+#
+#   AC_CHECK_DOCBOOK_XSLT([xslt-version])
+#
+# DESCRIPTION
+#
+#   Check for access to docbook stylesheets of a particular revision.
+#
+#   This macro can be used for multiple versions within the same script.
+#
+#   Input:
+#    $1 is the version of docbook to search for; default 'current'
+#   Output:
+#    $HAVE_DOCBOOK_XSLT_VERS will be set to 'yes' or 'no' depending
+#    on the results of the test, where VERS is $1, with '_' substituted
+#    for '.'  $HAVE_DOCBOOK_XSLT will also be set to the same value.
+#
+#   Example:
+#    AC_CHECK_DOCBOOK_XSLT(1.72.0)
+#    if test "x$HAVE_DOCBOOK_XSLT_1_72_0" = "xyes"; then
+#      ..
+#
+# LAST MODIFICATION
+#
+#   2007-06-28
+#
+# AUTHOR
+#
+#   Dustin J. Mitchell <dustin@zmanda.com>
+#
+# COPYRIGHT
+#
+#   Copyright (c) 2007 Zmanda Inc.  All Rights Reserved.
+#  
+#   This program is free software; you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License version 2 as published
+#   by the Free Software Foundation.
+#  
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#   for more details.
+#  
+#   You should have received a copy of the GNU General Public License along
+#   with this program; if not, write to the Free Software Foundation, Inc.,
+#   59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#   This special exception to the GPL applies to versions of the
+#   Autoconf Macro released by the Autoconf Macro Archive. When you
+#   make and distribute a modified version of the Autoconf Macro, you
+#   may extend this special exception to the GPL to apply to your
+#   modified version as well.
+#
+#   Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+#   Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+AC_DEFUN([AC_CHECK_DOCBOOK_XSLT],
+[
+    AC_REQUIRE([AC_PROG_XSLTPROC])
+
+    dnl define a temporary variable for the version, so this macro can be
+    dnl used with multiple versions
+    define([_VERS], $1)
+    ifelse(_VERS, [], [define([_VERS], [current])])
+
+    dnl define variable names ending in _VERS which will actually have the
+    dnl version number as a suffix
+    define([ac_cv_docbook_xslt_VERS], patsubst([ac_cv_docbook_xslt_]_VERS, [\.], [_]))
+    define([HAVE_DOCBOOK_XSLT_VERS], patsubst([HAVE_DOCBOOK_XSLT_]_VERS, [\.], [_]))
+
+    AC_CACHE_CHECK([for Docbook XSLT version ]_VERS, [ac_cv_docbook_xslt_VERS],
+    [
+       ac_cv_docbook_xslt_VERS=no
+       if test -n "$XSLTPROC"; then
+           echo "Trying '$XSLTPROC $XSLTPROC_FLAGS http://docbook.sourceforge.net/release/xsl/_VERS/xhtml/docbook.xsl'" >&AS_MESSAGE_LOG_FD
+           $XSLTPROC $XSLTPROC_FLAGS http://docbook.sourceforge.net/release/xsl/_VERS/xhtml/docbook.xsl >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+
+           if test "$?" = 0; then
+               ac_cv_docbook_xslt_VERS=yes
+           fi
+       fi
+    ])
+
+    HAVE_DOCBOOK_XSLT_VERS="$ac_cv_docbook_xslt_VERS"
+    HAVE_DOCBOOK_XSLT="$HAVE_DOCBOOK_XSLT_VERS"
+
+    dnl clean up m4 namespace
+    undefine([_VERS])
+    undefine([ac_cv_docbook_xslt_VERS])
+    undefine([HAVE_DOCBOOK_XSLT_VERS])
+])
diff --git a/config/macro-archive/file-list b/config/macro-archive/file-list
new file mode 100644 (file)
index 0000000..7773a1d
--- /dev/null
@@ -0,0 +1,9 @@
+## this file is automatically generated by autogen
+EXTRA_DIST += macro-archive/ac_define_dir.m4
+EXTRA_DIST += macro-archive/ac_prog_perl_version.m4
+EXTRA_DIST += macro-archive/ac_prog_swig.m4
+EXTRA_DIST += macro-archive/ax_compare_version.m4
+EXTRA_DIST += macro-archive/docbook-dtd.m4
+EXTRA_DIST += macro-archive/docbook-xslt.m4
+EXTRA_DIST += macro-archive/docbook-xslt-min.m4
+EXTRA_DIST += macro-archive/xsltproc.m4
diff --git a/config/macro-archive/xsltproc.m4 b/config/macro-archive/xsltproc.m4
new file mode 100644 (file)
index 0000000..b782967
--- /dev/null
@@ -0,0 +1,92 @@
+##### http://autoconf-archive.cryp.to/ac_prog_xsltproc.html
+#
+# SYNOPSIS
+#
+#   AC_PROG_XSLTPROC([default-flags])
+#
+# DESCRIPTION
+#
+#   Finds an xsltproc executable.
+#
+#   Input:
+#    default-flags is the default $XSLTPROC_FLAGS, which will be
+#    overridden if the user specifies --with-xsltproc-flags.
+#
+#   Output:
+#    $XSLTPROC contains the path to xsltproc, or is empty if none was
+#    found or the user specified --without-xsltproc. $XSLTPROC_FLAGS 
+#    contains the flags to use with xsltproc.
+#
+# LAST MODIFICATION
+#
+#   2007-04-17
+#
+# AUTHOR
+#
+#   Dustin J. Mitchell <dustin@zmanda.com>
+#
+# COPYRIGHT
+#
+#   Copyright (c) 2007 Zmanda Inc.  All Rights Reserved.
+#  
+#   This program is free software; you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License version 2 as published
+#   by the Free Software Foundation.
+#  
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#   for more details.
+#  
+#   You should have received a copy of the GNU General Public License along
+#   with this program; if not, write to the Free Software Foundation, Inc.,
+#   59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#   This special exception to the GPL applies to versions of the
+#   Autoconf Macro released by the Autoconf Macro Archive. When you
+#   make and distribute a modified version of the Autoconf Macro, you
+#   may extend this special exception to the GPL to apply to your
+#   modified version as well.
+#
+#   Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+#   Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+AC_DEFUN([AC_PROG_XSLTPROC],
+[
+XSLTPROC_FLAGS="$1"
+AC_SUBST(XSLTPROC_FLAGS)
+
+# The (lack of) whitespace and overquoting here are all necessary for
+# proper formatting.
+AC_ARG_WITH(xsltproc,
+AS_HELP_STRING([--with-xsltproc[[[[[=PATH]]]]]],
+               [Use the xsltproc binary in in PATH.]),
+    [ ac_with_xsltproc=$withval; ],
+    [ ac_with_xsltproc=maybe; ])
+
+AC_ARG_WITH(xsltproc-flags,
+AS_HELP_STRING([  --with-xsltproc-flags=FLAGS],
+               [Flags to pass to xsltproc (default $1)]),
+    [ if test "x$withval" == "xno"; then
+       XSLTPROC_FLAGS=''
+    else
+       if test "x$withval" != "xyes"; then
+           XSLTPROC_FLAGS="$withval"
+       fi
+    fi
+       ])
+
+# search for xsltproc if it wasn't specified
+if test "$ac_with_xsltproc" = "yes" -o "$ac_with_xsltproc" = "maybe"; then
+    AC_PATH_PROGS(XSLTPROC,xsltproc,,$LOCSYSPATH)
+else
+    if test "$ac_with_xsltproc" != "no"; then
+        if test -x "$ac_with_xsltproc"; then
+            XSLTPROC="$ac_with_xsltproc";
+        else
+            AMANDA_MSG_WARN([Specified xsltproc of $ac_with_xsltproc isn't executable; searching for an alternative.])
+            AC_PATH_PROGS(XSLTPROC,xsltproc,,$LOCSYSPATH)
+        fi
+    fi
+fi
+])
diff --git a/config/ylwrap b/config/ylwrap
new file mode 100755 (executable)
index 0000000..102bd89
--- /dev/null
@@ -0,0 +1,223 @@
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2005-05-14.22
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005
+#   Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case "$1" in
+  '')
+    echo "$0: No files given.  Try \`$0 --help' for more information." 1>&2
+    exit 1
+    ;;
+  --basedir)
+    basedir=$2
+    shift 2
+    ;;
+  -h|--h*)
+    cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+  INPUT is the input file
+  OUTPUT is one file PROG generates
+  DESIRED is the file we actually want instead of OUTPUT
+  PROGRAM is program to run
+  ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v|--v*)
+    echo "ylwrap $scriptversion"
+    exit $?
+    ;;
+esac
+
+
+# The input.
+input="$1"
+shift
+case "$input" in
+  [\\/]* | ?:[\\/]*)
+    # Absolute path; do nothing.
+    ;;
+  *)
+    # Relative path.  Make it absolute.
+    input="`pwd`/$input"
+    ;;
+esac
+
+pairlist=
+while test "$#" -ne 0; do
+  if test "$1" = "--"; then
+    shift
+    break
+  fi
+  pairlist="$pairlist $1"
+  shift
+done
+
+# The program to run.
+prog="$1"
+shift
+# Make any relative path in $prog absolute.
+case "$prog" in
+  [\\/]* | ?:[\\/]*) ;;
+  *[\\/]*) prog="`pwd`/$prog" ;;
+esac
+
+# FIXME: add hostname here for parallel makes that run commands on
+# other machines.  But that might take us over the 14-char limit.
+dirname=ylwrap$$
+trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+  0) $prog "$input" ;;
+  *) $prog "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+  set X $pairlist
+  shift
+  first=yes
+  # Since DOS filename conventions don't allow two dots,
+  # the DOS version of Bison writes out y_tab.c instead of y.tab.c
+  # and y_tab.h instead of y.tab.h. Test to see if this is the case.
+  y_tab_nodot="no"
+  if test -f y_tab.c || test -f y_tab.h; then
+    y_tab_nodot="yes"
+  fi
+
+  # The directory holding the input.
+  input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'`
+  # Quote $INPUT_DIR so we can use it in a regexp.
+  # FIXME: really we should care about more than `.' and `\'.
+  input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'`
+
+  while test "$#" -ne 0; do
+    from="$1"
+    # Handle y_tab.c and y_tab.h output by DOS
+    if test $y_tab_nodot = "yes"; then
+      if test $from = "y.tab.c"; then
+       from="y_tab.c"
+      else
+       if test $from = "y.tab.h"; then
+         from="y_tab.h"
+       fi
+      fi
+    fi
+    if test -f "$from"; then
+      # If $2 is an absolute path name, then just use that,
+      # otherwise prepend `../'.
+      case "$2" in
+       [\\/]* | ?:[\\/]*) target="$2";;
+       *) target="../$2";;
+      esac
+
+      # We do not want to overwrite a header file if it hasn't
+      # changed.  This avoid useless recompilations.  However the
+      # parser itself (the first file) should always be updated,
+      # because it is the destination of the .y.c rule in the
+      # Makefile.  Divert the output of all other files to a temporary
+      # file so we can compare them to existing versions.
+      if test $first = no; then
+       realtarget="$target"
+       target="tmp-`echo $target | sed s/.*[\\/]//g`"
+      fi
+      # Edit out `#line' or `#' directives.
+      #
+      # We don't want the resulting debug information to point at
+      # an absolute srcdir; it is better for it to just mention the
+      # .y file with no path.
+      #
+      # We want to use the real output file name, not yy.lex.c for
+      # instance.
+      #
+      # We want the include guards to be adjusted too.
+      FROM=`echo "$from" | sed \
+            -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+            -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+      TARGET=`echo "$2" | sed \
+            -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+            -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+
+      sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \
+          -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$?
+
+      # Check whether header files must be updated.
+      if test $first = no; then
+       if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+         echo "$2" is unchanged
+         rm -f "$target"
+       else
+          echo updating "$2"
+          mv -f "$target" "$realtarget"
+        fi
+      fi
+    else
+      # A missing file is only an error for the first file.  This
+      # is a blatant hack to let us support using "yacc -d".  If -d
+      # is not specified, we don't want an error when the header
+      # file is "missing".
+      if test $first = yes; then
+        ret=1
+      fi
+    fi
+    shift
+    shift
+    first=no
+  done
+else
+  ret=$?
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/device-src/Makefile.am b/device-src/Makefile.am
new file mode 100644 (file)
index 0000000..75177d7
--- /dev/null
@@ -0,0 +1,64 @@
+# Makefile for Amanda tape library.
+
+SUBDIRS = . tests
+
+include $(top_srcdir)/config/automake/precompile.am
+
+INCLUDES =     -I$(top_builddir)/common-src \
+               -I$(top_srcdir)/common-src \
+               -I$(top_srcdir)/gnulib
+
+AM_CFLAGS = $(AMANDA_WARNING_CFLAGS)
+AM_LDFLAGS = $(AMANDA_STATIC_LDFLAGS)
+
+sbin_PROGRAMS =
+
+## libamdevice.la
+
+amlib_LTLIBRARIES =    libamdevice.la
+libamdevice_la_LDFLAGS = -release $(VERSION) 
+libamdevice_la_SOURCES = property.c device.c queueing.c semaphore.c \
+       null-device.c rait-device.c vfs-device.c 
+libamdevice_la_LIBADD = ../common-src/libamanda.la
+
+# tape-device has *lots* of conditionals; the first is whether to support
+# the device at all, and the remainder select a particular kind of OS-specific
+# backend.
+
+if WANT_TAPE_DEVICE
+libamdevice_la_SOURCES += tape-device.c
+
+if WANT_TAPE_XENIX
+libamdevice_la_SOURCES += tape-xenix.c
+endif
+if WANT_TAPE_AIX
+libamdevice_la_SOURCES += tape-aix.c
+endif
+if WANT_TAPE_UWARE
+libamdevice_la_SOURCES += tape-uware.c
+endif
+if WANT_TAPE_POSIX
+libamdevice_la_SOURCES += tape-posix.c
+endif
+
+endif
+
+if WANT_S3_DEVICE
+libamdevice_la_SOURCES += s3-device.c s3.c
+endif
+
+## activate-devpay
+
+if WANT_DEVPAY
+sbin_PROGRAMS += activate-devpay
+activate_devpay_SOURCES = activate-devpay.c
+endif
+
+## headers
+
+noinst_HEADERS = null-device.h semaphore.h \
+       tape-ops.h property.h rait-device.h s3.h \
+       s3-device.h tape-device.h vfs-device.h \
+       device.h queueing.h
+       
+aminclude_HEADERS = 
diff --git a/device-src/Makefile.in b/device-src/Makefile.in
new file mode 100644 (file)
index 0000000..70898dd
--- /dev/null
@@ -0,0 +1,1122 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for Amanda tape library.
+
+# vim:ft=automake
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(aminclude_HEADERS) $(noinst_HEADERS) \
+       $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(top_srcdir)/config/automake/precompile.am
+sbin_PROGRAMS = $(am__EXEEXT_1)
+
+# tape-device has *lots* of conditionals; the first is whether to support
+# the device at all, and the remainder select a particular kind of OS-specific
+# backend.
+@WANT_TAPE_DEVICE_TRUE@am__append_1 = tape-device.c
+@WANT_TAPE_DEVICE_TRUE@@WANT_TAPE_XENIX_TRUE@am__append_2 = tape-xenix.c
+@WANT_TAPE_AIX_TRUE@@WANT_TAPE_DEVICE_TRUE@am__append_3 = tape-aix.c
+@WANT_TAPE_DEVICE_TRUE@@WANT_TAPE_UWARE_TRUE@am__append_4 = tape-uware.c
+@WANT_TAPE_DEVICE_TRUE@@WANT_TAPE_POSIX_TRUE@am__append_5 = tape-posix.c
+@WANT_S3_DEVICE_TRUE@am__append_6 = s3-device.c s3.c
+@WANT_DEVPAY_TRUE@am__append_7 = activate-devpay
+subdir = device-src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps =  \
+       $(top_srcdir)/config/macro-archive/ac_define_dir.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_perl_version.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_swig.m4 \
+       $(top_srcdir)/config/macro-archive/ax_compare_version.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-dtd.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt-min.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt.m4 \
+       $(top_srcdir)/config/macro-archive/xsltproc.m4 \
+       $(top_srcdir)/config/amanda/amplot.m4 \
+       $(top_srcdir)/config/amanda/bsd-security.m4 \
+       $(top_srcdir)/config/amanda/bsdtcp-security.m4 \
+       $(top_srcdir)/config/amanda/bsdudp-security.m4 \
+       $(top_srcdir)/config/amanda/changer.m4 \
+       $(top_srcdir)/config/amanda/components.m4 \
+       $(top_srcdir)/config/amanda/compress.m4 \
+       $(top_srcdir)/config/amanda/config.m4 \
+       $(top_srcdir)/config/amanda/debugging.m4 \
+       $(top_srcdir)/config/amanda/defaults.m4 \
+       $(top_srcdir)/config/amanda/devprefix.m4 \
+       $(top_srcdir)/config/amanda/dirs.m4 \
+       $(top_srcdir)/config/amanda/documentation.m4 \
+       $(top_srcdir)/config/amanda/dumpers.m4 \
+       $(top_srcdir)/config/amanda/flags.m4 \
+       $(top_srcdir)/config/amanda/flock.m4 \
+       $(top_srcdir)/config/amanda/funcs.m4 \
+       $(top_srcdir)/config/amanda/getfsent.m4 \
+       $(top_srcdir)/config/amanda/i18n.m4 \
+       $(top_srcdir)/config/amanda/ipv6.m4 \
+       $(top_srcdir)/config/amanda/krb4-security.m4 \
+       $(top_srcdir)/config/amanda/krb5-security.m4 \
+       $(top_srcdir)/config/amanda/lfs.m4 \
+       $(top_srcdir)/config/amanda/libs.m4 \
+       $(top_srcdir)/config/amanda/net.m4 \
+       $(top_srcdir)/config/amanda/progs.m4 \
+       $(top_srcdir)/config/amanda/readdir.m4 \
+       $(top_srcdir)/config/amanda/readline.m4 \
+       $(top_srcdir)/config/amanda/rsh-security.m4 \
+       $(top_srcdir)/config/amanda/s3-device.m4 \
+       $(top_srcdir)/config/amanda/shmem.m4 \
+       $(top_srcdir)/config/amanda/socklen_t_equiv.m4 \
+       $(top_srcdir)/config/amanda/ssh-security.m4 \
+       $(top_srcdir)/config/amanda/summary.m4 \
+       $(top_srcdir)/config/amanda/swig.m4 \
+       $(top_srcdir)/config/amanda/syshacks.m4 \
+       $(top_srcdir)/config/amanda/tape.m4 \
+       $(top_srcdir)/config/amanda/types.m4 \
+       $(top_srcdir)/config/amanda/userid.m4 \
+       $(top_srcdir)/config/amanda/version.m4 \
+       $(top_srcdir)/config/gnulib/alloca.m4 \
+       $(top_srcdir)/config/gnulib/arpa_inet_h.m4 \
+       $(top_srcdir)/config/gnulib/base64.m4 \
+       $(top_srcdir)/config/gnulib/eoverflow.m4 \
+       $(top_srcdir)/config/gnulib/extensions.m4 \
+       $(top_srcdir)/config/gnulib/float_h.m4 \
+       $(top_srcdir)/config/gnulib/fsusage.m4 \
+       $(top_srcdir)/config/gnulib/getaddrinfo.m4 \
+       $(top_srcdir)/config/gnulib/gettimeofday.m4 \
+       $(top_srcdir)/config/gnulib/gnulib-comp.m4 \
+       $(top_srcdir)/config/gnulib/include_next.m4 \
+       $(top_srcdir)/config/gnulib/inet_ntop.m4 \
+       $(top_srcdir)/config/gnulib/intmax_t.m4 \
+       $(top_srcdir)/config/gnulib/lock.m4 \
+       $(top_srcdir)/config/gnulib/longlong.m4 \
+       $(top_srcdir)/config/gnulib/malloc.m4 \
+       $(top_srcdir)/config/gnulib/mkdtemp.m4 \
+       $(top_srcdir)/config/gnulib/netinet_in_h.m4 \
+       $(top_srcdir)/config/gnulib/onceonly_2_57.m4 \
+       $(top_srcdir)/config/gnulib/physmem.m4 \
+       $(top_srcdir)/config/gnulib/safe-read.m4 \
+       $(top_srcdir)/config/gnulib/safe-write.m4 \
+       $(top_srcdir)/config/gnulib/snprintf.m4 \
+       $(top_srcdir)/config/gnulib/socklen.m4 \
+       $(top_srcdir)/config/gnulib/sockpfaf.m4 \
+       $(top_srcdir)/config/gnulib/ssize_t.m4 \
+       $(top_srcdir)/config/gnulib/stdbool.m4 \
+       $(top_srcdir)/config/gnulib/stdint.m4 \
+       $(top_srcdir)/config/gnulib/stdio_h.m4 \
+       $(top_srcdir)/config/gnulib/stdlib_h.m4 \
+       $(top_srcdir)/config/gnulib/strdup.m4 \
+       $(top_srcdir)/config/gnulib/string_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_socket_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_stat_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_time_h.m4 \
+       $(top_srcdir)/config/gnulib/tempname.m4 \
+       $(top_srcdir)/config/gnulib/ulonglong.m4 \
+       $(top_srcdir)/config/gnulib/unistd_h.m4 \
+       $(top_srcdir)/config/gnulib/vasnprintf.m4 \
+       $(top_srcdir)/config/gnulib/visibility.m4 \
+       $(top_srcdir)/config/gnulib/wchar.m4 \
+       $(top_srcdir)/config/gettext-macros/gettext.m4 \
+       $(top_srcdir)/config/gettext-macros/iconv.m4 \
+       $(top_srcdir)/config/gettext-macros/inttypes_h.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-ld.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-link.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-prefix.m4 \
+       $(top_srcdir)/config/gettext-macros/longlong.m4 \
+       $(top_srcdir)/config/gettext-macros/nls.m4 \
+       $(top_srcdir)/config/gettext-macros/po.m4 \
+       $(top_srcdir)/config/gettext-macros/progtest.m4 \
+       $(top_srcdir)/config/gettext-macros/size_max.m4 \
+       $(top_srcdir)/config/gettext-macros/stdint_h.m4 \
+       $(top_srcdir)/config/gettext-macros/wchar_t.m4 \
+       $(top_srcdir)/config/gettext-macros/wint_t.m4 \
+       $(top_srcdir)/config/gettext-macros/xsize.m4 \
+       $(top_srcdir)/config/libtool.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(amlibdir)" "$(DESTDIR)$(sbindir)" \
+       "$(DESTDIR)$(amincludedir)"
+amlibLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(amlib_LTLIBRARIES)
+libamdevice_la_DEPENDENCIES = ../common-src/libamanda.la
+am__libamdevice_la_SOURCES_DIST = property.c device.c queueing.c \
+       semaphore.c null-device.c rait-device.c vfs-device.c \
+       tape-device.c tape-xenix.c tape-aix.c tape-uware.c \
+       tape-posix.c s3-device.c s3.c
+@WANT_TAPE_DEVICE_TRUE@am__objects_1 = tape-device.lo
+@WANT_TAPE_DEVICE_TRUE@@WANT_TAPE_XENIX_TRUE@am__objects_2 =  \
+@WANT_TAPE_DEVICE_TRUE@@WANT_TAPE_XENIX_TRUE@  tape-xenix.lo
+@WANT_TAPE_AIX_TRUE@@WANT_TAPE_DEVICE_TRUE@am__objects_3 =  \
+@WANT_TAPE_AIX_TRUE@@WANT_TAPE_DEVICE_TRUE@    tape-aix.lo
+@WANT_TAPE_DEVICE_TRUE@@WANT_TAPE_UWARE_TRUE@am__objects_4 =  \
+@WANT_TAPE_DEVICE_TRUE@@WANT_TAPE_UWARE_TRUE@  tape-uware.lo
+@WANT_TAPE_DEVICE_TRUE@@WANT_TAPE_POSIX_TRUE@am__objects_5 =  \
+@WANT_TAPE_DEVICE_TRUE@@WANT_TAPE_POSIX_TRUE@  tape-posix.lo
+@WANT_S3_DEVICE_TRUE@am__objects_6 = s3-device.lo s3.lo
+am_libamdevice_la_OBJECTS = property.lo device.lo queueing.lo \
+       semaphore.lo null-device.lo rait-device.lo vfs-device.lo \
+       $(am__objects_1) $(am__objects_2) $(am__objects_3) \
+       $(am__objects_4) $(am__objects_5) $(am__objects_6)
+libamdevice_la_OBJECTS = $(am_libamdevice_la_OBJECTS)
+libamdevice_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libamdevice_la_LDFLAGS) $(LDFLAGS) -o $@
+@WANT_DEVPAY_TRUE@am__EXEEXT_1 = activate-devpay$(EXEEXT)
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(sbin_PROGRAMS)
+am__activate_devpay_SOURCES_DIST = activate-devpay.c
+@WANT_DEVPAY_TRUE@am_activate_devpay_OBJECTS =  \
+@WANT_DEVPAY_TRUE@     activate-devpay.$(OBJEXT)
+activate_devpay_OBJECTS = $(am_activate_devpay_OBJECTS)
+activate_devpay_LDADD = $(LDADD)
+DEFAULT_INCLUDES = -I. -I$(top_builddir)/config@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
+SOURCES = $(libamdevice_la_SOURCES) $(activate_devpay_SOURCES)
+DIST_SOURCES = $(am__libamdevice_la_SOURCES_DIST) \
+       $(am__activate_devpay_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+       html-recursive info-recursive install-data-recursive \
+       install-dvi-recursive install-exec-recursive \
+       install-html-recursive install-info-recursive \
+       install-pdf-recursive install-ps-recursive install-recursive \
+       installcheck-recursive installdirs-recursive pdf-recursive \
+       ps-recursive uninstall-recursive
+amincludeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(aminclude_HEADERS) $(noinst_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMANDA_DBGDIR = @AMANDA_DBGDIR@
+AMANDA_DEBUG_DAYS = @AMANDA_DEBUG_DAYS@
+AMANDA_STATIC_LDFLAGS = @AMANDA_STATIC_LDFLAGS@
+AMANDA_TMPDIR = @AMANDA_TMPDIR@
+AMANDA_WARNING_CFLAGS = @AMANDA_WARNING_CFLAGS@
+AMLINT = @AMLINT@
+AMLINTFLAGS = @AMLINTFLAGS@
+AMPLOT_CAT_COMPRESS = @AMPLOT_CAT_COMPRESS@
+AMPLOT_CAT_GZIP = @AMPLOT_CAT_GZIP@
+AMPLOT_CAT_PACK = @AMPLOT_CAT_PACK@
+AMPLOT_COMPRESS = @AMPLOT_COMPRESS@
+AMTAR = @AMTAR@
+AR = @AR@
+ARPA_INET_H = @ARPA_INET_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASH = @BASH@
+BINARY_OWNER = @BINARY_OWNER@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+CAT = @CAT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CHIO = @CHIO@
+CHS = @CHS@
+CLIENT_LOGIN = @CLIENT_LOGIN@
+CLIENT_SCRIPTS_OPT = @CLIENT_SCRIPTS_OPT@
+COMPRESS = @COMPRESS@
+CONFIG_DIR = @CONFIG_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURL_CONFIG = @CURL_CONFIG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DD = @DD@
+DEFAULT_AMANDATES_FILE = @DEFAULT_AMANDATES_FILE@
+DEFAULT_CHANGER_DEVICE = @DEFAULT_CHANGER_DEVICE@
+DEFAULT_CONFIG = @DEFAULT_CONFIG@
+DEFAULT_SERVER = @DEFAULT_SERVER@
+DEFAULT_TAPE_DEVICE = @DEFAULT_TAPE_DEVICE@
+DEFAULT_TAPE_SERVER = @DEFAULT_TAPE_SERVER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOC_BUILD_DATE = @DOC_BUILD_DATE@
+DUMP = @DUMP@
+DUMPER_DIR = @DUMPER_DIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXAMPLE_TAPEDEV = @EXAMPLE_TAPEDEV@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FLOAT_H = @FLOAT_H@
+GETCONF = @GETCONF@
+GETTEXT = @GETTEXT@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@
+GNULIB_CHOWN = @GNULIB_CHOWN@
+GNULIB_DUP2 = @GNULIB_DUP2@
+GNULIB_FCHDIR = @GNULIB_FCHDIR@
+GNULIB_FFLUSH = @GNULIB_FFLUSH@
+GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@
+GNULIB_FSEEK = @GNULIB_FSEEK@
+GNULIB_FSEEKO = @GNULIB_FSEEKO@
+GNULIB_FTELL = @GNULIB_FTELL@
+GNULIB_FTELLO = @GNULIB_FTELLO@
+GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@
+GNULIB_GETCWD = @GNULIB_GETCWD@
+GNULIB_GETDELIM = @GNULIB_GETDELIM@
+GNULIB_GETLINE = @GNULIB_GETLINE@
+GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@
+GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@
+GNULIB_LCHOWN = @GNULIB_LCHOWN@
+GNULIB_LSEEK = @GNULIB_LSEEK@
+GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@
+GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@
+GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@
+GNULIB_MBSCHR = @GNULIB_MBSCHR@
+GNULIB_MBSCSPN = @GNULIB_MBSCSPN@
+GNULIB_MBSLEN = @GNULIB_MBSLEN@
+GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@
+GNULIB_MBSNLEN = @GNULIB_MBSNLEN@
+GNULIB_MBSPBRK = @GNULIB_MBSPBRK@
+GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@
+GNULIB_MBSRCHR = @GNULIB_MBSRCHR@
+GNULIB_MBSSEP = @GNULIB_MBSSEP@
+GNULIB_MBSSPN = @GNULIB_MBSSPN@
+GNULIB_MBSSTR = @GNULIB_MBSSTR@
+GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@
+GNULIB_MEMMEM = @GNULIB_MEMMEM@
+GNULIB_MEMPCPY = @GNULIB_MEMPCPY@
+GNULIB_MEMRCHR = @GNULIB_MEMRCHR@
+GNULIB_MKDTEMP = @GNULIB_MKDTEMP@
+GNULIB_MKSTEMP = @GNULIB_MKSTEMP@
+GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@
+GNULIB_READLINK = @GNULIB_READLINK@
+GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@
+GNULIB_SLEEP = @GNULIB_SLEEP@
+GNULIB_SNPRINTF = @GNULIB_SNPRINTF@
+GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@
+GNULIB_STPCPY = @GNULIB_STPCPY@
+GNULIB_STPNCPY = @GNULIB_STPNCPY@
+GNULIB_STRCASESTR = @GNULIB_STRCASESTR@
+GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@
+GNULIB_STRDUP = @GNULIB_STRDUP@
+GNULIB_STRNDUP = @GNULIB_STRNDUP@
+GNULIB_STRNLEN = @GNULIB_STRNLEN@
+GNULIB_STRPBRK = @GNULIB_STRPBRK@
+GNULIB_STRSEP = @GNULIB_STRSEP@
+GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
+GNULIB_VASPRINTF = @GNULIB_VASPRINTF@
+GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@
+GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@
+GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@
+GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@
+GNULIB_WCWIDTH = @GNULIB_WCWIDTH@
+GNUPLOT = @GNUPLOT@
+GNUTAR = @GNUTAR@
+GNUTAR_LISTED_INCREMENTAL_DIR = @GNUTAR_LISTED_INCREMENTAL_DIR@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GZIP = @GZIP@
+HAVE_CALLOC_POSIX = @HAVE_CALLOC_POSIX@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_MKDIR = @HAVE_DECL_MKDIR@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DUP2 = @HAVE_DUP2@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_IO_H = @HAVE_IO_H@
+HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MALLOC_POSIX = @HAVE_MALLOC_POSIX@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_REALLOC_POSIX = @HAVE_REALLOC_POSIX@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRNDUP = @HAVE_STRNDUP@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE__BOOL = @HAVE__BOOL@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPTH = @LIBPTH@
+LIBS = @LIBS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBPTH = @LTLIBPTH@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAILER = @MAILER@
+MAKEINFO = @MAKEINFO@
+MAXTAPEBLOCKSIZE = @MAXTAPEBLOCKSIZE@
+MCUTIL = @MCUTIL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+MT = @MT@
+MTX = @MTX@
+MT_FILE_FLAG = @MT_FILE_FLAG@
+NETINET_IN_H = @NETINET_IN_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCAT = @PCAT@
+PERL = @PERL@
+PERLEXTLIBS = @PERLEXTLIBS@
+PERL_INC = @PERL_INC@
+PKG_CONFIG = @PKG_CONFIG@
+POSUB = @POSUB@
+PRINT = @PRINT@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_FCHDIR = @REPLACE_FCHDIR@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+RESTORE = @RESTORE@
+SAMBA_CLIENT = @SAMBA_CLIENT@
+SERVICE_SUFFIX = @SERVICE_SUFFIX@
+SETUID_GROUP = @SETUID_GROUP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+SNAPSHOT_STAMP = @SNAPSHOT_STAMP@
+SORT = @SORT@
+SSH = @SSH@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SVN = @SVN@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYS_SOCKET_H = @SYS_SOCKET_H@
+SYS_STAT_H = @SYS_STAT_H@
+SYS_TIME_H = @SYS_TIME_H@
+USE_NLS = @USE_NLS@
+USE_VERSION_SUFFIXES = @USE_VERSION_SUFFIXES@
+VDUMP = @VDUMP@
+VERSION = @VERSION@
+VERSION_COMMENT = @VERSION_COMMENT@
+VERSION_MAJOR = @VERSION_MAJOR@
+VERSION_MINOR = @VERSION_MINOR@
+VERSION_PATCH = @VERSION_PATCH@
+VERSION_SUFFIX = @VERSION_SUFFIX@
+VRESTORE = @VRESTORE@
+VXDUMP = @VXDUMP@
+VXRESTORE = @VXRESTORE@
+WCHAR_H = @WCHAR_H@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+XFSDUMP = @XFSDUMP@
+XFSRESTORE = @XFSRESTORE@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XSLREL = @XSLREL@
+XSLTPROC = @XSLTPROC@
+XSLTPROC_FLAGS = @XSLTPROC_FLAGS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+amincludedir = @amincludedir@
+amlibdir = @amlibdir@
+amlibexecdir = @amlibexecdir@
+amperldir = @amperldir@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = . tests
+INCLUDES = -I$(top_builddir)/common-src \
+               -I$(top_srcdir)/common-src \
+               -I$(top_srcdir)/gnulib
+
+AM_CFLAGS = $(AMANDA_WARNING_CFLAGS)
+AM_LDFLAGS = $(AMANDA_STATIC_LDFLAGS)
+amlib_LTLIBRARIES = libamdevice.la
+libamdevice_la_LDFLAGS = -release $(VERSION) 
+libamdevice_la_SOURCES = property.c device.c queueing.c semaphore.c \
+       null-device.c rait-device.c vfs-device.c $(am__append_1) \
+       $(am__append_2) $(am__append_3) $(am__append_4) \
+       $(am__append_5) $(am__append_6)
+libamdevice_la_LIBADD = ../common-src/libamanda.la
+@WANT_DEVPAY_TRUE@activate_devpay_SOURCES = activate-devpay.c
+noinst_HEADERS = null-device.h semaphore.h \
+       tape-ops.h property.h rait-device.h s3.h \
+       s3-device.h tape-device.h vfs-device.h \
+       device.h queueing.h
+
+aminclude_HEADERS = 
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/config/automake/precompile.am $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  device-src/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --gnu  device-src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-amlibLTLIBRARIES: $(amlib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(amlibdir)" || $(MKDIR_P) "$(DESTDIR)$(amlibdir)"
+       @list='$(amlib_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(amlibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(amlibdir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(amlibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(amlibdir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-amlibLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(amlib_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(amlibdir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(amlibdir)/$$p"; \
+       done
+
+clean-amlibLTLIBRARIES:
+       -test -z "$(amlib_LTLIBRARIES)" || rm -f $(amlib_LTLIBRARIES)
+       @list='$(amlib_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+libamdevice.la: $(libamdevice_la_OBJECTS) $(libamdevice_la_DEPENDENCIES) 
+       $(libamdevice_la_LINK) -rpath $(amlibdir) $(libamdevice_la_OBJECTS) $(libamdevice_la_LIBADD) $(LIBS)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+            || test -f $$p1 \
+         ; then \
+           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
+          $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
+         else :; fi; \
+       done
+
+uninstall-sbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
+         rm -f "$(DESTDIR)$(sbindir)/$$f"; \
+       done
+
+clean-sbinPROGRAMS:
+       @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+         f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         echo " rm -f $$p $$f"; \
+         rm -f $$p $$f ; \
+       done
+activate-devpay$(EXEEXT): $(activate_devpay_OBJECTS) $(activate_devpay_DEPENDENCIES) 
+       @rm -f activate-devpay$(EXEEXT)
+       $(LINK) $(activate_devpay_OBJECTS) $(activate_devpay_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/activate-devpay.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/null-device.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/property.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/queueing.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rait-device.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s3-device.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s3.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/semaphore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tape-aix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tape-device.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tape-posix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tape-uware.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tape-xenix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vfs-device.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+install-amincludeHEADERS: $(aminclude_HEADERS)
+       @$(NORMAL_INSTALL)
+       test -z "$(amincludedir)" || $(MKDIR_P) "$(DESTDIR)$(amincludedir)"
+       @list='$(aminclude_HEADERS)'; for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         f=$(am__strip_dir) \
+         echo " $(amincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(amincludedir)/$$f'"; \
+         $(amincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(amincludedir)/$$f"; \
+       done
+
+uninstall-amincludeHEADERS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(aminclude_HEADERS)'; for p in $$list; do \
+         f=$(am__strip_dir) \
+         echo " rm -f '$(DESTDIR)$(amincludedir)/$$f'"; \
+         rm -f "$(DESTDIR)$(amincludedir)/$$f"; \
+       done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+       @failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+       @failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       rev=''; for subdir in $$list; do \
+         if test "$$subdir" = "."; then :; else \
+           rev="$$subdir $$rev"; \
+         fi; \
+       done; \
+       rev="$$rev ."; \
+       target=`echo $@ | sed s/-recursive//`; \
+       for subdir in $$rev; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+       done
+ctags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+           $$tags $$unique; \
+       fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$tags $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && cd $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+       list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test -d "$(distdir)/$$subdir" \
+           || $(MKDIR_P) "$(distdir)/$$subdir" \
+           || exit 1; \
+           distdir=`$(am__cd) $(distdir) && pwd`; \
+           top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+           (cd $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$top_distdir" \
+               distdir="$$distdir/$$subdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+installdirs: installdirs-recursive
+installdirs-am:
+       for dir in "$(DESTDIR)$(amlibdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(amincludedir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-amlibLTLIBRARIES clean-generic clean-libtool \
+       clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-amincludeHEADERS install-amlibLTLIBRARIES
+
+install-dvi: install-dvi-recursive
+
+install-exec-am: install-sbinPROGRAMS
+
+install-html: install-html-recursive
+
+install-info: install-info-recursive
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-ps: install-ps-recursive
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-amincludeHEADERS uninstall-amlibLTLIBRARIES \
+       uninstall-sbinPROGRAMS
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
+       install-strip
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+       all all-am check check-am clean clean-amlibLTLIBRARIES \
+       clean-generic clean-libtool clean-sbinPROGRAMS ctags \
+       ctags-recursive distclean distclean-compile distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am \
+       install-amincludeHEADERS install-amlibLTLIBRARIES install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-sbinPROGRAMS install-strip \
+       installcheck installcheck-am installdirs installdirs-am \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+       pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+       uninstall-amincludeHEADERS uninstall-amlibLTLIBRARIES \
+       uninstall-sbinPROGRAMS
+
+
+# A rule to make precompiler output from C files.  This is not used during
+# ordinary builds, but but can very useful in debugging problems on strange
+# architectures.  With this rule, we can ask users to 'make foo.i' and send
+# the result to us.
+#
+# It touches some automake internals ($COMPILE), but since it's not
+# build-critical, that's OK.
+%.i : %.c
+       $(COMPILE) -E -o $@ $<
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/device-src/activate-devpay.c b/device-src/activate-devpay.c
new file mode 100644 (file)
index 0000000..196834d
--- /dev/null
@@ -0,0 +1,226 @@
+/* This program creates the token and certificate files for Amazon Devpay's
+ * Simple Token Service (STS). Right now you can then use those files with
+ * the S3 device. */
+
+#include "amanda.h"
+
+#include <curl/curl.h>
+#include <glib.h>
+
+#include <errno.h>
+#include <getopt.h>
+
+#include "base64.h"
+#include "s3.h"
+
+#ifndef WANT_DEVPAY
+# error activate_devpay only works if devpay is enabled.
+#endif
+
+#define MAX_RESPONSE_SIZE (1024*1024)
+
+typedef struct {
+    GString * user_token;
+    GString * access_key;
+    GString * secret_key;
+} Credentials;
+
+static void usage(void) {
+    g_fprintf(stderr,
+"USAGE: activate-devpay KEY [ >> amanda.conf ]\n"
+"  This tool uses an Amazon Devpay activation key to retrieve an\n"
+"  user token, access key, and secret key for use with Amazon S3. Output\n"
+"  is in a form suitable for placement in an Amanda configuration file\n");
+
+    exit(EXIT_FAILURE);
+}
+
+/* This function is **not** thread-safe. Sorry. */
+static const char * parse_commandline(int argc, char ** argv) {
+    if (argc != 2) {
+        usage();
+        return NULL;
+    } else {
+        return argv[1];
+    }
+}
+
+static char * activation_url(const char *key) {
+    char * url;
+    char * encoded_key;
+    
+    encoded_key = curl_escape(key, 0);
+    url = g_strdup_printf(STS_BASE_URL "?Action=ActivateDesktopProduct&ActivationKey=%s&ProductToken=" STS_PRODUCT_TOKEN "&Version=2007-06-05", encoded_key);
+    curl_free(encoded_key);
+
+    return url;
+}
+
+/* This function is a CURLOPT_WRITEFUNCTION and a wrapper for
+   g_markup_parse_context_parse(). It's not very smart about errors. */
+static size_t libcurl_gmarkup_glue(void *ptr, size_t size1, size_t size2,
+                                   void *stream) {
+    GMarkupParseContext *context = stream;
+    /* If this overflows, we have real problems, because we are expected to
+     * return the result of this multiplication in a size_t. */
+    size_t read_size = size1 * size2;
+    GError * error = NULL;
+
+    read_size = size1 * size2;
+
+    if (g_markup_parse_context_parse(context, ptr, read_size, &error)) {
+        return read_size;
+    } else {
+        if (error == NULL) {
+            g_fprintf(stderr, "Internal error parsing XML.\n");
+        } else {
+            g_fprintf(stderr, "Error parsing XML: %s\n",
+                    error->message);
+            g_error_free(error);
+        }
+        exit(EXIT_FAILURE);
+    }
+}
+
+static void do_server_stuff(const char * key, GMarkupParseContext * parser) {
+    char * url;
+    CURL* handle;
+    char curl_error_buffer[CURL_ERROR_SIZE];
+
+    handle = curl_easy_init();
+    
+    curl_easy_setopt(handle, CURLOPT_NOPROGRESS, TRUE);
+    curl_easy_setopt(handle, CURLOPT_NOSIGNAL, TRUE);
+    curl_easy_setopt(handle, CURLOPT_AUTOREFERER, TRUE);
+    curl_easy_setopt(handle, CURLOPT_ENCODING, ""); /* Support everything. */
+#ifdef CURLOPT_MAXFILESIZE
+    curl_easy_setopt(handle, CURLOPT_MAXFILESIZE, MAX_RESPONSE_SIZE);
+#endif
+    curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_buffer);
+
+    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, libcurl_gmarkup_glue);
+    curl_easy_setopt(handle, CURLOPT_WRITEDATA, parser);
+    url = activation_url(key);
+    curl_easy_setopt(handle, CURLOPT_URL, url);
+
+    if (curl_easy_perform(handle) != 0) {
+        g_error("Problem fetching data from server:\n%s",
+                curl_error_buffer);
+        exit(EXIT_FAILURE);
+    }
+    
+    g_free(url);
+}
+
+static void parser_got_text(GMarkupParseContext * context,
+                            const char * text,
+                            size_t text_len,
+                            gpointer user_data,
+                            GError ** error) {
+    Credentials * rval = user_data;
+
+    const char * current_tag = g_markup_parse_context_get_element(context);
+
+    g_assert(rval != NULL);
+    g_assert(*error == NULL);
+
+    /* We use strrstr instead of strcmp because Amazon uses namespaces
+     * that I don't want to deal with. */
+    if (g_strrstr(current_tag, "UserToken")) {
+        g_string_append_len(rval->user_token, text, text_len);
+        return;
+    } else if (g_strrstr(current_tag, "AWSAccessKeyId")) {
+        g_string_append_len(rval->access_key, text, text_len);
+        return;
+    } else if (g_strrstr(current_tag, "SecretAccessKey")) {
+        g_string_append_len(rval->secret_key, text, text_len);
+        return;
+    } else if (g_strrstr(current_tag, "Code")) {
+        /* Is it a code we know? */
+        if (strncmp(text, "ExpiredActivationKey", text_len) == 0) {
+            g_set_error(error, G_MARKUP_ERROR, -1,
+                        "Activation key has expired; get a new one.");
+        } else if (strncmp(text, "InvalidActivationKey", text_len) == 0) {
+            g_set_error(error, G_MARKUP_ERROR, -1,
+                        "Activation key is not valid; double-check.");
+        } else {
+            /* Do nothing; wait for the message. */
+        }
+    } else if (g_strrstr(current_tag, "Message")) {
+        g_set_error(error, G_MARKUP_ERROR, -1, "%.*s", text_len, text);
+    }
+}               
+
+static void parser_got_error(GMarkupParseContext * context G_GNUC_UNUSED,
+                             GError * error,
+                             gpointer user_data G_GNUC_UNUSED) {
+    g_fprintf (stderr, "Problem with Amazon response: %s\n", error->message);
+    exit(EXIT_FAILURE);
+}
+
+static GMarkupParseContext * parser_init(Credentials * credentials) {
+    static const GMarkupParser parser_settings = {
+        NULL, /* start_element */
+        NULL, /* end_element */
+        parser_got_text, /* text */
+        NULL, /* passthrough */
+        parser_got_error /* error */
+    };
+    bzero(credentials, sizeof(*credentials));
+
+    credentials->user_token = g_string_new("");
+    credentials->access_key = g_string_new("");
+    credentials->secret_key = g_string_new("");
+
+    return g_markup_parse_context_new(&parser_settings, 0, credentials, NULL);
+}
+
+static void parser_cleanup(GMarkupParseContext * context) {
+    GError * error = NULL;
+    g_markup_parse_context_end_parse(context, &error);
+    
+    if (error != NULL) {
+        g_fprintf (stderr, "Unexpected end of Amazon response: %s\n",
+                 error->message);
+        exit(EXIT_FAILURE);
+    }
+
+    g_markup_parse_context_free(context);
+}
+
+/* This function is responsible for the whole output thing. */
+static void do_output(Credentials * rare) {
+    if (rare == NULL ||
+        rare->user_token == NULL || !rare->user_token->len ||
+        rare->access_key == NULL || !rare->access_key->len ||
+        rare->secret_key == NULL || !rare->secret_key->len) {
+        g_fprintf(stderr, "Missing authentication data in response!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    g_printf("device_property \"S3_USER_TOKEN\" \"%s\"\n"
+             "device_property \"S3_ACCESS_KEY\" \"%s\"\n"
+             "device_property \"S3_SECRET_KEY\" \"%s\"\n",
+             rare->user_token->str, rare->access_key->str,
+             rare->secret_key->str);
+}
+
+int main(int argc, char ** argv) {
+    const char * key;
+    GMarkupParseContext * parser;
+    Credentials credentials;
+
+    key = parse_commandline(argc, argv);
+
+    curl_global_init(CURL_GLOBAL_ALL);
+    parser = parser_init(&credentials);
+
+    do_server_stuff(key, parser);
+
+    curl_global_cleanup();
+    parser_cleanup(parser);
+
+    do_output(&credentials);
+    
+    return 0;
+}
diff --git a/device-src/device.c b/device-src/device.c
new file mode 100644 (file)
index 0000000..001db2a
--- /dev/null
@@ -0,0 +1,1121 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* The Device API abstracts device workings, interaction, properties, and
+ * capabilities from the rest of the Amanda code base. It supports
+ * pluggable modules for different kinds of devices. */
+
+#include "amanda.h"
+#include "conffile.h"
+
+#include <regex.h>
+
+#include "device.h"
+#include "queueing.h"
+#include "property.h"
+
+#include "null-device.h"
+#include "timestamp.h"
+#include "vfs-device.h"
+#include "util.h"
+#ifdef WANT_TAPE_DEVICE
+#include "tape-device.h"
+#endif
+#include "rait-device.h"
+#ifdef WANT_S3_DEVICE
+  #include "s3-device.h"
+#endif
+
+static GHashTable* driverList = NULL;
+
+void device_api_init(void) {
+    g_type_init();
+    amanda_thread_init();
+    device_property_init();
+    driverList = g_hash_table_new(g_str_hash, g_str_equal);
+
+    /* register other types and devices. */
+    null_device_register();
+    vfs_device_register();
+#ifdef WANT_TAPE_DEVICE
+    tape_device_register();
+#endif
+    rait_device_register();
+#ifdef WANT_S3_DEVICE
+    s3_device_register();
+#endif
+}
+
+void register_device(DeviceFactory factory,
+                     const char ** device_prefix_list) {
+    char ** tmp;
+    g_assert(driverList != NULL);
+    g_assert(factory != NULL);
+    g_return_if_fail(device_prefix_list != NULL);
+    g_return_if_fail(*device_prefix_list != NULL);
+
+    tmp = (char**)device_prefix_list;
+    while (*tmp != NULL) {
+        g_hash_table_insert(driverList, *tmp, (gpointer)factory);
+        tmp ++;
+    }
+}
+
+static DeviceFactory lookup_device_factory(const char *device_name) {
+    gpointer key, value;
+    g_assert(driverList != NULL);
+
+    if (g_hash_table_lookup_extended(driverList, device_name, &key, &value)) {
+        return (DeviceFactory)value;
+    } else {
+        return NULL;
+    }
+}
+
+static const GFlagsValue read_label_status_flags_values[] = {
+    { READ_LABEL_STATUS_SUCCESS,
+      "READ_LABEL_STATUS_SUCCESS",
+      "Success" },
+    { READ_LABEL_STATUS_DEVICE_MISSING,
+      "READ_LABEL_STATUS_DEVICE_MISSING",
+      "Device not found" },
+    { READ_LABEL_STATUS_DEVICE_ERROR,
+      "READ_LABEL_STATUS_DEVICE_ERROR",
+      "Device error" },
+    { READ_LABEL_STATUS_VOLUME_MISSING,
+      "READ_LABEL_STATUS_VOLUME_MISSING",
+      "Volume not found" },
+    { READ_LABEL_STATUS_VOLUME_UNLABELED,
+      "READ_LABEL_STATUS_VOLUME_UNLABELED",
+      "Volume not labeled" },
+    { READ_LABEL_STATUS_VOLUME_ERROR,
+      "READ_LABEL_STATUS_VOLUME_ERROR",
+      "Volume error" },
+    { 0, NULL, NULL }
+};
+
+GType read_label_status_flags_get_type(void) {
+    static GType type = 0;
+    if (G_UNLIKELY(type == 0)) {
+        type = g_flags_register_static("ReadLabelStatusFlags",
+                                       read_label_status_flags_values);
+    }
+    return type;
+}
+
+/* Device class definition starts here. */
+
+struct DevicePrivate_s {
+    /* This is the return value of the device_get_property_list()
+       method. */
+    GArray *property_list;
+    GHashTable * property_response;
+};
+
+/* This holds the default response to a particular property. */
+typedef struct {
+    PropertyAccessFlags access;
+    GValue response;
+} PropertyResponse;
+
+#define selfp (self->private)
+
+/* here are local prototypes, so we can make function pointers. */
+static void device_init (Device * o) G_GNUC_UNUSED;
+static void device_class_init (DeviceClass * c) G_GNUC_UNUSED;
+
+static void property_response_free(PropertyResponse *o);
+
+static gboolean default_device_open_device(Device * self, char * device_name);
+static gboolean default_device_finish(Device * self);
+static gboolean default_device_start(Device * self, DeviceAccessMode mode,
+                                     char * label, char * timestamp);
+static gboolean default_device_start_file (Device * self,
+                                           const dumpfile_t * jobinfo);
+static gboolean default_device_write_block (Device * self, guint size,
+                                            gpointer data, gboolean last);
+static gboolean default_device_write_from_fd(Device *self, int fd);
+static gboolean default_device_finish_file (Device * self);
+static dumpfile_t* default_device_seek_file (Device * self, guint file);
+static gboolean default_device_seek_block (Device * self, guint64 block);
+static int default_device_read_block (Device * self, gpointer buffer,
+                                      int * size);
+static gboolean default_device_read_to_fd(Device *self, int fd);
+static gboolean default_device_property_get(Device * self, DevicePropertyId ID,
+                                            GValue * value);
+
+/* pointer to the class of our parent */
+static GObjectClass *parent_class = NULL;
+
+GType
+device_get_type (void)
+{
+    static GType type = 0;
+    
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (DeviceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) device_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (Device),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) device_init,
+            NULL
+        };
+        
+        type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
+                                       (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
+    }
+    
+    return type;
+}
+
+static void device_finalize(GObject *obj_self) {
+    Device *self G_GNUC_UNUSED = DEVICE (obj_self);
+    if(G_OBJECT_CLASS(parent_class)->finalize)
+        (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+
+    /* Here we call device_finish() if it hasn't been done
+       yet. Subclasses may need to do this same check earlier. */
+    if (self->access_mode != ACCESS_NULL) {
+        device_finish(self);
+    }
+
+    amfree(self->device_name);
+    amfree(self->volume_label);
+    amfree(self->volume_time);
+    g_array_free(selfp->property_list, TRUE);
+    g_hash_table_destroy(selfp->property_response);
+    amfree(self->private);
+}
+
+static void 
+device_init (Device * self G_GNUC_UNUSED)
+{
+    self->private = malloc(sizeof(DevicePrivate));
+    self->device_name = NULL;
+    self->access_mode = ACCESS_NULL;
+    self->is_eof = FALSE;
+    self->file = -1;
+    self->block = 0;
+    self->in_file = FALSE;
+    self->volume_label = NULL;
+    self->volume_time = NULL;
+    selfp->property_list = g_array_new(TRUE, FALSE, sizeof(DeviceProperty));
+    selfp->property_response =
+        g_hash_table_new_full(g_direct_hash,
+                              g_direct_equal,
+                              NULL,
+                              (GDestroyNotify) property_response_free);
+}
+
+static void 
+device_class_init (DeviceClass * c G_GNUC_UNUSED)
+{
+    GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c;
+    
+    parent_class = g_type_class_ref (G_TYPE_OBJECT);
+    
+    c->open_device = default_device_open_device;
+    c->finish = default_device_finish;
+    c->read_label = NULL;
+    c->start = default_device_start;
+    c->start_file = default_device_start_file;
+    c->write_block = default_device_write_block;
+    c->write_from_fd = default_device_write_from_fd;
+    c->finish_file = default_device_finish_file;
+    c->seek_file = default_device_seek_file;
+    c->seek_block = default_device_seek_block;
+    c->read_block = default_device_read_block;
+    c->read_to_fd = default_device_read_to_fd;
+    c->property_get = default_device_property_get;
+    c->property_set = NULL;
+    c->recycle_file = NULL;
+    g_object_class->finalize = device_finalize;
+}
+
+static void property_response_free(PropertyResponse * resp) {
+    g_value_unset(&(resp->response));
+    amfree(resp);
+}
+
+static char *
+regex_message(int result, regex_t *regex) {
+    char * rval;
+    size_t size;
+
+    size = regerror(result, regex, NULL, 0);
+    rval = malloc(size);
+    regerror(result, regex, rval, size);
+
+    return rval;
+}
+
+static gboolean
+handle_device_regex(const char * user_name, char ** driver_name,
+                    char ** device) {
+    regex_t regex;
+    int reg_result;
+    regmatch_t pmatch[3];
+    static const char * regex_string = "^([a-z0-9]+):(.*)$";
+
+    bzero(&regex, sizeof(regex));
+
+    reg_result = regcomp(&regex, regex_string, REG_EXTENDED | REG_ICASE);
+    if (reg_result != 0) {
+        char * message = regex_message(reg_result, &regex);
+        g_fprintf(stderr, "Error compiling regular expression \"%s\": %s\n",
+               regex_string, message);
+        amfree(message);
+        return FALSE;
+    }
+
+    reg_result = regexec(&regex, user_name, 3, pmatch, 0);
+    if (reg_result != 0 && reg_result != REG_NOMATCH) {
+        char * message = regex_message(reg_result, &regex);
+        g_fprintf(stderr, "Error applying regular expression \"%s\" to string \"%s\":\n"
+               "%s\n", user_name, regex_string, message);
+        regfree(&regex);
+        return FALSE;
+    } else if (reg_result == REG_NOMATCH) {
+#ifdef WANT_TAPE_DEVICE
+        g_fprintf(stderr, "\"%s\" uses deprecated device naming convention; \n"
+                "using \"tape:%s\" instead.\n",
+                user_name, user_name);
+        *driver_name = stralloc("tape");
+        *device = stralloc(user_name);
+#else /* !WANT_TAPE_DEVICE */
+        g_fprintf(stderr, "\"%s\" is not a valid device name.\n", user_name);
+       regfree(&regex);
+       return FALSE;
+#endif /* WANT_TAPE_DEVICE */
+    } else {
+        *driver_name = find_regex_substring(user_name, pmatch[1]);
+        *device = find_regex_substring(user_name, pmatch[2]);
+    }
+    regfree(&regex);
+    return TRUE;
+}
+
+Device* 
+device_open (char * device_name)
+{
+    char *device_driver_name = NULL;
+    char *device_node_name = NULL;
+    DeviceFactory factory;
+    Device *device;
+
+    g_return_val_if_fail (device_name != NULL, NULL);
+
+    if (driverList == NULL) {
+        g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR,
+              "device_open() called without device_api_init()!\n");
+        g_assert_not_reached();
+    }
+
+    if (!handle_device_regex(device_name, &device_driver_name, &device_node_name)) {
+        amfree(device_driver_name);
+        amfree(device_node_name);
+        return NULL;
+    }
+
+    factory = lookup_device_factory(device_driver_name);
+
+    if (factory == NULL) {
+        g_fprintf(stderr, "Device driver %s is not known.\n",
+                device_driver_name);
+        amfree(device_driver_name);
+        amfree(device_node_name);
+        return NULL;
+    }
+
+    device = factory(device_driver_name, device_node_name);
+    amfree(device_driver_name);
+    amfree(device_node_name);
+    return device;
+}
+
+void 
+device_add_property (Device * self, DeviceProperty * prop, GValue * response)
+{
+    unsigned int i;
+    g_return_if_fail (self != NULL);
+    g_return_if_fail (IS_DEVICE (self));
+    g_assert(selfp->property_list != NULL);
+    g_assert(selfp->property_response != NULL);
+
+    /* Delete it if it already exists. */
+    for(i = 0; i < selfp->property_list->len; i ++) {
+        if (g_array_index(selfp->property_list,
+                          DeviceProperty, i).base->ID == prop->base->ID) {
+            g_array_remove_index_fast(selfp->property_list, i);
+            break;
+        }
+    }
+
+    g_array_append_val(selfp->property_list, *prop);
+    
+    if (response != NULL) {
+        PropertyResponse * property_response;
+        
+        g_return_if_fail(G_IS_VALUE(response));
+        
+        property_response = malloc(sizeof(*property_response));
+        property_response->access = prop->access;
+        bzero(&(property_response->response),
+              sizeof(property_response->response));
+        g_value_init(&(property_response->response),
+                     G_VALUE_TYPE(response));
+        g_value_copy(response, &(property_response->response));
+        
+        g_hash_table_insert(selfp->property_response,
+                            GINT_TO_POINTER(prop->base->ID),
+                            property_response);
+    }
+}
+
+const DeviceProperty * 
+device_property_get_list (Device * self)
+{
+       g_return_val_if_fail (self != NULL, (const DeviceProperty * )0);
+       g_return_val_if_fail (IS_DEVICE (self), (const DeviceProperty * )0);
+
+        return (const DeviceProperty*) selfp->property_list->data;
+}
+
+guint device_write_min_size(Device * self) {
+    GValue g_tmp;
+    int block_size, min_block_size;
+    
+    bzero(&g_tmp, sizeof(g_tmp));
+    device_property_get(self, PROPERTY_BLOCK_SIZE, &g_tmp);
+    block_size = g_value_get_int(&g_tmp);
+    g_value_unset(&g_tmp);
+    if (block_size > 0) {
+        return block_size;
+    }
+
+    /* variable block size */
+    device_property_get(self, PROPERTY_MIN_BLOCK_SIZE, &g_tmp);
+    min_block_size = g_value_get_uint(&g_tmp);
+    g_value_unset(&g_tmp);
+    return min_block_size;
+}
+
+guint device_write_max_size(Device * self) {
+    GValue g_tmp;
+    int block_size, max_block_size;
+    
+    bzero(&g_tmp, sizeof(g_tmp));
+    device_property_get(self, PROPERTY_BLOCK_SIZE, &g_tmp);
+    block_size = g_value_get_int(&g_tmp);
+    g_value_unset(&g_tmp);
+    if (block_size > 0) {
+        return block_size;
+    }
+
+    /* variable block size */
+    device_property_get(self, PROPERTY_MAX_BLOCK_SIZE, &g_tmp);
+    max_block_size = g_value_get_uint(&g_tmp);
+    g_value_unset(&g_tmp);
+    return max_block_size;
+}
+
+guint device_read_max_size(Device * self) {
+    GValue g_tmp;
+    
+    bzero(&g_tmp, sizeof(g_tmp));
+    if (device_property_get(self, PROPERTY_READ_BUFFER_SIZE, &g_tmp)) {
+        guint rval = g_value_get_uint(&g_tmp);
+        g_value_unset(&g_tmp);
+        return rval;
+    } else {
+        return device_write_max_size(self);
+    }
+}
+
+char * device_build_amanda_header(Device * self, const dumpfile_t * info,
+                                  int * size, gboolean * oneblock) {
+    char *amanda_header;
+    unsigned int min_header_length;
+    unsigned int header_buffer_size;
+
+    min_header_length = device_write_min_size(self);
+    amanda_header = build_header(info, min_header_length);
+    header_buffer_size = MAX(min_header_length, strlen(amanda_header)+1);
+    if (size != NULL)
+        *size = header_buffer_size;
+    if (oneblock != NULL)
+        *oneblock = (header_buffer_size <=  device_write_max_size(self));
+    return amanda_header;
+}
+
+dumpfile_t * make_tapestart_header(Device * self, char * label,
+                                   char * timestamp) {
+    dumpfile_t * rval;
+
+    g_return_val_if_fail(label != NULL, NULL);
+
+    rval = malloc(sizeof(*rval));
+    fh_init(rval);
+    rval->type = F_TAPESTART;
+    amfree(self->volume_time);
+    if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
+        self->volume_time = get_proper_stamp_from_time(time(NULL));
+    } else {
+        self->volume_time = g_strdup(timestamp);
+    }
+    strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
+    strncpy(rval->name, label, sizeof(rval->name));
+
+    return rval;
+}
+
+dumpfile_t * make_tapeend_header(void) {
+    dumpfile_t * rval;
+    char * timestamp;
+
+    rval = malloc(sizeof(*rval));
+    rval->type = F_TAPEEND;
+    timestamp = get_timestamp_from_time(time(NULL));
+    strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
+    amfree(timestamp);
+    return rval;
+}
+
+/* Try setting max/fixed blocksize on a device. Check results, fallback, and
+ * print messages for problems. */
+static void try_set_blocksize(Device * device, guint blocksize,
+                              gboolean try_max_first) {
+    GValue val;
+    gboolean success;
+    bzero(&val, sizeof(val));
+    g_value_init(&val, G_TYPE_UINT);
+    g_value_set_uint(&val, blocksize);
+    if (try_max_first) {
+        success = device_property_set(device,
+                                      PROPERTY_MAX_BLOCK_SIZE,
+                                      &val);
+        if (!success) {
+            g_fprintf(stderr, "Setting MAX_BLOCK_SIZE to %u "
+                    "not supported for device %s.\n"
+                    "trying BLOCK_SIZE instead.\n",
+                    blocksize, device->device_name);
+        } else {
+            g_value_unset(&val);
+            return;
+        }
+    }
+
+    g_value_unset(&val);
+    g_value_init(&val, G_TYPE_INT);
+    g_value_set_int(&val, blocksize);
+    success = device_property_set(device,
+                                  PROPERTY_BLOCK_SIZE,
+                                  &val);
+    if (!success) {
+        g_fprintf(stderr, "Setting BLOCK_SIZE to %u "
+                "not supported for device %s.\n",
+                blocksize, device->device_name);
+    }
+    g_value_unset(&val);
+}
+
+/* A GHFunc (callback for g_hash_table_foreach) */
+static void set_device_property(gpointer key_p, gpointer value_p,
+                                   gpointer user_data_p) {
+    char * property_s = key_p;
+    char * value_s = value_p;
+    Device * device = user_data_p;
+    const DevicePropertyBase* property_base;
+    GValue property_value;
+
+    g_return_if_fail(IS_DEVICE(device));
+    g_return_if_fail(property_s != NULL);
+    g_return_if_fail(value_s != NULL);
+
+    property_base = device_property_get_by_name(property_s);
+    if (property_base == NULL) {
+        /* Nonexistant property name. */
+        g_fprintf(stderr, _("Unknown device property name %s.\n"), property_s);
+        return;
+    }
+    
+    bzero(&property_value, sizeof(property_value));
+    g_value_init(&property_value, property_base->type);
+    if (!g_value_set_from_string(&property_value, value_s)) {
+        /* Value type could not be interpreted. */
+        g_fprintf(stderr,
+                _("Could not parse property value %s for property type %s.\n"),
+                value_s, g_type_name(property_base->type));
+        return;
+    } else {
+        g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
+    }
+
+    if (!device_property_set(device, property_base->ID, &property_value)) {
+        /* Device rejects property. */
+        g_fprintf(stderr, _("Could not set property %s to %s on device %s.\n"),
+                property_base->name, value_s, device->device_name);
+        return;
+    }
+}
+
+/* Set up first-run properties, including DEVICE_MAX_VOLUME_USAGE property
+ * based on the tapetype. */
+void device_set_startup_properties_from_config(Device * device) {
+    char * tapetype_name = getconf_str(CNF_TAPETYPE);
+    if (tapetype_name != NULL) {
+        tapetype_t * tapetype = lookup_tapetype(tapetype_name);
+        if (tapetype != NULL) {
+            GValue val;
+            guint64 length;
+            guint blocksize_kb;
+            gboolean success;
+
+            bzero(&val, sizeof(GValue));
+
+            if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
+               length = tapetype_get_length(tapetype);
+                g_value_init(&val, G_TYPE_UINT64);
+                g_value_set_uint64(&val, length * 1024);
+                /* If this fails, it's not really an error. */
+                device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
+                g_value_unset(&val);
+            }
+
+            if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
+               blocksize_kb = tapetype_get_readblocksize(tapetype);
+                g_value_init(&val, G_TYPE_UINT);
+                g_value_set_uint(&val, blocksize_kb * 1024);
+                success = device_property_set(device,
+                                              PROPERTY_READ_BUFFER_SIZE,
+                                              &val);
+                g_value_unset(&val);
+                if (!success) {
+                    g_fprintf(stderr, "Setting READ_BUFFER_SIZE to %llu "
+                            "not supported for device %s.\n",
+                            1024*(long long unsigned int)blocksize_kb,
+                           device->device_name);
+                }
+            }
+
+            if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
+               blocksize_kb = tapetype_get_blocksize(tapetype);
+                try_set_blocksize(device, blocksize_kb * 1024,
+                                  !tapetype_get_file_pad(tapetype));
+            }
+        }
+    }
+
+    g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
+                         set_device_property, device);
+}
+
+void device_clear_volume_details(Device * device) {
+    if (device == NULL || device->access_mode != ACCESS_NULL) {
+        return;
+    }
+
+    amfree(device->volume_label);
+    amfree(device->volume_time);
+}
+
+/* Here we put default implementations of virtual functions. Since
+   this class is virtual, many of these functions offer at best
+   incomplete functionality. But they do offer the useful commonality
+   that all devices can expect to need. */
+
+/* This function only updates access_mode, volume_label, and volume_time. */
+static gboolean
+default_device_start (Device * self, DeviceAccessMode mode, char * label,
+                      char * timestamp) {
+    if (mode != ACCESS_WRITE && self->volume_label == NULL) {
+       g_debug("default_device_start calling device_read_label with mode %d", mode);
+        if (device_read_label(self) != READ_LABEL_STATUS_SUCCESS)
+            return FALSE;
+    } else if (mode == ACCESS_WRITE) {
+        self->volume_label = newstralloc(self->volume_label, label);
+        self->volume_time = newstralloc(self->volume_time, timestamp);
+    }
+    self->access_mode = mode;
+
+    return TRUE;
+}
+
+static gboolean default_device_open_device(Device * self,
+                                           char * device_name) {
+    DeviceProperty prop;
+    guint i;
+
+    self->device_name = stralloc(device_name);
+
+    prop.base = &device_property_canonical_name;
+    prop.access = PROPERTY_ACCESS_GET_MASK;
+
+    for(i = 0; i < selfp->property_list->len; i ++) {
+        if (g_array_index(selfp->property_list,
+                          DeviceProperty, i).base->ID == prop.base->ID) {
+            return TRUE;
+        }
+    }
+    /* If we got here, the property was not registered. */
+    device_add_property(self, &prop, NULL);
+
+    return TRUE;
+}
+
+/* This default implementation does very little. */
+static gboolean
+default_device_finish (Device * self) {
+    self->access_mode = ACCESS_NULL;
+    return TRUE;
+}
+
+/* This function updates the file, in_file, and block attributes. */
+static gboolean
+default_device_start_file (Device * self,
+                           const dumpfile_t * jobInfo G_GNUC_UNUSED) {
+    self->in_file = TRUE;
+    if (self->file <= 0)
+        self->file = 1;
+    else
+        self->file ++;
+    self->block = 0;
+    return TRUE;
+}
+
+/* This function lies: It updates the block number and maybe calls
+   device_finish_file(), but returns FALSE. */
+static gboolean
+default_device_write_block(Device * self, guint size G_GNUC_UNUSED,
+                           gpointer data G_GNUC_UNUSED, gboolean last_block) {
+    self->block ++;
+    if (last_block)
+        device_finish_file(self);
+    return FALSE;
+}
+
+/* This function lies: It updates the block number, but returns
+   -1. */
+static int
+default_device_read_block(Device * self, gpointer buf G_GNUC_UNUSED,
+                          int * size G_GNUC_UNUSED) {
+    self->block ++;
+    return -1;
+}
+
+/* This function just updates the in_file field. */
+static gboolean
+default_device_finish_file(Device * self) {
+    self->in_file = FALSE;
+    return TRUE;
+}
+
+/* This function just updates the file number. */
+static dumpfile_t *
+default_device_seek_file(Device * self, guint file) {
+    self->in_file = TRUE;
+    self->file = file;
+    return NULL;
+}
+
+/* This function just updates the block number. */
+static gboolean
+default_device_seek_block(Device * self, guint64 block) {
+    self->block = block;
+    return TRUE;
+}
+
+/* This default implementation serves up static responses, and
+   implements a default response to the "canonical name" property. */
+
+static gboolean
+default_device_property_get(Device * self, DevicePropertyId ID,
+                            GValue * value) {
+    const PropertyResponse * resp;
+
+    resp = (PropertyResponse*)g_hash_table_lookup(selfp->property_response,
+                                                  GINT_TO_POINTER(ID));
+    if (resp == NULL) {
+        if (ID == PROPERTY_CANONICAL_NAME) {
+            g_value_unset_init(value, G_TYPE_STRING);
+            g_value_set_string(value, self->device_name);
+           return TRUE;
+        } else {
+            return FALSE;
+        }
+    }
+
+    g_value_unset_copy(&resp->response, value);
+
+    return TRUE;
+}
+
+static gboolean
+default_device_read_to_fd(Device *self, int fd) {
+    GValue val;
+    StreamingRequirement streaming_mode;
+
+    /* Get the device's parameters */
+    bzero(&val, sizeof(val));
+    if (!device_property_get(self, PROPERTY_STREAMING, &val)
+       || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
+       streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
+    } else {
+       streaming_mode = g_value_get_enum(&val);
+    }
+
+    return QUEUE_SUCCESS ==
+       do_consumer_producer_queue_full(
+           device_read_producer,
+           self,
+           fd_write_consumer,
+           GINT_TO_POINTER(fd),
+           device_read_max_size(self),
+           DEFAULT_MAX_BUFFER_MEMORY,
+           streaming_mode);
+}
+
+static gboolean
+default_device_write_from_fd(Device *self, int fd) {
+    GValue val;
+    StreamingRequirement streaming_mode;
+
+    /* Get the device's parameters */
+    bzero(&val, sizeof(val));
+    if (!device_property_get(self, PROPERTY_STREAMING, &val)
+       || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
+       streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
+    } else {
+       streaming_mode = g_value_get_enum(&val);
+    }
+
+    return QUEUE_SUCCESS ==
+       do_consumer_producer_queue_full(
+           fd_read_producer,
+           GINT_TO_POINTER(fd),
+           device_write_consumer,
+           self,
+           device_write_max_size(self),
+           DEFAULT_MAX_BUFFER_MEMORY,
+           streaming_mode);
+}
+
+/* XXX WARNING XXX
+ * All the functions below this comment are stub functions that do nothing
+ * but implement the virtual function table. Call these functions and they
+ * will do what you expect vis-a-vis virtual functions. But don't put code
+ * in them beyond error checking and VFT lookup. */
+
+gboolean 
+device_open_device (Device * self, char * device_name)
+{
+        DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+       g_return_val_if_fail (device_name != NULL, FALSE);
+       klass = DEVICE_GET_CLASS(self);
+
+       if(klass->open_device)
+            return (*klass->open_device)(self,device_name);
+       else
+               return FALSE;
+}
+
+ReadLabelStatusFlags device_read_label(Device * self) {
+    DeviceClass * klass;
+    g_debug("device_read_label; mode = %d", self->access_mode);
+    g_return_val_if_fail(self != NULL, FALSE);
+    g_return_val_if_fail(IS_DEVICE(self), FALSE);
+    g_return_val_if_fail(self->access_mode == ACCESS_NULL, FALSE);
+
+    klass = DEVICE_GET_CLASS(self);
+    if (klass->read_label) {
+        return (klass->read_label)(self);
+    } else {
+        return ~ READ_LABEL_STATUS_SUCCESS;
+    }
+}
+
+gboolean
+device_finish (Device * self) {
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+
+        if (self->access_mode == ACCESS_NULL)
+            return TRUE;
+
+       klass = DEVICE_GET_CLASS(self);
+        if (klass->finish) {
+            return (*klass->finish)(self);
+        } else {
+            return FALSE;
+        }
+}
+
+/* For a good combination of synchronization and public simplicity,
+   this stub function does not take a timestamp, but the actual
+   implementation function does. We generate the timestamp here with
+   time(). */
+gboolean 
+device_start (Device * self, DeviceAccessMode mode,
+              char * label, char * timestamp)
+{
+       DeviceClass *klass;
+
+       g_debug("device_start mode = %d", mode);
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+        g_return_val_if_fail (mode != ACCESS_NULL, FALSE);
+        g_return_val_if_fail (mode != ACCESS_WRITE || label != NULL,
+                              FALSE);
+       klass = DEVICE_GET_CLASS(self);
+
+       if(klass->start) {
+           char * local_timestamp = NULL;
+           gboolean rv;
+
+           /* fill in a timestamp if none was given */
+           if (mode == ACCESS_WRITE &&
+               get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
+               local_timestamp = timestamp = 
+                   get_proper_stamp_from_time(time(NULL));
+           }
+
+            rv = (*klass->start)(self, mode, label, timestamp);
+           amfree(local_timestamp);
+           g_debug("device_start done; dev->access_mode = %d, result %d", self->access_mode, rv);
+           return rv;
+        } else {
+            return FALSE;
+        }
+}
+
+gboolean
+device_write_block (Device * self, guint size, gpointer block,
+                    gboolean short_block)
+{
+    DeviceClass *klass;
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (IS_DEVICE (self), FALSE);
+    g_return_val_if_fail (size > 0, FALSE);
+    g_return_val_if_fail (short_block ||
+                          size >= device_write_min_size(self), FALSE);
+    g_return_val_if_fail (size <= device_write_max_size(self), FALSE);
+    g_return_val_if_fail (block != NULL, FALSE);
+    g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
+                          FALSE);
+
+    klass = DEVICE_GET_CLASS(self);
+    
+    if(klass->write_block)
+        return (*klass->write_block)(self,size, block, short_block);
+    else
+        return FALSE;
+}
+
+gboolean 
+device_write_from_fd (Device * self, int fd)
+{
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+       g_return_val_if_fail (fd >= 0, FALSE);
+        g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
+                              FALSE);
+
+       klass = DEVICE_GET_CLASS(self);
+
+       if(klass->write_from_fd)
+               return (*klass->write_from_fd)(self,fd);
+       else
+               return FALSE;
+}
+
+gboolean
+device_start_file (Device * self, const dumpfile_t * jobInfo) {
+    DeviceClass * klass;
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (IS_DEVICE (self), FALSE);
+    g_return_val_if_fail (!(self->in_file), FALSE);
+    g_return_val_if_fail (jobInfo != NULL, FALSE);
+
+    klass = DEVICE_GET_CLASS(self);
+    
+    if(klass->start_file)
+        return (*klass->start_file)(self, jobInfo );
+    else
+        return FALSE;
+}
+
+gboolean 
+device_finish_file (Device * self)
+{
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+        g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
+                              FALSE);
+        g_return_val_if_fail (self->in_file, FALSE);
+
+       klass = DEVICE_GET_CLASS(self);
+
+       if(klass->finish_file)
+               return (*klass->finish_file)(self);
+       else
+               return FALSE;
+}
+
+dumpfile_t*
+device_seek_file (Device * self, guint file)
+{
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, NULL);
+       g_return_val_if_fail (IS_DEVICE (self), NULL);
+        g_return_val_if_fail (self->access_mode == ACCESS_READ,
+                              NULL);
+
+       klass = DEVICE_GET_CLASS(self);
+
+       if(klass->seek_file)
+               return (*klass->seek_file)(self,file);
+       else
+               return FALSE;
+}
+
+gboolean 
+device_seek_block (Device * self, guint64 block)
+{
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+        g_return_val_if_fail (self->access_mode == ACCESS_READ,
+                              FALSE);
+        g_return_val_if_fail (self->in_file, FALSE);
+
+       klass = DEVICE_GET_CLASS(self);
+
+       if(klass->seek_block)
+               return (*klass->seek_block)(self,block);
+       else
+               return FALSE;
+}
+
+int
+device_read_block (Device * self, gpointer buffer, int * size)
+{
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, -1);
+       g_return_val_if_fail (IS_DEVICE (self), -1);
+       g_return_val_if_fail (size != NULL, -1);
+        g_return_val_if_fail (self->access_mode == ACCESS_READ, -1);
+        if (*size != 0) {
+            g_return_val_if_fail (buffer != NULL, -1);
+        }
+
+        /* Do a quick check here, so fixed-block subclasses don't have to. */
+        if (*size == 0 &&
+            device_write_min_size(self) == device_write_max_size(self)) {
+            *size = device_write_min_size(self);
+            return 0;
+        }
+
+       klass = DEVICE_GET_CLASS(self);
+
+       if(klass->read_block)
+            return (*klass->read_block)(self,buffer,size);
+       else
+            return -1;
+}
+
+gboolean 
+device_read_to_fd (Device * self, int fd)
+{
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+       g_return_val_if_fail (fd >= 0, FALSE);
+        g_return_val_if_fail (self->access_mode == ACCESS_READ, FALSE);
+
+       klass = DEVICE_GET_CLASS(self);
+
+       if(klass->read_to_fd)
+               return (*klass->read_to_fd)(self,fd);
+       else
+               return FALSE;
+}
+
+
+gboolean 
+device_property_get (Device * self, DevicePropertyId id, GValue * val)
+{
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+        g_return_val_if_fail (device_property_get_by_id(id) != NULL, FALSE);
+
+       klass = DEVICE_GET_CLASS(self);
+
+        /* FIXME: Check access flags? */
+
+       if(klass->property_get)
+               return (*klass->property_get)(self,id,val);
+       else
+               return FALSE;
+}
+
+gboolean 
+device_property_set (Device * self, DevicePropertyId id, GValue * val)
+{
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+
+       klass = DEVICE_GET_CLASS(self);
+
+        /* FIXME: Check access flags? */
+
+       if(klass->property_set)
+               return (*klass->property_set)(self,id,val);
+       else
+               return FALSE;
+}
+
+gboolean 
+device_recycle_file (Device * self, guint filenum)
+{
+       DeviceClass *klass;
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (IS_DEVICE (self), FALSE);
+        g_return_val_if_fail (self->access_mode == ACCESS_APPEND, FALSE);
+
+       klass = DEVICE_GET_CLASS(self);
+
+       if(klass->recycle_file)
+               return (*klass->recycle_file)(self,filenum);
+       else
+               return FALSE;
+}
+
diff --git a/device-src/device.h b/device-src/device.h
new file mode 100644 (file)
index 0000000..262be39
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* The Device API abstracts device workings, interaction, properties, and
+ * capabilities from the rest of the Amanda code base. It supports
+ * pluggable modules for different kinds of devices. */
+
+#ifndef DEVICE_H
+#define DEVICE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "property.h"
+#include "fileheader.h"
+
+/* Device API version. */
+#define DEVICE_API_VERSION 0
+
+extern void device_api_init(void);
+
+/* Different access modes */
+typedef enum {
+    ACCESS_NULL, /* Device is not yet opened. */
+    ACCESS_READ,
+    ACCESS_WRITE,
+    ACCESS_APPEND
+} DeviceAccessMode;
+
+#define IS_WRITABLE_ACCESS_MODE(mode) ((mode) == ACCESS_WRITE || \
+                                       (mode) == ACCESS_APPEND)
+
+/* Device object definition follows. */
+
+/*
+ * Type checking and casting macros
+ */
+#define TYPE_DEVICE    (device_get_type())
+#define DEVICE(obj)    G_TYPE_CHECK_INSTANCE_CAST((obj), device_get_type(), Device)
+#define DEVICE_CONST(obj)      G_TYPE_CHECK_INSTANCE_CAST((obj), device_get_type(), Device const)
+#define DEVICE_CLASS(klass)    G_TYPE_CHECK_CLASS_CAST((klass), device_get_type(), DeviceClass)
+#define IS_DEVICE(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), device_get_type ())
+
+#define DEVICE_GET_CLASS(obj)  G_TYPE_INSTANCE_GET_CLASS((obj), device_get_type(), DeviceClass)
+
+typedef struct DevicePrivate_s DevicePrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct {
+    GObject __parent__;
+
+    /* You can peek at the stuff below, but only subclasses should
+       change these values.*/
+
+    /* What file, block are we at? (and are we in the middle of a
+     * file?) This is automatically updated by
+     * the default implementations of start_file, finish_file,
+     * write_block, read_block, seek_file, and seek_block. */
+    int file;
+    guint64 block;
+    gboolean in_file;
+    /* Holds the user-specified device name. */
+    char * device_name;
+    /* Holds the user-specified access-mode. */
+    DeviceAccessMode access_mode;
+    /* In reading mode, FALSE unless all the data from the current file
+     * was successfully read. */
+    gboolean is_eof;
+    /* Holds the label and time of the currently-inserted volume,
+     * or NULL if it has not been read/written yet. */
+    char * volume_label;
+    char * volume_time;
+
+    DevicePrivate * private;
+} Device;
+
+/* Pointer to factory function for device types. The factory functions
+   take control of their arguments, which should be dynamically
+   allocated. The factory should call open_device() with this
+   device_name. */
+typedef Device* (*DeviceFactory)(char * device_type,
+                                 char * device_name);
+
+/* This function registers a new device with the allocation system.
+ * Call it after you register your type with the GLib type system.
+ * This function takes ownership of the strings inside device_prefix_list,
+ * but not the device_prefix_list itself. */
+extern void register_device(DeviceFactory factory,
+                            const char ** device_prefix_list);
+
+/* This structure is a Flags (bitwise OR of values). Zero indicates success;
+ * any other value indicates some kind of problem reading the label. If
+ * multiple bits are set, it does not necessarily indicate that /all/ of
+ * the specified issues occured, but rather that /at least one/ did. */
+typedef enum {
+    /* When changing, Also update read_label_status_flags_values in device.c */
+    READ_LABEL_STATUS_SUCCESS          = 0,
+    READ_LABEL_STATUS_DEVICE_MISSING   = (1 << 0),
+    READ_LABEL_STATUS_DEVICE_ERROR     = (1 << 1),
+    READ_LABEL_STATUS_VOLUME_MISSING   = (1 << 2),
+    READ_LABEL_STATUS_VOLUME_UNLABELED = (1 << 3),
+    READ_LABEL_STATUS_VOLUME_ERROR     = (1 << 4),
+    READ_LABEL_STATUS_FLAGS_MAX              = (1 << 5)
+} ReadLabelStatusFlags;
+
+#define READ_LABEL_STATUS_FLAGS_MASK (READ_LABEL_STATUS_MAX-1)
+#define READ_LABEL_STATUS_FLAGS_TYPE (read_label_status_flags_get_type())
+GType read_label_status_flags_get_type(void);
+
+/*
+ * Class definition
+ */
+typedef struct _DeviceClass DeviceClass;
+struct _DeviceClass {
+    GObjectClass __parent__;
+    gboolean (* open_device) (Device * self,
+                              char * device_name); /* protected */
+    ReadLabelStatusFlags (* read_label)(Device * self);
+    gboolean (* start) (Device * self, DeviceAccessMode mode,
+                        char * label, char * timestamp);
+    gboolean (* start_file) (Device * self, const dumpfile_t * info);
+    gboolean (* write_block) (Device * self, guint size, gpointer data,
+                              gboolean last_block);
+    gboolean (* write_from_fd) (Device * self, int fd);
+    gboolean (* finish_file) (Device * self);
+    dumpfile_t* (* seek_file) (Device * self, guint file);
+    gboolean (* seek_block) (Device * self, guint64 block);
+    int (* read_block) (Device * self, gpointer buf, int * size);
+    gboolean (* read_to_fd) (Device * self, int fd);
+    gboolean (* property_get) (Device * self, DevicePropertyId id,
+                               GValue * val);
+    gboolean (* property_set) (Device * self, DevicePropertyId id,
+                               GValue * val);
+    gboolean (* recycle_file) (Device * self, guint filenum);
+    gboolean (* finish) (Device * self);
+};
+
+
+/*
+ * Public methods
+ *
+ * Note to implementors: The default implementation of many of these
+ * methods does not follow the documentation. For example, the default
+ * implementation of device_read_block will always return -1, but
+ * nonetheless update the block index in the Device structure. In
+ * general, it is OK to chain up to the default implmentation after
+ * successfully implementing whatever appears below. The particulars
+ * of what the default implementations do is documented in device.c.
+ */
+GType  device_get_type (void);
+
+/* This is how you get a new Device. Pass in a device name like
+ * file:/path/to/storage, and (assuming everything goes OK) you will get
+ * back a nice happy Device* that you can do operations on. Note that you
+ * must device_start() it before you can do anything besides talk about
+ * properties or read the label. device_name remains the responsibility
+ * of the caller. */
+Device*        device_open     (char * device_name);
+
+/* This instructs the device to read the label on the current
+ * volume. device->volume_label will not be initalized until after this
+ * is called. You are encouraged to read the label only after setting any
+ * properties that may affect the label-reading process. */
+ReadLabelStatusFlags        device_read_label (Device * self);
+
+/* This tells the Device that it's OK to start reading and writing
+ * data. Before you call this, you can only call
+ * device_property_{get, set} and device_read_label. You can only call
+ * this a second time if you call device_finish() first.
+ *
+ * You should pass a label and timestamp if and only if you are
+ * opening in WRITE mode (not READ or APPEND). The label and timestamp
+ * remain the caller's responsibility in terms of memory management. The
+ * passed timestamp may be NULL, in which case it will be filled in with 
+ * the current time. */
+gboolean       device_start    (Device * self,
+                                 DeviceAccessMode mode, char * label,
+                                 char * timestamp);
+
+/* This undoes device_start, returning you to the NULL state. Do this
+ * if you want to (for example) change access mode.
+ * 
+ * Note to subclass implementors: Call this function first from your
+ * finalization function. */
+gboolean       device_finish   (Device * self);
+
+/* But you can't write any data until you call this function, too.
+ * This function does not take ownership of the passed dumpfile_t; you must
+ * free it yourself. */
+gboolean        device_start_file       (Device * self,
+                                         const dumpfile_t * jobInfo);
+
+guint           device_write_min_size   (Device * self);
+guint           device_write_max_size   (Device * self);
+guint           device_read_max_size   (Device * self);
+
+/* Does what you expect. size had better be inside the block size
+ * range, or this function will write nothing.
+ *
+ * The short_block parameter needs some additional explanation: If
+ * short_block is set to TRUE, then this function will accept a write
+ * smaller than the minimum block size, subject to the following
+ * caveats:
+ * % The block may be padded with NULL bytes, which will be present on
+ *   restore.
+ * % device_write_block will automatically call device_finish_file()
+ *   after writing this short block.
+ * It is permitted to use short_block with a block that is not short;
+ * in this case, it is equivalent to calling device_write() and then
+ * calling device_finish_file(). */
+gboolean       device_write_block      (Device * self,
+                                         guint size,
+                                         gpointer data,
+                                         gboolean short_block);
+
+/* This will drain the given fd (reading until EOF), and write the
+ * resulting data out to the device using maximally-sized blocks. */
+gboolean       device_write_from_fd    (Device * self,
+                                       int fd);
+
+/* Call this when you are finished writing a file. This function will
+ * write a filemark or the local equivalent, flush the buffers, and do
+ * whatever dirty work needs to be done at such a point in time. */
+gboolean       device_finish_file      (Device * self);
+
+/* For reading only: Seeks to the beginning of a particular
+ * filemark. Only do this when reading; opening in
+ * ACCESS_WRITE will start you out at the first file, and opening in
+ * ACCESS_APPEND will automatically seek to the end of the medium.
+ * 
+ * If the requested file doesn't exist, this function will seek to the
+ * next-numbered valid file. You can check where this function seeked to
+ * by examining the file field of the Device structure. If the requested
+ * file number is exactly one more than the last valid file, this
+ * function returns a TAPEEND header.
+ *
+ * If an error occurs or if the requested file is two or more beyond the
+ * last valid file, this function returns NULL.
+ *
+ * Example results for a volume that has only files 1 and 3:
+ * 1 -> Seeks to file 1
+ * 2 -> Seeks to file 3
+ * 3 -> Seeks to file 3
+ * 4 -> Returns TAPEEND
+ * 5 -> Returns NULL
+ *
+ * The returned dumpfile_t is yours to keep, at no extra charge. */
+dumpfile_t*    device_seek_file        (Device * self,
+                                       guint file);
+
+/* After you have called device_seek_file (and /only/ after having
+ * called device_seek_file), you can call this to seek to a particular
+ * block inside the file. It works like SEEK_SET, only in blocks. */
+gboolean       device_seek_block       (Device * self,
+                                       guint64 block);
+
+/* After you have called device_seek_file and/or device_seek_block,
+ * you can start calling this function. It always reads exactly one whole
+ * block at a time, however big that might be. You must pass in a buffer and
+ * specify its size. If the buffer is big enough, the read is
+ * performed, and both *size and the return value are equal to the
+ * number of bytes actually read. If the buffer is not big enough, then
+ * no read is performed, the function returns 0, and *size is set
+ * to the minimum buffer size required to read the next block. If an
+ * error occurs, the function returns -1  and *size is left unchanged.
+ * 
+ * It is not an error if buffer == NULL and *size == 0. This should be
+ * treated as a query as to the possible size of the next block. */
+int    device_read_block       (Device * self,
+                                 gpointer buffer,
+                                 int * size);
+
+/* This is the reading equivalent of device_write_from_fd(). It will
+ * read from the device from the current location until end of file,
+ * and drains the results out into the specified fd. Returns FALSE if
+ * there is a problem writing to the fd. */
+gboolean       device_read_to_fd       (Device * self,
+                                       int fd);
+
+/* This function tells you what properties are supported by this
+ * device, and when you are allowed to get and set them. The return
+ * value is an array of DeviceProperty structs. The last struct in
+ * the array is zeroed, so you know when the end is (check the
+ * pointer element "base"). The return value from this function on any
+ * given object (or physical device) should be invariant. */
+const DeviceProperty *         device_property_get_list        (Device * self);
+
+/* These functions get or set a particular property. The val should be
+ * compatible with the DevicePropertyBase associated with the given
+ * DevicePropertyId, and this function should only be called when
+ * DeviceProperty.access says it is OK. Otherwise you will get an
+ * error and not the tasty property action you wanted. */
+gboolean       device_property_get     (Device * self,
+                                         DevicePropertyId id,
+                                         GValue * val);
+gboolean       device_property_set     (Device * self,
+                                         DevicePropertyId id,
+                                         GValue * val);
+
+/* On devices that support it (check PROPERTY_PARTIAL_DELETION),
+ * this will free only the space associated with a particular file. 
+ * This way, you can apply a different retention policy to every file
+ * on the volume, appending new data at the end and recycling anywhere
+ * in the middle -- even simultaneously (via different Device
+ * handles)! Note that you generally can't recycle a file that is presently in
+ * use (being read or written).
+ *
+ * To use this, open the device as DEVICE_MODE_APPEND. But you don't
+ * have to call device_start_file(), unless you want to write some
+ * data, too. */
+gboolean       device_recycle_file     (Device * self,
+                                       guint filenum);
+
+/* Protected methods. Don't call these except in subclass implementations. */
+
+/* Registers a new device / property pair. Every superclass of Device
+ * should call this in its init() function. At the moment, any
+ * particular property Id can only be registered once per object.
+ *
+ * If you want to register a standard response to a property (e.g.,
+ * whether or not the device supports compression), you can pass a
+ * non-NULL response. Then the default implementation of
+ * device_get_property (which you may override) will return this
+ * response.
+ * The contents of prop and response are copied into a private array, so the
+ * calling function retains ownership of all arguments.
+ */
+void            device_add_property(Device * self, DeviceProperty * prop,
+                                    GValue * response);
+
+/* This method provides post-construction initalization once the
+ * device name is known. It should only be used by Device
+ * factories. It is provided here as a virtual method (instead of
+ * a static function) because some devices may want to chain
+ * initilization to their parents. */
+gboolean device_open_device (Device * self,
+                             char * device_name);
+
+/* Builds a proper header based on device block size possibilities.
+ * If non-null, size is filled in with the number of bytes that should
+ * be written.
+ * If non-null, oneblock is filled in with TRUE if the header will fit
+ * in a single Device block (FALSE otherwise). */
+char * device_build_amanda_header(Device * self, const dumpfile_t * jobinfo,
+                                  int * size, gboolean * oneblock);
+
+/* Does what you expect. You have to free the returned header. Ensures
+   that self->volume_time matches the header written to tape. */
+dumpfile_t * make_tapestart_header(Device * self, char * label,
+                                   char * timestamp);
+
+/* Does what you expect. Uses the current time. */
+dumpfile_t * make_tapeend_header(void);
+
+/* Set up first-run properties from loaded configuration file, including
+ * DEVICE_MAX_VOLUME_USAGE property based on the tapetype. */
+void device_set_startup_properties_from_config(Device * device);
+
+/* Erase any stored volume information. Use this if something happens (e.g.,
+ * a property is set) that voids previously-read volume details.
+ * This function is a NOOP unless the device is in the NULL state. */
+void device_clear_volume_details(Device * device);
+
+#endif /* DEVICE_H */
diff --git a/device-src/null-device.c b/device-src/null-device.c
new file mode 100644 (file)
index 0000000..a6b1a02
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include "amanda.h"
+#include "device.h"
+#include "null-device.h"
+
+#define NULL_DEVICE_MIN_BLOCK_SIZE (1)
+#define NULL_DEVICE_MAX_BLOCK_SIZE SHRT_MAX
+
+/* here are local prototypes */
+static void null_device_init (NullDevice * o);
+static void null_device_class_init (NullDeviceClass * c);
+static gboolean null_device_start (Device * self, DeviceAccessMode mode,
+                                   char * label, char * timestamp);
+static gboolean null_device_write_block (Device * self, guint size,
+                                         gpointer data, gboolean last);
+static Device* null_device_factory(char * device_type,
+                                   char * device_name);
+
+/* pointer to the class of our parent */
+static DeviceClass *parent_class = NULL;
+
+void null_device_register(void) {
+    static const char * device_prefix_list[] = { "null", NULL };
+    register_device(null_device_factory, device_prefix_list);
+}
+
+GType
+null_device_get_type (void)
+{
+    static GType type = 0;
+    
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (NullDeviceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) null_device_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (NullDevice),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) null_device_init,
+            NULL
+        };
+        
+        type = g_type_register_static (TYPE_DEVICE, "NullDevice", &info,
+                                       (GTypeFlags)0);
+    }
+
+    return type;
+}
+
+static void 
+null_device_init (NullDevice * self)
+{
+    Device * o;
+    DeviceProperty prop;
+    GValue response;
+
+    o = (Device*)(self);
+    bzero(&response, sizeof(response));
+
+    /* Register properties */
+    prop.base = &device_property_concurrency;
+    prop.access = PROPERTY_ACCESS_GET_MASK;
+    g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
+    g_value_set_enum(&response, CONCURRENCY_PARADIGM_RANDOM_ACCESS);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+    
+
+    prop.base = &device_property_streaming;
+    g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
+    g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+    
+    prop.base = &device_property_block_size;
+    g_value_init(&response, G_TYPE_INT);
+    g_value_set_int(&response, -1);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+    
+    prop.base = &device_property_min_block_size;
+    g_value_init(&response, G_TYPE_UINT);
+    g_value_set_uint(&response, NULL_DEVICE_MIN_BLOCK_SIZE);
+    device_add_property(o, &prop, &response);
+
+    prop.base = &device_property_max_block_size;
+    g_value_set_uint(&response, NULL_DEVICE_MAX_BLOCK_SIZE);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_appendable;
+    g_value_init(&response, G_TYPE_BOOLEAN);
+    g_value_set_boolean(&response, FALSE);
+    device_add_property(o, &prop, &response);
+
+    prop.base = &device_property_partial_deletion;
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_canonical_name;
+    g_value_init(&response, G_TYPE_STRING);
+    g_value_set_static_string(&response, "null:");
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_medium_access_type;
+    g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
+    g_value_set_enum(&response, MEDIA_ACCESS_MODE_WRITE_ONLY);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+}
+
+static void 
+null_device_class_init (NullDeviceClass * c G_GNUC_UNUSED)
+{
+    DeviceClass *device_class = (DeviceClass *)c;
+
+    parent_class = g_type_class_ref (TYPE_DEVICE);
+
+    device_class->start = null_device_start;
+    device_class->write_block = null_device_write_block;
+}
+
+
+static Device* null_device_factory(char * device_type,
+                                   char * device_name G_GNUC_UNUSED) {
+    g_assert(0 == strcmp(device_type, "null"));
+    return DEVICE(g_object_new(TYPE_NULL_DEVICE, NULL));
+    
+}
+
+/* Begin virtual function overrides */
+
+static gboolean 
+null_device_start (Device * pself, DeviceAccessMode mode,
+                   char * label, char * timestamp) {
+    NullDevice * self;
+    self = NULL_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, FALSE);
+
+    if (mode == ACCESS_WRITE) {
+        if (parent_class->start) {
+            return parent_class->start((Device*)self, mode, label, timestamp);
+        } else {
+            return TRUE;
+        }
+    } else {
+        g_fprintf(stderr, "Can't open NULL device for reading or appending.\n");
+        return FALSE;
+    }
+}
+
+static gboolean
+null_device_write_block (Device * pself, guint size, gpointer data,
+                         gboolean last_block) {
+    NullDevice * self;
+    self = NULL_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (data != NULL, FALSE);
+    
+    if ((size < NULL_DEVICE_MIN_BLOCK_SIZE && !last_block) ||
+        size > NULL_DEVICE_MAX_BLOCK_SIZE) {
+        return FALSE;
+    } else {
+        if (parent_class->write_block) {
+            /* Calls device_finish_file(). */
+            parent_class->write_block((Device*)self, size, data, last_block);
+        }
+        return TRUE;
+    }
+
+    g_assert_not_reached();
+}
diff --git a/device-src/null-device.h b/device-src/null-device.h
new file mode 100644 (file)
index 0000000..b68a824
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* The NULL device accepts data and sends it to the bit bucket. Like
+   /dev/null, you cannot read from the NULL device -- only
+   write. While useful for testing, the NULL device is incredibly
+   dangerous in practice (because it eats your data). So it will
+   generate warnings whenever you use it. */
+
+#include <glib.h>
+#include <glib-object.h>
+#ifndef __NULL_DEVICE_H__
+#define __NULL_DEVICE_H__
+
+/* This header file is very boring, because the class just overrides
+   existing methods. */
+
+/*
+ * Type checking and casting macros
+ */
+#define TYPE_NULL_DEVICE       (null_device_get_type())
+#define NULL_DEVICE(obj)       G_TYPE_CHECK_INSTANCE_CAST((obj), null_device_get_type(), NullDevice)
+#define NULL_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), null_device_get_type(), NullDevice const)
+#define NULL_DEVICE_CLASS(klass)       G_TYPE_CHECK_CLASS_CAST((klass), null_device_get_type(), NullDeviceClass)
+#define IS_NULL_DEVICE(obj)    G_TYPE_CHECK_INSTANCE_TYPE((obj), null_device_get_type ())
+
+#define NULL_DEVICE_GET_CLASS(obj)     G_TYPE_INSTANCE_GET_CLASS((obj), null_device_get_type(), NullDeviceClass)
+
+/*
+ * Main object structure
+ */
+#ifndef __TYPEDEF_NULL_DEVICE__
+#define __TYPEDEF_NULL_DEVICE__
+typedef struct _NullDevice NullDevice;
+#endif
+struct _NullDevice {
+       Device __parent__;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _NullDeviceClass NullDeviceClass;
+struct _NullDeviceClass {
+    DeviceClass __parent__;
+    gboolean in_file;
+};
+
+
+/*
+ * Public methods
+ */
+GType  null_device_get_type    (void);
+void    null_device_register    (void);
+
+#endif
diff --git a/device-src/property.c b/device-src/property.c
new file mode 100644 (file)
index 0000000..3980a3f
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include "amanda.h"
+
+#include "property.h"
+
+static const GEnumValue _concurrency_paradigm_values[] = {
+        { CONCURRENCY_PARADIGM_EXCLUSIVE,
+          "CONCURRENCY_PARADIGM_EXCLUSIVE",
+          "exclusive" },
+        { CONCURRENCY_PARADIGM_SHARED_READ, 
+          "CONCURRENCY_PARADIGM_SHARED_READ",
+          "shared-read" },
+        { CONCURRENCY_PARADIGM_RANDOM_ACCESS,
+          "CONCURRENCY_PARADIGM_RANDOM_ACCESS",
+          "random-access" },
+        { 0, NULL, NULL }
+};
+
+GType concurrency_paradigm_get_type (void) {
+    static GType type = 0;
+    if (G_UNLIKELY(type == 0)) {
+        type = g_enum_register_static ("ConcurrencyParadigm",
+                                       _concurrency_paradigm_values);
+    }
+    return type;
+}
+
+static const GEnumValue _streaming_requirement_values[] = {
+        { STREAMING_REQUIREMENT_NONE,
+          "STREAMING_REQUIREMENT_NONE",
+          "none" },
+        { STREAMING_REQUIREMENT_DESIRED,
+          "STREAMING_REQUIREMENT_DESIRED",
+          "desired" },
+        { STREAMING_REQUIREMENT_REQUIRED,
+          "STREAMING_REQUIREMENT_REQUIRED",
+          "required" },
+        { 0, NULL, NULL }
+};
+
+GType streaming_requirement_get_type (void) {
+    static GType type = 0;
+    if (G_UNLIKELY(type == 0)) {
+        type = g_enum_register_static ("StreamingRequirement",
+                                       _streaming_requirement_values);
+    }
+    return type;
+}
+
+static const GEnumValue _media_access_mode_values[] = {
+        { MEDIA_ACCESS_MODE_READ_ONLY,
+          "MEDIA_ACCESS_MODE_READ_ONLY",
+          (char *)"read-only" },
+        { MEDIA_ACCESS_MODE_WORM,
+          "MEDIA_ACCESS_MODE_WORM",
+          (char *)"write-once-read-many" },
+        { MEDIA_ACCESS_MODE_READ_WRITE,
+          "MEDIA_ACCESS_MODE_READ_WRITE",
+          (char *)"read-write" },
+        { MEDIA_ACCESS_MODE_WRITE_ONLY,
+          "MEDIA_ACCESS_MODE_WRITE_ONLY",
+          (char *)"write-many-read-never" },
+        { 0, NULL, NULL }
+};
+
+GType media_access_mode_get_type (void) {
+    static GType type = 0;
+    if (G_UNLIKELY(type == 0)) {
+        type = g_enum_register_static ("MediaAccessMode",
+                                       _media_access_mode_values);
+    }
+    return type;
+}
+
+/* Copy function for GBoxed QualifiedSize. */
+static gpointer qualified_size_copy(gpointer source) {
+    gpointer rval = malloc(sizeof(QualifiedSize));
+    memcpy(rval, source, sizeof(QualifiedSize));
+    return rval;
+}
+
+GType qualified_size_get_type (void) {
+    static GType type = 0;
+    if (G_UNLIKELY(type == 0)) {
+        type = g_boxed_type_register_static ("QualifiedSize",
+                                             qualified_size_copy,
+                                             free);
+    }
+    return type;
+}
+
+static const GFlagsValue _feature_support_flags_values[] = {
+    { FEATURE_STATUS_ENABLED,
+      "FEATURE_STATUS_ENABLED",
+      "enabled" },
+    { FEATURE_STATUS_DISABLED,
+      "FEATURE_STATUS_DISABLED",
+      "disabled" },
+    { FEATURE_SURETY_BAD,
+      "FEATURE_SURETY_BAD",
+      "bad" },
+    { FEATURE_SURETY_GOOD,
+      "FEATURE_SURETY_GOOD",
+      "good" },
+    { FEATURE_SOURCE_DEFAULT,
+      "FEATURE_SOURCE_DEFAULT",
+      "default" },
+    { FEATURE_SOURCE_DETECTED,
+      "FEATURE_SOURCE_DETECTED",
+      "detected" },
+    { FEATURE_SOURCE_USER,
+      "FEATURE_SOURCE_USER",
+      "user"},
+    { 0, NULL, NULL }
+};
+
+GType feature_support_get_type (void) {
+    static GType type = 0;
+    if (G_UNLIKELY(type == 0)) {
+        type = g_flags_register_static ("FeatureSupportFlags",
+                                        _feature_support_flags_values);
+    }
+    return type;
+}
+
+gboolean feature_support_flags_is_valid(FeatureSupportFlags f) {
+    int status = 0, surety = 0, source = 0;
+
+    if (f & FEATURE_STATUS_ENABLED)
+        status ++;
+    if (f & FEATURE_STATUS_DISABLED)
+        status ++;
+    if (f & FEATURE_SURETY_BAD)
+        surety ++;
+    if (f & FEATURE_SURETY_GOOD)
+        surety ++;
+    if (f & FEATURE_SOURCE_DEFAULT)
+        source ++;
+    if (f & FEATURE_SOURCE_DETECTED)
+        source ++;
+    if (f & FEATURE_SOURCE_USER)
+        source ++;
+
+    return (!(f & ~FEATURE_SUPPORT_FLAGS_MASK) &&
+            status == 1  &&  surety == 1  &&  source == 1);
+}
+
+static GSList* device_property_base_list = NULL;
+
+const DevicePropertyBase* device_property_get_by_id(DevicePropertyId id) {
+    GSList *iter;
+
+    iter = device_property_base_list;
+    while (iter != NULL) {
+        DevicePropertyBase* rval = (DevicePropertyBase*)(iter->data);
+        if (rval->ID == id) {
+            return rval;
+        }
+        iter = g_slist_next(iter);
+    }
+
+    return NULL;
+}
+
+const DevicePropertyBase* device_property_get_by_name(const char *name) {
+    GSList *iter = device_property_base_list;
+
+    g_return_val_if_fail(name != NULL, NULL);
+
+    while (iter != NULL) {
+        DevicePropertyBase* rval = (DevicePropertyBase*)(iter->data);
+        if (strcasecmp(rval->name, name) == 0) {
+            return rval;
+        }
+        iter = g_slist_next(iter);
+    }
+
+    return NULL;
+}
+
+DevicePropertyId device_property_register(DevicePropertyBase* base) {
+    static guint id = 0;
+    g_assert(base != NULL);
+    g_assert(base->ID == -1);
+    g_assert(base->name != NULL);
+    g_assert(base->description != NULL);
+    
+    base->ID = id++;
+
+    device_property_base_list = g_slist_prepend(device_property_base_list,
+                                                base);
+    return id;
+}
+
+/* Does the same thing, but fills in a new DevicePropertyBase. */
+static void
+device_property_fill_and_register(DevicePropertyBase * base,
+                                  GType type,
+                                  const char * name,
+                                  const char * desc) {
+    base->type = type;
+    base->name = name;
+    base->description = desc;
+    base->ID = -1;
+    device_property_register(base);
+}
+
+
+void device_property_init(void) {
+    device_property_fill_and_register(&device_property_concurrency,
+                                      CONCURRENCY_PARADIGM_TYPE, "concurrency",
+      "Supported concurrency mode (none, multiple readers, multiple writers)");
+    device_property_fill_and_register(&device_property_streaming,
+                                      STREAMING_REQUIREMENT_TYPE, "streaming",
+      "Streaming desirability (unnecessary, desired, required)");
+    device_property_fill_and_register(&device_property_compression,
+                                      G_TYPE_BOOLEAN, "compression",
+      "Is device performing data compression?");
+    device_property_fill_and_register(&device_property_compression_rate,
+                                      G_TYPE_DOUBLE, "compression_rate",
+      "Compression rate, "
+          "averaged for some (currently undefined) period of time)");
+    device_property_fill_and_register(&device_property_block_size,
+                                      G_TYPE_INT, "block_size",
+                                      "Device blocking factor in bytes.");
+    device_property_fill_and_register(&device_property_min_block_size,
+                                      G_TYPE_UINT, "min_block_size",
+      "Minimum supported blocking factor.");
+    device_property_fill_and_register(&device_property_max_block_size,
+                                      G_TYPE_UINT, "max_block_size",
+      "Maximum supported blocking factor.");
+    device_property_fill_and_register(&device_property_appendable,
+                                      G_TYPE_BOOLEAN, "appendable",
+      "Does device support appending to previously-written media?");
+    device_property_fill_and_register(&device_property_canonical_name,
+                                      G_TYPE_STRING, "canonical_name",
+      "The most reliable device name to use to refer to this device.");
+    device_property_fill_and_register(&device_property_medium_access_type,
+                                      MEDIA_ACCESS_MODE_TYPE,
+                                      "medium_access_type",
+      "What kind of media (RO/WORM/RW/WORN) do we have here?");
+    device_property_fill_and_register(&device_property_partial_deletion,
+                                     G_TYPE_BOOLEAN, "partial_deletion",
+      "Does this device support recycling just part of a volume?" );
+    device_property_fill_and_register(&device_property_free_space,
+                                      QUALIFIED_SIZE_TYPE, "free_space",
+      "Remaining capacity of the device.");
+    device_property_fill_and_register(&device_property_max_volume_usage,
+                                      G_TYPE_UINT64, "max_volume_usage",
+      "Artificial limit to data written to volume.");
+    device_property_fill_and_register(&device_property_fsf,
+                                      FEATURE_SUPPORT_FLAGS_TYPE, "fsf",
+      "Does this drive support the MTFSF command?");
+    device_property_fill_and_register(&device_property_bsf,
+                                      FEATURE_SUPPORT_FLAGS_TYPE, "bsf",
+      "Does this drive support the MTBSF command?" );
+    device_property_fill_and_register(&device_property_fsr,
+                                      FEATURE_SUPPORT_FLAGS_TYPE, "fsr",
+      "Does this drive support the MTFSR command?");
+    device_property_fill_and_register(&device_property_bsr,
+                                      FEATURE_SUPPORT_FLAGS_TYPE, "bsr",
+      "Does this drive support the MTBSR command?");
+    /* FIXME: Is this feature even useful? */
+    device_property_fill_and_register(&device_property_eom,
+                                      FEATURE_SUPPORT_FLAGS_TYPE, "eom",
+      "Does this drive support the MTEOM command?");
+    device_property_fill_and_register(&device_property_bsf_after_eom,
+                                      FEATURE_SUPPORT_FLAGS_TYPE,
+                                      "bsf_after_eom",
+      "Does this drive require an MTBSF after MTEOM in order to append?" );
+    device_property_fill_and_register(&device_property_final_filemarks,
+                                      G_TYPE_UINT, "final_filemarks",
+      "How many filemarks to write after the last tape file?" );
+    device_property_fill_and_register(&device_property_read_buffer_size,
+                                      G_TYPE_UINT, "read_buffer_size",
+      "What buffer size should be used for reading?");
+    device_property_fill_and_register(&device_property_s3_secret_key,
+                                      G_TYPE_STRING, "s3_secret_key",
+       "Secret access key to authenticate with Amazon S3");
+    device_property_fill_and_register(&device_property_s3_access_key,
+                                      G_TYPE_STRING, "s3_access_key",
+       "Access key ID to authenticate with Amazon S3");
+#ifdef WANT_DEVPAY
+    device_property_fill_and_register(&device_property_s3_user_token,
+                                      G_TYPE_STRING, "s3_user_token",
+       "User token for authentication Amazon devpay requests");
+#endif
+    device_property_fill_and_register(&device_property_verbose,
+                                     G_TYPE_BOOLEAN, "verbose",
+       "Should the device produce verbose output?");
+}
+
+DevicePropertyBase device_property_concurrency;
+DevicePropertyBase device_property_streaming;
+DevicePropertyBase device_property_compression;
+DevicePropertyBase device_property_compression_rate;
+DevicePropertyBase device_property_block_size;
+DevicePropertyBase device_property_min_block_size;
+DevicePropertyBase device_property_max_block_size;
+DevicePropertyBase device_property_appendable;
+DevicePropertyBase device_property_canonical_name;
+DevicePropertyBase device_property_medium_access_type;
+DevicePropertyBase device_property_partial_deletion;
+DevicePropertyBase device_property_free_space;
+DevicePropertyBase device_property_max_volume_usage;
+DevicePropertyBase device_property_fsf;
+DevicePropertyBase device_property_bsf;
+DevicePropertyBase device_property_fsr;
+DevicePropertyBase device_property_bsr;
+DevicePropertyBase device_property_eom;
+DevicePropertyBase device_property_bsf_after_eom;
+DevicePropertyBase device_property_final_filemarks;
+DevicePropertyBase device_property_read_buffer_size;
+DevicePropertyBase device_property_s3_access_key;
+DevicePropertyBase device_property_s3_secret_key;
+DevicePropertyBase device_property_s3_user_token;
+DevicePropertyBase device_property_verbose;
diff --git a/device-src/property.h b/device-src/property.h
new file mode 100644 (file)
index 0000000..8138a05
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#ifndef DEVICE_PROPERTY_H
+#define DEVICE_PROPERTY_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+/* The properties interface defines define capabilities and other interesting
+ * properties. */
+
+typedef enum {
+    PROPERTY_PHASE_BEFORE_START       = (1 << 0),
+    PROPERTY_PHASE_BETWEEN_FILE_WRITE = (1 << 1),
+    PROPERTY_PHASE_INSIDE_FILE_WRITE  = (1 << 2),
+    PROPERTY_PHASE_BETWEEN_FILE_READ  = (1 << 3),
+    PROPERTY_PHASE_INSIDE_FILE_READ   = (1 << 4),
+    PROPERTY_PHASE_MAX                = (1 << 5)
+} PropertyPhaseFlags;
+
+#define PROPERTY_PHASE_MASK (PROPERTY_PHASE_MAX-1)
+#define PROPERTY_PHASE_SHIFT (PROPERTY_PHASE_MASK/2)
+
+typedef enum {
+    PROPERTY_ACCESS_GET_BEFORE_START = (PROPERTY_PHASE_BEFORE_START),
+    PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE =
+        (PROPERTY_PHASE_BETWEEN_FILE_WRITE),
+    PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE = (PROPERTY_PHASE_INSIDE_FILE_WRITE),
+    PROPERTY_ACCESS_GET_BETWEEN_FILE_READ =
+        (PROPERTY_PHASE_BETWEEN_FILE_READ),
+    PROPERTY_ACCESS_GET_INSIDE_FILE_READ = (PROPERTY_PHASE_INSIDE_FILE_READ),
+
+    PROPERTY_ACCESS_SET_BEFORE_START =
+        (PROPERTY_PHASE_BEFORE_START << PROPERTY_PHASE_SHIFT),
+    PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE =
+        (PROPERTY_PHASE_BETWEEN_FILE_WRITE << PROPERTY_PHASE_SHIFT),
+    PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE =
+        (PROPERTY_PHASE_INSIDE_FILE_WRITE << PROPERTY_PHASE_SHIFT),
+    PROPERTY_ACCESS_SET_BETWEEN_FILE_READ =
+        (PROPERTY_PHASE_BETWEEN_FILE_READ << PROPERTY_PHASE_SHIFT),
+    PROPERTY_ACCESS_SET_INSIDE_FILE_READ =
+        (PROPERTY_PHASE_INSIDE_FILE_READ << PROPERTY_PHASE_SHIFT)
+} PropertyAccessFlags;
+
+#define PROPERTY_ACCESS_GET_MASK (PROPERTY_PHASE_MASK)
+#define PROPERTY_ACCESS_SET_MASK (PROPERTY_PHASE_MASK << PROPERTY_PHASE_SHIFT)
+
+
+/* This structure is usually statically allocated.
+ * It holds information about a property that is common to all devices of
+ * a given type. */
+
+typedef int DevicePropertyId;
+
+typedef struct {
+    DevicePropertyId ID; /* Set by device_property_register() */
+    GType type;
+    const char *name;
+    const char *description;
+} DevicePropertyBase;
+
+/* This structure is usually held inside a Device object. It holds
+ * information about a property that is specific to the device/medium
+ * in question. */
+typedef struct {
+    const DevicePropertyBase *base;
+    PropertyAccessFlags access;
+} DeviceProperty;
+
+/* Registers a new property and returns its ID. This function takes ownership
+ * of its argument; it must not be freed later. */
+extern DevicePropertyId device_property_register(DevicePropertyBase*);
+
+/* This should be called exactly once from device_api_init(). */
+extern void device_property_init(void);
+
+/* Gets a DevicePropertyBase from its ID. */
+extern const DevicePropertyBase* device_property_get_by_id(DevicePropertyId);
+extern const DevicePropertyBase* device_property_get_by_name(const char*);
+
+/* Standard property value types here.
+ * Important: see property.c for the other half of type declarations.*/
+typedef enum {
+    CONCURRENCY_PARADIGM_EXCLUSIVE,
+    CONCURRENCY_PARADIGM_SHARED_READ,
+    CONCURRENCY_PARADIGM_RANDOM_ACCESS
+} ConcurrencyParadigm;
+#define CONCURRENCY_PARADIGM_TYPE concurrency_paradigm_get_type()
+GType concurrency_paradigm_get_type (void);
+
+typedef enum {
+    STREAMING_REQUIREMENT_NONE,
+    STREAMING_REQUIREMENT_DESIRED,
+    STREAMING_REQUIREMENT_REQUIRED
+} StreamingRequirement;
+#define STREAMING_REQUIREMENT_TYPE streaming_requirement_get_type()
+GType streaming_requirement_get_type (void);
+
+typedef enum {
+    MEDIA_ACCESS_MODE_READ_ONLY,
+    MEDIA_ACCESS_MODE_WORM,
+    MEDIA_ACCESS_MODE_READ_WRITE,
+    MEDIA_ACCESS_MODE_WRITE_ONLY
+} MediaAccessMode;
+#define MEDIA_ACCESS_MODE_TYPE media_access_mode_get_type()
+GType media_access_mode_get_type (void);
+
+/* This one is not a Glibified enum */
+typedef enum {
+    SIZE_ACCURACY_UNKNOWN,
+    SIZE_ACCURACY_ESTIMATE,
+    SIZE_ACCURACY_REAL
+} SizeAccuracy;
+
+/* But SizeAccuracy does apear in this Glibified (gBoxed) struct. */
+typedef struct {
+    SizeAccuracy accuracy;
+    guint64           bytes;
+} QualifiedSize;
+#define QUALIFIED_SIZE_TYPE qualified_size_get_type()
+GType qualified_size_get_type (void);
+
+/* Some features can only be occasionally (or unreliably) detected, so
+   this enum allows the user to override the detected or default
+   setting. */
+typedef enum {
+    /* Feature support status. (exactly one of these is set) */
+        /* Feature is supported & will be used */
+        FEATURE_STATUS_ENABLED   = (1 << 0),
+        /* Features will not be used. */
+        FEATURE_STATUS_DISABLED  = (1 << 1),
+
+    /* Feature support confidence. (exactly one of these is set). */
+        /* Support is not based on conclusive evidence. */
+        FEATURE_SURETY_BAD       = (1 << 2),
+        /* Support is based on conclusive evidence. */
+        FEATURE_SURETY_GOOD      = (1 << 3),
+
+   /* Source of this information. (exactly one of these is set). */
+        /* Source of status is from default setting. */
+        FEATURE_SOURCE_DEFAULT   = (1 << 4),
+        /* Source of status is from device query. */
+        FEATURE_SOURCE_DETECTED  = (1 << 5),
+        /* Source of status is from user override. */
+        FEATURE_SOURCE_USER      = (1 << 6),
+
+    FEATURE_SUPPORT_FLAGS_MAX = (1 << 7)
+} FeatureSupportFlags;
+
+#define FEATURE_SUPPORT_FLAGS_MASK (FEATURE_SUPPORT_FLAGS_MAX-1)
+#define FEATURE_SUPPORT_FLAGS_STATUS_MASK (FEATURE_STATUS_ENABLED |  \
+                                           FEATURE_STATUS_DISABLED)
+#define FEATURE_SUPPORT_FLAGS_SURETY_MASK (FEATURE_SURETY_BAD |      \
+                                           FEATURE_SURETY_GOOD)
+#define FEATURE_SUPPORT_FLAGS_SOURCE_MASK (FEATURE_SOURCE_DEFAULT |  \
+                                           FEATURE_SOURCE_DETECTED | \
+                                           FEATURE_SOURCE_USER)
+/* Checks that mutually exclusive flags are not set. */
+gboolean feature_support_flags_is_valid(FeatureSupportFlags);
+#define FEATURE_SUPPORT_FLAGS_TYPE feature_support_get_type()
+GType feature_support_get_type (void);    
+
+/* Standard property definitions follow. See also property.c. */
+
+/* Value is a ConcurrencyParadigm */
+extern DevicePropertyBase device_property_concurrency;
+#define PROPERTY_CONCURRENCY (device_property_concurrency.ID)
+
+/* Value is a StreamingRequirement */
+extern DevicePropertyBase device_property_streaming;
+#define PROPERTY_STREAMING (device_property_streaming.ID)
+
+/* Value is a gboolean. */
+extern DevicePropertyBase device_property_compression;
+#define PROPERTY_COMPRESSION (device_property_compression.ID)
+
+/* Value is a gdouble, representing (compressed size)/(original
+   size). The period over which this value is measured is undefined. */
+extern DevicePropertyBase device_property_compression_rate;
+#define PROPERTY_COMPRESSION_RATE (device_property_compression_rate.ID)
+
+/* Value is a gint, where a negative number indicates variable block size. */
+extern DevicePropertyBase device_property_block_size;
+#define PROPERTY_BLOCK_SIZE (device_property_block_size.ID)
+
+/* Value is a guint. */
+extern DevicePropertyBase device_property_min_block_size;
+extern DevicePropertyBase device_property_max_block_size;
+#define PROPERTY_MIN_BLOCK_SIZE (device_property_min_block_size.ID)
+#define PROPERTY_MAX_BLOCK_SIZE (device_property_max_block_size.ID)
+
+/* Value is a gboolean. */
+extern DevicePropertyBase device_property_appendable;
+#define PROPERTY_APPENDABLE (device_property_appendable.ID)
+
+/* Value is a string. */
+extern DevicePropertyBase device_property_canonical_name;
+#define PROPERTY_CANONICAL_NAME (device_property_canonical_name.ID)
+
+/* Value is MediaAccessMode. */
+extern DevicePropertyBase device_property_medium_access_type;
+#define PROPERTY_MEDIUM_TYPE (device_property_medium_access_type.ID)
+
+/* Value is a gboolean. */
+extern DevicePropertyBase device_property_partial_deletion;
+#define PROPERTY_PARTIAL_DELETION (device_property_partial_deletion.ID)
+
+/* Value is a QualifiedSize, though the accuracy may be SIZE_ACCURACY_NONE. */
+extern DevicePropertyBase device_property_free_space;
+#define PROPERTY_FREE_SPACE (device_property_free_space.ID)
+
+/* Value is a guint64. On devices that support it, this property will
+   limit the total amount of data written to a volume; attempts to
+   write beyond this point will cause the device to simulate "out of
+   space". Zero means no limit. */
+extern DevicePropertyBase device_property_max_volume_usage;
+#define PROPERTY_MAX_VOLUME_USAGE (device_property_max_volume_usage.ID)
+
+/* Tape device properties. These properties do not exist on non-linear
+   devices. All of them have a value type of FeatureSupportFlags. */
+extern DevicePropertyBase device_property_fsf;
+#define PROPERTY_FSF (device_property_fsf.ID)
+
+extern DevicePropertyBase device_property_bsf;
+#define PROPERTY_BSF (device_property_bsf.ID)
+
+extern DevicePropertyBase device_property_fsr;
+#define PROPERTY_FSR (device_property_fsr.ID)
+
+extern DevicePropertyBase device_property_bsr;
+#define PROPERTY_BSR (device_property_bsr.ID)
+
+/* Is EOM supported? Must be able to read file number afterwards as
+   well. */
+extern DevicePropertyBase device_property_eom;
+#define PROPERTY_EOM (device_property_eom.ID)
+
+/* Is it necessary to perform a BSF after EOM? */
+extern DevicePropertyBase device_property_bsf_after_eom;
+#define PROPERTY_BSF_AFTER_EOM (device_property_bsf_after_eom.ID)
+
+/* How many filemarks to write at EOD? (Default is 2).
+ * This property is a G_TYPE_UINT, but can only really be set to 1 or 2. */
+extern DevicePropertyBase device_property_final_filemarks;
+#define PROPERTY_FINAL_FILEMARKS (device_property_final_filemarks.ID)
+
+/* What buffer size is used for reading? */
+extern DevicePropertyBase device_property_read_buffer_size;
+#define PROPERTY_READ_BUFFER_SIZE (device_property_read_buffer_size.ID)
+
+/* Authentication information for Amazon S3. Both of these are strings. */
+extern DevicePropertyBase device_property_s3_secret_key;
+extern DevicePropertyBase device_property_s3_access_key;
+#define PROPERTY_S3_SECRET_KEY (device_property_s3_secret_key.ID)
+#define PROPERTY_S3_ACCESS_KEY (device_property_s3_access_key.ID)
+
+#ifdef WANT_DEVPAY
+/* Same, but for S3 with DevPay. This directory can be relative to the
+ * config director, or absolute. */
+extern DevicePropertyBase device_property_s3_user_token;
+#define PROPERTY_S3_USER_TOKEN (device_property_s3_user_token.ID)
+#endif
+
+/* Should the device produce verbose output?  Value is a gboolean.  Not
+ * recognized by all devices. */
+extern DevicePropertyBase device_property_verbose;
+#define PROPERTY_VERBOSE (device_property_verbose.ID)
+
+#endif
diff --git a/device-src/queueing.c b/device-src/queueing.c
new file mode 100644 (file)
index 0000000..2ec0e8c
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include "queueing.h"
+#include "device.h"
+#include "semaphore.h"
+#include "amanda.h"
+
+/* Queueing framework here. */
+typedef struct {
+    guint block_size;
+    ProducerFunctor producer;
+    gpointer producer_user_data;
+    ConsumerFunctor consumer;
+    gpointer consumer_user_data;
+    GAsyncQueue *data_queue, *free_queue;
+    semaphore_t *free_memory;
+    StreamingRequirement streaming_mode;
+} queue_data_t;
+
+static queue_buffer_t *invent_buffer(void) {
+    queue_buffer_t *rval;
+    rval = malloc(sizeof(*rval));
+
+    rval->data = NULL;
+    rval->alloc_size = 0;
+    rval->data_size = 0;
+    rval->offset = 0;
+
+    return rval;
+}
+
+void free_buffer(queue_buffer_t *buf) {
+    if (buf != NULL)
+        amfree(buf->data);
+    amfree(buf);
+}
+
+static queue_buffer_t * merge_buffers(queue_buffer_t *buf1,
+                                      queue_buffer_t *buf2) {
+    if (buf1 == NULL)
+        return buf2;
+    else if (buf2 == NULL)
+        return buf1;
+
+    if (buf2->offset >= buf1->data_size) {
+        /* We can fit buf1 at the beginning of buf2. */
+        memcpy(buf2->data + buf2->offset - buf1->data_size,
+               buf1->data + buf1->offset,
+               buf1->data_size);
+        buf2->offset -= buf1->data_size;
+        buf2->data_size += buf1->data_size;
+        free_buffer(buf1);
+        return buf2;
+    } else if (buf1->alloc_size - buf1->offset - buf1->data_size
+               >= buf2->data_size) {
+        /* We can fit buf2 at the end of buf1. */
+        memcpy(buf1->data + buf1->offset + buf1->data_size,
+               buf2->data + buf2->offset, buf2->data_size);
+        buf1->data_size += buf2->data_size;
+        free_buffer(buf2);
+        return buf1;
+    } else {
+        /* We can grow buf1 and put everything there. */
+        if (buf1->offset != 0) {
+            /* But first we have to fix up buf1. */
+            memmove(buf1->data, buf1->data + buf1->offset, buf1->data_size);
+            buf1->offset = 0;
+        }
+        buf1->alloc_size = buf1->data_size + buf2->data_size;
+        buf1->data = realloc(buf1->data, buf1->alloc_size);
+        memcpy(buf1->data + buf1->data_size, buf2->data + buf2->offset,
+               buf2->data_size);
+        buf1->data_size = buf1->alloc_size;
+        free_buffer(buf2);
+        return buf1;
+    }
+}
+
+/* Invalidate the first "bytes" bytes of the buffer, by adjusting the
+   offset and data size. */
+static void consume_buffer(queue_buffer_t* buf, int bytes) {
+    buf->offset += bytes;
+    buf->data_size -= bytes;
+}
+
+/* Looks at the buffer to see how much free space it has. If it has more than
+ * twice the data size of unused space at the end, or more than four times
+ * the data size of unused space at the beginning, then that space is
+ * reclaimed. */
+static void heatshrink_buffer(queue_buffer_t *buf) {
+    if (buf == NULL)
+        return;
+
+    if (G_UNLIKELY(buf->data_size * 4 > buf->offset)) {
+        /* Consolodate with memmove. We will reclaim the space in the next
+         * step. */
+        memmove(buf->data, buf->data + buf->offset, buf->data_size);
+        buf->offset = 0;
+    } 
+
+    if (buf->alloc_size > buf->data_size*2 + buf->offset) {
+        buf->alloc_size = buf->data_size + buf->offset;
+        buf->data = realloc(buf->data, buf->alloc_size);
+    }
+}
+
+static gpointer do_producer_thread(gpointer datap) {
+    queue_data_t* data = datap;
+
+    for (;;) {
+        queue_buffer_t *buf;
+        gboolean result;
+
+        semaphore_decrement(data->free_memory, 0);
+        buf = g_async_queue_try_pop(data->free_queue);
+        if (buf != NULL && buf->data == NULL) {
+            /* Consumer is finished, then so are we. */
+            amfree(buf);
+            return GINT_TO_POINTER(TRUE);
+        }
+
+        if (buf == NULL) {
+            buf = invent_buffer();
+        }
+        buf->offset = 0;
+        buf->data_size = 0;
+
+        result = data->producer(data->producer_user_data, buf,
+                                data->block_size);
+
+        // Producers can allocate way too much memory.
+        heatshrink_buffer(buf);
+
+        if (buf->data_size > 0) {
+            semaphore_force_adjust(data->free_memory, -buf->alloc_size);
+            
+            g_async_queue_push(data->data_queue, buf);
+            buf = NULL;
+        } else {
+            g_assert(result != PRODUCER_MORE);
+            free_buffer(buf);
+            buf = NULL;
+        }
+
+
+        if (result == PRODUCER_MORE) {
+            continue;
+        } else {
+            /* We are finished (and the first to do so). */
+            g_async_queue_push(data->data_queue, invent_buffer());
+            semaphore_force_set(data->free_memory, INT_MIN);
+
+            return GINT_TO_POINTER(result == PRODUCER_FINISHED);
+        }
+    }
+}
+
+static gpointer do_consumer_thread(gpointer datap) {
+    queue_data_t* data = datap;
+    gboolean finished = FALSE;
+    queue_buffer_t *buf = NULL;
+
+    if (data->streaming_mode != STREAMING_REQUIREMENT_NONE) {
+        semaphore_wait_empty(data->free_memory);
+    }
+
+    for (;;) {
+        gboolean result;
+
+        if (finished) {
+            return GINT_TO_POINTER(TRUE);
+        }
+
+        while (buf == NULL || buf->data_size < data->block_size) {
+            queue_buffer_t *next_buf;
+            if (data->streaming_mode == STREAMING_REQUIREMENT_DESIRED) {
+                do {
+                    next_buf = g_async_queue_try_pop(data->data_queue);
+                    if (next_buf == NULL) {
+                        semaphore_wait_empty(data->free_memory);
+                    }
+                } while (next_buf == NULL);
+            } else {
+                next_buf = g_async_queue_pop(data->data_queue);
+                g_assert(next_buf != NULL);
+            }
+
+            if (next_buf->data == NULL) {
+                /* Producer is finished, then so are we.*/
+                free_buffer(next_buf);
+                if (buf != NULL) {
+                    /* But we can't quit yet, we have a buffer to flush.*/
+                    finished = TRUE;
+                    break;
+                } else {
+                    /* We are so outta here. */
+                    return GINT_TO_POINTER(TRUE);
+                }            
+            }
+
+            semaphore_increment(data->free_memory, next_buf->alloc_size);
+            
+            buf = merge_buffers(buf, next_buf);
+        }
+
+        result = data->consumer(data->consumer_user_data, buf);
+
+        if (result > 0) {
+            consume_buffer(buf, result);
+            if (buf->data_size == 0) {
+                g_async_queue_push(data->free_queue, buf);
+                buf = NULL;
+            }
+            continue;
+        } else {
+            free_buffer(buf);
+            return GINT_TO_POINTER(FALSE);
+        }
+    }
+}
+
+/* Empties a buffer queue and frees all the buffers associated with it.
+ *
+ * If full_cleanup is TRUE, then we delete the queue itself.
+ * If full_cleanup is FALSE, then we leave the queue around, with a
+ *         signal element in it. */
+static void cleanup_buffer_queue(GAsyncQueue *Q, gboolean full_cleanup) {
+    g_async_queue_lock(Q);
+    for (;;) {
+        queue_buffer_t *buftmp;
+        buftmp = g_async_queue_try_pop_unlocked(Q);
+        if (buftmp == NULL)
+            break;
+
+        free_buffer(buftmp);
+    }
+    if (!full_cleanup)
+        g_async_queue_push_unlocked(Q, invent_buffer());
+
+    g_async_queue_unlock(Q);
+    
+    if (full_cleanup)
+        g_async_queue_unref(Q);
+}
+
+/* This function sacrifices performance, but will still work just
+   fine, on systems where threads are not supported. */
+static queue_result_flags
+do_unthreaded_consumer_producer_queue(guint block_size,
+                                      ProducerFunctor producer,
+                                      gpointer producer_user_data,
+                                      ConsumerFunctor consumer,
+                                      gpointer consumer_user_data) {
+    queue_buffer_t *buf = NULL, *next_buf = NULL;
+    gboolean finished = FALSE;
+    queue_result_flags rval = 0;
+
+    /* The basic theory of operation here is to read until we have
+       enough data to write, then write until we don't.. */
+    while (!finished) {
+        int result;
+        
+        while ((buf == NULL || buf->data_size < block_size) && !finished) {
+            if (next_buf == NULL)
+                next_buf = invent_buffer();
+
+            result = producer(producer_user_data, next_buf, block_size);
+
+            if (result != PRODUCER_MORE) {
+                finished = TRUE;
+                if (result != PRODUCER_FINISHED) {
+                    rval |= QUEUE_PRODUCER_ERROR;
+                }
+            }
+
+            buf = merge_buffers(buf, next_buf);
+            next_buf = NULL;
+        }
+
+        while (buf != NULL && buf->data_size > 0 &&
+               (buf->data_size >= block_size || finished)) {
+            result = consumer(consumer_user_data, buf);
+            
+            if (result > 0) {
+                consume_buffer(buf, result);
+                if (buf->data_size == 0) {
+                    next_buf = buf;
+                    buf = NULL;
+                }
+            } else {
+                finished = TRUE;
+                rval |= QUEUE_CONSUMER_ERROR;
+                break;
+            }
+        }
+    }
+
+    free_buffer(buf);
+    free_buffer(next_buf);
+    return rval;
+}
+
+gboolean do_consumer_producer_queue(ProducerFunctor producer,
+                                    gpointer producer_user_data,
+                                    ConsumerFunctor consumer,
+                                    gpointer consumer_user_data) {
+    return QUEUE_SUCCESS ==
+        do_consumer_producer_queue_full(producer, producer_user_data,
+                                        consumer, consumer_user_data,
+                                        0, DEFAULT_MAX_BUFFER_MEMORY,
+                                        STREAMING_REQUIREMENT_NONE);
+}
+
+queue_result_flags
+do_consumer_producer_queue_full(ProducerFunctor producer,
+                                gpointer producer_user_data,
+                                ConsumerFunctor consumer,
+                                gpointer consumer_user_data,
+                                int block_size,
+                                size_t max_memory,
+                                StreamingRequirement streaming_mode) {
+    GThread     * producer_thread;
+    GThread     * consumer_thread;
+    queue_data_t  queue_data;
+    gpointer      producer_result;
+    gpointer      consumer_result;
+    queue_result_flags rval;
+
+    if (block_size <= 0) {
+        block_size = DISK_BLOCK_BYTES;
+    }
+
+    g_return_val_if_fail(producer != NULL, FALSE);
+    g_return_val_if_fail(consumer != NULL, FALSE);
+
+    if (!g_thread_supported()) {
+        return do_unthreaded_consumer_producer_queue(block_size, producer,
+                                                     producer_user_data,
+                                                     consumer,
+                                                     consumer_user_data);
+    }
+
+    queue_data.block_size = block_size;
+    queue_data.producer = producer;
+    queue_data.producer_user_data = producer_user_data;
+    queue_data.consumer = consumer;
+    queue_data.consumer_user_data = consumer_user_data;
+    queue_data.streaming_mode = streaming_mode;
+
+    queue_data.data_queue = g_async_queue_new();
+    queue_data.free_queue = g_async_queue_new();
+
+    max_memory = MAX(1,MIN(max_memory, INT_MAX / 2));
+    queue_data.free_memory = semaphore_new_with_value(max_memory);
+
+    producer_thread = g_thread_create(do_producer_thread, &queue_data,
+                                      TRUE,
+                                      NULL /* FIXME: Should handle
+                                              errors. */);
+    consumer_thread = g_thread_create(do_consumer_thread, &queue_data,
+                                      TRUE,
+                                      NULL /* FIXME: Should handle
+                                              errors. */);
+    
+    /* The order of cleanup here is very important, to avoid deadlock. */
+    /* 1) Reap the consumer. */
+    consumer_result = g_thread_join(consumer_thread);
+    /* 2) Stop the producer. */
+    semaphore_force_set(queue_data.free_memory, -1);
+    /* 3) Cleanup the free queue; add a signal flag. */
+    cleanup_buffer_queue(queue_data.free_queue, FALSE);
+    /* 4) Restart the producer (so it can exit). */
+    semaphore_force_set(queue_data.free_memory, INT_MAX);
+    /* 5) Reap the producer. */
+    producer_result = g_thread_join(producer_thread);
+
+    cleanup_buffer_queue(queue_data.free_queue, TRUE);
+    cleanup_buffer_queue(queue_data.data_queue, TRUE);
+
+    semaphore_free(queue_data.free_memory);
+    
+    rval = 0;
+    if (!GPOINTER_TO_INT(producer_result)) {
+        rval |= QUEUE_PRODUCER_ERROR;
+    }
+    if (!GPOINTER_TO_INT(consumer_result)) {
+        rval |= QUEUE_CONSUMER_ERROR;
+    }
+    return rval;
+}
+
+/* Commonly-useful producers and consumers below. */
+
+producer_result_t device_read_producer(gpointer devicep,
+                                       queue_buffer_t *buffer,
+                                       int hint_size G_GNUC_UNUSED) {
+    Device* device;
+
+    device = (Device*) devicep;
+    g_assert(IS_DEVICE(device));
+
+    buffer->offset = 0;
+    for (;;) {
+        int result, read_size;
+        read_size = buffer->alloc_size;
+        result = device_read_block(device, buffer->data, &read_size);
+        if (result > 0) {
+            buffer->data_size = read_size;
+            return PRODUCER_MORE;
+        } else if (result == 0) {
+            buffer->data = realloc(buffer->data, read_size);
+            buffer->alloc_size = read_size;
+        } else if (device->is_eof) {
+            return PRODUCER_FINISHED;
+        } else {
+            buffer->data_size = 0;
+            return PRODUCER_ERROR;
+        }
+    }
+}
+
+int device_write_consumer(gpointer devicep, queue_buffer_t *buffer) {
+    Device* device;
+    unsigned int write_size;
+    static gboolean wrote_blocksize = FALSE;
+
+    device = (Device*) devicep;
+    g_assert(IS_DEVICE(device));
+    write_size = MIN(buffer->data_size,
+                     device_write_max_size(device));
+
+    if (!wrote_blocksize) {
+       wrote_blocksize = TRUE;
+       dbprintf("USING BLOCKSIZE %d bytes\n", write_size);
+    }
+
+    if (device_write_block(device, write_size,
+                           buffer->data + buffer->offset,
+                           buffer->data_size <
+                               device_write_min_size(device))) {
+        /* Success! */
+        return write_size;
+    } else {
+        /* Nope, really an error. */
+        return -1;
+    }
+}
+
+producer_result_t fd_read_producer(gpointer fdp, queue_buffer_t *buffer,
+                                   int hint_size) {
+    int fd;
+
+    fd = GPOINTER_TO_INT(fdp);
+    g_assert(fd >= 0);
+    g_assert(buffer->data_size == 0);
+
+    buffer->offset = 0;
+
+    if (buffer->data == NULL) {
+        /* Set up the buffer. */
+        buffer->data = malloc(hint_size);
+        buffer->alloc_size = hint_size;
+    }
+
+    for (;;) {
+        int result;
+        result = read(fd, buffer->data, buffer->alloc_size);
+
+        if (result > 0) {
+            buffer->data_size = result;
+            return PRODUCER_MORE;
+        } else if (result == 0) {
+            /* End of file. */
+            return PRODUCER_FINISHED;
+        } else if (0
+#ifdef EAGAIN
+                || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                || errno == EINTR
+#endif
+                ) {
+                /* Try again. */
+                continue;
+        } else {
+            /* Error occured. */
+            g_fprintf(stderr, "Error reading fd %d: %s\n", fd, strerror(errno));
+            return PRODUCER_ERROR;
+        }
+    }
+}
+
+int fd_write_consumer(gpointer fdp, queue_buffer_t *buffer) {
+    int fd;
+
+    fd = GPOINTER_TO_INT(fdp);
+    g_assert(fd >= 0);
+
+    g_return_val_if_fail(buffer->data_size > 0, 0);
+
+    for (;;) {
+        int write_size;
+        write_size = write(fd, buffer->data + buffer->offset,
+                           buffer->data_size);
+        
+        if (write_size > 0) {
+            return write_size;
+        } else if (0
+#ifdef EAGAIN
+                || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                || errno == EINTR
+#endif
+                ) {
+                /* Try again. */
+                continue;
+        } else {
+            /* Error occured. */
+            g_fprintf(stderr, "Error writing fd %d: %s\n", fd, strerror(errno));
+            return -1;
+        }        
+    }
+}
diff --git a/device-src/queueing.h b/device-src/queueing.h
new file mode 100644 (file)
index 0000000..4a22081
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#ifndef QUEUEING_H
+#define QUEUEING_H
+
+/* This file contains the code for fast threaded reading and writing to/from
+ * media, for devices that don't require any special handling. Some
+ * devices (e.g., CD-ROM) may use a different method for bulk reads or
+ * writes. */
+
+#include <glib.h>
+#include "property.h"
+
+#define DEFAULT_MAX_BUFFER_MEMORY (1*1024*1024)
+
+/* Valid data in this structure starts at data + offset, and has size
+ * data_size. Allocation starts at data and has size alloc_size. */
+typedef struct {
+    char *data;
+    guint alloc_size;
+    guint data_size;
+    guint offset;
+} queue_buffer_t;
+
+void free_buffer(queue_buffer_t*);
+
+typedef enum {
+    PRODUCER_MORE,     /* Means the producer should be run again. */
+    PRODUCER_FINISHED, /* Means that no error occured, but the
+                          producer should not be run again. */
+    PRODUCER_ERROR     /* Means an error occured, and the producer
+                          should not be run again. */
+} producer_result_t;
+
+typedef enum {
+    QUEUE_SUCCESS = 0,
+    QUEUE_PRODUCER_ERROR = 1 << 0,
+    QUEUE_CONSUMER_ERROR = 1 << 1,
+    QUEUE_INTERNAL_ERROR = 1 << 2
+} queue_result_flags;
+
+/* The producer takes the given buffer (which is not itself NULL, but
+ * may contain a NULL data segment), and fills it with data. The
+ * producer should feel free to allocate or reallocate data as
+ * necessary; the queueing system will free it when necessary. The
+ * result of the production operation is specified in the return
+ * value, but if the buffer is left without data, then that is
+ * interpreted as PRODUCER_ERROR. It is preferred (but not required)
+ * that the producer produce hint_size bytes of data, 
+ *
+ * The consumer takes the given buffer (which will not be NULL, nor
+ * contain a NULL data segment) and processess it. If there is a
+ * problem consuming data (such that no further data should be
+ * consumed), the consumer may return -1. Otherwise, the consumer
+ * should return the number of bytes actually consumed.
+ * If an error occurs, return -1, regardless of the number of bytes consumed.
+ * If the amount of data written is not a full block, then this is the
+ * last (partial block) of data. The consumer should do whatever is
+ * appropriate in that case.
+ *
+ * Note that the handling of the queue_buffer_t is different between
+ * the two functions: The producer should update queue_buffer_t as
+ * necessary to corespond to read data, while the consumer should
+ * leave the queue_buffer_t unadjusted: The queueing framework will
+ * invalidate data in the buffer according to the return value of the
+ * consumer.*/
+typedef producer_result_t (* ProducerFunctor)(gpointer user_data,
+                                              queue_buffer_t* buffer,
+                                              int hint_size);
+typedef int (* ConsumerFunctor)(gpointer user_data,
+                                queue_buffer_t* buffer);
+
+
+/* These functions make the magic happen. The first one assumes
+   reasonable defaults, the second one provides more options.
+   % producer           : A function that provides data to write.
+   % producer_user_data : A pointer to pass to that function.
+   % consumer           : A function that writes data out.
+   % consumer_user_data : A pointer to pass to that function.
+   % block_size         : Size of chunks to write out to consumer. If
+                          nonpositive, data will be written in
+                          variable-sized chunks.
+   % max_memory         : Amount of memory to be used for buffering.
+                          (default is DEFAULT_MAX_BUFFER_MEMORY).
+   % streaming_mode     : Describes streaming mode.
+         STREAMING_REQUIREMENT_NONE:     Data will be written as fast
+                                         as possible. No prebuffering
+                                         will be done.
+         STREAMING_REQUIREMENT_DESIRED:  max_memory bytes of data will
+                                         be prebuffered, and if the
+                                         buffer ever empties, no data
+                                         will be written until it
+                                         fills again.
+         STREAMING_REQUIREMENT_REQUIRED: max_memory bytes of data will
+                                         be prebuffered, and
+                                         thereafter data will be
+                                         written as fast as possible.
+*/
+gboolean
+do_consumer_producer_queue(ProducerFunctor producer,
+                           gpointer producer_user_data,
+                           ConsumerFunctor consumer,
+                           gpointer consumer_user_data);
+queue_result_flags
+do_consumer_producer_queue_full(ProducerFunctor producer,
+                                gpointer producer_user_data,
+                                ConsumerFunctor consumer,
+                                gpointer consumer_user_data,
+                                int block_size,
+                                size_t max_memory,
+                                StreamingRequirement streaming_mode);
+
+/* Some commonly-useful producers and consumers.*/
+
+/* These functions will call device_read_block and device_write_block
+ * respectively. The user data should be a Device*.
+ *
+ * device_write_consumer assumes that the block_size passed to
+ * do_consumer_producer_queue_full is at least device_write_min_size();
+ * do_consumer_thread() will not pass a buffer of less than block_size
+ * to the consumer unless it has received EOF from the producer thread.
+ */
+producer_result_t device_read_producer(gpointer device,
+                                       queue_buffer_t *buffer,
+                                       int hint_size);
+int device_write_consumer(gpointer device, queue_buffer_t *buffer);
+
+/* These functions will call read() or write() respectively. The user
+   data should be a file descriptor stored with GINT_TO_POINTER. */
+producer_result_t fd_read_producer(gpointer fd, queue_buffer_t *buffer,
+                                   int hint_size);
+int fd_write_consumer(gpointer fd, queue_buffer_t *buffer);
+
+
+
+#endif /* QUEUEING_H */
diff --git a/device-src/rait-device.c b/device-src/rait-device.c
new file mode 100644 (file)
index 0000000..72f7c6d
--- /dev/null
@@ -0,0 +1,1935 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* The RAIT device encapsulates some number of other devices into a single
+ * redundant device. */
+
+#include "rait-device.h"
+#include <amanda.h>
+#include "property.h"
+#include "util.h"
+
+typedef enum {
+    RAIT_STATUS_COMPLETE, /* All subdevices OK. */
+    RAIT_STATUS_DEGRADED, /* One subdevice failed. */
+    RAIT_STATUS_FAILED    /* Two or more subdevices failed. */
+} RaitStatus;
+
+struct RaitDevicePrivate_s {
+    GPtrArray * children;
+    /* These flags are only relevant for reading. */
+    RaitStatus status;
+    /* If status == RAIT_STATUS_DEGRADED, this holds the index of the
+       failed node. It holds a negative number otherwise. */
+    int failed;
+    guint block_size;
+};
+
+#define PRIVATE(o) (o->private)
+
+/* here are local prototypes */
+static void rait_device_init (RaitDevice * o);
+static void rait_device_class_init (RaitDeviceClass * c);
+static gboolean rait_device_open_device (Device * self, char * device_name);
+static gboolean rait_device_start (Device * self, DeviceAccessMode mode,
+                                   char * label, char * timestamp);
+static gboolean rait_device_start_file(Device * self, const dumpfile_t * info);
+static gboolean rait_device_write_block (Device * self, guint size,
+                                         gpointer data, gboolean last_block);
+static gboolean rait_device_finish_file (Device * self);
+static dumpfile_t * rait_device_seek_file (Device * self, guint file);
+static gboolean rait_device_seek_block (Device * self, guint64 block);
+static int      rait_device_read_block (Device * self, gpointer buf,
+                                        int * size);
+static gboolean rait_device_property_get (Device * self, DevicePropertyId id,
+                                          GValue * val);
+static gboolean rait_device_property_set (Device * self, DevicePropertyId id,
+                                          GValue * val);
+static gboolean rait_device_recycle_file (Device * self, guint filenum);
+static gboolean rait_device_finish (Device * self);
+static ReadLabelStatusFlags rait_device_read_label(Device * dself);
+static void find_simple_params(RaitDevice * self, guint * num_children,
+                               guint * data_children, int * blocksize);
+
+/* pointer to the class of our parent */
+static DeviceClass *parent_class = NULL;
+
+/* This function is replicated here in case we have GLib from before 2.4.
+ * It should probably go eventually. */
+#if !GLIB_CHECK_VERSION(2,4,0)
+static void
+g_ptr_array_foreach (GPtrArray *array,
+                     GFunc      func,
+                     gpointer   user_data)
+{
+  guint i;
+
+  g_return_if_fail (array);
+
+  for (i = 0; i < array->len; i++)
+    (*func) (array->pdata[i], user_data);
+}
+#endif
+
+GType
+rait_device_get_type (void)
+{
+    static GType type = 0;
+
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (RaitDeviceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) rait_device_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (RaitDevice),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) rait_device_init,
+            NULL
+        };
+        
+        type = g_type_register_static (TYPE_DEVICE, "RaitDevice", &info,
+                                       (GTypeFlags)0);
+       }
+    
+    return type;
+}
+
+static void g_object_unref_foreach(gpointer data,
+                                   gpointer user_data G_GNUC_UNUSED) {
+    g_return_if_fail(G_IS_OBJECT(data));
+    g_object_unref(data);
+}
+
+static void
+rait_device_finalize(GObject *obj_self)
+{
+    RaitDevice *self G_GNUC_UNUSED = RAIT_DEVICE (obj_self);
+    if(G_OBJECT_CLASS(parent_class)->finalize) \
+           (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+    if(self->private->children) {
+        g_ptr_array_foreach(self->private->children,
+                            g_object_unref_foreach, NULL);
+        g_ptr_array_free (self->private->children, TRUE);
+        self->private->children = NULL;
+    }
+    amfree(self->private);
+}
+
+static void 
+rait_device_init (RaitDevice * o G_GNUC_UNUSED)
+{
+    PRIVATE(o) = malloc(sizeof(RaitDevicePrivate));
+    PRIVATE(o)->children = g_ptr_array_new();
+    PRIVATE(o)->status = RAIT_STATUS_COMPLETE;
+    PRIVATE(o)->failed = -1;
+}
+
+static void 
+rait_device_class_init (RaitDeviceClass * c G_GNUC_UNUSED)
+{
+    GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c;
+    DeviceClass *device_class = (DeviceClass *)c;
+
+    parent_class = g_type_class_ref (TYPE_DEVICE);
+
+    device_class->open_device = rait_device_open_device;
+    device_class->start = rait_device_start;
+    device_class->start_file = rait_device_start_file;
+    device_class->write_block = rait_device_write_block;
+    device_class->finish_file = rait_device_finish_file;
+    device_class->seek_file = rait_device_seek_file;
+    device_class->seek_block = rait_device_seek_block;
+    device_class->read_block = rait_device_read_block;
+    device_class->property_get = rait_device_property_get;
+    device_class->property_set = rait_device_property_set;
+    device_class->recycle_file = rait_device_recycle_file; 
+    device_class->finish = rait_device_finish;
+    device_class->read_label = rait_device_read_label;
+
+    g_object_class->finalize = rait_device_finalize;
+
+    /* Versions of glib before 2.10.2 crash if
+     * g_thread_pool_set_max_unused_threads is called before the first
+     * invocation of g_thread_pool_new.  So we make up a thread pool, but don't
+     * start any threads in it, and free it */
+
+#if !GLIB_CHECK_VERSION(2,10,2)
+    {
+       GThreadPool *pool = g_thread_pool_new((GFunc)-1, NULL, -1, FALSE, NULL);
+       g_thread_pool_free(pool, TRUE, FALSE);
+    }
+#endif
+
+    g_thread_pool_set_max_unused_threads(-1);
+}
+
+/* This function does something a little clever and a little
+ * complicated. It takes an array of operations and runs the given
+ * function on each element in the array. The trick is that it runs them
+ * all in parallel, in different threads. This is more efficient than it
+ * sounds because we use a GThreadPool, which means calling this function
+ * will probably not start any new threads at all, but rather use
+ * existing ones. The func is called with two gpointer arguments: The
+ * first from the array, the second is the data argument.
+ * 
+ * When it returns, all the operations have been successfully
+ * executed. If you want results from your operations, do it yourself
+ * through the array. */
+static void do_thread_pool_op(GFunc func, GPtrArray * ops, gpointer data) {
+    GThreadPool * pool;
+    guint i;
+
+    pool = g_thread_pool_new(func, data, -1, FALSE, NULL);
+    for (i = 0; i < ops->len; i ++) {
+        g_thread_pool_push(pool, g_ptr_array_index(ops, i), NULL);
+    }
+
+    g_thread_pool_free(pool, FALSE, TRUE);
+}
+
+/* This does the above, in a serial fashion (and without using threads) */
+static void do_unthreaded_ops(GFunc func, GPtrArray * ops,
+                              gpointer data G_GNUC_UNUSED) {
+    guint i;
+
+    for (i = 0; i < ops->len; i ++) {
+        func(g_ptr_array_index(ops, i), NULL);
+    }
+}
+
+/* This is the one that code below should call. It switches
+   automatically between do_thread_pool_op and do_unthreaded_ops,
+   depending on g_thread_supported(). */
+static void do_rait_child_ops(GFunc func, GPtrArray * ops, gpointer data) {
+    if (g_thread_supported()) {
+        do_thread_pool_op(func, ops, data);
+    } else {
+        do_unthreaded_ops(func, ops, data);
+    }
+}
+
+/* Take a text string user_name, and break it out into an argv-style
+   array of strings. For example, {foo,{bar,baz},bat} would return the
+   strings "foo", "{bar,baz}", "bat", and NULL. Returns NULL on
+   error. */
+static char ** parse_device_name(char * user_name) {
+    GPtrArray * rval;
+    char * cur_end = user_name;
+    char * cur_begin = user_name;
+    
+    rval = g_ptr_array_new();
+    
+    /* Check opening brace. */
+    if (*cur_begin != '{')
+        return NULL;
+    cur_begin ++;
+    
+    cur_end = cur_begin;
+    for (;;) {
+        switch (*cur_end) {
+        case ',': {
+            g_ptr_array_add(rval, g_strndup(cur_begin, cur_end - cur_begin));
+            cur_end ++;
+            cur_begin = cur_end;
+            continue;
+        }
+
+        case '{':
+            /* We read until the matching closing brace. */
+            while (*cur_end != '}' && *cur_end != '\0')
+                cur_end ++;
+            if (*cur_end == '}')
+                cur_end ++;
+            continue;
+            
+        case '}':
+            g_ptr_array_add(rval, g_strndup(cur_begin, cur_end - cur_begin));
+            goto OUTER_END; /* break loop, not switch */
+
+        case '\0':
+            /* Unexpected NULL; abort. */
+            g_fprintf(stderr, "Invalid RAIT device name %s\n", user_name);
+            g_ptr_array_free_full(rval);
+            return NULL;
+
+        default:
+            cur_end ++;
+            continue;
+        }
+        g_assert_not_reached();
+    }
+ OUTER_END:
+    
+    if (cur_end[1] != '\0') {
+        g_fprintf(stderr, "Invalid RAIT device name %s\n", user_name);
+        g_ptr_array_free_full(rval);
+        return NULL;
+    }
+
+    g_ptr_array_add(rval, NULL);
+
+    return (char**) g_ptr_array_free(rval, FALSE);
+}
+
+/* Find a workable block size. */
+static gboolean find_block_size(RaitDevice * self) {
+    uint min = 0;
+    uint max = G_MAXUINT;
+    uint result;
+    GValue val;
+    gboolean rval;
+    guint i;
+    guint data_children;
+    
+    for (i = 0; i < self->private->children->len; i ++) {
+        uint child_min, child_max;
+        GValue property_result;
+        bzero(&property_result, sizeof(property_result));
+
+        if (!device_property_get(g_ptr_array_index(self->private->children, i),
+                                 PROPERTY_MIN_BLOCK_SIZE, &property_result))
+            return FALSE;
+        child_min = g_value_get_uint(&property_result);
+        g_return_val_if_fail(child_min > 0, FALSE);
+        if (!device_property_get(g_ptr_array_index(self->private->children, i),
+                                 PROPERTY_MAX_BLOCK_SIZE, &property_result))
+            return FALSE;
+        child_max = g_value_get_uint(&property_result);
+        g_return_val_if_fail(child_max > 0, FALSE);
+        
+        if (child_min > max || child_max < min || child_min == 0) {
+            return FALSE;
+        } else {
+            min = MAX(min, child_min);
+            max = MIN(max, child_max);
+        }
+    }
+
+    /* Now pick a number. */
+    g_assert(min <= max);
+    if (max < MAX_TAPE_BLOCK_BYTES)
+        result = max;
+    else if (min > MAX_TAPE_BLOCK_BYTES)
+        result = min;
+    else
+        result = MAX_TAPE_BLOCK_BYTES;
+
+    /* User reads and writes bigger blocks. */
+    find_simple_params(self, NULL, &data_children, NULL);
+    self->private->block_size = result * data_children;
+
+    bzero(&val, sizeof(val));
+    g_value_init(&val, G_TYPE_INT);
+    g_value_set_int(&val, result);
+    /* We can't do device_property_set because it's disallowed
+       according to the registered property base. */
+    rval = rait_device_property_set(DEVICE(self), PROPERTY_BLOCK_SIZE, &val);
+    g_value_unset(&val);
+    return rval;
+}
+
+/* Register properties that belong to the RAIT device proper, and not
+   to subdevices. */
+static void register_rait_properties(RaitDevice * self) {
+    Device * o = DEVICE(self);
+    DeviceProperty prop;
+
+    prop.access = PROPERTY_ACCESS_GET_MASK;
+
+    prop.base = &device_property_min_block_size;
+    device_add_property(o, &prop, NULL);
+
+    prop.base = &device_property_max_block_size;
+    device_add_property(o, &prop, NULL);
+  
+    prop.base = &device_property_block_size;
+    device_add_property(o, &prop, NULL);
+
+    prop.base = &device_property_canonical_name;
+    device_add_property(o, &prop, NULL);
+}
+
+static void property_hash_union(GHashTable * properties,
+                                const DeviceProperty * prop) {
+    PropertyAccessFlags before, after;
+    gpointer tmp;
+    gboolean found;
+    
+    found = g_hash_table_lookup_extended(properties,
+                                         GUINT_TO_POINTER(prop->base->ID),
+                                         NULL, &tmp);
+    before = GPOINTER_TO_UINT(tmp);
+    
+    if (!found) {
+        after = prop->access;
+    } else {
+        after = before & prop->access;
+    }
+    
+    g_hash_table_insert(properties, GUINT_TO_POINTER(prop->base->ID),
+                        GUINT_TO_POINTER(after));
+}
+
+/* A GHRFunc. */
+static gboolean zero_value(gpointer key G_GNUC_UNUSED, gpointer value,
+                           gpointer user_data G_GNUC_UNUSED) {
+    return (0 == GPOINTER_TO_UINT(value));
+}
+
+/* A GHFunc */
+static void register_property_hash(gpointer key, gpointer value,
+                                   gpointer user_data) {
+    DevicePropertyId id = GPOINTER_TO_UINT(key);
+    DeviceProperty prop;
+    Device * device = (Device*)user_data;
+
+    g_assert(IS_DEVICE(device));
+
+    prop.access = GPOINTER_TO_UINT(value);
+    prop.base = device_property_get_by_id(id);
+
+    device_add_property(device, &prop, NULL);
+}
+
+/* This function figures out which properties exist for all children, and 
+ * exports the unioned access mask. */
+static void register_properties(RaitDevice * self) {
+    GHashTable * properties; /* PropertyID => PropertyAccessFlags */
+    guint j;
+    
+    properties = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+    /* Iterate the device list, find all properties. */
+    for (j = 0; j < self->private->children->len; j ++) {
+        int i;
+        Device * child = g_ptr_array_index(self->private->children, j);
+        const DeviceProperty* device_property_list;
+
+        device_property_list = device_property_get_list(child);
+        for (i = 0; device_property_list[i].base != NULL; i ++) {
+            property_hash_union(properties, &(device_property_list[i]));
+        }
+    }
+
+    /* Then toss properties that can't be accessed. */
+    g_hash_table_foreach_remove(properties, zero_value, NULL);
+    g_hash_table_remove(properties, GINT_TO_POINTER(PROPERTY_BLOCK_SIZE));
+    g_hash_table_remove(properties, GINT_TO_POINTER(PROPERTY_MIN_BLOCK_SIZE));
+    g_hash_table_remove(properties, GINT_TO_POINTER(PROPERTY_MAX_BLOCK_SIZE));
+    g_hash_table_remove(properties, GINT_TO_POINTER(PROPERTY_CANONICAL_NAME));
+
+    /* Finally, register the lot. */
+    g_hash_table_foreach(properties, register_property_hash, self);
+
+    g_hash_table_destroy(properties);
+
+    /* Then we have some of our own properties to register. */
+    register_rait_properties(self);
+}
+
+/* This structure contains common fields for many operations. Not all
+   operations use all fields, however. */
+typedef struct {
+    gpointer result; /* May be a pointer; may be an integer or boolean
+                        stored with GINT_TO_POINTER. */
+    Device * child;  /* The device in question. Used by all
+                        operations. */
+    guint child_index; /* For recoverable operations (read-related
+                          operations), this field provides the number
+                          of this child in the self->private->children
+                          array. */
+} GenericOp;
+
+typedef gboolean (*BooleanExtractor)(gpointer data);
+
+/* A BooleanExtractor */
+static gboolean extract_boolean_generic_op(gpointer data) {
+    GenericOp * op = data;
+    return GPOINTER_TO_INT(op->result);
+}
+
+/* A BooleanExtractor */
+static gboolean extract_boolean_pointer_op(gpointer data) {
+    GenericOp * op = data;
+    return op->result != NULL;
+}
+
+/* Does the equivalent of this perl command:
+     ! (first { !extractor($_) } @_
+   That is, calls extractor on each element of the array, and returns
+   TRUE if and only if all calls to extractor return TRUE.
+*/
+static gboolean g_ptr_array_and(GPtrArray * array,
+                                BooleanExtractor extractor) {
+    guint i;
+    if (array == NULL || array->len <= 0)
+        return FALSE;
+
+    for (i = 0; i < array->len; i ++) {
+        if (!extractor(g_ptr_array_index(array, i)))
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+/* Calls extractor on each element of the array, and returns
+   TRUE if at least one of the calls to extractor return TRUE.
+*/
+static gboolean g_ptr_array_or(GPtrArray * array,
+                                BooleanExtractor extractor) {
+    guint i;
+    if (array == NULL || array->len <= 0)
+        return FALSE;
+
+    for (i = 0; i < array->len; i ++) {
+        if (extractor(g_ptr_array_index(array, i)))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* Takes a RaitDevice, and makes a GPtrArray of GenericOp. */
+static GPtrArray * make_generic_boolean_op_array(RaitDevice* self) {
+    GPtrArray * rval;
+    guint i;
+
+    rval = g_ptr_array_sized_new(self->private->children->len);
+    for (i = 0; i < self->private->children->len; i ++) {
+        GenericOp * op;
+        op = malloc(sizeof(*op));
+        op->child = g_ptr_array_index(self->private->children, i);
+        op->child_index = i;
+        g_ptr_array_add(rval, op);
+    }
+
+    return rval;
+}
+
+/* Takes a GPtrArray of GenericOp, and a BooleanExtractor, and does
+   all the proper handling for the result of operations that allow
+   device isolation. Returns FALSE only if an unrecoverable error
+   occured. */
+static gboolean g_ptr_array_union_robust(RaitDevice * self, GPtrArray * ops,
+                                         BooleanExtractor extractor) {
+    int nfailed;
+    guint i;
+
+    /* We found one or more failed elements.  See which elements failed, and
+     * isolate them*/
+    nfailed = 0;
+    for (i = 0; i < ops->len; i ++) {
+       GenericOp * op = g_ptr_array_index(ops, i);
+       if (!extractor(op)) {
+           self->private->failed = op->child_index;
+           g_fprintf(stderr, "RAIT array %s isolated device %s\n",
+                   DEVICE(self)->device_name,
+                   op->child->device_name);
+           nfailed++;
+       }
+    }
+
+    /* no failures? great! */
+    if (nfailed == 0)
+       return TRUE;
+
+    /* a single failure in COMPLETE just puts us in DEGRADED mode */
+    if (self->private->status == RAIT_STATUS_COMPLETE && nfailed == 1) {
+       self->private->status = RAIT_STATUS_DEGRADED;
+       g_fprintf(stderr, "RAIT array %s DEGRADED\n", DEVICE(self)->device_name);
+       return TRUE;
+    } else {
+       self->private->status = RAIT_STATUS_FAILED;
+       g_fprintf(stderr, "RAIT array %s FAILED\n", DEVICE(self)->device_name);
+       return FALSE;
+    }
+}
+
+typedef struct {
+    Device * result;    /* IN */
+    char * device_name; /* OUT */
+} OpenDeviceOp;
+
+/* A GFunc. */
+static void open_device_do_op(gpointer data,
+                              gpointer user_data G_GNUC_UNUSED) {
+    OpenDeviceOp * op = data;
+
+    op->result = device_open(op->device_name);
+    amfree(op->device_name);
+}
+
+/* Returns TRUE if and only if the volume label and time are equal. */
+static gboolean compare_volume_results(Device * a, Device * b) {
+    return (0 == compare_possibly_null_strings(a->volume_time, b->volume_time)
+        && 0 == compare_possibly_null_strings(a->volume_label, b->volume_label));
+}
+
+static gboolean 
+rait_device_open_device (Device * dself, char * device_name) {
+    char ** device_names;
+    GPtrArray * open_device_ops;
+    guint i;
+    gboolean failure;
+    RaitDevice * self;
+
+    self = RAIT_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, FALSE);
+    g_return_val_if_fail (device_name != NULL, FALSE);
+
+    device_names = parse_device_name(device_name);
+    
+    if (device_names == NULL)
+        return FALSE;
+
+    /* Open devices in a separate thread, in case they have to rewind etc. */
+    open_device_ops = g_ptr_array_new();
+
+    for (i = 0; device_names[i] != NULL; i ++) {
+        OpenDeviceOp *op;
+
+        op = malloc(sizeof(*op));
+        op->device_name = device_names[i];
+        op->result = NULL;
+        g_ptr_array_add(open_device_ops, op);
+    }
+
+    free(device_names);
+    do_rait_child_ops(open_device_do_op, open_device_ops, NULL);
+
+    failure = FALSE;
+    /* Check results of opening devices. */
+    for (i = 0; i < open_device_ops->len; i ++) {
+        OpenDeviceOp *op = g_ptr_array_index(open_device_ops, i);
+        
+        if (op->result != NULL) {
+            g_ptr_array_add(self->private->children, op->result);
+        } else {
+            failure = TRUE;
+        }
+    }
+
+    g_ptr_array_free_full(open_device_ops);
+
+    failure = failure || !find_block_size(self);
+    if (failure)
+        return FALSE; /* This will clean up any created children. */
+
+    register_properties(self);
+
+    /* Chain up. */
+    if (parent_class->open_device) {
+        return parent_class->open_device(dself, device_name);
+    } else {
+        return TRUE;
+    }
+}
+
+/* A GFunc. */
+static void read_label_do_op(gpointer data,
+                             gpointer user_data G_GNUC_UNUSED) {
+    GenericOp * op = data;
+    op->result = GINT_TO_POINTER(device_read_label(op->child));
+}
+
+static ReadLabelStatusFlags rait_device_read_label(Device * dself) {
+    RaitDevice * self;
+    GPtrArray * ops;
+    ReadLabelStatusFlags failed_result = 0;
+    ReadLabelStatusFlags rval;
+    GenericOp * failed_op = NULL; /* If this is non-null, we will isolate. */
+    unsigned int i;
+    Device * first_success = NULL;
+
+    self = RAIT_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    amfree(dself->volume_label);
+
+    ops = make_generic_boolean_op_array(self);
+    
+    do_rait_child_ops(read_label_do_op, ops, NULL);
+    
+    for (i = 0; i < ops->len; i ++) {
+        GenericOp * op = g_ptr_array_index(ops, i);
+        ReadLabelStatusFlags result = GPOINTER_TO_INT(op->result);
+        if (op->result == READ_LABEL_STATUS_SUCCESS) {
+            if (first_success == NULL) {
+                /* This is the first successful device. */
+                first_success = op->child;
+            } else if (!compare_volume_results(first_success, op->child)) {
+                /* Doesn't match. :-( */
+                g_fprintf(stderr, "Inconsistant volume labels: "
+                        "Got %s/%s against %s/%s.\n",
+                        first_success->volume_label,
+                        first_success->volume_time, 
+                        op->child->volume_label,
+                        op->child->volume_time);
+                failed_result |= READ_LABEL_STATUS_VOLUME_ERROR;
+                failed_op = NULL;
+            }
+        } else {
+            if (failed_result == 0 &&
+                self->private->status == RAIT_STATUS_COMPLETE) {
+                /* This is the first failed device; note it and we'll isolate
+                   later. */
+                failed_op = op;
+                failed_result = result;
+            } else {
+                /* We've encountered multiple failures. OR them together. */
+                failed_result |= result;
+                failed_op = NULL;
+            }
+        }
+    }
+
+    if (failed_op != NULL) {
+        /* We have a single device to isolate. */
+        failed_result = READ_LABEL_STATUS_SUCCESS; /* Recover later */
+        self->private->failed = failed_op->child_index;
+        g_fprintf(stderr, "RAIT array %s Isolated device %s.\n",
+                dself->device_name,
+                failed_op->child->device_name);
+    }
+
+    if (failed_result != READ_LABEL_STATUS_SUCCESS) {
+        /* We had multiple failures or an inconsistency. */
+        rval = failed_result;
+    } else {
+        /* Everything peachy. */
+        rval = READ_LABEL_STATUS_SUCCESS;
+        g_assert(first_success != NULL);
+        if (first_success->volume_label != NULL) {
+            dself->volume_label = g_strdup(first_success->volume_label);
+        }
+        if (first_success->volume_time != NULL) {
+            dself->volume_time = g_strdup(first_success->volume_time);
+        }
+    }
+    
+    g_ptr_array_free_full(ops);
+
+    return rval;
+}
+
+typedef struct {
+    GenericOp base;
+    DeviceAccessMode mode; /* IN */
+    char * label;          /* IN */
+    char * timestamp;      /* IN */
+} StartOp;
+
+/* A GFunc. */
+static void start_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
+    DeviceClass *klass;
+    StartOp * param = data;
+    
+    klass = DEVICE_GET_CLASS(param->base.child);
+    if (klass->start) {
+        param->base.result =
+            GINT_TO_POINTER((klass->start)(param->base.child,
+                                            param->mode, param->label,
+                                            param->timestamp));
+    } else {
+        param->base.result = FALSE;
+    }
+}
+
+static gboolean 
+rait_device_start (Device * dself, DeviceAccessMode mode, char * label,
+                   char * timestamp) {
+    GPtrArray * ops;
+    guint i;
+    gboolean success;
+    RaitDevice * self;
+    char * label_from_device = NULL;
+
+    self = RAIT_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    amfree(dself->volume_label);
+    amfree(dself->volume_time);
+
+    ops = g_ptr_array_sized_new(self->private->children->len);
+    for (i = 0; i < self->private->children->len; i ++) {
+        StartOp * op;
+        op = malloc(sizeof(*op));
+        op->base.child = g_ptr_array_index(self->private->children, i);
+        op->mode = mode;
+        op->label = g_strdup(label);
+        op->timestamp = g_strdup(timestamp);
+        g_ptr_array_add(ops, op);
+    }
+    
+    do_rait_child_ops(start_do_op, ops, NULL);
+
+    success = g_ptr_array_and(ops, extract_boolean_generic_op);
+
+    /* check that all of the volume labels agree */
+    if (success) {
+       for (i = 0; i < self->private->children->len; i ++) {
+           Device *child = g_ptr_array_index(self->private->children, i);
+
+           if (child->volume_label != NULL && child->volume_time != NULL) {
+                if (dself->volume_label != NULL && dself->volume_time != NULL) {
+                    if (strcmp(child->volume_label, dself->volume_label) != 0 ||
+                        strcmp(child->volume_time, dself->volume_time) != 0) {
+                        /* Mismatch! (Two devices provided different labels) */
+                       g_fprintf(stderr, "%s: Label (%s/%s) is different "
+                                          "from label (%s/%s) found at "
+                                          "device %s",
+                                          child->device_name,
+                                          child->volume_label,
+                                          child->volume_time,
+                                          dself->volume_label,
+                                          dself->volume_time,
+                                          label_from_device);
+                       success = FALSE;
+                    }
+                } else {
+                    /* First device with a volume. */
+                    dself->volume_label = g_strdup(child->volume_label);
+                    dself->volume_time = g_strdup(child->volume_time);
+                    label_from_device = g_strdup(child->device_name);
+                }
+            } else {
+                /* Device problem, it says it succeeded but sets no label? */
+               g_fprintf(stderr, "%s: %s",
+                                  child->device_name,
+                                  "Says label read, but device->volume_label "
+                                  " is NULL.");
+               success = FALSE;
+            }
+       }
+    }
+
+    amfree(label_from_device);
+    g_ptr_array_free_full(ops);
+
+    if (!success) {
+        return FALSE;
+    } else if (parent_class->start) {
+        return parent_class->start(dself, mode, label, timestamp);
+    } else {
+        return TRUE;
+    }
+}
+
+typedef struct {
+    GenericOp base;
+    const dumpfile_t * info; /* IN */
+    int fileno;
+} StartFileOp;
+
+/* a GFunc */
+static void start_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
+    StartFileOp * op = data;
+    op->base.result = GINT_TO_POINTER(device_start_file(op->base.child,
+                                                        op->info));
+    op->fileno = op->base.child->file;
+    if (op->fileno < 1) {
+        op->base.result = FALSE;
+    }
+}
+
+static gboolean
+rait_device_start_file (Device * dself, const dumpfile_t * info) {
+    GPtrArray * ops;
+    guint i;
+    gboolean success;
+    RaitDevice * self;
+    int actual_file = -1;
+
+    self = RAIT_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    ops = g_ptr_array_sized_new(self->private->children->len);
+    for (i = 0; i < self->private->children->len; i ++) {
+        StartFileOp * op;
+        op = malloc(sizeof(*op));
+        op->base.child = g_ptr_array_index(self->private->children, i);
+        op->info = info;
+        g_ptr_array_add(ops, op);
+    }
+    
+    do_rait_child_ops(start_file_do_op, ops, NULL);
+
+    success = g_ptr_array_and(ops, extract_boolean_generic_op);
+    
+    for (i = 0; i < self->private->children->len && success; i ++) {
+        StartFileOp * op = g_ptr_array_index(ops, i);
+        if (!op->base.result)
+            continue;
+        g_assert(op->fileno >= 1);
+        if (actual_file < 1) {
+            actual_file = op->fileno;
+        }
+        if (actual_file != op->fileno) {
+            /* File number mismatch! Aah, my hair is on fire! */
+           g_fprintf(stderr, "File number mismatch in "
+                            "rait_device_start_file(): "
+                            "Child %s reported file number "
+                            "%d, another child reported "
+                            "file number %d.",
+                            op->base.child->device_name,
+                            op->fileno, actual_file);
+            success = FALSE;
+            op->base.result = FALSE;
+        }
+    }
+
+    g_ptr_array_free_full(ops);
+
+    g_assert(actual_file >= 1);
+    dself->file = actual_file - 1; /* chain-up, below, will re-increment this */
+    dself->in_file = TRUE;
+
+    if (!success) {
+       g_fprintf(stderr, _("One or more devices failed to start_file"));
+        return FALSE;
+    } else if (parent_class->start_file) {
+        return parent_class->start_file(dself, info);
+    } else {
+        return TRUE;
+    }
+}
+
+static void find_simple_params(RaitDevice * self,
+                               guint * num_children,
+                               guint * data_children,
+                               int * blocksize) {
+    int num, data;
+    
+    num = self->private->children->len;
+    if (num > 1)
+        data = num - 1;
+    else
+        data = num;
+    if (num_children != NULL)
+        *num_children = num;
+    if (data_children != NULL)
+        *data_children = data;
+
+    if (blocksize != NULL) {
+        *blocksize = device_write_min_size(DEVICE(self));
+    }
+}
+
+typedef struct {
+    GenericOp base;
+    guint size;           /* IN */
+    gpointer data;        /* IN */
+    gboolean short_block; /* IN */
+    gboolean data_needs_free; /* bookkeeping */
+} WriteBlockOp;
+
+/* a GFunc. */
+static void write_block_do_op(gpointer data,
+                              gpointer user_data G_GNUC_UNUSED) {
+    WriteBlockOp * op = data;
+
+    op->base.result =
+        GINT_TO_POINTER(device_write_block(op->base.child, op->size, op->data,
+                                           op->short_block));
+}
+
+/* Parity block generation. Performance of this function can be improved
+   considerably by using larger-sized integers or
+   assembly-coded vector instructions. Parameters are:
+   % data       - All data chunks in series (chunk_size * num_chunks bytes)
+   % parity     - Allocated space for parity block (chunk_size bytes)
+ */
+static void make_parity_block(char * data, char * parity,
+                              guint chunk_size, guint num_chunks) {
+    guint i;
+    bzero(parity, chunk_size);
+    for (i = 0; i < num_chunks - 1; i ++) {
+        guint j;
+        for (j = 0; j < chunk_size; j ++) {
+            parity[j] ^= data[chunk_size*i + j];
+        }
+    }
+}
+
+/* Does the same thing as make_parity_block, but instead of using a
+   single memory chunk holding all chunks, it takes a GPtrArray of
+   chunks. */
+static void make_parity_block_extents(GPtrArray * data, char * parity,
+                                      guint chunk_size) {
+    guint i;
+    bzero(parity, chunk_size);
+    for (i = 0; i < data->len; i ++) {
+        guint j;
+        char * data_chunk;
+        data_chunk = g_ptr_array_index(data, i);
+        for (j = 0; j < chunk_size; j ++) {
+            parity[j] ^= data_chunk[j];
+        }
+    }
+}
+
+/* Does the parity creation algorithm. Allocates and returns a single
+   device block from a larger RAIT block. chunks and chunk are 1-indexed. */
+static char * extract_data_block(char * data, guint size,
+                                 guint chunks, guint chunk) {
+    char * rval;
+    guint chunk_size;
+
+    g_return_val_if_fail(chunks > 0 && chunk > 0 && chunk <= chunks, NULL);
+    g_return_val_if_fail(data != NULL, NULL);
+    g_return_val_if_fail(size > 0 && size % (chunks - 1) == 0, NULL);
+
+    chunk_size = size / (chunks - 1);
+    rval = malloc(chunk_size);
+    if (chunks != chunk) {
+        /* data block. */
+        memcpy(rval, data + chunk_size * (chunk - 1), chunk_size);
+    } else {
+        make_parity_block(data, rval, chunk_size, chunks);
+    }
+    
+    return rval;
+}
+
+static gboolean 
+rait_device_write_block (Device * dself, guint size, gpointer data,
+                         gboolean last_block) {
+    GPtrArray * ops;
+    guint i;
+    gboolean success;
+    guint data_children, num_children;
+    int blocksize;
+    RaitDevice * self;
+
+    self = RAIT_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    find_simple_params(RAIT_DEVICE(self), &num_children, &data_children,
+                       &blocksize);
+    num_children = self->private->children->len;
+    if (num_children != 1)
+        data_children = num_children - 1;
+    else
+        data_children = num_children;
+    
+    g_return_val_if_fail(size % data_children == 0 || last_block, FALSE);
+
+    if (last_block) {
+        char *new_data;
+
+        new_data = malloc(blocksize);
+        memcpy(new_data, data, size);
+        bzero(new_data + size, blocksize - size);
+
+        data = new_data;
+        size = blocksize;
+    }
+
+    ops = g_ptr_array_sized_new(num_children);
+    for (i = 0; i < self->private->children->len; i ++) {
+        WriteBlockOp * op;
+        op = malloc(sizeof(*op));
+        op->base.child = g_ptr_array_index(self->private->children, i);
+        op->short_block = last_block;
+        op->size = size / data_children;
+        if (num_children <= 2) {
+            op->data = data;
+            op->data_needs_free = FALSE;
+        } else {
+            op->data_needs_free = TRUE;
+            op->data = extract_data_block(data, size, num_children, i + 1);
+        }
+        g_ptr_array_add(ops, op);
+    }
+
+    do_rait_child_ops(write_block_do_op, ops, NULL);
+
+    success = g_ptr_array_and(ops, extract_boolean_generic_op);
+
+    for (i = 0; i < self->private->children->len; i ++) {
+        WriteBlockOp * op = g_ptr_array_index(ops, i);
+        if (op->data_needs_free)
+            free(op->data);
+    }
+
+    if (last_block) {
+        amfree(data);
+    }
+    
+    g_ptr_array_free_full(ops);
+
+    if (!success) {
+       /* TODO be more specific here */
+       /* TODO: handle EOF here -- if one or more (or two or more??)
+        * children have is_eof* set, then reflect that in our error
+        * status, and finish_file all of the non-EOF children. What's
+        * more fun is when one device fails and must be isolated at
+        * the same time another hits EOF. */
+       g_fprintf(stderr, "One or more devices failed to write_block");
+        return FALSE;
+    } else {
+        /* We don't chain up here because we must handle finish_file
+           differently. If we were called with last_block, then the
+           children have already called finish_file themselves. So we
+           update the device block numbers manually. */
+        dself->block ++;
+        if (last_block)
+            dself->in_file = FALSE;
+
+        return TRUE;
+    }
+}
+
+/* A GFunc */
+static void finish_file_do_op(gpointer data,
+                              gpointer user_data G_GNUC_UNUSED) {
+    GenericOp * op = data;
+    op->result = GINT_TO_POINTER(device_finish_file(op->child));
+}
+
+static gboolean 
+rait_device_finish_file (Device * self) {
+    GPtrArray * ops;
+    gboolean success;
+
+    ops = make_generic_boolean_op_array(RAIT_DEVICE(self));
+    
+    do_rait_child_ops(finish_file_do_op, ops, NULL);
+
+    success = g_ptr_array_and(ops, extract_boolean_generic_op);
+
+    g_ptr_array_free_full(ops);
+
+    if (!success) {
+        return FALSE;
+    } else if (parent_class->finish_file) {
+        return parent_class->finish_file(self);
+    } else {
+        return TRUE;
+    }
+}
+
+typedef struct {
+    GenericOp base;
+    guint requested_file;                /* IN */
+    guint actual_file;                   /* OUT */
+} SeekFileOp;
+
+/* a GFunc. */
+static void seek_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
+    SeekFileOp * op = data;
+    op->base.result = device_seek_file(op->base.child, op->requested_file);
+    op->actual_file = op->base.child->file;
+}
+
+static dumpfile_t * 
+rait_device_seek_file (Device * dself, guint file) {
+    GPtrArray * ops;
+    guint i;
+    gboolean success;
+    dumpfile_t * rval;
+    RaitDevice * self = RAIT_DEVICE(dself);
+    guint actual_file = 0;
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    ops = g_ptr_array_sized_new(self->private->children->len);
+    for (i = 0; i < self->private->children->len; i ++) {
+        SeekFileOp * op;
+        if ((int)i == self->private->failed)
+            continue; /* This device is broken. */
+        op = malloc(sizeof(*op));
+        op->base.child = g_ptr_array_index(self->private->children, i);
+        op->base.child_index = i;
+        op->requested_file = file;
+        g_ptr_array_add(ops, op);
+    }
+    
+    do_rait_child_ops(seek_file_do_op, ops, NULL);
+
+    /* This checks for NULL values, but we still have to check for
+       consistant headers. */
+    success = g_ptr_array_union_robust(RAIT_DEVICE(self),
+                                       ops, extract_boolean_pointer_op);
+
+    rval = NULL;
+    for (i = 0; i < self->private->children->len; i ++) {
+        SeekFileOp * this_op;
+        dumpfile_t * this_result;
+        guint this_actual_file;
+        if ((int)i == self->private->failed)
+            continue;
+        
+        this_op = (SeekFileOp*)g_ptr_array_index(ops, i);
+        this_result = this_op->base.result;
+        this_actual_file = this_op->actual_file;
+
+        if (rval == NULL) {
+            rval = this_result;
+            actual_file = this_actual_file;
+        } else {
+            if (headers_are_equal(rval, this_result) &&
+                actual_file == this_actual_file) {
+                /* Do nothing. */
+            } else {
+                success = FALSE;
+            }
+            free(this_result);
+        }
+    }
+
+    g_ptr_array_free_full(ops);
+
+    if (!success) {
+        amfree(rval);
+        return NULL;
+    } else if (parent_class->seek_file) {
+        parent_class->seek_file(dself, file);
+    }
+
+    return rval;
+}
+
+typedef struct {
+    GenericOp base;
+    guint64 block; /* IN */
+} SeekBlockOp;
+
+/* a GFunc. */
+static void seek_block_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
+    SeekBlockOp * op = data;
+    op->base.result =
+        GINT_TO_POINTER(device_seek_block(op->base.child, op->block));
+}
+
+static gboolean 
+rait_device_seek_block (Device * dself, guint64 block) {
+    GPtrArray * ops;
+    guint i;
+    gboolean success;
+
+    RaitDevice * self = RAIT_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    ops = g_ptr_array_sized_new(self->private->children->len);
+    for (i = 0; i < self->private->children->len; i ++) {
+        SeekBlockOp * op;
+        if ((int)i == self->private->failed)
+            continue; /* This device is broken. */
+        op = malloc(sizeof(*op));
+        op->base.child = g_ptr_array_index(self->private->children, i);
+        op->base.child_index = i;
+        op->block = block;
+        g_ptr_array_add(ops, op);
+    }
+    
+    do_rait_child_ops(seek_block_do_op, ops, NULL);
+
+    success = g_ptr_array_union_robust(RAIT_DEVICE(self),
+                                       ops, extract_boolean_generic_op);
+
+    g_ptr_array_free_full(ops);
+
+    if (!success) {
+        return FALSE;
+    } else if (parent_class->seek_block) {
+        return parent_class->seek_block(dself, block);
+    } else {
+        return success;
+    }
+}
+
+typedef struct {
+    GenericOp base;
+    gpointer buffer; /* IN */
+    int read_size;      /* IN/OUT -- note not a pointer */
+    int desired_read_size; /* bookkeeping */
+} ReadBlockOp;
+
+/* a GFunc. */
+static void read_block_do_op(gpointer data,
+                             gpointer user_data G_GNUC_UNUSED) {
+    ReadBlockOp * op = data;
+    op->base.result =
+        GINT_TO_POINTER(device_read_block(op->base.child, op->buffer,
+                                          &(op->read_size)));
+}
+
+/* A BooleanExtractor. This one checks for a successful read. */
+static gboolean extract_boolean_read_block_op_data(gpointer data) {
+    ReadBlockOp * op = data;
+    return GPOINTER_TO_INT(op->base.result) == op->desired_read_size;
+}
+
+/* A BooleanExtractor. This one checks for EOF. */
+static gboolean extract_boolean_read_block_op_eof(gpointer data) {
+    ReadBlockOp * op = data;
+    return op->base.child->is_eof;
+}
+
+/* Counts the number of elements in an array matching a given proposition. */
+static int g_ptr_array_count(GPtrArray * array, BooleanExtractor filter) {
+    int rval;
+    unsigned int i;
+    rval = 0;
+    for (i = 0; i < array->len ; i++) {
+        if (filter(g_ptr_array_index(array, i)))
+            rval ++;
+    }
+    return rval;
+}
+
+static gboolean raid_block_reconstruction(RaitDevice * self, GPtrArray * ops,
+                                      gpointer buf, size_t bufsize) {
+    guint num_children, data_children;
+    int blocksize, child_blocksize;
+    guint i;
+    int parity_child;
+    gpointer parity_block = NULL;
+    gboolean success;
+
+    success = TRUE;
+    find_simple_params(self, &num_children, &data_children, &blocksize);
+    if (num_children > 1)
+        parity_child = num_children - 1;
+    else
+        parity_child = -1;
+
+    child_blocksize = blocksize / data_children;
+
+    for (i = 0; i < ops->len; i ++) {
+        ReadBlockOp * op = g_ptr_array_index(ops, i);
+        if (!extract_boolean_read_block_op_data(op))
+            continue;
+        if ((int)(op->base.child_index) == parity_child) {
+            parity_block = op->buffer;
+        } else {
+           g_assert(child_blocksize * (op->base.child_index+1) <= bufsize);
+            memcpy((char *)buf + child_blocksize * op->base.child_index, op->buffer,
+                   child_blocksize);
+        }
+    }
+
+    if (self->private->status == RAIT_STATUS_COMPLETE) {
+        if (num_children >= 2) {
+            /* Verify the parity block. This code is inefficient but
+               does the job for the 2-device case, too. */
+            gpointer constructed_parity;
+            GPtrArray * data_extents;
+            
+            constructed_parity = malloc(child_blocksize);
+            data_extents = g_ptr_array_sized_new(data_children);
+            for (i = 0; i < data_children; i ++) {
+                ReadBlockOp * op = g_ptr_array_index(ops, i);
+                g_assert(extract_boolean_read_block_op_data(op));
+                if ((int)op->base.child_index == parity_child)
+                    continue;
+                g_ptr_array_add(data_extents, op->buffer);
+            }
+            make_parity_block_extents(data_extents, constructed_parity,
+                                      child_blocksize);
+            
+            if (0 != memcmp(parity_block, constructed_parity,
+                            child_blocksize)) {
+                g_fprintf(stderr, "RAIT is inconsistant: "
+                        "Parity block did not match data blocks.\n");
+                success = FALSE;
+            }
+            g_ptr_array_free(data_extents, TRUE);
+            amfree(constructed_parity);
+        } else { /* do nothing. */ }
+    } else if (self->private->status == RAIT_STATUS_DEGRADED) {
+       g_assert(self->private->failed >= 0 && self->private->failed < (int)num_children);
+        /* We are in degraded mode. What's missing? */
+        if (self->private->failed == parity_child) {
+            /* do nothing. */
+        } else if (num_children >= 2) {
+            /* Reconstruct failed block from parity block. */
+            GPtrArray * data_extents = g_ptr_array_new();            
+
+            for (i = 0; i < data_children; i ++) {
+                ReadBlockOp * op = g_ptr_array_index(ops, i);
+                if (!extract_boolean_read_block_op_data(op))
+                    continue;
+                g_ptr_array_add(data_extents, op->buffer);
+            }
+
+            /* Conveniently, the reconstruction is the same procedure
+               as the parity generation. This even works if there is
+               only one remaining device! */
+            make_parity_block_extents(data_extents,
+                                      (char *)buf + (child_blocksize *
+                                             self->private->failed),
+                                      child_blocksize);
+
+            /* The array members belong to our ops argument. */
+            g_ptr_array_free(data_extents, TRUE);
+        } else {
+            g_assert_not_reached();
+        }
+    } else {
+        success = FALSE;
+    }
+    return success;
+}
+
+static int
+rait_device_read_block (Device * dself, gpointer buf, int * size) {
+    GPtrArray * ops;
+    guint i;
+    gboolean success;
+    guint num_children, data_children;
+    int blocksize;
+    gsize child_blocksize;
+
+    RaitDevice * self = RAIT_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, -1);
+
+    find_simple_params(self, &num_children, &data_children,
+                       &blocksize);
+
+    /* tell caller they haven't given us a big enough buffer */
+    if (blocksize < *size) {
+       *size = blocksize;
+       return 0;
+    }
+
+    g_return_val_if_fail(*size >= (int)device_write_min_size(dself), -1);
+
+    g_assert(blocksize % data_children == 0); /* If not we are screwed */
+    child_blocksize = blocksize / data_children;
+
+    ops = g_ptr_array_sized_new(num_children);
+    for (i = 0; i < num_children; i ++) {
+        ReadBlockOp * op;
+        if ((int)i == self->private->failed)
+            continue; /* This device is broken. */
+        op = malloc(sizeof(*op));
+        op->base.child = g_ptr_array_index(self->private->children, i);
+        op->base.child_index = i;
+        op->buffer = malloc(child_blocksize);
+        op->desired_read_size = op->read_size = blocksize / data_children;
+        g_ptr_array_add(ops, op);
+    }
+    
+    do_rait_child_ops(read_block_do_op, ops, NULL);
+
+    if (g_ptr_array_count(ops, extract_boolean_read_block_op_data)) {
+        if (!g_ptr_array_union_robust(RAIT_DEVICE(self),
+                                     ops,
+                                     extract_boolean_read_block_op_data)) {
+           success = FALSE;
+       } else {
+           success = raid_block_reconstruction(RAIT_DEVICE(self),
+                                                ops, buf, (size_t)*size);
+       }
+    } else {
+        success = FALSE;
+        if (g_ptr_array_union_robust(RAIT_DEVICE(self),
+                                     ops,
+                                     extract_boolean_read_block_op_eof)) {
+            /* We hit EOF. */
+            dself->is_eof = TRUE;
+           dself->in_file = FALSE;
+        } else {
+           g_fprintf(stderr, _("All child devices failed to read, but not all are at eof"));
+       }
+    }
+
+    for (i = 0; i < ops->len; i ++) {
+        ReadBlockOp * op = g_ptr_array_index(ops, i);
+        amfree(op->buffer);
+    }
+    g_ptr_array_free_full(ops);
+
+    if (success) {
+        if (parent_class->read_block)
+            parent_class->read_block(dself, buf, size);
+       *size = blocksize;
+        return blocksize;
+    } else {
+        return -1;
+    }
+}
+
+typedef struct {
+    GenericOp base;
+    DevicePropertyId id;   /* IN */
+    GValue value;          /* IN/OUT */
+    gboolean label_changed; /* Did the device label change? OUT; _set only*/
+} PropertyOp;
+
+/* Creates a GPtrArray of PropertyOf for a get or set operation. */
+static GPtrArray * make_property_op_array(RaitDevice * self,
+                                          DevicePropertyId id,
+                                          GValue * value) {
+    guint i;
+    GPtrArray * ops;
+    ops = g_ptr_array_sized_new(self->private->children->len);
+    for (i = 0; i < self->private->children->len; i ++) {
+        PropertyOp * op;
+        op = malloc(sizeof(*op));
+        op->base.child = g_ptr_array_index(self->private->children, i);
+        op->id = id;
+        bzero(&(op->value), sizeof(op->value));
+        if (value != NULL) {
+            g_value_unset_copy(value, &(op->value));
+        }
+        g_ptr_array_add(ops, op);
+    }
+
+    return ops;
+}
+
+/* A GFunc. */
+static void property_get_do_op(gpointer data,
+                               gpointer user_data G_GNUC_UNUSED) {
+    PropertyOp * op = data;
+
+    bzero(&(op->value), sizeof(op->value));
+    op->base.result =
+        GINT_TO_POINTER(device_property_get(op->base.child, op->id,
+                                            &(op->value)));
+}
+
+/* Merge ConcurrencyParadigm results. */
+static gboolean property_get_concurrency(GPtrArray * ops, GValue * val) {
+    ConcurrencyParadigm result = CONCURRENCY_PARADIGM_RANDOM_ACCESS;
+    guint i = 0;
+    
+    for (i = 0; i < ops->len; i ++) {
+        ConcurrencyParadigm cur;
+        PropertyOp * op = g_ptr_array_index(ops, i);
+        g_return_val_if_fail(G_VALUE_TYPE(&(op->value)) ==
+                             CONCURRENCY_PARADIGM_TYPE, FALSE);
+        cur = g_value_get_enum(&(op->value));
+        if (result == CONCURRENCY_PARADIGM_EXCLUSIVE ||
+            cur == CONCURRENCY_PARADIGM_EXCLUSIVE) {
+            result = CONCURRENCY_PARADIGM_EXCLUSIVE;
+        } else if (result == CONCURRENCY_PARADIGM_SHARED_READ ||
+                   cur == CONCURRENCY_PARADIGM_SHARED_READ) {
+            result = CONCURRENCY_PARADIGM_SHARED_READ;
+        } else if (result == CONCURRENCY_PARADIGM_RANDOM_ACCESS &&
+                   cur == CONCURRENCY_PARADIGM_RANDOM_ACCESS) {
+            result = CONCURRENCY_PARADIGM_RANDOM_ACCESS;
+        } else {
+            g_return_val_if_fail(FALSE, FALSE);
+        }
+    }
+
+    g_value_unset_init(val, CONCURRENCY_PARADIGM_TYPE);
+    g_value_set_enum(val, result);
+    return TRUE;
+}
+
+/* Merge StreamingRequirement results. */
+static gboolean property_get_streaming(GPtrArray * ops, GValue * val) {
+    StreamingRequirement result = STREAMING_REQUIREMENT_NONE;
+    guint i = 0;
+    
+    for (i = 0; i < ops->len; i ++) {
+        StreamingRequirement cur;
+        PropertyOp * op = g_ptr_array_index(ops, i);
+        g_return_val_if_fail(G_VALUE_TYPE(&(op->value)) ==
+                             STREAMING_REQUIREMENT_TYPE, FALSE);
+        cur = g_value_get_enum(&(op->value));
+        if (result == STREAMING_REQUIREMENT_REQUIRED ||
+            cur == STREAMING_REQUIREMENT_REQUIRED) {
+            result = STREAMING_REQUIREMENT_REQUIRED;
+        } else if (result == STREAMING_REQUIREMENT_DESIRED ||
+                   cur == STREAMING_REQUIREMENT_DESIRED) {
+            result = STREAMING_REQUIREMENT_DESIRED;
+        } else if (result == STREAMING_REQUIREMENT_NONE &&
+                   cur == STREAMING_REQUIREMENT_NONE) {
+            result = STREAMING_REQUIREMENT_NONE;
+        } else {
+            g_return_val_if_fail(FALSE, FALSE);
+        }
+    }
+
+    g_value_unset_init(val, STREAMING_REQUIREMENT_TYPE);
+    g_value_set_enum(val, result);
+    return TRUE;
+}
+    
+/* Merge MediaAccessMode results. */
+static gboolean property_get_medium_type(GPtrArray * ops, GValue * val) {
+    MediaAccessMode result = 0;
+    guint i = 0;
+
+    for (i = 0; i < ops->len; i ++) {
+        MediaAccessMode cur;
+        PropertyOp * op = g_ptr_array_index(ops, i);
+        g_return_val_if_fail(G_VALUE_TYPE(&(op->value)) ==
+                             MEDIA_ACCESS_MODE_TYPE, FALSE);
+        cur = g_value_get_enum(&(op->value));
+        
+        if (i == 0) {
+            result = cur;
+        } else if ((result == MEDIA_ACCESS_MODE_READ_ONLY &&
+                    cur == MEDIA_ACCESS_MODE_WRITE_ONLY) ||
+                   (result == MEDIA_ACCESS_MODE_WRITE_ONLY &&
+                    cur == MEDIA_ACCESS_MODE_READ_ONLY)) {
+            /* Invalid combination; one device can only read, other
+               can only write. */
+            return FALSE;
+        } else if (result == MEDIA_ACCESS_MODE_READ_ONLY ||
+                   cur == MEDIA_ACCESS_MODE_READ_ONLY) {
+            result = MEDIA_ACCESS_MODE_READ_ONLY;
+        } else if (result == MEDIA_ACCESS_MODE_WRITE_ONLY ||
+                   cur == MEDIA_ACCESS_MODE_WRITE_ONLY) {
+            result = MEDIA_ACCESS_MODE_WRITE_ONLY;
+        } else if (result == MEDIA_ACCESS_MODE_WORM ||
+                   cur == MEDIA_ACCESS_MODE_WORM) {
+            result = MEDIA_ACCESS_MODE_WORM;
+        } else if (result == MEDIA_ACCESS_MODE_READ_WRITE &&
+                   cur == MEDIA_ACCESS_MODE_READ_WRITE) {
+            result = MEDIA_ACCESS_MODE_READ_WRITE;
+        } else {
+            g_return_val_if_fail(FALSE, FALSE);
+        }
+    }
+    
+    g_value_unset_init(val, MEDIA_ACCESS_MODE_TYPE);
+    g_value_set_enum(val, result);
+    return TRUE;
+}
+    
+/* Merge QualifiedSize results. */
+static gboolean property_get_free_space(GPtrArray * ops, GValue * val) {
+    QualifiedSize result;
+    guint i = 0;
+
+    for (i = 0; i < ops->len; i ++) {
+        QualifiedSize cur;
+        PropertyOp * op = g_ptr_array_index(ops, i);
+        g_return_val_if_fail(G_VALUE_TYPE(&(op->value)) ==
+                             QUALIFIED_SIZE_TYPE, FALSE);
+        cur = *(QualifiedSize*)(g_value_get_boxed(&(op->value)));
+
+        if (result.accuracy != cur.accuracy) {
+            result.accuracy = SIZE_ACCURACY_ESTIMATE;
+        }
+
+        if (result.accuracy == SIZE_ACCURACY_UNKNOWN &&
+            cur.accuracy != SIZE_ACCURACY_UNKNOWN) {
+            result.bytes = cur.bytes;
+        } else if (result.accuracy != SIZE_ACCURACY_UNKNOWN &&
+                   cur.accuracy == SIZE_ACCURACY_UNKNOWN) {
+            /* result.bytes unchanged. */
+        } else {
+            result.bytes = MIN(result.bytes, cur.bytes);
+        }
+    }
+
+    g_value_unset_init(val, QUALIFIED_SIZE_TYPE);
+    g_value_set_boxed(val, &result);
+    return TRUE;
+}
+    
+/* Merge boolean results by ANDing them together. */
+static gboolean property_get_boolean_and(GPtrArray * ops, GValue * val) {
+    gboolean result = FALSE;
+    guint i = 0;
+
+    for (i = 0; i < ops->len; i ++) {
+        gboolean cur;
+        PropertyOp * op = g_ptr_array_index(ops, i);
+        g_return_val_if_fail(G_VALUE_HOLDS_BOOLEAN(&(op->value)), FALSE);
+        cur = g_value_get_boolean(&(op->value));
+
+        result = result && cur;
+    }
+
+    g_value_unset_init(val, G_TYPE_BOOLEAN);
+    g_value_set_boolean(val, result);
+    return TRUE;
+}
+    
+
+static gboolean 
+rait_device_property_get (Device * dself, DevicePropertyId id, GValue * val) {
+    GPtrArray * ops;
+    guint i;
+    gboolean success;
+    GValue result;
+    GValue * first_value;
+    RaitDevice * self = RAIT_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    /* Some properties are handled completely differently. */
+    if (id == PROPERTY_BLOCK_SIZE) {
+        g_value_unset_init(val, G_TYPE_INT);
+        g_value_set_int(val, self->private->block_size);
+        return TRUE;
+    } else if (id == PROPERTY_MIN_BLOCK_SIZE ||
+        id == PROPERTY_MAX_BLOCK_SIZE) {
+        g_value_unset_init(val, G_TYPE_UINT);
+        g_value_set_uint(val, self->private->block_size);
+        return TRUE;
+    } else if (id == PROPERTY_CANONICAL_NAME) {
+        if (parent_class->property_get != NULL) {
+            return parent_class->property_get(dself, id, val);
+        } else {
+            return FALSE;
+        }
+    }
+
+    ops = make_property_op_array(self, id, NULL);
+    
+    do_rait_child_ops(property_get_do_op, ops, NULL);
+
+    if (id == PROPERTY_CONCURRENCY) {
+        success = property_get_concurrency(ops, val);
+    } else if (id == PROPERTY_STREAMING) { 
+        success = property_get_streaming(ops, val);
+    } else if (id == PROPERTY_APPENDABLE ||
+               id == PROPERTY_PARTIAL_DELETION) {
+        success = property_get_boolean_and(ops, val);
+    } else if (id == PROPERTY_MEDIUM_TYPE) {
+        success = property_get_medium_type(ops, val);
+    } else if (id == PROPERTY_FREE_SPACE) {
+        success = property_get_free_space(ops, val);
+    } else {
+        /* Generic handling; if all results are the same, we succeed
+           and return that result. If not, we fail. */
+        success = TRUE;
+        
+        /* Set up comparison value. */
+        bzero(&result, sizeof(result));
+        first_value = &(((PropertyOp*)g_ptr_array_index(ops,0))->value);
+        if (G_IS_VALUE(first_value)) {
+            g_value_unset_copy(first_value, &result);
+        } else {
+            success = FALSE;
+        }
+        
+        for (i = 0; i < ops->len; i ++) {
+            PropertyOp * op = g_ptr_array_index(ops, i);
+            if (!GPOINTER_TO_INT(op->base.result) ||
+                !G_IS_VALUE(first_value) ||
+                !g_value_compare(&result, &(op->value))) {
+                success = FALSE;
+            }
+           /* free the GValue if the child call succeeded */
+           if (GPOINTER_TO_INT(op->base.result))
+               g_value_unset(&(op->value));
+        }
+
+        if (success) {
+            memcpy(val, &result, sizeof(result));
+        } else if (G_IS_VALUE(&result)) {
+            g_value_unset(&result);
+        }
+    }
+
+    g_ptr_array_free_full(ops);
+
+    return success;
+}
+
+/* A GFunc. */
+static void property_set_do_op(gpointer data,
+                               gpointer user_data G_GNUC_UNUSED) {
+    PropertyOp * op = data;
+    gboolean label_set = (op->base.child->volume_label != NULL);
+    op->base.result =
+        GINT_TO_POINTER(device_property_set(op->base.child, op->id,
+                                            &(op->value)));
+    op->label_changed = (label_set != (op->base.child->volume_label != NULL));
+}
+
+/* A BooleanExtractor */
+static gboolean extract_label_changed_property_op(gpointer data) {
+    PropertyOp * op = data;
+    return op->label_changed;
+}
+
+/* A GFunc. */
+static void clear_volume_details_do_op(gpointer data,
+                                       gpointer user_data G_GNUC_UNUSED) {
+    GenericOp * op = data;
+    device_clear_volume_details(op->child);
+}
+
+static gboolean 
+rait_device_property_set (Device * d_self, DevicePropertyId id, GValue * val) {
+    RaitDevice * self;
+    GPtrArray * ops;
+    gboolean success;
+    gboolean label_changed;
+
+    self = RAIT_DEVICE(d_self);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    /* it doesn't make sense to hand these properties down to our child devices,
+     * so we'll just pretend we set them.  This is a 2.6.0 hack -- the device gets
+     * this right in 2.6.1.  */
+    if (id == PROPERTY_BLOCK_SIZE
+       || id == PROPERTY_MIN_BLOCK_SIZE
+       || id == PROPERTY_MAX_BLOCK_SIZE) {
+       return TRUE; /* lies! */
+    }
+
+    ops = make_property_op_array(self, id, val);
+    
+    do_rait_child_ops(property_set_do_op, ops, NULL);
+
+    success = g_ptr_array_union_robust(self, ops, extract_boolean_generic_op);
+    label_changed = g_ptr_array_or(ops, extract_label_changed_property_op);
+    g_ptr_array_free_full(ops);
+
+    if (label_changed) {
+        /* At least one device considered this property set a label-changing
+         * operation, so now we clear labels on all devices. */
+        ops = make_generic_boolean_op_array(self);
+        do_rait_child_ops(clear_volume_details_do_op, ops, NULL);
+        g_ptr_array_free_full(ops);
+    }
+
+    return success;
+}
+
+typedef struct {
+    GenericOp base;
+    guint filenum;
+} RecycleFileOp;
+
+/* A GFunc */
+static void recycle_file_do_op(gpointer data,
+                               gpointer user_data G_GNUC_UNUSED) {
+    RecycleFileOp * op = data;
+    op->base.result =
+        GINT_TO_POINTER(device_recycle_file(op->base.child, op->filenum));
+}
+
+static gboolean 
+rait_device_recycle_file (Device * dself, guint filenum) {
+    GPtrArray * ops;
+    guint i;
+    gboolean success;
+
+    RaitDevice * self = RAIT_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    ops = g_ptr_array_sized_new(self->private->children->len);
+    for (i = 0; i < self->private->children->len; i ++) {
+        RecycleFileOp * op;
+        op = malloc(sizeof(*op));
+        op->base.child = g_ptr_array_index(self->private->children, i);
+        op->filenum = filenum;
+        g_ptr_array_add(ops, op);
+    }
+    
+    do_rait_child_ops(recycle_file_do_op, ops, NULL);
+
+    success = g_ptr_array_and(ops, extract_boolean_generic_op);
+
+    g_ptr_array_free_full(ops);
+
+    if (!success) {
+        return FALSE;
+    } else if (parent_class->recycle_file) {
+        return parent_class->recycle_file(dself, filenum);
+    } else {
+        return TRUE;
+    }
+}
+
+/* GFunc */
+static void finish_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {
+    GenericOp * op = data;
+    op->result = GINT_TO_POINTER(device_finish(op->child));
+}
+
+static gboolean 
+rait_device_finish (Device * self) {
+    GPtrArray * ops;
+    gboolean success;
+
+    ops = make_generic_boolean_op_array(RAIT_DEVICE(self));
+    
+    do_rait_child_ops(finish_do_op, ops, NULL);
+
+    success = g_ptr_array_and(ops, extract_boolean_generic_op);
+
+    g_ptr_array_free_full(ops);
+
+    if (!success) {
+        return FALSE;
+    } else if (parent_class->finish) {
+        return parent_class->finish(self);
+    } else {
+        return TRUE;
+    }
+}
+
+Device *
+rait_device_factory (char * type, char * name) {
+    Device * rval;
+    g_assert(0 == strcmp(type, "rait"));
+    rval = DEVICE(g_object_new(TYPE_RAIT_DEVICE, NULL));
+    if (!device_open_device(rval, name)) {
+        g_object_unref(rval);
+        return NULL;
+    } else {
+        return rval;
+    }
+}
+
+Device * rait_device_new_from_devices(Device ** devices) {
+    RaitDevice * rval;
+    int i;
+    gboolean success = TRUE;
+
+    g_return_val_if_fail(devices != NULL && *devices != NULL, NULL);
+
+    rval = RAIT_DEVICE(g_object_new(TYPE_RAIT_DEVICE, NULL));
+
+    for (i = 0; devices[i] != NULL; i ++) {
+        g_assert(IS_DEVICE(devices[i]));
+        if (devices[i]->access_mode != ACCESS_NULL) {
+            success = FALSE;
+            break;
+        }
+        g_object_ref(devices[i]);
+        g_ptr_array_add(PRIVATE(rval)->children, devices[i]);
+    }
+
+    success = success && find_block_size(rval);
+
+    if (!success) {
+        g_ptr_array_free(PRIVATE(rval)->children, TRUE);
+        return NULL;
+    } else {
+        register_properties(rval);
+
+        return DEVICE(rval);
+    }
+}
+
+void 
+rait_device_register (void) {
+    static const char * device_prefix_list[] = {"rait", NULL};
+    register_device(rait_device_factory, device_prefix_list);
+}
diff --git a/device-src/rait-device.h b/device-src/rait-device.h
new file mode 100644 (file)
index 0000000..b7df6bb
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* The RAIT device encapsulates some number of other devices into a single
+ * redundant device. */
+
+#ifndef RAIT_DEVICE_H
+#define RAIT_DEVICE_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include "device.h"
+
+/*
+ * Type checking and casting macros
+ */
+#define TYPE_RAIT_DEVICE       (rait_device_get_type())
+#define RAIT_DEVICE(obj)       G_TYPE_CHECK_INSTANCE_CAST((obj), rait_device_get_type(), RaitDevice)
+#define RAIT_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), rait_device_get_type(), RaitDevice const)
+#define RAIT_DEVICE_CLASS(klass)       G_TYPE_CHECK_CLASS_CAST((klass), rait_device_get_type(), RaitDeviceClass)
+#define IS_RAIT_DEVICE(obj)    G_TYPE_CHECK_INSTANCE_TYPE((obj), rait_device_get_type ())
+
+#define RAIT_DEVICE_GET_CLASS(obj)     G_TYPE_INSTANCE_GET_CLASS((obj), rait_device_get_type(), RaitDeviceClass)
+
+/*
+ * Main object structure
+ */
+typedef struct RaitDevicePrivate_s RaitDevicePrivate;
+typedef struct RaitDevice_s {
+    Device __parent__;
+
+    RaitDevicePrivate * private;
+} RaitDevice;
+
+/*
+ * Class definition
+ */
+typedef struct _RaitDeviceClass RaitDeviceClass;
+struct _RaitDeviceClass {
+    DeviceClass __parent__;
+};
+
+
+/*
+ * Public methods
+ */
+GType  rait_device_get_type    (void);
+Device * rait_device_factory   (char * type,
+                                 char * name);
+/* Pass this factory a NULL-terminated array of Devices, and it will make a
+   RAIT out of them. The returned device refss the passed devices, so unref
+   them yourself. */
+Device * rait_device_new_from_devices(Device ** devices);
+void   rait_device_register    (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/device-src/s3-device.c b/device-src/s3-device.c
new file mode 100644 (file)
index 0000000..bebb6ef
--- /dev/null
@@ -0,0 +1,1184 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* An S3 device uses Amazon's S3 service (http://www.amazon.com/s3) to store 
+ * data.  It stores data in keys named with a user-specified prefix, inside a
+ * user-specified bucket.  Data is stored in the form of numbered (large) 
+ * blocks. 
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <regex.h>
+#include <time.h>
+#include "util.h"
+#include "amanda.h"
+#include "conffile.h"
+#include "device.h"
+#include "s3-device.h"
+#include <curl/curl.h>
+#ifdef HAVE_OPENSSL_HMAC_H
+# include <openssl/hmac.h>
+#else
+# ifdef HAVE_CRYPTO_HMAC_H
+#  include <crypto/hmac.h>
+# else
+#  ifdef HAVE_HMAC_H
+#   include <hmac.h>
+#  endif
+# endif
+#endif
+
+/*
+ * Constants and static data
+ */
+
+/* Maximum key length as specified in the S3 documentation
+ * (*excluding* null terminator) */
+#define S3_MAX_KEY_LENGTH 1024
+
+#define S3_DEVICE_MIN_BLOCK_SIZE 1024
+#define S3_DEVICE_MAX_BLOCK_SIZE (10*1024*1024)
+
+/* This goes in lieu of file number for metadata. */
+#define SPECIAL_INFIX "special-"
+
+/* pointer to the class of our parent */
+static DeviceClass *parent_class = NULL;
+
+/*
+ * prototypes
+ */
+
+/* 
+ * utility functions */
+
+/* Given file and block numbers, return an S3 key.
+ * 
+ * @param self: the S3Device object
+ * @param file: the file number
+ * @param block: the block within that file
+ * @returns: a newly allocated string containing an S3 key.
+ */
+static char * 
+file_and_block_to_key(S3Device *self, 
+                      int file, 
+                      guint64 block);
+
+/* Given the name of a special file (such as 'tapestart'), generate
+ * the S3 key to use for that file.
+ *
+ * @param self: the S3Device object
+ * @param special_name: name of the special file
+ * @param file: a file number to include; omitted if -1
+ * @returns: a newly alocated string containing an S3 key.
+ */
+static char * 
+special_file_to_key(S3Device *self, 
+                    char *special_name, 
+                    int file);
+/* Write an amanda header file to S3.
+ *
+ * @param self: the S3Device object
+ * @param label: the volume label
+ * @param timestamp: the volume timestamp
+ */
+static gboolean 
+write_amanda_header(S3Device *self, 
+                    char *label, 
+                    char * timestamp);
+
+/* "Fast forward" this device to the end by looking up the largest file number
+ * present and setting the current file number one greater.
+ *
+ * @param self: the S3Device object
+ */
+static gboolean 
+seek_to_end(S3Device *self);
+
+/* Find the number of the last file that contains any data (even just a header). 
+ *
+ * @param self: the S3Device object
+ * @returns: the last file, or -1 in event of an error
+ */
+static int 
+find_last_file(S3Device *self);
+
+/* Delete all blocks in the given file, including the filestart block
+ *
+ * @param self: the S3Device object
+ * @param file: the file to delete
+ */
+static gboolean 
+delete_file(S3Device *self, 
+            int file);
+
+/* Set up self->s3 as best as possible.  Unless SILENT is TRUE,
+ * any problems will generate warnings (with g_warning).  Regardless,
+ * the return value is TRUE iff self->s3 is useable.
+ *
+ * @param self: the S3Device object
+ * @param silent: silence warnings
+ * @returns: TRUE if the handle is set up
+ */
+static gboolean 
+setup_handle(S3Device * self, 
+            gboolean ignore_problems);
+
+/* 
+ * class mechanics */
+
+static void
+s3_device_init(S3Device * o);
+
+static void
+s3_device_class_init(S3DeviceClass * c);
+
+static void
+s3_device_finalize(GObject * o);
+
+static Device*
+s3_device_factory(char * device_type,
+                  char * device_name);
+
+/* 
+ * virtual functions */
+
+static gboolean
+s3_device_open_device(Device *pself, 
+                      char *device_name);
+
+static ReadLabelStatusFlags s3_device_read_label(Device * self);
+
+static gboolean 
+s3_device_start(Device * self, 
+                DeviceAccessMode mode, 
+                char * label, 
+                char * timestamp);
+
+static gboolean 
+s3_device_start_file(Device * self,
+                     const dumpfile_t * jobInfo);
+
+static gboolean 
+s3_device_write_block(Device * self, 
+                      guint size, 
+                      gpointer data, 
+                      gboolean last);
+
+static gboolean 
+s3_device_finish_file(Device * self);
+
+static dumpfile_t* 
+s3_device_seek_file(Device *pself, 
+                    guint file);
+
+static gboolean 
+s3_device_seek_block(Device *pself, 
+                     guint64 block);
+
+static int
+s3_device_read_block(Device * pself, 
+                     gpointer data, 
+                     int *size_req);
+
+static gboolean 
+s3_device_recycle_file(Device *pself, 
+                       guint file);
+
+static gboolean s3_device_property_set(Device * p_self, DevicePropertyId id,
+                                       GValue * val);
+static gboolean s3_device_property_get(Device * p_self, DevicePropertyId id,
+                                       GValue * val);
+/*
+ * Private functions
+ */
+
+/* {{{ file_and_block_to_key */
+static char *
+file_and_block_to_key(S3Device *self, 
+                      int file, 
+                      guint64 block)
+{
+    char *s3_key = g_strdup_printf("%sf%08x-b%016llx.data",
+                                   self->prefix, file, (long long unsigned int)block);
+    g_assert(strlen(s3_key) <= S3_MAX_KEY_LENGTH);
+    return s3_key;
+}
+/* }}} */
+
+/* {{{ special_file_to_key */
+static char *
+special_file_to_key(S3Device *self, 
+                    char *special_name, 
+                    int file)
+{
+    if (file == -1)
+        return g_strdup_printf("%s" SPECIAL_INFIX "%s", self->prefix, special_name);
+    else
+        return g_strdup_printf("%sf%08x-%s", self->prefix, file, special_name);
+}
+/* }}} */
+
+/* {{{ write_amanda_header */
+static gboolean
+write_amanda_header(S3Device *self, 
+                    char *label, 
+                    char * timestamp)
+{
+    char * amanda_header = NULL;
+    char * key = NULL;
+    int header_size;
+    gboolean header_fits, result;
+    dumpfile_t * dumpinfo = NULL;
+
+    /* build the header */
+    dumpinfo = make_tapestart_header(DEVICE(self), label, timestamp);
+    amanda_header = device_build_amanda_header(DEVICE(self), dumpinfo, 
+                                               &header_size, &header_fits);
+    if (!header_fits) {
+        fprintf(stderr,
+                _("Amanda tapestart header won't fit in a single block!\n"));
+       g_free(amanda_header);
+       return FALSE;
+    }
+
+    /* write out the header and flush the uploads. */
+    key = special_file_to_key(self, "tapestart", -1);
+    result = s3_upload(self->s3, self->bucket, key, amanda_header, header_size);
+    g_free(amanda_header);
+    g_free(key);
+
+    if (!result) {
+        fprintf(stderr, _("While writing amanda header: %s\n"),
+                s3_strerror(self->s3));
+    }
+    return result;
+}
+/* }}} */
+
+/* {{{ seek_to_end */
+static gboolean
+seek_to_end(S3Device *self) {
+    int last_file;
+
+    Device *pself = DEVICE(self);
+
+    last_file = find_last_file(self);
+    if (last_file < 0)
+        return FALSE;
+
+    pself->file = last_file;
+
+    return TRUE;
+}
+/* }}} */
+
+/* Convert an object name into a file number, assuming the given prefix
+ * length. Returns -1 if the object name is invalid, or 0 if the object name
+ * is a "special" key. */
+static int key_to_file(guint prefix_len, const char * key) {
+    int file;
+    int i;
+    
+    /* skip the prefix */
+    g_return_val_if_fail(strlen(key) > prefix_len, -1);
+
+    key += prefix_len;
+
+    if (strncmp(key, SPECIAL_INFIX, strlen(SPECIAL_INFIX)) == 0) {
+        return 0;
+    }
+    
+    /* check that key starts with 'f' */
+    g_return_val_if_fail(key[0] == 'f', -1);
+    key++;
+    
+    /* check that key is of the form "%08x-" */
+    for (i = 0; i < 8; i++) {
+        if (!(key[i] >= '0' && key[i] <= '9') &&
+            !(key[i] >= 'a' && key[i] <= 'f') &&
+            !(key[i] >= 'A' && key[i] <= 'F')) break;
+    }
+    if (key[i] != '-') return -1;
+    if (i < 8) return -1;
+
+    /* convert the file number */
+    errno = 0;
+    file = strtoul(key, NULL, 16);
+    if (errno != 0) {
+        g_warning(_("unparseable file number '%s'"), key);
+        return -1;
+    }
+    
+    return file;
+}
+
+/* {{{ find_last_file */
+/* Find the number of the last file that contains any data (even just a header). 
+ * Returns -1 in event of an error
+ */
+static int
+find_last_file(S3Device *self) {
+    gboolean result;
+    GSList *keys;
+    unsigned int prefix_len = strlen(self->prefix);
+    int last_file = 0;
+
+    /* list all keys matching C{PREFIX*-*}, stripping the C{-*} */
+    result = s3_list_keys(self->s3, self->bucket, self->prefix, "-", &keys);
+    if (!result) {
+        fprintf(stderr, _("While listing S3 keys: %s\n"),
+                s3_strerror(self->s3));
+        return -1;
+    }
+
+    for (; keys; keys = g_slist_remove(keys, keys->data)) {
+        int file = key_to_file(prefix_len, keys->data);
+
+        /* and if it's the last, keep it */
+        if (file > last_file)
+            last_file = file;
+    }
+
+    return last_file;
+}
+/* }}} */
+
+/* {{{ find_next_file */
+/* Find the number of the file following the requested one, if any. 
+ * Returns 0 if there is no such file or -1 in event of an error
+ */
+static int
+find_next_file(S3Device *self, int last_file) {
+    gboolean result;
+    GSList *keys;
+    unsigned int prefix_len = strlen(self->prefix);
+    int next_file = 0;
+
+    /* list all keys matching C{PREFIX*-*}, stripping the C{-*} */
+    result = s3_list_keys(self->s3, self->bucket, self->prefix, "-", &keys);
+    if (!result) {
+        fprintf(stderr, _("While listing S3 keys: %s\n"),
+                s3_strerror(self->s3));
+        return -1;
+    }
+
+    for (; keys; keys = g_slist_remove(keys, keys->data)) {
+        int file;
+
+        file = key_to_file(prefix_len, (char*)keys->data);
+
+        if (file < 0) {
+            /* Set this in case we don't find a next file; this is not a
+             * hard error, so if we can find a next file we'll return that
+             * instead. */
+            next_file = -1;
+        }
+
+        if (file < next_file && file > last_file) {
+            next_file = file;
+        }
+    }
+
+    return last_file;
+}
+/* }}} */
+
+/* {{{ delete_file */
+static gboolean
+delete_file(S3Device *self,
+            int file)
+{
+    gboolean result;
+    GSList *keys;
+    char *my_prefix = g_strdup_printf("%sf%08x-", self->prefix, file);
+    
+    result = s3_list_keys(self->s3, self->bucket, my_prefix, NULL, &keys);
+    if (!result) {
+        fprintf(stderr, _("While listing S3 keys: %s\n"),
+                s3_strerror(self->s3));
+        return FALSE;
+    }
+
+    /* this will likely be a *lot* of keys */
+    for (; keys; keys = g_slist_remove(keys, keys->data)) {
+        if (self->verbose) g_debug(_("Deleting %s"), (char*)keys->data);
+        if (!s3_delete(self->s3, self->bucket, keys->data)) {
+            fprintf(stderr, _("While deleting key '%s': %s\n"),
+                    (char*)keys->data, s3_strerror(self->s3));
+            g_slist_free(keys);
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+/* }}} */
+
+/*
+ * Class mechanics
+ */
+
+/* {{{ s3_device_register */
+void 
+s3_device_register(void)
+{
+    static const char * device_prefix_list[] = { "s3", NULL };
+    g_assert(s3_init());
+    register_device(s3_device_factory, device_prefix_list);
+}
+/* }}} */
+
+/* {{{ s3_device_get_type */
+GType
+s3_device_get_type(void)
+{
+    static GType type = 0;
+    
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (S3DeviceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) s3_device_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (S3Device),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) s3_device_init,
+            NULL
+        };
+        
+        type = g_type_register_static (TYPE_DEVICE, "S3Device", &info,
+                                       (GTypeFlags)0);
+    }
+
+    return type;
+}
+/* }}} */
+
+/* {{{ s3_device_init */
+static void 
+s3_device_init(S3Device * self)
+{
+    Device * o;
+    DeviceProperty prop;
+    GValue response;
+
+    self->initializing = TRUE;
+
+    /* Register property values */
+    o = (Device*)(self);
+    bzero(&response, sizeof(response));
+
+    prop.base = &device_property_concurrency;
+    prop.access = PROPERTY_ACCESS_GET_MASK;
+    g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
+    g_value_set_enum(&response, CONCURRENCY_PARADIGM_SHARED_READ);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+    
+    prop.base = &device_property_streaming;
+    g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
+    g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+    
+    prop.base = &device_property_block_size;
+    g_value_init(&response, G_TYPE_INT);
+    g_value_set_int(&response, -1); /* indicates a variable block size; see below */
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+    
+    prop.base = &device_property_min_block_size;
+    g_value_init(&response, G_TYPE_UINT);
+    g_value_set_uint(&response, S3_DEVICE_MIN_BLOCK_SIZE);
+    device_add_property(o, &prop, &response);
+
+    prop.base = &device_property_max_block_size;
+    g_value_set_uint(&response, S3_DEVICE_MAX_BLOCK_SIZE);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_appendable;
+    g_value_init(&response, G_TYPE_BOOLEAN);
+    g_value_set_boolean(&response, TRUE);
+    device_add_property(o, &prop, &response);
+
+    prop.base = &device_property_partial_deletion;
+    g_value_set_boolean(&response, TRUE);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_canonical_name;
+    g_value_init(&response, G_TYPE_STRING);
+    g_value_set_static_string(&response, "s3:");
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_medium_access_type;
+    g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
+    g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+    
+    prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START;
+    prop.base = &device_property_s3_secret_key;
+    device_add_property(o, &prop, NULL);
+    prop.base = &device_property_s3_access_key;
+    device_add_property(o, &prop, NULL);
+#ifdef WANT_DEVPAY
+    prop.base = &device_property_s3_user_token;
+    device_add_property(o, &prop, NULL);
+#endif
+}
+/* }}} */
+
+/* {{{ s3_device_class_init */
+static void 
+s3_device_class_init(S3DeviceClass * c G_GNUC_UNUSED)
+{
+    GObjectClass *g_object_class = (GObjectClass*) c;
+    DeviceClass *device_class = (DeviceClass *)c;
+
+    parent_class = g_type_class_ref (TYPE_DEVICE);
+
+    device_class->open_device = s3_device_open_device;
+    device_class->read_label = s3_device_read_label;
+    device_class->start = s3_device_start;
+
+    device_class->start_file = s3_device_start_file;
+    device_class->write_block = s3_device_write_block;
+    device_class->finish_file = s3_device_finish_file;
+
+    device_class->seek_file = s3_device_seek_file;
+    device_class->seek_block = s3_device_seek_block;
+    device_class->read_block = s3_device_read_block;
+    device_class->recycle_file = s3_device_recycle_file;
+
+    device_class->property_set = s3_device_property_set;
+    device_class->property_get = s3_device_property_get;
+
+    g_object_class->finalize = s3_device_finalize;
+}
+/* }}} */
+
+/* {{{ s3_device_factory */
+static Device* 
+s3_device_factory(char * device_type,
+                  char * device_name)
+{
+    Device *rval;
+    S3Device * s3_rval;
+    g_assert(0 == strcmp(device_type, "s3"));
+    rval = DEVICE(g_object_new(TYPE_S3_DEVICE, NULL));
+    s3_rval = (S3Device*)rval;
+
+    if (!device_open_device(rval, device_name)) {
+        g_object_unref(rval);
+        return NULL;
+    } else {
+        s3_rval->initializing = FALSE;
+        return rval;
+    }
+    
+}
+/* }}} */
+
+/*
+ * Virtual function overrides
+ */
+
+/* {{{ s3_device_open_device */
+static gboolean 
+s3_device_open_device(Device *pself, 
+                      char *device_name)
+{
+    S3Device *self = S3_DEVICE(pself);
+    char * name_colon;
+
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    /* Device name may be bucket/prefix, to support multiple volumes in a
+     * single bucket. */
+    name_colon = index(device_name, '/');
+    if (name_colon == NULL) {
+        self->bucket = g_strdup(device_name);
+        self->prefix = g_strdup("");
+    } else {
+        self->bucket = g_strndup(device_name, name_colon - device_name);
+        self->prefix = g_strdup(name_colon + 1);
+    }
+    
+    if (self->bucket == NULL || self->bucket[0] == '\0') {
+        fprintf(stderr, _("Empty bucket name in device %s.\n"), device_name);
+        amfree(self->bucket);
+        amfree(self->prefix);
+        return FALSE;
+    }
+
+    g_debug(_("S3 driver using bucket '%s', prefix '%s'"), self->bucket, self->prefix);
+
+    /* default value */
+    self->verbose = FALSE;
+
+    if (parent_class->open_device) {
+        parent_class->open_device(pself, device_name);
+    }
+
+    return TRUE;
+}
+/* }}} */
+
+/* {{{ s3_device_finalize */
+static void s3_device_finalize(GObject * obj_self) {
+    S3Device *self = S3_DEVICE (obj_self);
+
+    if(G_OBJECT_CLASS(parent_class)->finalize)
+        (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+
+    if(self->s3) s3_free(self->s3);
+    if(self->bucket) g_free(self->bucket);
+    if(self->prefix) g_free(self->prefix);
+}
+/* }}} */
+
+static gboolean setup_handle(S3Device * self, G_GNUC_UNUSED gboolean silent) {
+    if (self->s3 == NULL) {
+        if (self->access_key == NULL) {
+           if (!silent) fprintf(stderr, _("No S3 access key specified\n"));
+            return FALSE;
+       }
+       if (self->secret_key == NULL) {
+           if (!silent) fprintf(stderr, _("No S3 secret key specified\n"));
+            return FALSE;
+       }
+#ifdef WANT_DEVPAY
+       if (self->user_token == NULL) {
+           if (!silent) fprintf(stderr, _("No S3 user token specified\n"));
+            return FALSE;
+       }
+#endif
+        self->s3 = s3_open(self->access_key, self->secret_key
+#ifdef WANT_DEVPAY
+                           , self->user_token
+#endif
+                           );
+        if (self->s3 == NULL) {
+            fprintf(stderr, "Internal error creating S3 handle.\n");
+            return FALSE;
+        }
+    }
+
+    s3_verbose(self->s3, self->verbose);
+
+    return TRUE;
+}
+
+/* {{{ s3_device_read_label */
+static ReadLabelStatusFlags
+s3_device_read_label(Device *pself) {
+    S3Device *self = S3_DEVICE(pself);
+    char *key;
+    gpointer buf;
+    guint buf_size;
+    dumpfile_t amanda_header;
+    
+    if (!setup_handle(self, self->initializing))
+        return READ_LABEL_STATUS_DEVICE_ERROR;
+
+    key = special_file_to_key(self, "tapestart", -1);
+    if (!s3_read(self->s3, self->bucket, key, &buf, &buf_size, S3_DEVICE_MAX_BLOCK_SIZE)) {
+        guint response_code;
+        s3_error_code_t s3_error_code;
+        s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
+
+        /* if it's an expected error (not found), just return FALSE */
+        if (response_code == 404 && 
+             (s3_error_code == S3_ERROR_NoSuchKey || s3_error_code == S3_ERROR_NoSuchBucket)) {
+            g_debug(_("Amanda header not found while reading tapestart header (this is expected for empty tapes)"));
+            return READ_LABEL_STATUS_VOLUME_UNLABELED;
+        }
+
+        /* otherwise, log it and return */
+        fprintf(stderr, _("While trying to read tapestart header: %s\n"),
+                s3_strerror(self->s3));
+        return READ_LABEL_STATUS_DEVICE_ERROR;
+    }
+
+    g_assert(buf != NULL);
+    fh_init(&amanda_header);
+    parse_file_header(buf, &amanda_header, buf_size);
+
+    g_free(buf);
+
+    if (amanda_header.type != F_TAPESTART) {
+        fprintf(stderr, _("Invalid amanda header\n"));
+        return READ_LABEL_STATUS_VOLUME_ERROR;
+    }
+
+    amfree(pself->volume_label);
+    pself->volume_label = g_strdup(amanda_header.name);
+    amfree(pself->volume_time);
+    pself->volume_time = g_strdup(amanda_header.datestamp);
+
+    return READ_LABEL_STATUS_SUCCESS;
+}
+/* }}} */
+
+/* {{{ s3_device_start */
+static gboolean 
+s3_device_start (Device * pself, DeviceAccessMode mode,
+                 char * label, char * timestamp) {
+    S3Device * self;
+    int file, last_file;
+
+    self = S3_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, FALSE);
+
+    if (!setup_handle(self, FALSE))
+        return FALSE;
+
+    /* try creating the bucket, in case it doesn't exist */
+    if (mode != ACCESS_READ && !s3_make_bucket(self->s3, self->bucket)) {
+        guint response_code;
+        s3_error_code_t s3_error_code;
+        s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
+
+        /* if it isn't an expected error (bucket already exists),
+         * return FALSE */
+        if (response_code != 409 ||
+            s3_error_code != S3_ERROR_BucketAlreadyExists) {
+            fprintf(stderr, _("While creating new S3 bucket: %s\n"),
+                    s3_strerror(self->s3));
+            return FALSE;
+        }
+    }
+
+    /* call up to the parent (Device) to set access_mode, volume_label,
+     * and volume_time, either from the arguments (ACCESS_WRITE) or by 
+     * reading from the 0th file (otherwise)
+     */
+    if (parent_class->start) 
+        if (!parent_class->start((Device*)self, mode, label, timestamp))
+            return FALSE;
+
+    /* take care of any dirty work for this mode */
+    switch (mode) {
+        case ACCESS_READ:
+            break;
+
+        case ACCESS_WRITE:
+            /* delete all files */
+            last_file = find_last_file(self);
+            if (last_file < 0) return FALSE;
+            for (file = 0; file <= last_file; file++) {
+                if (!delete_file(self, file)) return FALSE;
+            }
+
+            /* write a new amanda header */
+            if (!write_amanda_header(self, label, timestamp)) {
+                return FALSE;
+            }
+            break;
+
+        case ACCESS_APPEND:
+            return seek_to_end(self);
+            break;
+        case ACCESS_NULL:
+            g_assert_not_reached();
+    }
+
+    g_assert(pself->access_mode == mode);
+
+    return TRUE;
+}
+/* }}} */
+
+static gboolean s3_device_property_get(Device * p_self, DevicePropertyId id,
+                                       GValue * val) {
+    S3Device * self;
+    const DevicePropertyBase * base;
+
+    self = S3_DEVICE(p_self);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    base = device_property_get_by_id(id);
+    g_return_val_if_fail(self != NULL, FALSE);
+    
+    g_value_unset_init(val, base->type);
+    
+    if (id == PROPERTY_S3_SECRET_KEY) {
+        if (self->secret_key != NULL) {
+            g_value_set_string(val, self->secret_key);
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    } else if (id == PROPERTY_S3_ACCESS_KEY) {
+        if (self->access_key != NULL) {
+            g_value_set_string(val, self->access_key);
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    }
+#ifdef WANT_DEVPAY
+    else if (id == PROPERTY_S3_USER_TOKEN) {
+        if (self->user_token != NULL) {
+            g_value_set_string(val, self->user_token);
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    }
+#endif /* WANT_DEVPAY */
+    else if (id == PROPERTY_VERBOSE) {
+        g_value_set_boolean(val, self->verbose);
+        return TRUE;
+    } else {
+        /* chain up */
+        if (parent_class->property_get) {
+            return (parent_class->property_get)(p_self, id, val);
+        } else {
+            return FALSE;
+        }
+    }
+
+    g_assert_not_reached();
+}
+
+static gboolean s3_device_property_set(Device * p_self, DevicePropertyId id,
+                                       GValue * val) {
+    S3Device * self;
+    const DevicePropertyBase * base;
+
+    self = S3_DEVICE(p_self);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    base = device_property_get_by_id(id);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    g_return_val_if_fail(G_VALUE_HOLDS(val, base->type), FALSE);
+
+    if (id == PROPERTY_S3_SECRET_KEY) {
+        if (p_self->access_mode != ACCESS_NULL)
+            return FALSE;
+        amfree(self->secret_key);
+        self->secret_key = g_value_dup_string(val);
+        device_clear_volume_details(p_self);
+        return TRUE;
+    } else if (id == PROPERTY_S3_ACCESS_KEY) {
+        if (p_self->access_mode != ACCESS_NULL)
+            return FALSE;
+        amfree(self->access_key);
+        self->access_key = g_value_dup_string(val);
+        device_clear_volume_details(p_self);
+        return TRUE;
+    }
+#ifdef WANT_DEVPAY
+    else if (id == PROPERTY_S3_USER_TOKEN) {
+        if (p_self->access_mode != ACCESS_NULL)
+            return FALSE;
+        amfree(self->user_token);
+        self->user_token = g_value_dup_string(val);
+        device_clear_volume_details(p_self);
+        return TRUE;
+    }
+#endif /* WANT_DEVPAY */
+    else if (id == PROPERTY_VERBOSE) {
+        self->verbose = g_value_get_boolean(val);
+       /* Our S3 handle may not yet have been instantiated; if so, it will
+        * get the proper verbose setting when it is created */
+       if (self->s3)
+           s3_verbose(self->s3, self->verbose);
+       return TRUE;
+    } else {
+        if (parent_class->property_set) {
+            return (parent_class->property_set)(p_self, id, val);
+        } else {
+            return FALSE;
+        }
+    }
+
+    g_assert_not_reached();
+}
+
+/* functions for writing */
+
+/* {{{ s3_device_start_file */
+
+static gboolean
+s3_device_start_file (Device *pself, const dumpfile_t *jobInfo) {
+    S3Device *self = S3_DEVICE(pself);
+    char *amanda_header;
+    int header_size;
+    gboolean header_fits, result;
+    char *key;
+
+    g_return_val_if_fail (self != NULL, FALSE);
+
+    /* Build the amanda header. */
+    amanda_header = device_build_amanda_header(pself, jobInfo,
+                                               &header_size, &header_fits);
+    g_return_val_if_fail(amanda_header != NULL, FALSE);
+    g_return_val_if_fail(header_fits, FALSE);
+
+    /* set the file and block numbers correctly */
+    pself->file = (pself->file > 0)? pself->file+1 : 1;
+    pself->block = 0;
+    pself->in_file = TRUE;
+
+    /* write it out as a special block (not the 0th) */
+    key = special_file_to_key(self, "filestart", pself->file);
+    result = s3_upload(self->s3, self->bucket, key, amanda_header, header_size);
+    g_free(amanda_header);
+    g_free(key);
+    if (!result) {
+        fprintf(stderr, _("While writing filestart header: %s\n"),
+                s3_strerror(self->s3));
+        return FALSE;
+    }
+
+    return TRUE;
+}
+/* }}} */
+
+/* {{{ s3_device_write_block */
+static gboolean
+s3_device_write_block (Device * pself, guint size, gpointer data,
+                         gboolean last_block) {
+    gboolean result;
+    char *filename;
+    S3Device * self = S3_DEVICE(pself);;
+
+    g_assert (self != NULL);
+    g_assert (data != NULL);
+    
+    filename = file_and_block_to_key(self, pself->file, pself->block);
+
+    result = s3_upload(self->s3, self->bucket, filename, data, size);
+    g_free(filename);
+    if (!result) {
+        fprintf(stderr, _("While writing data block to S3: %s\n"),
+                s3_strerror(self->s3));
+        return FALSE;
+    }
+
+    pself->block++;
+
+    /* if this is the last block, finish the file */
+    if (last_block) {
+        return s3_device_finish_file(pself);
+    }
+
+    return TRUE;
+}
+/* }}} */
+
+/* {{{ s3_device_finish_file */
+static gboolean
+s3_device_finish_file (Device * pself) {
+    /* we're not in a file anymore */
+    pself->in_file = FALSE;
+
+    return TRUE;
+}
+/* }}} */
+
+/* {{{ s3_device_recycle_file */
+static gboolean
+s3_device_recycle_file(Device *pself, guint file) {
+    S3Device *self = S3_DEVICE(pself);
+
+    return delete_file(self, file);
+}
+/* }}} */
+
+/* functions for reading */
+
+/* {{{ s3_device_seek_file */
+static dumpfile_t*
+s3_device_seek_file(Device *pself, guint file) {
+    S3Device *self = S3_DEVICE(pself);
+    gboolean result;
+    char *key;
+    gpointer buf;
+    guint buf_size;
+    dumpfile_t *amanda_header;
+
+    pself->file = file;
+    pself->block = 0;
+    pself->in_file = TRUE;
+
+    /* read it in */
+    key = special_file_to_key(self, "filestart", pself->file);
+    result = s3_read(self->s3, self->bucket, key, &buf, &buf_size, S3_DEVICE_MAX_BLOCK_SIZE);
+    g_free(key);
+    if (!result) {
+        guint response_code;
+        s3_error_code_t s3_error_code;
+        s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
+
+        /* if it's an expected error (not found), check what to do. */
+        if (response_code == 404 && s3_error_code == S3_ERROR_NoSuchKey) {
+            int next_file;
+            pself->file = -1;
+            pself->in_file = FALSE;
+            next_file = find_next_file(self, pself->file);
+            if (next_file > 0) {
+                /* Note short-circut of dispatcher. */
+                return s3_device_seek_file(pself, next_file);
+            } else if (next_file == 0) {
+                /* No next file. Check if we are one past the end. */
+                key = special_file_to_key(self, "filestart", pself->file - 1);
+                result = s3_read(self->s3, self->bucket, key, &buf, &buf_size,
+                                 S3_DEVICE_MAX_BLOCK_SIZE);
+                g_free(key);
+                if (result) {
+                    return make_tapeend_header();
+                } else {
+                    return NULL;
+                }
+            }
+        } else {
+            /* An error occured finding out if we are the last file. */
+            return NULL;
+        }
+    }
+   
+    /* and make a dumpfile_t out of it */
+    g_assert(buf != NULL);
+    amanda_header = g_new(dumpfile_t, 1);
+    fh_init(amanda_header);
+    parse_file_header(buf, amanda_header, buf_size);
+    g_free(buf);
+
+    switch (amanda_header->type) {
+        case F_DUMPFILE:
+        case F_CONT_DUMPFILE:
+        case F_SPLIT_DUMPFILE:
+            return amanda_header;
+
+        default:
+            fprintf(stderr,
+                    _("Invalid amanda header while reading file header\n"));
+            g_free(amanda_header);
+            return NULL;
+    }
+}
+/* }}} */
+
+/* {{{ s3_device_seek_block */
+static gboolean
+s3_device_seek_block(Device *pself, guint64 block) {
+    pself->block = block;
+    return TRUE;
+}
+/* }}} */
+
+/* {{{ s3_device_read_block */
+static int
+s3_device_read_block (Device * pself, gpointer data, int *size_req) {
+    S3Device * self = S3_DEVICE(pself);
+    char *key;
+    gpointer buf;
+    gboolean result;
+    guint buf_size;
+
+    g_assert (self != NULL);
+
+    /* get the file*/
+    key = file_and_block_to_key(self, pself->file, pself->block);
+    g_assert(key != NULL);
+    if (self->cached_key && (0 == strcmp(key, self->cached_key))) {
+        /* use the cached copy and clear the cache */
+        buf = self->cached_buf;
+        buf_size = self->cached_size;
+
+        self->cached_buf = NULL;
+        g_free(self->cached_key);
+        self->cached_key = NULL;
+    } else {
+        /* clear the cache and actually download the file */
+        if (self->cached_buf) {
+            g_free(self->cached_buf);
+            self->cached_buf = NULL;
+        }
+        if (self->cached_key) {
+            g_free(self->cached_key);
+            self->cached_key = NULL;
+        }
+
+        result = s3_read(self->s3, self->bucket, key, &buf, &buf_size, S3_DEVICE_MAX_BLOCK_SIZE);
+        if (!result) {
+            guint response_code;
+            s3_error_code_t s3_error_code;
+            s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
+
+            g_free(key);
+            key = NULL;
+
+            /* if it's an expected error (not found), just return -1 */
+            if (response_code == 404 && s3_error_code == S3_ERROR_NoSuchKey) {
+                pself->is_eof = TRUE;
+                pself->in_file = FALSE;
+                return -1;
+            }
+
+            /* otherwise, log it and return FALSE */
+            fprintf(stderr, _("While reading data block from S3: %s\n"),
+                    s3_strerror(self->s3));
+            return -1;
+        }
+    }
+
+    /* INVARIANT: cache is NULL */
+    g_assert(self->cached_buf == NULL);
+    g_assert(self->cached_key == NULL);
+
+    /* now see how the caller wants to deal with that */
+    if (data == NULL || *size_req < 0 || buf_size > (guint)*size_req) {
+        /* A size query or short buffer -- load the cache and return the size*/
+        self->cached_buf = buf;
+        self->cached_key = key;
+        self->cached_size = buf_size;
+
+        *size_req = buf_size;
+        return 0;
+    } else {
+        /* ok, all checks are passed -- copy the data */
+        *size_req = buf_size;
+        g_memmove(data, buf, buf_size);
+        g_free(key);
+        g_free(buf);
+
+        /* move on to the next block */
+        pself->block++;
+
+        return buf_size;
+    }
+}
+/* }}} */
diff --git a/device-src/s3-device.h b/device-src/s3-device.h
new file mode 100644 (file)
index 0000000..286cb36
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#ifndef __S3_DEVICE_H__
+#define __S3_DEVICE_H__
+#include <glib.h>
+#include <curl/curl.h>
+#include <glib-object.h>
+#include "s3.h"
+
+/*
+ * Constants
+ */
+
+/*
+ * Type checking and casting macros
+ */
+#define TYPE_S3_DEVICE (s3_device_get_type())
+#define S3_DEVICE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), s3_device_get_type(), S3Device)
+#define S3_DEVICE_CONST(obj)   G_TYPE_CHECK_INSTANCE_CAST((obj), s3_device_get_type(), S3Device const)
+#define S3_DEVICE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), s3_device_get_type(), S3DeviceClass)
+#define IS_S3_DEVICE(obj)      G_TYPE_CHECK_INSTANCE_TYPE((obj), s3_device_get_type ())
+
+#define S3_DEVICE_GET_CLASS(obj)       G_TYPE_INSTANCE_GET_CLASS((obj), s3_device_get_type(), S3DeviceClass)
+
+/*
+ * Main object structure
+ */
+typedef struct _S3MetadataFile S3MetadataFile;
+
+#ifndef __TYPEDEF_S3_DEVICE__
+#define __TYPEDEF_S3_DEVICE__
+typedef struct _S3Device S3Device;
+#endif
+struct _S3Device {
+    Device __parent__;
+    
+    /* The "easy" curl handle we use to access Amazon S3 */
+    S3Handle *s3;
+
+    /* S3 access information */
+    char *bucket;
+    char *prefix;
+
+    /* The S3 access information. */
+    char *secret_key;
+    char *access_key;
+#ifdef WANT_DEVPAY
+    char *user_token;
+#endif
+
+    /* a cache for unsuccessful reads (where we get the file but the caller
+     * doesn't have space for it or doesn't want it), where we expect the
+     * next call will request the same file.
+     */
+    char *cached_buf;
+    char *cached_key;
+    int cached_size;
+
+    /* Produce verbose output? */
+    gboolean verbose;
+    /* Set to FALSE once s3_device_open_device is finished. */
+    gboolean initializing;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _S3DeviceClass S3DeviceClass;
+struct _S3DeviceClass {
+    DeviceClass __parent__;
+};
+
+
+/*
+ * Public methods
+ */
+GType  s3_device_get_type      (void);
+void    s3_device_register    (void);
+
+#endif
diff --git a/device-src/s3.c b/device-src/s3.c
new file mode 100644 (file)
index 0000000..dfd29dc
--- /dev/null
@@ -0,0 +1,1397 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* TODO
+ * - Compute and send Content-MD5 header
+ * - check SSL certificate
+ * - collect speed statistics
+ * - debugging mode
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <regex.h>
+#include <time.h>
+#include "util.h"
+#include "amanda.h"
+#include "s3.h"
+#include "base64.h"
+#include <curl/curl.h>
+
+/* Constant renamed after version 7.10.7 */
+#ifndef CURLINFO_RESPONSE_CODE
+#define CURLINFO_RESPONSE_CODE CURLINFO_HTTP_CODE
+#endif
+
+/* We don't need OpenSSL's kerberos support, and it's broken in
+ * RHEL 3 anyway. */
+#define OPENSSL_NO_KRB5
+
+#ifdef HAVE_OPENSSL_HMAC_H
+# include <openssl/hmac.h>
+#else
+# ifdef HAVE_CRYPTO_HMAC_H
+#  include <crypto/hmac.h>
+# else
+#  ifdef HAVE_HMAC_H
+#   include <hmac.h>
+#  endif
+# endif
+#endif
+
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+/*
+ * Constants / definitions
+ */
+
+/* Maximum key length as specified in the S3 documentation
+ * (*excluding* null terminator) */
+#define S3_MAX_KEY_LENGTH 1024
+
+#define AMAZON_SECURITY_HEADER "x-amz-security-token"
+
+/* parameters for exponential backoff in the face of retriable errors */
+
+/* start at 0.01s */
+#define EXPONENTIAL_BACKOFF_START_USEC 10000
+/* double at each retry */
+#define EXPONENTIAL_BACKOFF_BASE 2
+/* retry 15 times (for a total of about 5 minutes spent waiting) */
+#define EXPONENTIAL_BACKOFF_MAX_RETRIES 5
+
+/* general "reasonable size" parameters */
+#define MAX_ERROR_RESPONSE_LEN (100*1024)
+
+/* Results which should always be retried */
+#define RESULT_HANDLING_ALWAYS_RETRY \
+        { 400,  S3_ERROR_RequestTimeout,     0,                         S3_RESULT_RETRY }, \
+        { 409,  S3_ERROR_OperationAborted,   0,                         S3_RESULT_RETRY }, \
+        { 412,  S3_ERROR_PreconditionFailed, 0,                         S3_RESULT_RETRY }, \
+        { 500,  S3_ERROR_InternalError,      0,                         S3_RESULT_RETRY }, \
+        { 501,  S3_ERROR_NotImplemented,     0,                         S3_RESULT_RETRY }, \
+        { 0,    0,                           CURLE_COULDNT_CONNECT,     S3_RESULT_RETRY }, \
+        { 0,    0,                           CURLE_PARTIAL_FILE,        S3_RESULT_RETRY }, \
+        { 0,    0,                           CURLE_OPERATION_TIMEOUTED, S3_RESULT_RETRY }, \
+        { 0,    0,                           CURLE_SEND_ERROR,          S3_RESULT_RETRY }, \
+        { 0,    0,                           CURLE_RECV_ERROR,          S3_RESULT_RETRY }
+
+/*
+ * Data structures and associated functions
+ */
+
+struct S3Handle {
+    /* (all strings in this struct are freed by s3_free()) */
+
+    char *access_key;
+    char *secret_key;
+#ifdef WANT_DEVPAY
+    char *user_token;
+#endif
+
+    CURL *curl;
+
+    gboolean verbose;
+
+    /* information from the last request */
+    char *last_message;
+    guint last_response_code;
+    s3_error_code_t last_s3_error_code;
+    CURLcode last_curl_code;
+    guint last_num_retries;
+    void *last_response_body;
+    guint last_response_body_size;
+};
+
+/*
+ * S3 errors */
+
+/* (see preprocessor magic in s3.h) */
+
+static char * s3_error_code_names[] = {
+#define S3_ERROR(NAME) #NAME
+    S3_ERROR_LIST
+#undef S3_ERROR
+};
+
+/* Convert an s3 error name to an error code.  This function
+ * matches strings case-insensitively, and is appropriate for use
+ * on data from the network.
+ *
+ * @param s3_error_code: the error name
+ * @returns: the error code (see constants in s3.h)
+ */
+static s3_error_code_t
+s3_error_code_from_name(char *s3_error_name);
+
+/* Convert an s3 error code to a string
+ *
+ * @param s3_error_code: the error code to convert
+ * @returns: statically allocated string
+ */
+static const char *
+s3_error_name_from_code(s3_error_code_t s3_error_code);
+
+/* Does this install of curl support SSL?
+ *
+ * @returns: boolean
+ */
+static gboolean
+s3_curl_supports_ssl(void);
+
+/*
+ * result handling */
+
+/* result handling is specified by a static array of result_handling structs,
+ * which match based on response_code (from HTTP) and S3 error code.  The result
+ * given for the first match is used.  0 acts as a wildcard for both response_code
+ * and s3_error_code.  The list is terminated with a struct containing 0 for both
+ * response_code and s3_error_code; the result for that struct is the default
+ * result.
+ *
+ * See RESULT_HANDLING_ALWAYS_RETRY for an example.
+ */
+typedef enum {
+    S3_RESULT_RETRY = -1,
+    S3_RESULT_FAIL = 0,
+    S3_RESULT_OK = 1
+} s3_result_t;
+
+typedef struct result_handling {
+    guint response_code;
+    s3_error_code_t s3_error_code;
+    CURLcode curl_code;
+    s3_result_t result;
+} result_handling_t;
+
+/* Lookup a result in C{result_handling}.
+ *
+ * @param result_handling: array of handling specifications
+ * @param response_code: response code from operation
+ * @param s3_error_code: s3 error code from operation, if any
+ * @param curl_code: the CURL error, if any
+ * @returns: the matching result
+ */
+static s3_result_t
+lookup_result(const result_handling_t *result_handling,
+              guint response_code,
+              s3_error_code_t s3_error_code,
+              CURLcode curl_code);
+
+/*
+ * Precompiled regular expressions */
+
+static const char *error_name_regex_string = "<Code>[:space:]*([^<]*)[:space:]*</Code>";
+static const char *message_regex_string = "<Message>[:space:]*([^<]*)[:space:]*</Message>";
+static regex_t error_name_regex, message_regex;
+
+/*
+ * Utility functions
+ */
+
+/* Build a resource URI as /[bucket[/key]], with proper URL
+ * escaping.
+ *
+ * The caller is responsible for freeing the resulting string.
+ *
+ * @param bucket: the bucket, or NULL if none is involved
+ * @param key: the key within the bucket, or NULL if none is involved
+ * @returns: completed URI
+ */
+static char *
+build_resource(const char *bucket,
+               const char *key);
+
+/* Create proper authorization headers for an Amazon S3 REST
+ * request to C{headers}.
+ *
+ * @note: C{X-Amz} headers (in C{headers}) must
+ *  - be in lower-case
+ *  - be in alphabetical order
+ *  - have no spaces around the colon
+ * (don't yell at me -- see the Amazon Developer Guide)
+ *
+ * @param hdl: the S3Handle object
+ * @param verb: capitalized verb for this request ('PUT', 'GET', etc.)
+ * @param resource: the resource being accessed
+ */
+static struct curl_slist *
+authenticate_request(S3Handle *hdl,
+                     const char *verb,
+                     const char *resource);
+
+/* Interpret the response to an S3 operation, assuming CURL completed its request
+ * successfully.  This function fills in the relevant C{hdl->last*} members.
+ *
+ * @param hdl: The S3Handle object
+ * @param body: the response body
+ * @param body_len: the length of the response body
+ * @returns: TRUE if the response should be retried (e.g., network error)
+ */
+static gboolean
+interpret_response(S3Handle *hdl,
+                   CURLcode curl_code,
+                   char *curl_error_buffer,
+                   void *body,
+                   guint body_len);
+
+/* Perform an S3 operation.  This function handles all of the details
+ * of retryig requests and so on.
+ * 
+ * @param hdl: the S3Handle object
+ * @param resource: the UTF-8 encoded resource to access
+                    (without query parameters)
+ * @param uri: the urlencoded URI to access at Amazon (may be identical to resource)
+ * @param verb: the HTTP request method
+ * @param request_body: the request body, or NULL if none should be sent
+ * @param request_body_size: the length of the request body
+ * @param max_response_size: the maximum number of bytes to accept in the
+ * response, or 0 for no limit.
+ * @param preallocate_response_size: for more efficient operation, preallocate
+ * a buffer of this size for the response body.  Addition space will be allocated
+ * if the response exceeds this size.
+ * @param result_handling: instructions for handling the results; see above.
+ * @returns: the result specified by result_handling; details of the response
+ * are then available in C{hdl->last*}
+ */
+static s3_result_t
+perform_request(S3Handle *hdl,
+                const char *resource,
+                const char *uri,
+                const char *verb,
+                const void *request_body,
+                guint request_body_size,
+                guint max_response_size,
+                guint preallocate_response_size,
+                const result_handling_t *result_handling);
+
+/*
+ * Static function implementations
+ */
+
+/* {{{ s3_error_code_from_name */
+static s3_error_code_t
+s3_error_code_from_name(char *s3_error_name)
+{
+    int i;
+
+    if (!s3_error_name) return S3_ERROR_Unknown;
+
+    /* do a brute-force search through the list, since it's not sorted */
+    for (i = 0; i < S3_ERROR_END; i++) {
+        if (strcasecmp(s3_error_name, s3_error_code_names[i]) == 0)
+            return i;
+    }
+
+    return S3_ERROR_Unknown;
+}
+/* }}} */
+
+/* {{{ s3_error_name_from_code */
+static const char *
+s3_error_name_from_code(s3_error_code_t s3_error_code)
+{
+    if (s3_error_code >= S3_ERROR_END)
+        s3_error_code = S3_ERROR_Unknown;
+
+    if (s3_error_code == 0)
+        return NULL;
+
+    return s3_error_code_names[s3_error_code];
+}
+/* }}} */
+
+/* {{{ s3_curl_supports_ssl */
+static gboolean
+s3_curl_supports_ssl(void)
+{
+    static int supported = -1;
+
+    if (supported == -1) {
+#if defined(CURL_VERSION_SSL)
+       curl_version_info_data *info = curl_version_info(CURLVERSION_NOW);
+       if (info->features & CURL_VERSION_SSL)
+           supported = 1;
+       else
+           supported = 0;
+#else
+       supported = 0;
+#endif
+    }
+
+    return supported;
+}
+/* }}} */
+
+/* {{{ lookup_result */
+static s3_result_t
+lookup_result(const result_handling_t *result_handling,
+              guint response_code,
+              s3_error_code_t s3_error_code,
+              CURLcode curl_code)
+{
+    g_return_val_if_fail(result_handling != NULL, S3_RESULT_FAIL);
+
+    while (result_handling->response_code
+        || result_handling->s3_error_code 
+        || result_handling->curl_code) {
+        if ((result_handling->response_code && result_handling->response_code != response_code)
+         || (result_handling->s3_error_code && result_handling->s3_error_code != s3_error_code)
+         || (result_handling->curl_code && result_handling->curl_code != curl_code)) {
+            result_handling++;
+            continue;
+        }
+
+        return result_handling->result;
+    }
+
+    /* return the result for the terminator, as the default */
+    return result_handling->result;
+}
+/* }}} */
+
+/* {{{ build_resource */
+static char *
+build_resource(const char *bucket,
+               const char *key)
+{
+    char *esc_bucket = NULL, *esc_key = NULL;
+    char *resource = NULL;
+
+    if (bucket)
+        if (!(esc_bucket = curl_escape(bucket, 0)))
+            goto cleanup;
+
+    if (key)
+        if (!(esc_key = curl_escape(key, 0)))
+            goto cleanup;
+
+    if (esc_bucket) {
+        if (esc_key) {
+            resource = g_strdup_printf("/%s/%s", esc_bucket, esc_key);
+        } else {
+            resource = g_strdup_printf("/%s", esc_bucket);
+        }
+    } else {
+        resource = g_strdup("/");
+    }
+cleanup:
+    if (esc_bucket) curl_free(esc_bucket);
+    if (esc_key) curl_free(esc_key);
+
+    return resource;
+}
+/* }}} */
+
+/* {{{ authenticate_request */
+static struct curl_slist *
+authenticate_request(S3Handle *hdl,
+                     const char *verb,
+                     const char *resource) 
+{
+    time_t t;
+    struct tm tmp;
+    char date[100];
+    char * buf;
+    HMAC_CTX ctx;
+    char md_value[EVP_MAX_MD_SIZE+1];
+    char auth_base64[40];
+    unsigned int md_len;
+    struct curl_slist *headers = NULL;
+    char * auth_string;
+
+    /* calculate the date */
+    t = time(NULL);
+    if (!localtime_r(&t, &tmp)) perror("localtime");
+    if (!strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %Z", &tmp)) 
+        perror("strftime");
+
+    /* run HMAC-SHA1 on the canonicalized string */
+    HMAC_CTX_init(&ctx);
+    HMAC_Init_ex(&ctx, hdl->secret_key, strlen(hdl->secret_key), EVP_sha1(), NULL);
+    auth_string = g_strconcat(verb, "\n\n\n", date, "\n",
+#ifdef WANT_DEVPAY
+                              AMAZON_SECURITY_HEADER, ":",
+                              hdl->user_token, ",",
+                              STS_PRODUCT_TOKEN, "\n",
+#endif
+                              resource, NULL);
+    HMAC_Update(&ctx, (unsigned char*) auth_string, strlen(auth_string));
+    g_free(auth_string);
+    md_len = EVP_MAX_MD_SIZE;
+    HMAC_Final(&ctx, (unsigned char*)md_value, &md_len);
+    HMAC_CTX_cleanup(&ctx);
+    base64_encode(md_value, md_len, auth_base64, sizeof(auth_base64));
+
+    /* append the new headers */
+#ifdef WANT_DEVPAY
+    /* Devpay headers are included in hash. */
+    buf = g_strdup_printf(AMAZON_SECURITY_HEADER ": %s", hdl->user_token);
+    headers = curl_slist_append(headers, buf);
+    amfree(buf);
+
+    buf = g_strdup_printf(AMAZON_SECURITY_HEADER ": %s", STS_PRODUCT_TOKEN);
+    headers = curl_slist_append(headers, buf);
+    amfree(buf);
+#endif
+
+    buf = g_strdup_printf("Authorization: AWS %s:%s",
+                          hdl->access_key, auth_base64);
+    headers = curl_slist_append(headers, buf);
+    amfree(buf);
+    
+    buf = g_strdup_printf("Date: %s", date);
+    headers = curl_slist_append(headers, buf);
+    amfree(buf);
+
+    return headers;
+}
+/* }}} */
+
+/* {{{ interpret_response */
+static void
+regex_error(regex_t *regex, int reg_result)
+{
+    char *message;
+    int size;
+
+    size = regerror(reg_result, regex, NULL, 0);
+    message = g_malloc(size);
+    if (!message) abort(); /* we're really out of luck */
+    regerror(reg_result, regex, message, size);
+
+    /* this is programmer error (bad regexp), so just log
+     * and abort().  There's no good way to signal a
+     * permanaent error from interpret_response. */
+    g_error(_("Regex error: %s"), message);
+    g_assert_not_reached();
+}
+
+static gboolean
+interpret_response(S3Handle *hdl,
+                   CURLcode curl_code,
+                   char *curl_error_buffer,
+                   void *body,
+                   guint body_len)
+{
+    long response_code = 0;
+    regmatch_t pmatch[2];
+    int reg_result;
+    char *error_name = NULL, *message = NULL;
+    char *body_copy = NULL;
+
+    if (!hdl) return FALSE;
+
+    if (hdl->last_message) g_free(hdl->last_message);
+    hdl->last_message = NULL;
+
+    /* bail out from a CURL error */
+    if (curl_code != CURLE_OK) {
+        hdl->last_curl_code = curl_code;
+        hdl->last_message = g_strdup_printf("CURL error: %s", curl_error_buffer);
+        return FALSE;
+    }
+
+    /* CURL seems to think things were OK, so get its response code */
+    curl_easy_getinfo(hdl->curl, CURLINFO_RESPONSE_CODE, &response_code);
+    hdl->last_response_code = response_code;
+
+    /* 2xx and 3xx codes won't have a response body*/
+    if (200 <= response_code && response_code < 400) {
+        hdl->last_s3_error_code = S3_ERROR_None;
+        return FALSE;
+    }
+
+    /* Now look at the body to try to get the actual Amazon error message. Rather
+     * than parse out the XML, just use some regexes. */
+
+    /* impose a reasonable limit on body size */
+    if (body_len > MAX_ERROR_RESPONSE_LEN) {
+        hdl->last_message = g_strdup("S3 Error: Unknown (response body too large to parse)");
+        return FALSE;
+    } else if (!body || body_len == 0) {
+        hdl->last_message = g_strdup("S3 Error: Unknown (empty response body)");
+        return TRUE; /* perhaps a network error; retry the request */
+    }
+
+    /* use strndup to get a zero-terminated string */
+    body_copy = g_strndup(body, body_len);
+    if (!body_copy) goto cleanup;
+
+    reg_result = regexec(&error_name_regex, body_copy, 2, pmatch, 0);
+    if (reg_result != 0) {
+        if (reg_result == REG_NOMATCH) {
+            error_name = NULL;
+        } else {
+            regex_error(&error_name_regex, reg_result);
+            g_assert_not_reached();
+        }
+    } else {
+        error_name = find_regex_substring(body_copy, pmatch[1]);
+    }
+
+    reg_result = regexec(&message_regex, body_copy, 2, pmatch, 0);
+    if (reg_result != 0) {
+        if (reg_result == REG_NOMATCH) {
+            message = NULL;
+        } else {
+            regex_error(&message_regex, reg_result);
+            g_assert_not_reached();
+        }
+    } else {
+        message = find_regex_substring(body_copy, pmatch[1]);
+    }
+
+    if (error_name) {
+        hdl->last_s3_error_code = s3_error_code_from_name(error_name);
+    }
+
+    if (message) {
+        hdl->last_message = message;
+        message = NULL; /* steal the reference to the string */
+    }
+
+cleanup:
+    if (body_copy) g_free(body_copy);
+    if (message) g_free(message);
+    if (error_name) g_free(error_name);
+
+    return FALSE;
+}
+/* }}} */
+
+/* {{{ perform_request */
+size_t buffer_readfunction(void *ptr, size_t size,
+                           size_t nmemb, void * stream) {
+    CurlBuffer *data = stream;
+    guint bytes_desired = size * nmemb;
+
+    /* check the number of bytes remaining, just to be safe */
+    if (bytes_desired > data->buffer_len - data->buffer_pos)
+        bytes_desired = data->buffer_len - data->buffer_pos;
+
+    memcpy((char *)ptr, data->buffer + data->buffer_pos, bytes_desired);
+    data->buffer_pos += bytes_desired;
+
+    return bytes_desired;
+}
+
+size_t
+buffer_writefunction(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+    CurlBuffer * data = stream;
+    guint new_bytes = size * nmemb;
+    guint bytes_needed = data->buffer_pos + new_bytes;
+
+    /* error out if the new size is greater than the maximum allowed */
+    if (data->max_buffer_size && bytes_needed > data->max_buffer_size)
+        return 0;
+
+    /* reallocate if necessary. We use exponential sizing to make this
+     * happen less often. */
+    if (bytes_needed > data->buffer_len) {
+        guint new_size = MAX(bytes_needed, data->buffer_len * 2);
+        if (data->max_buffer_size) {
+            new_size = MIN(new_size, data->max_buffer_size);
+        }
+        data->buffer = g_realloc(data->buffer, new_size);
+        data->buffer_len = new_size;
+    }
+    g_return_val_if_fail(data->buffer, 0); /* returning zero signals an error to libcurl */
+
+    /* actually copy the data to the buffer */
+    memcpy(data->buffer + data->buffer_pos, ptr, new_bytes);
+    data->buffer_pos += new_bytes;
+
+    /* signal success to curl */
+    return new_bytes;
+}
+
+static int 
+curl_debug_message(CURL *curl G_GNUC_UNUSED, 
+                  curl_infotype type, 
+                  char *s, 
+                  size_t len, 
+                  void *unused G_GNUC_UNUSED)
+{
+    char *lineprefix;
+    char *message;
+    char **lines, **line;
+
+    switch (type) {
+       case CURLINFO_TEXT:
+           lineprefix="";
+           break;
+
+       case CURLINFO_HEADER_IN:
+           lineprefix="Hdr In: ";
+           break;
+
+       case CURLINFO_HEADER_OUT:
+           lineprefix="Hdr Out: ";
+           break;
+
+       default:
+           /* ignore data in/out -- nobody wants to see that in the
+            * debug logs! */
+           return 0;
+    }
+
+    /* split the input into lines */
+    message = g_strndup(s, len);
+    lines = g_strsplit(message, "\n", -1);
+    g_free(message);
+
+    for (line = lines; *line; line++) {
+       if (**line == '\0') continue; /* skip blank lines */
+       g_debug("%s%s", lineprefix, *line);
+    }
+    g_strfreev(lines);
+
+    return 0;
+}
+
+static s3_result_t
+perform_request(S3Handle *hdl,
+                const char *resource,
+                const char *uri,
+                const char *verb,
+                const void *request_body,
+                guint request_body_size,
+                guint max_response_size,
+                guint preallocate_response_size,
+                const result_handling_t *result_handling)
+{
+    const char *baseurl;
+    char *url = NULL;
+    s3_result_t result = S3_RESULT_FAIL; /* assume the worst.. */
+    CURLcode curl_code = CURLE_OK;
+    char curl_error_buffer[CURL_ERROR_SIZE] = "";
+    struct curl_slist *headers = NULL;
+    CurlBuffer readdata = { (void*)request_body, request_body_size, 0, 0 };
+    CurlBuffer writedata = { NULL, 0, 0, max_response_size };
+    gboolean should_retry;
+    guint retries = 0;
+    gulong backoff = EXPONENTIAL_BACKOFF_START_USEC;
+
+    g_return_val_if_fail(hdl != NULL && hdl->curl != NULL, S3_RESULT_FAIL);
+
+    s3_reset(hdl);
+
+    baseurl = s3_curl_supports_ssl()? "https://s3.amazonaws.com":"http://s3.amazonaws.com";
+    url = g_strconcat(baseurl, uri, NULL);
+    if (!url) goto cleanup;
+
+    if (preallocate_response_size) {
+        writedata.buffer = g_malloc(preallocate_response_size);
+        if (!writedata.buffer) goto cleanup;
+        writedata.buffer_len = preallocate_response_size;
+    }
+
+    while (1) {
+        /* reset things */
+        if (headers) {
+            curl_slist_free_all(headers);
+        }
+        readdata.buffer_pos = 0;
+        writedata.buffer_pos = 0;
+       curl_error_buffer[0] = '\0';
+
+        /* set up the request */
+        headers = authenticate_request(hdl, verb, resource);
+
+        if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_VERBOSE, hdl->verbose)))
+            goto curl_error;
+       if (hdl->verbose)
+           if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_DEBUGFUNCTION, 
+                                             curl_debug_message)))
+               goto curl_error;
+        if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_ERRORBUFFER,
+                                          curl_error_buffer)))
+            goto curl_error;
+        if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_NOPROGRESS, 1)))
+            goto curl_error;
+        if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_URL, url)))
+            goto curl_error;
+        if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_HTTPHEADER,
+                                          headers)))
+            goto curl_error;
+        if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_CUSTOMREQUEST,
+                                          verb)))
+            goto curl_error;
+        if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_WRITEFUNCTION, buffer_writefunction))) 
+            goto curl_error;
+        if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_WRITEDATA, &writedata))) 
+            goto curl_error;
+        if (max_response_size) {
+#ifdef CURLOPT_MAXFILESIZE_LARGE
+            if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_MAXFILESIZE_LARGE, (curl_off_t)max_response_size))) 
+                goto curl_error;
+#else
+# ifdef CURLOPT_MAXFILESIZE
+            if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_MAXFILESIZE, (long)max_response_size))) 
+                goto curl_error;
+# else
+           /* no MAXFILESIZE option -- that's OK */
+# endif
+#endif
+       }
+
+        if (request_body) {
+            if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_UPLOAD, 1))) 
+                goto curl_error;
+#ifdef CURLOPT_INFILESIZE_LARGE
+           if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)request_body_size))) 
+                goto curl_error;
+#else
+           if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_INFILESIZE, (long)request_body_size))) 
+                goto curl_error;
+#endif
+            if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_READFUNCTION, buffer_readfunction))) 
+                goto curl_error;
+            if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_READDATA, &readdata))) 
+                goto curl_error;
+        } else {
+            /* Clear request_body options. */
+            if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_UPLOAD, 0))) 
+                goto curl_error;
+            if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_READFUNCTION,
+                                              NULL)))
+                goto curl_error;
+            if ((curl_code = curl_easy_setopt(hdl->curl, CURLOPT_READDATA, 
+                                              NULL)))
+                goto curl_error;
+        }
+
+        /* Perform the request */
+        curl_code = curl_easy_perform(hdl->curl);
+
+
+        /* interpret the response into hdl->last* */
+    curl_error: /* (label for short-circuiting the curl_easy_perform call) */
+        should_retry = interpret_response(hdl, curl_code, curl_error_buffer, 
+                            writedata.buffer, writedata.buffer_pos);
+        
+        /* and, unless we know we need to retry, see what we're to do now */
+        if (!should_retry) {
+            result = lookup_result(result_handling, hdl->last_response_code, 
+                                   hdl->last_s3_error_code, hdl->last_curl_code);
+
+            /* break out of the while(1) unless we're retrying */
+            if (result != S3_RESULT_RETRY)
+                break;
+        }
+
+        if (retries >= EXPONENTIAL_BACKOFF_MAX_RETRIES) {
+            /* we're out of retries, so annotate hdl->last_message appropriately and bail
+             * out. */
+            char *m = g_strdup_printf("Too many retries; last message was '%s'", hdl->last_message);
+            if (hdl->last_message) g_free(hdl->last_message);
+            hdl->last_message = m;
+            result = S3_RESULT_FAIL;
+            break;
+        }
+
+        g_usleep(backoff);
+        retries++;
+        backoff *= EXPONENTIAL_BACKOFF_BASE;
+    }
+
+    if (result != S3_RESULT_OK) {
+        g_debug(_("%s %s failed with %d/%s"), verb, url,
+                hdl->last_response_code,
+                s3_error_name_from_code(hdl->last_s3_error_code)); 
+    }
+
+cleanup:
+    if (url) g_free(url);
+    if (headers) curl_slist_free_all(headers);
+    
+    /* we don't deallocate the response body -- we keep it for later */
+    hdl->last_response_body = writedata.buffer;
+    hdl->last_response_body_size = writedata.buffer_pos;
+    hdl->last_num_retries = retries;
+
+    return result;
+}
+/* }}} */
+
+/*
+ * Public function implementations
+ */
+
+/* {{{ s3_init */
+gboolean
+s3_init(void)
+{
+    char regmessage[1024];
+    int size;
+    int reg_result;
+
+    reg_result = regcomp(&error_name_regex, error_name_regex_string, REG_EXTENDED | REG_ICASE);
+    if (reg_result != 0) {
+        size = regerror(reg_result, &error_name_regex, regmessage, sizeof(regmessage));
+        g_error(_("Regex error: %s"), regmessage);
+        return FALSE;
+    }
+
+    reg_result = regcomp(&message_regex, message_regex_string, REG_EXTENDED | REG_ICASE);
+    if (reg_result != 0) {
+        size = regerror(reg_result, &message_regex, regmessage, sizeof(regmessage));
+        g_error(_("Regex error: %s"), regmessage);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+/* }}} */
+
+/* {{{ s3_open */
+S3Handle *
+s3_open(const char *access_key,
+        const char *secret_key
+#ifdef WANT_DEVPAY
+        ,
+        const char *user_token
+#endif
+        ) {
+    S3Handle *hdl;
+
+    hdl = g_new0(S3Handle, 1);
+    if (!hdl) goto error;
+
+    hdl->verbose = FALSE;
+
+    hdl->access_key = g_strdup(access_key);
+    if (!hdl->access_key) goto error;
+
+    hdl->secret_key = g_strdup(secret_key);
+    if (!hdl->secret_key) goto error;
+
+#ifdef WANT_DEVPAY
+    hdl->user_token = g_strdup(user_token);
+    if (!hdl->user_token) goto error;
+#endif
+
+    hdl->curl = curl_easy_init();
+    if (!hdl->curl) goto error;
+
+    return hdl;
+
+error:
+    s3_free(hdl);
+    return NULL;
+}
+/* }}} */
+
+/* {{{ s3_free */
+void
+s3_free(S3Handle *hdl)
+{
+    s3_reset(hdl);
+
+    if (hdl) {
+        if (hdl->access_key) g_free(hdl->access_key);
+        if (hdl->secret_key) g_free(hdl->secret_key);
+#ifdef WANT_DEVPAY
+        if (hdl->user_token) g_free(hdl->user_token);
+#endif
+        if (hdl->curl) curl_easy_cleanup(hdl->curl);
+
+        g_free(hdl);
+    }
+}
+/* }}} */
+
+/* {{{ s3_reset */
+void
+s3_reset(S3Handle *hdl)
+{
+    if (hdl) {
+        /* We don't call curl_easy_reset here, because doing that in curl
+         * < 7.16 blanks the default CA certificate path, and there's no way
+         * to get it back. */
+        if (hdl->last_message) {
+            g_free(hdl->last_message);
+            hdl->last_message = NULL;
+        }
+
+        hdl->last_response_code = 0;
+        hdl->last_curl_code = 0;
+        hdl->last_s3_error_code = 0;
+        hdl->last_num_retries = 0;
+
+        if (hdl->last_response_body) {
+            g_free(hdl->last_response_body);
+            hdl->last_response_body = NULL;
+        }
+
+        hdl->last_response_body_size = 0;
+    }
+}
+/* }}} */
+
+/* {{{ s3_error */
+void
+s3_error(S3Handle *hdl,
+         const char **message,
+         guint *response_code,
+         s3_error_code_t *s3_error_code,
+         const char **s3_error_name,
+         CURLcode *curl_code,
+         guint *num_retries)
+{
+    if (hdl) {
+        if (message) *message = hdl->last_message;
+        if (response_code) *response_code = hdl->last_response_code;
+        if (s3_error_code) *s3_error_code = hdl->last_s3_error_code;
+        if (s3_error_name) *s3_error_name = s3_error_name_from_code(hdl->last_s3_error_code);
+        if (curl_code) *curl_code = hdl->last_curl_code;
+        if (num_retries) *num_retries = hdl->last_num_retries;
+    } else {
+        /* no hdl? return something coherent, anyway */
+        if (message) *message = "NULL S3Handle";
+        if (response_code) *response_code = 0;
+        if (s3_error_code) *s3_error_code = 0;
+        if (s3_error_name) *s3_error_name = NULL;
+        if (curl_code) *curl_code = 0;
+        if (num_retries) *num_retries = 0;
+    }
+}
+/* }}} */
+
+/* {{{ s3_verbose */
+void
+s3_verbose(S3Handle *hdl, gboolean verbose)
+{
+    hdl->verbose = verbose;
+}
+/* }}} */
+
+/* {{{ s3_sterror */
+char *
+s3_strerror(S3Handle *hdl)
+{
+    const char *message;
+    guint response_code;
+    const char *s3_error_name;
+    CURLcode curl_code;
+    guint num_retries;
+
+    char s3_info[256] = "";
+    char response_info[16] = "";
+    char curl_info[32] = "";
+    char retries_info[32] = "";
+
+    s3_error(hdl, &message, &response_code, NULL, &s3_error_name, &curl_code, &num_retries);
+
+    if (!message) 
+        message = "Unkonwn S3 error";
+    if (s3_error_name)
+        g_snprintf(s3_info, sizeof(s3_info), " (%s)", s3_error_name);
+    if (response_code)
+        g_snprintf(response_info, sizeof(response_info), " (HTTP %d)", response_code);
+    if (curl_code)
+        g_snprintf(curl_info, sizeof(curl_info), " (CURLcode %d)", curl_code);
+    if (num_retries) 
+        g_snprintf(retries_info, sizeof(retries_info), " (after %d retries)", num_retries);
+
+    return g_strdup_printf("%s%s%s%s%s", message, s3_info, curl_info, response_info, retries_info);
+}
+/* }}} */
+
+/* {{{ s3_upload */
+/* Perform an upload. When this function returns, KEY and
+ * BUFFER remain the responsibility of the caller.
+ *
+ * @param self: the s3 device
+ * @param key: the key to which the upload should be made
+ * @param buffer: the data to be uploaded
+ * @param buffer_len: the length of the data to upload
+ * @returns: false if an error ocurred
+ */
+gboolean
+s3_upload(S3Handle *hdl,
+          const char *bucket,
+          const char *key, 
+          gpointer buffer,
+          guint buffer_len)
+{
+    char *resource = NULL;
+    s3_result_t result = S3_RESULT_FAIL;
+    static result_handling_t result_handling[] = {
+        { 200,  0,          0,                   S3_RESULT_OK },
+        RESULT_HANDLING_ALWAYS_RETRY,
+        { 0, 0,    0,                /* default: */ S3_RESULT_FAIL }
+        };
+
+    g_return_val_if_fail(hdl != NULL, FALSE);
+
+    resource = build_resource(bucket, key);
+    if (resource) {
+        result = perform_request(hdl, resource, resource, "PUT",
+                                 buffer, buffer_len, MAX_ERROR_RESPONSE_LEN, 0,
+                                 result_handling);
+        g_free(resource);
+    }
+
+    return result == S3_RESULT_OK;
+}
+/* }}} */
+
+/* {{{ s3_list_keys */
+
+/* Private structure for our "thunk", which tracks where the user is in the list
+ * of keys. */
+struct list_keys_thunk {
+    GSList *filename_list; /* all pending filenames */
+
+    gboolean in_contents; /* look for "key" entities in here */
+    gboolean in_common_prefixes; /* look for "prefix" entities in here */
+
+    gboolean is_truncated;
+    gchar *next_marker;
+
+    gboolean want_text;
+    
+    gchar *text;
+    gsize text_len;
+};
+
+/* Functions for a SAX parser to parse the XML from Amazon */
+
+static void
+list_start_element(GMarkupParseContext *context G_GNUC_UNUSED, 
+                   const gchar *element_name, 
+                   const gchar **attribute_names G_GNUC_UNUSED, 
+                   const gchar **attribute_values G_GNUC_UNUSED, 
+                   gpointer user_data, 
+                   GError **error G_GNUC_UNUSED)
+{
+    struct list_keys_thunk *thunk = (struct list_keys_thunk *)user_data;
+
+    thunk->want_text = 0;
+    if (strcasecmp(element_name, "contents") == 0) {
+        thunk->in_contents = 1;
+    } else if (strcasecmp(element_name, "commonprefixes") == 0) {
+        thunk->in_common_prefixes = 1;
+    } else if (strcasecmp(element_name, "prefix") == 0 && thunk->in_common_prefixes) {
+        thunk->want_text = 1;
+    } else if (strcasecmp(element_name, "key") == 0 && thunk->in_contents) {
+        thunk->want_text = 1;
+    } else if (strcasecmp(element_name, "istruncated")) {
+        thunk->want_text = 1;
+    } else if (strcasecmp(element_name, "nextmarker")) {
+        thunk->want_text = 1;
+    }
+}
+
+static void
+list_end_element(GMarkupParseContext *context G_GNUC_UNUSED, 
+                 const gchar *element_name,
+                 gpointer user_data, 
+                 GError **error G_GNUC_UNUSED)
+{
+    struct list_keys_thunk *thunk = (struct list_keys_thunk *)user_data;
+
+    if (strcasecmp(element_name, "contents") == 0) {
+        thunk->in_contents = 0;
+    } else if (strcasecmp(element_name, "commonprefixes") == 0) {
+        thunk->in_common_prefixes = 0;
+    } else if (strcasecmp(element_name, "key") == 0 && thunk->in_contents) {
+        thunk->filename_list = g_slist_prepend(thunk->filename_list, thunk->text);
+        thunk->text = NULL;
+    } else if (strcasecmp(element_name, "prefix") == 0 && thunk->in_common_prefixes) {
+        thunk->filename_list = g_slist_prepend(thunk->filename_list, thunk->text);
+        thunk->text = NULL;
+    } else if (strcasecmp(element_name, "istruncated") == 0) {
+        if (thunk->text && strncasecmp(thunk->text, "false", 5) != 0)
+            thunk->is_truncated = TRUE;
+    } else if (strcasecmp(element_name, "nextmarker") == 0) {
+        if (thunk->next_marker) g_free(thunk->next_marker);
+        thunk->next_marker = thunk->text;
+        thunk->text = NULL;
+    }
+}
+
+static void
+list_text(GMarkupParseContext *context G_GNUC_UNUSED,
+          const gchar *text, 
+          gsize text_len, 
+          gpointer user_data, 
+          GError **error G_GNUC_UNUSED)
+{
+    struct list_keys_thunk *thunk = (struct list_keys_thunk *)user_data;
+
+    if (thunk->want_text) {
+        if (thunk->text) g_free(thunk->text);
+        thunk->text = g_strndup(text, text_len);
+    }
+}
+
+/* Helper function for list_fetch */
+static gboolean
+list_build_url_component(char **rv,
+                         const char *delim,
+                         const char *key,
+                         const char *value)
+{
+    char *esc_value = NULL;
+    char *new_rv = NULL;
+
+    esc_value = curl_escape(value, 0);
+    if (!esc_value) goto cleanup;
+
+    new_rv = g_strconcat(*rv, delim, key, "=", esc_value, NULL);
+    if (!new_rv) goto cleanup;
+
+    g_free(*rv);
+    *rv = new_rv;
+    curl_free(esc_value);
+
+    return TRUE;
+
+cleanup:
+    if (new_rv) g_free(new_rv);
+    if (esc_value) curl_free(esc_value);
+
+    return FALSE;
+}
+
+/* Perform a fetch from S3; several fetches may be involved in a
+ * single listing operation */
+static s3_result_t
+list_fetch(S3Handle *hdl,
+           const char *resource,
+           const char *prefix, 
+           const char *delimiter, 
+           const char *marker,
+           const char *max_keys)
+{
+    char *urldelim = "?";
+    char *uri = g_strdup(resource);
+    s3_result_t result = S3_RESULT_FAIL;
+    static result_handling_t result_handling[] = {
+        { 200,  0,          0,                   S3_RESULT_OK },
+        RESULT_HANDLING_ALWAYS_RETRY,
+        { 0, 0,    0,                /* default: */ S3_RESULT_FAIL  }
+        };
+
+    /* build the URI */
+    if (prefix) {
+        if (!list_build_url_component(&uri, urldelim, "prefix", prefix)) goto cleanup;
+        urldelim = "&";
+    }
+    if (delimiter) {
+        if (!list_build_url_component(&uri, urldelim, "delimiter", delimiter)) goto cleanup;
+        urldelim = "&";
+    }
+    if (marker) {
+        if (!list_build_url_component(&uri, urldelim, "marker", marker)) goto cleanup;
+        urldelim = "&";
+    }
+    if (max_keys) {
+        if (!list_build_url_component(&uri, urldelim, "max-keys", max_keys)) goto cleanup;
+        urldelim = "&";
+    }
+
+    /* and perform the request on that URI */
+    result = perform_request(hdl, resource, uri, "GET", NULL,
+                             0, MAX_ERROR_RESPONSE_LEN, 0, result_handling);
+
+cleanup:
+    if (uri) g_free(uri);
+    return result;
+}
+
+gboolean
+s3_list_keys(S3Handle *hdl,
+              const char *bucket,
+              const char *prefix,
+              const char *delimiter,
+              GSList **list)
+{
+    char *resource = NULL;
+    struct list_keys_thunk thunk;
+    GMarkupParseContext *ctxt = NULL;
+    static GMarkupParser parser = { list_start_element, list_end_element, list_text, NULL, NULL };
+    GError *err = NULL;
+    s3_result_t result = S3_RESULT_FAIL;
+
+    g_assert(list);
+    *list = NULL;
+    thunk.filename_list = NULL;
+    thunk.text = NULL;
+    thunk.next_marker = NULL;
+
+    resource = build_resource(bucket, NULL);
+    if (!resource) goto cleanup;
+
+    /* Loop until S3 has given us the entire picture */
+    do {
+        /* get some data from S3 */
+        result = list_fetch(hdl, resource, prefix, delimiter, thunk.next_marker, NULL);
+        if (result != S3_RESULT_OK) goto cleanup;
+
+        /* run the parser over it */
+        thunk.in_contents = FALSE;
+        thunk.in_common_prefixes = FALSE;
+        thunk.is_truncated = FALSE;
+        thunk.want_text = FALSE;
+
+        ctxt = g_markup_parse_context_new(&parser, 0, (gpointer)&thunk, NULL);
+
+        if (!g_markup_parse_context_parse(ctxt, hdl->last_response_body, 
+                                          hdl->last_response_body_size, &err)) {
+            if (hdl->last_message) g_free(hdl->last_message);
+            hdl->last_message = g_strdup(err->message);
+            result = S3_RESULT_FAIL;
+            goto cleanup;
+        }
+
+        if (!g_markup_parse_context_end_parse(ctxt, &err)) {
+            if (hdl->last_message) g_free(hdl->last_message);
+            hdl->last_message = g_strdup(err->message);
+            result = S3_RESULT_FAIL;
+            goto cleanup;
+        }
+        
+        g_markup_parse_context_free(ctxt);
+        ctxt = NULL;
+    } while (thunk.next_marker);
+
+cleanup:
+    if (err) g_error_free(err);
+    if (thunk.text) g_free(thunk.text);
+    if (thunk.next_marker) g_free(thunk.next_marker);
+    if (resource) g_free(resource);
+    if (ctxt) g_markup_parse_context_free(ctxt);
+
+    if (result != S3_RESULT_OK) {
+        g_slist_free(thunk.filename_list);
+        return FALSE;
+    } else {
+        *list = thunk.filename_list;
+        return TRUE;
+    }
+}
+/* }}} */
+
+/* {{{ s3_read */
+gboolean
+s3_read(S3Handle *hdl,
+        const char *bucket,
+        const char *key,
+        gpointer *buf_ptr,
+        guint *buf_size,
+        guint max_size)
+{
+    char *resource = NULL;
+    s3_result_t result = S3_RESULT_FAIL;
+    static result_handling_t result_handling[] = {
+        { 200,  0,          0,                   S3_RESULT_OK },
+        RESULT_HANDLING_ALWAYS_RETRY,
+        { 0, 0,    0,                /* default: */ S3_RESULT_FAIL  }
+        };
+
+    g_return_val_if_fail(hdl != NULL, FALSE);
+    g_assert(buf_ptr != NULL);
+    g_assert(buf_size != NULL);
+
+    *buf_ptr = NULL;
+    *buf_size = 0;
+
+    resource = build_resource(bucket, key);
+    if (resource) {
+        result = perform_request(hdl, resource, resource,
+                                 "GET", NULL, 0, max_size, 0, result_handling);
+        g_free(resource);
+
+        /* copy the pointer to the result parameters and remove
+         * our reference to it */
+        if (result == S3_RESULT_OK) {
+            *buf_ptr = hdl->last_response_body;
+            *buf_size = hdl->last_response_body_size;
+            
+            hdl->last_response_body = NULL;
+            hdl->last_response_body_size = 0;
+        }
+    }        
+
+    return result == S3_RESULT_OK;
+}
+/* }}} */
+
+/* {{{ s3_delete */
+gboolean
+s3_delete(S3Handle *hdl,
+          const char *bucket,
+          const char *key)
+{
+    char *resource = NULL;
+    s3_result_t result = S3_RESULT_FAIL;
+    static result_handling_t result_handling[] = {
+        { 204,  0,          0,                   S3_RESULT_OK },
+        RESULT_HANDLING_ALWAYS_RETRY,
+        { 0, 0,    0,                /* default: */ S3_RESULT_FAIL  }
+        };
+
+    g_return_val_if_fail(hdl != NULL, FALSE);
+
+    resource = build_resource(bucket, key);
+    if (resource) {
+        result = perform_request(hdl, resource, resource, "DELETE", NULL, 0,
+                                 MAX_ERROR_RESPONSE_LEN, 0, result_handling);
+        g_free(resource);
+    }
+
+    return result == S3_RESULT_OK;
+}
+/* }}} */
+
+/* {{{ s3_make_bucket */
+gboolean
+s3_make_bucket(S3Handle *hdl,
+               const char *bucket)
+{
+    char *resource = NULL;
+    s3_result_t result = result = S3_RESULT_FAIL;
+    static result_handling_t result_handling[] = {
+        { 200,  0,          0,                   S3_RESULT_OK },
+        RESULT_HANDLING_ALWAYS_RETRY,
+        { 0, 0,    0,                /* default: */ S3_RESULT_FAIL  }
+        };
+
+    g_return_val_if_fail(hdl != NULL, FALSE);
+
+    resource = build_resource(bucket, NULL);
+    if (resource) {
+        result = perform_request(hdl, resource, resource, "PUT", NULL, 0, 
+                                 MAX_ERROR_RESPONSE_LEN, 0, result_handling);
+        g_free(resource);
+    }
+
+    return result == S3_RESULT_OK;
+}
+/* }}} */
diff --git a/device-src/s3.h b/device-src/s3.h
new file mode 100644 (file)
index 0000000..086b6f0
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#ifndef __S3_H__
+#define __S3_H__
+#include <glib.h>
+#include <curl/curl.h>
+
+/*
+ * Data types
+ */
+
+/* An opaque handle.  S3Handles should only be accessed from a single
+ * thread at any given time, although it is fine to use different handles
+ * in different threads simultaneously. */
+typedef struct S3Handle S3Handle;
+
+/*
+ * Constants
+ */
+
+#ifdef WANT_DEVPAY
+/* These are assumed to be already URL-escaped. */
+# define STS_BASE_URL "https://sts.amazonaws.com/"
+# define STS_PRODUCT_TOKEN "{ProductToken}AAAGQXBwVGtu4geoGybuwuk8VEEPzJ9ZANpu0yzbf9g4Gs5Iarzff9B7qaDBEEaWcAzWpcN7zmdMO765jOtEFc4DWTRNkpPSzUnTdkHbdYUamath73OreaZtB86jy/JF0gsHZfhxeKc/3aLr8HNT//DsX3r272zYHLDPWWUbFguOwqNjllnt6BshYREx59l8RrWABLSa37dyJeN+faGvz3uQxiDakZRn3LfInOE6d9+fTFl50LPoP08LCqI/SJfpouzWix7D/cep3Jq8yYNyM1rgAOTF7/wh7r8OuPDLJ/xZUDLfykePIAM="
+#endif
+
+/* This preprocessor magic will enumerate constants named S3_ERROR_XxxYyy for
+ * each of the errors in parentheses.
+ *
+ * see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/ErrorCodeList.html
+ * for Amazon's breakdown of error responses.
+ */
+#define S3_ERROR_LIST \
+    S3_ERROR(None), \
+    S3_ERROR(AccountProblem), \
+    S3_ERROR(AllAccessDisabled), \
+    S3_ERROR(AmbiguousGrantByEmailAddress), \
+    S3_ERROR(OperationAborted), \
+    S3_ERROR(BadDigest), \
+    S3_ERROR(BucketAlreadyExists), \
+    S3_ERROR(BucketNotEmpty), \
+    S3_ERROR(CredentialsNotSupported), \
+    S3_ERROR(EntityTooLarge), \
+    S3_ERROR(IncompleteBody), \
+    S3_ERROR(InternalError), \
+    S3_ERROR(InvalidAccessKeyId), \
+    S3_ERROR(InvalidArgument), \
+    S3_ERROR(InvalidBucketName), \
+    S3_ERROR(InvalidDigest), \
+    S3_ERROR(InvalidRange), \
+    S3_ERROR(InvalidSecurity), \
+    S3_ERROR(InvalidSOAPRequest), \
+    S3_ERROR(InvalidStorageClass), \
+    S3_ERROR(InvalidTargetBucketForLogging), \
+    S3_ERROR(KeyTooLong), \
+    S3_ERROR(InvalidURI), \
+    S3_ERROR(MalformedACLError), \
+    S3_ERROR(MaxMessageLengthExceeded), \
+    S3_ERROR(MetadataTooLarge), \
+    S3_ERROR(MethodNotAllowed), \
+    S3_ERROR(MissingAttachment), \
+    S3_ERROR(MissingContentLength), \
+    S3_ERROR(MissingSecurityElement), \
+    S3_ERROR(MissingSecurityHeader), \
+    S3_ERROR(NoLoggingStatusForKey), \
+    S3_ERROR(NoSuchBucket), \
+    S3_ERROR(NoSuchKey), \
+    S3_ERROR(NotImplemented), \
+    S3_ERROR(NotSignedUp), \
+    S3_ERROR(PreconditionFailed), \
+    S3_ERROR(RequestTimeout), \
+    S3_ERROR(RequestTimeTooSkewed), \
+    S3_ERROR(RequestTorrentOfBucketError), \
+    S3_ERROR(SignatureDoesNotMatch), \
+    S3_ERROR(TooManyBuckets), \
+    S3_ERROR(UnexpectedContent), \
+    S3_ERROR(UnresolvableGrantByEmailAddress), \
+    S3_ERROR(Unknown), \
+    S3_ERROR(END)
+
+typedef enum {
+#define S3_ERROR(NAME) S3_ERROR_ ## NAME
+    S3_ERROR_LIST
+#undef S3_ERROR
+} s3_error_code_t;
+
+/*
+ * Functions
+ */
+
+/* Initialize S3 operation
+ *
+ * As a requirement of C{curl_global_init}, which this function calls,
+ * s3_init I{must} be called before any other threads are started.
+ *
+ * If an error occurs in this function, diagnostic information is 
+ * printed to stderr.
+ *
+ * @returns: false if an error occurred
+ */
+gboolean
+s3_init(void);
+
+/* Set up an S3Handle.
+ */
+S3Handle *
+s3_open(const char * access_key, const char *secret_key
+#ifdef WANT_DEVPAY
+        , const char * user_token
+#endif
+        );
+
+/* Deallocate an S3Handle
+ *
+ * @param hdl: the S3Handle object
+ */
+void
+s3_free(S3Handle *hdl);
+
+/* Reset the information about the last request, including
+ * freeing any allocated memory.  The S3Handle itself is not
+ * freed and may be used again.  This function is called
+ * automatically as needed, and should be called to free memory
+ * when the handle will not be used for some time.
+ *
+ * @param hdl: the S3Handle object
+ */
+void
+s3_reset(S3Handle *hdl);
+
+/* Get the error information for the last operation
+ *
+ * All results are returned via result parameters.  If any parameter is
+ * NULL, that result will not be returned.  Caller is not responsible for
+ * freeing any returned strings, although the results are only valid until
+ * the next call to an S3 function with this handle.
+ * 
+ * @param hdl: the S3Handle object
+ * @param message: (result) the error message, or NULL if none exists
+ * @param response_code: (result) the HTTP response code (or 0 if none exists)
+ * @param s3_error_code: (result) the S3 error code (see constants, above)
+ * @param s3_error_name: (result) the S3 error name (e.g., "RequestTimeout"),
+ * or NULL if none exists
+ * @param curl_code: (result) the curl error code (or 0 if none exists)
+ * @param num_retries: (result) number of retries
+ */
+void
+s3_error(S3Handle *hdl,
+         const char **message,
+         guint *response_code,
+         s3_error_code_t *s3_error_code,
+         const char **s3_error_name,
+         CURLcode *curl_code,
+         guint *num_retries);
+
+/* Control verbose output of HTTP transactions, etc.
+ *
+ * @param hdl: the S3Handle object
+ * @param verbose: if true, send HTTP transactions, etc. to debug output
+ */
+void
+s3_verbose(S3Handle *hdl,
+          gboolean verbose);
+
+/* Get the error information from the last operation on this handle,
+ * formatted as a string.
+ *
+ * Caller is responsible for freeing the resulting string.
+ *
+ * @param hdl: the S3Handle object
+ * @returns: string, or NULL if no error occurred
+ */
+char *
+s3_strerror(S3Handle *hdl);
+
+/* Perform an upload.
+ * 
+ * When this function returns, KEY and BUFFER remain the
+ * responsibility of the caller.
+ *
+ * @param hdl: the S3Handle object
+ * @param bucket: the bucket to which the upload should be made
+ * @param key: the key to which the upload should be made
+ * @param buffer: the data to be uploaded
+ * @param buffer_len: the length of the data to upload
+ * @returns: false if an error ocurred
+ */
+gboolean
+s3_upload(S3Handle *hdl,
+          const char *bucket,
+          const char *key, 
+          gpointer buffer,
+          guint buffer_len);
+
+/* List all of the files matching the pseudo-glob C{PREFIX*DELIMITER*}, 
+ * returning only that portion which matches C{PREFIX*DELIMITER}.  S3 supports
+ * this particular semantics, making it quite efficient.  The returned list
+ * should be freed by the caller.
+ *
+ * @param hdl: the S3Handle object
+ * @param bucket: the bucket to list
+ * @param prefix: the prefix
+ * @param delimiter: delimiter (any length string)
+ * @param list: (output) the list of files
+ * @returns: FALSE if an error occurs
+ */
+gboolean
+s3_list_keys(S3Handle *hdl,
+              const char *bucket,
+              const char *prefix,
+              const char *delimiter,
+              GSList **list);
+
+/* Read an entire file.  The buffer returned is the responsibility of the caller.  A
+ * buffer is only returned if no error occurred, and will be NULL otherwise.
+ *
+ * @param hdl: the S3Handle object
+ * @param bucket: the bucket to read from
+ * @param key: the key to read from
+ * @param buf_ptr: (result) a pointer to a C{gpointer} which will contain a pointer to
+ * the block read
+ * @param buf_size: (result) a pointer to a C{guint} which will contain the size of the
+ * block read
+ * @param max_size: maximum size of the file
+ * @returns: FALSE if an error occurs
+ */
+gboolean
+s3_read(S3Handle *hdl,
+        const char *bucket,
+        const char *key,
+        gpointer *buf_ptr,
+        guint *buf_size,
+        guint max_size);
+
+/* Delete a file.
+ *
+ * @param hdl: the S3Handle object
+ * @param bucket: the bucket to delete from
+ * @param key: the key to delete
+ * @returns: FALSE if an error occurs; a non-existent file is I{not} considered an error.
+ */
+gboolean
+s3_delete(S3Handle *hdl,
+          const char *bucket,
+          const char *key);
+
+/* Create a bucket.
+ *
+ * @param hdl: the S3Handle object
+ * @param bucket: the bucket to create
+ * @returns: FALSE if an error occurs
+ */
+gboolean
+s3_make_bucket(S3Handle *hdl,
+               const char *bucket);
+
+/* Attempt a RefreshAWSSecurityToken on a token; if it succeeds, the old
+ * token will be freed and replaced by the new. If it fails, the old
+ * token is left unchanged and FALSE is returned. */
+gboolean sts_refresh_token(char ** token, const char * directory);
+
+/* These functions are for if you want to use curl on your own. You get more
+ * control, but it's a lot of work that way: */
+typedef struct {
+    char *buffer;
+    guint buffer_len;
+    guint buffer_pos;
+    guint max_buffer_size;
+} CurlBuffer;
+
+/* a CURLOPT_READFUNCTION to read data from a buffer. */
+size_t buffer_readfunction(void *ptr, size_t size,
+                           size_t nmemb, void * stream);
+
+/* a CURLOPT_WRITEFUNCTION to write data to a buffer. */
+size_t
+buffer_writefunction(void *ptr, size_t size, size_t nmemb, void *stream);
+
+/* Adds a null termination to a buffer. */
+void terminate_buffer(CurlBuffer *);
+
+#endif
diff --git a/device-src/semaphore.c b/device-src/semaphore.c
new file mode 100644 (file)
index 0000000..20a2a95
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* GLib does not provide semaphores, which are useful in queue.c.
+   So, we implement it here. */
+
+#include "semaphore.h"
+#include "amanda.h"
+
+semaphore_t* semaphore_new_with_value(int value) {
+    semaphore_t *rval;
+
+    if (!g_thread_supported())
+        return NULL;
+
+    rval = malloc(sizeof(*rval));
+    rval->value = value;
+    rval->mutex = g_mutex_new();
+    rval->decrement_cond = g_cond_new();
+    rval->zero_cond = g_cond_new();
+    
+    if (rval->mutex == NULL || rval->decrement_cond == NULL ||
+        rval->zero_cond == NULL) {
+        semaphore_free(rval);
+        return NULL;
+    } else {
+        return rval;
+    }
+}
+
+void semaphore_free(semaphore_t* o) {
+    g_mutex_free(o->mutex);
+    g_cond_free(o->decrement_cond);
+    g_cond_free(o->zero_cond);
+    free(o);
+}
+
+/* This function checks if the semaphore would is zero or negative.
+ * If so, the zero_cond is signalled. We assume that the mutex is
+ * locked. */
+static void check_empty(semaphore_t * o) {
+    if (o->value <= 0) {
+        g_cond_broadcast(o->zero_cond);
+    }
+}
+
+void semaphore_increment(semaphore_t* o, unsigned int inc) {
+    g_return_if_fail(o != NULL);
+    g_return_if_fail(inc != 0);
+
+    semaphore_force_adjust(o, inc);
+}
+
+void semaphore_decrement(semaphore_t* o, unsigned int dec) {
+    int sdec;
+    g_return_if_fail(o != NULL);
+    sdec = (int) dec;
+    g_return_if_fail(sdec >= 0);
+
+    g_mutex_lock(o->mutex);
+    while (o->value < sdec) {
+        g_cond_wait(o->decrement_cond, o->mutex);
+    }
+    o->value -= sdec;
+    check_empty(o);
+    g_mutex_unlock(o->mutex);
+}
+
+void semaphore_force_adjust(semaphore_t* o, int inc) {
+    g_return_if_fail(o != NULL);
+
+    g_mutex_lock(o->mutex);
+    o->value += inc;
+    if (inc < 0)
+       check_empty(o);
+    else
+       g_cond_broadcast(o->decrement_cond);
+    g_mutex_unlock(o->mutex);
+
+}
+
+void semaphore_force_set(semaphore_t* o, int value) {
+    int oldvalue;
+    g_return_if_fail(o != NULL);
+    
+    g_mutex_lock(o->mutex);
+    oldvalue = o->value;
+    o->value = value;
+    if (value < oldvalue)
+       check_empty(o);
+    else
+       g_cond_broadcast(o->decrement_cond);
+    g_mutex_unlock(o->mutex);
+    
+}
+
+void semaphore_wait_empty(semaphore_t * o) {
+    g_return_if_fail(o != NULL);
+    
+    g_mutex_lock(o->mutex);
+    while (o->value > 0) {
+        g_cond_wait(o->zero_cond, o->mutex);
+    }
+    g_mutex_unlock(o->mutex);
+}
diff --git a/device-src/semaphore.h b/device-src/semaphore.h
new file mode 100644 (file)
index 0000000..17d41fe
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* GLib does not provide semaphores, which are useful in queue.c.
+   So, we implement it here. */
+
+#include <glib.h>
+
+#ifndef SEMAPHORE_H
+
+typedef struct {
+    int value;
+    GMutex *mutex;
+    GCond * decrement_cond;
+    GCond * zero_cond;
+} semaphore_t;
+
+/* Create a new semaphore object with the given value.
+ *
+ * @param value: new value
+ * @returns: newly allocated semaphore_t
+ */
+semaphore_t* semaphore_new_with_value(int value);
+
+/* Shortcut to make a new semaphore with value 1.
+ */
+#define semaphore_new() semaphore_new_with_value(1)
+
+/* Free a semaphore allocated by semaphore_with_new_value().  Be sure the
+ * semaphore is no longer in use by any threads.
+ *
+ * @param sem: the semaphore to free
+ */
+void semaphore_free(semaphore_t *sem);
+
+/* Increment the value of the semaphore by incr.  This corresponds to
+ * Dijkstra's V(), or the typical semaphore's release().
+ *
+ * This function will not block, but may wake other threads waiting
+ * on semaphore_decrement().
+ *
+ * @param sem: the semaphore
+ * @param incr: added to the semaphore's value
+ */
+void semaphore_increment(semaphore_t *sem, unsigned int incr);
+
+/* Shortcut to increment the semaphore by 1.
+ */
+#define semaphore_up(semaphore) semphore_increment(semaphore,1)
+
+/* Decrement the value of the semaphore by incr.  If this operation
+ * would make the semaphore zero or less, block until the semaphore
+ * value is large enough, then perform the decerement operation. Threads
+ * waiting on semaphore_wait_empty() may be awakened if the value
+ * reaches 0.
+ *
+ * @param sem: the semaphore
+ * @param decr: subtracted from the semaphore's value
+ */
+void semaphore_decrement(semaphore_t *sem, unsigned int decr);
+
+/* Shortcut to decrement the semaphore by 1.
+ */
+#define semaphore_down(semaphore) semaphore_decrement(semaphore, 1)
+
+/* Increment or decrement (with a negative incr) the value without
+ * blocking.  Threads waiting on semaphore_decrement() or
+ * semaphore_wait_empty() will be awakened if necessary.
+ *
+ * @param sem: the semaphore
+ * @param incr: added to the semaphore's value
+ */
+void semaphore_force_adjust(semaphore_t *sem, int incr);
+
+/* Set the semaphore to a given value without blocking.  Threads
+ * waiting on semaphore_decrement() or semaphore_wait_empty()
+ * will be awakened if necessary.
+ *
+ * @param sem: the semaphore
+ * @param value: the new value
+ */
+void semaphore_force_set(semaphore_t *sem, int value);
+
+/* Block until the semaphore's value is zero.
+ *
+ * @param sem: the semaphore
+ */
+void semaphore_wait_empty(semaphore_t *sem);
+
+#endif /* SEMAPHORE_H */
diff --git a/device-src/tape-aix.c b/device-src/tape-aix.c
new file mode 100644 (file)
index 0000000..a9665a7
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include <amanda.h>
+#include "tape-ops.h"
+
+/* Tape operations for AIX systems. Most of this stuff is based on
+   documentation from 
+   http://publibn.boulder.ibm.com/doc_link/Ja_JP/a_doc_lib/files/aixfiles/rmt.htm */
+
+/* Uncomment to test compilation on non-AIX systems. */
+/* ---
+#undef MTIOCTOP
+#define STIOCTOP 0
+#define stop mtop
+#define st_op mt_op
+#define st_count mt_count
+#define STREW MTREW
+#define STFSF MTFSF
+#define STRSF MTBSF
+#define STFSR MTFSR
+#define STRSR MTBSR
+#define STWEOF MTWEOF
+--- */
+
+gboolean tape_rewind(int fd) {
+    struct stop st;
+    st.st_op = STREW;
+    st.st_count = 1;
+    return 0 == ioctl(fd, STIOCTOP, &st);
+}
+
+gboolean tape_fsf(int fd, guint count) {
+    struct stop st;
+    st.st_op = STFSF;
+    st.st_count = count;
+    return 0 == ioctl(fd, STIOCTOP, &st);
+}
+
+gboolean tape_bsf(int fd, guint count) {
+    struct stop st;
+    st.st_op = STRSF;
+    st.st_count = count;
+    return 0 == ioctl(fd, STIOCTOP, &st);
+}
+
+gboolean tape_fsr(int fd, guint count) {
+    struct stop st;
+    st.st_op = STFSR;
+    st.st_count = count;
+    return 0 == ioctl(fd, STIOCTOP, &st);
+}
+
+gboolean tape_bsr(int fd, guint count) {
+    struct stop st;
+    st.st_op = STRSR;
+    st.st_count = count;
+    return 0 == ioctl(fd, STIOCTOP, &st);
+}
+
+gint tape_eod(int fd) {
+    g_assert_not_reached();
+    return TAPE_OP_ERROR;
+}
+
+gboolean tape_weof(int fd, guint8 count) {
+    struct stop st;
+    st.st_op = STWEOF;
+    st.st_count = count;
+    return 0 == ioctl(fd, STIOCTOP, &st);
+}
+
+gboolean tape_setcompression(int fd, gboolean on) {
+    return FALSE;
+}
+
+ReadLabelStatusFlags tape_is_tape_device(int fd) {
+    /* AIX doesn't have a no-op. */
+    return READ_LABEL_STATUS_SUCCESS;
+}
+
+TapeCheckResult tape_is_ready(int fd) {
+    return TAPE_CHECK_UNKNOWN;
+}
+
+void tape_device_discover_capabilities(TapeDevice * t_self) {
+    Device * self;
+    GValue val;
+
+    self = DEVICE(t_self);
+    g_return_if_fail(self != NULL);
+
+    bzero(&val, sizeof(val));
+    g_value_init(&val, FEATURE_SUPPORT_FLAGS_TYPE);
+
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_FSF, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_BSF, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_FSR, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_BSR, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_DISABLED | FEATURE_SURETY_GOOD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_EOM, &val);
+
+    g_value_unset_init(&val, G_TYPE_UINT);
+    g_value_set_uint(&val, 2);
+    device_property_set(self, PROPERTY_FINAL_FILEMARKS, &val);
+}
diff --git a/device-src/tape-device.c b/device-src/tape-device.c
new file mode 100644 (file)
index 0000000..1274fcd
--- /dev/null
@@ -0,0 +1,1347 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include <string.h> /* memset() */
+#include "util.h"
+#include "tape-device.h"
+#include "tape-ops.h"
+
+/* This is equal to 2*1024*1024*1024 - 16*1024*1024 - 1, but written 
+   explicitly to avoid overflow issues. */
+#define RESETOFS_THRESHOLD (0x7effffff)
+
+/* Largest possible block size on SCSI systems. */
+#define LARGEST_BLOCK_ESTIMATE (16 * 1024 * 1024)
+
+struct TapeDevicePrivate_s {
+    /* This holds the total number of bytes written to the device,
+       modulus RESETOFS_THRESHOLD. */
+    int write_count;
+};
+
+/* Possible (abstracted) results from a system I/O operation. */
+typedef enum {
+    RESULT_SUCCESS,
+    RESULT_ERROR,        /* Undefined error. */
+    RESULT_SMALL_BUFFER, /* Tried to read with a buffer that is too
+                            small. */
+    RESULT_NO_DATA,      /* End of File, while reading */
+    RESULT_NO_SPACE,     /* Out of space. Sometimes we don't know if
+                            it was this or I/O error, but this is the
+                            preferred explanation. */
+    RESULT_MAX
+} IoResult;
+
+/* here are local prototypes */
+static void tape_device_init (TapeDevice * o);
+static void tape_device_class_init (TapeDeviceClass * c);
+static gboolean tape_device_open_device (Device * self, char * device_name);
+static ReadLabelStatusFlags tape_device_read_label(Device * self);
+static gboolean tape_device_write_block(Device * self, guint size,
+                                        gpointer data, gboolean short_block);
+static int tape_device_read_block(Device * self,  gpointer buf,
+                                       int * size_req);
+static gboolean tape_device_start (Device * self, DeviceAccessMode mode,
+                                   char * label, char * timestamp);
+static gboolean tape_device_start_file (Device * self, const dumpfile_t * ji);
+static dumpfile_t * tape_device_seek_file (Device * self, guint file);
+static gboolean tape_device_seek_block (Device * self, guint64 block);
+static gboolean tape_device_property_get (Device * self, DevicePropertyId id,
+                                          GValue * val);
+static gboolean tape_device_property_set (Device * self, DevicePropertyId id,
+                                          GValue * val);
+static gboolean tape_device_finish (Device * self);
+static IoResult tape_device_robust_read (TapeDevice * self, void * buf,
+                                               int * count);
+static IoResult tape_device_robust_write (TapeDevice * self, void * buf, int count);
+static gboolean tape_device_fsf (TapeDevice * self, guint count);
+static gboolean tape_device_bsf (TapeDevice * self, guint count, guint file);
+static gboolean tape_device_fsr (TapeDevice * self, guint count);
+static gboolean tape_device_bsr (TapeDevice * self, guint count, guint file, guint block);
+static gboolean tape_device_eod (TapeDevice * self);
+
+/* pointer to the class of our parent */
+static DeviceClass *parent_class = NULL;
+
+GType tape_device_get_type (void)
+{
+    static GType type = 0;
+    
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (TapeDeviceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) tape_device_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (TapeDevice),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) tape_device_init,
+            NULL
+        };
+        
+        type = g_type_register_static (TYPE_DEVICE, "TapeDevice",
+                                       &info, (GTypeFlags)0);
+    }
+
+    return type;
+}
+
+static void 
+tape_device_init (TapeDevice * self) {
+    Device * device_self;
+    DeviceProperty prop;
+    GValue response;
+
+    device_self = (Device*)self;
+    bzero(&response, sizeof(response));
+
+    self->private = malloc(sizeof(TapeDevicePrivate));
+
+    /* Clear all fields. */
+    self->min_block_size = self->fixed_block_size = 32768;
+    self->max_block_size = self->read_block_size = MAX_TAPE_BLOCK_BYTES;
+
+    self->fd = -1;
+    
+    self->fsf = self->bsf = self->fsr = self->bsr = self->eom =
+        self->bsf_after_eom = self->compression = self->first_file = 0;
+    self->final_filemarks = 2;
+
+    self->private->write_count = 0;
+
+    /* Register properites */
+    prop.base = &device_property_concurrency;
+    prop.access = PROPERTY_ACCESS_GET_MASK;
+    g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
+    g_value_set_enum(&response, CONCURRENCY_PARADIGM_EXCLUSIVE);
+    device_add_property(device_self, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_streaming;
+    g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
+    g_value_set_enum(&response, STREAMING_REQUIREMENT_DESIRED);
+    device_add_property(device_self, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_appendable;
+    g_value_init(&response, G_TYPE_BOOLEAN);
+    g_value_set_boolean(&response, TRUE);
+    device_add_property(device_self, &prop, &response);
+
+    prop.base = &device_property_partial_deletion;
+    g_value_set_boolean(&response, FALSE);
+    device_add_property(device_self, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_medium_access_type;
+    g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
+    g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
+    device_add_property(device_self, &prop, &response);
+    g_value_unset(&response);
+
+    prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK;
+    prop.base = &device_property_compression;
+    device_add_property(device_self, &prop, NULL);
+
+    prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START;
+    prop.base = &device_property_min_block_size;
+    device_add_property(device_self, &prop, NULL);
+    prop.base = &device_property_max_block_size;
+    device_add_property(device_self, &prop, NULL);
+    prop.base = &device_property_block_size;
+    device_add_property(device_self, &prop, NULL);
+    prop.base = &device_property_fsf;
+    device_add_property(device_self, &prop, NULL);
+    prop.base = &device_property_bsf;
+    device_add_property(device_self, &prop, NULL);
+    prop.base = &device_property_fsr;
+    device_add_property(device_self, &prop, NULL);
+    prop.base = &device_property_bsr;
+    device_add_property(device_self, &prop, NULL);
+    prop.base = &device_property_eom;
+    device_add_property(device_self, &prop, NULL);
+    prop.base = &device_property_bsf_after_eom;
+    device_add_property(device_self, &prop, NULL);
+    prop.base = &device_property_final_filemarks;
+    device_add_property(device_self, &prop, NULL);
+    
+    prop.access = PROPERTY_ACCESS_GET_MASK;
+    prop.base = &device_property_canonical_name;
+    device_add_property(device_self, &prop, NULL);
+}
+
+static void tape_device_finalize(GObject * obj_self) {
+    TapeDevice * self = TAPE_DEVICE(obj_self);
+
+    if(G_OBJECT_CLASS(parent_class)->finalize) \
+           (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+
+    robust_close(self->fd);
+    self->fd = -1;
+    amfree(self->private);
+}
+
+static void 
+tape_device_class_init (TapeDeviceClass * c)
+{
+    DeviceClass *device_class = (DeviceClass *)c;
+    GObjectClass *g_object_class = (GObjectClass *)c;
+
+    parent_class = g_type_class_ref (TYPE_DEVICE);
+    
+    device_class->open_device = tape_device_open_device;
+    device_class->read_label = tape_device_read_label;
+    device_class->write_block = tape_device_write_block;
+    device_class->read_block = tape_device_read_block;
+    device_class->start = tape_device_start;
+    device_class->start_file = tape_device_start_file;
+    device_class->seek_file = tape_device_seek_file;
+    device_class->seek_block = tape_device_seek_block;
+    device_class->property_get = tape_device_property_get;
+    device_class->property_set = tape_device_property_set;
+    device_class->finish = tape_device_finish;
+    
+    g_object_class->finalize = tape_device_finalize;
+}
+
+void tape_device_register(void) {
+    static const char * device_prefix_list[] = { "tape", NULL };
+    register_device(tape_device_factory, device_prefix_list);
+}
+
+/* Open the tape device, trying various combinations of O_RDWR and
+   O_NONBLOCK.  Returns -1 and sets status_result for errors */
+static int try_open_tape_device(TapeDevice * self, char * device_filename,
+       ReadLabelStatusFlags *status_result) {
+    int fd;
+    int save_errno;
+    ReadLabelStatusFlags new_status;
+    TapeCheckResult tcr;
+    *status_result = READ_LABEL_STATUS_SUCCESS;
+
+#ifdef O_NONBLOCK
+    fd  = robust_open(device_filename, O_RDWR | O_NONBLOCK, 0);
+    save_errno = errno;
+    if (fd < 0 && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
+        /* Maybe we don't support O_NONBLOCK for tape devices. */
+        fd = robust_open(device_filename, O_RDWR, 0);
+       save_errno = errno;
+    }
+#else
+    fd = robust_open(device_filename, O_RDWR);
+    save_errno = errno;
+#endif
+    if (fd >= 0) {
+        self->write_open_errno = 0;
+    } else {
+        if (errno == EACCES || errno == EPERM) {
+            /* Device is write-protected. */
+            self->write_open_errno = errno;
+#ifdef O_NONBLOCK
+            fd = robust_open(device_filename, O_RDONLY | O_NONBLOCK, 0);
+           save_errno = errno;
+            if (fd < 0 && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
+                fd = robust_open(device_filename, O_RDONLY, 0);
+               save_errno = errno;
+            }
+#else
+            fd = robust_open(device_filename, O_RDONLY);
+           save_errno = errno;
+#endif
+        }
+    }
+#ifdef O_NONBLOCK
+    /* Clear O_NONBLOCK for operations from now on. */
+    if (fd >= 0)
+       fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
+    errno = save_errno;
+    /* function continues after #endif */
+
+#endif /* O_NONBLOCK */
+
+    if (fd < 0) {
+       g_fprintf(stderr, _("Can't open tape device %s: %s\n"),
+           DEVICE(self)->device_name, strerror(errno));
+       *status_result = READ_LABEL_STATUS_DEVICE_ERROR;
+        return -1;
+    }
+
+    /* Check that this is actually a tape device. */
+    new_status = tape_is_tape_device(fd);
+    if (new_status & (READ_LABEL_STATUS_DEVICE_ERROR | READ_LABEL_STATUS_VOLUME_MISSING)) {
+       g_fprintf(stderr, _("File %s is not a tape device\n"),
+           DEVICE(self)->device_name);
+        robust_close(fd);
+       *status_result = new_status;
+        return -1;
+    }
+
+    tcr = tape_is_ready(fd);
+    if (new_status == TAPE_CHECK_FAILURE) {
+       g_fprintf(stderr, _("Tape device %s is not ready or is empty\n"),
+           DEVICE(self)->device_name);
+        robust_close(fd);
+       *status_result = READ_LABEL_STATUS_DEVICE_ERROR;
+        return -1;
+    }
+
+    return fd;
+}
+
+static gboolean 
+tape_device_open_device (Device * d_self, char * device_name) {
+    TapeDevice * self;
+
+    self = TAPE_DEVICE(d_self);
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (device_name != NULL, FALSE);
+
+    /* Get tape drive/OS info */
+    tape_device_discover_capabilities(self);
+
+    /* And verify the above. */
+    g_assert(feature_support_flags_is_valid(self->fsf));
+    g_assert(feature_support_flags_is_valid(self->bsf));
+    g_assert(feature_support_flags_is_valid(self->fsr));
+    g_assert(feature_support_flags_is_valid(self->bsr));
+    g_assert(feature_support_flags_is_valid(self->eom));
+    g_assert(feature_support_flags_is_valid(self->bsf_after_eom));
+    g_assert(self->final_filemarks == 1 ||
+             self->final_filemarks == 2);
+
+    /* Chain up */
+    if (parent_class->open_device) {
+        if (!(parent_class->open_device)(d_self, device_name)) {
+            robust_close(self->fd);
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+static ReadLabelStatusFlags tape_device_read_label(Device * dself) {
+    TapeDevice * self;
+    char * header_buffer;
+    int buffer_len;
+    IoResult result;
+    dumpfile_t header;
+
+    self = TAPE_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    amfree(dself->volume_label);
+    amfree(dself->volume_time);
+
+    if (self->fd == -1) {
+       ReadLabelStatusFlags status;
+        self->fd = try_open_tape_device(self, dself->device_name, &status);
+       if (self->fd == -1)
+           return status;
+    }
+
+    /* Rewind it. */
+    if (!tape_rewind(self->fd)) {
+        g_fprintf(stderr, "Error rewinding device %s\n",
+                dself->device_name);
+        return (READ_LABEL_STATUS_DEVICE_ERROR |
+                READ_LABEL_STATUS_VOLUME_ERROR);
+    }   
+
+    buffer_len = self->read_block_size;
+    header_buffer = malloc(buffer_len);
+    result = tape_device_robust_read(self, header_buffer, &buffer_len);
+
+    if (result != RESULT_SUCCESS) {
+        free(header_buffer);
+        tape_rewind(self->fd);
+        /* I/O error. */
+        g_fprintf(stderr, "Error reading Amanda header.\n");
+        if (result == RESULT_NO_DATA) {
+            return (READ_LABEL_STATUS_VOLUME_ERROR |
+                    READ_LABEL_STATUS_VOLUME_UNLABELED);
+        } else {
+            return (READ_LABEL_STATUS_DEVICE_ERROR |
+                    READ_LABEL_STATUS_VOLUME_ERROR |
+                    READ_LABEL_STATUS_VOLUME_UNLABELED);
+        }
+    }
+
+    parse_file_header(header_buffer, &header, buffer_len);
+    amfree(header_buffer);
+    if (header.type != F_TAPESTART) {
+        return READ_LABEL_STATUS_VOLUME_UNLABELED;
+    }
+     
+    dself->volume_label = g_strdup(header.name);
+    dself->volume_time = g_strdup(header.datestamp);
+   
+    if (parent_class->read_label) {
+        return parent_class->read_label(dself);
+    } else {
+        return READ_LABEL_STATUS_SUCCESS;
+    }
+}
+
+static gboolean
+tape_device_write_block(Device * pself, guint size,
+                        gpointer data, gboolean short_block) {
+    TapeDevice * self;
+    char *replacement_buffer = NULL;
+    IoResult result;
+
+    self = TAPE_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (self->fd >= 0, FALSE);
+   
+    if (short_block && self->min_block_size > size) {
+        replacement_buffer = malloc(self->min_block_size);
+        memcpy(replacement_buffer, data, size);
+        bzero(replacement_buffer+size, self->min_block_size-size);
+        
+        data = replacement_buffer;
+        size = self->min_block_size;
+    }
+
+    result = tape_device_robust_write(self, data, size);
+    if (result == RESULT_SUCCESS) {
+        if (parent_class->write_block) {
+            (parent_class->write_block)(pself, size, data, short_block);
+        }
+        amfree(replacement_buffer);
+        return TRUE;
+    } else {
+        amfree(replacement_buffer);
+        return FALSE;
+    }
+    
+    g_assert_not_reached();
+}
+
+static int tape_device_read_block (Device * pself, gpointer buf,
+                                   int * size_req) {
+    TapeDevice * self;
+    int size;
+    IoResult result;
+    
+    self = TAPE_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, -1);
+
+    if (buf == NULL || *size_req < (int)self->read_block_size) {
+        /* Just a size query. */
+        *size_req = self->read_block_size;
+        return 0;
+    }
+
+    size = *size_req;
+    result = tape_device_robust_read(self, buf, &size);
+    switch (result) {
+    case RESULT_SUCCESS:
+        *size_req = size;
+        return size;
+    case RESULT_SMALL_BUFFER: {
+        int new_size;
+        /* If this happens, it means that we have:
+         *     (next block size) > (buffer size) >= (read_block_size)
+         * The solution is to ask for an even bigger buffer. We also play
+         * some games to refrain from reading above the SCSI limit or from
+         * integer overflow. */
+        new_size = MIN(INT_MAX/2 - 1, *size_req) * 2;
+        if (new_size > LARGEST_BLOCK_ESTIMATE &&
+            *size_req < LARGEST_BLOCK_ESTIMATE) {
+            new_size = LARGEST_BLOCK_ESTIMATE;
+        }
+        if (new_size <= *size_req) {
+            return -1;
+        } else {
+            *size_req = new_size;
+            return 0;
+        }
+    }
+    case RESULT_NO_DATA:
+        pself->is_eof = TRUE;
+       pself->in_file = FALSE;
+        return -1;
+
+    default:
+        return -1;
+    }
+
+    g_assert_not_reached();
+}
+
+/* Just a helper function for tape_device_start(). */
+static gboolean write_tapestart_header(TapeDevice * self, char * label,
+                                       char * timestamp) {
+     IoResult result;
+     dumpfile_t * header;
+     char * header_buf;
+     int header_size;
+     gboolean header_fits;
+     Device * d_self = (Device*)self;
+     tape_rewind(self->fd);
+    
+     header = make_tapestart_header(d_self, label, timestamp);
+     g_assert(header != NULL);
+     header_buf = device_build_amanda_header(d_self, header, &header_size,
+                                             &header_fits);
+     amfree(header);
+     g_assert(header_buf != NULL);
+                                             
+     if (!header_fits) {
+         amfree(header_buf);
+         g_fprintf(stderr, "Tapestart header won't fit in a single block!\n");
+         return FALSE;
+     }
+
+     g_assert(header_size >= (int)self->min_block_size);
+     result = tape_device_robust_write(self, header_buf, header_size);
+     amfree(header_buf);
+     return (result == RESULT_SUCCESS);
+}
+
+static gboolean 
+tape_device_start (Device * d_self, DeviceAccessMode mode, char * label,
+                   char * timestamp) {
+    TapeDevice * self;
+
+    self = TAPE_DEVICE(d_self);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    if (self->fd == -1) {
+       ReadLabelStatusFlags status;
+        self->fd = try_open_tape_device(self, d_self->device_name, &status);
+       if (self->fd == -1)
+           return FALSE;   /* can't do anything with status here */
+    }
+
+    if (mode != ACCESS_WRITE && d_self->volume_label == NULL) {
+       /* we need a labeled volume for APPEND and READ */
+       if (tape_device_read_label(d_self) != READ_LABEL_STATUS_SUCCESS)
+           return FALSE;
+    }
+
+    d_self->access_mode = mode;
+    d_self->in_file = FALSE;
+
+    if (IS_WRITABLE_ACCESS_MODE(mode)) {
+        if (self->write_open_errno != 0) {
+            /* We tried and failed to open the device in write mode. */
+            g_fprintf(stderr, "Can't open tape device %s for writing: %s\n",
+                    d_self->device_name, strerror(self->write_open_errno));
+            return FALSE;
+        } else if (!tape_rewind(self->fd)) {
+            g_fprintf(stderr, "Couldn't rewind device: %s\n",
+                    strerror(errno));
+        }
+    }
+
+    /* Position the tape */
+    switch (mode) {
+    case ACCESS_APPEND:
+        if (!tape_device_eod(self))
+            return FALSE;
+        self->first_file = TRUE;
+        break;
+        
+    case ACCESS_READ:
+        if (!tape_rewind(self->fd)) {
+            g_fprintf(stderr, "Error rewinding device %s\n",
+                    d_self->device_name);
+            return FALSE;
+        }
+        d_self->file = 0;
+        break;
+
+    case ACCESS_WRITE:
+        if (!write_tapestart_header(self, label, timestamp)) {
+            return FALSE;
+        }
+        self->first_file = TRUE;
+        break;
+
+    default:
+        g_assert_not_reached();
+    }
+
+    if (parent_class->start) {
+        return parent_class->start(d_self, mode, label, timestamp);
+    } else {
+        return TRUE;
+    }
+}
+
+static gboolean tape_device_start_file(Device * d_self,
+                                       const dumpfile_t * info) {
+    TapeDevice * self;
+    IoResult result;
+    char * amanda_header;
+    int header_size;
+    gboolean header_fits;
+
+    self = TAPE_DEVICE(d_self);
+    g_return_val_if_fail(self != NULL, FALSE);
+    g_return_val_if_fail (self->fd >= 0, FALSE);
+
+    if (!(d_self->access_mode == ACCESS_APPEND && self->first_file)) {
+        if (!tape_weof(self->fd, 1)) {
+            g_fprintf(stderr, "Error writing filemark: %s\n", strerror(errno));
+            return FALSE;
+        }
+    }
+
+    self->first_file = FALSE;
+
+    /* Make the Amanda header suitable for writing to the device. */
+    /* Then write the damn thing. */
+    amanda_header = device_build_amanda_header(d_self, info,
+                                               &header_size, &header_fits);
+    g_return_val_if_fail(amanda_header != NULL, FALSE);
+    g_return_val_if_fail(header_fits, FALSE);
+    result = tape_device_robust_write(self, amanda_header, header_size);
+    amfree(amanda_header);
+    if (result == RESULT_SUCCESS) {
+        /* Chain up. */
+        if (parent_class->start_file) {
+            parent_class->start_file(d_self, info);
+        }
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+static dumpfile_t * 
+tape_device_seek_file (Device * d_self, guint file) {
+    TapeDevice * self;
+    int difference;
+    char * header_buffer;
+    dumpfile_t * rval;
+    int buffer_len;
+    IoResult result;
+
+    self = TAPE_DEVICE(d_self);
+    g_return_val_if_fail(d_self != NULL, NULL);
+
+    d_self->in_file = FALSE;
+
+    difference = file - d_self->file;
+
+    /* Check if we already read a filemark. */
+    if (d_self->is_eof) {
+        difference --;
+    }
+
+    if (difference > 0) {
+        /* Seeking forwards */
+        if (!tape_device_fsf(self, difference)) {
+            tape_rewind(self->fd);
+            return NULL;
+        }
+    } else if (difference < 0) {
+        /* Seeking backwards */
+        if (!tape_device_bsf(self, -difference, d_self->file)) {
+            tape_rewind(self->fd);
+            return NULL;
+        }
+    }
+
+    buffer_len = self->read_block_size;
+    header_buffer = malloc(buffer_len);
+    d_self->is_eof = FALSE;
+    result = tape_device_robust_read(self, header_buffer, &buffer_len);
+
+    if (result != RESULT_SUCCESS) {
+        free(header_buffer);
+        tape_rewind(self->fd);
+        if (result == RESULT_NO_DATA) {
+            /* If we read 0 bytes, that means we encountered a double
+             * filemark, which indicates end of tape. This should
+             * work even with QIC tapes on operating systems with
+             * proper support. */
+            return make_tapeend_header();
+        }
+        /* I/O error. */
+        g_fprintf(stderr, "Error reading Amanda header.\n");
+        return FALSE;
+    }
+        
+    rval = malloc(sizeof(*rval));
+    parse_file_header(header_buffer, rval, buffer_len);
+    amfree(header_buffer);
+    switch (rval->type) {
+    case F_DUMPFILE:
+    case F_CONT_DUMPFILE:
+    case F_SPLIT_DUMPFILE:
+        d_self->in_file = TRUE;
+        d_self->file = file;
+        return rval;
+    default:
+        tape_rewind(self->fd);
+        amfree(rval);
+        return NULL;
+    }
+}
+
+static gboolean 
+tape_device_seek_block (Device * d_self, guint64 block) {
+    TapeDevice * self;
+    int difference;
+
+    self = TAPE_DEVICE(d_self);
+    g_return_val_if_fail(d_self != NULL, FALSE);
+
+    difference = block - d_self->block;
+    
+    if (difference > 0) {
+        if (!tape_device_fsr(self, difference))
+            return FALSE;
+    } else if (difference < 0) {
+        if (!tape_device_bsr(self, difference, d_self->file, d_self->block))
+            return FALSE;
+    }
+
+    if (parent_class->seek_block) {
+        return (parent_class->seek_block)(d_self, block);
+    } else {
+        return TRUE;
+    }
+}
+
+/* Just checks that the flag is valid before setting it. */
+static gboolean get_feature_flag(GValue * val, FeatureSupportFlags f) {
+    if (feature_support_flags_is_valid(f)) {
+        g_value_set_flags(val, f);
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+static gboolean 
+tape_device_property_get (Device * d_self, DevicePropertyId id, GValue * val) {
+    TapeDevice * self;
+    const DevicePropertyBase * base;
+
+    self = TAPE_DEVICE(d_self);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    base = device_property_get_by_id(id);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    g_value_unset_init(val, base->type);
+
+    if (id == PROPERTY_COMPRESSION) {
+        g_value_set_boolean(val, self->compression);
+        return TRUE;
+    } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
+        g_value_set_uint(val, self->min_block_size);
+        return TRUE;
+    } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
+        g_value_set_uint(val, self->max_block_size);
+        return TRUE;
+    } else if (id == PROPERTY_BLOCK_SIZE) {
+        if (self->fixed_block_size == 0) {
+            g_value_set_int(val, -1);
+        } else {
+            g_value_set_int(val, self->fixed_block_size);
+        }
+        return TRUE;
+    } else if (id == PROPERTY_FSF) {
+        return get_feature_flag(val, self->fsf);
+    } else if (id == PROPERTY_BSF) {
+        return get_feature_flag(val, self->bsf);
+    } else if (id == PROPERTY_FSR) {
+        return get_feature_flag(val, self->fsr);
+    } else if (id == PROPERTY_BSR) {
+        return get_feature_flag(val, self->bsr);
+    } else if (id == PROPERTY_EOM) {
+        return get_feature_flag(val, self->eom);
+    } else if (id == PROPERTY_BSF_AFTER_EOM) {
+        return get_feature_flag(val, self->bsf_after_eom);
+    } else if (id == PROPERTY_FINAL_FILEMARKS) {
+        g_value_set_uint(val, self->final_filemarks);
+        return TRUE;
+    } else {
+        /* Chain up */
+        if (parent_class->property_get) {
+            return (parent_class->property_get)(d_self, id, val);
+        } else {
+            return FALSE;
+        }
+    }
+
+    g_assert_not_reached();
+}
+
+/* We don't allow overriding of flags with _GOOD surety. That way, if
+   e.g., a feature has no matching IOCTL on a given platform, we don't
+   ever try to set it. */
+static gboolean flags_settable(FeatureSupportFlags request,
+                               FeatureSupportFlags existing) {
+    if (!feature_support_flags_is_valid(request))
+        return FALSE;
+    else if (!feature_support_flags_is_valid(existing))
+        return TRUE;
+    else if (request == existing)
+        return TRUE;
+    else if (existing & FEATURE_SURETY_GOOD)
+        return FALSE;
+    else
+        return TRUE;
+}
+
+/* If the access listed is NULL, and the provided flags can override the
+   existing ones, then do it and return TRUE. */
+static gboolean try_set_feature(DeviceAccessMode mode,
+                                FeatureSupportFlags request,
+                                FeatureSupportFlags * existing) {
+    if (mode != ACCESS_NULL) {
+        return FALSE;
+    } else if (flags_settable(request, *existing)) {
+        *existing = request;
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+static gboolean 
+tape_device_property_set (Device * d_self, DevicePropertyId id, GValue * val) {
+    TapeDevice * self;
+    FeatureSupportFlags feature_request_flags = 0;
+    const DevicePropertyBase * base;
+
+    self = TAPE_DEVICE(d_self);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    base = device_property_get_by_id(id);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    g_return_val_if_fail(G_VALUE_HOLDS(val, base->type), FALSE);
+
+    if (base->type == FEATURE_SUPPORT_FLAGS_TYPE) {
+        feature_request_flags = g_value_get_flags(val);
+        g_return_val_if_fail(
+            feature_support_flags_is_valid(feature_request_flags), FALSE);
+    }
+
+    if (id == PROPERTY_COMPRESSION) {
+        /* We allow this property to be set at any time. This is mostly
+         * because setting compression is a hit-and-miss proposition
+         * at any time; some drives accept the mode setting but don't
+         * actually support compression, while others do support
+         * compression but do it via density settings or some other
+         * way. Set this property whenever you want, but all we'll do
+         * is report whether or not the ioctl succeeded. */
+        gboolean request = g_value_get_boolean(val);
+        if (tape_setcompression(self->fd, request)) {
+            self->compression = request;
+            device_clear_volume_details(d_self);
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
+        if (d_self->access_mode != ACCESS_NULL)
+            return FALSE;
+        self->min_block_size = g_value_get_uint(val);
+        device_clear_volume_details(d_self);
+        return TRUE;
+    } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
+        if (d_self->access_mode != ACCESS_NULL)
+            return FALSE;
+        self->max_block_size = g_value_get_uint(val);
+        device_clear_volume_details(d_self);
+        return TRUE;
+    } else if (id == PROPERTY_BLOCK_SIZE) {
+        if (d_self->access_mode != ACCESS_NULL)
+            return FALSE;
+
+        self->fixed_block_size = g_value_get_int(val);
+        device_clear_volume_details(d_self);
+        return TRUE;
+    } else if (id == PROPERTY_READ_BUFFER_SIZE) {
+        if (d_self->access_mode != ACCESS_NULL)
+            return FALSE;
+        self->read_block_size = g_value_get_uint(val);
+        device_clear_volume_details(d_self);
+        return TRUE;
+    } else if (id == PROPERTY_FSF) {
+        return try_set_feature(d_self->access_mode,
+                               feature_request_flags,
+                               &(self->fsf));
+    } else if (id == PROPERTY_BSF) {
+        return try_set_feature(d_self->access_mode,
+                               feature_request_flags,
+                               &(self->bsf));
+    } else if (id == PROPERTY_FSR) {
+        return try_set_feature(d_self->access_mode,
+                               feature_request_flags,
+                               &(self->fsr));
+    } else if (id == PROPERTY_BSR) {
+        return try_set_feature(d_self->access_mode,
+                               feature_request_flags,
+                               &(self->bsr));
+    } else if (id == PROPERTY_EOM) {
+        /* Setting this to disabled also clears BSF after EOM. */
+        if (try_set_feature(d_self->access_mode,
+                            feature_request_flags,
+                            &(self->eom))) {
+            feature_request_flags &= ~FEATURE_SUPPORT_FLAGS_STATUS_MASK;
+            feature_request_flags |= FEATURE_STATUS_DISABLED;
+            self->bsf_after_eom = feature_request_flags;
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    } else if (id == PROPERTY_BSF_AFTER_EOM) {
+        /* You can only set this if EOM is enabled. */
+        if (self->bsf | FEATURE_STATUS_DISABLED)
+            return FALSE;
+        else
+            return try_set_feature(d_self->access_mode,
+                                   feature_request_flags,
+                                   &(self->bsf_after_eom));
+    } else if (id == PROPERTY_FINAL_FILEMARKS) {
+        guint request = g_value_get_uint(val);
+        if (request == 1 || request == 2) {
+            self->final_filemarks = request;
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    } else {
+        /* Chain up */
+        if (parent_class->property_set) {
+            return (parent_class->property_set)(d_self, id, val);
+        } else {
+            return FALSE;
+        }
+    }
+
+    g_assert_not_reached();
+}
+
+static gboolean 
+tape_device_finish (Device * d_self) {
+    TapeDevice * self;
+
+    self = TAPE_DEVICE(d_self);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    /* Polish off this file, if relevant. */
+    if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
+        if (!device_finish_file(d_self))
+            return FALSE;
+    }
+
+    /* Write an extra filemark, if needed. The OS will give us one for
+       sure. */
+    if (self->final_filemarks > 1 &&
+        IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
+        if (!tape_weof(self->fd, 1)) {
+            g_fprintf(stderr, "Error writing final filemark: %s\n",
+                    strerror(errno));
+            return FALSE;
+        }
+    }
+
+    /* Rewind. */
+    if (!tape_rewind(self->fd)) {
+        g_fprintf(stderr, "Error rewinding tape: %s\n", strerror(errno));
+        return FALSE;
+    }
+
+    d_self->access_mode = ACCESS_NULL;
+
+    if (parent_class->finish) {
+        return (parent_class->finish)(d_self);
+    } else {
+        return TRUE;
+    }
+
+}
+
+/* Works just like read(), except for the following:
+ * 1) Retries on EINTR & friends.
+ * 2) Stores count in parameter, not return value.
+ * 3) Provides explicit return result. */
+static IoResult
+tape_device_robust_read (TapeDevice * self, void * buf, int * count) {
+    Device * d_self;
+    int result;
+
+    d_self = (Device*)self;
+    g_return_val_if_fail(self != NULL, RESULT_ERROR);
+    g_return_val_if_fail(*count >= 0, RESULT_ERROR);
+    /* Callers should ensure this. */
+    g_assert((guint)(*count) <= self->read_block_size);
+
+    for (;;) {
+        result = read(self->fd, buf, *count);
+        if (result > 0) {
+            /* Success. By definition, we read a full block. */
+            *count = result;
+            return RESULT_SUCCESS;
+        } else if (result == 0) {
+            return RESULT_NO_DATA;
+        } else {
+            if (0
+#ifdef EAGAIN
+                || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                || errno == EINTR
+#endif
+                ) {
+                /* Interrupted system call */
+                continue;
+            } else if ((self->fixed_block_size == 0) &&
+                       (0
+#ifdef ENOMEM
+                        || errno == ENOMEM /* bad user-space buffer */
+#endif
+#ifdef EOVERFLOW
+                        || errno == EOVERFLOW /* bad kernel-space buffer */
+#endif
+#ifdef EINVAL
+                        || errno == EINVAL /* ??? */
+#endif
+                        )) {
+                /* Buffer too small. */
+                return RESULT_SMALL_BUFFER;
+            } else {
+                g_fprintf(stderr, "Error reading %d bytes from %s: %s\n",
+                        *count, d_self->device_name, strerror(errno));
+                return RESULT_ERROR;
+            }
+        }
+
+    }
+
+    g_assert_not_reached();
+}
+
+/* Kernel workaround: If needed, poke the kernel so it doesn't fail.
+   at the 2GB boundry. Parameters are G_GNUC_UNUSED in case NEED_RESETOFS
+   is not defined. */
+static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,
+                           int count G_GNUC_UNUSED) {
+#ifdef NEED_RESETOFS
+    int result;
+
+    self->private->write_count += count;
+    if (self->private->write_count < RESETOFS_THRESHOLD) {
+        return;
+    }
+
+    result = lseek(self->fd, 0, SEEK_SET);
+    if (result < 0) {
+        g_fprintf(stderr,
+                "Warning: lseek() failed during kernel 2GB workaround.\n");
+    }
+#endif
+}
+
+static IoResult 
+tape_device_robust_write (TapeDevice * self, void * buf, int count) {
+    Device * d_self;
+    int result;
+
+    g_return_val_if_fail(self != NULL, RESULT_ERROR);
+    d_self = (Device*)self;
+    
+    check_resetofs(self, count);
+
+    for (;;) {
+        result = write(self->fd, buf, count);
+
+        if (result == count) {
+            /* Success. */
+
+            self->private->write_count ++;
+            return RESULT_SUCCESS;
+        } else if (result >= 0) {
+            /* write() returned a short count. This should not happen. */
+            g_fprintf(stderr,
+                  "Mysterious short write on tape device: Tried %d, got %d.\n",
+                    count, result);
+            return RESULT_ERROR;
+        } else if (0
+#ifdef EAGAIN
+                   || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                   || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                   || errno == EINTR
+#endif
+                   ) {
+                /* Interrupted system call */
+            continue;
+        } else if (0
+#ifdef ENOSPC
+                   || errno == ENOSPC
+#endif
+#ifdef EIO
+                   || errno == EIO
+#endif
+                   ) {
+            /* Probably EOT. Print a message if we got EIO. */
+#ifdef EIO
+            if (errno == EIO) {
+                g_fprintf(stderr, "Got EIO on %s, assuming end of tape.\n",
+                        d_self->device_name);
+            }
+#endif
+            return RESULT_NO_SPACE;
+        } else {
+            /* WTF */
+            g_fprintf(stderr,
+     "Kernel gave unexpected write() result of \"%s\" on device %s.\n",
+                    strerror(errno), d_self->device_name);
+            return RESULT_ERROR;
+        }
+    }
+
+    g_assert_not_reached();
+}
+
+/* Reads some number of tape blocks into the bit-bucket. If the count
+   is negative, then we read the rest of the entire file. Returns the
+   number of blocks read, or -1 if an error occured. If we encounter
+   EOF (as opposed to some other error) we return the number of blocks
+   actually read. */
+static int drain_tape_blocks(TapeDevice * self, int count) {
+    char * buffer;
+    int buffer_size;
+    int i;
+
+    buffer_size = self->read_block_size;
+
+    buffer = malloc(sizeof(buffer_size));
+
+    for (i = 0; i < count || count < 0;) {
+        int result;
+
+        result = read(self->fd, buffer, buffer_size);
+        if (result > 0) {
+            i ++;
+            continue;
+        } else if (result == 0) {
+            free(buffer);
+            return i;
+        } else {
+            /* First check for interrupted system call. */
+            if (0
+#ifdef EAGAIN
+                || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                || errno == EINTR
+#endif
+                ) {
+                /* Interrupted system call */
+                continue;
+            } else if (0
+#ifdef ENOSPC
+                       || errno == ENOSPC /* bad user-space buffer */
+#endif
+#ifdef EOVERFLOW
+                       || errno == EOVERFLOW /* bad kernel-space buffer */
+#endif
+#ifdef EINVAL
+                       || errno == EINVAL /* ??? */
+#endif
+                       ) {
+                /* The buffer may not be big enough. But the OS is not
+                   100% clear. We double the buffer and try again, but
+                   in no case allow a buffer bigger than 32 MB. */
+                buffer_size *= 2;
+
+                if (buffer_size > 32*1024*1024) {
+                    free(buffer);
+                    return -1;
+                } else {
+                    buffer = realloc(buffer, buffer_size);
+                    continue;
+                }
+            }
+        }
+    }
+    
+    return count;
+}
+
+/* FIXME: Make sure that there are no cycles in reimplementation
+   dependencies. */
+
+static gboolean 
+tape_device_fsf (TapeDevice * self, guint count) {
+    g_return_val_if_fail (self != NULL, (gboolean )0);
+    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
+    
+    if (self->fsf & FEATURE_STATUS_ENABLED) {
+        return tape_fsf(self->fd, count);
+    } else {
+        guint i;
+        for (i = 0; i < count; i ++) {
+            if (drain_tape_blocks(self, -1) < 0)
+                return FALSE;
+        }
+        return TRUE;
+    }
+}
+
+/* Seek back over count + 1 filemarks to the start of the given file. */
+static gboolean 
+tape_device_bsf (TapeDevice * self, guint count, guint file) {
+    g_return_val_if_fail (self != NULL, (gboolean )0);
+    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
+
+    if (self->bsf & FEATURE_STATUS_ENABLED) {
+        /* The BSF operation is not very smart; it includes the
+           filemark of the present file as part of the count, and seeks
+           to the wrong (BOT) side of the filemark. We compensate for
+           this by seeking one filemark too many, then FSFing back over
+           it.
+
+           If this procedure fails for some reason, we can still try
+           the backup plan. */
+        if (tape_bsf(self->fd, count + 1) &&
+            tape_device_fsf(self, 1))
+            return TRUE;
+    } /* Fall through to backup plan. */
+
+    /* We rewind the tape, then seek forward the given number of
+       files. */
+    if (!tape_rewind(self->fd))
+        return FALSE;
+
+    return tape_device_fsf(self, file);
+}
+
+
+static gboolean 
+tape_device_fsr (TapeDevice * self, guint count) {
+    g_return_val_if_fail (self != NULL, (gboolean )0);
+    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
+
+    if (self->fsr & FEATURE_STATUS_ENABLED) {
+        return tape_fsr(self->fd, count);
+    } else {
+        int result = drain_tape_blocks(self, count);
+        return result > 0 && (int)count == result;
+    }
+}
+
+/* Seek back the given number of blocks to block number block within
+ * the current file, numbered file. */
+
+static gboolean 
+tape_device_bsr (TapeDevice * self, guint count, guint file, guint block) {
+    g_return_val_if_fail (self != NULL, (gboolean )0);
+    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
+    
+    g_return_val_if_fail (self != NULL, (gboolean )0);
+    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
+
+    if (self->bsr & FEATURE_STATUS_ENABLED) {
+        return tape_bsr(self->fd, count);
+    } else {
+        /* We BSF, then FSR. */
+        if (!tape_device_bsf(self, 0, file))
+            return FALSE;
+        
+        return tape_device_fsr(self, block);
+    }
+    g_assert_not_reached();
+}
+
+/* Go to the right place to write more data, and update the file
+   number if possible. */
+static gboolean 
+tape_device_eod (TapeDevice * self) {
+    Device * d_self;
+    g_return_val_if_fail (self != NULL, (gboolean )0);
+    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
+    d_self = (Device*)self;
+
+    if (self->eom & FEATURE_STATUS_ENABLED) {
+        int result;
+        result = tape_eod(self->fd); 
+        if (result == TAPE_OP_ERROR) {
+            return FALSE;
+        } else if (result == TAPE_POSITION_UNKNOWN) {
+            d_self->file = -1;
+        } else {
+            /* We drop by 1 because Device will increment the first
+               time the user does start_file. */
+            d_self->file = result - 1;
+        }
+        return TRUE;
+    } else {
+        int count = 0;
+        if (!tape_rewind(self->fd))
+            return FALSE;
+        
+        for (;;) {
+            /* We alternately read a block and FSF. If the read is
+               successful, then we are not there yet and should FSF
+               again. */
+            int result;
+            result = drain_tape_blocks(self, 1);
+            if (result == 1) {
+                /* More data, FSF. */
+                tape_device_fsf(self, 1);
+                count ++;
+            } else if (result == 0) {
+                /* Finished. */
+                d_self->file = count;
+                return TRUE;
+            } else {
+                return FALSE;
+            }
+        }
+    }
+}
+
+Device *
+tape_device_factory (char * device_type, char * device_name) {
+    Device * rval;
+    g_assert(0 == strcmp(device_type, "tape"));
+    rval = DEVICE(g_object_new(TYPE_TAPE_DEVICE, NULL));
+    if (!device_open_device(rval, device_name)) {
+        g_object_unref(rval);
+        return NULL;
+    } else {
+        return rval;
+    }
+}
diff --git a/device-src/tape-device.h b/device-src/tape-device.h
new file mode 100644 (file)
index 0000000..7bfa1da
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#ifndef TAPE_DEVICE_H
+#define TAPE_DEVICE_H
+
+#include <device.h>
+
+/*
+ * Type checking and casting macros
+ */
+#define TYPE_TAPE_DEVICE       (tape_device_get_type())
+#define TAPE_DEVICE(obj)       G_TYPE_CHECK_INSTANCE_CAST((obj), tape_device_get_type(), TapeDevice)
+#define TAPE_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), tape_device_get_type(), TapeDevice const)
+#define TAPE_DEVICE_CLASS(klass)       G_TYPE_CHECK_CLASS_CAST((klass), tape_device_get_type(), TapeDeviceClass)
+#define IS_TAPE_DEVICE(obj)    G_TYPE_CHECK_INSTANCE_TYPE((obj), tape_device_get_type ())
+
+#define TAPE_DEVICE_GET_CLASS(obj)     G_TYPE_INSTANCE_GET_CLASS((obj), tape_device_get_type(), TapeDeviceClass)
+
+/*
+ * Main object structure
+ */
+typedef struct TapeDevicePrivate_s TapeDevicePrivate;
+typedef struct _TapeDevice {
+    Device __parent__;
+
+    /* It should go without saying that all this stuff is
+     * look-but-don't-touch. */
+    guint min_block_size, max_block_size, fixed_block_size, read_block_size;
+    FeatureSupportFlags fsf, bsf, fsr, bsr, eom, bsf_after_eom;
+    int final_filemarks;
+    gboolean compression;
+    /* 0 if we opened with O_RDWR; error otherwise. */
+    gboolean write_open_errno;
+    gboolean first_file; /* Is this the first file in append mode? */
+    int fd;
+
+    TapeDevicePrivate * private;
+} TapeDevice;
+
+/*
+ * Class definition
+ */
+typedef struct _TapeDeviceClass TapeDeviceClass;
+struct _TapeDeviceClass {
+       DeviceClass __parent__;
+};
+
+
+/*
+ * Public methods
+ */
+GType  tape_device_get_type    (void);
+Device*        tape_device_factory     (char * type,
+                                 char * name);
+void    tape_device_register    (void);
+
+#endif
diff --git a/device-src/tape-ops.h b/device-src/tape-ops.h
new file mode 100644 (file)
index 0000000..bebe28a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#ifndef TAPE_OPS_H
+
+#include <glib.h>
+#include "tape-device.h"
+#include "amanda.h"
+
+#ifdef HAVE_SYS_TAPE_H
+# include <sys/tape.h>
+#endif
+#ifdef HAVE_SYS_MTIO_H
+# include <sys/mtio.h>
+#endif
+
+/* Return codes for tape_eod */
+#define TAPE_OP_ERROR -1
+#define TAPE_POSITION_UNKNOWN -2
+
+/* Real Operations (always return FALSE if not implemented). These are
+ * implemented in one of tape-{uware,aix,xenix,posix}.c, depending on
+ * the platform. */
+gboolean tape_rewind(int fd);
+gboolean tape_fsf(int fd, guint count);
+gboolean tape_bsf(int fd, guint count);
+gboolean tape_fsr(int fd, guint count);
+gboolean tape_bsr(int fd, guint count);
+/* Returns tape position file number, or one of the return codes above. */
+gint tape_eod(int fd);
+gboolean tape_weof(int fd, guint8 count);
+gboolean tape_setcompression(int fd, gboolean on);
+
+typedef enum {
+    TAPE_CHECK_SUCCESS,
+    TAPE_CHECK_UNKNOWN,
+    TAPE_CHECK_FAILURE
+} TapeCheckResult;
+ReadLabelStatusFlags tape_is_tape_device(int fd);
+TapeCheckResult tape_is_ready(int fd);
+
+/* Also implemented in above files. Sets properties on the device. */
+void tape_device_discover_capabilities(TapeDevice * self);
+
+#endif
+
diff --git a/device-src/tape-posix.c b/device-src/tape-posix.c
new file mode 100644 (file)
index 0000000..70e9480
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include "amanda.h"
+#include "util.h"
+#include "tape-ops.h"
+#include "property.h"
+#include <glob.h>
+
+/* Having one name for every operation would be too easy. */
+#if !defined(MTCOMPRESSION) && defined(MTCOMP)
+# define MTCOMPRESSION MTCOMP
+#endif
+
+#if !defined(MTSETBLK) && defined(MTSETBSIZ)
+# define MTSETBLK MTSETBSIZ
+#endif
+
+#if !defined(MTEOM) && defined(MTEOD)
+# define MTEOM MTEOD
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+gboolean tape_rewind(int fd) {
+    int count = 5;
+    time_t stop_time;
+
+    /* We will retry this for up to 30 seconds or 5 retries,
+       whichever is less, because some hardware/software combinations
+       (notably EXB-8200 on FreeBSD) can fail to rewind. */
+    stop_time = time(NULL) + 30;
+
+    while (--count >= 0 && time(NULL) < stop_time) {
+        struct mtop mt;
+        mt.mt_op = MTREW;
+        mt.mt_count = 1;
+
+        if (0 == ioctl(fd, MTIOCTOP, &mt))
+            return TRUE;
+
+        sleep(3);
+    }
+
+    return FALSE;
+}
+
+gboolean tape_fsf(int fd, guint count) {
+    struct mtop mt;
+    mt.mt_op = MTFSF;
+    mt.mt_count = count;
+    return 0 == ioctl(fd, MTIOCTOP, &mt);
+}
+
+gboolean tape_bsf(int fd, guint count) {
+    struct mtop mt;
+    mt.mt_op = MTBSF;
+    mt.mt_count = count;
+    return 0 == ioctl(fd, MTIOCTOP, &mt);
+}
+
+gboolean tape_fsr(int fd, guint count) {
+    struct mtop mt;
+    mt.mt_op = MTFSR;
+    mt.mt_count = count;
+    return 0 == ioctl(fd, MTIOCTOP, &mt);
+}
+
+gboolean tape_bsr(int fd, guint count) {
+    struct mtop mt;
+    mt.mt_op = MTBSR;
+    mt.mt_count = count;
+    return 0 == ioctl(fd, MTIOCTOP, &mt);
+}
+
+gint tape_eod(int fd) {
+    struct mtop mt;
+    struct mtget get;
+    mt.mt_op = MTEOM;
+    mt.mt_count = 1;
+    if (0 != ioctl(fd, MTIOCTOP, &mt))
+        return TAPE_OP_ERROR;
+
+    /* Ignored result. This is just to flush buffers. */
+    mt.mt_op = MTNOP;
+    ioctl(fd, MTIOCTOP, &mt);
+
+    if (0 != ioctl(fd, MTIOCGET, &get))
+        return TAPE_POSITION_UNKNOWN;
+    if (get.mt_fileno < 0)
+        return TAPE_POSITION_UNKNOWN;
+    else
+        return get.mt_fileno;
+}
+
+gboolean tape_weof(int fd, guint8 count) {
+    struct mtop mt;
+    mt.mt_op = MTWEOF;
+    mt.mt_count = count;
+    return 0 == ioctl(fd, MTIOCTOP, &mt);
+}
+
+gboolean tape_setcompression(int fd G_GNUC_UNUSED, 
+       gboolean on G_GNUC_UNUSED) {
+#ifdef MTCOMPRESSION
+    struct mtop mt;
+    mt.mt_op = MTCOMPRESSION;
+    mt.mt_count = on;
+    return 0 == ioctl(fd, MTIOCTOP, &mt);
+#else
+    return 0;
+#endif
+}
+
+ReadLabelStatusFlags tape_is_tape_device(int fd) {
+    struct mtop mt;
+    mt.mt_op = MTNOP;
+    mt.mt_count = 1;
+    if (0 == ioctl(fd, MTIOCTOP, &mt)) {
+        return READ_LABEL_STATUS_SUCCESS;
+    } else {
+       dbprintf("tape_is_tape_device: ioctl(MTIOCTOP/MTNOP) failed: %s",
+                strerror(errno));
+       if (errno == EIO) {
+           /* some devices return EIO while the drive is busy loading */
+           return READ_LABEL_STATUS_DEVICE_ERROR|READ_LABEL_STATUS_VOLUME_MISSING;
+       } else {
+           return READ_LABEL_STATUS_DEVICE_ERROR;
+       }
+    }
+}
+
+TapeCheckResult tape_is_ready(int fd) {
+    struct mtget get;
+    if (0 == ioctl(fd, MTIOCGET, &get)) {
+#if defined(GMT_DR_OPEN)
+        if (!GMT_DR_OPEN(get.mt_gstat)) {
+            return TAPE_CHECK_SUCCESS;
+        } else {
+           dbprintf("tape_is_read: ioctl(MTIOCGET) failed: %s", strerror(errno));
+            return TAPE_CHECK_FAILURE;
+        }
+#else /* Neither macro is defined. */
+        return TAPE_CHECK_UNKNOWN;
+#endif
+    } else {
+        return TAPE_CHECK_FAILURE;
+    }
+}
+
+void tape_device_discover_capabilities(TapeDevice * t_self) {
+    Device * self;
+    GValue val;
+
+    self = DEVICE(t_self);
+    g_return_if_fail(self != NULL);
+
+    bzero(&val, sizeof(val));
+    g_value_init(&val, FEATURE_SUPPORT_FLAGS_TYPE);
+
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_FSF, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_BSF, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_FSR, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_BSR, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_EOM, &val);
+
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_DISABLED | FEATURE_SURETY_BAD | 
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_BSF_AFTER_EOM, &val);
+
+    g_value_unset_init(&val, G_TYPE_UINT);
+    g_value_set_uint(&val, 2);
+    device_property_set(self, PROPERTY_FINAL_FILEMARKS, &val);
+}
diff --git a/device-src/tape-uware.c b/device-src/tape-uware.c
new file mode 100644 (file)
index 0000000..0b86761
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* Tape operations for SVR4 systems. Most of this stuff is based on
+   documentation from http://docsrv.sco.com/cgi-bin/man/man?sdi+7 */
+
+#include <amanda.h>
+#include <tape-ops.h>
+
+/* Uncomment to test on non-SYSV4 systems. */
+/* ---
+#undef MTIOCTOP
+#define T_RWD 0
+#define T_SFF 0
+#define T_SFB 0
+#define T_SBF 0
+#define T_SBB 0
+#define T_WRFILEM 0
+#define T_RDBLKLEN 0
+#define T_WRBLKLEN 0
+#define T_SETCOMP 0
+
+struct blklen {
+    int min_blen, max_blen;
+};
+
+ --- */
+
+gboolean tape_rewind(int fd) {
+    return 0 == ioctl(fd, T_RWD);
+}
+
+gboolean tape_fsf(int fd, guint count) {
+    return 0 == ioctl(fd, T_SFF, count);
+}
+
+gboolean tape_bsf(int fd, guint count) {
+    return 0 == ioctl(fd, T_SFB, count);
+}
+
+gboolean tape_fsr(int fd, guint count) {
+    return 0 == ioctl(fd, T_SBF, count);
+}
+
+gboolean tape_bsr(int fd, guint count) {
+    return 0 == ioctl(fd, T_SBB, count);
+}
+
+int tape_eod(int fd) {
+    g_assert_not_reached();
+    return TAPE_OP_ERROR;
+}
+
+gboolean tape_weof(int fd, guint8 count) {
+    return 0 == ioctl(fd, T_WRFILEM, count);
+}
+
+gboolean tape_setcompression(int fd, gboolean on) {
+    int cmd;
+    if (on) {
+        cmd = 3;
+    } else {
+        cmd = 2;
+    }
+
+    return 0 == ioctl(fd, T_SETCOMP, cmd);
+}
+
+ReadLabelStatusFlags tape_is_tape_device(int fd) {
+    /* If we can read block information, it's probably a tape device. */
+    struct blklen result;
+    if (0 == ioctl(fd, T_RDBLKLEN, &result)) {
+        return READ_LABEL_STATUS_SUCCESS;
+    } else {
+       dbprintf("tape_is_tape_device: ioctl(MTIOCTOP/MTNOP) failed: %s",
+                strerror(errno));
+       return READ_LABEL_STATUS_DEVICE_ERROR;
+    }
+}
+
+TapeCheckResult tape_is_tape_ready(int fd) {
+    return TAPE_CHECK_UNKNOWN;
+}
+
+void tape_device_discover_capabilities(TapeDevice * t_self) {
+    Device * self;
+    GValue val;
+
+    self = DEVICE(t_self);
+    g_return_if_fail(self != NULL);
+
+    bzero(&val, sizeof(val));
+    g_value_init(&val, FEATURE_SUPPORT_FLAGS_TYPE);
+
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_FSF, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_BSF, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_FSR, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_BSR, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_DISABLED | FEATURE_SURETY_GOOD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_EOM, &val);
+
+    g_value_unset_init(&val, G_TYPE_UINT);
+    g_value_set_uint(&val, 2);
+    device_property_set(self, PROPERTY_FINAL_FILEMARKS, &val);
+}
diff --git a/device-src/tape-xenix.c b/device-src/tape-xenix.c
new file mode 100644 (file)
index 0000000..1890cd2
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* Tape operations for XENIX systems. Most of this stuff is based on
+   documentation from
+   http://www.ifthenfi.nl:8080/cgi-bin/ssl_getmanpage?tape+HW+XNX234+tape
+*/
+
+#include <amanda.h>
+#include <tape-ops.h>
+
+/* Uncomment to test compilation on non-XENIX systems. */
+/* --- 
+#undef MTIOCTOP
+#define MT_REWIND 0
+#define MT_STATUS 0
+#define T_RFM 0
+#define T_WFM 0
+struct tape_info {};
+  --- */
+
+gboolean tape_rewind(int fd) {
+    return 0 == ioctl(fd, MT_REWIND);
+}
+
+gboolean tape_fsf(int fd, guint count) {
+    while (--count >= 0) {
+        if (0 != ioctl(fd, T_RFM))
+            return FALSE;
+    }
+    return TRUE;
+}
+
+gboolean tape_bsf(int fd, guint count) {
+    g_assert_not_reached();
+    return FALSE;
+}
+
+gboolean tape_fsr(int fd, guint count) {
+    g_assert_not_reached();
+    return FALSE;
+}
+
+gboolean tape_bsr(int fd, guint count) {
+    g_assert_not_reached();
+    return FALSE;
+}
+
+gint tape_eod(int fd) {
+    g_assert_not_reached();
+    return TAPE_OP_ERROR;
+}
+
+gboolean tape_weof(int fd, guint8 count) {
+    while (count -- > 0) {
+        if (0 != ioctl(fd, T_WFM))
+            return FALSE;
+    } 
+
+    return TRUE;
+}
+
+gboolean tape_setcompression(int fd, gboolean on) {
+    return FALSE;
+}
+
+ReadLabelStatusFlags tape_is_tape_device(int fd) {
+    struct tape_info result;
+    if (0 == ioctl(fd, MT_STATUS, &result)) {
+        return READ_LABEL_STATUS_SUCCESS;
+    } else {
+       dbprintf("tape_is_tape_device: ioctl(MTIOCTOP/MTNOP) failed: %s",
+                strerror(errno));
+       return READ_LABEL_STATUS_DEVICE_ERROR;
+    }
+}
+
+TapeCheckResult tape_is_ready(int fd) {
+    /* We can probably do better. */
+    return TAPE_CHECK_UNKNOWN;
+}
+
+void tape_device_discover_capabilities(TapeDevice * t_self) {
+    Device * self;
+    GValue val;
+
+    self = DEVICE(t_self);
+    g_return_if_fail(self != NULL);
+
+    bzero(&val, sizeof(val));
+    g_value_init(&val, FEATURE_SUPPORT_FLAGS_TYPE);
+
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_ENABLED | FEATURE_SURETY_BAD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_FSF, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_DISABLED | FEATURE_SURETY_GOOD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_BSF, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_DISABLED | FEATURE_SURETY_GOOD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_FSR, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_DISABLED | FEATURE_SURETY_GOOD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_BSR, &val);
+    
+    g_value_set_flags(&val,
+                      FEATURE_STATUS_DISABLED | FEATURE_SURETY_GOOD |
+                      FEATURE_SOURCE_DEFAULT);
+    device_property_set(self, PROPERTY_EOM, &val);
+
+    g_value_unset_init(&val, G_TYPE_UINT);
+    g_value_set_uint(&val, 2);
+    device_property_set(self, PROPERTY_FINAL_FILEMARKS, &val);
+}
diff --git a/device-src/tests/Makefile.am b/device-src/tests/Makefile.am
new file mode 100644 (file)
index 0000000..9c54473
--- /dev/null
@@ -0,0 +1,28 @@
+# Makefile for Amanda tape library.
+
+INCLUDES =     -I$(top_builddir)/common-src \
+               -I$(top_srcdir)/common-src \
+               -I$(top_srcdir)/gnulib \
+               -I$(top_srcdir)/device-src
+
+# automake-style tests
+
+noinst_PROGRAMS = queue_test device_test $(TESTS)
+
+###
+# Because libamanda includes routines (e.g. regex) provided by some system
+# libraries, and because of the way libtool sets up the command line, we
+# need to list libamanda twice here, first to override the system library
+# routines, and second to pick up any references in the other libraries.
+###
+LDADD = ../../common-src/libamanda.la \
+       ../libamdevice.la \
+       ../../common-src/libamanda.la \
+       ../../gnulib/libgnu.la
+
+
+TESTS = semaphore-test vfs_test
+
+semaphore_test_SOURCES = semaphore-test.c
+
+vfs_test_SOURCES = vfs_test.c
diff --git a/device-src/tests/Makefile.in b/device-src/tests/Makefile.in
new file mode 100644 (file)
index 0000000..37fe55e
--- /dev/null
@@ -0,0 +1,964 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for Amanda tape library.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+noinst_PROGRAMS = queue_test$(EXEEXT) device_test$(EXEEXT) \
+       $(am__EXEEXT_1)
+TESTS = semaphore-test$(EXEEXT) vfs_test$(EXEEXT)
+subdir = device-src/tests
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps =  \
+       $(top_srcdir)/config/macro-archive/ac_define_dir.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_perl_version.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_swig.m4 \
+       $(top_srcdir)/config/macro-archive/ax_compare_version.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-dtd.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt-min.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt.m4 \
+       $(top_srcdir)/config/macro-archive/xsltproc.m4 \
+       $(top_srcdir)/config/amanda/amplot.m4 \
+       $(top_srcdir)/config/amanda/bsd-security.m4 \
+       $(top_srcdir)/config/amanda/bsdtcp-security.m4 \
+       $(top_srcdir)/config/amanda/bsdudp-security.m4 \
+       $(top_srcdir)/config/amanda/changer.m4 \
+       $(top_srcdir)/config/amanda/components.m4 \
+       $(top_srcdir)/config/amanda/compress.m4 \
+       $(top_srcdir)/config/amanda/config.m4 \
+       $(top_srcdir)/config/amanda/debugging.m4 \
+       $(top_srcdir)/config/amanda/defaults.m4 \
+       $(top_srcdir)/config/amanda/devprefix.m4 \
+       $(top_srcdir)/config/amanda/dirs.m4 \
+       $(top_srcdir)/config/amanda/documentation.m4 \
+       $(top_srcdir)/config/amanda/dumpers.m4 \
+       $(top_srcdir)/config/amanda/flags.m4 \
+       $(top_srcdir)/config/amanda/flock.m4 \
+       $(top_srcdir)/config/amanda/funcs.m4 \
+       $(top_srcdir)/config/amanda/getfsent.m4 \
+       $(top_srcdir)/config/amanda/i18n.m4 \
+       $(top_srcdir)/config/amanda/ipv6.m4 \
+       $(top_srcdir)/config/amanda/krb4-security.m4 \
+       $(top_srcdir)/config/amanda/krb5-security.m4 \
+       $(top_srcdir)/config/amanda/lfs.m4 \
+       $(top_srcdir)/config/amanda/libs.m4 \
+       $(top_srcdir)/config/amanda/net.m4 \
+       $(top_srcdir)/config/amanda/progs.m4 \
+       $(top_srcdir)/config/amanda/readdir.m4 \
+       $(top_srcdir)/config/amanda/readline.m4 \
+       $(top_srcdir)/config/amanda/rsh-security.m4 \
+       $(top_srcdir)/config/amanda/s3-device.m4 \
+       $(top_srcdir)/config/amanda/shmem.m4 \
+       $(top_srcdir)/config/amanda/socklen_t_equiv.m4 \
+       $(top_srcdir)/config/amanda/ssh-security.m4 \
+       $(top_srcdir)/config/amanda/summary.m4 \
+       $(top_srcdir)/config/amanda/swig.m4 \
+       $(top_srcdir)/config/amanda/syshacks.m4 \
+       $(top_srcdir)/config/amanda/tape.m4 \
+       $(top_srcdir)/config/amanda/types.m4 \
+       $(top_srcdir)/config/amanda/userid.m4 \
+       $(top_srcdir)/config/amanda/version.m4 \
+       $(top_srcdir)/config/gnulib/alloca.m4 \
+       $(top_srcdir)/config/gnulib/arpa_inet_h.m4 \
+       $(top_srcdir)/config/gnulib/base64.m4 \
+       $(top_srcdir)/config/gnulib/eoverflow.m4 \
+       $(top_srcdir)/config/gnulib/extensions.m4 \
+       $(top_srcdir)/config/gnulib/float_h.m4 \
+       $(top_srcdir)/config/gnulib/fsusage.m4 \
+       $(top_srcdir)/config/gnulib/getaddrinfo.m4 \
+       $(top_srcdir)/config/gnulib/gettimeofday.m4 \
+       $(top_srcdir)/config/gnulib/gnulib-comp.m4 \
+       $(top_srcdir)/config/gnulib/include_next.m4 \
+       $(top_srcdir)/config/gnulib/inet_ntop.m4 \
+       $(top_srcdir)/config/gnulib/intmax_t.m4 \
+       $(top_srcdir)/config/gnulib/lock.m4 \
+       $(top_srcdir)/config/gnulib/longlong.m4 \
+       $(top_srcdir)/config/gnulib/malloc.m4 \
+       $(top_srcdir)/config/gnulib/mkdtemp.m4 \
+       $(top_srcdir)/config/gnulib/netinet_in_h.m4 \
+       $(top_srcdir)/config/gnulib/onceonly_2_57.m4 \
+       $(top_srcdir)/config/gnulib/physmem.m4 \
+       $(top_srcdir)/config/gnulib/safe-read.m4 \
+       $(top_srcdir)/config/gnulib/safe-write.m4 \
+       $(top_srcdir)/config/gnulib/snprintf.m4 \
+       $(top_srcdir)/config/gnulib/socklen.m4 \
+       $(top_srcdir)/config/gnulib/sockpfaf.m4 \
+       $(top_srcdir)/config/gnulib/ssize_t.m4 \
+       $(top_srcdir)/config/gnulib/stdbool.m4 \
+       $(top_srcdir)/config/gnulib/stdint.m4 \
+       $(top_srcdir)/config/gnulib/stdio_h.m4 \
+       $(top_srcdir)/config/gnulib/stdlib_h.m4 \
+       $(top_srcdir)/config/gnulib/strdup.m4 \
+       $(top_srcdir)/config/gnulib/string_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_socket_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_stat_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_time_h.m4 \
+       $(top_srcdir)/config/gnulib/tempname.m4 \
+       $(top_srcdir)/config/gnulib/ulonglong.m4 \
+       $(top_srcdir)/config/gnulib/unistd_h.m4 \
+       $(top_srcdir)/config/gnulib/vasnprintf.m4 \
+       $(top_srcdir)/config/gnulib/visibility.m4 \
+       $(top_srcdir)/config/gnulib/wchar.m4 \
+       $(top_srcdir)/config/gettext-macros/gettext.m4 \
+       $(top_srcdir)/config/gettext-macros/iconv.m4 \
+       $(top_srcdir)/config/gettext-macros/inttypes_h.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-ld.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-link.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-prefix.m4 \
+       $(top_srcdir)/config/gettext-macros/longlong.m4 \
+       $(top_srcdir)/config/gettext-macros/nls.m4 \
+       $(top_srcdir)/config/gettext-macros/po.m4 \
+       $(top_srcdir)/config/gettext-macros/progtest.m4 \
+       $(top_srcdir)/config/gettext-macros/size_max.m4 \
+       $(top_srcdir)/config/gettext-macros/stdint_h.m4 \
+       $(top_srcdir)/config/gettext-macros/wchar_t.m4 \
+       $(top_srcdir)/config/gettext-macros/wint_t.m4 \
+       $(top_srcdir)/config/gettext-macros/xsize.m4 \
+       $(top_srcdir)/config/libtool.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+am__EXEEXT_1 = semaphore-test$(EXEEXT) vfs_test$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+device_test_SOURCES = device_test.c
+device_test_OBJECTS = device_test.$(OBJEXT)
+device_test_LDADD = $(LDADD)
+device_test_DEPENDENCIES = ../../common-src/libamanda.la \
+       ../libamdevice.la ../../common-src/libamanda.la \
+       ../../gnulib/libgnu.la
+queue_test_SOURCES = queue_test.c
+queue_test_OBJECTS = queue_test.$(OBJEXT)
+queue_test_LDADD = $(LDADD)
+queue_test_DEPENDENCIES = ../../common-src/libamanda.la \
+       ../libamdevice.la ../../common-src/libamanda.la \
+       ../../gnulib/libgnu.la
+am_semaphore_test_OBJECTS = semaphore-test.$(OBJEXT)
+semaphore_test_OBJECTS = $(am_semaphore_test_OBJECTS)
+semaphore_test_LDADD = $(LDADD)
+semaphore_test_DEPENDENCIES = ../../common-src/libamanda.la \
+       ../libamdevice.la ../../common-src/libamanda.la \
+       ../../gnulib/libgnu.la
+am_vfs_test_OBJECTS = vfs_test.$(OBJEXT)
+vfs_test_OBJECTS = $(am_vfs_test_OBJECTS)
+vfs_test_LDADD = $(LDADD)
+vfs_test_DEPENDENCIES = ../../common-src/libamanda.la \
+       ../libamdevice.la ../../common-src/libamanda.la \
+       ../../gnulib/libgnu.la
+DEFAULT_INCLUDES = -I. -I$(top_builddir)/config@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
+SOURCES = device_test.c queue_test.c $(semaphore_test_SOURCES) \
+       $(vfs_test_SOURCES)
+DIST_SOURCES = device_test.c queue_test.c $(semaphore_test_SOURCES) \
+       $(vfs_test_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMANDA_DBGDIR = @AMANDA_DBGDIR@
+AMANDA_DEBUG_DAYS = @AMANDA_DEBUG_DAYS@
+AMANDA_STATIC_LDFLAGS = @AMANDA_STATIC_LDFLAGS@
+AMANDA_TMPDIR = @AMANDA_TMPDIR@
+AMANDA_WARNING_CFLAGS = @AMANDA_WARNING_CFLAGS@
+AMLINT = @AMLINT@
+AMLINTFLAGS = @AMLINTFLAGS@
+AMPLOT_CAT_COMPRESS = @AMPLOT_CAT_COMPRESS@
+AMPLOT_CAT_GZIP = @AMPLOT_CAT_GZIP@
+AMPLOT_CAT_PACK = @AMPLOT_CAT_PACK@
+AMPLOT_COMPRESS = @AMPLOT_COMPRESS@
+AMTAR = @AMTAR@
+AR = @AR@
+ARPA_INET_H = @ARPA_INET_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASH = @BASH@
+BINARY_OWNER = @BINARY_OWNER@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+CAT = @CAT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CHIO = @CHIO@
+CHS = @CHS@
+CLIENT_LOGIN = @CLIENT_LOGIN@
+CLIENT_SCRIPTS_OPT = @CLIENT_SCRIPTS_OPT@
+COMPRESS = @COMPRESS@
+CONFIG_DIR = @CONFIG_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURL_CONFIG = @CURL_CONFIG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DD = @DD@
+DEFAULT_AMANDATES_FILE = @DEFAULT_AMANDATES_FILE@
+DEFAULT_CHANGER_DEVICE = @DEFAULT_CHANGER_DEVICE@
+DEFAULT_CONFIG = @DEFAULT_CONFIG@
+DEFAULT_SERVER = @DEFAULT_SERVER@
+DEFAULT_TAPE_DEVICE = @DEFAULT_TAPE_DEVICE@
+DEFAULT_TAPE_SERVER = @DEFAULT_TAPE_SERVER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOC_BUILD_DATE = @DOC_BUILD_DATE@
+DUMP = @DUMP@
+DUMPER_DIR = @DUMPER_DIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXAMPLE_TAPEDEV = @EXAMPLE_TAPEDEV@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FLOAT_H = @FLOAT_H@
+GETCONF = @GETCONF@
+GETTEXT = @GETTEXT@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@
+GNULIB_CHOWN = @GNULIB_CHOWN@
+GNULIB_DUP2 = @GNULIB_DUP2@
+GNULIB_FCHDIR = @GNULIB_FCHDIR@
+GNULIB_FFLUSH = @GNULIB_FFLUSH@
+GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@
+GNULIB_FSEEK = @GNULIB_FSEEK@
+GNULIB_FSEEKO = @GNULIB_FSEEKO@
+GNULIB_FTELL = @GNULIB_FTELL@
+GNULIB_FTELLO = @GNULIB_FTELLO@
+GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@
+GNULIB_GETCWD = @GNULIB_GETCWD@
+GNULIB_GETDELIM = @GNULIB_GETDELIM@
+GNULIB_GETLINE = @GNULIB_GETLINE@
+GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@
+GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@
+GNULIB_LCHOWN = @GNULIB_LCHOWN@
+GNULIB_LSEEK = @GNULIB_LSEEK@
+GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@
+GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@
+GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@
+GNULIB_MBSCHR = @GNULIB_MBSCHR@
+GNULIB_MBSCSPN = @GNULIB_MBSCSPN@
+GNULIB_MBSLEN = @GNULIB_MBSLEN@
+GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@
+GNULIB_MBSNLEN = @GNULIB_MBSNLEN@
+GNULIB_MBSPBRK = @GNULIB_MBSPBRK@
+GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@
+GNULIB_MBSRCHR = @GNULIB_MBSRCHR@
+GNULIB_MBSSEP = @GNULIB_MBSSEP@
+GNULIB_MBSSPN = @GNULIB_MBSSPN@
+GNULIB_MBSSTR = @GNULIB_MBSSTR@
+GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@
+GNULIB_MEMMEM = @GNULIB_MEMMEM@
+GNULIB_MEMPCPY = @GNULIB_MEMPCPY@
+GNULIB_MEMRCHR = @GNULIB_MEMRCHR@
+GNULIB_MKDTEMP = @GNULIB_MKDTEMP@
+GNULIB_MKSTEMP = @GNULIB_MKSTEMP@
+GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@
+GNULIB_READLINK = @GNULIB_READLINK@
+GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@
+GNULIB_SLEEP = @GNULIB_SLEEP@
+GNULIB_SNPRINTF = @GNULIB_SNPRINTF@
+GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@
+GNULIB_STPCPY = @GNULIB_STPCPY@
+GNULIB_STPNCPY = @GNULIB_STPNCPY@
+GNULIB_STRCASESTR = @GNULIB_STRCASESTR@
+GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@
+GNULIB_STRDUP = @GNULIB_STRDUP@
+GNULIB_STRNDUP = @GNULIB_STRNDUP@
+GNULIB_STRNLEN = @GNULIB_STRNLEN@
+GNULIB_STRPBRK = @GNULIB_STRPBRK@
+GNULIB_STRSEP = @GNULIB_STRSEP@
+GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
+GNULIB_VASPRINTF = @GNULIB_VASPRINTF@
+GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@
+GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@
+GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@
+GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@
+GNULIB_WCWIDTH = @GNULIB_WCWIDTH@
+GNUPLOT = @GNUPLOT@
+GNUTAR = @GNUTAR@
+GNUTAR_LISTED_INCREMENTAL_DIR = @GNUTAR_LISTED_INCREMENTAL_DIR@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GZIP = @GZIP@
+HAVE_CALLOC_POSIX = @HAVE_CALLOC_POSIX@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_MKDIR = @HAVE_DECL_MKDIR@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DUP2 = @HAVE_DUP2@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_IO_H = @HAVE_IO_H@
+HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MALLOC_POSIX = @HAVE_MALLOC_POSIX@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_REALLOC_POSIX = @HAVE_REALLOC_POSIX@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRNDUP = @HAVE_STRNDUP@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE__BOOL = @HAVE__BOOL@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPTH = @LIBPTH@
+LIBS = @LIBS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBPTH = @LTLIBPTH@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAILER = @MAILER@
+MAKEINFO = @MAKEINFO@
+MAXTAPEBLOCKSIZE = @MAXTAPEBLOCKSIZE@
+MCUTIL = @MCUTIL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+MT = @MT@
+MTX = @MTX@
+MT_FILE_FLAG = @MT_FILE_FLAG@
+NETINET_IN_H = @NETINET_IN_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCAT = @PCAT@
+PERL = @PERL@
+PERLEXTLIBS = @PERLEXTLIBS@
+PERL_INC = @PERL_INC@
+PKG_CONFIG = @PKG_CONFIG@
+POSUB = @POSUB@
+PRINT = @PRINT@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_FCHDIR = @REPLACE_FCHDIR@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+RESTORE = @RESTORE@
+SAMBA_CLIENT = @SAMBA_CLIENT@
+SERVICE_SUFFIX = @SERVICE_SUFFIX@
+SETUID_GROUP = @SETUID_GROUP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+SNAPSHOT_STAMP = @SNAPSHOT_STAMP@
+SORT = @SORT@
+SSH = @SSH@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SVN = @SVN@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYS_SOCKET_H = @SYS_SOCKET_H@
+SYS_STAT_H = @SYS_STAT_H@
+SYS_TIME_H = @SYS_TIME_H@
+USE_NLS = @USE_NLS@
+USE_VERSION_SUFFIXES = @USE_VERSION_SUFFIXES@
+VDUMP = @VDUMP@
+VERSION = @VERSION@
+VERSION_COMMENT = @VERSION_COMMENT@
+VERSION_MAJOR = @VERSION_MAJOR@
+VERSION_MINOR = @VERSION_MINOR@
+VERSION_PATCH = @VERSION_PATCH@
+VERSION_SUFFIX = @VERSION_SUFFIX@
+VRESTORE = @VRESTORE@
+VXDUMP = @VXDUMP@
+VXRESTORE = @VXRESTORE@
+WCHAR_H = @WCHAR_H@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+XFSDUMP = @XFSDUMP@
+XFSRESTORE = @XFSRESTORE@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XSLREL = @XSLREL@
+XSLTPROC = @XSLTPROC@
+XSLTPROC_FLAGS = @XSLTPROC_FLAGS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+amincludedir = @amincludedir@
+amlibdir = @amlibdir@
+amlibexecdir = @amlibexecdir@
+amperldir = @amperldir@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = -I$(top_builddir)/common-src \
+               -I$(top_srcdir)/common-src \
+               -I$(top_srcdir)/gnulib \
+               -I$(top_srcdir)/device-src
+
+
+###
+# Because libamanda includes routines (e.g. regex) provided by some system
+# libraries, and because of the way libtool sets up the command line, we
+# need to list libamanda twice here, first to override the system library
+# routines, and second to pick up any references in the other libraries.
+###
+LDADD = ../../common-src/libamanda.la \
+       ../libamdevice.la \
+       ../../common-src/libamanda.la \
+       ../../gnulib/libgnu.la
+
+semaphore_test_SOURCES = semaphore-test.c
+vfs_test_SOURCES = vfs_test.c
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  device-src/tests/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --gnu  device-src/tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstPROGRAMS:
+       @list='$(noinst_PROGRAMS)'; for p in $$list; do \
+         f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         echo " rm -f $$p $$f"; \
+         rm -f $$p $$f ; \
+       done
+device_test$(EXEEXT): $(device_test_OBJECTS) $(device_test_DEPENDENCIES) 
+       @rm -f device_test$(EXEEXT)
+       $(LINK) $(device_test_OBJECTS) $(device_test_LDADD) $(LIBS)
+queue_test$(EXEEXT): $(queue_test_OBJECTS) $(queue_test_DEPENDENCIES) 
+       @rm -f queue_test$(EXEEXT)
+       $(LINK) $(queue_test_OBJECTS) $(queue_test_LDADD) $(LIBS)
+semaphore-test$(EXEEXT): $(semaphore_test_OBJECTS) $(semaphore_test_DEPENDENCIES) 
+       @rm -f semaphore-test$(EXEEXT)
+       $(LINK) $(semaphore_test_OBJECTS) $(semaphore_test_LDADD) $(LIBS)
+vfs_test$(EXEEXT): $(vfs_test_OBJECTS) $(vfs_test_DEPENDENCIES) 
+       @rm -f vfs_test$(EXEEXT)
+       $(LINK) $(vfs_test_OBJECTS) $(vfs_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/queue_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/semaphore-test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vfs_test.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+           $$tags $$unique; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$tags $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && cd $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+       @failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[        ]'; \
+       srcdir=$(srcdir); export srcdir; \
+       list=' $(TESTS) '; \
+       if test -n "$$list"; then \
+         for tst in $$list; do \
+           if test -f ./$$tst; then dir=./; \
+           elif test -f $$tst; then dir=; \
+           else dir="$(srcdir)/"; fi; \
+           if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *$$ws$$tst$$ws*) \
+               xpass=`expr $$xpass + 1`; \
+               failed=`expr $$failed + 1`; \
+               echo "XPASS: $$tst"; \
+             ;; \
+             *) \
+               echo "PASS: $$tst"; \
+             ;; \
+             esac; \
+           elif test $$? -ne 77; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *$$ws$$tst$$ws*) \
+               xfail=`expr $$xfail + 1`; \
+               echo "XFAIL: $$tst"; \
+             ;; \
+             *) \
+               failed=`expr $$failed + 1`; \
+               echo "FAIL: $$tst"; \
+             ;; \
+             esac; \
+           else \
+             skip=`expr $$skip + 1`; \
+             echo "SKIP: $$tst"; \
+           fi; \
+         done; \
+         if test "$$failed" -eq 0; then \
+           if test "$$xfail" -eq 0; then \
+             banner="All $$all tests passed"; \
+           else \
+             banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+           fi; \
+         else \
+           if test "$$xpass" -eq 0; then \
+             banner="$$failed of $$all tests failed"; \
+           else \
+             banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+           fi; \
+         fi; \
+         dashes="$$banner"; \
+         skipped=""; \
+         if test "$$skip" -ne 0; then \
+           skipped="($$skip tests were not run)"; \
+           test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$skipped"; \
+         fi; \
+         report=""; \
+         if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+           report="Please report to $(PACKAGE_BUGREPORT)"; \
+           test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$report"; \
+         fi; \
+         dashes=`echo "$$dashes" | sed s/./=/g`; \
+         echo "$$dashes"; \
+         echo "$$banner"; \
+         test -z "$$skipped" || echo "$$skipped"; \
+         test -z "$$report" || echo "$$report"; \
+         echo "$$dashes"; \
+         test "$$failed" -eq 0; \
+       else :; fi
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+       clean-generic clean-libtool clean-noinstPROGRAMS ctags \
+       distclean distclean-compile distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/device-src/tests/device_test.c b/device-src/tests/device_test.c
new file mode 100644 (file)
index 0000000..9a46fee
--- /dev/null
@@ -0,0 +1,198 @@
+#include <device.h>
+#include <amanda.h>
+#include <timestamp.h>
+
+int blocksize;
+unsigned int seed = 0;
+
+static char * make_rand_buf(int size) {
+    char * rval;
+    unsigned int i;
+
+    rval = malloc(size);
+    i = size;
+    while (i > sizeof(int)) {
+        int rand;
+        rand = rand_r(&seed);
+        memcpy(rval + size - i, &rand, sizeof(int));
+        i -= sizeof(int);
+    }
+    
+    if (size > 0) {
+        int rand;
+        rand = rand_r(&seed);
+        memcpy(rval + size - i, &rand, i);
+    }
+
+    return rval;
+}
+
+static gboolean write_whole_file(Device * device) {
+    dumpfile_t dumpfile;
+    char * tmp;
+    int i;
+
+    fh_init(&dumpfile);
+    dumpfile.type = F_DUMPFILE;
+    tmp = get_timestamp_from_time(time(NULL));
+    strcpy(dumpfile.datestamp, tmp);
+    amfree(tmp);
+    strcpy(dumpfile.name, "localhost");
+    tmp = g_get_current_dir();
+    strcpy(dumpfile.disk, tmp);
+    amfree(tmp);
+    strcpy(dumpfile.program, "TESTER");
+    strcpy(dumpfile.recover_cmd, "recover_cmd");
+
+    blocksize = device_write_max_size(device);
+    
+    g_return_val_if_fail(device_start_file(device, &dumpfile), FALSE);
+    
+    for (i = 0; i < 1000; i ++) {
+        int size;
+        char * buf;
+        if (i == 999)
+            size = blocksize / 2;
+        else
+            size = blocksize;
+        buf = make_rand_buf(size);
+        g_return_val_if_fail(device_write_block(device, size, buf, i == 999),
+                             FALSE);
+        amfree(buf);
+    }
+    
+    g_return_val_if_fail(device->in_file == FALSE, FALSE);
+
+    return TRUE;
+}
+
+static gboolean read_whole_file(Device * device, int fileno) {
+    int size = 0;
+    dumpfile_t * file = device_seek_file(device, fileno + 1);
+    int i;
+    char *buf;
+
+    if (file == NULL)
+        g_assert_not_reached();
+    else
+        amfree(file);
+
+    g_return_val_if_fail(device_seek_block(device, 0), FALSE);
+    
+    g_return_val_if_fail(0 == device_read_block(device, NULL, &size),
+                         FALSE);
+    g_assert(size >= blocksize);
+        
+    for (i = 0; i < 1000; i ++) {
+        int size, size2;
+        char buf2[blocksize];
+        size2 = blocksize;
+        if (i == 999)
+            size = blocksize/2;
+        else
+            size = blocksize;
+        buf = make_rand_buf(size);
+        
+        g_return_val_if_fail(device_read_block(device, buf2, &size2),
+                             FALSE);
+        g_assert(size2 == size || size2 == blocksize);
+        g_assert(memcmp(buf, buf2, size) == 0);
+        amfree(buf);
+    }
+    
+    size = blocksize;
+    buf = malloc(blocksize);
+    g_assert(-1 == device_read_block(device, &buf, &size));
+    g_return_val_if_fail(device->is_eof, FALSE);
+    free(buf);
+
+    return TRUE;
+}
+
+static MediaAccessMode get_medium_type(Device * device) {
+    GValue value;
+    MediaAccessMode rval;
+    
+    bzero(&value, sizeof(value));
+
+    g_return_val_if_fail(device_property_get(device, PROPERTY_MEDIUM_TYPE,
+                                             &value), 0);
+
+    rval = g_value_get_enum(&value);
+    g_value_unset(&value);
+    return rval;
+}
+
+int main(int argc, char ** argv) {
+    Device * device;
+    int h;
+    MediaAccessMode medium_type;
+    
+    g_return_val_if_fail(argc == 2, 1);
+
+    device_api_init();
+
+    device = device_open(argv[1]);
+    g_return_val_if_fail(device != NULL, 2);
+
+    medium_type = get_medium_type(device);
+
+    if (device->volume_label) {
+        printf("Last header: %s %s\n", device->volume_label,
+               device->volume_time);
+    }
+
+    if (medium_type != MEDIA_ACCESS_MODE_READ_ONLY) {
+        g_return_val_if_fail(device_start(device, ACCESS_WRITE, 
+                                          "foo", NULL),
+                             2);
+        
+        for (h = 0; h < 10; h ++) {
+            gboolean appendable;
+            GValue value;
+            g_return_val_if_fail(write_whole_file(device), 3);
+            
+            bzero(&value, sizeof(value));
+            g_return_val_if_fail(device_property_get(device,
+                                                     PROPERTY_APPENDABLE,
+                                                     &value), 4);
+            appendable = g_value_get_boolean(&value);
+            g_value_unset(&value);
+            
+            if (appendable && h == 5) {
+                g_object_unref(device);
+                
+                device = device_open(argv[1]);
+                g_return_val_if_fail(device != NULL, 6);
+                
+                g_return_val_if_fail(device_start(device, ACCESS_APPEND, 
+                                                  "foo", NULL),
+                                     2);
+            }
+        }
+        
+        g_object_unref(device);    
+        
+        device = device_open(argv[1]);
+        g_return_val_if_fail(device != NULL, 6);
+    }
+
+    /* Fixme: check for readable access mode. */
+    if (medium_type != MEDIA_ACCESS_MODE_WRITE_ONLY) {
+        g_return_val_if_fail(device->volume_label, 7);
+        printf("This header: %s %s\n", device->volume_label,
+               device->volume_time);    
+        
+        g_return_val_if_fail(device_start(device, ACCESS_READ, 
+                                          "foo", NULL),
+                             2);
+        seed = 0;
+        for (h = 0; h < 10; h ++) {
+            g_return_val_if_fail(read_whole_file(device, h), 8);
+        }
+    }
+
+    g_object_unref(device);    
+
+    return 0;
+}
diff --git a/device-src/tests/queue_test.c b/device-src/tests/queue_test.c
new file mode 100644 (file)
index 0000000..f6cef95
--- /dev/null
@@ -0,0 +1,21 @@
+#include <queueing.h>
+#include <device.h>
+#include <amanda.h>
+
+int main(void) {
+    /* ignore SIGPIPE */
+    signal(SIGPIPE, SIG_IGN);
+
+    /* Comment out this line to disable threads. */
+    device_api_init();
+
+    /* The integer here is the block size to use. Set it to something
+     * bigger for better performance. */
+    return !do_consumer_producer_queue_full(fd_read_producer,
+                                            GINT_TO_POINTER(0),
+                                            fd_write_consumer,
+                                            GINT_TO_POINTER(1),
+                                            1,  /* Block size */
+                                            10, /* Buffer size. */
+                                            STREAMING_REQUIREMENT_DESIRED);
+}
diff --git a/device-src/tests/semaphore-test.c b/device-src/tests/semaphore-test.c
new file mode 100644 (file)
index 0000000..2e523c7
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include "semaphore.h"
+#include "amanda.h"
+#include "util.h"
+
+/*
+ * test that decrement waits properly
+ */
+
+struct test_decr_wait_data {
+    semaphore_t *sem;
+    gboolean increment_called;
+};
+
+static gpointer
+test_decr_wait_thread(gpointer datap)
+{
+    struct test_decr_wait_data *data = datap;
+
+    /* should block */
+    semaphore_decrement(data->sem, 20);
+
+    /* if increment hasn't been called yet, that's an error. */
+    if (!data->increment_called)
+       return GINT_TO_POINTER(0);
+
+    return GINT_TO_POINTER(1);
+}
+
+static gboolean
+test_decr_wait(void)
+{
+    GThread *th;
+    struct test_decr_wait_data data = { NULL, FALSE };
+    int rv;
+
+    data.sem = semaphore_new_with_value(10),
+
+    /* die after 10 seconds (default signal disposition is to fail) */
+    alarm(10);
+
+    th = g_thread_create(test_decr_wait_thread, (gpointer)&data, TRUE, NULL);
+
+    /* sleep to give semaphore_decrement() a chance to block (or not). */
+    g_usleep(G_USEC_PER_SEC / 4);
+
+    /* and then increment the semaphore enough that the decrement can succeed */
+    data.increment_called = TRUE;
+    semaphore_increment(data.sem, 10);
+
+    /* join the thread and see how it fared. */
+    rv = GPOINTER_TO_INT(g_thread_join(th));
+
+    semaphore_free(data.sem);
+
+    if (rv == 1) {
+       printf(" PASS: semaphore-test.test_decr_wait\n");
+       return TRUE;
+    } else {
+       printf(" FAIL: semaphore-test.test_decr_wait\n");
+       return FALSE;
+    }
+}
+
+
+/*
+ * test that semaphore_wait_empty waits properly
+ */
+
+static gpointer
+test_wait_empty_thread(gpointer datap)
+{
+    semaphore_t *sem = datap;
+
+    /* should block */
+    semaphore_decrement(sem, 20);
+
+    /* value should be 10 now (decremented from 30) */
+    if (sem->value != 10)
+       return GINT_TO_POINTER(1);
+
+    /* sleep for a bit */
+    g_usleep(G_USEC_PER_SEC / 4);
+
+    /* decrement those last 10, which should trigger the zero */
+    semaphore_decrement(sem, 10);
+
+    return GINT_TO_POINTER(0);
+}
+
+static gboolean
+test_wait_empty(void)
+{
+    GThread *th;
+    semaphore_t *sem = semaphore_new_with_value(10);
+    int rv;
+
+    /* die after 10 seconds (default signal disposition is to fail) */
+    alarm(10);
+
+    th = g_thread_create(test_wait_empty_thread, (gpointer)sem, TRUE, NULL);
+
+    /* sleep to give semaphore_decrement() a chance to block (or not). */
+    g_usleep(G_USEC_PER_SEC / 4);
+
+    /* add another 10, so decrement can hit zero next time it's called */
+    semaphore_increment(sem, 10);
+
+    /* and wait on the semaphore emptying */
+    semaphore_wait_empty(sem);
+
+    /* join the thread and see how it fared. */
+    rv = GPOINTER_TO_INT(g_thread_join(th));
+
+    semaphore_free(sem);
+
+    if (rv == 1) {
+       printf(" PASS: semaphore-test.test_wait_empty\n");
+       return TRUE;
+    } else {
+       printf(" FAIL: semaphore-test.test_wait_empty\n");
+       return FALSE;
+    }
+}
+
+/*
+ * test that semaphore_force_adjust correctly wakes both
+ * semaphore_decrement and semaphore_wait_empty.
+ */
+
+static gpointer
+test_force_adjust_thread(gpointer datap)
+{
+    semaphore_t *sem = datap;
+
+    /* this should block */
+    semaphore_decrement(sem, 20);
+
+    /* and this should block, too - it's fun */
+    semaphore_wait_empty(sem);
+
+    return NULL;
+}
+
+static gboolean
+test_force_adjust(void)
+{
+    GThread *th;
+    semaphore_t *sem = semaphore_new_with_value(10);
+
+    /* die after 10 seconds (default signal disposition is to fail) */
+    alarm(10);
+
+    th = g_thread_create(test_force_adjust_thread, (gpointer)sem, TRUE, NULL);
+
+    /* sleep to give semaphore_decrement() a chance to block (or not). */
+    g_usleep(G_USEC_PER_SEC / 4);
+
+    /* add another 20, so decrement can proceed, but leave the value at 10 */
+    semaphore_force_adjust(sem, 20);
+
+    /* sleep to give semaphore_wait_empty() a chance to block (or not). */
+    g_usleep(G_USEC_PER_SEC / 4);
+
+    /* and empty out the semaphore */
+    semaphore_force_adjust(sem, -10);
+
+    g_thread_join(th);
+
+    semaphore_free(sem);
+
+    /* it we didn't hang yet, it's all good */
+    printf(" PASS: semaphore-test.test_force_adjust\n");
+    return TRUE;
+}
+
+/*
+ * test that semaphore_force_set correctly wakes both
+ * semaphore_decrement and semaphore_wait_empty.
+ */
+
+static gpointer
+test_force_set_thread(gpointer datap)
+{
+    semaphore_t *sem = datap;
+
+    /* this should block */
+    semaphore_decrement(sem, 20);
+
+    /* and this should block, too - it's fun */
+    semaphore_wait_empty(sem);
+
+    return NULL;
+}
+
+static gboolean
+test_force_set(void)
+{
+    GThread *th;
+    semaphore_t *sem = semaphore_new_with_value(10);
+
+    /* die after 10 seconds (default signal disposition is to fail) */
+    alarm(10);
+
+    th = g_thread_create(test_force_set_thread, (gpointer)sem, TRUE, NULL);
+
+    /* sleep to give semaphore_decrement() a chance to block (or not). */
+    g_usleep(G_USEC_PER_SEC / 4);
+
+    /* set it to 30, so decrement can proceed, but leave the value at 10 */
+    semaphore_force_set(sem, 30);
+
+    /* sleep to give semaphore_wait_empty() a chance to block (or not). */
+    g_usleep(G_USEC_PER_SEC / 4);
+
+    /* and empty out the semaphore */
+    semaphore_force_set(sem, 0);
+
+    g_thread_join(th);
+
+    semaphore_free(sem);
+
+    /* it we didn't hang yet, it's all good */
+    printf(" PASS: semaphore-test.test_force_set\n");
+    return TRUE;
+}
+
+/*
+ * Main loop
+ */
+
+int
+main(void)
+{
+    gboolean pass = TRUE;
+
+#if defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
+    amanda_thread_init();
+
+    pass = test_decr_wait() && pass;
+    pass = test_wait_empty() && pass;
+    pass = test_force_adjust() && pass;
+    pass = test_force_set() && pass;
+
+    return pass?0:1;
+#else
+    printf("No thread support on this platform -- nothing to test\n");
+    return 0;
+#endif
+}
diff --git a/device-src/tests/vfs_test.c b/device-src/tests/vfs_test.c
new file mode 100644 (file)
index 0000000..b05ee78
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include <device.h>
+#include <amanda.h>
+#include "util.h"
+
+/* global so the 'atexit' handler can access it */
+
+static void
+cleanup_vtape_dir(char *device_path)
+{
+    char *quoted = g_shell_quote(device_path);
+    char *cmd = vstralloc("rm -rf ", quoted, NULL);
+
+    /* would you rather write 'rm -rf' here? */
+    if (system(cmd) == -1) {
+       exit(1);
+    }
+
+    amfree(cmd);
+    amfree(quoted);
+}
+
+static char *
+setup_vtape_dir(void)
+{
+    char *cwd = g_get_current_dir();
+    char *device_path = NULL;
+    char *data_dir = NULL;
+
+    device_path = vstralloc(cwd, "/vfs-test-XXXXXX", NULL);
+    amfree(cwd);
+
+    if (mkdtemp(device_path) == NULL) {
+       fprintf(stderr, "Could not create temporary directory in %s\n", cwd);
+       return NULL;
+    }
+
+    /* append "/data/" to that for the VFS device*/
+    data_dir = vstralloc(device_path, "/data/", NULL);
+    if (mkdir(data_dir, 0777) == -1) {
+       fprintf(stderr, "Could not create %s: %s\n", cwd, strerror(errno));
+       amfree(data_dir);
+       return NULL;
+    }
+
+    amfree(data_dir);
+    return device_path;
+}
+
+static Device *
+setup_device(char *device_path)
+{
+    Device *device;
+    char *device_name = NULL;
+
+    device_name = vstralloc("file:", device_path, NULL);
+    device = device_open(device_name);
+    if (!device) {
+       fprintf(stderr, "Could not open device %s\n", device_name);
+    }
+
+    amfree(device_name);
+    return device;
+}
+
+static gboolean
+check_free_space(Device *device)
+{
+    GValue value;
+    QualifiedSize qsize;
+
+    bzero(&value, sizeof(value));
+    if (!device_property_get(device, PROPERTY_FREE_SPACE, &value)) {
+       fprintf(stderr, "Could not get property_free_space\n");
+       return FALSE;
+    }
+
+    qsize = *(QualifiedSize*)g_value_get_boxed(&value);
+    g_value_unset(&value);
+
+    if (qsize.accuracy != SIZE_ACCURACY_REAL) {
+       fprintf(stderr, "property_free_space accuracy is not SIZE_ACCURACY_REAL\n");
+       return FALSE;
+    }
+
+    if (qsize.bytes == 0) {
+       fprintf(stderr, "property_free_space returned bytes=0\n");
+       return FALSE;
+    }
+
+    return TRUE;
+}
+
+int
+main(int argc G_GNUC_UNUSED, char **argv G_GNUC_UNUSED)
+{
+    Device *device = NULL;
+    gboolean ok = TRUE;
+    char *device_path = NULL;
+    pid_t pid;
+    amwait_t status;
+
+    amanda_thread_init();
+
+    device_path = setup_vtape_dir();
+
+    /* run the tests in a subprocess so we can clean up even if they fail */
+    switch (pid = fork()) {
+       case -1: /* error */
+           perror("fork");
+           g_assert_not_reached();
+
+       case 0: /* child */
+           device_api_init();
+
+           device = setup_device(device_path);
+           if (!device)
+               return 1;
+
+           ok = ok && check_free_space(device);
+
+           g_object_unref(device);
+
+           if (!ok) exit(1);
+           exit(0);
+           g_assert_not_reached();
+
+       default: /* parent */
+           if (waitpid(pid, &status, 0) == -1)
+               perror("waitpid");
+
+           /* cleanup */
+           cleanup_vtape_dir(device_path);
+           amfree(device_path);
+
+           /* figure our own return status */
+           if (WIFEXITED(status))
+               return WEXITSTATUS(status);
+           else if (WIFSIGNALED(status)) {
+               fprintf(stderr, "Test failed with signal %d\n", (int)WTERMSIG(status));
+               return 1;
+           } else {
+               /* weird.. */
+               return 1;
+           }
+           g_assert_not_reached();
+    }
+}
diff --git a/device-src/vfs-device.c b/device-src/vfs-device.c
new file mode 100644 (file)
index 0000000..a69b584
--- /dev/null
@@ -0,0 +1,1269 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include <string.h> /* memset() */
+
+#include "amanda.h"
+#include "vfs-device.h"
+#include "fsusage.h"
+#include "util.h"
+#include <regex.h>
+
+/* This regex will match all VfsDevice files in a directory. We use it
+   for cleanup and verification. Note that this regex does NOT match
+   the volume label. */
+#define VFS_DEVICE_FILE_REGEX "^[0-9]+[\\.-]"
+
+/* The name of the volume lockfile. Should be the same as that
+   generated by lockfile_name(0). */
+#define VOLUME_LOCKFILE_NAME "00000-lock"
+
+/* Possible (abstracted) results from a system I/O operation. */
+typedef enum {
+    RESULT_SUCCESS,
+    RESULT_ERROR,        /* Undefined error. */
+    RESULT_NO_DATA,      /* End of File, while reading */
+    RESULT_NO_SPACE,     /* Out of space. Sometimes we don't know if
+                            it was this or I/O error, but this is the
+                            preferred explanation. */
+    RESULT_MAX
+} IoResult;
+
+/* here are local prototypes */
+static void vfs_device_init (VfsDevice * o);
+static void vfs_device_class_init (VfsDeviceClass * c);
+static void vfs_device_finalize (GObject * o);
+
+static gboolean vfs_device_start(Device * pself, DeviceAccessMode mode,
+                                 char * label, char * timestamp);
+static gboolean vfs_device_open_device (Device * pself,
+                                        char * device_name);
+static gboolean vfs_device_start_file (Device * pself, const dumpfile_t * ji);
+static gboolean vfs_device_finish_file (Device * pself);
+static dumpfile_t * vfs_device_seek_file (Device * self, guint file);
+static gboolean vfs_device_seek_block (Device * self, guint64 block);
+static gboolean vfs_device_property_get (Device * pself, DevicePropertyId ID,
+                                         GValue * val);
+static gboolean vfs_device_property_set (Device * pself, DevicePropertyId ID,
+                                         GValue * val);
+static gboolean vfs_device_recycle_file (Device * pself, guint filenum);
+static Device * vfs_device_factory(char * device_type,
+                                   char * device_name);
+static ReadLabelStatusFlags vfs_device_read_label(Device * dself);
+static gboolean vfs_device_write_block(Device * self, guint size,
+                                       gpointer data, gboolean last_block);
+static int vfs_device_read_block(Device * self, gpointer data, int * size_req);
+static IoResult vfs_device_robust_write(VfsDevice * self,  char *buf,
+                                              int count);
+static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
+                                             int *count);
+
+/* Various helper functions. */
+static void release_file(VfsDevice * self);
+static gboolean check_is_dir(const char * name, gboolean printmsg);
+static char* file_number_to_file_name(VfsDevice * self, guint file);
+static gboolean file_number_to_file_name_functor(const char * filename,
+                                                 gpointer datap);
+//static char* lockfile_name(VfsDevice * self, guint file);
+static gboolean open_lock(VfsDevice * self, int file, gboolean exclusive);
+static void promote_volume_lock(VfsDevice * self);
+static void demote_volume_lock(VfsDevice * self);
+static gboolean delete_vfs_files(VfsDevice * self);
+static gboolean delete_vfs_files_functor(const char * filename,
+                                         gpointer self);
+static gboolean check_dir_empty_functor(const char * filename,
+                                        gpointer self);
+static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
+                                        char * timestamp);
+static gint get_last_file_number(VfsDevice * self);
+static gboolean get_last_file_number_functor(const char * filename,
+                                             gpointer datap);
+static char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji);
+static gboolean try_unlink(const char * file);
+
+/* pointer to the classes of our parents */
+static DeviceClass *parent_class = NULL;
+
+void vfs_device_register(void) {
+    static const char * device_prefix_list[] = { "file", NULL };
+    register_device(vfs_device_factory, device_prefix_list);
+}
+
+GType
+vfs_device_get_type (void)
+{
+    static GType type = 0;
+
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (VfsDeviceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) vfs_device_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (VfsDevice),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) vfs_device_init,
+            NULL
+        };
+
+        type = g_type_register_static (TYPE_DEVICE, "VfsDevice",
+                                       &info, (GTypeFlags)0);
+    }
+    
+    return type;
+}
+
+static void 
+vfs_device_init (VfsDevice * self) {
+    Device * o;
+    DeviceProperty prop;
+    GValue response;
+
+    self->dir_handle = NULL;
+    self->dir_name = self->file_name = NULL;
+    self->file_lock_name = self->volume_lock_name = NULL;
+    self->file_lock_fd = self->volume_lock_fd = self->open_file_fd = -1;
+    self->block_size = VFS_DEVICE_DEFAULT_BLOCK_SIZE;
+    self->volume_bytes = 0; 
+    self->volume_limit = 0;
+
+    /* Register Properties */
+    o = DEVICE(self);
+    bzero(&response, sizeof(response));
+    prop.base = &device_property_concurrency;
+    prop.access = PROPERTY_ACCESS_GET_MASK;
+    g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
+    g_value_set_enum(&response, CONCURRENCY_PARADIGM_RANDOM_ACCESS);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_streaming;
+    g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
+    g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_min_block_size;
+    g_value_init(&response, G_TYPE_UINT);
+    g_value_set_uint(&response, VFS_DEVICE_MIN_BLOCK_SIZE);
+    device_add_property(o, &prop, &response);
+
+    prop.base = &device_property_max_block_size;
+    g_value_set_uint(&response, VFS_DEVICE_MAX_BLOCK_SIZE);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    prop.base = &device_property_appendable;
+    g_value_init(&response, G_TYPE_BOOLEAN);
+    g_value_set_boolean(&response, TRUE);
+    device_add_property(o, &prop, &response);
+
+    prop.base = &device_property_partial_deletion;
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    /* This one is handled by Device's get_property handler. */
+    prop.base = &device_property_canonical_name;
+    device_add_property(o, &prop, NULL);
+
+    prop.base = &device_property_medium_access_type;
+    g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
+    g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
+    device_add_property(o, &prop, &response);
+    g_value_unset(&response);
+
+    /* These are dynamic, handled in vfs_device_property_xxx */
+    prop.base = &device_property_block_size;
+    prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START;
+    device_add_property(o, &prop, NULL);
+
+    prop.base = &device_property_max_volume_usage;
+    prop.access =
+        (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
+        (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE);
+    device_add_property(o, &prop, NULL);
+}
+
+static void 
+vfs_device_class_init (VfsDeviceClass * c G_GNUC_UNUSED)
+{
+    GObjectClass *g_object_class = (GObjectClass*) c;
+    DeviceClass *device_class = (DeviceClass *)c;
+
+    parent_class = g_type_class_ref(TYPE_DEVICE);
+
+    device_class->open_device = vfs_device_open_device;
+    device_class->start = vfs_device_start;
+    device_class->start_file = vfs_device_start_file;
+    device_class->read_label = vfs_device_read_label;
+    device_class->write_block = vfs_device_write_block;
+    device_class->read_block = vfs_device_read_block;
+    device_class->finish_file = vfs_device_finish_file;
+    device_class->seek_file = vfs_device_seek_file;
+    device_class->seek_block = vfs_device_seek_block;
+    device_class->property_get = vfs_device_property_get;
+    device_class->property_set = vfs_device_property_set;
+    device_class->recycle_file = vfs_device_recycle_file;
+    g_object_class->finalize = vfs_device_finalize;
+}
+
+/* Drops everything associated with the volume file: Its name and fd,
+   its lock, and its lock's name and fd. */
+static void release_file(VfsDevice * self) {
+    /* Doesn't hurt. */
+    robust_close(self->open_file_fd);
+    amfree(self->file_name);
+
+    if (self->file_lock_fd > 0) {
+        amfunlock(self->file_lock_fd, self->file_lock_name);
+        close(self->file_lock_fd);
+        amfree(self->file_lock_name);
+    }
+    self->file_lock_fd = self->open_file_fd = -1;
+}
+
+static void vfs_device_finalize(GObject * obj_self) {
+    VfsDevice *self = VFS_DEVICE (obj_self);
+    Device * d_self = (Device*)self;
+
+    if (d_self->access_mode != ACCESS_NULL) {
+        device_finish(d_self);
+    }
+
+    if(G_OBJECT_CLASS(parent_class)->finalize)
+        (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+
+    amfree(self->dir_name);
+
+    if(self->dir_handle) {
+        closedir (self->dir_handle);
+        self->dir_handle = NULL;
+    }
+
+    release_file(self);
+
+    if (self->volume_lock_fd >= 0) {
+        amfunlock(self->volume_lock_fd, self->volume_lock_name);
+        close(self->volume_lock_fd);
+    }
+
+    amfree(self->volume_lock_name);
+}
+
+static Device * vfs_device_factory(char * device_type,
+                                   char * device_name) {
+    Device * rval;
+    g_assert(0 == strcmp(device_type, "file"));
+    rval = DEVICE(g_object_new(TYPE_VFS_DEVICE, NULL));
+    if (!device_open_device(rval, device_name)) {
+        g_object_unref(rval);
+        return NULL;
+    } else {
+        return rval;
+    }
+}
+
+static gboolean check_is_dir(const char * name, gboolean printmsg) {
+    struct stat dir_status;
+    
+    if (stat(name, &dir_status) < 0) {
+#ifdef EINTR
+        if (errno == EINTR) {
+            return check_is_dir(name, printmsg);
+        }
+#endif /* EINTR */
+        if (printmsg) {
+            g_fprintf(stderr, "Error checking directory %s: %s\n",
+                    name, strerror(errno));
+        }
+        return FALSE;
+    } else if (!S_ISDIR(dir_status.st_mode)) {
+        if (printmsg) {
+            g_fprintf(stderr, "VFS Device path %s is not a directory.\n",
+                    name);
+        }
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+
+typedef struct {
+    VfsDevice * self;
+    int count;
+    char * result;
+} fnfn_data;
+
+/* A SearchDirectoryFunctor. */
+static gboolean file_number_to_file_name_functor(const char * filename,
+                                                 gpointer datap) {
+    char * result_tmp;
+    struct stat file_status;
+    fnfn_data *data = (fnfn_data*)datap;
+    
+    result_tmp = vstralloc(data->self->dir_name, "/", filename, NULL);    
+    
+    /* Just to be thorough, let's check that it's a real
+       file. */
+    if (0 != stat(result_tmp, &file_status)) {
+        g_fprintf(stderr, "Cannot stat file %s (%s), ignoring it.\n", 
+                result_tmp, strerror(errno));
+    } else if (!S_ISREG(file_status.st_mode)) {
+        g_fprintf(stderr, "%s is not a regular file, ignoring it.\n",
+                result_tmp);
+    } else {
+        data->count ++;
+        if (data->result == NULL) {
+            data->result = result_tmp;
+            result_tmp = NULL;
+        }
+    }
+    amfree(result_tmp);
+    return TRUE;
+}
+
+/* This function finds the filename for a given file number. We search
+ * for a filesystem file matching the regex /^0*$device_file\./; if
+ * there is more than one such file we make a warning and take an
+ * arbitrary one. */
+static char * file_number_to_file_name(VfsDevice * self, guint device_file) {
+    char * regex;
+    fnfn_data data;
+
+    g_return_val_if_fail(self != NULL, NULL);
+    data.self = self;
+    data.count = 0;
+    data.result = NULL;
+
+    regex = g_strdup_printf("^0*%u\\.", device_file);
+
+    search_directory(self->dir_handle, regex,
+                     file_number_to_file_name_functor, &data);
+
+    amfree(regex);
+
+    if (data.count == 0) {
+        g_assert(data.result == NULL);
+        return NULL;
+    } else if (data.count > 1) {
+        g_fprintf(stderr,
+                "Found multiple names for file number %d, choosing file %s.\n",
+                device_file, data.result);
+        return data.result;
+    } else {
+        g_assert(data.result != NULL);
+        return data.result;
+    }
+    g_assert_not_reached();
+}
+
+/* This function returns the dynamically-allocated lockfile name for a
+   given file number. */
+/*
+static char * lockfile_name(VfsDevice * self, guint number) {
+    return g_strdup_printf("%s/%05d-lock", self->dir_name, number);
+}
+*/
+
+/* Does what you expect. If the lock already exists, it is released
+ * and regained, in case the mode is changing.
+ * The file field has several options:
+ * - file > 0: Open a lock on a real volume file.
+ * - file = 0: Open the volume lock as a volume file (for setup).
+ * - file < 0: Open the volume lock as a volume lock (persistantly).
+ */
+static gboolean open_lock(G_GNUC_UNUSED VfsDevice * self,
+                         G_GNUC_UNUSED int file,
+                         G_GNUC_UNUSED gboolean exclusive) {
+
+    /* At the moment, file locking is horribly broken. */
+    return TRUE;
+
+/*
+    int fd;
+    char * name;
+    if (file < 0) {
+        if (self->volume_lock_name == NULL) {
+            self->volume_lock_name = lockfile_name(self, 0);
+        } else if (self->volume_lock_fd >= 0) {
+            amfunlock(self->volume_lock_fd, self->volume_lock_name);
+            close(self->volume_lock_fd);
+        }
+        name = self->volume_lock_name;
+    } else {
+        if (self->file_lock_fd >= 0 && self->file_lock_name != NULL) {
+            amfunlock(self->file_lock_fd, self->file_lock_name);
+        }
+        amfree(self->file_lock_name);
+        close(self->file_lock_fd);
+        name = self->file_lock_name = lockfile_name(self, file);
+    }
+        
+
+    fd = robust_open(name, O_CREAT | O_WRONLY, VFS_DEVICE_CREAT_MODE);
+
+    if (fd < 0) {
+        g_fprintf(stderr, "Can't open lock file %s: %s\n",
+                name, strerror(errno));
+        return FALSE;
+    }
+
+    if (exclusive) {
+        amflock(fd, name);
+    } else {
+        amroflock(fd, name);
+    }
+
+    if (file < 0) {
+        self->volume_lock_fd = fd;
+    } else {
+        self->file_lock_fd = fd;
+    }
+    return TRUE;
+*/
+}
+
+/* For now, does it the bad way. */
+static void promote_volume_lock(VfsDevice * self) {
+    amfunlock(self->volume_lock_fd, self->volume_lock_name);
+    amflock(self->volume_lock_fd, self->volume_lock_name);
+}
+
+static void demote_volume_lock(VfsDevice * self) {
+    amfunlock(self->volume_lock_fd, self->volume_lock_name);
+    amroflock(self->volume_lock_fd, self->volume_lock_name);
+}
+
+/* A SearchDirectoryFunctor */
+static gboolean update_volume_size_functor(const char * filename,
+                                           gpointer user_data) {
+    char * full_filename;
+    struct stat stat_buf;
+    VfsDevice * self = user_data;
+    g_return_val_if_fail(IS_VFS_DEVICE(self), FALSE);
+    
+    full_filename = vstralloc(self->dir_name, "/", filename, NULL);
+
+    if (stat(full_filename, &stat_buf) < 0) {
+        /* Log it and keep going. */
+        g_fprintf(stderr, "Couldn't stat file %s: %s\n",
+                full_filename, strerror(errno));
+        amfree(full_filename);
+        return TRUE;
+    }
+
+    amfree(full_filename);
+    self->volume_bytes += stat_buf.st_size;
+
+    return TRUE;
+}
+
+static void update_volume_size(VfsDevice * self) {
+    self->volume_bytes = 0;
+    search_directory(self->dir_handle, "^[0-9]+\\.",
+                     update_volume_size_functor, self);
+
+}
+
+static gboolean 
+vfs_device_open_device (Device * pself, char * device_name) {
+    VfsDevice * self;
+    dumpfile_t * rval;
+    
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (device_name != NULL, FALSE);
+
+    /* We don't have to free this ourselves; it will be freed by
+     * vfs_device_finalize whether we succeed here or not. */
+    self->dir_name = g_strconcat(device_name, "/data/", NULL);
+    if (!check_is_dir(self->dir_name, TRUE)) {
+        return FALSE;
+    }
+
+    /* Next open the directory itself. */
+    self->dir_handle = opendir(self->dir_name);
+    if (self->dir_handle == NULL) {
+        g_fprintf(stderr, "Couldn't open directory %s for reading: %s\n",
+                device_name, strerror(errno));
+        return FALSE;
+    }
+
+    if (!open_lock(self, -1, FALSE))
+        return FALSE;
+
+    /* Not an error if this fails. Note that we ignore the class hierarchy.
+     */
+    rval = vfs_device_seek_file(pself, 0);
+    amfree(rval);
+
+    if (parent_class->open_device) {
+        /* Will call vfs_device_read_label. */
+        return (parent_class->open_device)(pself, device_name);
+    } else {
+        return TRUE;
+    }
+}
+
+/* A SearchDirectoryFunctor */
+static gboolean delete_vfs_files_functor(const char * filename,
+                                         gpointer user_data) {
+    VfsDevice * self;
+    char * path_name;
+
+    self = VFS_DEVICE(user_data);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    /* Skip the volume lock. */
+    if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
+        return TRUE;
+
+    path_name = vstralloc(self->dir_name, "/", filename, NULL);
+    if (unlink(path_name) != 0) {
+        g_fprintf(stderr, "Error unlinking %s: %s\n", path_name,
+                strerror(errno));
+    }
+    amfree(path_name);
+    return TRUE;
+}
+
+/* delete_vfs_files deletes all VfsDevice files in the directory except the
+   volume lockfile. */
+static gboolean delete_vfs_files(VfsDevice * self) {
+    g_assert(self != NULL);
+    g_assert(self->dir_handle != NULL);
+
+    /* This function assumes that the volume is locked! */
+    search_directory(self->dir_handle, VFS_DEVICE_FILE_REGEX,
+                     delete_vfs_files_functor, self);
+    return TRUE;
+}
+
+/* This is a functor suitable for search_directory. It simply prints a
+   warning. It also dodges the volume lockfile. */
+static gboolean check_dir_empty_functor(const char * filename,
+                                        gpointer user_data) {
+    VfsDevice * self;
+    char * path_name;
+
+    self = VFS_DEVICE(user_data);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
+        return TRUE;
+
+    path_name = vstralloc(self->dir_name, "/", filename, NULL);
+
+    g_fprintf(stderr, "Found spurious storage file %s\n", path_name);
+
+    amfree(path_name);
+    return TRUE;
+}
+
+/* This function is used to write volume and dump headers. */
+static gboolean write_amanda_header(VfsDevice * self,
+                                    const dumpfile_t * header) {
+    char * label_buffer;
+    IoResult result;
+    
+    g_return_val_if_fail(header != NULL, FALSE);
+    g_return_val_if_fail(self != NULL, FALSE);
+    label_buffer = build_header(header, VFS_DEVICE_LABEL_SIZE);
+    if (strlen(label_buffer)+1 > VFS_DEVICE_LABEL_SIZE) {
+        amfree(label_buffer);
+        g_fprintf(stderr, "Amanda header header won't fit on VFS device!\n");
+        return FALSE;
+    }
+
+    result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE);
+    amfree(label_buffer);
+    return (result == RESULT_SUCCESS);
+}
+
+/* clear_and_label will erase the contents of the directory, and write
+ * this label in its place. This function assumes we already have a volume
+ * label write lock in place (e.g., promote_lock() has been called.) */
+static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
+                                        char * timestamp) {
+    dumpfile_t * label_header;
+
+    release_file(self);
+
+    /* Delete any extant data, except our volume lock. */
+    if (!delete_vfs_files(self)) {
+        return FALSE;
+    }
+
+    /* Print warnings about any remaining files. */
+    search_directory(self->dir_handle, VFS_DEVICE_FILE_REGEX,
+                     check_dir_empty_functor, self);
+
+    self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label);
+
+    self->open_file_fd = robust_open(self->file_name,
+                                     O_CREAT | O_EXCL | O_WRONLY,
+                                     VFS_DEVICE_CREAT_MODE);
+    if (self->open_file_fd < 0) {
+        g_fprintf(stderr, "Can't open file %s: %s\n", self->file_name,
+                strerror(errno));
+        return FALSE;
+    }
+
+    label_header = make_tapestart_header(DEVICE(self), label, timestamp);
+    if (write_amanda_header(self, label_header)) {
+        amfree(label_header);
+        self->volume_bytes = VFS_DEVICE_LABEL_SIZE;
+        return TRUE;
+    } else {
+        amfree(label_header);
+        return FALSE;
+    }
+}
+
+static ReadLabelStatusFlags vfs_device_read_label(Device * dself) {
+    dumpfile_t * amanda_header;
+    VfsDevice * self;
+
+    self = VFS_DEVICE(dself);
+    g_return_val_if_fail(self != NULL, ~READ_LABEL_STATUS_SUCCESS);
+
+    amanda_header = vfs_device_seek_file(dself, 0);
+    if (amanda_header == NULL) {
+        /* This means an error occured getting locks or opening the header
+         * file. */
+        return (READ_LABEL_STATUS_DEVICE_ERROR |
+                READ_LABEL_STATUS_VOLUME_ERROR |
+                READ_LABEL_STATUS_VOLUME_UNLABELED);
+    }
+
+    if (amanda_header->type != F_TAPESTART) {
+        /* This is an error, and should not happen. */
+        g_fprintf(stderr, "Got a bad volume label\n");
+        amfree(amanda_header);
+        return READ_LABEL_STATUS_VOLUME_ERROR;
+    }
+
+    dself->volume_label = g_strdup(amanda_header->name);
+    dself->volume_time = g_strdup(amanda_header->datestamp);
+    amfree(amanda_header);
+
+    update_volume_size(self);
+
+    if (parent_class->read_label) {
+        return (parent_class->read_label)(dself);
+    } else {
+        return READ_LABEL_STATUS_SUCCESS;
+    }
+}
+
+static gboolean vfs_device_write_block(Device * pself, guint size,
+                                       gpointer data, gboolean last_block) {
+    VfsDevice * self = VFS_DEVICE(pself);
+    IoResult result;
+    g_return_val_if_fail(self != NULL, FALSE);
+    g_return_val_if_fail(last_block || size >= (guint)self->block_size, FALSE);
+    g_return_val_if_fail(pself->in_file, FALSE);
+    g_assert(self->open_file_fd >= 0);
+
+    if (self->volume_limit > 0 &&
+        self->volume_bytes + size > self->volume_limit) {
+        /* Simulate EOF. */
+        pself->is_eof = TRUE;
+        return FALSE;
+    }
+
+    result = vfs_device_robust_write(self, data, size);
+    if (result == RESULT_SUCCESS) {
+        self->volume_bytes += size;
+        if (parent_class->write_block) {
+            (parent_class->write_block)(pself, size, data, last_block);
+        }
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+static int
+vfs_device_read_block(Device * pself, gpointer data, int * size_req) {
+    VfsDevice * self;
+    int size;
+    IoResult result;
+    
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, -1);
+
+    if (data == NULL || *size_req < self->block_size) {
+        /* Just a size query. */
+        *size_req = self->block_size;
+        return 0;
+    }
+
+    size = self->block_size;
+    result = vfs_device_robust_read(self, data, &size);
+    switch (result) {
+    case RESULT_SUCCESS:
+        *size_req = size;
+        return size;
+    case RESULT_NO_DATA:
+        pself->is_eof = TRUE;
+        pself->in_file = FALSE;
+        return -1;
+    default:
+        return -1;
+    }
+
+    g_assert_not_reached();
+}
+
+static gboolean        vfs_device_start(Device * pself,
+                                 DeviceAccessMode mode, char * label,
+                                 char * timestamp) {
+    VfsDevice * self;
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail(self != NULL, FALSE);
+    g_return_val_if_fail(parent_class->start != NULL, FALSE);
+    
+    if (mode == ACCESS_WRITE) {
+        promote_volume_lock(self);
+        if (!clear_and_prepare_label(self, label, timestamp)) {
+            demote_volume_lock(self);
+            return FALSE;
+        }
+        demote_volume_lock(self);
+    }
+
+    release_file(self);
+    if (parent_class->start) {
+        return parent_class->start(pself, mode, label, timestamp);
+    } else {
+        return TRUE;
+    }
+}
+
+typedef struct {
+    VfsDevice * self;
+    int rval;
+} glfn_data;
+
+/* A SearchDirectoryFunctor. */
+static gboolean get_last_file_number_functor(const char * filename,
+                                             gpointer datap) {
+    guint64 file;
+    glfn_data * data = (glfn_data*)datap;
+    g_return_val_if_fail(IS_VFS_DEVICE(data->self), FALSE);
+    file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
+    if (file > G_MAXINT) {
+        g_fprintf(stderr, "Super-large device file %s found, ignoring.\n",
+               filename);
+        return TRUE;
+    }
+    /* This condition is needlessly complex due to sign issues. */
+    if (data->rval < 0 || ((guint)data->rval) < file) {
+        data->rval = file;
+    }
+    return TRUE;
+}
+
+static gint get_last_file_number(VfsDevice * self) {
+    glfn_data data;
+    int count;
+    data.self = self;
+    data.rval = -1;
+    
+    count = search_directory(self->dir_handle, "^[0-9]+\\.",
+                             get_last_file_number_functor, &data);
+
+    if (count <= 0) {
+        /* Somebody deleted something important while we weren't looking. */
+        g_fprintf(stderr, "Error identifying VFS device contents!\n");
+        return -1;
+    } else {
+        g_assert(data.rval >= 0);
+    }
+    
+    return data.rval;
+}
+
+typedef struct {
+    VfsDevice * self;
+    guint request;
+    int best_found;
+} gnfn_data;
+
+/* A SearchDirectoryFunctor. */
+static gboolean get_next_file_number_functor(const char * filename,
+                                             gpointer datap) {
+    guint file;
+    gnfn_data * data = (gnfn_data*)datap;
+    g_return_val_if_fail(IS_VFS_DEVICE(data->self), FALSE);
+    file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
+    if (file > G_MAXINT) {
+        g_fprintf(stderr, "Super-large device file %s found, ignoring.\n",
+               filename);
+        return TRUE;
+    }
+    /* This condition is needlessly complex due to sign issues. */
+    if (file >= data->request &&
+        (data->best_found < 0 || file < (guint)data->best_found)) {
+        data->best_found = file;
+    }
+    return TRUE;
+}
+
+/* Returns the file number equal to or greater than the given requested
+ * file number. */
+static gint get_next_file_number(VfsDevice * self, guint request) {
+    gnfn_data data;
+    int count;
+    data.self = self;
+    data.request = request;
+    data.best_found = -1;
+    
+    count = search_directory(self->dir_handle, "^[0-9]+\\.",
+                             get_next_file_number_functor, &data);
+
+    if (count <= 0) {
+        /* Somebody deleted something important while we weren't looking. */
+        g_fprintf(stderr, "Error identifying VFS device contents!\n");
+        return -1;
+    }
+    
+    /* Could be -1. */
+    return data.best_found;
+}
+
+/* Finds the file number, acquires a lock, and returns the new file name. */
+static
+char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) {
+    char * rval;
+    char *base, *sanitary_base;
+    int fileno;
+
+    for (;;) {
+        fileno = 1 + get_last_file_number(self);
+        if (fileno <= 0)
+            return NULL;
+    
+        if (open_lock(self, fileno, TRUE)) {
+            break;
+        } else {
+            continue;
+        }
+    }
+
+    /* record that we're at this filenum now */
+    DEVICE(self)->file = fileno;
+
+    base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk,
+                           ji->dumplevel);
+    sanitary_base = sanitise_filename(base);
+    amfree(base);
+    rval = g_strdup_printf("%s/%s", self->dir_name, sanitary_base);
+    amfree(sanitary_base);
+    return rval;
+}
+
+static gboolean 
+vfs_device_start_file (Device * pself, const dumpfile_t * ji) {
+    VfsDevice * self;
+
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (ji != NULL, FALSE);
+
+    if (self->volume_limit > 0 &&
+        self->volume_bytes + VFS_DEVICE_LABEL_SIZE > self->volume_limit) {
+        /* No more room. */
+        return FALSE;
+    }
+
+    /* The basic idea here is thus:
+       1) Try to get a lock on the next filenumber.
+       2) If that fails, update our idea of "next filenumber" and try again.
+       3) Then open the file itself.
+       4) Write the label.
+       5) Chain up. */
+
+    self->file_name = make_new_file_name(self, ji);
+    if (self->file_name == NULL)
+        return FALSE;
+
+    self->open_file_fd = robust_open(self->file_name,
+                                     O_CREAT | O_EXCL | O_RDWR,
+                                     VFS_DEVICE_CREAT_MODE);
+    if (self->open_file_fd < 0) {
+        g_fprintf(stderr, "Can't create file %s: %s\n", self->file_name,
+                strerror(errno));
+        release_file(self);
+        return FALSE;
+    }
+
+    
+    if (!write_amanda_header(self, ji)) {
+        release_file(self);
+        return FALSE;
+    }
+
+    self->volume_bytes += VFS_DEVICE_LABEL_SIZE;
+    /* make_new_file_name set pself->file for us, but the parent class will increment it, so decrement it now */
+    pself->file--;
+
+    if (parent_class->start_file) {
+        parent_class->start_file(pself, ji);
+    }
+    return TRUE;
+}
+
+static gboolean 
+vfs_device_finish_file (Device * pself) {
+    VfsDevice * self;
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail(self != NULL, FALSE);
+
+    release_file(self);
+    
+    if (parent_class->finish_file) {
+        return parent_class->finish_file(pself);
+    } else {
+        return TRUE;
+    }
+    g_assert_not_reached();
+}
+
+/* This function is used for two purposes, rather than one. In
+ * addition to its documented behavior, we also use it to open the
+ * volume label for reading at startup. In that second case, we avoid
+ * FdDevice-related side effects. */
+static dumpfile_t * 
+vfs_device_seek_file (Device * pself, guint requested_file) {
+    VfsDevice * self;
+    int file;
+    dumpfile_t * rval;
+    char header_buffer[VFS_DEVICE_LABEL_SIZE];
+    int header_buffer_size = sizeof(header_buffer);
+    IoResult result;
+
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, NULL);
+
+    pself->in_file = FALSE;
+    
+    release_file(self);
+
+    if (requested_file > 0) {
+        file = get_next_file_number(self, requested_file);
+    } else {
+        file = requested_file;
+    }
+
+    if (file < 0) {
+        /* Did they request one past the end? */
+        char * tmp_file_name;
+        tmp_file_name = file_number_to_file_name(self, requested_file - 1);
+        if (tmp_file_name != NULL) {
+            free(tmp_file_name);
+            return make_tapeend_header();
+        } else {
+            return NULL;
+        }
+    }
+
+    if (!open_lock(self, file, FALSE)) {
+        return NULL;
+    }
+
+    self->file_name = file_number_to_file_name(self, file);
+    if (self->file_name == NULL) {
+        release_file(self);
+        return NULL;
+    }
+
+    self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0);
+    if (self->open_file_fd <= 0) {
+        g_fprintf(stderr, "Couldn't open file %s: %s\n", self->file_name,
+                strerror(errno));
+        amfree(self->file_name);
+        release_file(self);
+        return NULL;
+    }
+
+    result = vfs_device_robust_read(self, header_buffer,
+                                    &header_buffer_size);
+    if (result != RESULT_SUCCESS) {
+        g_fprintf(stderr, "Problem reading Amanda header.\n");
+        release_file(self);
+        return NULL;
+    }
+
+    rval = malloc(sizeof(*rval));
+    parse_file_header(header_buffer, rval, header_buffer_size);
+    if (file > 0) {
+        switch (rval->type) {
+        case F_DUMPFILE:
+        case F_CONT_DUMPFILE:
+        case F_SPLIT_DUMPFILE:
+            /* Chain up. */
+            if (parent_class->seek_file) {
+                parent_class->seek_file(pself, file);
+            }
+            return rval;
+        default:
+            amfree(rval);
+            release_file(self);
+            return NULL;
+        }
+    } else if (file == 0) {
+        return rval;
+    } else {
+        amfree(rval);
+        return NULL;
+    }
+}
+
+static gboolean 
+vfs_device_seek_block (Device * pself, guint64 block) {
+    VfsDevice * self;
+    off_t result;
+
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (self->open_file_fd >= 0, FALSE);
+    g_assert(sizeof(off_t) >= sizeof(guint64));
+
+    /* Pretty simple. We figure out the blocksize and use that. */
+    result = lseek(self->open_file_fd,
+                   (block) * self->block_size + VFS_DEVICE_LABEL_SIZE,
+                   SEEK_SET);
+    return (result != (off_t)(-1));
+}
+
+static gboolean
+vfs_device_property_get (Device * pself, DevicePropertyId ID, GValue * val) {
+    VfsDevice * self;
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail(self != NULL, FALSE);
+    if (ID == PROPERTY_BLOCK_SIZE) {
+        g_value_unset_init(val, G_TYPE_INT);
+        g_value_set_int(val, self->block_size);
+        return TRUE;
+    } else if (ID == PROPERTY_MAX_VOLUME_USAGE) {
+        g_value_unset_init(val, G_TYPE_UINT64);
+        g_value_set_uint64(val, self->volume_limit);
+        return TRUE;
+    } else if (ID == PROPERTY_FREE_SPACE) {
+       QualifiedSize qsize;
+       struct fs_usage fsusage;
+       guint64 bytes_avail;
+
+       if (get_fs_usage(self->dir_name, NULL, &fsusage) == 0) {
+           if (fsusage.fsu_bavail_top_bit_set)
+               bytes_avail = 0;
+           else
+               bytes_avail = fsusage.fsu_bavail * fsusage.fsu_blocksize;
+           if (self->volume_limit && (guint64)self->volume_limit < bytes_avail / 1024)
+               bytes_avail = (guint64)self->volume_limit * 1024;
+
+           qsize.accuracy = SIZE_ACCURACY_REAL;
+           qsize.bytes = bytes_avail;
+       } else {
+           g_warning(_("get_fs_usage('%s') failed: %s"), self->dir_name, strerror(errno));
+           qsize.accuracy = SIZE_ACCURACY_UNKNOWN;
+           qsize.bytes = 0;
+       }
+       g_value_unset_init(val, QUALIFIED_SIZE_TYPE);
+       g_value_set_boxed(val, &qsize);
+       return TRUE;
+    } else {
+        if (parent_class->property_get) {
+            return parent_class->property_get(pself, ID, val);
+        } else {
+            return FALSE;
+        }
+    }
+    g_assert_not_reached();
+}
+
+static gboolean 
+vfs_device_property_set (Device * pself, DevicePropertyId ID, GValue * val) {
+    VfsDevice * self;
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail(self != NULL, FALSE);
+    if (ID == PROPERTY_BLOCK_SIZE) {
+        int block_size = g_value_get_int(val);
+        g_return_val_if_fail(block_size > 0, FALSE);
+        self->block_size = block_size;
+        return TRUE;
+    } else if (ID == PROPERTY_MAX_VOLUME_USAGE) {
+        self->volume_limit = g_value_get_uint64(val);
+        return TRUE;
+    } else {
+        if (parent_class->property_set) {
+            return parent_class->property_set(pself, ID, val);
+        } else {
+            return FALSE;
+        }
+    }
+    g_assert_not_reached();
+}
+
+static gboolean try_unlink(const char * file) {
+    if (unlink(file) < 0) {
+        g_fprintf(stderr, "Can't unlink file %s: %s\n", file, strerror(errno));
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+
+static gboolean 
+vfs_device_recycle_file (Device * pself, guint filenum) {
+    VfsDevice * self;
+    struct stat file_status;
+    off_t file_size;
+
+    self = VFS_DEVICE(pself);
+    g_return_val_if_fail(self != NULL, FALSE);
+    g_return_val_if_fail(!(pself->in_file), FALSE);
+
+    /* Game Plan:
+     * 1) Get a write lock on the file in question.
+     * 2) Unlink the file in question.
+     * 3) Unlink the lock.
+     * 4) Release the lock.
+     * FIXME: Is it OK to unlink the lockfile?
+     */
+
+    self->file_name = file_number_to_file_name(self, filenum);
+
+    if (self->file_name == NULL)
+        return FALSE;
+
+    if (!open_lock(self, filenum, TRUE))
+        return FALSE;
+
+    if (0 != stat(self->file_name, &file_status)) {
+        fprintf(stderr, "Cannot stat file %s (%s), so not removing.\n",
+                self->file_name, strerror(errno));
+        return FALSE;
+    }
+    file_size = file_status.st_size;
+    
+    if (!try_unlink(self->file_name) ||
+        !try_unlink(self->file_lock_name)) {
+        release_file(self);
+        return FALSE;
+    }
+
+    self->volume_bytes -= file_size;
+    release_file(self);
+    return TRUE;
+}
+
+static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
+                                             int *count) {
+    int fd = self->open_file_fd;
+    int want = *count, got = 0;
+
+    while (got < want) {
+        int result;
+        result = read(fd, buf + got, want - got);
+        if (result > 0) {
+            got += result;
+        } else if (result == 0) {
+            /* end of file */
+            if (got == 0) {
+                return RESULT_NO_DATA;
+            } else {
+                *count = got;
+                return RESULT_SUCCESS;
+            }
+        } else if (0
+#ifdef EAGAIN
+                || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                || errno == EINTR
+#endif
+                   ) {
+            /* Try again. */
+            continue;
+        } else {
+            /* Error occured. */
+            g_fprintf(stderr, "Error reading fd %d: %s\n", fd, strerror(errno));
+            *count = got;
+            return -1;
+        }
+    }
+
+    *count = got;
+    return RESULT_SUCCESS;
+}
+
+static IoResult
+vfs_device_robust_write(VfsDevice * self,  char *buf, int count) {
+    int fd = self->open_file_fd;
+    int rval = 0;
+
+    while (rval < count) {
+        int result;
+        result = write(fd, buf + rval, count - rval);
+        if (result > 0) {
+            rval += result;
+            continue;
+        } else if (0
+#ifdef EAGAIN
+                || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                || errno == EINTR
+#endif
+                   ) {
+            /* Try again. */
+            continue;
+        } else if (0
+#ifdef EFBIG
+                   || errno == EFBIG
+#endif
+#ifdef ENOSPC
+                   || errno == ENOSPC
+#endif
+                   ) {
+            /* We are definitely out of space. */
+            return RESULT_NO_SPACE;
+        } else {
+            /* Error occured. Note that here we handle EIO as an error. */
+            g_fprintf(stderr, "Error writing device fd %d: %s\n",
+                    fd, strerror(errno));
+            
+            return RESULT_ERROR;
+        }
+    }
+    return RESULT_SUCCESS;
+}
diff --git a/device-src/vfs-device.h b/device-src/vfs-device.h
new file mode 100644 (file)
index 0000000..6b5796f
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as 
+ * published by the Free Software Foundation.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ * 
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* The VFS device is the driver formerly known as the vtape driver or
+ * the file driver. It uses a directory on the UNIX filesystem as a
+ * data store. */
+
+#include <glib.h>
+#include <glib-object.h>
+#include "device.h"
+#include <dirent.h>
+
+#ifndef VFS_DEVICE_H
+#define VFS_DEVICE_H
+
+#define VFS_DEVICE_MIN_BLOCK_SIZE (1)
+#define VFS_DEVICE_MAX_BLOCK_SIZE (INT_MAX)
+#define VFS_DEVICE_DEFAULT_BLOCK_SIZE (MAX_TAPE_BLOCK_BYTES)
+#define VFS_DEVICE_LABEL_SIZE (32768)
+
+/* This looks dangerous, but is actually modified by the umask. */
+#define VFS_DEVICE_CREAT_MODE 0666
+
+/*
+ * Type checking and casting macros
+ */
+#define TYPE_VFS_DEVICE        (vfs_device_get_type())
+#define VFS_DEVICE(obj)        G_TYPE_CHECK_INSTANCE_CAST((obj), vfs_device_get_type(), VfsDevice)
+#define VFS_DEVICE_CONST(obj)  G_TYPE_CHECK_INSTANCE_CAST((obj), vfs_device_get_type(), VfsDevice const)
+#define VFS_DEVICE_CLASS(klass)        G_TYPE_CHECK_CLASS_CAST((klass), vfs_device_get_type(), VfsDeviceClass)
+#define IS_VFS_DEVICE(obj)     G_TYPE_CHECK_INSTANCE_TYPE((obj), vfs_device_get_type ())
+
+#define VFS_DEVICE_GET_CLASS(obj)      G_TYPE_INSTANCE_GET_CLASS((obj), vfs_device_get_type(), VfsDeviceClass)
+
+/*
+ * Main object structure
+ */
+typedef struct {
+    Device __parent__;
+
+    /*< private >*/
+    DIR * dir_handle;
+    char * dir_name;
+    char * file_name;
+    int file_lock_fd;
+    char * file_lock_name;
+    int volume_lock_fd;
+    char * volume_lock_name;
+    int open_file_fd;
+    
+    /* Properties */
+    int block_size;
+    guint64 volume_bytes;
+    guint64 volume_limit;
+} VfsDevice;
+
+/*
+ * Class definition
+ */
+typedef struct {
+    DeviceClass __parent__;
+} VfsDeviceClass;
+
+
+/*
+ * Public methods
+ */
+GType  vfs_device_get_type     (void);
+void    vfs_device_register     (void);
+
+#endif
+
diff --git a/dumper-src/amgtar.pl b/dumper-src/amgtar.pl
new file mode 100644 (file)
index 0000000..8fe9024
--- /dev/null
@@ -0,0 +1,326 @@
+#!@PERL@ -T
+#
+
+# Run perl.
+eval '(exit $?0)' && eval 'exec @PERL@ -S $0 ${1+"$@"}'
+       & eval 'exec @PERL@ -S $0 $argv:q'
+               if 0;
+
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
+$ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin";
+
+$debug=1;
+push(@INC, ".", "@DUMPER_DIR@");
+
+use File::Copy;
+use IPC::Open3;
+use Sys::Hostname;
+
+
+open(DEBUG,">>@AMANDA_DBGDIR@/amgtar.$$.debug") if ($debug==1);
+
+$prefix='@prefix@';
+$prefix = $prefix;
+$exec_prefix="@exec_prefix@";
+$exec_prefix=$exec_prefix;
+$amlibexecdir="@amlibexecdir@";
+$amlibexecdir=$amlibexecdir;
+
+$USE_VERSION_SUFFIXES='@USE_VERSION_SUFFIXES@';
+$suf = '';
+if ( $USE_VERSION_SUFFIXES =~ /^yes$/i ) {
+   $suf='-@VERSION@';
+}
+
+$myhost = hostname;
+$myhost =~ s/\..*$//;
+$runtar="${amlibexecdir}/runtar${suf}";
+$gnulist = '@GNUTAR_LISTED_INCREMENTAL_DIR@';
+$gnutar = '@GNUTAR@';
+
+
+
+$max_level    = 9;
+$index_line   = 1;
+$index_xml    = 0;
+$message_line = 1;
+$message_xml  = 0;
+$record       = 1;
+$include_file = 1;
+$include_list = 1;
+$exclude_file = 1;
+$exclude_list = 1;
+$collection   = 0;
+
+#$user_support  = "";
+#$group_support = "";
+
+#$user_selfcheck  = "";
+#$group_selfcheck = "";
+
+#$user_estimate  = "";
+#$group_estimate = "";
+
+#$user_estimate_parse  = "";
+#$group_estimate_parse = "";
+
+$user_backup  = "root";
+#$group_backup = "";
+
+#$user_backup_parse  = "";
+#$group_backup_parse = "";
+
+#$user_index_from_output  = "";
+#$group_index_from_output = "";
+
+#$user_index_from_image  = "";
+#$group_index_from_image = "";
+
+#$user_restore  = "";
+#$group_restore = "";
+
+#$user_print_command  = "";
+#$group_print_command = "";
+
+$user_default  = "amanda";
+$group_default = "amanda";
+
+
+sub command_support {
+   my($config, $host, $disk, $device, $level) = @_;
+   print "CONFIG YES\n";
+   print DEBUG "STDOUT: CONFIG YES\n" if ($debug == 1);
+   print "HOST YES\n";
+   print DEBUG "STDOUT: HOST YES\n" if ($debug == 1);
+   print "DISK YES\n";
+   print DEBUG "STDOUT: DISK YES\n" if ($debug == 1);
+   print "MAX-LEVEL 9\n";
+   print DEBUG "STDOUT: MAX-LEVEL 9\n" if ($debug == 1);
+   print "INDEX-LINE YES\n";
+   print DEBUG "STDOUT: INDEX-LINE YES\n" if ($debug == 1);
+   print "INDEX-XML NO\n";
+   print DEBUG "STDOUT: INDEX-XML NO\n" if ($debug == 1);
+   print "MESSAGE-LINE YES\n";
+   print DEBUG "STDOUT: MESSAGE-LINE YES\n" if ($debug == 1);
+   print "MESSAGE-XML NO\n";
+   print DEBUG "STDOUT: MESSAGE-XML NO\n" if ($debug == 1);
+   print "RECORD YES\n";
+   print DEBUG "STDOUT: RECORD YES\n" if ($debug == 1);
+   print "INCLUDE-FILE YES\n";
+   print "INCLUDE-LIST YES\n";
+   print "EXCLUDE-FILE YES\n";
+   print "EXCLUDE-LIST YES\n";
+   print "COLLECTION NO\n";
+}
+
+sub command_selfcheck {
+   my($config, $host, $disk, $device, $level) = @_;
+   print DEBUG "STDOUT: OK $disk\n" if ($debug == 1);
+   print DEBUG "STDOUT: OK $device\n" if ($debug == 1);
+   print "OK $disk\n";
+   print "OK $device\n";
+   #check binary
+   #check statefile
+   #check amdevice
+   #check property include/exclude
+}
+
+sub command_estimate {
+   my($config, $host, $disk, $device, $level) = @_;
+   my($listdir) = "$host$disk";
+   $listdir     =~ s/\//_/g;
+   if($level == 0) {
+      open(GNULIST, ">${gnulist}/${listdir}_${level}.new") || die();
+      close(GNULIST) || die();
+   }
+   else {
+      my($prev_level) = $level - 1;
+      if (-f "${gnulist}/${listdir}_${prev_level}") {
+        copy("${gnulist}/${listdir}_${prev_level}", "${gnulist}/${listdir}_${level}.new");
+      } else {
+        open(GNULIST, ">${gnulist}/${listdir}_${level}.new") || die();
+        close(GNULIST) || die();
+       #print "ERROR file ${gnulist}/${listdir}_${level}.new doesn't exist\n";
+      }
+   }
+   command_estimate_opt_direct($config, $host, $disk, $device, $level, $listdir);
+}
+
+
+sub command_estimate_opt_direct {
+   my($config, $host, $disk, $device, $level, $listdir) = @_;
+   my($size) = -1;
+   my(@cmd) = ($runtar, $config, $gnutar, "--create", "--directory", $device, "--listed-incremental", "${gnulist}/${listdir}_${level}.new", "--sparse", "--one-file-system", "--ignore-failed-read", "--totals", "--file", "/dev/null", ".");
+   #my(@cmd) = ($gnutar, "--create", "--directory", $device, "--listed-incremental", "${gnulist}/${listdir}_${level}.new", "--sparse", "--one-file-system", "--ignore-failed-read", "--totals", "--file", "/dev/null", ".");
+   print DEBUG "cmd:" , join(" ", @cmd), "\n" if ($debug == 1);
+   open3(\*WTRFH, '>&STDOUT', \*ESTIMATE, @cmd);
+
+   $size = parse_estimate(ESTIMATE);
+   close(ESTIMATE);
+   output_size($size);
+   unlink "${gnulist}/${listdir}_${level}.new";
+   exit 0;
+}
+
+sub parse_estimate {
+   my($fh) = @_;
+   my($size) = -1;
+   while(<$fh>) {
+print DEBUG "READ 2: $_" if ($debug == 1);
+      if ($_ =~ /^Total bytes written: (\d*)/) {
+         $size = $1;
+         last;
+      }
+   }
+   return $size;
+}
+
+sub output_size {
+   my($size) = @_;
+   if($size == -1) {
+      print DEBUG "STDOUT A: -1 -1\n" if ($debug == 1);
+      print "-1 -1\n";
+      exit 2;
+   }
+   else {
+      my($ksize) = int $size / (1024);
+      $ksize=32 if ($ksize<32);
+      print DEBUG "STDOUT B: $ksize 1\n" if ($debug == 1);
+      print "$ksize 1\n";
+   }
+}
+
+sub command_backup {
+   my($config, $host, $disk, $device, $level) = @_;
+   my($listdir) = "$host$disk";
+   my($verbose) = "";
+   $listdir     =~ s/\//_/g;
+
+print DEBUG "config =" . $config . "\n" if ($debug == 1);
+print DEBUG "host   =" . $host   . "\n" if ($debug == 1);
+print DEBUG "disk   =" . $disk   . "\n" if ($debug == 1);
+print DEBUG "device =" . $device . "\n" if ($debug == 1);
+print DEBUG "level  =" . $level  . "\n" if ($debug == 1);
+
+   if($level == 0) {
+      open(GNULIST, ">${gnulist}/${listdir}_${level}.new") || die();
+      close(GNULIST) || die();
+   }
+   else {
+      my($prev_level) = $level - 1;
+      copy("${gnulist}/${listdir}_${prev_level}", 
+           "${gnulist}/${listdir}_${level}.new");
+   }
+
+   if(defined($opt_index)) {
+      $verbose = "--verbose";
+   }
+   my(@cmd) = ($runtar, $config, $gnutar, "--create", $verbose, "--directory", $device, "--listed-incremental", "${gnulist}/${listdir}_${level}.new", "--sparse", "--one-file-system", "--ignore-failed-read", "--totals", "--file", "-", ".");
+   #my(@cmd) = ($gnutar, "--create", $verbose, "--directory", $device, "--listed-incremental", "${gnulist}/${listdir}_${level}.new", "--sparse", "--one-file-system", "--ignore-failed-read", "--totals", "--file", "-", ".");
+
+   print DEBUG "cmd:" , join(" ", @cmd), "\n" if ($debug == 1);
+
+   open3(\*WTRFH, '>&STDOUT', \*INDEX, @cmd) || die();
+
+   if(defined($opt_index)) {
+      open(INDEXOUT, '>&=3') || die();
+      parse_backup(INDEX, STDERR, INDEXOUT);
+      close(INDEXOUT);
+   }
+   else {
+      parse_backup(INDEX, STDERR, undef);
+   }
+   close(INDEX);
+   close(WTRFH);
+
+   if(defined($opt_record)) {
+      rename "${gnulist}/${listdir}_${level}.new", 
+             "${gnulist}/${listdir}_${level}";
+   }
+   else {
+      unlink "${gnulist}/${listdir}_${level}.new";
+   }
+   exit 0;
+}
+
+sub parse_backup {
+   my($fhin, $fhout, $indexout) = @_;
+   my($size) = -1;
+   while(<$fhin>) {
+print DEBUG "READ 3: $_" if ($debug == 1);
+      if ( /^\.\//) {
+         if(defined($indexout)) {
+           if(defined($opt_index)) {
+               s/^\.//;
+print DEBUG "INDEXOUT: $_" if ($debug == 1);
+               print $indexout $_;
+           }
+         }
+      }
+      else {
+            if (/^Total bytes written: (\d*)/) {
+               $size = $1;
+              $ksize = int ($size / 1024);
+            }
+            elsif(defined($fhout)) {
+               next if /: Directory is new$/;
+print DEBUG "FHOUT 2: $_" if ($debug == 1);
+               print $fhout $_;
+            }
+      }
+   }
+   if(defined($fhout)) {
+      if ($size == -1) {
+print DEBUG "FHOUT 4: $command -1 -1\n" if ($debug == 1);
+         print $fhout "$command -1 -1\n";
+      }
+      else {
+         my($ksize) = int ($size/1024);
+print DEBUG "FHOUT 5: sendbackup: size $ksize\n" if ($debug == 1);
+         print $fhout "sendbackup: size $ksize\n";
+print DEBUG "FHOUT 5: sendbackup: end\n" if ($debug == 1);
+              print $fhout "sendbackup: end\n";
+      }
+   }
+}
+
+sub command_index_from_output {
+   index_from_output(STDIN, STDOUT);
+   exit 0;
+}
+
+sub index_from_output {
+   my($fhin, $fhout) = @_;
+   my($size) = -1;
+   while(<$fhin>) {
+print DEBUG "READ 4: $_" if ($debug == 1);
+      next if /^Total bytes written:/;
+      next if !/^\.\//;
+      s/^\.//;
+print DEBUG "FHOUT 6: $_" if ($debug == 1);
+      print $fhout $_;
+   }
+}
+
+sub command_index_from_image {
+   my($config, $host, $disk, $device, $level) = @_;
+   open(INDEX, "$gnutar --list --file - |") || die();
+   index_from_output(INDEX, STDOUT);
+}
+
+sub command_restore {
+   my($config, $host, $disk, $device, $level) = @_;
+
+#   $ARGV[0] = undef;   
+   my(@cmd) = ($gnutar, "--numeric-owner", "-xpGvf", "-");
+   for($i=1;defined $ARGV[$i]; $i++) {
+      push @cmd, $ARGV[$i];
+   }
+   print DEBUG "cmd:" , join(" ", @cmd), "\n" if ($debug == 1);
+   exec @cmd;
+}
+
+sub command_print_command {
+}
+
+require "generic-dumper"
diff --git a/dumper-src/generic-dumper.pl b/dumper-src/generic-dumper.pl
new file mode 100644 (file)
index 0000000..f1fc6d3
--- /dev/null
@@ -0,0 +1,273 @@
+require "newgetopt.pl";
+use Text::ParseWords;
+
+print DEBUG "FHOUT 6: ARGV[0]=" . $ARGV[0] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: ARGV[1]=" . $ARGV[1] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: ARGV[2]=" . $ARGV[2] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: ARGV[3]=" . $ARGV[3] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: ARGV[4]=" . $ARGV[4] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: ARGV[5]=" . $ARGV[5] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: ARGV[6]=" . $ARGV[6] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: ARGV[7]=" . $ARGV[7] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: ARGV[8]=" . $ARGV[8] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: ARGV[9]=" . $ARGV[9] . "\n" if ($debug == 1);
+
+$result = &NGetOpt ("config=s", "host=s", "disk=s", "device=s", "level=s", "index=s", "message=s", "collection", "record");
+$result = $result;
+
+print DEBUG "FHOUT 6: config    =" . $opt_config . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: disk      =" . $opt_disk   . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: host      =" . $opt_host   . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: device    =" . $opt_device . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: level     =" . $opt_level  . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: index     =" . $opt_index  . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: message   =" . $opt_message. "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: collection=" . $opt_collection. "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: record    =" . $opt_record . "\n" if ($debug == 1);
+
+print DEBUG "FHOUT 6: A-ARGV[0]=" . $ARGV[0] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: A-ARGV[1]=" . $ARGV[1] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: A-ARGV[2]=" . $ARGV[2] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: A-ARGV[3]=" . $ARGV[3] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: A-ARGV[4]=" . $ARGV[4] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: A-ARGV[5]=" . $ARGV[5] . "\n" if ($debug == 1);
+print DEBUG "FHOUT 6: A-ARGV[6]=" . $ARGV[6] . "\n" if ($debug == 1);
+
+if (defined $opt_config) {
+  $opt_config =~ /^([\_\.A-Za-z0-9]*)$/;
+  $opt_config = $1;
+}
+
+if (defined $opt_host) {
+  $opt_host =~ /^([\_\.A-Za-z0-9]*)$/;
+  $opt_host = $1;
+}
+
+if (defined $opt_disk) {
+  $opt_disk =~ /^([\/\_\:\.A-Za-z0-9]*)$/;
+  $opt_disk = $1;
+}
+
+if (defined $opt_device) {
+  $opt_device =~ /^([\/\_\:\.A-Za-z0-9]*)$/;
+  $opt_device = $1;
+}
+
+if (defined $opt_level) {
+  $opt_level =~ /^(\d)$/;
+  $opt_level = $1;
+}
+
+# Read tool property
+
+$command = $ARGV[0];
+
+%property = ();
+while($property_line = <STDIN>) {
+  chomp $property_line;
+  ($prop_name, $prop_value) = shellwords($property_line);
+  push @{$property{$prop_name}}, $prop_value;
+  print DEBUG "$prop_name = $prop_value\n" if ($debug == 1);
+}
+
+if ($debug == 1) {
+  foreach $prop_name (keys(%property)) {
+    print DEBUG "PROPERTY: $prop_name\n";
+    print DEBUG "    VALUE: ", join(',',@{$property{$prop_name}}) , "\n";
+  }
+}
+
+sub wrapper_support();
+sub wrapper_selfcheck();
+sub wrapper_estimate();
+sub wrapper_backup();
+sub wrapper_restore();
+
+if ($command eq "support") {
+   wrapper_support();
+}
+elsif ($command eq "selfcheck") {
+   wrapper_selfcheck();
+}
+elsif ($command eq "estimate") {
+   wrapper_estimate();
+}
+elsif ($command eq "backup") {
+   wrapper_backup();
+}
+elsif ($command eq "restore") {
+   wrapper_restore();
+}
+else {
+   printf STDERR "Unknown command `$command'.\n";
+   exit 1;
+}
+
+
+sub wrapper_support() {
+   if(defined(&command_support)) {
+      command_support($opt_config, $opt_host, $opt_disk, $opt_device, $opt_level);
+      exit 0;
+   }
+   print "LEVEL 0-", $max_level , "\n" if defined($max_level);
+   print "INDEX-LINE YES\n"   if defined($index_line)   && $index_line   == 1;
+   print "INDEX-XML NO\n"     if defined($index_xml)    && $index_xml    == 1;
+   print "MESSAGE-LINE YES\n" if defined($message_line) && $message_line == 1;
+   print "MESSAGE-XML NO\n"   if defined($message_xml)  && $message_xml  == 1;
+   print "RECORD YES\n"       if defined($record)       && $record       == 1;
+   print "INCLUDE-FILE NO\n"  if defined($include_file) && $include_file == 1;
+   print "INCLUDE-LIST NO\n"  if defined($include_list) && $include_list == 1;
+   print "EXCLUDE-FILE NO\n"  if defined($exclude_file) && $exclude_file == 1;
+   print "EXCLUDE-LIST NO\n"  if defined($exclude_list) && $exclude_list == 1;
+   print "COLLECTION NO\n"    if defined($collection)   && $collection   == 1;
+   exit 1;
+}
+
+sub wrapper_selfcheck() {
+   if(defined(&command_selfcheck)) {
+      command_selfcheck($opt_config, $opt_host, $opt_disk, $opt_device, $opt_level);
+   }
+   else {
+      exit 1;
+   }
+}
+
+sub wrapper_estimate() {
+   if(defined(&command_estimate)) {
+      command_estimate($opt_config, $opt_host, $opt_disk, $opt_device, $opt_level);
+   } else {
+      exit 1;
+   }
+}
+
+sub wrapper_estimate_parse() {
+   if(defined(&command_estimate_parse)) {
+      command_estimate_parse($opt_config, $opt_host, $opt_disk, $opt_device, $opt_level);
+   }
+   else {
+      printf STDERR "`estimate-parse' is not supported.\n";
+      exit 1;
+   }
+}
+
+sub wrapper_backup() {
+   if(defined(&command_backup)) {
+      command_backup($opt_config, $opt_host, $opt_disk, $opt_device, $opt_level);
+   } else {
+print DEBUG "wrapper_backup: !defined(command_backup)\n" if ($debug == 1);
+      exit 1;
+   }
+}
+
+sub wrapper_backup_parse() {
+   if(defined(&command_backup_parse)) {
+      command_backup_parse($opt_config, $opt_host, $opt_disk, $opt_device, $opt_level);
+   }
+   else {
+      printf STDERR "`backup-parse' is not supported.\n";
+      exit 1;
+   }
+}
+
+sub wrapper_index_from_output() {
+   if(defined(&command_index_from_output)) {
+      command_index_from_output($opt_config, $opt_host, $opt_disk, $opt_device, $opt_level);
+   }
+   else {
+      printf STDERR "`index-from-output' is not supported.\n";
+      exit 1;
+   }
+}
+
+sub wrapper_index_from_image() {
+   if(defined(&command_index_from_image)) {
+      command_index_from_image($opt_config, $opt_host, $opt_disk, $opt_device, $opt_level);
+   }
+   else {
+      printf STDERR "command `index-from-image' is not supported.\n";
+      exit 1;
+   }
+}
+
+sub wrapper_restore() {
+   if(defined(&command_restore)) {
+      command_restore($opt_config, $opt_host, $opt_disk, $opt_device, $opt_level);
+   }
+   else {
+     printf STDERR "`restore' is not supported.\n";
+     exit 1;
+   }
+}
+
+sub parse_options() {
+   my($no_option) = @_;
+   my($options, @options, $option, $name, $option_name, $value);
+
+   while($no_option <= $#ARGV) {
+      $options = $ARGV[${no_option}];
+      @options = split (/;/,$options);
+      foreach $option (@options) {
+         if( $option =~ /=/ ) {
+            ($name,$value) = split(/=/,$option);
+         }
+         else {
+            $name  = $option;
+            $value = 1;
+         }
+         $option_name = "option_$name";
+         $option_name =~ s/\-/\_/g;
+        $$option_name = $value;
+      }
+      $no_option++;
+   }
+}
+
+sub check_file {
+   my($filename, $mode) = @_;
+
+   stat($filename);
+
+   if($mode eq "e") {
+      if( -e _ ) {
+         print "OK $filename exists\n";
+      }
+      else {
+         print "ERROR [can not find $filename]\n";
+      }
+   }
+   elsif($mode eq "x") {
+      if( -x _ ) {
+         print "OK $filename executable\n";
+      }
+      else {
+         print "ERROR [can not execute $filename]\n";
+      }
+   }
+   elsif($mode eq "r") {
+      if( -r _ ) {
+         print "OK $filename readable\n";
+      }
+      else {
+         print "ERROR [can not read $filename]\n";
+      }
+   }
+   elsif($mode eq "w") {
+      if( -w _ ) {
+         print "OK $filename writable\n";
+      }
+      else {
+         print "ERROR [can not write $filename]\n";
+      }
+   }
+   else {
+      print "ERROR [check_file: unknow mode $mode]\n";
+   }
+}
+
+sub check_dir {
+}
+
+sub check_suid {
+}
+
+1;
diff --git a/example/DLT-A4.ps b/example/DLT-A4.ps
new file mode 100644 (file)
index 0000000..fed0893
--- /dev/null
@@ -0,0 +1,263 @@
+%!
+%%BoundingBox: 0 0 595 842
+%%Title: AMANDA ExaLabel
+%%Pages: 1
+%%EndComments
+
+%%%%
+%%%% This is a template file used by AMANDA to create PostScript tape
+%%%% labels for each dump.  This file is set up for DAT 4mm tapes,
+%%%% but you can edit it to work with anything.
+%%%%
+%%%% NOTE: this is quick-hack for DAT TAPES; it is simply a scaled 
+%%%% version of the Exabyte version.
+%%%%
+
+%
+% The label is made up of 6 parts:  statistics, tape name, date,
+% header, filesystem list, and the logo.  Geometrically, the label 
+% looks like this:
+%
+%   +------------------------+
+%   |statistics              |   <- section 'A'
+%   +----+-------------------+
+%   |logo|     TAPE_NAME     |   <- section 'B'  (logo) <- section 'F'
+%   |    | version      date |   <- section 'C'
+%   +----+--+--------+-------+
+%   | h   fs   l | h  fs   l |   <- section 'D'
+%   +-------+--------+-------+
+%   |            |           |   <- section 'E'
+%   |            |           |
+%   v            v           v
+%
+% Sections D and E, which hold the bulk of the information are 
+% cut into columns.
+%
+
+% Quick-hack for DAT tapes
+%
+
+72 25.4 div dup scale              %% scale to millimeters
+
+% section 'A' font, start position, and line separation
+%
+/StatFont              { /Courier findfont 4.5 scalefont setfont } def
+/StatPos               { 30 255 } def
+/StatSep               { 4 } def
+
+% section 'B' font and position (text centered around this point)
+%
+/TitleFont             { /Helvetica-Bold findfont 10 scalefont setfont } def
+/TitlePos              { 115 230 } def
+
+% section 'C' font, position of the date (left justified) and the version
+%
+/DateFont              { /Palatino-Bold findfont 5 scalefont setfont } def
+/DatePos               { 190 222 } def
+/VersFont              { /Palatino-Bold findfont 5 scalefont setfont } def
+/VersPos               { 43 222 } def
+
+% section 'D' font, and field positions (x coord is relative to each column)
+%
+
+/HeadingFont           { /Palatino-Bold findfont 5 scalefont setfont } def
+/HeadingHostPos                { 1 212 } def
+/HeadingFsPos          { 17 212 } def
+/HeadingLvlPos         { 57 212 } def
+
+% section 'E' font, and line separation
+%
+/HostFont              { /Courier findfont 2.6 scalefont setfont } def
+/HostSep               { 2.5 } def
+
+
+% the following rectangles separate the regions
+%
+/StatBox               { 200 260 15 240 } def
+/TitleBox              { 200 240 15 220 } def
+/LogoBox               { 35 240 15 220 } def
+/HeadingBox            { 200 220 15 210 } def
+/HostBox               { 200 210 15 0 } def
+% Punckmark marks center of page height to aid punching holes for ring binder
+/PunchMark             { 13 130 15 130 } def
+
+% number of columns for section 'E,' column width, position of first 
+% entry in first column, y coordinate of top and bottom of dividing lines
+%
+/NumColumns            { 3 } def
+/ColumnWidth           { 60 } def
+/ColumnBasePos         { 16 200 } def
+/TopColDivLine         { 201 } def
+/BotColDivLine         { 2 } def
+
+% 5
+
+%%%%
+%%%% END OF USER-CONFIGURABLE OPTIONS
+%%%%
+%%%% the rest of this file contains the internal functions that are used
+%%%% by genlabel to draw the label
+%%%%
+
+
+%
+% Initial Setup... draws everything that is the same for all labels
+%
+
+% function to draw a box
+%
+/box {
+       /ury exch def
+       /urx exch def
+       /lly exch def
+       /llx exch def
+
+       llx lly moveto
+       llx ury lineto
+       urx ury lineto
+       urx lly lineto
+       closepath
+} def
+
+
+% move the origin up a bit
+%
+0 19 translate
+
+% draw all of the boxes
+%
+0 setgray 
+.3 setlinewidth                                        % thick lines
+StatBox box stroke
+TitleBox box stroke
+LogoBox box stroke
+HeadingBox box stroke
+HostBox box stroke
+% and the PunchMark to aid puching ring binder holes
+PunchMark box stroke
+
+% draw the column dividers
+%
+0.2 setlinewidth                               % thin lines
+/i 1 def
+{
+       NumColumns i sub 0 le { exit } if       % no lines if this last col.
+       /xoff ColumnBasePos pop                 % get x base position
+          i ColumnWidth mul add def            % offset for this column
+       xoff TopColDivLine moveto 
+       xoff BotColDivLine lineto stroke        
+       /i i 1 add def
+} loop
+
+
+% draw the heading names
+%
+/i 0 def
+HeadingFont
+{
+       NumColumns i sub 0 le { exit } if
+       /xoff ColumnBasePos pop
+         i ColumnWidth mul add def
+       HeadingHostPos exch xoff add exch moveto
+         (Host) show
+       HeadingFsPos exch xoff add exch moveto
+         (Fs) show
+       HeadingLvlPos exch xoff add exch moveto
+         (*) show
+       /i i 1 add def
+} loop
+
+
+%
+% the following functions draw strings for each kind of information
+%
+
+/CurrStatY StatPos exch pop def
+ColumnBasePos /CurrColumnY exch def
+  /CurrColumnX exch def
+
+
+% DrawStat draws the string on the top of the stack in the next position
+% in section 'A'
+%
+/DrawStat {
+       StatFont
+       StatPos pop CurrStatY moveto
+       show
+       /CurrStatY CurrStatY StatSep sub def
+} def
+
+
+% DrawTitle draws the string on the top of the stack in section 'B'
+%
+/DrawTitle {
+       TitleFont
+       TitlePos moveto
+       dup stringwidth pop 2 div neg 0 rmoveto
+       show
+} def
+
+
+% DrawDate draws the string on the top of the stack in section 'C'
+%
+/DrawDate {
+       DateFont
+       DatePos moveto
+       dup stringwidth pop neg 0 rmoveto
+       show
+} def
+
+
+% DrawVers draws the string on the top of the stack in section 'C'
+%
+/DrawVers {
+       VersFont
+       VersPos moveto
+       show
+} def
+
+
+/StripDomain {
+
+(.) search {
+  3 1 roll pop pop
+} if
+
+} def
+
+/TrimFs {
+
+dup length 25 gt {
+  dup (*                         ) dup 4 2 roll length 24 sub 24 getinterval 1 exch putinterval
+} if
+
+} def
+
+
+% DrawHost expects five strings to be on the stack; right now it
+% uses only the first three.  The strings are Host Name, Partition Name,
+% Dump Level, Tape File Number, and Output Size.
+% 
+/DrawHost {
+       HostFont
+       pop pop pop                     % discard sizes and fileno
+       CurrColumnX HeadingLvlPos pop add CurrColumnY moveto
+       show
+       CurrColumnX HeadingFsPos pop add CurrColumnY moveto
+       TrimFs
+       show
+       CurrColumnX HeadingHostPos pop add CurrColumnY moveto
+       StripDomain
+       show
+       /CurrColumnY CurrColumnY HostSep sub def
+       CurrColumnY BotColDivLine lt {
+               /CurrColumnY ColumnBasePos exch pop def
+               /CurrColumnX CurrColumnX ColumnWidth add def
+       } if
+} def
+
+
+%%%%
+%%%% END OF TEMPLATE FILE
+%%%% 
+
diff --git a/example/amanda-client.conf b/example/amanda-client.conf
new file mode 100644 (file)
index 0000000..2179acb
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# amanda.conf - sample Amanda client configuration file.
+#
+# This file normally goes in /etc/amanda/amanda-client.conf.
+#
+
+conf "DailySet1"               # your config name
+
+index_server "kdc.localdomain" # your amindexd server
+tape_server  "kdc.localdomain" # your amidxtaped server
+#tapedev      "tape:/dev/YOUR-TAPE-DEVICE-HERE"        # your tape device
+                       # if not set, Use configure or ask server.
+                       # if set to empty string "", ask server
+                       # amrecover will use the changer if set to the value
+                       # of 'amrecover_changer' in the server amanda.conf.
+
+#   auth       - authentication scheme to use between server and client.
+#                Valid values are "bsd", "bsdudp", "bsdtcp", "krb5", "local",
+#                "rsh" and "ssh".  
+#                Default: [auth "bsdtcp"]
+auth "bsdtcp"
+
+ssh_keys ""                    # your ssh keys file if you use ssh auth
+
diff --git a/example/inetd.conf.amandaclient b/example/inetd.conf.amandaclient
new file mode 100644 (file)
index 0000000..d103b6d
--- /dev/null
@@ -0,0 +1,2 @@
+#amanda stream tcp nowait amandabackup /usr/lib/amanda/amandad -auth=bsdtcp amdump
+amanda stream tcp nowait amandabackup /usr/lib/amanda/amandad amandad -auth=bsdtcp amdump
diff --git a/example/template.d/README b/example/template.d/README
new file mode 100644 (file)
index 0000000..162f5d1
--- /dev/null
@@ -0,0 +1,38 @@
+README for template.d directory
+-------------------------------
+
+This directory contains seven files that are used by amserverconfig.
+
+amanda-harddisk.conf:          contains common parameters for a typical Amanda configuration using
+                               virtual tapes.
+
+amanda-single-tape.conf:       contains common parameters for a typical Amanda configuration using
+                               one tape.
+
+amanda-tape-changer.conf:      contains common parameters for a typical Amanda configuration using
+                               tape changer.
+
+advanced.conf:                 contains advanced Amanda parameters that are not usually changed by a site.
+
+dumptypes:                     contains Amanda dumptype definitions.
+
+tapetypes:                     contains Amanda tapetype definitions.
+
+README:                                this file.
+
+
+amserverconfig will create a Amanda configuration in the following directory structure:
+
+/etc/amanda/template.d:
+dumptypes
+tapetypes
+
+/etc/amanda/$config_name:
+amanda.conf    [ it's a copy of amanda-harddisk.conf, amanda-single-tape.conf or amanda-tape-changer.conf ] 
+advanced.conf
+
+
+See amserverconfig(8) or amaddclient(8) for detail.
+
+
+
diff --git a/example/template.d/advanced.conf b/example/template.d/advanced.conf
new file mode 100644 (file)
index 0000000..6036089
--- /dev/null
@@ -0,0 +1,160 @@
+dumpuser "martinea"    # the user to run dumps under
+inparallel 4           # maximum dumpers that will run in parallel (max 63)
+                       # this maximum can be increased at compile-time,
+                       # modifying MAX_DUMPERS in server-src/driverio.h
+
+dumporder "sssS"       # specify the priority order of each dumper
+                       #   s -> smallest size
+                       #   S -> biggest size
+                       #   t -> smallest time
+                       #   T -> biggest time
+                       #   b -> smallest bandwidth
+                       #   B -> biggest bandwitdh
+                       # try "BTBTBTBTBTBT" if you are not holding
+                       # disk constrained
+
+taperalgo first                # The algorithm used to choose which dump image to send
+                       # to the taper.
+
+                       # Possible values: [first|firstfit|largest|largestfit|smallest|last]
+                       # Default: first. 
+
+                       # first         First in - first out.
+                       # firstfit      The first dump image that will fit on the current tape.
+                       # largest       The largest dump image.
+                       # largestfit    The largest dump image that will fit on the current tape.
+                       # smallest      The smallest dump image.
+                       # last          Last in - first out.
+displayunit "m"                # Possible values: "k|m|g|t"
+                       # Default: k. 
+                       # The unit used to print many numbers.
+                       # k=kilo, m=mega, g=giga, t=tera
+netusage  8000 Kbps    # maximum net bandwidth for Amanda, in KB per sec
+
+bumpsize 20 Mb         # minimum savings (threshold) to bump level 1 -> 2
+bumppercent 20         # minimum savings (threshold) to bump level 1 -> 2
+bumpdays 1             # minimum days at each level
+
+# By default, Amanda can only track at most one run per calendar day. When
+# the usetimestamps option is enabled, however, Amanda can track as many
+# runs as you care to make.
+# WARNING: This option is not backward-compatible. Do not enable it if you
+#          intend to downgrade your server installation to any version
+#          earlier than Amanda 2.5.1
+usetimestamps yes
+
+device_output_buffer_size 1280k
+                        # amount of buffer space to use when writing to devices
+
+# If you want Amanda to automatically label any non-Amanda tapes it
+# encounters, uncomment the line below. Note that this will ERASE any
+# non-Amanda tapes you may have, and may also ERASE any near-failing tapes.
+# Use with caution.
+## label_new_tapes "DailySet1-%%%"
+                       
+maxdumpsize -1         # Maximum number of bytes the planner will schedule
+                       # for a run (default: runtapes * tape_length).
+amrecover_do_fsf yes           # amrecover will call amrestore with the
+                               # -f flag for faster positioning of the tape.
+amrecover_check_label yes      # amrecover will call amrestore with the
+                               # -l flag to check the label.
+bumpmult 4             # threshold = bumpsize * bumpmult^(level-1)
+
+
+
+amrecover_changer "changer"    # amrecover will use the changer if you restore
+    # from this device. It could be a string like 'changer' and amrecover will use your
+    # changer if you set your tape to 'changer' with 'setdevice changer' or via 
+    # 'tapedev "changer"' in amanda-client.conf
+
+
+
+
+# If amanda cannot find a tape on which to store backups, it will run
+# as many backups as it can to the holding disks.  In order to save
+# space for unattended backups, by default, amanda will only perform
+# incremental backups in this case, i.e., it will reserve 100% of the
+# holding disk space for the so-called degraded mode backups.
+# However, if you specify a different value for the `reserve'
+# parameter, amanda will not degrade backups if they will fit in the
+# non-reserved portion of the holding disk.
+
+# reserve 30 # percent
+# This means save at least 30% of the holding disk space for degraded
+# mode backups.  
+
+autoflush no 
+# if autoflush is set to yes, then amdump will schedule all dump on
+# holding disks to be flush to tape during the run.
+
+# Amanda needs a few Mb of diskspace for the log and debug files,
+# as well as a database.  This stuff can grow large, so the conf directory
+# isn't usually appropriate.  Some sites use /usr/local/var and some /usr/adm.
+# Create an amanda directory under there.  You need a separate infofile and
+# logdir for each configuration, so create subdirectories for each conf and
+# put the files there.  Specify the locations below.
+
+# Note that, although the keyword below is infofile, it is only so for
+# historic reasons, since now it is supposed to be a directory (unless
+# you have selected some database format other than the `text' default)
+infofile "/etc/amanda/DailySet1/curinfo"      # database DIRECTORY
+logdir   "/etc/amanda/DailySet1"              # log directory
+indexdir "/etc/amanda/DailySet1/index"        # index directory
+#tapelist "@CONFIG_DIR/DailySet1/tapelist"     # list of used tapes
+# tapelist is stored, by default, in the directory that contains amanda.conf
+
+# Specify holding disks.  These are used as a temporary staging area for
+# dumps before they are written to tape and are recommended for most sites.
+# The advantages include: tape drive is more likely to operate in streaming
+# mode (which reduces tape and drive wear, reduces total dump time); multiple
+# dumps can be done in parallel (which can dramatically reduce total dump time.
+# The main disadvantage is that dumps on the holding disk need to be flushed
+# (with amflush) to tape after an operating system crash or a tape failure.
+# If no holding disks are specified then all dumps will be written directly
+# to tape.  If a dump is too big to fit on the holding disk than it will be
+# written directly to tape.  If more than one holding disk is specified then
+# they will all be used based on activity and available space.
+
+#holdingdisk hd1 {
+#    comment "main holding disk"
+#    directory "/dumps/amanda" # where the holding disk is
+#    use -100 Mb               # how much space can we use on it
+#                      # a non-positive value means:
+#                      #        use all space but that value
+#    chunksize 1Gb     # size of chunk if you want big dump to be
+#                      # dumped on multiple files on holding disks
+#                      #  N Kb/Mb/Gb split images in chunks of size N
+#                      #             The maximum value should be
+#                      #             (MAX_FILE_SIZE - 1Mb)
+#                      #  0          same as INT_MAX bytes
+#    }
+#holdingdisk hd2 {
+#    directory "/dumps2/amanda"
+#    use 1000 Mb
+#    }
+
+# network interfaces
+#
+# These are referred to by the disklist file.  They define the attributes
+# of the network interface that the remote machine is accessed through.
+# Notes: - netusage above defines the attributes t
+#          disklist entry doesn't specify otherwise.
+#        - the values below are only samples.
+#        - specifying an interface does not force the traffic to pass
+#          through that interface.  Your OS routing tables do that.  This
+#          is just a mechanism to stop Amanda trashing your network.
+# Attributes are:
+#      use             - bandwidth above which amanda won't start
+#                        backups using this interface.  Note that if
+#                        a single backup will take more than that,
+#                        amanda won't try to make it run slower!
+
+define interface local {
+    comment "a local disk"
+    use 8000 kbps
+}
+
+#define interface le0 {
+#    comment "10 Mbps ethernet"
+#    use 400 kbps
+#}
diff --git a/example/template.d/advanced.conf.in b/example/template.d/advanced.conf.in
new file mode 100644 (file)
index 0000000..19b963e
--- /dev/null
@@ -0,0 +1,160 @@
+dumpuser "@CLIENT_LOGIN@"      # the user to run dumps under
+inparallel 4           # maximum dumpers that will run in parallel (max 63)
+                       # this maximum can be increased at compile-time,
+                       # modifying MAX_DUMPERS in server-src/driverio.h
+
+dumporder "sssS"       # specify the priority order of each dumper
+                       #   s -> smallest size
+                       #   S -> biggest size
+                       #   t -> smallest time
+                       #   T -> biggest time
+                       #   b -> smallest bandwidth
+                       #   B -> biggest bandwitdh
+                       # try "BTBTBTBTBTBT" if you are not holding
+                       # disk constrained
+
+taperalgo first                # The algorithm used to choose which dump image to send
+                       # to the taper.
+
+                       # Possible values: [first|firstfit|largest|largestfit|smallest|last]
+                       # Default: first. 
+
+                       # first         First in - first out.
+                       # firstfit      The first dump image that will fit on the current tape.
+                       # largest       The largest dump image.
+                       # largestfit    The largest dump image that will fit on the current tape.
+                       # smallest      The smallest dump image.
+                       # last          Last in - first out.
+displayunit "m"                # Possible values: "k|m|g|t"
+                       # Default: k. 
+                       # The unit used to print many numbers.
+                       # k=kilo, m=mega, g=giga, t=tera
+netusage  8000 Kbps    # maximum net bandwidth for Amanda, in KB per sec
+
+bumpsize 20 Mb         # minimum savings (threshold) to bump level 1 -> 2
+bumppercent 20         # minimum savings (threshold) to bump level 1 -> 2
+bumpdays 1             # minimum days at each level
+
+# By default, Amanda can only track at most one run per calendar day. When
+# the usetimestamps option is enabled, however, Amanda can track as many
+# runs as you care to make.
+# WARNING: This option is not backward-compatible. Do not enable it if you
+#          intend to downgrade your server installation to any version
+#          earlier than Amanda 2.5.1
+usetimestamps yes
+
+device_output_buffer_size 1280k
+                        # amount of buffer space to use when writing to devices
+
+# If you want Amanda to automatically label any non-Amanda tapes it
+# encounters, uncomment the line below. Note that this will ERASE any
+# non-Amanda tapes you may have, and may also ERASE any near-failing tapes.
+# Use with caution.
+## label_new_tapes "DailySet1-%%%"
+                       
+maxdumpsize -1         # Maximum number of bytes the planner will schedule
+                       # for a run (default: runtapes * tape_length).
+amrecover_do_fsf yes           # amrecover will call amrestore with the
+                               # -f flag for faster positioning of the tape.
+amrecover_check_label yes      # amrecover will call amrestore with the
+                               # -l flag to check the label.
+bumpmult 4             # threshold = bumpsize * bumpmult^(level-1)
+
+
+
+amrecover_changer "changer"    # amrecover will use the changer if you restore
+    # from this device. It could be a string like 'changer' and amrecover will use your
+    # changer if you set your tape to 'changer' with 'setdevice changer' or via 
+    # 'tapedev "changer"' in amanda-client.conf
+
+
+
+
+# If amanda cannot find a tape on which to store backups, it will run
+# as many backups as it can to the holding disks.  In order to save
+# space for unattended backups, by default, amanda will only perform
+# incremental backups in this case, i.e., it will reserve 100% of the
+# holding disk space for the so-called degraded mode backups.
+# However, if you specify a different value for the `reserve'
+# parameter, amanda will not degrade backups if they will fit in the
+# non-reserved portion of the holding disk.
+
+# reserve 30 # percent
+# This means save at least 30% of the holding disk space for degraded
+# mode backups.  
+
+autoflush no 
+# if autoflush is set to yes, then amdump will schedule all dump on
+# holding disks to be flush to tape during the run.
+
+# Amanda needs a few Mb of diskspace for the log and debug files,
+# as well as a database.  This stuff can grow large, so the conf directory
+# isn't usually appropriate.  Some sites use /usr/local/var and some /usr/adm.
+# Create an amanda directory under there.  You need a separate infofile and
+# logdir for each configuration, so create subdirectories for each conf and
+# put the files there.  Specify the locations below.
+
+# Note that, although the keyword below is infofile, it is only so for
+# historic reasons, since now it is supposed to be a directory (unless
+# you have selected some database format other than the `text' default)
+infofile "@CONFIG_DIR@/@DEFAULT_CONFIG@/curinfo"      # database DIRECTORY
+logdir   "@CONFIG_DIR@/@DEFAULT_CONFIG@"              # log directory
+indexdir "@CONFIG_DIR@/@DEFAULT_CONFIG@/index"        # index directory
+#tapelist "@CONFIG_DIR/DailySet1/tapelist"     # list of used tapes
+# tapelist is stored, by default, in the directory that contains amanda.conf
+
+# Specify holding disks.  These are used as a temporary staging area for
+# dumps before they are written to tape and are recommended for most sites.
+# The advantages include: tape drive is more likely to operate in streaming
+# mode (which reduces tape and drive wear, reduces total dump time); multiple
+# dumps can be done in parallel (which can dramatically reduce total dump time.
+# The main disadvantage is that dumps on the holding disk need to be flushed
+# (with amflush) to tape after an operating system crash or a tape failure.
+# If no holding disks are specified then all dumps will be written directly
+# to tape.  If a dump is too big to fit on the holding disk than it will be
+# written directly to tape.  If more than one holding disk is specified then
+# they will all be used based on activity and available space.
+
+#holdingdisk hd1 {
+#    comment "main holding disk"
+#    directory "/dumps/amanda" # where the holding disk is
+#    use -100 Mb               # how much space can we use on it
+#                      # a non-positive value means:
+#                      #        use all space but that value
+#    chunksize 1Gb     # size of chunk if you want big dump to be
+#                      # dumped on multiple files on holding disks
+#                      #  N Kb/Mb/Gb split images in chunks of size N
+#                      #             The maximum value should be
+#                      #             (MAX_FILE_SIZE - 1Mb)
+#                      #  0          same as INT_MAX bytes
+#    }
+#holdingdisk hd2 {
+#    directory "/dumps2/amanda"
+#    use 1000 Mb
+#    }
+
+# network interfaces
+#
+# These are referred to by the disklist file.  They define the attributes
+# of the network interface that the remote machine is accessed through.
+# Notes: - netusage above defines the attributes t
+#          disklist entry doesn't specify otherwise.
+#        - the values below are only samples.
+#        - specifying an interface does not force the traffic to pass
+#          through that interface.  Your OS routing tables do that.  This
+#          is just a mechanism to stop Amanda trashing your network.
+# Attributes are:
+#      use             - bandwidth above which amanda won't start
+#                        backups using this interface.  Note that if
+#                        a single backup will take more than that,
+#                        amanda won't try to make it run slower!
+
+define interface local {
+    comment "a local disk"
+    use 8000 kbps
+}
+
+#define interface le0 {
+#    comment "10 Mbps ethernet"
+#    use 400 kbps
+#}
diff --git a/example/template.d/amanda-S3.conf b/example/template.d/amanda-S3.conf
new file mode 100644 (file)
index 0000000..70297b0
--- /dev/null
@@ -0,0 +1,54 @@
+org "DailySet1"        # your organization name for reports
+mailto "martinea"      # space separated list of operators at your site
+dumpcycle 1 week       # the number of days in the normal dump cycle
+runspercycle 5          # the number of amdump runs in dumpcycle days
+                       # (1 week * 5 amdump runs per week -- just weekdays)
+tapecycle 10 tapes     # the number of tapes in rotation
+                       # 1 week (dumpcycle) times 5 tapes per week (just
+                       # the weekdays) plus a few to handle errors that
+                       # need amflush and so we do not overwrite the full
+                       # backups performed at the beginning of the previous
+                       # cycle
+runtapes 1             # number of tapes to be used in a single run of amdump
+tpchanger "chg-multi"  # the tape-changer glue script
+tapedev "S3:"          # the no-rewind tape device to be used
+changerfile "/etc/amanda/DailySet1/changer.conf" 
+#changerdev "/dev/sg1"
+tapetype HARDDISK      # what kind of tape it is (see tapetypes below)
+
+holdingdisk hd2 {
+    directory "/var/lib/amanda/holdings/DailySet1"
+    use 1000 Mb
+    }
+
+label_new_tapes "DailySet1-%%%%"       # Enable auto labeling 
+labelstr "^DailySet1-[0-9][0-9]*$"     # label constraint regex: all tapes must match
+
+dtimeout 1800          # number of idle seconds before a dump is aborted.
+ctimeout 30            # maximum number of seconds that amcheck waits
+                       # for each client host
+etimeout 300           # number of seconds per filesystem for estimates.
+
+define dumptype global {
+        comment "Global definitions"
+        auth "bsdtcp"
+}
+
+define dumptype gui-base {
+        global
+        program "GNUTAR"
+        comment "gui base dumptype dumped with tar"
+        compress none
+        index yes
+}
+
+define tapetype HARDDISK {
+    comment "Virtual Tapes"
+    length 5000 mbytes
+}
+
+
+includefile "./advanced.conf"
+includefile "/etc/amanda/template.d/dumptypes"
+includefile "/etc/amanda/template.d/tapetypes"
+
diff --git a/example/template.d/amanda-S3.conf.in b/example/template.d/amanda-S3.conf.in
new file mode 100644 (file)
index 0000000..96592d6
--- /dev/null
@@ -0,0 +1,54 @@
+org "@DEFAULT_CONFIG@" # your organization name for reports
+mailto "@CLIENT_LOGIN@"        # space separated list of operators at your site
+dumpcycle 1 week       # the number of days in the normal dump cycle
+runspercycle 5          # the number of amdump runs in dumpcycle days
+                       # (1 week * 5 amdump runs per week -- just weekdays)
+tapecycle 10 tapes     # the number of tapes in rotation
+                       # 1 week (dumpcycle) times 5 tapes per week (just
+                       # the weekdays) plus a few to handle errors that
+                       # need amflush and so we do not overwrite the full
+                       # backups performed at the beginning of the previous
+                       # cycle
+runtapes 1             # number of tapes to be used in a single run of amdump
+tpchanger "chg-multi"  # the tape-changer glue script
+tapedev "S3:"          # the no-rewind tape device to be used
+changerfile "@CONFIG_DIR@/@DEFAULT_CONFIG@/changer.conf" 
+#changerdev "/dev/sg1"
+tapetype HARDDISK      # what kind of tape it is (see tapetypes below)
+
+holdingdisk hd2 {
+    directory "/var/lib/amanda/holdings/@DEFAULT_CONFIG@"
+    use 1000 Mb
+    }
+
+label_new_tapes "@DEFAULT_CONFIG@-%%%%"        # Enable auto labeling 
+labelstr "^@DEFAULT_CONFIG@-[0-9][0-9]*$"      # label constraint regex: all tapes must match
+
+dtimeout 1800          # number of idle seconds before a dump is aborted.
+ctimeout 30            # maximum number of seconds that amcheck waits
+                       # for each client host
+etimeout 300           # number of seconds per filesystem for estimates.
+
+define dumptype global {
+        comment "Global definitions"
+        auth "bsdtcp"
+}
+
+define dumptype gui-base {
+        global
+        program "GNUTAR"
+        comment "gui base dumptype dumped with tar"
+        compress none
+        index yes
+}
+
+define tapetype HARDDISK {
+    comment "Virtual Tapes"
+    length 5000 mbytes
+}
+
+
+includefile "./advanced.conf"
+includefile "@CONFIG_DIR@/template.d/dumptypes"
+includefile "@CONFIG_DIR@/template.d/tapetypes"
+
diff --git a/example/template.d/amanda-harddisk.conf b/example/template.d/amanda-harddisk.conf
new file mode 100644 (file)
index 0000000..395a836
--- /dev/null
@@ -0,0 +1,44 @@
+org "DailySet1"         # your organization name for reports
+mailto "martinea"        # space separated list of operators at your site
+dumpcycle 1 week               # the number of days in the normal dump cycle
+runspercycle 5                 # the number of amdump runs in dumpcycle days
+                               # (1 week * 5 amdump runs per week -- just weekdays)
+tapecycle 10 tapes             # the number of tapes in rotation
+                               # 1 week (dumpcycle) times 5 tapes per week (just
+                               # the weekdays) plus a few to handle errors that
+                               # need amflush and so we do not overwrite the full
+                               # backups performed at the beginning of the previous
+                               # cycle
+runtapes 1                     # number of tapes to be used in a single run of amdump
+tpchanger "chg-disk"           # the tape-changer glue script
+tapedev "file://var/lib/amanda/vtapes/DailySet1" # the no-rewind tape device to be used
+changerfile "/etc/amanda/DailySet1/changer.conf"
+changerdev "/dev/null"
+tapetype HARDDISK               # what kind of tape it is 
+labelstr "^DailySet1-[0-9][0-9]*$"    # label constraint regex: all tapes must match
+dtimeout 1800                          # number of idle seconds before a dump is aborted.
+ctimeout 30                            # maximum number of seconds that amcheck waits
+                                       # for each client host
+etimeout 300                           # number of seconds per filesystem for estimates.
+
+define dumptype global {
+        comment "Global definitions"
+        auth "bsdtcp"
+}
+
+define dumptype gui-base {
+       global
+        program "GNUTAR"
+        comment "gui base dumptype dumped with tar"
+        compress none
+        index yes
+}
+
+define tapetype HARDDISK {
+    comment "Virtual Tapes"
+    length 5000 mbytes
+}
+
+includefile "./advanced.conf"
+includefile "/etc/amanda/template.d/dumptypes"
+includefile "/etc/amanda/template.d/tapetypes"
diff --git a/example/template.d/amanda-harddisk.conf.in b/example/template.d/amanda-harddisk.conf.in
new file mode 100644 (file)
index 0000000..e1c920b
--- /dev/null
@@ -0,0 +1,44 @@
+org "@DEFAULT_CONFIG@"         # your organization name for reports
+mailto "@CLIENT_LOGIN@"        # space separated list of operators at your site
+dumpcycle 1 week               # the number of days in the normal dump cycle
+runspercycle 5                 # the number of amdump runs in dumpcycle days
+                               # (1 week * 5 amdump runs per week -- just weekdays)
+tapecycle 10 tapes             # the number of tapes in rotation
+                               # 1 week (dumpcycle) times 5 tapes per week (just
+                               # the weekdays) plus a few to handle errors that
+                               # need amflush and so we do not overwrite the full
+                               # backups performed at the beginning of the previous
+                               # cycle
+runtapes 1                     # number of tapes to be used in a single run of amdump
+tpchanger "chg-disk"           # the tape-changer glue script
+tapedev "file://var/lib/amanda/vtapes/@DEFAULT_CONFIG@" # the no-rewind tape device to be used
+changerfile "@CONFIG_DIR@/@DEFAULT_CONFIG@/changer.conf"
+changerdev "/dev/null"
+tapetype HARDDISK               # what kind of tape it is 
+labelstr "^@DEFAULT_CONFIG@-[0-9][0-9]*$"    # label constraint regex: all tapes must match
+dtimeout 1800                          # number of idle seconds before a dump is aborted.
+ctimeout 30                            # maximum number of seconds that amcheck waits
+                                       # for each client host
+etimeout 300                           # number of seconds per filesystem for estimates.
+
+define dumptype global {
+        comment "Global definitions"
+        auth "bsdtcp"
+}
+
+define dumptype gui-base {
+       global
+        program "GNUTAR"
+        comment "gui base dumptype dumped with tar"
+        compress none
+        index yes
+}
+
+define tapetype HARDDISK {
+    comment "Virtual Tapes"
+    length 5000 mbytes
+}
+
+includefile "./advanced.conf"
+includefile "@CONFIG_DIR@/template.d/dumptypes"
+includefile "@CONFIG_DIR@/template.d/tapetypes"
diff --git a/example/template.d/amanda-single-tape.conf b/example/template.d/amanda-single-tape.conf
new file mode 100644 (file)
index 0000000..8cd47c9
--- /dev/null
@@ -0,0 +1,47 @@
+org "DailySet1"        # your organization name for reports
+mailto "martinea"      # space separated list of operators at your site
+dumpcycle 1 week       # the number of days in the normal dump cycle
+runspercycle 5          # the number of amdump runs in dumpcycle days
+                       # (1 week * 5 amdump runs per week -- just weekdays)
+tapecycle 10 tapes     # the number of tapes in rotation
+                       # 1 week (dumpcycle) times 5 tapes per week (just
+                       # the weekdays) plus a few to handle errors that
+                       # need amflush and so we do not overwrite the full
+                       # backups performed at the beginning of the previous
+                       # cycle
+
+runtapes 1             # number of tapes to be used in a single run of amdump
+tpchanger "chg-manual" # the tape-changer glue script
+tapedev "tape:/dev/nst0"       # the no-rewind tape device to be used
+changerfile "/etc/amanda/DailySet1/chg-manual.conf"
+changerdev "/dev/null"
+tapetype HP-DAT                        # what kind of tape it is (see tapetypes below)
+holdingdisk hd2 {
+    directory "/var/lib/amanda/holdings/DailySet1"
+    use 1000 Mb
+    }
+
+labelstr "^DailySet1-[0-9][0-9]*$"     # label constraint regex: all tapes must match
+
+dtimeout 1800          # number of idle seconds before a dump is aborted.
+ctimeout 30            # maximum number of seconds that amcheck waits
+                       # for each client host
+etimeout 300           # number of seconds per filesystem for estimates.
+
+
+define dumptype global {
+        comment "Global definitions"
+        auth "bsdtcp"
+}
+
+define dumptype gui-base {
+        global
+        program "GNUTAR"
+        comment "gui base dumptype dumped with tar"
+        compress none
+        index yes
+}
+
+includefile "./advanced.conf"
+includefile "/etc/amanda/template.d/dumptypes"
+includefile "/etc/amanda/template.d/tapetypes"
diff --git a/example/template.d/amanda-single-tape.conf.in b/example/template.d/amanda-single-tape.conf.in
new file mode 100644 (file)
index 0000000..6012305
--- /dev/null
@@ -0,0 +1,47 @@
+org "@DEFAULT_CONFIG@" # your organization name for reports
+mailto "@CLIENT_LOGIN@"        # space separated list of operators at your site
+dumpcycle 1 week       # the number of days in the normal dump cycle
+runspercycle 5          # the number of amdump runs in dumpcycle days
+                       # (1 week * 5 amdump runs per week -- just weekdays)
+tapecycle 10 tapes     # the number of tapes in rotation
+                       # 1 week (dumpcycle) times 5 tapes per week (just
+                       # the weekdays) plus a few to handle errors that
+                       # need amflush and so we do not overwrite the full
+                       # backups performed at the beginning of the previous
+                       # cycle
+
+runtapes 1             # number of tapes to be used in a single run of amdump
+tpchanger "chg-manual" # the tape-changer glue script
+tapedev "tape:/dev/nst0"       # the no-rewind tape device to be used
+changerfile "@CONFIG_DIR@/@DEFAULT_CONFIG@/chg-manual.conf"
+changerdev "/dev/null"
+tapetype HP-DAT                        # what kind of tape it is (see tapetypes below)
+holdingdisk hd2 {
+    directory "/var/lib/amanda/holdings/@DEFAULT_CONFIG@"
+    use 1000 Mb
+    }
+
+labelstr "^@DEFAULT_CONFIG@-[0-9][0-9]*$"      # label constraint regex: all tapes must match
+
+dtimeout 1800          # number of idle seconds before a dump is aborted.
+ctimeout 30            # maximum number of seconds that amcheck waits
+                       # for each client host
+etimeout 300           # number of seconds per filesystem for estimates.
+
+
+define dumptype global {
+        comment "Global definitions"
+        auth "bsdtcp"
+}
+
+define dumptype gui-base {
+        global
+        program "GNUTAR"
+        comment "gui base dumptype dumped with tar"
+        compress none
+        index yes
+}
+
+includefile "./advanced.conf"
+includefile "@CONFIG_DIR@/template.d/dumptypes"
+includefile "@CONFIG_DIR@/template.d/tapetypes"
diff --git a/example/template.d/amanda-tape-changer.conf b/example/template.d/amanda-tape-changer.conf
new file mode 100644 (file)
index 0000000..382259f
--- /dev/null
@@ -0,0 +1,47 @@
+org "DailySet1"        # your organization name for reports
+mailto "martinea"      # space separated list of operators at your site
+dumpcycle 1 week       # the number of days in the normal dump cycle
+runspercycle 5          # the number of amdump runs in dumpcycle days
+                       # (1 week * 5 amdump runs per week -- just weekdays)
+tapecycle 10 tapes     # the number of tapes in rotation
+                       # 1 week (dumpcycle) times 5 tapes per week (just
+                       # the weekdays) plus a few to handle errors that
+                       # need amflush and so we do not overwrite the full
+                       # backups performed at the beginning of the previous
+                       # cycle
+runtapes 1             # number of tapes to be used in a single run of amdump
+tpchanger "chg-zd-mtx" # the tape-changer glue script
+tapedev "tape:/dev/nst0"       # the no-rewind tape device to be used
+changerfile "/etc/amanda/DailySet1/changer.conf" 
+changerdev "/dev/sg1"
+tapetype HP-DAT                        # what kind of tape it is (see tapetypes below)
+
+holdingdisk hd2 {
+    directory "/var/lib/amanda/holdings/DailySet1"
+    use 1000 Mb
+    }
+
+labelstr "^DailySet1-[0-9][0-9]*$"     # label constraint regex: all tapes must match
+
+dtimeout 1800          # number of idle seconds before a dump is aborted.
+ctimeout 30            # maximum number of seconds that amcheck waits
+                       # for each client host
+etimeout 300           # number of seconds per filesystem for estimates.
+
+define dumptype global {
+        comment "Global definitions"
+        auth "bsdtcp"
+}
+
+define dumptype gui-base {
+        global
+        program "GNUTAR"
+        comment "gui base dumptype dumped with tar"
+        compress none
+        index yes
+}
+
+includefile "./advanced.conf"
+includefile "/etc/amanda/template.d/dumptypes"
+includefile "/etc/amanda/template.d/tapetypes"
+
diff --git a/example/template.d/amanda-tape-changer.conf.in b/example/template.d/amanda-tape-changer.conf.in
new file mode 100644 (file)
index 0000000..f46e729
--- /dev/null
@@ -0,0 +1,47 @@
+org "@DEFAULT_CONFIG@" # your organization name for reports
+mailto "@CLIENT_LOGIN@"        # space separated list of operators at your site
+dumpcycle 1 week       # the number of days in the normal dump cycle
+runspercycle 5          # the number of amdump runs in dumpcycle days
+                       # (1 week * 5 amdump runs per week -- just weekdays)
+tapecycle 10 tapes     # the number of tapes in rotation
+                       # 1 week (dumpcycle) times 5 tapes per week (just
+                       # the weekdays) plus a few to handle errors that
+                       # need amflush and so we do not overwrite the full
+                       # backups performed at the beginning of the previous
+                       # cycle
+runtapes 1             # number of tapes to be used in a single run of amdump
+tpchanger "chg-zd-mtx" # the tape-changer glue script
+tapedev "tape:/dev/nst0"       # the no-rewind tape device to be used
+changerfile "@CONFIG_DIR@/@DEFAULT_CONFIG@/changer.conf" 
+changerdev "/dev/sg1"
+tapetype HP-DAT                        # what kind of tape it is (see tapetypes below)
+
+holdingdisk hd2 {
+    directory "/var/lib/amanda/holdings/@DEFAULT_CONFIG@"
+    use 1000 Mb
+    }
+
+labelstr "^@DEFAULT_CONFIG@-[0-9][0-9]*$"      # label constraint regex: all tapes must match
+
+dtimeout 1800          # number of idle seconds before a dump is aborted.
+ctimeout 30            # maximum number of seconds that amcheck waits
+                       # for each client host
+etimeout 300           # number of seconds per filesystem for estimates.
+
+define dumptype global {
+        comment "Global definitions"
+        auth "bsdtcp"
+}
+
+define dumptype gui-base {
+        global
+        program "GNUTAR"
+        comment "gui base dumptype dumped with tar"
+        compress none
+        index yes
+}
+
+includefile "./advanced.conf"
+includefile "@CONFIG_DIR@/template.d/dumptypes"
+includefile "@CONFIG_DIR@/template.d/tapetypes"
+
diff --git a/example/template.d/chg-manual.conf b/example/template.d/chg-manual.conf
new file mode 100644 (file)
index 0000000..4fb86f2
--- /dev/null
@@ -0,0 +1,10 @@
+#
+#configuration used by chg-manual
+#
+resend_mail=3600        # every hour
+timeout_mail=43200      # 12 hours
+#request="tty"          # Use the tty to ask the user to change tape.
+                        # Can't be use by cron
+#request="email"        # Send an email to ask the user to change tape.
+request="tty_email"    # Send request through tty if it exists. 
+                       # Otherwise, it will send an email.
diff --git a/example/template.d/dumptypes b/example/template.d/dumptypes
new file mode 100644 (file)
index 0000000..d0f2ae8
--- /dev/null
@@ -0,0 +1,422 @@
+# dumptypes
+#
+# These are referred to by the disklist file.  The dumptype specifies
+# certain parameters for dumping including:
+#   auth       - authentication scheme to use between server and client.
+#                Valid values are "bsd", "bsdudp", "bsdtcp", "krb5", "local",
+#                "rsh" and "ssh" 
+#                 Default: [auth bsd]
+#   comment    - just a comment string
+#   comprate   - set default compression rate.  Should be followed by one or
+#                two numbers, optionally separated by a comma.  The 1st is
+#                the full compression rate; the 2nd is the incremental rate.
+#                If the second is omitted, it is assumed equal to the first.
+#                The numbers represent the amount of the original file the
+#                compressed file is expected to take up.
+#                Default: [comprate 0.50, 0.50]
+#   compress   - specify compression of the backed up data.  Valid values are:
+#                "none"        - don't compress the dump output.
+#                "client best" - compress on the client using the best (and
+#                                probably slowest) algorithm.
+#                "client fast" - compress on the client using fast algorithm.
+#                 "client custom" - compress using your custom client compression program.
+#                                   use client_custom_compress "PROG" to specify
+#                                   the custom compression program.
+#                                   PROG must not contain white space.
+#                "server best" - compress on the tape host using the best (and
+#                                probably slowest) algorithm.
+#                "server fast" - compress on the tape host using a fast
+#                                algorithm.  This may be useful when a fast
+#                                tape host is backing up slow clients.
+#                 "server custom" - compress using your server custom compression program.
+#                                   use server_custom_compress "PROG" to specify
+#                                   the custom compression program.
+#                                   PROG must not contain white space.
+#                Default: [compress client fast]
+#   dumpcycle  - set the number of days in the dump cycle, ie, set how often a
+#                full dump should be performed.  Default: from DUMPCYCLE variable
+#   estimate      Determine the way AMANDA does it's estimate. 
+#                "client"      - Use the same program as the dumping program,
+#                              this is the most accurate way to do estimates, 
+#                              but it can take a long time.
+#                "calcsize"    - Use a faster program to do estimates, but the
+#                              result is less accurate.
+#                "server"      - Use only statistics from the previous run to 
+#                              give an estimate, 
+#                              it takes only a few seconds but the result is not 
+#                              accurate if your disk usage changes from day to day.
+#                Default: [client]
+#   encrypt  - specify encryption of the backed up data. Valid values are:
+#                 "none"   - don't encrypt the dump output.
+#                 "client" - encrypt on the client using the program specified by
+#                            client_encrypt "PROG".
+#                            Use client_decrypt_option to specify the decrypt-
+#                            parameter, default is "-d".
+#                            PROG and decrypt-parameter must not contain white space.
+#                 "server" - encrypt on the server using the program specified by
+#                            server_encrypt "PROG".
+#                            Use server_decrypt_option to specify the decrypt-
+#                            parameter, default is "-d".
+#                            PROG and decrypt-parameter must not contain white space.
+#                 Default: [none]
+#   exclude    - specify files and directories to be excluded from the dump.
+#                Useful with gnutar only; silently ignored by dump and samba.
+#                Valid values are:
+#                "pattern"       - a shell glob pattern defining which files
+#                                  to exclude.
+#                                  gnutar gets --exclude="pattern"
+#                list "filename" - a file (on the client!) containing patterns
+#                                  re's (1 per line) defining which files to
+#                                  exclude.
+#                                  gnutar gets --exclude-from="filename"
+#                Note that the `full pathname' of a file within its
+#                filesystem starts with `./', because of the way amanda runs
+#                gnutar: `tar -C $mountpoint -cf - --lots-of-options .' (note
+#                the final dot!)  Thus, if you're backing up `/usr' with a
+#                diskfile entry like ``host /usr gnutar-root', but you don't
+#                want to backup /usr/tmp, your exclude list should contain
+#                the pattern `./tmp', as this is relative to the `/usr' above.
+#                Please refer to the man-page of gnutar for more information.
+#                If a relative pathname is specified as the exclude list,
+#                it is searched from within the directory that is
+#                going to be backed up.
+#                Default: include all files
+#   holdingdisk        - should the holding disk be used for this dump.  Useful for
+#                dumping the holding disk itself.  Default: [holdingdisk auto]
+#                "never"    - Never use the holding disk.
+#                "auto"     - Use the holding disk if possible.
+#                "required" - Always use the holding disk.
+#   ignore     - do not back this filesystem up.  Useful for sharing a single
+#                disklist in several configurations.
+#   index      - keep an index of the files backed up.  Default: [index no]
+#   kencrypt   - encrypt the data stream between the client and server.
+#                Default: [kencrypt no]
+#   maxdumps   - max number of concurrent dumps to run on the client.
+#                Default: [maxdumps 1]
+#   maxpromoteday - max number of day for a promotion, set it 0 if you don't
+#                want promotion, set it to 1 or 2 if your disk get
+#                overpromoted.
+#                Default: [10000]
+#   priority   - priority level of the dump.  Valid levels are "low", "medium"
+#                or "high".  These are really only used when Amanda has no
+#                tape to write to because of some error.  In that "degraded
+#                mode", as many incrementals as will fit on the holding disk
+#                are done, higher priority first, to insure the important
+#                disks are at least dumped.  Default: [priority medium]
+#   program    - specify the dump system to use.  Valid values are "DUMP" 
+#                "STAR" and "GNUTAR".  Default: [program "DUMP"].
+#   record     - record the backup in the time-stamp-database of the backup
+#                program (e.g. /etc/dumpdates for DUMP or
+#                /var/lib/amanda/gnutar-lists for GNUTAR.).
+#                Default: [record yes]
+#   skip-full  - skip the disk when a level 0 is due, to allow full backups
+#                outside Amanda, eg when the machine is in single-user mode.
+#   skip-incr  - skip the disk when the level 0 is NOT due.  This is used in
+#                archive configurations, where only full dumps are done and
+#                the tapes saved.
+#   starttime  - delay the start of the dump?  Default: no delay
+#   strategy   - set the dump strategy.  Valid strategies are currently:
+#                "standard" - the standard one.
+#                "nofull"   - do level 1 dumps every time.  This can be used,
+#                             for example, for small root filesystems that
+#                             only change slightly relative to a site-wide
+#                             prototype.  Amanda then backs up just the
+#                             changes.
+#                "noinc"    - do level 0 dumps every time.
+#                "skip"     - skip all dumps.  Useful for sharing a single
+#                             disklist in several configurations.
+#                "incronly" - do only incremental dumps. This is similar
+#                              to strategy 'nofull', but will increase
+#                              the dump level as usual. Full dumps will
+#                              only be performed when an 'amadmin force' 
+#                              has been issued 
+#                Default: [strategy standard]
+# tape_splitsize - (optional) split dump file into pieces of a specified size.
+#                This allows dumps to be spread across multiple tapes, and can
+#                potentially make more efficient use of tape space.  Note that
+#                if this value is too large (more than half the size of the
+#                average dump being split), substantial tape space can be
+#                wasted.  If too small, large dumps will be split into
+#                innumerable tiny dumpfiles, adding to restoration complexity.
+#                A good rule of thumb, usually, is 1/10 of the size of your
+#                tape.  Default: [disabled]
+# split_diskbuffer - (optional) When dumping a split dump  in  PORT-WRITE
+#                 mode (usually meaning "no holding disk"), buffer the split
+#                chunks to a file in the directory specified by this option.
+#                Default: [none]
+# fallback_splitsize - (optional) When dumping a split dump  in  PORT-WRITE
+#                 mode, if no split_diskbuffer is specified (or if we somehow
+#                 fail to use our split_diskbuffer), we must buffer split
+#                 chunks in memory.  This specifies the maximum size split
+#                 chunks can be in this scenario, and thus the maximum amount
+#                 of memory consumed for in-memory splitting.  Default: [10m]
+#
+#
+# Note that you may specify previously defined dumptypes as a shorthand way
+# of defining parameters.
+
+# dumptype global defined in $config/amanda.conf
+
+define dumptype always-full {
+    global
+    comment "Full dump of this filesystem always"
+    compress none
+    priority high
+    dumpcycle 0
+}
+
+# Dumptypes for star
+define dumptype root-star {
+    global
+    program "STAR"
+    comment "root partitions dumped with star"
+    compress none
+    index
+#    exclude list "/var/lib/amanda/exclude.star"
+    priority low
+}
+
+define dumptype user-star {
+    root-star
+    comment "user partitions dumped with star"
+    priority medium
+}
+
+define dumptype user-star-span {
+    root-star
+    tape_splitsize 3 Gb
+    comment "tape-spanning user partitions dumped with star"
+    priority medium
+}
+
+define dumptype high-star {
+    root-star
+    comment "partitions dumped with star"
+    priority high
+}
+
+define dumptype comp-root-star {
+    root-star
+    comment "Root partitions with compression"
+    compress client fast
+}
+
+define dumptype comp-user-star {
+    user-star
+    compress client fast
+}
+
+define dumptype comp-user-star-span {
+    user-star-span
+    compress client fast
+}
+
+# Dumptypes for gnutar
+
+define dumptype root-tar {
+    global
+    program "GNUTAR"
+    comment "root partitions dumped with tar"
+    compress none 
+    index
+    priority low
+}
+
+
+define dumptype user-tar {
+    root-tar
+    comment "user partitions dumped with tar"
+    priority medium
+}
+
+
+define dumptype user-tar-span {
+    root-tar
+    tape_splitsize 3 Gb
+    comment "tape-spanning user partitions dumped with tar"
+    priority medium
+}
+
+
+define dumptype high-tar {
+    root-tar
+    comment "partitions dumped with tar"
+    priority high
+}
+
+define dumptype comp-root-tar {
+    root-tar
+    comment "Root partitions with compression dumped with tar"
+    compress client fast
+}
+
+define dumptype comp-user-tar {
+    user-tar
+    compress client fast
+}
+
+define dumptype comp-user-tar-span {
+    user-tar-span
+    compress client fast
+}
+
+
+define dumptype holding-disk {
+    global
+    comment "The master-host holding disk itself"
+    holdingdisk never # do not use the holding disk
+    priority medium
+}
+
+define dumptype comp-user {
+    global
+    comment "Non-root partitions on reasonably fast machines"
+    compress client fast
+    priority medium
+}
+
+define dumptype comp-user-span {
+    global
+    tape_splitsize 5 Gb
+    comment "Tape-spanning non-root partitions on reasonably fast machines"
+    compress client fast
+    priority medium
+}
+
+
+define dumptype nocomp-user {
+    comp-user
+    comment "Non-root partitions on slow machines"
+    compress none
+}
+
+define dumptype nocomp-user-span {
+    comp-user-span
+    comment "Tape-spanning non-root partitions on slow machines"
+    compress none
+}
+
+
+define dumptype comp-root {
+    global
+    comment "Root partitions with compression"
+    compress client fast
+    priority low
+}
+
+define dumptype nocomp-root {
+    comp-root
+    comment "Root partitions without compression"
+    compress none
+}
+
+define dumptype comp-high {
+    global
+    comment "very important partitions on fast machines"
+    compress client best
+    priority high
+}
+
+define dumptype nocomp-high {
+    comp-high
+    comment "very important partitions on slow machines"
+    compress none
+}
+
+define dumptype nocomp-test {
+    global
+    comment "test dump without compression, no /etc/dumpdates recording"
+    compress none
+    record no
+    priority medium
+}
+
+define dumptype comp-test {
+    nocomp-test
+    comment "test dump with compression, no /etc/dumpdates recording"
+    compress client fast
+}
+
+define dumptype nocomp-ssh {
+   root-tar
+   comment "ssh authorization and dumped with tar"
+   auth "ssh"
+   ssh_keys "/var/lib/amanda/.ssh/id_rsa_amdump"
+   compress none
+}
+   
+
+define dumptype custom-compress {
+   root-tar
+   comment "custom client compression, dumped with tar"
+   compress client custom
+   client_custom_compress "/usr/bin/bzip2"
+}
+
+# amcrypt requires aespipe and uuencode
+define dumptype encrypt-fast {
+   root-tar
+   comment "fast client compression and server symmetric encryption, dumped with tar"
+   compress client fast
+   encrypt server
+   server_encrypt "/usr/sbin/amcrypt"
+   server_decrypt_option "-d"
+}
+
+
+# amcryptsimple use gpg symmetric encryption. gpg does compress with zlib by default.
+# Thus, specify compress none.
+define dumptype encrypt-simple-nocomp {
+   root-tar
+   comment "client simple symmetric encryption, dumped with tar"
+   compress none
+   encrypt client
+   client_encrypt "/usr/sbin/amcryptsimple"
+   client_decrypt_option "-d"
+}
+
+# To use gpg public-key encryption, gpg does compress with zlib by default.
+# Thus, specify compress none.
+
+define dumptype gpg-encrypt-nocomp {
+   root-tar
+   comment "server public-key encryption, dumped with tar"
+   compress none
+   encrypt server
+   server_encrypt "/usr/sbin/amgpgcrypt"
+   server_decrypt_option "-d"
+}
+
+# The following dumptypes are for ZMC
+# dumptype gui-base defined in $config/amanda.conf
+
+define dumptype gui-default {
+   gui-base
+   comment "gui default dumptype"
+   compress none
+   encrypt none
+}
+
+define dumptype gui-compress {
+   gui-base
+   comment "gui dumptype with compression"
+   compress client fast
+   encrypt none
+}
+
+define dumptype gui-encrypt {
+   gui-base
+   comment "gui dumptype with encryption"
+   compress none
+   encrypt server
+   server_encrypt "/usr/sbin/amcryptsimple"
+}
+
+define dumptype gui-encrypt-compress {
+   gui-base
+   comment "gui dumptype with compression and encryption"
+   compress client fast
+   encrypt server 
+   server_encrypt "/usr/sbin/amcryptsimple"
+}
+
diff --git a/example/template.d/tapetypes b/example/template.d/tapetypes
new file mode 100644 (file)
index 0000000..effaeed
--- /dev/null
@@ -0,0 +1,308 @@
+# tapetypes
+
+# Define the type of tape you use here, and use it in "tapetype"
+# above.  Some typical types of tapes are included here.  The tapetype
+# tells amanda how many MB will fit on the tape, how big the filemarks
+# are, and how fast the tape device is.
+
+# A filemark is the amount of wasted space every time a tape section
+# ends.  If you run `make tapetype' in tape-src, you'll get a program
+# that generates tapetype entries, but it is slow as hell, use it only
+# if you really must and, if you do, make sure you post the data to
+# the amanda mailing list, so that others can use what you found out
+# by searching the archives.
+
+# For completeness Amanda should calculate the inter-record gaps too,
+# but it doesn't.  For EXABYTE and DAT tapes this is ok.  Anyone using
+# 9 tracks for amanda and need IRG calculations?  Drop me a note if
+# so.
+
+# If you want amanda to print postscript paper tape labels
+# add a line after the comment in the tapetype of the form
+#    lbl-templ "/path/to/postscript/template/label.ps"
+
+# if you want the label to go to a printer other than the default
+# for your system, you can also add a line above for a different
+# printer. (i usually add that line after the dumpuser specification)
+
+# dumpuser "operator"     # the user to run dumps under
+# printer "mypostscript"  # printer to print paper label on
+
+# here is an example of my definition for an EXB-8500
+
+# define tapetype EXB-8500 {
+# ...
+#     lbl-templ "/usr/local/amanda/config/lbl.exabyte.ps"
+# }
+
+# HARDDISK defintion in amanda.conf
+
+define tapetype DLT-S4 {
+   comment "just produced by tapetype prog, compression off"
+   length 772096 mbytes
+   filemark 0 kbytes
+   speed 33596 kps
+}
+
+define tapetype DLT8000 {
+    comment "Quantum DLT8000 created by tapetype"
+    length 38130 mbytes
+    filemark 29 kbytes
+    speed 5627 kps
+}
+
+define tapetype QUANTUM-DLT4000 {
+    comment "Quantum DLT4000, compression off"
+    length 19534 mbytes
+    filemark 4 kbytes
+    speed 1096 kps
+}
+
+
+define tapetype SDLT600 {
+    comment "Quantum SDLT600 with 10MB/s"
+    length 306789 mbytes
+    filemark 0 kbytes
+    speed 8247 kps
+}
+
+
+define tapetype SDLT320 {
+     comment "HP Super DLTtape I, data cartridge, C7980A, compression on"
+     length 139776 mbytes
+     filemark 0 kbytes
+     speed 13980 kps
+}
+
+define tapetype SDLT220NOCOMP {
+  comment "Quantum SDLT 220, compression off"
+  length 109539 mbytes
+  filemark 0 kbytes
+  speed 10351 kps
+}
+
+define tapetype Quantum-DLT-V4 {
+     comment "Quantum-DLT-V4 on Adaptec 29160"
+     length 157284 mbytes
+     filemark 0 kbytes
+     speed 9936 kps
+}
+
+define tapetype AIT1{
+     comment "Sony AIT-1 with 170m tapes"
+     length 21568 mbytes
+     filemark 0 kbytes
+     speed 2699 kps
+} 
+
+define tapetype AIT1-35 {
+     comment "Sony AIT1 cartridge 35/70 Gbyte, compression off"
+     length 33400 mbytes    # rounded down
+     filemark 500 kbytes
+     speed 2890 kps
+}
+
+define tapetype LTO {
+   comment "Dell PowerVault 122T, Seagate Ultrium, IBM 3581-H17, compression off"
+   length 101376 mbytes
+   filemark 0 kbytes
+   speed 13872 kps
+}
+
+define tapetype QUANTUM-LTO2 {
+   comment " Quantum LTO-2 HH, compression off"
+   length 186368 mbytes
+   filemark 0 kbytes
+   speed 2781 kps
+}
+
+define tapetype LTO2 {
+   comment "HP Ultrium 448, hardware compression off"
+   length 193024 mbytes
+   filemark 0 kbytes
+   speed 20355 kps
+}
+
+define tapetype DELL-LTO3-400 {
+     comment "Dell PV124T LTO3, compression off"
+     length 402432 mbytes
+     filemark 0 kbytes
+     speed 71189 kps
+}
+
+define tapetype DELL-LTO2-200 {
+     comment "Dell PV132T LTO2, hardware compression"
+     length 201216 mbytes
+     filemark 0 kbytes
+     speed 31343 kps
+}
+
+define tapetype IBM-ULTRIUM-3582 {
+     comment "IBM Ultrium 3582, compression on"
+     length 199168 mbytes
+     filemark 0 kbytes
+     speed 30760 kps
+}
+
+define tapetype LTO3-400 {
+     comment "LTO Ultrium 3 400/800, compression off"
+     length 402432 mbytes
+     filemark 0 kbytes
+     speed 71702 kps
+}
+
+define tapetype HP-ULTRIUM-960 {
+     comment "HP Ultrium 960, compression off"
+     length 386048 mbytes
+     filemark 0 kbytes
+     speed 67629 kps
+}
+
+define tapetype SEAGATE-ULTRIUM-LTO {
+     comment "SEAGATE ULTRIUM 06242 LTO, compression off"
+     length 99584 mbytes
+     filemark 0 kbytes
+     speed 11288 kps
+}
+
+define tapetype QS3LTO-3 {
+     comment "Quantum Super Loader 3 LTO-3 16 tape library"
+     length 448369 mbytes
+     filemark 6403 kbytes
+     speed 37739 kps
+}
+
+define tapetype DDS90 {
+     comment "DDS tapes drives - 90 meter tapes"
+     length 1900000 kbytes # rounded down
+     filemark 111 kbytes
+     speed 380 kps
+}
+
+define tapetype DDS120 {
+     comment "DDS tape drives - 120 meter tapes"
+     length 3850000  # rounded down
+     filemark 111 kbytes
+     speed 380 kps
+}
+
+define tapetype IBM-DAT-72 {
+   comment "DDS5, compression on"
+   length 30227 mbytes
+   filemark 0 kbytes
+   speed 2559 kps
+}
+
+define tapetype HP-DAT-72 {
+   comment "DDS5, /dev/rmt/0ln, HP C7438A Rev V309, compression on"
+   length 30227 mbytes
+   filemark 0 kbytes
+   speed 2551 kps
+}
+
+define tapetype DLT1 {
+   comment "HP DLT1, DLT IV Tape C5141F, compression on"
+   length 34818 mbytes
+   filemark 32 kbytes
+   speed 2879 kps
+}
+
+define tapetype ARCvault24 {
+   comment "Overland ARCvault, compression off"
+   length 386048 mbytes
+   filemark 0 kbytes
+   speed 38246 kps
+}
+
+define tapetype QIC-60 {
+    comment "Archive Viper"
+    length 60 mbytes
+    filemark 100 kbytes         
+    speed 100 kbytes            
+}
+
+define tapetype CD650 {
+    comment "CD-R 650MB sized vtape"
+    length 681984000 bytes
+    filemark 4 Kbytes
+}
+
+
+define tapetype CD700 {
+    comment "CD-R 700MB sized vtape"
+    length 737280000 bytes
+    filemark 4 Kbytes
+}
+
+define tapetype DVD47 {
+    comment "A 4.7 Gbyte DVD-sized vtape"
+    length 4482 mbytes
+    filemark 4 kbytes
+}
+
+define tapetype DVD85 {
+     comment "A 8.5 GB DVD double layer"
+     length 8100 mbytes   # approximately - exact value not found
+     filemark 4 kbytes
+}
+
+
+define tapetype DEC-DLT2000 {
+    comment "DEC Differential Digital Linear Tape 2000"
+    length 15000 mbytes
+    filemark 8 kbytes
+    speed 1250 kbytes
+}
+
+# goluboff@butch.Colorado.EDU
+# in amanda-users (Thu Dec 26 01:55:38 MEZ 1996)
+define tapetype DLT {
+    comment "DLT tape drives"
+    length 20000 mbytes                # 20 Gig tapes
+    filemark 2000 kbytes       
+    speed 1536 kbytes          
+}
+
+define tapetype SURESTORE-1200E {
+    comment "HP AutoLoader"
+    length 3900 mbytes
+    filemark 100 kbytes
+    speed 500 kbytes
+}
+
+define tapetype EXB-8500 {
+    comment "Exabyte EXB-8500 drive on decent machine"
+    length 4200 mbytes
+    filemark 48 kbytes
+    speed 474 kbytes                   
+}
+
+define tapetype EXB-8200 {
+    comment "Exabyte EXB-8200 drive on decent machine"
+    length 2200 mbytes
+    filemark 2130 kbytes
+    speed 240 kbytes                   
+}
+
+define tapetype HP-DAT {
+    comment "DAT tape drives"
+    # data provided by Rob Browning <rlb@cs.utexas.edu>
+    length 1930 mbytes
+    filemark 111 kbytes
+    speed 468 kbytes
+}
+
+define tapetype DAT {
+    comment "DAT tape drives"
+    length 1000 mbytes         # these numbers are not accurate
+    filemark 100 kbytes                # but you get the idea
+    speed 100 kbytes
+}
+
+define tapetype MIMSY-MEGATAPE {
+    comment "Megatape (Exabyte based) drive through Emulex on Vax 8600"
+    length 2200 mbytes
+    filemark 2130 kbytes
+    speed 170 kbytes           # limited by the Emulex bus interface, ugh
+}
+
diff --git a/example/xinetd.amandaclient b/example/xinetd.amandaclient
new file mode 100644 (file)
index 0000000..7747b0f
--- /dev/null
@@ -0,0 +1,19 @@
+# default: on
+#
+# description: The Amanda backup client should be enabled for systems
+#              which will be backed up by an Amanda backup server.
+
+service amanda
+{
+       disable         = no
+       flags           = IPv4
+        flags          = IPv6
+       socket_type     = stream
+       protocol        = tcp
+       wait            = no
+       user            = amandabackup
+       group           = disk
+       groups          = yes
+       server          = /usr/libexec/amanda/amandad 
+       server_args     = -auth=bsdtcp amdump
+}
diff --git a/example/xinetd.amandaserver b/example/xinetd.amandaserver
new file mode 100644 (file)
index 0000000..8279d4e
--- /dev/null
@@ -0,0 +1,19 @@
+# default: on
+#
+# description: Amanda services for Amanda server and client.
+#              
+
+service amanda
+{
+        disable         = no
+       flags           = IPv4
+        flags          = IPv6
+        socket_type     = stream
+        protocol        = tcp
+        wait            = no
+        user            = amandabackup
+        group           = disk
+        groups          = yes
+        server          = /usr/libexec/amanda/amandad
+        server_args     = -auth=bsdtcp amdump amindexd amidxtaped
+}
diff --git a/gnulib/base64.c b/gnulib/base64.c
new file mode 100644 (file)
index 0000000..f237cd6
--- /dev/null
@@ -0,0 +1,425 @@
+/* base64.c -- Encode binary data using printable characters.
+   Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006 Free Software
+   Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Simon Josefsson.  Partially adapted from GNU MailUtils
+ * (mailbox/filter_trans.c, as of 2004-11-28).  Improved by review
+ * from Paul Eggert, Bruno Haible, and Stepan Kasal.
+ *
+ * See also RFC 3548 <http://www.ietf.org/rfc/rfc3548.txt>.
+ *
+ * Be careful with error checking.  Here is how you would typically
+ * use these functions:
+ *
+ * bool ok = base64_decode_alloc (in, inlen, &out, &outlen);
+ * if (!ok)
+ *   FAIL: input was not valid base64
+ * if (out == NULL)
+ *   FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN
+ *
+ * size_t outlen = base64_encode_alloc (in, inlen, &out);
+ * if (out == NULL && outlen == 0 && inlen != 0)
+ *   FAIL: input too long
+ * if (out == NULL)
+ *   FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN.
+ *
+ */
+
+#include <config.h>
+
+/* Get prototype. */
+#include "base64.h"
+
+/* Get malloc. */
+#include <stdlib.h>
+
+/* Get UCHAR_MAX. */
+#include <limits.h>
+
+/* C89 compliant way to cast 'char' to 'unsigned char'. */
+static inline unsigned char
+to_uchar (char ch)
+{
+  return ch;
+}
+
+/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
+   If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
+   possible.  If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
+   terminate the output buffer. */
+void
+base64_encode (const char *restrict in, size_t inlen,
+              char *restrict out, size_t outlen)
+{
+  static const char b64str[64] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  while (inlen && outlen)
+    {
+      *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f];
+      if (!--outlen)
+       break;
+      *out++ = b64str[((to_uchar (in[0]) << 4)
+                      + (--inlen ? to_uchar (in[1]) >> 4 : 0))
+                     & 0x3f];
+      if (!--outlen)
+       break;
+      *out++ =
+       (inlen
+        ? b64str[((to_uchar (in[1]) << 2)
+                  + (--inlen ? to_uchar (in[2]) >> 6 : 0))
+                 & 0x3f]
+        : '=');
+      if (!--outlen)
+       break;
+      *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '=';
+      if (!--outlen)
+       break;
+      if (inlen)
+       inlen--;
+      if (inlen)
+       in += 3;
+    }
+
+  if (outlen)
+    *out = '\0';
+}
+
+/* Allocate a buffer and store zero terminated base64 encoded data
+   from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
+   the length of the encoded data, excluding the terminating zero.  On
+   return, the OUT variable will hold a pointer to newly allocated
+   memory that must be deallocated by the caller.  If output string
+   length would overflow, 0 is returned and OUT is set to NULL.  If
+   memory allocation failed, OUT is set to NULL, and the return value
+   indicates length of the requested memory block, i.e.,
+   BASE64_LENGTH(inlen) + 1. */
+size_t
+base64_encode_alloc (const char *in, size_t inlen, char **out)
+{
+  size_t outlen = 1 + BASE64_LENGTH (inlen);
+
+  /* Check for overflow in outlen computation.
+   *
+   * If there is no overflow, outlen >= inlen.
+   *
+   * If the operation (inlen + 2) overflows then it yields at most +1, so
+   * outlen is 0.
+   *
+   * If the multiplication overflows, we lose at least half of the
+   * correct value, so the result is < ((inlen + 2) / 3) * 2, which is
+   * less than (inlen + 2) * 0.66667, which is less than inlen as soon as
+   * (inlen > 4).
+   */
+  if (inlen > outlen)
+    {
+      *out = NULL;
+      return 0;
+    }
+
+  *out = malloc (outlen);
+  if (!*out)
+    return outlen;
+
+  base64_encode (in, inlen, *out, outlen);
+
+  return outlen - 1;
+}
+
+/* With this approach this file works independent of the charset used
+   (think EBCDIC).  However, it does assume that the characters in the
+   Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255.  POSIX
+   1003.1-2001 require that char and unsigned char are 8-bit
+   quantities, though, taking care of that problem.  But this may be a
+   potential problem on non-POSIX C99 platforms.
+
+   IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
+   as the formal parameter rather than "x".  */
+#define B64(_)                                 \
+  ((_) == 'A' ? 0                              \
+   : (_) == 'B' ? 1                            \
+   : (_) == 'C' ? 2                            \
+   : (_) == 'D' ? 3                            \
+   : (_) == 'E' ? 4                            \
+   : (_) == 'F' ? 5                            \
+   : (_) == 'G' ? 6                            \
+   : (_) == 'H' ? 7                            \
+   : (_) == 'I' ? 8                            \
+   : (_) == 'J' ? 9                            \
+   : (_) == 'K' ? 10                           \
+   : (_) == 'L' ? 11                           \
+   : (_) == 'M' ? 12                           \
+   : (_) == 'N' ? 13                           \
+   : (_) == 'O' ? 14                           \
+   : (_) == 'P' ? 15                           \
+   : (_) == 'Q' ? 16                           \
+   : (_) == 'R' ? 17                           \
+   : (_) == 'S' ? 18                           \
+   : (_) == 'T' ? 19                           \
+   : (_) == 'U' ? 20                           \
+   : (_) == 'V' ? 21                           \
+   : (_) == 'W' ? 22                           \
+   : (_) == 'X' ? 23                           \
+   : (_) == 'Y' ? 24                           \
+   : (_) == 'Z' ? 25                           \
+   : (_) == 'a' ? 26                           \
+   : (_) == 'b' ? 27                           \
+   : (_) == 'c' ? 28                           \
+   : (_) == 'd' ? 29                           \
+   : (_) == 'e' ? 30                           \
+   : (_) == 'f' ? 31                           \
+   : (_) == 'g' ? 32                           \
+   : (_) == 'h' ? 33                           \
+   : (_) == 'i' ? 34                           \
+   : (_) == 'j' ? 35                           \
+   : (_) == 'k' ? 36                           \
+   : (_) == 'l' ? 37                           \
+   : (_) == 'm' ? 38                           \
+   : (_) == 'n' ? 39                           \
+   : (_) == 'o' ? 40                           \
+   : (_) == 'p' ? 41                           \
+   : (_) == 'q' ? 42                           \
+   : (_) == 'r' ? 43                           \
+   : (_) == 's' ? 44                           \
+   : (_) == 't' ? 45                           \
+   : (_) == 'u' ? 46                           \
+   : (_) == 'v' ? 47                           \
+   : (_) == 'w' ? 48                           \
+   : (_) == 'x' ? 49                           \
+   : (_) == 'y' ? 50                           \
+   : (_) == 'z' ? 51                           \
+   : (_) == '0' ? 52                           \
+   : (_) == '1' ? 53                           \
+   : (_) == '2' ? 54                           \
+   : (_) == '3' ? 55                           \
+   : (_) == '4' ? 56                           \
+   : (_) == '5' ? 57                           \
+   : (_) == '6' ? 58                           \
+   : (_) == '7' ? 59                           \
+   : (_) == '8' ? 60                           \
+   : (_) == '9' ? 61                           \
+   : (_) == '+' ? 62                           \
+   : (_) == '/' ? 63                           \
+   : -1)
+
+static const signed char b64[0x100] = {
+  B64 (0), B64 (1), B64 (2), B64 (3),
+  B64 (4), B64 (5), B64 (6), B64 (7),
+  B64 (8), B64 (9), B64 (10), B64 (11),
+  B64 (12), B64 (13), B64 (14), B64 (15),
+  B64 (16), B64 (17), B64 (18), B64 (19),
+  B64 (20), B64 (21), B64 (22), B64 (23),
+  B64 (24), B64 (25), B64 (26), B64 (27),
+  B64 (28), B64 (29), B64 (30), B64 (31),
+  B64 (32), B64 (33), B64 (34), B64 (35),
+  B64 (36), B64 (37), B64 (38), B64 (39),
+  B64 (40), B64 (41), B64 (42), B64 (43),
+  B64 (44), B64 (45), B64 (46), B64 (47),
+  B64 (48), B64 (49), B64 (50), B64 (51),
+  B64 (52), B64 (53), B64 (54), B64 (55),
+  B64 (56), B64 (57), B64 (58), B64 (59),
+  B64 (60), B64 (61), B64 (62), B64 (63),
+  B64 (64), B64 (65), B64 (66), B64 (67),
+  B64 (68), B64 (69), B64 (70), B64 (71),
+  B64 (72), B64 (73), B64 (74), B64 (75),
+  B64 (76), B64 (77), B64 (78), B64 (79),
+  B64 (80), B64 (81), B64 (82), B64 (83),
+  B64 (84), B64 (85), B64 (86), B64 (87),
+  B64 (88), B64 (89), B64 (90), B64 (91),
+  B64 (92), B64 (93), B64 (94), B64 (95),
+  B64 (96), B64 (97), B64 (98), B64 (99),
+  B64 (100), B64 (101), B64 (102), B64 (103),
+  B64 (104), B64 (105), B64 (106), B64 (107),
+  B64 (108), B64 (109), B64 (110), B64 (111),
+  B64 (112), B64 (113), B64 (114), B64 (115),
+  B64 (116), B64 (117), B64 (118), B64 (119),
+  B64 (120), B64 (121), B64 (122), B64 (123),
+  B64 (124), B64 (125), B64 (126), B64 (127),
+  B64 (128), B64 (129), B64 (130), B64 (131),
+  B64 (132), B64 (133), B64 (134), B64 (135),
+  B64 (136), B64 (137), B64 (138), B64 (139),
+  B64 (140), B64 (141), B64 (142), B64 (143),
+  B64 (144), B64 (145), B64 (146), B64 (147),
+  B64 (148), B64 (149), B64 (150), B64 (151),
+  B64 (152), B64 (153), B64 (154), B64 (155),
+  B64 (156), B64 (157), B64 (158), B64 (159),
+  B64 (160), B64 (161), B64 (162), B64 (163),
+  B64 (164), B64 (165), B64 (166), B64 (167),
+  B64 (168), B64 (169), B64 (170), B64 (171),
+  B64 (172), B64 (173), B64 (174), B64 (175),
+  B64 (176), B64 (177), B64 (178), B64 (179),
+  B64 (180), B64 (181), B64 (182), B64 (183),
+  B64 (184), B64 (185), B64 (186), B64 (187),
+  B64 (188), B64 (189), B64 (190), B64 (191),
+  B64 (192), B64 (193), B64 (194), B64 (195),
+  B64 (196), B64 (197), B64 (198), B64 (199),
+  B64 (200), B64 (201), B64 (202), B64 (203),
+  B64 (204), B64 (205), B64 (206), B64 (207),
+  B64 (208), B64 (209), B64 (210), B64 (211),
+  B64 (212), B64 (213), B64 (214), B64 (215),
+  B64 (216), B64 (217), B64 (218), B64 (219),
+  B64 (220), B64 (221), B64 (222), B64 (223),
+  B64 (224), B64 (225), B64 (226), B64 (227),
+  B64 (228), B64 (229), B64 (230), B64 (231),
+  B64 (232), B64 (233), B64 (234), B64 (235),
+  B64 (236), B64 (237), B64 (238), B64 (239),
+  B64 (240), B64 (241), B64 (242), B64 (243),
+  B64 (244), B64 (245), B64 (246), B64 (247),
+  B64 (248), B64 (249), B64 (250), B64 (251),
+  B64 (252), B64 (253), B64 (254), B64 (255)
+};
+
+#if UCHAR_MAX == 255
+# define uchar_in_range(c) true
+#else
+# define uchar_in_range(c) ((c) <= 255)
+#endif
+
+/* Return true if CH is a character from the Base64 alphabet, and
+   false otherwise.  Note that '=' is padding and not considered to be
+   part of the alphabet.  */
+bool
+isbase64 (char ch)
+{
+  return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
+}
+
+/* Decode base64 encoded input array IN of length INLEN to output
+   array OUT that can hold *OUTLEN bytes.  Return true if decoding was
+   successful, i.e. if the input was valid base64 data, false
+   otherwise.  If *OUTLEN is too small, as many bytes as possible will
+   be written to OUT.  On return, *OUTLEN holds the length of decoded
+   bytes in OUT.  Note that as soon as any non-alphabet characters are
+   encountered, decoding is stopped and false is returned.  This means
+   that, when applicable, you must remove any line terminators that is
+   part of the data stream before calling this function.  */
+bool
+base64_decode (const char *restrict in, size_t inlen,
+              char *restrict out, size_t *outlen)
+{
+  size_t outleft = *outlen;
+
+  while (inlen >= 2)
+    {
+      if (!isbase64 (in[0]) || !isbase64 (in[1]))
+       break;
+
+      if (outleft)
+       {
+         *out++ = ((b64[to_uchar (in[0])] << 2)
+                   | (b64[to_uchar (in[1])] >> 4));
+         outleft--;
+       }
+
+      if (inlen == 2)
+       break;
+
+      if (in[2] == '=')
+       {
+         if (inlen != 4)
+           break;
+
+         if (in[3] != '=')
+           break;
+
+       }
+      else
+       {
+         if (!isbase64 (in[2]))
+           break;
+
+         if (outleft)
+           {
+             *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0)
+                       | (b64[to_uchar (in[2])] >> 2));
+             outleft--;
+           }
+
+         if (inlen == 3)
+           break;
+
+         if (in[3] == '=')
+           {
+             if (inlen != 4)
+               break;
+           }
+         else
+           {
+             if (!isbase64 (in[3]))
+               break;
+
+             if (outleft)
+               {
+                 *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
+                           | b64[to_uchar (in[3])]);
+                 outleft--;
+               }
+           }
+       }
+
+      in += 4;
+      inlen -= 4;
+    }
+
+  *outlen -= outleft;
+
+  if (inlen != 0)
+    return false;
+
+  return true;
+}
+
+/* Allocate an output buffer in *OUT, and decode the base64 encoded
+   data stored in IN of size INLEN to the *OUT buffer.  On return, the
+   size of the decoded data is stored in *OUTLEN.  OUTLEN may be NULL,
+   if the caller is not interested in the decoded length.  *OUT may be
+   NULL to indicate an out of memory error, in which case *OUTLEN
+   contains the size of the memory block needed.  The function returns
+   true on successful decoding and memory allocation errors.  (Use the
+   *OUT and *OUTLEN parameters to differentiate between successful
+   decoding and memory error.)  The function returns false if the
+   input was invalid, in which case *OUT is NULL and *OUTLEN is
+   undefined. */
+bool
+base64_decode_alloc (const char *in, size_t inlen, char **out,
+                    size_t *outlen)
+{
+  /* This may allocate a few bytes too much, depending on input,
+     but it's not worth the extra CPU time to compute the exact amount.
+     The exact amount is 3 * inlen / 4, minus 1 if the input ends
+     with "=" and minus another 1 if the input ends with "==".
+     Dividing before multiplying avoids the possibility of overflow.  */
+  size_t needlen = 3 * (inlen / 4) + 2;
+
+  *out = malloc (needlen);
+  if (!*out)
+    return true;
+
+  if (!base64_decode (in, inlen, *out, &needlen))
+    {
+      free (*out);
+      *out = NULL;
+      return false;
+    }
+
+  if (outlen)
+    *outlen = needlen;
+
+  return true;
+}
diff --git a/gnulib/base64.h b/gnulib/base64.h
new file mode 100644 (file)
index 0000000..6bb9a97
--- /dev/null
@@ -0,0 +1,45 @@
+/* base64.h -- Encode binary data using printable characters.
+   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+   Written by Simon Josefsson.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef BASE64_H
+# define BASE64_H
+
+/* Get size_t. */
+# include <stddef.h>
+
+/* Get bool. */
+# include <stdbool.h>
+
+/* This uses that the expression (n+(k-1))/k means the smallest
+   integer >= n/k, i.e., the ceiling of n/k.  */
+# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
+
+extern bool isbase64 (char ch);
+
+extern void base64_encode (const char *restrict in, size_t inlen,
+                          char *restrict out, size_t outlen);
+
+extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out);
+
+extern bool base64_decode (const char *restrict in, size_t inlen,
+                          char *restrict out, size_t *outlen);
+
+extern bool base64_decode_alloc (const char *in, size_t inlen,
+                                char **out, size_t *outlen);
+
+#endif /* BASE64_H */
diff --git a/gnulib/float+.h b/gnulib/float+.h
new file mode 100644 (file)
index 0000000..4de25a9
--- /dev/null
@@ -0,0 +1,148 @@
+/* Supplemental information about the floating-point formats.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2007.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _FLOATPLUS_H
+#define _FLOATPLUS_H
+
+#include <float.h>
+#include <limits.h>
+
+/* Number of bits in the mantissa of a floating-point number, including the
+   "hidden bit".  */
+#if FLT_RADIX == 2
+# define FLT_MANT_BIT FLT_MANT_DIG
+# define DBL_MANT_BIT DBL_MANT_DIG
+# define LDBL_MANT_BIT LDBL_MANT_DIG
+#elif FLT_RADIX == 4
+# define FLT_MANT_BIT (FLT_MANT_DIG * 2)
+# define DBL_MANT_BIT (DBL_MANT_DIG * 2)
+# define LDBL_MANT_BIT (LDBL_MANT_DIG * 2)
+#elif FLT_RADIX == 16
+# define FLT_MANT_BIT (FLT_MANT_DIG * 4)
+# define DBL_MANT_BIT (DBL_MANT_DIG * 4)
+# define LDBL_MANT_BIT (LDBL_MANT_DIG * 4)
+#endif
+
+/* Bit mask that can be used to mask the exponent, as an unsigned number.  */
+#define FLT_EXP_MASK ((FLT_MAX_EXP - FLT_MIN_EXP) | 7)
+#define DBL_EXP_MASK ((DBL_MAX_EXP - DBL_MIN_EXP) | 7)
+#define LDBL_EXP_MASK ((LDBL_MAX_EXP - LDBL_MIN_EXP) | 7)
+
+/* Number of bits used for the exponent of a floating-point number, including
+   the exponent's sign.  */
+#define FLT_EXP_BIT \
+  (FLT_EXP_MASK < 0x100 ? 8 : \
+   FLT_EXP_MASK < 0x200 ? 9 : \
+   FLT_EXP_MASK < 0x400 ? 10 : \
+   FLT_EXP_MASK < 0x800 ? 11 : \
+   FLT_EXP_MASK < 0x1000 ? 12 : \
+   FLT_EXP_MASK < 0x2000 ? 13 : \
+   FLT_EXP_MASK < 0x4000 ? 14 : \
+   FLT_EXP_MASK < 0x8000 ? 15 : \
+   FLT_EXP_MASK < 0x10000 ? 16 : \
+   FLT_EXP_MASK < 0x20000 ? 17 : \
+   FLT_EXP_MASK < 0x40000 ? 18 : \
+   FLT_EXP_MASK < 0x80000 ? 19 : \
+   FLT_EXP_MASK < 0x100000 ? 20 : \
+   FLT_EXP_MASK < 0x200000 ? 21 : \
+   FLT_EXP_MASK < 0x400000 ? 22 : \
+   FLT_EXP_MASK < 0x800000 ? 23 : \
+   FLT_EXP_MASK < 0x1000000 ? 24 : \
+   FLT_EXP_MASK < 0x2000000 ? 25 : \
+   FLT_EXP_MASK < 0x4000000 ? 26 : \
+   FLT_EXP_MASK < 0x8000000 ? 27 : \
+   FLT_EXP_MASK < 0x10000000 ? 28 : \
+   FLT_EXP_MASK < 0x20000000 ? 29 : \
+   FLT_EXP_MASK < 0x40000000 ? 30 : \
+   FLT_EXP_MASK <= 0x7fffffff ? 31 : \
+   32)
+#define DBL_EXP_BIT \
+  (DBL_EXP_MASK < 0x100 ? 8 : \
+   DBL_EXP_MASK < 0x200 ? 9 : \
+   DBL_EXP_MASK < 0x400 ? 10 : \
+   DBL_EXP_MASK < 0x800 ? 11 : \
+   DBL_EXP_MASK < 0x1000 ? 12 : \
+   DBL_EXP_MASK < 0x2000 ? 13 : \
+   DBL_EXP_MASK < 0x4000 ? 14 : \
+   DBL_EXP_MASK < 0x8000 ? 15 : \
+   DBL_EXP_MASK < 0x10000 ? 16 : \
+   DBL_EXP_MASK < 0x20000 ? 17 : \
+   DBL_EXP_MASK < 0x40000 ? 18 : \
+   DBL_EXP_MASK < 0x80000 ? 19 : \
+   DBL_EXP_MASK < 0x100000 ? 20 : \
+   DBL_EXP_MASK < 0x200000 ? 21 : \
+   DBL_EXP_MASK < 0x400000 ? 22 : \
+   DBL_EXP_MASK < 0x800000 ? 23 : \
+   DBL_EXP_MASK < 0x1000000 ? 24 : \
+   DBL_EXP_MASK < 0x2000000 ? 25 : \
+   DBL_EXP_MASK < 0x4000000 ? 26 : \
+   DBL_EXP_MASK < 0x8000000 ? 27 : \
+   DBL_EXP_MASK < 0x10000000 ? 28 : \
+   DBL_EXP_MASK < 0x20000000 ? 29 : \
+   DBL_EXP_MASK < 0x40000000 ? 30 : \
+   DBL_EXP_MASK <= 0x7fffffff ? 31 : \
+   32)
+#define LDBL_EXP_BIT \
+  (LDBL_EXP_MASK < 0x100 ? 8 : \
+   LDBL_EXP_MASK < 0x200 ? 9 : \
+   LDBL_EXP_MASK < 0x400 ? 10 : \
+   LDBL_EXP_MASK < 0x800 ? 11 : \
+   LDBL_EXP_MASK < 0x1000 ? 12 : \
+   LDBL_EXP_MASK < 0x2000 ? 13 : \
+   LDBL_EXP_MASK < 0x4000 ? 14 : \
+   LDBL_EXP_MASK < 0x8000 ? 15 : \
+   LDBL_EXP_MASK < 0x10000 ? 16 : \
+   LDBL_EXP_MASK < 0x20000 ? 17 : \
+   LDBL_EXP_MASK < 0x40000 ? 18 : \
+   LDBL_EXP_MASK < 0x80000 ? 19 : \
+   LDBL_EXP_MASK < 0x100000 ? 20 : \
+   LDBL_EXP_MASK < 0x200000 ? 21 : \
+   LDBL_EXP_MASK < 0x400000 ? 22 : \
+   LDBL_EXP_MASK < 0x800000 ? 23 : \
+   LDBL_EXP_MASK < 0x1000000 ? 24 : \
+   LDBL_EXP_MASK < 0x2000000 ? 25 : \
+   LDBL_EXP_MASK < 0x4000000 ? 26 : \
+   LDBL_EXP_MASK < 0x8000000 ? 27 : \
+   LDBL_EXP_MASK < 0x10000000 ? 28 : \
+   LDBL_EXP_MASK < 0x20000000 ? 29 : \
+   LDBL_EXP_MASK < 0x40000000 ? 30 : \
+   LDBL_EXP_MASK <= 0x7fffffff ? 31 : \
+   32)
+
+/* Number of bits used for a floating-point number: the mantissa (not
+   counting the "hidden bit", since it may or may not be explicit), the
+   exponent, and the sign.  */
+#define FLT_TOTAL_BIT ((FLT_MANT_BIT - 1) + FLT_EXP_BIT + 1)
+#define DBL_TOTAL_BIT ((DBL_MANT_BIT - 1) + DBL_EXP_BIT + 1)
+#define LDBL_TOTAL_BIT ((LDBL_MANT_BIT - 1) + LDBL_EXP_BIT + 1)
+
+/* Number of bytes used for a floating-point number.
+   This can be smaller than the 'sizeof'.  For example, on i386 systems,
+   'long double' most often have LDBL_MANT_BIT = 64, LDBL_EXP_BIT = 16, hence
+   LDBL_TOTAL_BIT = 80 bits, i.e. 10 bytes of consecutive memory, but
+   sizeof (long double) = 12 or = 16.  */
+#define SIZEOF_FLT ((FLT_TOTAL_BIT + CHAR_BIT - 1) / CHAR_BIT)
+#define SIZEOF_DBL ((DBL_TOTAL_BIT + CHAR_BIT - 1) / CHAR_BIT)
+#define SIZEOF_LDBL ((LDBL_TOTAL_BIT + CHAR_BIT - 1) / CHAR_BIT)
+
+/* Verify that SIZEOF_FLT <= sizeof (float) etc.  */
+typedef int verify_sizeof_flt[2 * (SIZEOF_FLT <= sizeof (float)) - 1];
+typedef int verify_sizeof_dbl[2 * (SIZEOF_DBL <= sizeof (double)) - 1];
+typedef int verify_sizeof_ldbl[2 * (SIZEOF_LDBL <= sizeof (long double)) - 1];
+
+#endif /* _FLOATPLUS_H */
diff --git a/gnulib/float_.h b/gnulib/float_.h
new file mode 100644 (file)
index 0000000..d61d630
--- /dev/null
@@ -0,0 +1,59 @@
+/* A correct <float.h>.
+
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _GL_FLOAT_H
+
+/* The include_next requires a split double-inclusion guard.  */
+#@INCLUDE_NEXT@ @NEXT_FLOAT_H@
+
+#ifndef _GL_FLOAT_H
+#define _GL_FLOAT_H
+
+/* 'long double' properties.  */
+#if defined __i386__ && defined __BEOS__
+/* Number of mantissa units, in base FLT_RADIX.  */
+# undef LDBL_MANT_DIG
+# define LDBL_MANT_DIG   64
+/* Number of decimal digits that is sufficient for representing a number.  */
+# undef LDBL_DIG
+# define LDBL_DIG        18
+/* x-1 where x is the smallest representable number > 1.  */
+# undef LDBL_EPSILON
+# define LDBL_EPSILON    1.0842021724855044340E-19L
+/* Minimum e such that FLT_RADIX^(e-1) is a normalized number.  */
+# undef LDBL_MIN_EXP
+# define LDBL_MIN_EXP    (-16381)
+/* Maximum e such that FLT_RADIX^(e-1) is a representable finite number.  */
+# undef LDBL_MAX_EXP
+# define LDBL_MAX_EXP    16384
+/* Minimum positive normalized number.  */
+# undef LDBL_MIN
+# define LDBL_MIN        3.3621031431120935063E-4932L
+/* Maximum representable finite number.  */
+# undef LDBL_MAX
+# define LDBL_MAX        1.1897314953572317650E+4932L
+/* Minimum e such that 10^e is in the range of normalized numbers.  */
+# undef LDBL_MIN_10_EXP
+# define LDBL_MIN_10_EXP (-4931)
+/* Maximum e such that 10^e is in the range of representable finite numbers.  */
+# undef LDBL_MAX_10_EXP
+# define LDBL_MAX_10_EXP 4932
+#endif
+
+#endif /* _GL_FLOAT_H */
+#endif /* _GL_FLOAT_H */
diff --git a/gnulib/fsusage.c b/gnulib/fsusage.c
new file mode 100644 (file)
index 0000000..337bf53
--- /dev/null
@@ -0,0 +1,264 @@
+/* fsusage.c -- return space usage of mounted file systems
+
+   Copyright (C) 1991, 1992, 1996, 1998, 1999, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <config.h>
+
+#include "fsusage.h"
+
+#include <limits.h>
+#include <sys/types.h>
+
+#if STAT_STATVFS               /* POSIX 1003.1-2001 (and later) with XSI */
+# include <sys/statvfs.h>
+#else
+/* Don't include backward-compatibility files unless they're needed.
+   Eventually we'd like to remove all this cruft.  */
+# include <fcntl.h>
+# include <unistd.h>
+# include <sys/stat.h>
+# if HAVE_SYS_PARAM_H
+#  include <sys/param.h>
+# endif
+# if HAVE_SYS_MOUNT_H
+#  include <sys/mount.h>
+# endif
+# if HAVE_SYS_VFS_H
+#  include <sys/vfs.h>
+# endif
+# if HAVE_SYS_FS_S5PARAM_H     /* Fujitsu UXP/V */
+#  include <sys/fs/s5param.h>
+# endif
+# if defined HAVE_SYS_FILSYS_H && !defined _CRAY
+#  include <sys/filsys.h>      /* SVR2 */
+# endif
+# if HAVE_SYS_STATFS_H
+#  include <sys/statfs.h>
+# endif
+# if HAVE_DUSTAT_H             /* AIX PS/2 */
+#  include <sys/dustat.h>
+# endif
+# include "full-read.h"
+#endif
+
+/* The results of open() in this file are not used with fchdir,
+   therefore save some unnecessary work in fchdir.c.  */
+#undef open
+#undef close
+
+/* Many space usage primitives use all 1 bits to denote a value that is
+   not applicable or unknown.  Propagate this information by returning
+   a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
+   is unsigned and narrower than uintmax_t.  */
+#define PROPAGATE_ALL_ONES(x) \
+  ((sizeof (x) < sizeof (uintmax_t) \
+    && (~ (x) == (sizeof (x) < sizeof (int) \
+                 ? - (1 << (sizeof (x) * CHAR_BIT)) \
+                 : 0))) \
+   ? UINTMAX_MAX : (uintmax_t) (x))
+
+/* Extract the top bit of X as an uintmax_t value.  */
+#define EXTRACT_TOP_BIT(x) ((x) \
+                           & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
+
+/* If a value is negative, many space usage primitives store it into an
+   integer variable by assignment, even if the variable's type is unsigned.
+   So, if a space usage variable X's top bit is set, convert X to the
+   uintmax_t value V such that (- (uintmax_t) V) is the negative of
+   the original value.  If X's top bit is clear, just yield X.
+   Use PROPAGATE_TOP_BIT if the original value might be negative;
+   otherwise, use PROPAGATE_ALL_ONES.  */
+#define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
+
+/* Fill in the fields of FSP with information about space usage for
+   the file system on which FILE resides.
+   DISK is the device on which FILE is mounted, for space-getting
+   methods that need to know it.
+   Return 0 if successful, -1 if not.  When returning -1, ensure that
+   ERRNO is either a system error value, or zero if DISK is NULL
+   on a system that requires a non-NULL value.  */
+int
+get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
+{
+#if defined STAT_STATVFS               /* POSIX */
+
+  struct statvfs fsd;
+
+  if (statvfs (file, &fsd) < 0)
+    return -1;
+
+  /* f_frsize isn't guaranteed to be supported.  */
+  fsp->fsu_blocksize = (fsd.f_frsize
+                       ? PROPAGATE_ALL_ONES (fsd.f_frsize)
+                       : PROPAGATE_ALL_ONES (fsd.f_bsize));
+
+#elif defined STAT_STATFS2_FS_DATA     /* Ultrix */
+
+  struct fs_data fsd;
+
+  if (statfs (file, &fsd) != 1)
+    return -1;
+
+  fsp->fsu_blocksize = 1024;
+  fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
+  fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
+  fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
+  fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
+  fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
+  fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
+
+#elif defined STAT_READ_FILSYS         /* SVR2 */
+# ifndef SUPERBOFF
+#  define SUPERBOFF (SUPERB * 512)
+# endif
+
+  struct filsys fsd;
+  int fd;
+
+  if (! disk)
+    {
+      errno = 0;
+      return -1;
+    }
+
+  fd = open (disk, O_RDONLY);
+  if (fd < 0)
+    return -1;
+  lseek (fd, (off_t) SUPERBOFF, 0);
+  if (full_read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd)
+    {
+      close (fd);
+      return -1;
+    }
+  close (fd);
+
+  fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
+  fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
+  fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
+  fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
+  fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
+  fsp->fsu_files = (fsd.s_isize == -1
+                   ? UINTMAX_MAX
+                   : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
+  fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
+
+#elif defined STAT_STATFS3_OSF1
+
+  struct statfs fsd;
+
+  if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
+    return -1;
+
+  fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
+
+#elif defined STAT_STATFS2_BSIZE       /* 4.3BSD, SunOS 4, HP-UX, AIX */
+
+  struct statfs fsd;
+
+  if (statfs (file, &fsd) < 0)
+    return -1;
+
+  fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
+
+# ifdef STATFS_TRUNCATES_BLOCK_COUNTS
+
+  /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
+     struct statfs are truncated to 2GB.  These conditions detect that
+     truncation, presumably without botching the 4.1.1 case, in which
+     the values are not truncated.  The correct counts are stored in
+     undocumented spare fields.  */
+  if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
+    {
+      fsd.f_blocks = fsd.f_spare[0];
+      fsd.f_bfree = fsd.f_spare[1];
+      fsd.f_bavail = fsd.f_spare[2];
+    }
+# endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
+
+#elif defined STAT_STATFS2_FSIZE       /* 4.4BSD */
+
+  struct statfs fsd;
+
+  if (statfs (file, &fsd) < 0)
+    return -1;
+
+  fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
+
+#elif defined STAT_STATFS4             /* SVR3, Dynix, Irix, AIX */
+
+# if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN
+#  define f_bavail f_bfree
+# endif
+
+  struct statfs fsd;
+
+  if (statfs (file, &fsd, sizeof fsd, 0) < 0)
+    return -1;
+
+  /* Empirically, the block counts on most SVR3 and SVR3-derived
+     systems seem to always be in terms of 512-byte blocks,
+     no matter what value f_bsize has.  */
+# if _AIX || defined _CRAY
+   fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
+# else
+   fsp->fsu_blocksize = 512;
+# endif
+
+#endif
+
+#if (defined STAT_STATVFS \
+     || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS))
+
+  fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
+  fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
+  fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
+  fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
+  fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
+  fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
+
+#endif
+
+  return 0;
+}
+
+#if defined _AIX && defined _I386
+/* AIX PS/2 does not supply statfs.  */
+
+int
+statfs (char *file, struct statfs *fsb)
+{
+  struct stat stats;
+  struct dustat fsd;
+
+  if (stat (file, &stats) != 0)
+    return -1;
+  if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
+    return -1;
+  fsb->f_type   = 0;
+  fsb->f_bsize  = fsd.du_bsize;
+  fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
+  fsb->f_bfree  = fsd.du_tfree;
+  fsb->f_bavail = fsd.du_tfree;
+  fsb->f_files  = (fsd.du_isize - 2) * fsd.du_inopb;
+  fsb->f_ffree  = fsd.du_tinode;
+  fsb->f_fsid.val[0] = fsd.du_site;
+  fsb->f_fsid.val[1] = fsd.du_pckno;
+  return 0;
+}
+
+#endif /* _AIX && _I386 */
diff --git a/gnulib/fsusage.h b/gnulib/fsusage.h
new file mode 100644 (file)
index 0000000..7fa9f8d
--- /dev/null
@@ -0,0 +1,41 @@
+/* fsusage.h -- declarations for file system space usage info
+
+   Copyright (C) 1991, 1992, 1997, 2003, 2004, 2005, 2006 Free Software
+   Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Space usage statistics for a file system.  Blocks are 512-byte. */
+
+#if !defined FSUSAGE_H_
+# define FSUSAGE_H_
+
+# include <stdint.h>
+# include <stdbool.h>
+
+struct fs_usage
+{
+  uintmax_t fsu_blocksize;     /* Size of a block.  */
+  uintmax_t fsu_blocks;                /* Total blocks. */
+  uintmax_t fsu_bfree;         /* Free blocks available to superuser. */
+  uintmax_t fsu_bavail;                /* Free blocks available to non-superuser. */
+  bool fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0.  */
+  uintmax_t fsu_files;         /* Total file nodes. */
+  uintmax_t fsu_ffree;         /* Free file nodes. */
+};
+
+int get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp);
+
+#endif
diff --git a/gnulib/full-read.c b/gnulib/full-read.c
new file mode 100644 (file)
index 0000000..8c3472a
--- /dev/null
@@ -0,0 +1,19 @@
+/* An interface to read that retries after partial reads and interrupts.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#define FULL_READ
+#include "full-write.c"
diff --git a/gnulib/full-read.h b/gnulib/full-read.h
new file mode 100644 (file)
index 0000000..05d83a7
--- /dev/null
@@ -0,0 +1,24 @@
+/* An interface to read() that reads all it is asked to read.
+
+   Copyright (C) 2002 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, read to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <stddef.h>
+
+/* Read COUNT bytes at BUF to descriptor FD, retrying if interrupted
+   or if partial reads occur.  Return the number of bytes successfully
+   read, setting errno if that is less than COUNT.  errno = 0 means EOF.  */
+extern size_t full_read (int fd, void *buf, size_t count);
diff --git a/gnulib/full-write.c b/gnulib/full-write.c
new file mode 100644 (file)
index 0000000..cc16872
--- /dev/null
@@ -0,0 +1,81 @@
+/* An interface to read and write that retries (if necessary) until complete.
+
+   Copyright (C) 1993, 1994, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <config.h>
+
+/* Specification.  */
+#ifdef FULL_READ
+# include "full-read.h"
+#else
+# include "full-write.h"
+#endif
+
+#include <errno.h>
+
+#ifdef FULL_READ
+# include "safe-read.h"
+# define safe_rw safe_read
+# define full_rw full_read
+# undef const
+# define const /* empty */
+#else
+# include "safe-write.h"
+# define safe_rw safe_write
+# define full_rw full_write
+#endif
+
+#ifdef FULL_READ
+/* Set errno to zero upon EOF.  */
+# define ZERO_BYTE_TRANSFER_ERRNO 0
+#else
+/* Some buggy drivers return 0 when one tries to write beyond
+   a device's end.  (Example: Linux 1.2.13 on /dev/fd0.)
+   Set errno to ENOSPC so they get a sensible diagnostic.  */
+# define ZERO_BYTE_TRANSFER_ERRNO ENOSPC
+#endif
+
+/* Write(read) COUNT bytes at BUF to(from) descriptor FD, retrying if
+   interrupted or if a partial write(read) occurs.  Return the number
+   of bytes transferred.
+   When writing, set errno if fewer than COUNT bytes are written.
+   When reading, if fewer than COUNT bytes are read, you must examine
+   errno to distinguish failure from EOF (errno == 0).  */
+size_t
+full_rw (int fd, const void *buf, size_t count)
+{
+  size_t total = 0;
+  const char *ptr = (const char *) buf;
+
+  while (count > 0)
+    {
+      size_t n_rw = safe_rw (fd, ptr, count);
+      if (n_rw == (size_t) -1)
+       break;
+      if (n_rw == 0)
+       {
+         errno = ZERO_BYTE_TRANSFER_ERRNO;
+         break;
+       }
+      total += n_rw;
+      ptr += n_rw;
+      count -= n_rw;
+    }
+
+  return total;
+}
diff --git a/gnulib/full-write.h b/gnulib/full-write.h
new file mode 100644 (file)
index 0000000..d20d2fe
--- /dev/null
@@ -0,0 +1,35 @@
+/* An interface to write() that writes all it is asked to write.
+
+   Copyright (C) 2002-2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <stddef.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Write COUNT bytes at BUF to descriptor FD, retrying if interrupted
+   or if partial writes occur.  Return the number of bytes successfully
+   written, setting errno if that is less than COUNT.  */
+extern size_t full_write (int fd, const void *buf, size_t count);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/gnulib/gettimeofday.c b/gnulib/gettimeofday.c
new file mode 100644 (file)
index 0000000..bd5576c
--- /dev/null
@@ -0,0 +1,142 @@
+/* Provide gettimeofday for systems that don't have it or for which it's broken.
+
+   Copyright (C) 2001, 2002, 2003, 2005, 2006, 2007 Free Software
+   Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* written by Jim Meyering */
+
+#include <config.h>
+
+/* Specification.  */
+#include <sys/time.h>
+
+#include <time.h>
+
+#if HAVE_SYS_TIMEB_H
+# include <sys/timeb.h>
+#endif
+
+#if GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME
+
+/* Work around the bug in some systems whereby gettimeofday clobbers
+   the static buffer that localtime uses for its return value.  The
+   gettimeofday function from Mac OS X 10.0.4 (i.e., Darwin 1.3.7) has
+   this problem.  The tzset replacement is necessary for at least
+   Solaris 2.5, 2.5.1, and 2.6.  */
+
+static struct tm tm_zero_buffer;
+static struct tm *localtime_buffer_addr = &tm_zero_buffer;
+
+/* This is a wrapper for localtime.  It is used only on systems for which
+   gettimeofday clobbers the static buffer used for localtime's result.
+
+   On the first call, record the address of the static buffer that
+   localtime uses for its result.  */
+
+struct tm *
+localtime (time_t const *timep)
+{
+#undef localtime
+  extern struct tm *localtime (time_t const *);
+  struct tm *tm = localtime (timep);
+
+  if (localtime_buffer_addr == &tm_zero_buffer)
+    localtime_buffer_addr = tm;
+
+  return tm;
+}
+
+/* Same as above, since gmtime and localtime use the same buffer.  */
+struct tm *
+gmtime (time_t const *timep)
+{
+#undef gmtime
+  extern struct tm *gmtime (time_t const *);
+  struct tm *tm = gmtime (timep);
+
+  if (localtime_buffer_addr == &tm_zero_buffer)
+    localtime_buffer_addr = tm;
+
+  return tm;
+}
+
+#endif /* GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME */
+
+#if TZSET_CLOBBERS_LOCALTIME
+/* This is a wrapper for tzset, for systems on which tzset may clobber
+   the static buffer used for localtime's result.  */
+void
+tzset (void)
+{
+#undef tzset
+  extern void tzset (void);
+
+  /* Save and restore the contents of the buffer used for localtime's
+     result around the call to tzset.  */
+  struct tm save = *localtime_buffer_addr;
+  tzset ();
+  *localtime_buffer_addr = save;
+}
+#endif
+
+/* This is a wrapper for gettimeofday.  It is used only on systems
+   that lack this function, or whose implementation of this function
+   causes problems.  */
+
+int
+rpl_gettimeofday (struct timeval *restrict tv, void *restrict tz)
+{
+#undef gettimeofday
+#if HAVE_GETTIMEOFDAY
+# if GETTIMEOFDAY_CLOBBERS_LOCALTIME
+  /* Save and restore the contents of the buffer used for localtime's
+     result around the call to gettimeofday.  */
+  struct tm save = *localtime_buffer_addr;
+# endif
+
+  int result = gettimeofday (tv, tz);
+
+# if GETTIMEOFDAY_CLOBBERS_LOCALTIME
+  *localtime_buffer_addr = save;
+# endif
+
+  return result;
+
+#else
+
+# if HAVE__FTIME
+
+  struct _timeb timebuf;
+  _ftime (&timebuf);
+  tv->tv_sec = timebuf.time;
+  tv->tv_usec = timebuf.millitm * 1000;
+
+# else
+
+#  if !defined OK_TO_USE_1S_CLOCK
+#   error "Only 1-second nominal clock resolution found.  Is that intended?" \
+          "If so, compile with the -DOK_TO_USE_1S_CLOCK option."
+#  endif
+  tv->tv_sec = time (NULL);
+  tv->tv_usec = 0;
+
+# endif
+
+  return 0;
+
+#endif
+}
diff --git a/gnulib/malloc.c b/gnulib/malloc.c
new file mode 100644 (file)
index 0000000..eba131d
--- /dev/null
@@ -0,0 +1,57 @@
+/* malloc() function that is glibc compatible.
+
+   Copyright (C) 1997, 1998, 2006, 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* written by Jim Meyering and Bruno Haible */
+
+#include <config.h>
+/* Only the AC_FUNC_MALLOC macro defines 'malloc' already in config.h.  */
+#ifdef malloc
+# define NEED_MALLOC_GNU
+# undef malloc
+#endif
+
+/* Specification.  */
+#include <stdlib.h>
+
+#include <errno.h>
+
+/* Call the system's malloc below.  */
+#undef malloc
+
+/* Allocate an N-byte block of memory from the heap.
+   If N is zero, allocate a 1-byte block.  */
+
+void *
+rpl_malloc (size_t n)
+{
+  void *result;
+
+#ifdef NEED_MALLOC_GNU
+  if (n == 0)
+    n = 1;
+#endif
+
+  result = malloc (n);
+
+#if !HAVE_MALLOC_POSIX
+  if (result == NULL)
+    errno = ENOMEM;
+#endif
+
+  return result;
+}
diff --git a/gnulib/mkdtemp.c b/gnulib/mkdtemp.c
new file mode 100644 (file)
index 0000000..36b6c75
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 1999, 2001-2003, 2006-2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Extracted from misc/mkdtemp.c.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdlib.h>
+
+#include "tempname.h"
+
+/* Generate a unique temporary directory from TEMPLATE.
+   The last six characters of TEMPLATE must be "XXXXXX";
+   they are replaced with a string that makes the filename unique.
+   The directory is created, mode 700, and its name is returned.
+   (This function comes from OpenBSD.) */
+char *
+mkdtemp (char *template)
+{
+  if (gen_tempname (template, GT_DIR))
+    return NULL;
+  else
+    return template;
+}
diff --git a/gnulib/netinet_in_.h b/gnulib/netinet_in_.h
new file mode 100644 (file)
index 0000000..aa00e45
--- /dev/null
@@ -0,0 +1,43 @@
+/* Substitute for <netinet/in.h>.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _GL_NETINET_IN_H
+
+#if @HAVE_NETINET_IN_H@
+
+/* On many platforms, <netinet/in.h> assumes prior inclusion of
+   <sys/types.h>.  */
+# include <sys/types.h>
+
+/* The include_next requires a split double-inclusion guard.  */
+# @INCLUDE_NEXT@ @NEXT_NETINET_IN_H@
+
+#endif
+
+#ifndef _GL_NETINET_IN_H
+#define _GL_NETINET_IN_H
+
+#if !@HAVE_NETINET_IN_H@
+
+/* A platform that lacks <netinet/in.h>.  */
+
+# include <sys/socket.h>
+
+#endif
+
+#endif /* _GL_NETINET_IN_H */
+#endif /* _GL_NETINET_IN_H */
diff --git a/gnulib/physmem.c b/gnulib/physmem.c
new file mode 100644 (file)
index 0000000..844817b
--- /dev/null
@@ -0,0 +1,305 @@
+/* Calculate the size of physical memory.
+
+   Copyright (C) 2000, 2001, 2003, 2005, 2006 Free Software
+   Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Paul Eggert.  */
+
+#include <config.h>
+
+#include "physmem.h"
+
+#include <unistd.h>
+
+#if HAVE_SYS_PSTAT_H
+# include <sys/pstat.h>
+#endif
+
+#if HAVE_SYS_SYSMP_H
+# include <sys/sysmp.h>
+#endif
+
+#if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H
+# include <sys/sysinfo.h>
+# include <machine/hal_sysinfo.h>
+#endif
+
+#if HAVE_SYS_TABLE_H
+# include <sys/table.h>
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#if HAVE_SYS_SYSCTL_H
+# include <sys/sysctl.h>
+#endif
+
+#if HAVE_SYS_SYSTEMCFG_H
+# include <sys/systemcfg.h>
+#endif
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+/*  MEMORYSTATUSEX is missing from older windows headers, so define
+    a local replacement.  */
+typedef struct
+{
+  DWORD dwLength;
+  DWORD dwMemoryLoad;
+  DWORDLONG ullTotalPhys;
+  DWORDLONG ullAvailPhys;
+  DWORDLONG ullTotalPageFile;
+  DWORDLONG ullAvailPageFile;
+  DWORDLONG ullTotalVirtual;
+  DWORDLONG ullAvailVirtual;
+  DWORDLONG ullAvailExtendedVirtual;
+} lMEMORYSTATUSEX;
+typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
+#endif
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+/* Return the total amount of physical memory.  */
+double
+physmem_total (void)
+{
+#if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE
+  { /* This works on linux-gnu, solaris2 and cygwin.  */
+    double pages = sysconf (_SC_PHYS_PAGES);
+    double pagesize = sysconf (_SC_PAGESIZE);
+    if (0 <= pages && 0 <= pagesize)
+      return pages * pagesize;
+  }
+#endif
+
+#if HAVE_PSTAT_GETSTATIC
+  { /* This works on hpux11.  */
+    struct pst_static pss;
+    if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0))
+      {
+       double pages = pss.physical_memory;
+       double pagesize = pss.page_size;
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE
+  { /* This works on irix6. */
+    struct rminfo realmem;
+    if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0)
+      {
+       double pagesize = sysconf (_SC_PAGESIZE);
+       double pages = realmem.physmem;
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_GETSYSINFO && defined GSI_PHYSMEM
+  { /* This works on Tru64 UNIX V4/5.  */
+    int physmem;
+
+    if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem),
+                   NULL, NULL, NULL) == 1)
+      {
+       double kbytes = physmem;
+
+       if (0 <= kbytes)
+         return kbytes * 1024.0;
+      }
+  }
+#endif
+
+#if HAVE_SYSCTL && defined HW_PHYSMEM
+  { /* This works on *bsd and darwin.  */
+    unsigned int physmem;
+    size_t len = sizeof physmem;
+    static int mib[2] = { CTL_HW, HW_PHYSMEM };
+
+    if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0
+       && len == sizeof (physmem))
+      return (double) physmem;
+  }
+#endif
+
+#if HAVE__SYSTEM_CONFIGURATION
+  /* This works on AIX.  */
+  return _system_configuration.physmem;
+#endif
+
+#if defined _WIN32
+  { /* this works on windows */
+    PFN_MS_EX pfnex;
+    HMODULE h = GetModuleHandle ("kernel32.dll");
+
+    if (!h)
+      return 0.0;
+
+    /*  Use GlobalMemoryStatusEx if available.  */
+    if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
+      {
+       lMEMORYSTATUSEX lms_ex;
+       lms_ex.dwLength = sizeof lms_ex;
+       if (!pfnex (&lms_ex))
+         return 0.0;
+       return (double) lms_ex.ullTotalPhys;
+      }
+
+    /*  Fall back to GlobalMemoryStatus which is always available.
+        but returns wrong results for physical memory > 4GB.  */
+    else
+      {
+       MEMORYSTATUS ms;
+       GlobalMemoryStatus (&ms);
+       return (double) ms.dwTotalPhys;
+      }
+  }
+#endif
+
+  /* Guess 64 MB.  It's probably an older host, so guess small.  */
+  return 64 * 1024 * 1024;
+}
+
+/* Return the amount of physical memory available.  */
+double
+physmem_available (void)
+{
+#if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE
+  { /* This works on linux-gnu, solaris2 and cygwin.  */
+    double pages = sysconf (_SC_AVPHYS_PAGES);
+    double pagesize = sysconf (_SC_PAGESIZE);
+    if (0 <= pages && 0 <= pagesize)
+      return pages * pagesize;
+  }
+#endif
+
+#if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC
+  { /* This works on hpux11.  */
+    struct pst_static pss;
+    struct pst_dynamic psd;
+    if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)
+       && 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0))
+      {
+       double pages = psd.psd_free;
+       double pagesize = pss.page_size;
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE
+  { /* This works on irix6. */
+    struct rminfo realmem;
+    if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0)
+      {
+       double pagesize = sysconf (_SC_PAGESIZE);
+       double pages = realmem.availrmem;
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_TABLE && defined TBL_VMSTATS
+  { /* This works on Tru64 UNIX V4/5.  */
+    struct tbl_vmstats vmstats;
+
+    if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1)
+      {
+       double pages = vmstats.free_count;
+       double pagesize = vmstats.pagesize;
+
+       if (0 <= pages && 0 <= pagesize)
+         return pages * pagesize;
+      }
+  }
+#endif
+
+#if HAVE_SYSCTL && defined HW_USERMEM
+  { /* This works on *bsd and darwin.  */
+    unsigned int usermem;
+    size_t len = sizeof usermem;
+    static int mib[2] = { CTL_HW, HW_USERMEM };
+
+    if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0
+       && len == sizeof (usermem))
+      return (double) usermem;
+  }
+#endif
+
+#if defined _WIN32
+  { /* this works on windows */
+    PFN_MS_EX pfnex;
+    HMODULE h = GetModuleHandle ("kernel32.dll");
+
+    if (!h)
+      return 0.0;
+
+    /*  Use GlobalMemoryStatusEx if available.  */
+    if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx")))
+      {
+       lMEMORYSTATUSEX lms_ex;
+       lms_ex.dwLength = sizeof lms_ex;
+       if (!pfnex (&lms_ex))
+         return 0.0;
+       return (double) lms_ex.ullAvailPhys;
+      }
+
+    /*  Fall back to GlobalMemoryStatus which is always available.
+        but returns wrong results for physical memory > 4GB  */
+    else
+      {
+       MEMORYSTATUS ms;
+       GlobalMemoryStatus (&ms);
+       return (double) ms.dwAvailPhys;
+      }
+  }
+#endif
+
+  /* Guess 25% of physical memory.  */
+  return physmem_total () / 4;
+}
+
+
+#if DEBUG
+
+# include <stdio.h>
+# include <stdlib.h>
+
+int
+main (void)
+{
+  printf ("%12.f %12.f\n", physmem_total (), physmem_available ());
+  exit (0);
+}
+
+#endif /* DEBUG */
+
+/*
+Local Variables:
+compile-command: "gcc -DDEBUG -g -O -Wall -W physmem.c"
+End:
+*/
diff --git a/gnulib/physmem.h b/gnulib/physmem.h
new file mode 100644 (file)
index 0000000..931aede
--- /dev/null
@@ -0,0 +1,27 @@
+/* Calculate the size of physical memory.
+
+   Copyright (C) 2000, 2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Paul Eggert.  */
+
+#ifndef PHYSMEM_H_
+# define PHYSMEM_H_ 1
+
+double physmem_total (void);
+double physmem_available (void);
+
+#endif /* PHYSMEM_H_ */
diff --git a/gnulib/regenerate/no-error.patch.BACKUP.7723.patch b/gnulib/regenerate/no-error.patch.BACKUP.7723.patch
new file mode 100644 (file)
index 0000000..6dcbd67
--- /dev/null
@@ -0,0 +1,18 @@
+Index: gnulib/Makefile.am
+===================================================================
+--- gnulib/Makefile.am (revision 5691)
++++ gnulib/Makefile.am (working copy)
+@@ -26,6 +26,9 @@
+ MAINTAINERCLEANFILES =
+ AM_CPPFLAGS =
++if GCC_COMPILER
+<<<<<<< HEAD:gnulib/regenerate/no-error.patch
++  AM_CFLAGS += -Wno-error
+=======
++  AM_CFLAGS = -Wno-error -Wno-sign-compare
+>>>>>>> upstream:gnulib/regenerate/no-error.patch
++endif
+ noinst_LTLIBRARIES += libgnu.la
diff --git a/gnulib/regenerate/no-error.patch.LOCAL.7723.patch b/gnulib/regenerate/no-error.patch.LOCAL.7723.patch
new file mode 100644 (file)
index 0000000..411d948
--- /dev/null
@@ -0,0 +1,14 @@
+Index: gnulib/Makefile.am
+===================================================================
+--- gnulib/Makefile.am (revision 5691)
++++ gnulib/Makefile.am (working copy)
+@@ -26,6 +26,9 @@
+ MAINTAINERCLEANFILES =
+ AM_CPPFLAGS =
++if GCC_COMPILER
++  AM_CFLAGS += -Wno-error
++endif
+ noinst_LTLIBRARIES += libgnu.la
diff --git a/gnulib/regenerate/no-error.patch.REMOTE.7723.patch b/gnulib/regenerate/no-error.patch.REMOTE.7723.patch
new file mode 100644 (file)
index 0000000..a12e7d2
--- /dev/null
@@ -0,0 +1,14 @@
+Index: gnulib/Makefile.am
+===================================================================
+--- gnulib/Makefile.am (revision 5691)
++++ gnulib/Makefile.am (working copy)
+@@ -26,6 +26,9 @@
+ MAINTAINERCLEANFILES =
+ AM_CPPFLAGS =
++if GCC_COMPILER
++  AM_CFLAGS = -Wno-error -Wno-sign-compare
++endif
+ noinst_LTLIBRARIES += libgnu.la
diff --git a/gnulib/safe-read.c b/gnulib/safe-read.c
new file mode 100644 (file)
index 0000000..b7bf1d5
--- /dev/null
@@ -0,0 +1,78 @@
+/* An interface to read and write that retries after interrupts.
+
+   Copyright (C) 1993, 1994, 1998, 2002, 2003, 2004, 2005, 2006 Free
+   Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <config.h>
+
+/* Specification.  */
+#ifdef SAFE_WRITE
+# include "safe-write.h"
+#else
+# include "safe-read.h"
+#endif
+
+/* Get ssize_t.  */
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+#ifdef EINTR
+# define IS_EINTR(x) ((x) == EINTR)
+#else
+# define IS_EINTR(x) 0
+#endif
+
+#include <limits.h>
+
+#ifdef SAFE_WRITE
+# define safe_rw safe_write
+# define rw write
+#else
+# define safe_rw safe_read
+# define rw read
+# undef const
+# define const /* empty */
+#endif
+
+/* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
+   interrupted.  Return the actual number of bytes read(written), zero for EOF,
+   or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error.  */
+size_t
+safe_rw (int fd, void const *buf, size_t count)
+{
+  /* Work around a bug in Tru64 5.1.  Attempting to read more than
+     INT_MAX bytes fails with errno == EINVAL.  See
+     <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
+     When decreasing COUNT, keep it block-aligned.  */
+  enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };
+
+  for (;;)
+    {
+      ssize_t result = rw (fd, buf, count);
+
+      if (0 <= result)
+       return result;
+      else if (IS_EINTR (errno))
+       continue;
+      else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)
+       count = BUGGY_READ_MAXIMUM;
+      else
+       return result;
+    }
+}
diff --git a/gnulib/safe-read.h b/gnulib/safe-read.h
new file mode 100644 (file)
index 0000000..3451955
--- /dev/null
@@ -0,0 +1,35 @@
+/* An interface to read() that retries after interrupts.
+   Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SAFE_READ_ERROR ((size_t) -1)
+
+/* Read up to COUNT bytes at BUF from descriptor FD, retrying if interrupted.
+   Return the actual number of bytes read, zero for EOF, or SAFE_READ_ERROR
+   upon error.  */
+extern size_t safe_read (int fd, void *buf, size_t count);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/gnulib/safe-write.c b/gnulib/safe-write.c
new file mode 100644 (file)
index 0000000..4c375a6
--- /dev/null
@@ -0,0 +1,19 @@
+/* An interface to write that retries after interrupts.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#define SAFE_WRITE
+#include "safe-read.c"
diff --git a/gnulib/safe-write.h b/gnulib/safe-write.h
new file mode 100644 (file)
index 0000000..c194636
--- /dev/null
@@ -0,0 +1,25 @@
+/* An interface to write() that retries after interrupts.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <stddef.h>
+
+#define SAFE_WRITE_ERROR ((size_t) -1)
+
+/* Write up to COUNT bytes at BUF to descriptor FD, retrying if interrupted.
+   Return the actual number of bytes written, zero for EOF, or SAFE_WRITE_ERROR
+   upon error.  */
+extern size_t safe_write (int fd, const void *buf, size_t count);
diff --git a/gnulib/stdint_.h b/gnulib/stdint_.h
new file mode 100644 (file)
index 0000000..121118c
--- /dev/null
@@ -0,0 +1,508 @@
+/* Copyright (C) 2001-2002, 2004-2007 Free Software Foundation, Inc.
+   Written by Paul Eggert, Bruno Haible, Sam Steingold, Peter Burwood.
+   This file is part of gnulib.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/*
+ * ISO C 99 <stdint.h> for platforms that lack it.
+ * <http://www.opengroup.org/susv3xbd/stdint.h.html>
+ */
+
+#ifndef _GL_STDINT_H
+
+/* Get those types that are already defined in other system include
+   files, so that we can "#define int8_t signed char" below without
+   worrying about a later system include file containing a "typedef
+   signed char int8_t;" that will get messed up by our macro.  Our
+   macros should all be consistent with the system versions, except
+   for the "fast" types and macros, which we recommend against using
+   in public interfaces due to compiler differences.  */
+
+#if @HAVE_STDINT_H@
+# if defined __sgi && ! defined __c99
+   /* Bypass IRIX's <stdint.h> if in C89 mode, since it merely annoys users
+      with "This header file is to be used only for c99 mode compilations"
+      diagnostics.  */
+#  define __STDINT_H__
+# endif
+  /* Other systems may have an incomplete or buggy <stdint.h>.
+     Include it before <inttypes.h>, since any "#include <stdint.h>"
+     in <inttypes.h> would reinclude us, skipping our contents because
+     _GL_STDINT_H is defined.
+     The include_next requires a split double-inclusion guard.  */
+# @INCLUDE_NEXT@ @NEXT_STDINT_H@
+#endif
+
+#if ! defined _GL_STDINT_H && ! defined _GL_JUST_INCLUDE_SYSTEM_STDINT_H
+#define _GL_STDINT_H
+
+/* <sys/types.h> defines some of the stdint.h types as well, on glibc,
+   IRIX 6.5, and OpenBSD 3.8 (via <machine/types.h>).
+   AIX 5.2 <sys/types.h> isn't needed and causes troubles.
+   MacOS X 10.4.6 <sys/types.h> includes <stdint.h> (which is us), but
+   relies on the system <stdint.h> definitions, so include
+   <sys/types.h> after @NEXT_STDINT_H@.  */
+#if @HAVE_SYS_TYPES_H@ && ! defined _AIX
+# include <sys/types.h>
+#endif
+
+/* Get LONG_MIN, LONG_MAX, ULONG_MAX.  */
+#include <limits.h>
+
+#if @HAVE_INTTYPES_H@
+  /* In OpenBSD 3.8, <inttypes.h> includes <machine/types.h>, which defines
+     int{8,16,32,64}_t, uint{8,16,32,64}_t and __BIT_TYPES_DEFINED__.
+     <inttypes.h> also defines intptr_t and uintptr_t.  */
+# define _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H
+# include <inttypes.h>
+# undef _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H
+#elif @HAVE_SYS_INTTYPES_H@
+  /* Solaris 7 <sys/inttypes.h> has the types except the *_fast*_t types, and
+     the macros except for *_FAST*_*, INTPTR_MIN, PTRDIFF_MIN, PTRDIFF_MAX.  */
+# include <sys/inttypes.h>
+#endif
+
+#if @HAVE_SYS_BITYPES_H@ && ! defined __BIT_TYPES_DEFINED__
+  /* Linux libc4 >= 4.6.7 and libc5 have a <sys/bitypes.h> that defines
+     int{8,16,32,64}_t and __BIT_TYPES_DEFINED__.  In libc5 >= 5.2.2 it is
+     included by <sys/types.h>.  */
+# include <sys/bitypes.h>
+#endif
+
+#if ! defined __cplusplus || defined __STDC_CONSTANT_MACROS
+
+/* Get WCHAR_MIN, WCHAR_MAX.  */
+# if ! (defined WCHAR_MIN && defined WCHAR_MAX)
+#  include <wchar.h>
+# endif
+
+#endif
+
+/* Minimum and maximum values for a integer type under the usual assumption.
+   Return an unspecified value if BITS == 0, adding a check to pacify
+   picky compilers.  */
+
+#define _STDINT_MIN(signed, bits, zero) \
+  ((signed) ? (- ((zero) + 1) << ((bits) ? (bits) - 1 : 0)) : (zero))
+
+#define _STDINT_MAX(signed, bits, zero) \
+  ((signed) \
+   ? ~ _STDINT_MIN (signed, bits, zero) \
+   : ((((zero) + 1) << ((bits) ? (bits) - 1 : 0)) - 1) * 2 + 1)
+
+/* 7.18.1.1. Exact-width integer types */
+
+/* Here we assume a standard architecture where the hardware integer
+   types have 8, 16, 32, optionally 64 bits.  */
+
+#undef int8_t
+#undef uint8_t
+#define int8_t signed char
+#define uint8_t unsigned char
+
+#undef int16_t
+#undef uint16_t
+#define int16_t short int
+#define uint16_t unsigned short int
+
+#undef int32_t
+#undef uint32_t
+#define int32_t int
+#define uint32_t unsigned int
+
+/* Do not undefine int64_t if gnulib is not being used with 64-bit
+   types, since otherwise it breaks platforms like Tandem/NSK.  */
+#if LONG_MAX >> 31 >> 31 == 1
+# undef int64_t
+# define int64_t long int
+# define GL_INT64_T
+#elif defined _MSC_VER
+# undef int64_t
+# define int64_t __int64
+# define GL_INT64_T
+#elif @HAVE_LONG_LONG_INT@
+# undef int64_t
+# define int64_t long long int
+# define GL_INT64_T
+#endif
+
+#if ULONG_MAX >> 31 >> 31 >> 1 == 1
+# undef uint64_t
+# define uint64_t unsigned long int
+# define GL_UINT64_T
+#elif defined _MSC_VER
+# undef uint64_t
+# define uint64_t unsigned __int64
+# define GL_UINT64_T
+#elif @HAVE_UNSIGNED_LONG_LONG_INT@
+# undef uint64_t
+# define uint64_t unsigned long long int
+# define GL_UINT64_T
+#endif
+
+/* Avoid collision with Solaris 2.5.1 <pthread.h> etc.  */
+#define _UINT8_T
+#define _UINT32_T
+#define _UINT64_T
+
+
+/* 7.18.1.2. Minimum-width integer types */
+
+/* Here we assume a standard architecture where the hardware integer
+   types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types
+   are the same as the corresponding N_t types.  */
+
+#undef int_least8_t
+#undef uint_least8_t
+#undef int_least16_t
+#undef uint_least16_t
+#undef int_least32_t
+#undef uint_least32_t
+#undef int_least64_t
+#undef uint_least64_t
+#define int_least8_t int8_t
+#define uint_least8_t uint8_t
+#define int_least16_t int16_t
+#define uint_least16_t uint16_t
+#define int_least32_t int32_t
+#define uint_least32_t uint32_t
+#ifdef GL_INT64_T
+# define int_least64_t int64_t
+#endif
+#ifdef GL_UINT64_T
+# define uint_least64_t uint64_t
+#endif
+
+/* 7.18.1.3. Fastest minimum-width integer types */
+
+/* Note: Other <stdint.h> substitutes may define these types differently.
+   It is not recommended to use these types in public header files. */
+
+/* Here we assume a standard architecture where the hardware integer
+   types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types
+   are taken from the same list of types.  Assume that 'long int'
+   is fast enough for all narrower integers.  */
+
+#undef int_fast8_t
+#undef uint_fast8_t
+#undef int_fast16_t
+#undef uint_fast16_t
+#undef int_fast32_t
+#undef uint_fast32_t
+#undef int_fast64_t
+#undef uint_fast64_t
+#define int_fast8_t long int
+#define uint_fast8_t unsigned int_fast8_t
+#define int_fast16_t long int
+#define uint_fast16_t unsigned int_fast16_t
+#define int_fast32_t long int
+#define uint_fast32_t unsigned int_fast32_t
+#ifdef GL_INT64_T
+# define int_fast64_t int64_t
+#endif
+#ifdef GL_UINT64_T
+# define uint_fast64_t uint64_t
+#endif
+
+/* 7.18.1.4. Integer types capable of holding object pointers */
+
+#undef intptr_t
+#undef uintptr_t
+#define intptr_t long int
+#define uintptr_t unsigned long int
+
+/* 7.18.1.5. Greatest-width integer types */
+
+/* Note: These types are compiler dependent. It may be unwise to use them in
+   public header files. */
+
+#undef intmax_t
+#if @HAVE_LONG_LONG_INT@ && LONG_MAX >> 30 == 1
+# define intmax_t long long int
+#elif defined GL_INT64_T
+# define intmax_t int64_t
+#else
+# define intmax_t long int
+#endif
+
+#undef uintmax_t
+#if @HAVE_UNSIGNED_LONG_LONG_INT@ && ULONG_MAX >> 31 == 1
+# define uintmax_t unsigned long long int
+#elif defined GL_UINT64_T
+# define uintmax_t uint64_t
+#else
+# define uintmax_t unsigned long int
+#endif
+
+/* 7.18.2. Limits of specified-width integer types */
+
+#if ! defined __cplusplus || defined __STDC_LIMIT_MACROS
+
+/* 7.18.2.1. Limits of exact-width integer types */
+
+/* Here we assume a standard architecture where the hardware integer
+   types have 8, 16, 32, optionally 64 bits.  */
+
+#undef INT8_MIN
+#undef INT8_MAX
+#undef UINT8_MAX
+#define INT8_MIN  (~ INT8_MAX)
+#define INT8_MAX  127
+#define UINT8_MAX  255
+
+#undef INT16_MIN
+#undef INT16_MAX
+#undef UINT16_MAX
+#define INT16_MIN  (~ INT16_MAX)
+#define INT16_MAX  32767
+#define UINT16_MAX  65535
+
+#undef INT32_MIN
+#undef INT32_MAX
+#undef UINT32_MAX
+#define INT32_MIN  (~ INT32_MAX)
+#define INT32_MAX  2147483647
+#define UINT32_MAX  4294967295U
+
+#undef INT64_MIN
+#undef INT64_MAX
+#ifdef GL_INT64_T
+/* Prefer (- INTMAX_C (1) << 63) over (~ INT64_MAX) because SunPRO C 5.0
+   evaluates the latter incorrectly in preprocessor expressions.  */
+# define INT64_MIN  (- INTMAX_C (1) << 63)
+# define INT64_MAX  INTMAX_C (9223372036854775807)
+#endif
+
+#undef UINT64_MAX
+#ifdef GL_UINT64_T
+# define UINT64_MAX  UINTMAX_C (18446744073709551615)
+#endif
+
+/* 7.18.2.2. Limits of minimum-width integer types */
+
+/* Here we assume a standard architecture where the hardware integer
+   types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types
+   are the same as the corresponding N_t types.  */
+
+#undef INT_LEAST8_MIN
+#undef INT_LEAST8_MAX
+#undef UINT_LEAST8_MAX
+#define INT_LEAST8_MIN  INT8_MIN
+#define INT_LEAST8_MAX  INT8_MAX
+#define UINT_LEAST8_MAX  UINT8_MAX
+
+#undef INT_LEAST16_MIN
+#undef INT_LEAST16_MAX
+#undef UINT_LEAST16_MAX
+#define INT_LEAST16_MIN  INT16_MIN
+#define INT_LEAST16_MAX  INT16_MAX
+#define UINT_LEAST16_MAX  UINT16_MAX
+
+#undef INT_LEAST32_MIN
+#undef INT_LEAST32_MAX
+#undef UINT_LEAST32_MAX
+#define INT_LEAST32_MIN  INT32_MIN
+#define INT_LEAST32_MAX  INT32_MAX
+#define UINT_LEAST32_MAX  UINT32_MAX
+
+#undef INT_LEAST64_MIN
+#undef INT_LEAST64_MAX
+#ifdef GL_INT64_T
+# define INT_LEAST64_MIN  INT64_MIN
+# define INT_LEAST64_MAX  INT64_MAX
+#endif
+
+#undef UINT_LEAST64_MAX
+#ifdef GL_UINT64_T
+# define UINT_LEAST64_MAX  UINT64_MAX
+#endif
+
+/* 7.18.2.3. Limits of fastest minimum-width integer types */
+
+/* Here we assume a standard architecture where the hardware integer
+   types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types
+   are taken from the same list of types.  */
+
+#undef INT_FAST8_MIN
+#undef INT_FAST8_MAX
+#undef UINT_FAST8_MAX
+#define INT_FAST8_MIN  LONG_MIN
+#define INT_FAST8_MAX  LONG_MAX
+#define UINT_FAST8_MAX  ULONG_MAX
+
+#undef INT_FAST16_MIN
+#undef INT_FAST16_MAX
+#undef UINT_FAST16_MAX
+#define INT_FAST16_MIN  LONG_MIN
+#define INT_FAST16_MAX  LONG_MAX
+#define UINT_FAST16_MAX  ULONG_MAX
+
+#undef INT_FAST32_MIN
+#undef INT_FAST32_MAX
+#undef UINT_FAST32_MAX
+#define INT_FAST32_MIN  LONG_MIN
+#define INT_FAST32_MAX  LONG_MAX
+#define UINT_FAST32_MAX  ULONG_MAX
+
+#undef INT_FAST64_MIN
+#undef INT_FAST64_MAX
+#ifdef GL_INT64_T
+# define INT_FAST64_MIN  INT64_MIN
+# define INT_FAST64_MAX  INT64_MAX
+#endif
+
+#undef UINT_FAST64_MAX
+#ifdef GL_UINT64_T
+# define UINT_FAST64_MAX  UINT64_MAX
+#endif
+
+/* 7.18.2.4. Limits of integer types capable of holding object pointers */
+
+#undef INTPTR_MIN
+#undef INTPTR_MAX
+#undef UINTPTR_MAX
+#define INTPTR_MIN  LONG_MIN
+#define INTPTR_MAX  LONG_MAX
+#define UINTPTR_MAX  ULONG_MAX
+
+/* 7.18.2.5. Limits of greatest-width integer types */
+
+#undef INTMAX_MIN
+#undef INTMAX_MAX
+#ifdef INT64_MAX
+# define INTMAX_MIN  INT64_MIN
+# define INTMAX_MAX  INT64_MAX
+#else
+# define INTMAX_MIN  INT32_MIN
+# define INTMAX_MAX  INT32_MAX
+#endif
+
+#undef UINTMAX_MAX
+#ifdef UINT64_MAX
+# define UINTMAX_MAX  UINT64_MAX
+#else
+# define UINTMAX_MAX  UINT32_MAX
+#endif
+
+/* 7.18.3. Limits of other integer types */
+
+/* ptrdiff_t limits */
+#undef PTRDIFF_MIN
+#undef PTRDIFF_MAX
+#define PTRDIFF_MIN  \
+   _STDINT_MIN (1, @BITSIZEOF_PTRDIFF_T@, 0@PTRDIFF_T_SUFFIX@)
+#define PTRDIFF_MAX  \
+   _STDINT_MAX (1, @BITSIZEOF_PTRDIFF_T@, 0@PTRDIFF_T_SUFFIX@)
+
+/* sig_atomic_t limits */
+#undef SIG_ATOMIC_MIN
+#undef SIG_ATOMIC_MAX
+#define SIG_ATOMIC_MIN  \
+   _STDINT_MIN (@HAVE_SIGNED_SIG_ATOMIC_T@, @BITSIZEOF_SIG_ATOMIC_T@, \
+               0@SIG_ATOMIC_T_SUFFIX@)
+#define SIG_ATOMIC_MAX  \
+   _STDINT_MAX (@HAVE_SIGNED_SIG_ATOMIC_T@, @BITSIZEOF_SIG_ATOMIC_T@, \
+               0@SIG_ATOMIC_T_SUFFIX@)
+
+
+/* size_t limit */
+#undef SIZE_MAX
+#define SIZE_MAX  _STDINT_MAX (0, @BITSIZEOF_SIZE_T@, 0@SIZE_T_SUFFIX@)
+
+/* wchar_t limits */
+#undef WCHAR_MIN
+#undef WCHAR_MAX
+#define WCHAR_MIN  \
+   _STDINT_MIN (@HAVE_SIGNED_WCHAR_T@, @BITSIZEOF_WCHAR_T@, 0@WCHAR_T_SUFFIX@)
+#define WCHAR_MAX  \
+   _STDINT_MAX (@HAVE_SIGNED_WCHAR_T@, @BITSIZEOF_WCHAR_T@, 0@WCHAR_T_SUFFIX@)
+
+/* wint_t limits */
+#undef WINT_MIN
+#undef WINT_MAX
+#define WINT_MIN  \
+   _STDINT_MIN (@HAVE_SIGNED_WINT_T@, @BITSIZEOF_WINT_T@, 0@WINT_T_SUFFIX@)
+#define WINT_MAX  \
+   _STDINT_MAX (@HAVE_SIGNED_WINT_T@, @BITSIZEOF_WINT_T@, 0@WINT_T_SUFFIX@)
+
+#endif /* !defined __cplusplus || defined __STDC_LIMIT_MACROS */
+
+/* 7.18.4. Macros for integer constants */
+
+#if ! defined __cplusplus || defined __STDC_CONSTANT_MACROS
+
+/* 7.18.4.1. Macros for minimum-width integer constants */
+/* According to ISO C 99 Technical Corrigendum 1 */
+
+/* Here we assume a standard architecture where the hardware integer
+   types have 8, 16, 32, optionally 64 bits, and int is 32 bits.  */
+
+#undef INT8_C
+#undef UINT8_C
+#define INT8_C(x) x
+#define UINT8_C(x) x
+
+#undef INT16_C
+#undef UINT16_C
+#define INT16_C(x) x
+#define UINT16_C(x) x
+
+#undef INT32_C
+#undef UINT32_C
+#define INT32_C(x) x
+#define UINT32_C(x) x ## U
+
+#undef INT64_C
+#undef UINT64_C
+#if LONG_MAX >> 31 >> 31 == 1
+# define INT64_C(x) x##L
+#elif defined _MSC_VER
+# define INT64_C(x) x##i64
+#elif @HAVE_LONG_LONG_INT@
+# define INT64_C(x) x##LL
+#endif
+#if ULONG_MAX >> 31 >> 31 >> 1 == 1
+# define UINT64_C(x) x##UL
+#elif defined _MSC_VER
+# define UINT64_C(x) x##ui64
+#elif @HAVE_UNSIGNED_LONG_LONG_INT@
+# define UINT64_C(x) x##ULL
+#endif
+
+/* 7.18.4.2. Macros for greatest-width integer constants */
+
+#undef INTMAX_C
+#if @HAVE_LONG_LONG_INT@ && LONG_MAX >> 30 == 1
+# define INTMAX_C(x)   x##LL
+#elif defined GL_INT64_T
+# define INTMAX_C(x)   INT64_C(x)
+#else
+# define INTMAX_C(x)   x##L
+#endif
+
+#undef UINTMAX_C
+#if @HAVE_UNSIGNED_LONG_LONG_INT@ && ULONG_MAX >> 31 == 1
+# define UINTMAX_C(x)  x##ULL
+#elif defined GL_UINT64_T
+# define UINTMAX_C(x)  UINT64_C(x)
+#else
+# define UINTMAX_C(x)  x##UL
+#endif
+
+#endif /* !defined __cplusplus || defined __STDC_CONSTANT_MACROS */
+
+#endif /* _GL_STDINT_H */
+#endif /* !defined _GL_STDINT_H && !defined _GL_JUST_INCLUDE_SYSTEM_STDINT_H */
diff --git a/gnulib/stdio_.h b/gnulib/stdio_.h
new file mode 100644 (file)
index 0000000..76d9856
--- /dev/null
@@ -0,0 +1,353 @@
+/* A GNU-like <stdio.h>.
+
+   Copyright (C) 2004, 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#if defined __need_FILE || defined __need___FILE
+/* Special invocation convention inside glibc header files.  */
+
+#@INCLUDE_NEXT@ @NEXT_STDIO_H@
+
+#else
+/* Normal invocation convention.  */
+
+#ifndef _GL_STDIO_H
+
+/* The include_next requires a split double-inclusion guard.  */
+#@INCLUDE_NEXT@ @NEXT_STDIO_H@
+
+#ifndef _GL_STDIO_H
+#define _GL_STDIO_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#if (@GNULIB_FSEEKO@ && @REPLACE_FSEEKO@) \
+  || (@GNULIB_FTELLO@ && @REPLACE_FTELLO@) \
+  || (@GNULIB_GETDELIM@ && !@HAVE_DECL_GETDELIM@) \
+  || (@GNULIB_GETLINE@ && (!@HAVE_DECL_GETLINE@ || @REPLACE_GETLINE@))
+/* Get off_t and ssize_t.  */
+# include <sys/types.h>
+#endif
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later.  */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+#  define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+   are accepted by gcc versions 2.6.4 (effectively 2.7) and later.  */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+#  define __format__ format
+#  define __printf__ printf
+# endif
+#endif
+
+
+/* The definition of GL_LINK_WARNING is copied here.  */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if @GNULIB_FPRINTF_POSIX@
+# if @REPLACE_FPRINTF@
+#  define fprintf rpl_fprintf
+extern int fprintf (FILE *fp, const char *format, ...)
+       __attribute__ ((__format__ (__printf__, 2, 3)));
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef fprintf
+# define fprintf \
+    (GL_LINK_WARNING ("fprintf is not always POSIX compliant - " \
+                      "use gnulib module fprintf-posix for portable " \
+                      "POSIX compliance"), \
+     fprintf)
+#endif
+
+#if @GNULIB_VFPRINTF_POSIX@
+# if @REPLACE_VFPRINTF@
+#  define vfprintf rpl_vfprintf
+extern int vfprintf (FILE *fp, const char *format, va_list args)
+       __attribute__ ((__format__ (__printf__, 2, 0)));
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef vfprintf
+# define vfprintf(s,f,a) \
+    (GL_LINK_WARNING ("vfprintf is not always POSIX compliant - " \
+                      "use gnulib module vfprintf-posix for portable " \
+                      "POSIX compliance"), \
+     vfprintf (s, f, a))
+#endif
+
+#if @GNULIB_PRINTF_POSIX@
+# if @REPLACE_PRINTF@
+/* Don't break __attribute__((format(printf,M,N))).  */
+#  define printf __printf__
+extern int printf (const char *format, ...)
+       __attribute__ ((__format__ (__printf__, 1, 2)));
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef printf
+# define printf \
+    (GL_LINK_WARNING ("printf is not always POSIX compliant - " \
+                      "use gnulib module printf-posix for portable " \
+                      "POSIX compliance"), \
+     printf)
+/* Don't break __attribute__((format(printf,M,N))).  */
+# define format(kind,m,n) format (__##kind##__, m, n)
+# define __format__(kind,m,n) __format__ (__##kind##__, m, n)
+# define ____printf____ __printf__
+# define ____scanf____ __scanf__
+# define ____strftime____ __strftime__
+# define ____strfmon____ __strfmon__
+#endif
+
+#if @GNULIB_VPRINTF_POSIX@
+# if @REPLACE_VPRINTF@
+#  define vprintf rpl_vprintf
+extern int vprintf (const char *format, va_list args)
+       __attribute__ ((__format__ (__printf__, 1, 0)));
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef vprintf
+# define vprintf(f,a) \
+    (GL_LINK_WARNING ("vprintf is not always POSIX compliant - " \
+                      "use gnulib module vprintf-posix for portable " \
+                      "POSIX compliance"), \
+     vprintf (f, a))
+#endif
+
+#if @GNULIB_SNPRINTF@
+# if @REPLACE_SNPRINTF@
+#  define snprintf rpl_snprintf
+# endif
+# if @REPLACE_SNPRINTF@ || !@HAVE_DECL_SNPRINTF@
+extern int snprintf (char *str, size_t size, const char *format, ...)
+       __attribute__ ((__format__ (__printf__, 3, 4)));
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef snprintf
+# define snprintf \
+    (GL_LINK_WARNING ("snprintf is unportable - " \
+                      "use gnulib module snprintf for portability"), \
+     snprintf)
+#endif
+
+#if @GNULIB_VSNPRINTF@
+# if @REPLACE_VSNPRINTF@
+#  define vsnprintf rpl_vsnprintf
+# endif
+# if @REPLACE_VSNPRINTF@ || !@HAVE_DECL_VSNPRINTF@
+extern int vsnprintf (char *str, size_t size, const char *format, va_list args)
+       __attribute__ ((__format__ (__printf__, 3, 0)));
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef vsnprintf
+# define vsnprintf(b,s,f,a) \
+    (GL_LINK_WARNING ("vsnprintf is unportable - " \
+                      "use gnulib module vsnprintf for portability"), \
+     vsnprintf (b, s, f, a))
+#endif
+
+#if @GNULIB_SPRINTF_POSIX@
+# if @REPLACE_SPRINTF@
+#  define sprintf rpl_sprintf
+extern int sprintf (char *str, const char *format, ...)
+       __attribute__ ((__format__ (__printf__, 2, 3)));
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef sprintf
+# define sprintf \
+    (GL_LINK_WARNING ("sprintf is not always POSIX compliant - " \
+                      "use gnulib module sprintf-posix for portable " \
+                      "POSIX compliance"), \
+     sprintf)
+#endif
+
+#if @GNULIB_VSPRINTF_POSIX@
+# if @REPLACE_VSPRINTF@
+#  define vsprintf rpl_vsprintf
+extern int vsprintf (char *str, const char *format, va_list args)
+       __attribute__ ((__format__ (__printf__, 2, 0)));
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef vsprintf
+# define vsprintf(b,f,a) \
+    (GL_LINK_WARNING ("vsprintf is not always POSIX compliant - " \
+                      "use gnulib module vsprintf-posix for portable " \
+                      "POSIX compliance"), \
+     vsprintf (b, f, a))
+#endif
+
+#if @GNULIB_VASPRINTF@
+# if @REPLACE_VASPRINTF@
+#  define asprintf rpl_asprintf
+#  define vasprintf rpl_vasprintf
+# endif
+# if @REPLACE_VASPRINTF@ || !@HAVE_VASPRINTF@
+  /* Write formatted output to a string dynamically allocated with malloc().
+     If the memory allocation succeeds, store the address of the string in
+     *RESULT and return the number of resulting bytes, excluding the trailing
+     NUL.  Upon memory allocation error, or some other error, return -1.  */
+  extern int asprintf (char **result, const char *format, ...)
+    __attribute__ ((__format__ (__printf__, 2, 3)));
+  extern int vasprintf (char **result, const char *format, va_list args)
+    __attribute__ ((__format__ (__printf__, 2, 0)));
+# endif
+#endif
+
+#if @GNULIB_FSEEKO@
+# if @REPLACE_FSEEKO@
+/* Provide fseek, fseeko functions that are aware of a preceding
+   fflush(), and which detect pipes.  */
+#  define fseeko rpl_fseeko
+extern int fseeko (FILE *fp, off_t offset, int whence);
+#  define fseek(fp, offset, whence) fseeko (fp, (off_t)(offset), whence)
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef fseeko
+# define fseeko(f,o,w) \
+   (GL_LINK_WARNING ("fseeko is unportable - " \
+                     "use gnulib module fseeko for portability"), \
+    fseeko (f, o, w))
+#endif
+
+#if @GNULIB_FSEEK@ && @REPLACE_FSEEK@
+extern int rpl_fseek (FILE *fp, long offset, int whence);
+# undef fseek
+# if defined GNULIB_POSIXCHECK
+#  define fseek(f,o,w) \
+     (GL_LINK_WARNING ("fseek cannot handle files larger than 4 GB " \
+                       "on 32-bit platforms - " \
+                       "use fseeko function for handling of large files"), \
+      rpl_fseek (f, o, w))
+# else
+#  define fseek rpl_fseek
+# endif
+#elif defined GNULIB_POSIXCHECK
+# ifndef fseek
+#  define fseek(f,o,w) \
+     (GL_LINK_WARNING ("fseek cannot handle files larger than 4 GB " \
+                       "on 32-bit platforms - " \
+                       "use fseeko function for handling of large files"), \
+      fseek (f, o, w))
+# endif
+#endif
+
+#if @GNULIB_FTELLO@
+# if @REPLACE_FTELLO@
+#  define ftello rpl_ftello
+extern off_t ftello (FILE *fp);
+#  define ftell(fp) ftello (fp)
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef ftello
+# define ftello(f) \
+   (GL_LINK_WARNING ("ftello is unportable - " \
+                     "use gnulib module ftello for portability"), \
+    ftello (f))
+#endif
+
+#if @GNULIB_FTELL@ && @REPLACE_FTELL@
+extern long rpl_ftell (FILE *fp);
+# undef ftell
+# if GNULIB_POSIXCHECK
+#  define ftell(f) \
+     (GL_LINK_WARNING ("ftell cannot handle files larger than 4 GB " \
+                       "on 32-bit platforms - " \
+                       "use ftello function for handling of large files"), \
+      rpl_ftell (f))
+# else
+#  define ftell rpl_ftell
+# endif
+#elif defined GNULIB_POSIXCHECK
+# ifndef ftell
+#  define ftell(f) \
+     (GL_LINK_WARNING ("ftell cannot handle files larger than 4 GB " \
+                       "on 32-bit platforms - " \
+                       "use ftello function for handling of large files"), \
+      ftell (f))
+# endif
+#endif
+
+#if @GNULIB_FFLUSH@
+# if @REPLACE_FFLUSH@
+#  define fflush rpl_fflush
+  /* Flush all pending data on STREAM according to POSIX rules.  Both
+     output and seekable input streams are supported.
+     Note! LOSS OF DATA can occur if fflush is applied on an input stream
+     that is _not_seekable_ or on an update stream that is _not_seekable_
+     and in which the most recent operation was input.  Seekability can
+     be tested with lseek(fileno(fp),0,SEEK_CUR).  */
+  extern int fflush (FILE *gl_stream);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef fflush
+# define fflush(f) \
+   (GL_LINK_WARNING ("fflush is not always POSIX compliant - " \
+                     "use gnulib module fflush for portable " \
+                     "POSIX compliance"), \
+    fflush (f))
+#endif
+
+#if @GNULIB_GETDELIM@
+# if !@HAVE_DECL_GETDELIM@
+  /* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
+     NUL-terminate it).  *LINEPTR is a pointer returned from malloc (or
+     NULL), pointing to *N characters of space.  It is realloc'ed as
+     necessary.  Returns the number of characters read (not including
+     the null terminator), or -1 on error or EOF.  */
+  extern ssize_t getdelim (char **, size_t *, int delim, FILE *);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef getdelim
+# define getdelim(l, s, d, f)                                      \
+  (GL_LINK_WARNING ("getdelim is unportable - "                            \
+                   "use gnulib module getdelim for portability"),  \
+   getdelim (l, s, d, f))
+#endif
+
+#if @GNULIB_GETLINE@
+# if @REPLACE_GETLINE@
+#  undef getline
+#  define getline rpl_getline
+# endif
+# if !@HAVE_DECL_GETLINE@ || @REPLACE_GETLINE@
+  /* Read up to (and including) a newline from FP into *LINEPTR (and
+     NUL-terminate it).  *LINEPTR is a pointer returned from malloc (or
+     NULL), pointing to *N characters of space.  It is realloc'ed as
+     necessary.  Returns the number of characters read (not including
+     the null terminator), or -1 on error or EOF.  */
+  extern ssize_t getline (char **, size_t *, FILE *);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef getline
+# define getline(l, s, f)                                              \
+  (GL_LINK_WARNING ("getline is unportable - "                         \
+                   "use gnulib module getline for portability"),       \
+   getline (l, s, f))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GL_STDIO_H */
+#endif /* _GL_STDIO_H */
+#endif
diff --git a/gnulib/stdlib_.h b/gnulib/stdlib_.h
new file mode 100644 (file)
index 0000000..a4946e6
--- /dev/null
@@ -0,0 +1,177 @@
+/* A GNU-like <stdlib.h>.
+
+   Copyright (C) 1995, 2001-2002, 2006-2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#if defined __need_malloc_and_calloc
+/* Special invocation convention inside glibc header files.  */
+
+#@INCLUDE_NEXT@ @NEXT_STDLIB_H@
+
+#else
+/* Normal invocation convention.  */
+
+#ifndef _GL_STDLIB_H
+
+/* The include_next requires a split double-inclusion guard.  */
+#@INCLUDE_NEXT@ @NEXT_STDLIB_H@
+
+#ifndef _GL_STDLIB_H
+#define _GL_STDLIB_H
+
+
+/* The definition of GL_LINK_WARNING is copied here.  */
+
+
+/* Some systems do not define EXIT_*, despite otherwise supporting C89.  */
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+/* Tandem/NSK and other platforms that define EXIT_FAILURE as -1 interfere
+   with proper operation of xargs.  */
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#elif EXIT_FAILURE != 1
+# undef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if @GNULIB_MALLOC_POSIX@
+# if !@HAVE_MALLOC_POSIX@
+#  undef malloc
+#  define malloc rpl_malloc
+extern void * malloc (size_t size);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef malloc
+# define malloc(s) \
+    (GL_LINK_WARNING ("malloc is not POSIX compliant everywhere - " \
+                      "use gnulib module malloc-posix for portability"), \
+     malloc (s))
+#endif
+
+
+#if @GNULIB_REALLOC_POSIX@
+# if !@HAVE_REALLOC_POSIX@
+#  undef realloc
+#  define realloc rpl_realloc
+extern void * realloc (void *ptr, size_t size);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef realloc
+# define realloc(p,s) \
+    (GL_LINK_WARNING ("realloc is not POSIX compliant everywhere - " \
+                      "use gnulib module realloc-posix for portability"), \
+     realloc (p, s))
+#endif
+
+
+#if @GNULIB_CALLOC_POSIX@
+# if !@HAVE_CALLOC_POSIX@
+#  undef calloc
+#  define calloc rpl_calloc
+extern void * calloc (size_t nmemb, size_t size);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef calloc
+# define calloc(n,s) \
+    (GL_LINK_WARNING ("calloc is not POSIX compliant everywhere - " \
+                      "use gnulib module calloc-posix for portability"), \
+     calloc (n, s))
+#endif
+
+
+#if @GNULIB_GETSUBOPT@
+/* Assuming *OPTIONP is a comma separated list of elements of the form
+   "token" or "token=value", getsubopt parses the first of these elements.
+   If the first element refers to a "token" that is member of the given
+   NULL-terminated array of tokens:
+     - It replaces the comma with a NUL byte, updates *OPTIONP to point past
+       the first option and the comma, sets *VALUEP to the value of the
+       element (or NULL if it doesn't contain an "=" sign),
+     - It returns the index of the "token" in the given array of tokens.
+   Otherwise it returns -1, and *OPTIONP and *VALUEP are undefined.
+   For more details see the POSIX:2001 specification.
+   http://www.opengroup.org/susv3xsh/getsubopt.html */
+# if !@HAVE_GETSUBOPT@
+extern int getsubopt (char **optionp, char *const *tokens, char **valuep);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef getsubopt
+# define getsubopt(o,t,v) \
+    (GL_LINK_WARNING ("getsubopt is unportable - " \
+                      "use gnulib module getsubopt for portability"), \
+     getsubopt (o, t, v))
+#endif
+
+
+#if @GNULIB_MKDTEMP@
+# if !@HAVE_MKDTEMP@
+/* Create a unique temporary directory from TEMPLATE.
+   The last six characters of TEMPLATE must be "XXXXXX";
+   they are replaced with a string that makes the directory name unique.
+   Returns TEMPLATE, or a null pointer if it cannot get a unique name.
+   The directory is created mode 700.  */
+extern char * mkdtemp (char * /*template*/);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef mkdtemp
+# define mkdtemp(t) \
+    (GL_LINK_WARNING ("mkdtemp is unportable - " \
+                      "use gnulib module mkdtemp for portability"), \
+     mkdtemp (t))
+#endif
+
+
+#if @GNULIB_MKSTEMP@
+# if @REPLACE_MKSTEMP@
+/* Create a unique temporary file from TEMPLATE.
+   The last six characters of TEMPLATE must be "XXXXXX";
+   they are replaced with a string that makes the file name unique.
+   The file is then created, ensuring it didn't exist before.
+   The file is created read-write (mask at least 0600 & ~umask), but it may be
+   world-readable and world-writable (mask 0666 & ~umask), depending on the
+   implementation.
+   Returns the open file descriptor if successful, otherwise -1 and errno
+   set.  */
+#  define mkstemp rpl_mkstemp
+extern int mkstemp (char * /*template*/);
+# else
+/* On MacOS X 10.3, only <unistd.h> declares mkstemp.  */
+#  include <unistd.h>
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef mkstemp
+# define mkstemp(t) \
+    (GL_LINK_WARNING ("mkstemp is unportable - " \
+                      "use gnulib module mkstemp for portability"), \
+     mkstemp (t))
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GL_STDLIB_H */
+#endif /* _GL_STDLIB_H */
+#endif
diff --git a/gnulib/sys_socket_.h b/gnulib/sys_socket_.h
new file mode 100644 (file)
index 0000000..c25b6ab
--- /dev/null
@@ -0,0 +1,91 @@
+/* Provide a sys/socket header file for systems lacking it (read: MinGW).
+   Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+   Written by Simon Josefsson.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* This file is supposed to be used on platforms that lack <sys/socket.h>
+   and on platforms where <sys/socket.h> cannot be included standalone.
+   It is intended to provide definitions and prototypes needed by an
+   application.  */
+
+#ifndef _GL_SYS_SOCKET_H
+
+#if @HAVE_SYS_SOCKET_H@
+
+/* On many platforms, <sys/socket.h> assumes prior inclusion of
+   <sys/types.h>.  */
+# include <sys/types.h>
+
+/* The include_next requires a split double-inclusion guard.  */
+# @INCLUDE_NEXT@ @NEXT_SYS_SOCKET_H@
+
+#endif
+
+#ifndef _GL_SYS_SOCKET_H
+#define _GL_SYS_SOCKET_H
+
+#if !@HAVE_SYS_SOCKET_H@
+
+/* A platform that lacks <sys/socket.h>.
+
+   Currently only MinGW is supported.  See the gnulib manual regarding
+   Windows sockets.  MinGW has the header files winsock2.h and
+   ws2tcpip.h that declare the sys/socket.h definitions we need.  Note
+   that you can influence which definitions you get by setting the
+   WINVER symbol before including these two files.  For example,
+   getaddrinfo is only available if _WIN32_WINNT >= 0x0501 (that
+   symbol is set indiriectly through WINVER).  You can set this by
+   adding AC_DEFINE(WINVER, 0x0501) to configure.ac.  Note that your
+   code may not run on older Windows releases then.  My Windows 2000
+   box was not able to run the code, for example.  The situation is
+   slightly confusing because:
+   http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/getaddrinfo_2.asp
+   suggests that getaddrinfo should be available on all Windows
+   releases. */
+
+
+# if @HAVE_WINSOCK2_H@
+#  include <winsock2.h>
+# endif
+# if @HAVE_WS2TCPIP_H@
+#  include <ws2tcpip.h>
+# endif
+
+/* For shutdown(). */
+# if !defined SHUT_RD && defined SD_RECEIVE
+#  define SHUT_RD SD_RECEIVE
+# endif
+# if !defined SHUT_WR && defined SD_SEND
+#  define SHUT_WR SD_SEND
+# endif
+# if !defined SHUT_RDWR && defined SD_BOTH
+#  define SHUT_RDWR SD_BOTH
+# endif
+
+# if defined _WIN32 || defined __WIN32__
+#  define ENOTSOCK                WSAENOTSOCK
+#  define EADDRINUSE              WSAEADDRINUSE
+#  define ENETRESET               WSAENETRESET
+#  define ECONNABORTED            WSAECONNABORTED
+#  define ECONNRESET              WSAECONNRESET
+#  define ENOTCONN                WSAENOTCONN
+#  define ESHUTDOWN               WSAESHUTDOWN
+# endif
+
+#endif /* HAVE_SYS_SOCKET_H */
+
+#endif /* _GL_SYS_SOCKET_H */
+#endif /* _GL_SYS_SOCKET_H */
diff --git a/gnulib/sys_stat_.h b/gnulib/sys_stat_.h
new file mode 100644 (file)
index 0000000..2e411cd
--- /dev/null
@@ -0,0 +1,280 @@
+/* Provide a more complete sys/stat header file.
+   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Eric Blake, Paul Eggert, and Jim Meyering.  */
+
+/* This file is supposed to be used on platforms where <sys/stat.h> is
+   incomplete.  It is intended to provide definitions and prototypes
+   needed by an application.  Start with what the system provides.  */
+
+#ifndef _GL_SYS_STAT_H
+
+/* The include_next requires a split double-inclusion guard.  */
+#@INCLUDE_NEXT@ @NEXT_SYS_STAT_H@
+
+#ifndef _GL_SYS_STAT_H
+#define _GL_SYS_STAT_H
+
+#ifndef S_IFMT
+# define S_IFMT 0170000
+#endif
+
+#if STAT_MACROS_BROKEN
+# undef S_ISBLK
+# undef S_ISCHR
+# undef S_ISDIR
+# undef S_ISFIFO
+# undef S_ISLNK
+# undef S_ISNAM
+# undef S_ISMPB
+# undef S_ISMPC
+# undef S_ISNWK
+# undef S_ISREG
+# undef S_ISSOCK
+#endif
+
+#ifndef S_ISBLK
+# ifdef S_IFBLK
+#  define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+# else
+#  define S_ISBLK(m) 0
+# endif
+#endif
+
+#ifndef S_ISCHR
+# ifdef S_IFCHR
+#  define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+# else
+#  define S_ISCHR(m) 0
+# endif
+#endif
+
+#ifndef S_ISDIR
+# ifdef S_IFDIR
+#  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# else
+#  define S_ISDIR(m) 0
+# endif
+#endif
+
+#ifndef S_ISDOOR /* Solaris 2.5 and up */
+# define S_ISDOOR(m) 0
+#endif
+
+#ifndef S_ISFIFO
+# ifdef S_IFIFO
+#  define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+# else
+#  define S_ISFIFO(m) 0
+# endif
+#endif
+
+#ifndef S_ISLNK
+# ifdef S_IFLNK
+#  define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+# else
+#  define S_ISLNK(m) 0
+# endif
+#endif
+
+#ifndef S_ISMPB /* V7 */
+# ifdef S_IFMPB
+#  define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#  define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+# else
+#  define S_ISMPB(m) 0
+#  define S_ISMPC(m) 0
+# endif
+#endif
+
+#ifndef S_ISNAM /* Xenix */
+# ifdef S_IFNAM
+#  define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM)
+# else
+#  define S_ISNAM(m) 0
+# endif
+#endif
+
+#ifndef S_ISNWK /* HP/UX */
+# ifdef S_IFNWK
+#  define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+# else
+#  define S_ISNWK(m) 0
+# endif
+#endif
+
+#ifndef S_ISPORT /* Solaris 10 and up */
+# define S_ISPORT(m) 0
+#endif
+
+#ifndef S_ISREG
+# ifdef S_IFREG
+#  define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+# else
+#  define S_ISREG(m) 0
+# endif
+#endif
+
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+#  define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+# else
+#  define S_ISSOCK(m) 0
+# endif
+#endif
+
+
+#ifndef S_TYPEISMQ
+# define S_TYPEISMQ(p) 0
+#endif
+
+#ifndef S_TYPEISTMO
+# define S_TYPEISTMO(p) 0
+#endif
+
+
+#ifndef S_TYPEISSEM
+# ifdef S_INSEM
+#  define S_TYPEISSEM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSEM)
+# else
+#  define S_TYPEISSEM(p) 0
+# endif
+#endif
+
+#ifndef S_TYPEISSHM
+# ifdef S_INSHD
+#  define S_TYPEISSHM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSHD)
+# else
+#  define S_TYPEISSHM(p) 0
+# endif
+#endif
+
+/* high performance ("contiguous data") */
+#ifndef S_ISCTG
+# define S_ISCTG(p) 0
+#endif
+
+/* Cray DMF (data migration facility): off line, with data  */
+#ifndef S_ISOFD
+# define S_ISOFD(p) 0
+#endif
+
+/* Cray DMF (data migration facility): off line, with no data  */
+#ifndef S_ISOFL
+# define S_ISOFL(p) 0
+#endif
+
+/* 4.4BSD whiteout */
+#ifndef S_ISWHT
+# define S_ISWHT(m) 0
+#endif
+
+/* If any of the following are undefined,
+   define them to their de facto standard values.  */
+#if !S_ISUID
+# define S_ISUID 04000
+#endif
+#if !S_ISGID
+# define S_ISGID 02000
+#endif
+
+/* S_ISVTX is a common extension to POSIX.  */
+#ifndef S_ISVTX
+# define S_ISVTX 01000
+#endif
+
+#if !S_IRUSR && S_IREAD
+# define S_IRUSR S_IREAD
+#endif
+#if !S_IRUSR
+# define S_IRUSR 00400
+#endif
+#if !S_IRGRP
+# define S_IRGRP (S_IRUSR >> 3)
+#endif
+#if !S_IROTH
+# define S_IROTH (S_IRUSR >> 6)
+#endif
+
+#if !S_IWUSR && S_IWRITE
+# define S_IWUSR S_IWRITE
+#endif
+#if !S_IWUSR
+# define S_IWUSR 00200
+#endif
+#if !S_IWGRP
+# define S_IWGRP (S_IWUSR >> 3)
+#endif
+#if !S_IWOTH
+# define S_IWOTH (S_IWUSR >> 6)
+#endif
+
+#if !S_IXUSR && S_IEXEC
+# define S_IXUSR S_IEXEC
+#endif
+#if !S_IXUSR
+# define S_IXUSR 00100
+#endif
+#if !S_IXGRP
+# define S_IXGRP (S_IXUSR >> 3)
+#endif
+#if !S_IXOTH
+# define S_IXOTH (S_IXUSR >> 6)
+#endif
+
+#if !S_IRWXU
+# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
+#if !S_IRWXG
+# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+#endif
+#if !S_IRWXO
+# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+#endif
+
+/* S_IXUGO is a common extension to POSIX.  */
+#if !S_IXUGO
+# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
+#endif
+
+#ifndef S_IRWXUGO
+# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)
+#endif
+
+/* mingw does not support symlinks, therefore it does not have lstat.  But
+   without links, stat does just fine.  */
+#if ! @HAVE_LSTAT@
+# define lstat stat
+#endif
+
+/* mingw's _mkdir() function has 1 argument, but we pass 2 arguments.
+   Additionally, it declares _mkdir (and depending on compile flags, an
+   alias mkdir), only in the nonstandard io.h.  */
+#if ! @HAVE_DECL_MKDIR@ && @HAVE_IO_H@
+# include <io.h>
+
+static inline int
+rpl_mkdir (char const *name, mode_t mode)
+{
+  return _mkdir (name);
+}
+
+# define mkdir rpl_mkdir
+#endif
+
+#endif /* _GL_SYS_STAT_H */
+#endif /* _GL_SYS_STAT_H */
diff --git a/gnulib/sys_time_.h b/gnulib/sys_time_.h
new file mode 100644 (file)
index 0000000..296d20d
--- /dev/null
@@ -0,0 +1,52 @@
+/* Provide a more complete sys/time.h.
+
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Paul Eggert.  */
+
+#if defined _GL_SYS_TIME_H
+
+/* Simply delegate to the system's header, without adding anything.  */
+# if @HAVE_SYS_TIME_H@
+#  @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@
+# endif
+
+#else
+
+# define _GL_SYS_TIME_H
+
+# if @HAVE_SYS_TIME_H@
+#  @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@
+# else
+#  include <time.h>
+# endif
+
+# if ! @HAVE_STRUCT_TIMEVAL@
+struct timeval
+{
+  time_t tv_sec;
+  long int tv_usec;
+};
+# endif
+
+# if @REPLACE_GETTIMEOFDAY@
+#  undef gettimeofday
+#  define gettimeofday rpl_gettimeofday
+int gettimeofday (struct timeval *restrict, void *restrict);
+# endif
+
+#endif /* _GL_SYS_TIME_H */
diff --git a/gnulib/tempname.c b/gnulib/tempname.c
new file mode 100644 (file)
index 0000000..e213600
--- /dev/null
@@ -0,0 +1,315 @@
+/* tempname.c - generate the name of a temporary file.
+
+   Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003, 2005, 2006, 2007 Free Software Foundation,
+   Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Extracted from glibc sysdeps/posix/tempname.c.  See also tmpdir.c.  */
+
+#if !_LIBC
+# include <config.h>
+# include "tempname.h"
+#endif
+
+#include <sys/types.h>
+#include <assert.h>
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#include <stdio.h>
+#ifndef P_tmpdir
+# define P_tmpdir "/tmp"
+#endif
+#ifndef TMP_MAX
+# define TMP_MAX 238328
+#endif
+#ifndef __GT_FILE
+# define __GT_FILE     0
+# define __GT_BIGFILE  1
+# define __GT_DIR      2
+# define __GT_NOCREATE 3
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+
+#if _LIBC
+# define struct_stat64 struct stat64
+# define small_open __open
+# define large_open __open64
+#else
+# define struct_stat64 struct stat
+# define small_open open
+# define large_open open
+# define __gen_tempname gen_tempname
+# define __getpid getpid
+# define __gettimeofday gettimeofday
+# define __mkdir mkdir
+# define __lxstat64(version, file, buf) lstat (file, buf)
+# define __xstat64(version, file, buf) stat (file, buf)
+#endif
+
+#if ! (HAVE___SECURE_GETENV || _LIBC)
+# define __secure_getenv getenv
+#endif
+
+#ifdef _LIBC
+# include <hp-timing.h>
+# if HP_TIMING_AVAIL
+#  define RANDOM_BITS(Var) \
+  if (__builtin_expect (value == UINT64_C (0), 0))                           \
+    {                                                                        \
+      /* If this is the first time this function is used initialize          \
+        the variable we accumulate the value in to some somewhat             \
+        random value.  If we'd not do this programs at startup time          \
+        might have a reduced set of possible names, at least on slow         \
+        machines.  */                                                        \
+      struct timeval tv;                                                     \
+      __gettimeofday (&tv, NULL);                                            \
+      value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;                     \
+    }                                                                        \
+  HP_TIMING_NOW (Var)
+# endif
+#endif
+
+/* Use the widest available unsigned type if uint64_t is not
+   available.  The algorithm below extracts a number less than 62**6
+   (approximately 2**35.725) from uint64_t, so ancient hosts where
+   uintmax_t is only 32 bits lose about 3.725 bits of randomness,
+   which is better than not having mkstemp at all.  */
+#if !defined UINT64_MAX && !defined uint64_t
+# define uint64_t uintmax_t
+#endif
+
+#if _LIBC
+/* Return nonzero if DIR is an existent directory.  */
+static int
+direxists (const char *dir)
+{
+  struct_stat64 buf;
+  return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode);
+}
+
+/* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is
+   non-null and exists, uses it; otherwise uses the first of $TMPDIR,
+   P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable
+   for use with mk[s]temp.  Will fail (-1) if DIR is non-null and
+   doesn't exist, none of the searched dirs exists, or there's not
+   enough space in TMPL. */
+int
+__path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
+              int try_tmpdir)
+{
+  const char *d;
+  size_t dlen, plen;
+
+  if (!pfx || !pfx[0])
+    {
+      pfx = "file";
+      plen = 4;
+    }
+  else
+    {
+      plen = strlen (pfx);
+      if (plen > 5)
+       plen = 5;
+    }
+
+  if (try_tmpdir)
+    {
+      d = __secure_getenv ("TMPDIR");
+      if (d != NULL && direxists (d))
+       dir = d;
+      else if (dir != NULL && direxists (dir))
+       /* nothing */ ;
+      else
+       dir = NULL;
+    }
+  if (dir == NULL)
+    {
+      if (direxists (P_tmpdir))
+       dir = P_tmpdir;
+      else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
+       dir = "/tmp";
+      else
+       {
+         __set_errno (ENOENT);
+         return -1;
+       }
+    }
+
+  dlen = strlen (dir);
+  while (dlen > 1 && dir[dlen - 1] == '/')
+    dlen--;                    /* remove trailing slashes */
+
+  /* check we have room for "${dir}/${pfx}XXXXXX\0" */
+  if (tmpl_len < dlen + 1 + plen + 6 + 1)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);
+  return 0;
+}
+#endif /* _LIBC */
+
+/* These are the characters used in temporary file names.  */
+static const char letters[] =
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Generate a temporary file name based on TMPL.  TMPL must match the
+   rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed
+   does not exist at the time of the call to __gen_tempname.  TMPL is
+   overwritten with the result.
+
+   KIND may be one of:
+   __GT_NOCREATE:      simply verify that the name does not exist
+                       at the time of the call.
+   __GT_FILE:          create the file using open(O_CREAT|O_EXCL)
+                       and return a read-write fd.  The file is mode 0600.
+   __GT_BIGFILE:       same as __GT_FILE but use open64().
+   __GT_DIR:           create a directory, which will be mode 0700.
+
+   We use a clever algorithm to get hard-to-predict names. */
+int
+__gen_tempname (char *tmpl, int kind)
+{
+  int len;
+  char *XXXXXX;
+  static uint64_t value;
+  uint64_t random_time_bits;
+  unsigned int count;
+  int fd = -1;
+  int save_errno = errno;
+  struct_stat64 st;
+
+  /* A lower bound on the number of temporary files to attempt to
+     generate.  The maximum total number of temporary file names that
+     can exist for a given template is 62**6.  It should never be
+     necessary to try all these combinations.  Instead if a reasonable
+     number of names is tried (we define reasonable as 62**3) fail to
+     give the system administrator the chance to remove the problems.  */
+#define ATTEMPTS_MIN (62 * 62 * 62)
+
+  /* The number of times to attempt to generate a temporary file.  To
+     conform to POSIX, this must be no smaller than TMP_MAX.  */
+#if ATTEMPTS_MIN < TMP_MAX
+  unsigned int attempts = TMP_MAX;
+#else
+  unsigned int attempts = ATTEMPTS_MIN;
+#endif
+
+  len = strlen (tmpl);
+  if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* This is where the Xs start.  */
+  XXXXXX = &tmpl[len - 6];
+
+  /* Get some more or less random data.  */
+#ifdef RANDOM_BITS
+  RANDOM_BITS (random_time_bits);
+#else
+  {
+    struct timeval tv;
+    __gettimeofday (&tv, NULL);
+    random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
+  }
+#endif
+  value += random_time_bits ^ __getpid ();
+
+  for (count = 0; count < attempts; value += 7777, ++count)
+    {
+      uint64_t v = value;
+
+      /* Fill in the random bits.  */
+      XXXXXX[0] = letters[v % 62];
+      v /= 62;
+      XXXXXX[1] = letters[v % 62];
+      v /= 62;
+      XXXXXX[2] = letters[v % 62];
+      v /= 62;
+      XXXXXX[3] = letters[v % 62];
+      v /= 62;
+      XXXXXX[4] = letters[v % 62];
+      v /= 62;
+      XXXXXX[5] = letters[v % 62];
+
+      switch (kind)
+       {
+       case __GT_FILE:
+         fd = small_open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+         break;
+
+       case __GT_BIGFILE:
+         fd = large_open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+         break;
+
+       case __GT_DIR:
+         fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
+         break;
+
+       case __GT_NOCREATE:
+         /* This case is backward from the other three.  __gen_tempname
+            succeeds if __xstat fails because the name does not exist.
+            Note the continue to bypass the common logic at the bottom
+            of the loop.  */
+         if (__lxstat64 (_STAT_VER, tmpl, &st) < 0)
+           {
+             if (errno == ENOENT)
+               {
+                 __set_errno (save_errno);
+                 return 0;
+               }
+             else
+               /* Give up now. */
+               return -1;
+           }
+         continue;
+
+       default:
+         assert (! "invalid KIND in __gen_tempname");
+       }
+
+      if (fd >= 0)
+       {
+         __set_errno (save_errno);
+         return fd;
+       }
+      else if (errno != EEXIST)
+       return -1;
+    }
+
+  /* We got out of the loop because we ran out of combinations to try.  */
+  __set_errno (EEXIST);
+  return -1;
+}
diff --git a/gnulib/tempname.h b/gnulib/tempname.h
new file mode 100644 (file)
index 0000000..c51fa69
--- /dev/null
@@ -0,0 +1,40 @@
+/* Create a temporary file or directory.
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* header written by Eric Blake */
+
+/* In gnulib, always prefer large files.  GT_FILE maps to
+   __GT_BIGFILE, not __GT_FILE, for a reason.  */
+#define GT_FILE                1
+#define GT_DIR         2
+#define GT_NOCREATE    3
+
+/* Generate a temporary file name based on TMPL.  TMPL must match the
+   rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed
+   does not exist at the time of the call to gen_tempname.  TMPL is
+   overwritten with the result.
+
+   KIND may be one of:
+   GT_NOCREATE:                simply verify that the name does not exist
+                       at the time of the call.
+   GT_FILE:            create a large file using open(O_CREAT|O_EXCL)
+                       and return a read-write fd.  The file is mode 0600.
+   GT_DIR:             create a directory, which will be mode 0700.
+
+   We use a clever algorithm to get hard-to-predict names. */
+extern int gen_tempname (char *tmpl, int kind);
diff --git a/gnulib/unistd_.h b/gnulib/unistd_.h
new file mode 100644 (file)
index 0000000..07c4877
--- /dev/null
@@ -0,0 +1,262 @@
+/* Substitute for and wrapper around <unistd.h>.
+   Copyright (C) 2004-2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _GL_UNISTD_H
+
+/* The include_next requires a split double-inclusion guard.  */
+#if @HAVE_UNISTD_H@
+# @INCLUDE_NEXT@ @NEXT_UNISTD_H@
+#endif
+
+#ifndef _GL_UNISTD_H
+#define _GL_UNISTD_H
+
+/* mingw doesn't define the SEEK_* macros in <unistd.h>.  */
+#if !(defined SEEK_CUR && defined SEEK_END && defined SEEK_SET)
+# include <stdio.h>
+#endif
+
+/* mingw fails to declare _exit in <unistd.h>.  */
+#include <stdlib.h>
+
+/* The definition of GL_LINK_WARNING is copied here.  */
+
+
+/* Declare overridden functions.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if @GNULIB_CHOWN@
+# if @REPLACE_CHOWN@
+#  ifndef REPLACE_CHOWN
+#   define REPLACE_CHOWN 1
+#  endif
+#  if REPLACE_CHOWN
+/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE
+   to GID (if GID is not -1).  Follow symbolic links.
+   Return 0 if successful, otherwise -1 and errno set.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/chown.html>.  */
+#   define chown rpl_chown
+extern int chown (const char *file, uid_t uid, gid_t gid);
+#  endif
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef chown
+# define chown(f,u,g) \
+    (GL_LINK_WARNING ("chown fails to follow symlinks on some systems and " \
+                      "doesn't treat a uid or gid of -1 on some systems - " \
+                      "use gnulib module chown for portability"), \
+     chown (f, u, g))
+#endif
+
+
+#if @GNULIB_DUP2@
+# if !@HAVE_DUP2@
+/* Copy the file descriptor OLDFD into file descriptor NEWFD.  Do nothing if
+   NEWFD = OLDFD, otherwise close NEWFD first if it is open.
+   Return 0 if successful, otherwise -1 and errno set.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/dup2.html>.  */
+extern int dup2 (int oldfd, int newfd);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef dup2
+# define dup2(o,n) \
+    (GL_LINK_WARNING ("dup2 is unportable - " \
+                      "use gnulib module dup2 for portability"), \
+     dup2 (o, n))
+#endif
+
+
+#if @GNULIB_FCHDIR@
+# if @REPLACE_FCHDIR@
+
+/* Change the process' current working directory to the directory on which
+   the given file descriptor is open.
+   Return 0 if successful, otherwise -1 and errno set.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/fchdir.html>.  */
+extern int fchdir (int /*fd*/);
+
+#  define close rpl_close
+extern int close (int);
+#  define dup rpl_dup
+extern int dup (int);
+#  define dup2 rpl_dup2
+extern int dup2 (int, int);
+
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef fchdir
+# define fchdir(f) \
+    (GL_LINK_WARNING ("fchdir is unportable - " \
+                      "use gnulib module fchdir for portability"), \
+     fchdir (f))
+#endif
+
+
+#if @GNULIB_FTRUNCATE@
+# if !@HAVE_FTRUNCATE@
+/* Change the size of the file to which FD is opened to become equal to LENGTH.
+   Return 0 if successful, otherwise -1 and errno set.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/ftruncate.html>.  */
+extern int ftruncate (int fd, off_t length);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef ftruncate
+# define ftruncate(f,l) \
+    (GL_LINK_WARNING ("ftruncate is unportable - " \
+                      "use gnulib module ftruncate for portability"), \
+     ftruncate (f, l))
+#endif
+
+
+#if @GNULIB_GETCWD@
+/* Include the headers that might declare getcwd so that they will not
+   cause confusion if included after this file.  */
+# include <stdlib.h>
+# if @REPLACE_GETCWD@
+/* Get the name of the current working directory, and put it in SIZE bytes
+   of BUF.
+   Return BUF if successful, or NULL if the directory couldn't be determined
+   or SIZE was too small.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/getcwd.html>.
+   Additionally, the gnulib module 'getcwd' guarantees the following GNU
+   extension: If BUF is NULL, an array is allocated with 'malloc'; the array
+   is SIZE bytes long, unless SIZE == 0, in which case it is as big as
+   necessary.  */
+#  define getcwd rpl_getcwd
+extern char * getcwd (char *buf, size_t size);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef getcwd
+# define getcwd(b,s) \
+    (GL_LINK_WARNING ("getcwd is unportable - " \
+                      "use gnulib module getcwd for portability"), \
+     getcwd (b, s))
+#endif
+
+
+#if @GNULIB_GETLOGIN_R@
+/* Copies the user's login name to NAME.
+   The array pointed to by NAME has room for SIZE bytes.
+
+   Returns 0 if successful.  Upon error, an error number is returned, or -1 in
+   the case that the login name cannot be found but no specific error is
+   provided (this case is hopefully rare but is left open by the POSIX spec).
+
+   See <http://www.opengroup.org/susv3xsh/getlogin.html>.
+ */
+# if !@HAVE_DECL_GETLOGIN_R@
+#  include <stddef.h>
+extern int getlogin_r (char *name, size_t size);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef getlogin_r
+# define getlogin_r(n,s) \
+    (GL_LINK_WARNING ("getlogin_r is unportable - " \
+                      "use gnulib module getlogin_r for portability"), \
+     getlogin_r (n, s))
+#endif
+
+
+#if @GNULIB_LCHOWN@
+# if @REPLACE_LCHOWN@
+/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE
+   to GID (if GID is not -1).  Do not follow symbolic links.
+   Return 0 if successful, otherwise -1 and errno set.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/lchown.html>.  */
+#  define lchown rpl_lchown
+extern int lchown (char const *file, uid_t owner, gid_t group);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef lchown
+# define lchown(f,u,g) \
+    (GL_LINK_WARNING ("lchown is unportable to pre-POSIX.1-2001 " \
+                      "systems - use gnulib module lchown for portability"), \
+     lchown (f, u, g))
+#endif
+
+
+#if @GNULIB_LSEEK@
+# if @REPLACE_LSEEK@
+/* Set the offset of FD relative to SEEK_SET, SEEK_CUR, or SEEK_END.
+   Return the new offset if successful, otherwise -1 and errno set.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/lseek.html>.  */
+#  define lseek rpl_lseek
+   extern off_t lseek (int fd, off_t offset, int whence);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef lseek
+# define lseek(f,o,w) \
+    (GL_LINK_WARNING ("lseek does not fail with ESPIPE on pipes on some " \
+                      "systems - use gnulib module lseek for portability"), \
+     lseek (f, o, w))
+#endif
+
+
+#if @GNULIB_READLINK@
+/* Read the contents of the symbolic link FILE and place the first BUFSIZE
+   bytes of it into BUF.  Return the number of bytes placed into BUF if
+   successful, otherwise -1 and errno set.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/readlink.html>.  */
+# if !@HAVE_READLINK@
+#  include <stddef.h>
+extern int readlink (const char *file, char *buf, size_t bufsize);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef readlink
+# define readlink(f,b,s) \
+    (GL_LINK_WARNING ("readlink is unportable - " \
+                      "use gnulib module readlink for portability"), \
+     readlink (f, b, s))
+#endif
+
+
+#if @GNULIB_SLEEP@
+/* Pause the execution of the current thread for N seconds.
+   Returns the number of seconds left to sleep.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/sleep.html>.  */
+# if !@HAVE_SLEEP@
+extern unsigned int sleep (unsigned int n);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef sleep
+# define sleep(n) \
+    (GL_LINK_WARNING ("sleep is unportable - " \
+                      "use gnulib module sleep for portability"), \
+     sleep (n))
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _GL_UNISTD_H */
+#endif /* _GL_UNISTD_H */
diff --git a/gnulib/wchar_.h b/gnulib/wchar_.h
new file mode 100644 (file)
index 0000000..924a338
--- /dev/null
@@ -0,0 +1,82 @@
+/* A substitute for ISO C99 <wchar.h>, for platforms that have issues.
+
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Eric Blake.  */
+
+/*
+ * ISO C 99 <wchar.h> for platforms that have issues.
+ * <http://www.opengroup.org/susv3xbd/wchar.h.html>
+ *
+ * For now, this just ensures proper prerequisite inclusion order and
+ * the declaration of wcwidth().
+ */
+
+#ifndef _GL_WCHAR_H
+
+/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
+   <wchar.h>.
+   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
+   included before <wchar.h>.  */
+#include <stddef.h>
+#include <stdio.h>
+#include <time.h>
+
+/* Include the original <wchar.h> if it exists.
+   Some builds of uClibc lack it.  */
+/* The include_next requires a split double-inclusion guard.  */
+#if @HAVE_WCHAR_H@
+# @INCLUDE_NEXT@ @NEXT_WCHAR_H@
+#endif
+
+#ifndef _GL_WCHAR_H
+#define _GL_WCHAR_H
+
+/* The definition of GL_LINK_WARNING is copied here.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Return the number of screen columns needed for WC.  */
+#if @GNULIB_WCWIDTH@
+# if @REPLACE_WCWIDTH@
+#  undef wcwidth
+#  define wcwidth rpl_wcwidth
+extern int wcwidth (wchar_t);
+# else
+#  if !defined wcwidth && !@HAVE_DECL_WCWIDTH@
+/* wcwidth exists but is not declared.  */
+extern int wcwidth (int /* actually wchar_t */);
+#  endif
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef wcwidth
+# define wcwidth(w) \
+    (GL_LINK_WARNING ("wcwidth is unportable - " \
+                      "use gnulib module wcwidth for portability"), \
+     wcwidth (w))
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GL_WCHAR_H */
+#endif /* _GL_WCHAR_H */
diff --git a/installcheck/Amanda_Changer.pl b/installcheck/Amanda_Changer.pl
new file mode 100644 (file)
index 0000000..d525fd6
--- /dev/null
@@ -0,0 +1,227 @@
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+use Test::More qw(no_plan);
+use Amconfig;
+use File::Path;
+use strict;
+
+use lib "@amperldir@";
+use Amanda::Paths;
+use Amanda::Device;
+use Amanda::Debug;
+use Amanda::Config qw( :init :getconf config_dir_relative );
+use Amanda::Changer;
+
+# set up debugging so debug output doesn't interfere with test results
+Amanda::Debug::dbopen("installcheck");
+
+my $changer_filename = "$AMANDA_TMPDIR/chg-test";
+
+sub setup_changer {
+    my ($changer_script) = @_;
+
+    open my $chg_test, ">", $changer_filename or die("Could not create test changer");
+    
+    $changer_script =~ s/\$AMANDA_TMPDIR/$AMANDA_TMPDIR/g;
+
+    print $chg_test "#! /bin/sh\n";
+    print $chg_test $changer_script;
+
+    close $chg_test;
+    chmod 0755, $changer_filename;
+}
+
+# set up and load a simple config with a tpchanger
+my $testconf = Amconfig->new();
+$testconf->add_param('tpchanger', "\"$changer_filename\"");
+$testconf->write();
+config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF') or die("Could not load test config");
+
+# some variables we'll need
+my ($error, $slot, $device);
+
+# OK, let's get started with some simple stuff
+setup_changer <<'EOC';
+case "${1}" in
+    -slot)
+        case "${2}" in
+            1) echo "1 fake:1"; exit 0;;
+            2) echo "<ignored> slot 2 is empty"; exit 1;;
+            3) echo "<error> oh noes!"; exit 2;;
+            4) echo "1"; exit 0;; # test missing 'device' portion
+        esac;;
+    -reset) echo "reset ignored";;
+    -eject) echo "eject ignored";;
+    -clean) echo "clean ignored";;
+    -label)
+        case "${2}" in
+            foo?bar) echo "1 ok"; exit 0;;
+            *) echo "<error> bad label"; exit 1;;
+        esac;;
+    -info) echo "7 10 1 1"; exit 0;;
+    -search) 
+        case "${2}" in
+            TAPE?01) echo "5 fakedev"; exit 0;;
+            *) echo "<error> not found"; exit 2;;
+        esac;;
+esac
+EOC
+
+is_deeply([ Amanda::Changer::loadslot(1) ], [0, "1", "fake:1"],
+    "A successful loadslot() returns the right stuff");
+
+($error, $slot, $device) = Amanda::Changer::loadslot(2);
+is($error, "slot 2 is empty", "A loadslot() with a benign error returns the right stuff");
+
+eval { Amanda::Changer::loadslot(3); };
+like($@, qr/.*oh noes!.*/, "A loadslot() with a serious error croaks");
+
+is_deeply([ Amanda::Changer::loadslot(4) ], [0, "1", undef],
+    "a response without a device string returns undef");
+
+is_deeply([ Amanda::Changer::reset() ], [ 0, "reset" ],
+    "reset() calls tapechanger -reset");
+is_deeply([ Amanda::Changer::eject() ], [ 0, "eject" ],
+    "eject() calls tapechanger -eject");
+is_deeply([ Amanda::Changer::clean() ], [ 0, "clean" ],
+    "clean() calls tapechanger -clean");
+
+is_deeply([ Amanda::Changer::label("foo bar") ], [ 0 ],
+    "label('foo bar') calls tapechanger -label 'foo bar' (note spaces)");
+
+is_deeply([ Amanda::Changer::query() ], [ 0, 7, 10, 1, 1 ],
+    "query() returns the correct values for a 4-value changer script");
+
+is_deeply([ Amanda::Changer::find("TAPE 01") ], [ 0, "5", "fakedev" ],
+    "find on a searchable changer invokes -search");
+
+eval { Amanda::Changer::find("TAPE 02") };
+ok($@, "A searchable changer croaks when the label can't be found");
+
+# Now a simple changer that returns three values for -info
+setup_changer <<'EOC';
+case "${1}" in
+    -info) echo "11 13 0"; exit 0;;
+esac
+EOC
+
+is_deeply([ Amanda::Changer::query() ], [ 0, 11, 13, 0, 0 ],
+    "query() returns the correct values for a 4-value changer script");
+
+# set up 5 vtapes
+for (my $i = 0; $i < 5; $i++) {
+    my $vtapedir = "$AMANDA_TMPDIR/chg-test-tapes/$i/data";
+    if (-e $vtapedir) {
+        rmtree($vtapedir) 
+            or die("Could not remove '$vtapedir'");
+    }
+    mkpath($vtapedir)
+        or die("Could not create '$vtapedir'");
+}
+
+# label three of them (slot 2 is empty; slot 4 is unlabeled)
+for (my $i = 0; $i < 5; $i++) {
+    next if $i == 2 || $i == 4;
+    my $dev = Amanda::Device->new("file:$AMANDA_TMPDIR/chg-test-tapes/$i")
+        or die("Could not open device");
+    $dev->start($Amanda::Device::ACCESS_WRITE, "TAPE$i", "19780615010203") 
+        or die("Could not write label");
+    $dev->finish();
+}
+
+# And finally a "stateful" changer that can support "scan" and "find"
+setup_changer <<'EOC';
+STATEFILE="$AMANDA_TMPDIR/chg-test-state"
+SLOT=0
+[ -f "$STATEFILE" ] && . "$STATEFILE"
+
+case "${1}" in
+    -slot)
+        case "${2}" in
+            current) ;;
+            0|1|2|3|4|5) SLOT="${2}";;
+            next|advance) SLOT=`expr $SLOT + 1`;;
+            prev) SLOT=`expr $SLOT - 1`;;
+            first) SLOT=0;;
+            last) SLOT=4;;
+        esac
+
+        # normalize 0 <= $SLOT  < 5
+        while [ "$SLOT" -ge 5 ]; do SLOT=`expr $SLOT - 5`; done
+        while [ "$SLOT" -lt 0 ]; do SLOT=`expr $SLOT + 5`; done
+
+        # signal an empty slot for slot 2
+        if [ "$SLOT" = 2 ]; then
+            echo "$SLOT slot $SLOT is empty"
+            EXIT=1
+        else
+            echo "$SLOT" "file:$AMANDA_TMPDIR/chg-test-tapes/$SLOT"
+        fi
+        ;;
+    -info) echo "$SLOT 5 1 0";;
+esac
+
+echo SLOT=$SLOT > $STATEFILE
+exit $EXIT
+EOC
+
+($error, $slot, $device) = Amanda::Changer::loadslot(0);
+if ($error) { die("Error loading slot 0: $error"); }
+is_deeply([ Amanda::Changer::find("TAPE3") ], [0, "3", "file:$AMANDA_TMPDIR/chg-test-tapes/3"],
+    "Finds a tape after skipping an empty slot");
+
+($error, $slot, $device) = Amanda::Changer::loadslot(3);
+if ($error) { die("Error loading slot 3: $error"); }
+is_deeply([ Amanda::Changer::find("TAPE1") ], [0, "1", "file:$AMANDA_TMPDIR/chg-test-tapes/1"],
+    "Finds a tape after skipping an unlabeled but filled slot");
+
+my @scanresults;
+sub cb {
+    fail("called too many times") if (!@scanresults);
+    my $expected = shift @scanresults;
+    my $descr = pop @$expected;
+    my $done = pop @$expected;
+    is_deeply([ @_ ], $expected, $descr);
+    return 1;
+}
+
+# scan the whole changer
+($error, $slot, $device) = Amanda::Changer::loadslot(0);
+if ($error) { die("Error loading slot 0: $error"); }
+@scanresults = (
+    [ "0", "file:$AMANDA_TMPDIR/chg-test-tapes/0", 0, 0, "scan starts with slot 0" ],
+    [ "1", "file:$AMANDA_TMPDIR/chg-test-tapes/1", 0, 0, "next in slot 1" ],
+    [ undef, undef, "slot 2 is empty",                0, "slot 2 is empty" ],
+    [ "3", "file:$AMANDA_TMPDIR/chg-test-tapes/3", 0, 0, "next in slot 3" ],
+    [ "4", "file:$AMANDA_TMPDIR/chg-test-tapes/4", 0, 0, "next in slot 4" ],
+);
+Amanda::Changer::scan(\&cb);
+
+# make sure it stops when "done"
+($error, $slot, $device) = Amanda::Changer::loadslot(0);
+if ($error) { die("Error loading slot 0: $error"); }
+@scanresults = (
+    [ "0", "file:$AMANDA_TMPDIR/chg-test-tapes/0", 0, 1, "scan starts with slot 0" ],
+);
+Amanda::Changer::scan(\&cb);
+
+# cleanup
+unlink("$AMANDA_TMPDIR/chg-test");
+unlink("$AMANDA_TMPDIR/chg-test-state");
+rmtree("$AMANDA_TMPDIR/chg-test-tapes");
diff --git a/installcheck/Amanda_Cmdline.pl b/installcheck/Amanda_Cmdline.pl
new file mode 100644 (file)
index 0000000..399101a
--- /dev/null
@@ -0,0 +1,106 @@
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+use Test::More qw( no_plan );
+
+use lib "@amperldir@";
+use Amanda::Paths;
+use Amanda::Cmdline;
+
+# convert a dumpspec_t object to an array, for easy is_deeply() comparisons
+sub ds2av {
+    my ($ds) = @_;
+    return (
+       $ds->{'host'},
+       $ds->{'disk'},
+       $ds->{'datestamp'},
+       $ds->{'level'},
+    );
+}
+
+# test dumpspec_t objects
+
+is_deeply([ ds2av(Amanda::Cmdline::dumpspec_t->new("h", "di", "ds", "l")) ],
+         [ "h", "di", "ds", "l" ],
+         "dumpspec_t constructor returns a valid dumpspec");
+
+is_deeply([ ds2av(Amanda::Cmdline::dumpspec_t->new("h", "di", "ds", undef)) ],
+         [ "h", "di", "ds", undef ],
+         "dumpspec_t constructor returns a valid dumpspec with only 3 args");
+
+is_deeply([ ds2av(Amanda::Cmdline::dumpspec_t->new("h", "di", undef, undef)) ],
+         [ "h", "di", undef, undef ],
+         "dumpspec_t constructor returns a valid dumpspec with only 2 args");
+
+is_deeply([ ds2av(Amanda::Cmdline::dumpspec_t->new("h", undef, undef, undef)) ],
+         [ "h", undef, undef, undef ],
+         "dumpspec_t constructor returns a valid dumpspec with only 1 arg");
+
+# TODO: test parse_dumpspecs
+my @specs;
+
+@specs = Amanda::Cmdline::parse_dumpspecs(["h1", "d1", "h2", "d2"], 0);
+is(@specs, 2, "parse of four elements with no flags yields 2 specs");
+is_deeply([ ds2av($specs[0]) ], [ "h1", "d1", undef, undef ], "..first spec is correct");
+is_deeply([ ds2av($specs[1]) ], [ "h2", "d2", undef, undef ], "..second spec is correct");
+
+@specs = Amanda::Cmdline::parse_dumpspecs(["h1", "d1", "ds1", "h2", "d2", "ds2" ], $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP);
+is(@specs, 2, "parse of six elements with CMDLINE_PARSE_DATESTAMP yields 2 specs");
+is_deeply([ ds2av($specs[0]) ], [ "h1", "d1", "ds1", undef ], "..first spec is correct");
+is_deeply([ ds2av($specs[1]) ], [ "h2", "d2", "ds2", undef ], "..second spec is correct");
+
+@specs = Amanda::Cmdline::parse_dumpspecs(["h1", "d1", "ds1", "lv1", "h2", "d2", "ds2", "lv2" ],
+               $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP | $Amanda::Cmdline::CMDLINE_PARSE_LEVEL);
+is(@specs, 2, "parse of eight elements with CMDLINE_PARSE_DATESTAMP and CMDLINE_PARSE_LEVEL yields 2 specs");
+is_deeply([ ds2av($specs[0]) ], [ "h1", "d1", "ds1", "lv1" ], "..first spec is correct");
+is_deeply([ ds2av($specs[1]) ], [ "h2", "d2", "ds2", "lv2" ], "..second spec is correct");
+
+@specs = Amanda::Cmdline::parse_dumpspecs(["h1", "d1", "ds1", "lv1" ],
+               $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP | $Amanda::Cmdline::CMDLINE_PARSE_LEVEL);
+is(@specs, 1, "parse of four elements with CMDLINE_PARSE_DATESTAMP and CMDLINE_PARSE_LEVEL yields one spec");
+is_deeply([ ds2av($specs[0]) ], [ "h1", "d1", "ds1", "lv1" ], "..which is correct");
+
+@specs = Amanda::Cmdline::parse_dumpspecs(["h1", "d1", "ds1" ],
+               $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP | $Amanda::Cmdline::CMDLINE_PARSE_LEVEL);
+is(@specs, 1, "parse of three elements with CMDLINE_PARSE_DATESTAMP and CMDLINE_PARSE_LEVEL yields one spec");
+is_deeply([ ds2av($specs[0]) ], [ "h1", "d1", "ds1", undef ], "..which is correct");
+
+@specs = Amanda::Cmdline::parse_dumpspecs(["h1", "d1" ],
+               $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP | $Amanda::Cmdline::CMDLINE_PARSE_LEVEL);
+is(@specs, 1, "parse of two elements with CMDLINE_PARSE_DATESTAMP and CMDLINE_PARSE_LEVEL yields one spec");
+is_deeply([ ds2av($specs[0]) ], [ "h1", "d1", undef, undef ], "..which is correct");
+
+@specs = Amanda::Cmdline::parse_dumpspecs(["h1" ],
+               $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP | $Amanda::Cmdline::CMDLINE_PARSE_LEVEL);
+is(@specs, 1, "parse of one element with CMDLINE_PARSE_DATESTAMP and CMDLINE_PARSE_LEVEL yields one spec");
+is_deeply([ ds2av($specs[0]) ], [ "h1", undef, undef, undef ], "..which is correct");
+
+@specs = Amanda::Cmdline::parse_dumpspecs([],
+               $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP | $Amanda::Cmdline::CMDLINE_PARSE_LEVEL);
+is(@specs, 0, "parse of no elements with CMDLINE_PARSE_DATESTAMP and CMDLINE_PARSE_LEVEL yields no specs");
+
+@specs = Amanda::Cmdline::parse_dumpspecs([],
+               $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP | $Amanda::Cmdline::CMDLINE_PARSE_LEVEL
+               | $Amanda::Cmdline::CMDLINE_EMPTY_TO_WILDCARD);
+is(@specs, 1, "parse of no elements with CMDLINE_EMPTY_TO_WILDCARD yields one spec");
+
+# test format_dumpspec_components
+
+is(Amanda::Cmdline::format_dumpspec_components("h", "di", "ds", "l"),
+   "h di ds l",
+   "format_dumpspec_components works ok");
diff --git a/installcheck/Amanda_Config.pl b/installcheck/Amanda_Config.pl
new file mode 100644 (file)
index 0000000..5a0bb22
--- /dev/null
@@ -0,0 +1,361 @@
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+use Test::More qw(no_plan);
+use Amconfig;
+use strict;
+
+use lib "@amperldir@";
+use Amanda::Paths;
+use Amanda::Config qw( :init :getconf );
+
+my $testconf;
+
+##
+# Try starting with no configuration at all
+ok(config_init(0, ''), "Initialize with no configuration");
+
+##
+# Parse up a basic configuration
+
+# invent "large" values for CONFTYPE_AM64 and CONFTYPE_SIZE
+my $am64_num = '171801575472'; # 0xA000B000C000 / 1024
+my $size_t_num = '2147483647'; # 0x7fffffff
+
+$testconf = Amconfig->new();
+$testconf->add_param('reserve', '75');
+$testconf->add_param('autoflush', 'yes');
+$testconf->add_param('tapedev', '"/dev/foo"');
+$testconf->add_param('bumpsize', $am64_num);
+$testconf->add_param('bumpmult', '1.4');
+$testconf->add_param('reserved-udp-port', '100,200');
+$testconf->add_param('device_output_buffer_size', $size_t_num);
+$testconf->add_param('taperalgo', 'last');
+$testconf->add_param('device_property', '"foo" "bar"');
+$testconf->add_param('device_property', '"blue" "car"');
+$testconf->add_param('displayunit', '"m"');
+$testconf->add_param('debug_auth', '1');
+$testconf->add_tapetype('mytapetype', [
+    'comment' => '"mine"',
+    'length' => '128 M',
+]);
+$testconf->add_dumptype('mydumptype', [
+    'comment' => '"mine"',
+    'priority' => 'high',  # == 2
+    'bumpsize' => $am64_num,
+    'bumpmult' => 1.75,
+    'starttime' => 1829,
+    'holdingdisk' => 'required',
+    'compress' => 'client best',
+    'encrypt' => 'server',
+    'strategy' => 'incronly',
+    'comprate' => '0.25,0.75',
+    'exclude list' => '"foo" "bar"',
+    'exclude list append' => '"true" "star"',
+    'exclude file' => '"foolist"',
+    'include list' => '"bing" "ting"',
+    'include list append' => '"string" "fling"',
+    'include file optional' => '"rhyme"',
+]);
+$testconf->add_interface('inyoface', [
+    'comment' => '"mine"',
+    'use' => '100',
+]);
+$testconf->add_interface('inherface', [
+    'comment' => '"empty"',
+]);
+$testconf->add_holdingdisk('hd1', [
+    'comment' => '"mine"',
+    'directory' => '"/mnt/hd1"',
+    'use' => '100M',
+    'chunksize' => '1024k',
+]);
+$testconf->add_holdingdisk('hd2', [
+    'comment' => '"empty"',
+]);
+$testconf->write();
+
+my $cfg_ok = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
+ok($cfg_ok, "Load test configuration");
+
+SKIP: {
+    skip "error loading config", unless $cfg_ok;
+
+    is(Amanda::Config::get_config_name(), "TESTCONF", 
+       "config_name set");
+    is(Amanda::Config::get_config_dir(), "$CONFIG_DIR/TESTCONF", 
+       "config_dir set");
+    is(Amanda::Config::get_config_filename(),
+       "$CONFIG_DIR/TESTCONF/amanda.conf", 
+       "config_filename set");
+}
+
+SKIP: { # global parameters
+    skip "error loading config", unless $cfg_ok;
+
+    is(getconf($CNF_RESERVE), 75,
+       "integer global confparm");
+    is(getconf($CNF_BUMPSIZE), $am64_num+0,
+       "am64 global confparm");
+    is(getconf($CNF_TAPEDEV), "/dev/foo",
+       "string global confparm");
+    is(getconf($CNF_DEVICE_OUTPUT_BUFFER_SIZE), $size_t_num+0,
+       "size global confparm");
+    ok(getconf($CNF_AUTOFLUSH),
+       "boolean global confparm");
+    is(getconf($CNF_TAPERALGO), $Amanda::Config::ALGO_LAST,
+       "taperalgo global confparam");
+    is_deeply([getconf($CNF_RESERVED_UDP_PORT)], [100,200],
+       "intrange global confparm");
+    is(getconf($CNF_DISPLAYUNIT), "M",
+       "displayunit is correctly uppercased");
+    is_deeply(getconf($CNF_DEVICE_PROPERTY),
+             { "foo" => "bar", "blue" => "car" },
+           "proplist global confparm");
+
+    ok(getconf_seen($CNF_TAPEDEV),
+       "'tapedev' parm was seen");
+    ok(!getconf_seen($CNF_NETUSAGE),
+       "'netusage' parm was not seen");
+}
+
+SKIP: { # derived values
+    skip "error loading config", unless $cfg_ok;
+
+    is(Amanda::Config::getconf_unit_divisor(), 1024, 
+       "correct unit divisor (from displayunit -> KB)");
+    ok($Amanda::Config::debug_auth, 
+       "debug_auth setting reflected in global variable");
+    ok(!$Amanda::Config::debug_amandad, 
+       "debug_amandad defaults to false");
+}
+
+SKIP: { # tapetypes
+    skip "error loading config", unless $cfg_ok;
+    my $ttyp = lookup_tapetype("mytapetype");
+    ok($ttyp, "found mytapetype");
+    is(tapetype_getconf($ttyp, $TAPETYPE_COMMENT), 'mine', 
+       "tapetype comment");
+    is(tapetype_getconf($ttyp, $TAPETYPE_LENGTH), 128 * 1024, 
+       "tapetype comment");
+
+    ok(tapetype_seen($ttyp, $TAPETYPE_COMMENT),
+       "tapetype comment was seen");
+    ok(!tapetype_seen($ttyp, $TAPETYPE_LBL_TEMPL),
+       "tapetype lbl_templ was not seen");
+
+    is_deeply([ sort(+getconf_list("tapetype")) ],
+             [ sort("mytapetype", "TEST-TAPE") ],
+       "getconf_list lists all tapetypes");
+}
+
+SKIP: { # dumptypes
+    skip "error loading config", unless $cfg_ok;
+
+    my $dtyp = lookup_dumptype("mydumptype");
+    ok($dtyp, "found mydumptype");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_COMMENT), 'mine', 
+       "dumptype string");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_PRIORITY), 2, 
+       "dumptype priority");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPSIZE), $am64_num+0,
+       "dumptype size");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPMULT), 1.75,
+       "dumptype real");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_STARTTIME), 1829,
+       "dumptype time");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_HOLDINGDISK), $HOLD_REQUIRED,
+       "dumptype holdingdisk");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_COMPRESS), $COMP_BEST,
+       "dumptype compress");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_ENCRYPT), $ENCRYPT_SERV_CUST,
+       "dumptype encrypt");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_STRATEGY), $DS_INCRONLY,
+       "dumptype strategy");
+    is_deeply([dumptype_getconf($dtyp, $DUMPTYPE_COMPRATE)], [0.25, 0.75],
+       "dumptype comprate");
+    is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_INCLUDE),
+       { 'file' => [ 'rhyme' ],
+         'list' => [ 'bing', 'ting', 'string', 'fling' ],
+         'optional' => 1 },
+       "dumptype include list");
+    is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_EXCLUDE),
+       { 'file' => [ 'foolist' ],
+         'list' => [ 'foo', 'bar', 'true', 'star' ],
+         'optional' => 0 },
+       "dumptype exclude list");
+
+    ok(dumptype_seen($dtyp, $DUMPTYPE_EXCLUDE),
+       "'exclude' parm was seen");
+    ok(!dumptype_seen($dtyp, $DUMPTYPE_RECORD),
+       "'record' parm was not seen");
+
+    is_deeply([ sort(+getconf_list("dumptype")) ],
+             [ sort(qw(
+               mydumptype
+               NO-COMPRESS COMPRESS-FAST COMPRESS-BEST COMPRESS-CUST
+               SRVCOMPRESS BSD-AUTH KRB4-AUTH NO-RECORD NO-HOLD
+               NO-FULL
+               )) ],
+       "getconf_list lists all dumptypes (including defaults)");
+}
+
+SKIP: { # interfaces
+    skip "error loading config" unless $cfg_ok;
+    my $iface = lookup_interface("inyoface");
+    ok($iface, "found inyoface");
+    is(interface_name($iface), "inyoface",
+       "interface knows its name");
+    is(interface_getconf($iface, $INTER_COMMENT), 'mine', 
+       "interface comment");
+    is(interface_getconf($iface, $INTER_MAXUSAGE), 100, 
+       "interface maxusage");
+
+    $iface = lookup_interface("inherface");
+    ok($iface, "found inherface");
+    ok(interface_seen($iface, $INTER_COMMENT),
+       "seen set for parameters that appeared");
+    ok(!interface_seen($iface, $INTER_MAXUSAGE),
+       "seen not set for parameters that did not appear");
+
+    is_deeply([ sort(+getconf_list("interface")) ],
+             [ sort('inyoface', 'inherface', 'default') ],
+       "getconf_list lists all interfaces (in any order)");
+}
+
+SKIP: { # holdingdisks
+    skip "error loading config" unless $cfg_ok;
+    my $hdisk = lookup_holdingdisk("hd1");
+    ok($hdisk, "found hd1");
+    is(holdingdisk_name($hdisk), "hd1",
+       "hd1 knows its name");
+    is(holdingdisk_getconf($hdisk, $HOLDING_COMMENT), 'mine', 
+       "holdingdisk comment");
+    is(holdingdisk_getconf($hdisk, $HOLDING_DISKDIR), '/mnt/hd1',
+       "holdingdisk diskdir (directory)");
+    is(holdingdisk_getconf($hdisk, $HOLDING_DISKSIZE), 100*1024, 
+       "holdingdisk disksize (use)");
+    is(holdingdisk_getconf($hdisk, $HOLDING_CHUNKSIZE), 1024, 
+       "holdingdisk chunksize");
+
+    $hdisk = lookup_holdingdisk("hd2");
+    ok($hdisk, "found hd2");
+    ok(holdingdisk_seen($hdisk, $HOLDING_COMMENT),
+       "seen set for parameters that appeared");
+    ok(!holdingdisk_seen($hdisk, $HOLDING_CHUNKSIZE),
+       "seen not set for parameters that did not appear");
+
+    # only holdingdisks have this linked-list structure
+    # exposed
+    $hdisk = getconf_holdingdisks();
+    like(holdingdisk_name($hdisk), qr/hd[12]/,
+       "one disk is first in list of holdingdisks");
+    $hdisk = holdingdisk_next($hdisk);
+    like(holdingdisk_name($hdisk), qr/hd[12]/,
+       "another is second in list of holdingdisks");
+    ok(!holdingdisk_next($hdisk),
+       "no third holding disk");
+
+    is_deeply([ sort(+getconf_list("holdingdisk")) ],
+             [ sort('hd1', 'hd2') ],
+       "getconf_list lists all holdingdisks (in any order)");
+}
+
+##
+# Test configuration dumping
+
+# (uses the config from the previous section)
+
+# fork a child and capture its stdout
+my $pid = open(my $kid, "-|");
+die "Can't fork: $!" unless defined($pid);
+if (!$pid) {
+    Amanda::Config::dump_configuration();
+    exit 1;
+}
+my $dump = join'', <$kid>;
+close $kid;
+
+my $fn = Amanda::Config::get_config_filename();
+like($dump, qr/AMANDA CONFIGURATION FROM FILE "$fn"/,
+    "config filename is included correctly");
+
+like($dump, qr/DEVICE_PROPERTY\s+"foo" "bar"\n/i,
+    "DEVICE_PROPERTY appears in dump output");
+
+like($dump, qr/AMRECOVER_CHECK_LABEL\s+(yes|no)/i,
+    "AMRECOVER_CHECK_LABEL has a trailing space");
+
+like($dump, qr/AMRECOVER_CHECK_LABEL\s+(yes|no)/i,
+    "AMRECOVER_CHECK_LABEL has a trailing space");
+
+like($dump, qr/EXCLUDE\s+LIST "foo" "bar" "true" "star"/i,
+    "EXCLUDE LIST is in the dump");
+like($dump, qr/EXCLUDE\s+FILE "foolist"/i,
+    "EXCLUDE FILE is in the dump");
+like($dump, qr/INCLUDE\s+LIST OPTIONAL "bing" "ting" "string" "fling"/i,
+    "INCLUDE LIST is in the dump");
+like($dump, qr/INCLUDE\s+FILE OPTIONAL "rhyme"/i,
+    "INCLUDE FILE is in the dump");
+
+##
+# Explore a quirk of exinclude parsing.  Only the last
+# exclude (or include) directive affects the 'optional' flag.
+# We may want to change this, but we should do so intentionally.
+# This is also tested by the 'amgetconf' installcheck.
+
+$testconf = Amconfig->new();
+$testconf->add_dumptype('mydumptype', [
+    'exclude list' => '"foo" "bar"',
+    'exclude list optional append' => '"true" "star"',
+    'exclude list append' => '"true" "star"',
+]);
+$testconf->write();
+
+$cfg_ok = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF");
+SKIP: {
+    skip "error loading config", unless $cfg_ok;
+
+    my $dtyp = lookup_dumptype("mydumptype");
+    ok($dtyp, "found mydumptype");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_EXCLUDE)->{'optional'}, 0,
+       "'optional' has no effect when not on the last occurrence");
+}
+
+$testconf = Amconfig->new();
+$testconf->add_dumptype('mydumptype', [
+    'exclude file' => '"foo" "bar"',
+    'exclude file optional append' => '"true" "star"',
+    'exclude list append' => '"true" "star"',
+]);
+$testconf->write();
+
+$cfg_ok = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF");
+SKIP: {
+    skip "error loading config", unless $cfg_ok;
+
+    my $dtyp = lookup_dumptype("mydumptype");
+    ok($dtyp, "found mydumptype");
+    is(dumptype_getconf($dtyp, $DUMPTYPE_EXCLUDE)->{'optional'}, 0,
+       "'optional' has no effect when not on the last occurrence of 'file'");
+}
+
+# TODO:
+# overwrites
+# inheritance
+# more init
diff --git a/installcheck/Amanda_Logfile.pl b/installcheck/Amanda_Logfile.pl
new file mode 100644 (file)
index 0000000..b6c6acd
--- /dev/null
@@ -0,0 +1,282 @@
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+use Test::More qw(no_plan);
+use File::Path;
+use Amconfig;
+use strict;
+
+use lib "@amperldir@";
+use Amanda::Paths;
+use Amanda::Tapefile;
+use Amanda::Logfile qw(:logtype_t :program_t open_logfile get_logline close_logfile);
+use Amanda::Config qw( :init :getconf config_dir_relative );
+
+# write a logfile and return the filename
+sub write_logfile {
+    my ($contents) = @_;
+    my $filename = "$AMANDA_TMPDIR/Amanda_Logfile_test.log";
+
+    if (!-e $AMANDA_TMPDIR) {
+       mkpath($AMANDA_TMPDIR);
+    }
+
+    open my $logfile, ">", $filename or die("Could not create temporary log file");
+    print $logfile $contents;
+    close $logfile;
+
+    return $filename;
+}
+
+####
+## RAW LOGFILE ACCESS
+
+my $logfile;
+my $logdata;
+
+##
+# Test out the constant functions
+
+is(logtype_t_to_string($L_MARKER), "L_MARKER", "logtype_t_to_string works");
+is(program_t_to_string($P_DRIVER), "P_DRIVER", "program_t_to_string works");
+
+##
+# Test a simple logfile
+
+$logdata = <<END;
+START planner date 20071026183200
+END
+
+$logfile = open_logfile(write_logfile($logdata));
+ok($logfile, "can open a simple logfile");
+is_deeply([ get_logline($logfile) ], 
+         [ $L_START, $P_PLANNER, "date 20071026183200" ],
+         "reads START line correctly");
+ok(!get_logline($logfile), "no second line");
+close_logfile($logfile);
+
+##
+# Test continuation lines
+
+$logdata = <<END;
+INFO chunker line1
+  line2
+END
+
+$logfile = open_logfile(write_logfile($logdata));
+ok($logfile, "can open a logfile containing conitinuation lines");
+is_deeply([ get_logline($logfile) ],
+         [ $L_INFO, $P_CHUNKER, "line1" ], 
+         "can read INFO line");
+is_deeply([ get_logline($logfile) ],
+         [ $L_CONT, $P_CHUNKER, "line2" ], 
+         "can read continuation line");
+ok(!get_logline($logfile), "no third line");
+close_logfile($logfile);
+
+##
+# Test skipping blank lines
+
+# (retain the two blank lines in the following:)
+$logdata = <<END;
+
+STATS taper foo
+
+END
+
+$logfile = open_logfile(write_logfile($logdata));
+ok($logfile, "can open a logfile containing blank lines");
+is_deeply([ get_logline($logfile) ], 
+         [ $L_STATS, $P_TAPER, "foo" ],
+         "reads non-blank line correctly");
+ok(!get_logline($logfile), "no second line");
+close_logfile($logfile);
+
+##
+# Test BOGUS values and short lines
+
+$logdata = <<END;
+SOMETHINGWEIRD somerandomprog bar
+MARKER amflush
+MARKER amflush put something in curstr
+PART
+END
+
+$logfile = open_logfile(write_logfile($logdata));
+ok($logfile, "can open a logfile containing bogus entries");
+is_deeply([ get_logline($logfile) ], 
+         [ $L_BOGUS, $P_UNKNOWN, "bar" ],
+         "can read line with bogus program and logtype");
+is_deeply([ get_logline($logfile) ], 
+         [ $L_MARKER, $P_AMFLUSH, "" ],
+         "can read line with an empty string");
+ok(get_logline($logfile), "can read third line (to fill in curstr with some text)");
+is_deeply([ get_logline($logfile) ], 
+         [ $L_PART, $P_UNKNOWN, "" ],
+         "can read a one-word line, with P_UNKNOWN");
+ok(!get_logline($logfile), "no next line");
+close_logfile($logfile);
+
+## HIGHER-LEVEL FUNCTIONS
+
+# a utility function for is_deeply checks, below.  Converts a hash to
+# an array, for more succinct comparisons
+sub res2arr {
+    my ($res) = @_;
+    return [
+       $res->{'timestamp'},
+       $res->{'hostname'},
+       $res->{'diskname'},
+       $res->{'level'},
+       $res->{'label'},
+       $res->{'filenum'},
+       $res->{'status'},
+       $res->{'partnum'}
+    ];
+}
+
+# set up a basic config
+my $testconf = Amconfig->new();
+$testconf->add_param("tapecycle", "20");
+$testconf->write();
+
+# load the config
+ok(config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"), "config_init is OK");
+my $tapelist = config_dir_relative("tapelist");
+
+# set up and read the tapelist
+open my $tlf, ">", $tapelist or die("Could not write tapelist");
+print $tlf "20071111010002 TESTCONF004 reuse\n";
+print $tlf "20071110010002 TESTCONF003 reuse\n";
+print $tlf "20071109010002 TESTCONF002 reuse\n";
+print $tlf "20071108010001 TESTCONF001 reuse\n";
+close $tlf;
+Amanda::Tapefile::read_tapelist($tapelist) == 0 or die("Could not read tapelist");
+
+# set up a number of logfiles in logdir.
+my $logf;
+my $logdir = $testconf->{'logdir'};
+
+# (an old log file that should be ignored)
+open $logf, ">", "$logdir/log.20071106010002.0" or die("Could not write logfile");
+print $logf "START taper datestamp 20071107010002 label TESTCONF017 tape 1\n";
+close $logf;
+
+# (a logfile with two tapes)
+open $logf, ">", "$logdir/log.20071106010002.0" or die("Could not write logfile");
+print $logf "START taper datestamp 20071106010002 label TESTCONF018 tape 1\n";
+print $logf "START taper datestamp 20071106010002 label TESTCONF019 tape 2\n";
+close $logf;
+
+open $logf, ">", "$logdir/log.20071108010001.0" or die("Could not write logfile");
+print $logf "START taper datestamp 20071108010001 label TESTCONF001 tape 1\n";
+close $logf;
+
+# a logfile with some detail, to run search_logfile against
+open $logf, ">", "$logdir/log.20071109010002.0" or die("Could not write logfile");
+print $logf <<EOF;
+START taper datestamp 20071109010002 label TESTCONF002 tape 1
+PART taper TESTCONF002 1 clihost /usr 20071109010002 1 0 [regular single part PART]
+DONE taper clihost /usr 20071109010002 1 0 [regular single part DONE]
+PART taper TESTCONF002 2 clihost "/my documents" 20071109010002 1 0 [diskname quoting]
+DONE taper clihost "/my documents" 20071109010002 1 0 [diskname quoting]
+PART taper TESTCONF002 3 thatbox /var 1 [regular 'old style' PART]
+DONE taper thatbox /var 1 [regular 'old style' DONE]
+PART taper TESTCONF002 4 clihost /home 20071109010002 1/5 0 [multi-part dump]
+PART taper TESTCONF002 5 clihost /home 20071109010002 2/5 0 [multi-part dump]
+PART taper TESTCONF002 6 clihost /home 20071109010002 3/5 0 [multi-part dump]
+PART taper TESTCONF002 7 clihost /home 20071109010002 4/5 0 [multi-part dump]
+PART taper TESTCONF002 8 clihost /home 20071109010002 5/5 0 [multi-part dump]
+DONE taper clihost /home 20071109010002 5 0 [multi-part dump]
+PART taper TESTCONF002 9 thatbox /u_lose 20071109010002 1/4 2 [multi-part failure]
+PART taper TESTCONF002 10 thatbox /u_lose 20071109010002 2/4 2 [multi-part failure]
+PART taper TESTCONF002 11 thatbox /u_lose 20071109010002 3/4 2 [multi-part failure]
+FAIL taper thatbox /u_lose 20071109010002 2 "Oh no!"
+DONE taper thatbox /u_lose 20071109010002 4 2 [multi-part failure]
+EOF
+close $logf;
+
+# "old-style amflush log"
+open $logf, ">", "$logdir/log.20071110010002.amflush" or die("Could not write logfile");
+print $logf "START taper datestamp 20071110010002 label TESTCONF003 tape 1\n";
+close $logf;
+
+# "old-style main log"
+open $logf, ">", "$logdir/log.20071111010002" or die("Could not write logfile");
+print $logf "START taper datestamp 20071111010002 label TESTCONF004 tape 1\n";
+close $logf;
+
+is_deeply([ Amanda::Logfile::find_log() ],
+         [ "log.20071111010002", "log.20071110010002.amflush",
+           "log.20071109010002.0", "log.20071108010001.0" ],
+         "find_log returns correct logfiles in the correct order");
+
+my @results;
+my @results_arr;
+
+@results = Amanda::Logfile::search_logfile("TESTCONF002", "20071109010002",
+                                          "$logdir/log.20071109010002.0", 1);
+is($#results+1, 11, "search_logfile returned 11 results");
+
+# sort by filenum so we can compare each to what it should be
+@results = sort { $a->{'filenum'} <=> $b->{'filenum'} } @results;
+
+# and convert the hashes to arrays for easy comparison
+@results_arr = map { res2arr($_) } @results;
+
+is_deeply(\@results_arr,
+       [ [ '20071109010002', 'clihost', '/usr',            0, 'TESTCONF002', 1,  'OK', '1'   ],
+         [ '20071109010002', 'clihost', '/my documents',   0, 'TESTCONF002', 2,  'OK', '1'   ],
+         [ '20071109010002', 'thatbox', '/var',            1, 'TESTCONF002', 3,  'OK', '--'  ],
+         [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 4,  'OK', '1/5' ],
+         [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 5,  'OK', '2/5' ],
+         [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 6,  'OK', '3/5' ],
+         [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 7,  'OK', '4/5' ],
+         [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 8,  'OK', '5/5' ],
+         [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 9,  '"Oh no!"', '1/4' ],
+         [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 10, '"Oh no!"', '2/4' ],
+         [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 11, '"Oh no!"', '3/4' ] ],
+         "results are correct");
+
+my @filtered;
+my @filtered_arr;
+
+@filtered = Amanda::Logfile::dumps_match([@results], "thatbox", undef, undef, undef, 0);
+is($#filtered+1, 4, "four results match 'thatbox'");
+@filtered = sort { $a->{'filenum'} <=> $b->{'filenum'} } @filtered;
+
+@filtered_arr = map { res2arr($_) } @filtered;
+
+is_deeply(\@filtered_arr,
+       [ [ '20071109010002', 'thatbox', '/var',      1, 'TESTCONF002', 3,  'OK',       '--' ],
+         [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 9,  '"Oh no!"', '1/4' ],
+         [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 10, '"Oh no!"', '2/4' ],
+         [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 11, '"Oh no!"', '3/4' ] ],
+         "results are  correct");
+
+@filtered = Amanda::Logfile::dumps_match([@results], "thatbox", "/var", undef, undef, 0);
+is($#filtered+1, 1, "only one result matches 'thatbox:/var'");
+
+@filtered = Amanda::Logfile::dumps_match([@results], undef, undef, "20071109010002", undef, 0);
+is($#filtered+1, 11, "all 11 results match '20071109010002'");
+
+@filtered = Amanda::Logfile::dumps_match([@results], undef, undef, "20071109010002", undef, 1);
+is($#filtered+1, 8, "of those, 8 results are 'OK'");
+
+@filtered = Amanda::Logfile::dumps_match([@results], undef, undef, undef, "2", 0);
+is($#filtered+1, 3, "3 results are at level 2");
diff --git a/installcheck/Amanda_Types.pl b/installcheck/Amanda_Types.pl
new file mode 100644 (file)
index 0000000..a301f80
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+use Test::More qw(no_plan);
+use Amconfig;
+use strict;
+
+use lib "@amperldir@";
+use Amanda::Types;
+
+# Not much to test, but we can at least exercise the constructor and destructor,
+# and the SWIG getters and setters:
+ok(my $df = Amanda::Types::dumpfile_t->new(), "can create a dumpfile_t");
+is($df->{'datestamp'}, '', "newly created dumpfile_t has empty datestamp");
+ok($df->{'name'} = "myhost", "can write to a string in the header");
+is($df->{'name'}, "myhost", "..and get it back");
diff --git a/installcheck/Amconfig.pm.in b/installcheck/Amconfig.pm.in
new file mode 100644 (file)
index 0000000..c2b78fd
--- /dev/null
@@ -0,0 +1,302 @@
+# vim:ft=perl
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+package Amconfig;
+use File::Path;
+use Carp;
+
+=head1 NAME
+
+Amconfig - set up amanda configurations for installcheck testing
+
+=head1 SYNOPSIS
+
+  use Amconfig;
+
+  my $testconf = Amconfig->new();
+  $testconf->add_param("runtapes", "5");
+  $testconf->add_subsec("tapetype", "DUCKTAPE", { length => "10G", filemark => "4096k" });
+  # ...
+  $testconf->write();
+
+The resulting configuration is always named "TESTCONF".  The basic
+configuration contains only a few parameters that are necessary just
+to run Amanda applications in the test environment.  It also contains
+a tapetype, C<TEST-TAPE>.
+
+Note that it's quite possible to produce an invalid configuration with this
+package (and, in fact, some of the tests do just that).
+
+=head2 VTAPES
+
+This module can set up a vtape configuration, replete with the proper
+vtape directories, using C<setup_vtape>.  The vtapes are created under
+the "TESTCONF" configuration directory, for ease of later deletion.  Do
+not store anything large in these vtapes!
+
+=head1 WARNING
+
+Using this module I<will> destroy any existing configuration named
+TESTDIR.  I<Please> do not use this on a production machine!
+
+=head1 FUNCTIONS
+
+=over
+
+=item C<new()>
+
+Create a new configuration object
+
+=cut
+
+sub new {
+    my $class = shift;
+
+    # An instance is a blessed hash containing parameters.  Start with
+    # some defaults to make sure things run.
+    my $infofile = '@CONFIG_DIR@/TESTCONF/curinfo';
+    my $logdir = '@CONFIG_DIR@/TESTCONF/log';
+    my $indexdir = '@CONFIG_DIR@/TESTCONF/index';
+
+    my $self = {
+       'infofile' => $infofile,
+       'logdir' => $logdir,
+       'indexdir' => $indexdir,
+
+       'vtapes' => [],
+
+       # Global params are stored as an arrayref, so that the same declaration
+       # can appear multiple times
+       'params' => [
+           'mailto' => '"nobody@invalidomain"',
+           'dumpuser' => '"' . (getpwuid($<))[0] . '"', # current username
+
+           # These dirs are under CONFIG_DIR just for ease of destruction.
+           # This is not a recommended layout!
+           'infofile' => "\"$infofile\"",
+           'logdir' => "\"$logdir\"",
+           'indexdir' => "\"$indexdir\"",
+
+           'tapetype' => '"TEST-TAPE"',
+       ],
+
+       # Subsections are stored as a hashref of arrayrefs, keyed by
+       # subsection name
+
+       'tapetypes' => {
+           'TEST-TAPE' => [
+               'length' => '50 mbytes',
+               'filemark' => '4 kbytes'
+           ],
+       },
+
+       'dumptypes' => { },
+
+       'interfaces' => { },
+
+       'holdingdisks' => { },
+
+       'dles' => [ ],
+    };
+    bless($self, $class);
+    return $self;
+}
+
+=item C<add_param($param, $value)>
+
+Add the given parameter to the configuration file, overriding any
+previous value.  Note that strings which should be quoted in the configuration
+file itself must be double-quoted here, e.g.,
+
+  $testconf->add_param('org' => '"MyOrganization"');
+
+=cut
+
+sub add_param {
+    my $self = shift;
+    my ($param, $value) = @_;
+
+    push @{$self->{'params'}}, $param, $value;
+}
+
+=item C<add_tapetype($name, $values_hashref)>
+=item C<add_dumptype($name, $values_hashref)>
+=item C<addholdingdisk($name, $values_hashref)>
+=item C<add_interface($name, $values_arrayref)>
+
+Add the given subsection to the configuration file, including all
+values in the arrayref.  The values should be specified as alternating
+key/value pairs.
+
+=cut
+
+sub add_tapetype {
+    my $self = shift;
+    my ($name, $values_arrayref) = @_;
+    $self->{'tapetypes'}{$name} = $values_arrayref;
+}
+
+sub add_dumptype {
+    my $self = shift;
+    my ($name, $values_arrayref) = @_;
+    $self->{'dumptypes'}{$name} = $values_arrayref;
+}
+
+sub add_holdingdisk {
+    my $self = shift;
+    my ($name, $values_arrayref) = @_;
+    $self->{'holdingdisks'}{$name} = $values_arrayref;
+}
+
+sub add_interface {
+    my $self = shift;
+    my ($name, $values_arrayref) = @_;
+    $self->{'interfaces'}{$name} = $values_arrayref;
+}
+
+=item C<add_dle($line)>
+
+Add a disklist entry; C<$line> is inserted verbatim into the disklist.
+
+=cut
+
+sub add_dle {
+    my $self = shift;
+    my ($line) = @_;
+    push @{$self->{'dles'}}, $line;
+}
+
+=item C<setup_vtape()>
+
+Set up to use a single vtape (no changer).  This creates the proper
+directory hierarchy and sets C<tapedev> to the relevant path.
+
+=cut
+
+sub setup_vtape {
+    my $self = shift;
+    my $tapepath = "@CONFIG_DIR@/TESTCONF/vtapes/tape1";
+    push @{$self->{'vtapes'}}, $tapepath;
+    
+    $self->add_param("tapedev", "\"file:$tapepath\"");
+}
+
+=item C<write()>
+
+Write out the accumulated configuration file, along with any other
+files necessary to run Amanda.
+
+=cut
+
+sub write {
+    my $self = shift;
+
+    my $testconf_dir = '@CONFIG_DIR@/TESTCONF';
+    if (-e $testconf_dir) {
+       rmtree($testconf_dir) or die("Could not remove '$testconf_dir'");
+    }
+    mkpath($testconf_dir);
+
+    # set up curinfo dir, etc.
+    mkpath($self->{'infofile'}) or die("Could not create infofile directory");
+    mkpath($self->{'logdir'}) or die("Could not create logdir directory");
+    mkpath($self->{'indexdir'}) or die("Could not create indexdir directory");
+
+    # create any vtapes
+    for my $vtape (@{$self->{'vtapes'}}) {
+       mkpath("$vtape/data") or die("Could not create vtape directory '$vtape/data'");
+    }
+
+    $self->_write_tapelist("$testconf_dir/tapelist");
+    $self->_write_disklist("$testconf_dir/disklist");
+    $self->_write_amanda_conf("$testconf_dir/amanda.conf");
+}
+
+sub _write_tapelist {
+    my $self = shift;
+    my ($filename) = @_;
+
+    # create an empty tapelist
+    open(my $tapelist, ">", $filename);
+    close($tapelist);
+}
+
+sub _write_disklist {
+    my $self = shift;
+    my ($filename) = @_;
+
+    # don't bother writing a disklist if there are no dle's
+    return unless $self->{'dles'};
+
+    open(my $disklist, ">", $filename);
+
+    for my $dle_line (@{$self->{'dles'}}) {
+       print $disklist "$dle_line\n";
+    }
+
+    close($disklist);
+}
+
+sub _write_amanda_conf {
+    my $self = shift;
+    my ($filename) = @_;
+
+    open my $amanda_conf, ">", $filename
+       or croak("Could not open '$filename'");
+
+    # write key/value pairs
+    my @params = @{$self->{'params'}};
+    while (@params) {
+       $param = shift @params;
+       $value = shift @params;
+       print $amanda_conf "$param $value\n";
+    }
+
+    # write out subsections
+    $self->_write_amanda_conf_subsection($amanda_conf, "tapetype", $self->{"tapetypes"});
+    $self->_write_amanda_conf_subsection($amanda_conf, "dumptype", $self->{"dumptypes"});
+    $self->_write_amanda_conf_subsection($amanda_conf, "interface", $self->{"interfaces"});
+    $self->_write_amanda_conf_subsection($amanda_conf, "holdingdisk", $self->{"holdingdisks"});
+
+    close($amanda_conf);
+}
+
+sub _write_amanda_conf_subsection {
+    my $self = shift;
+    my ($amanda_conf, $subsec_type, $subsec_ref) = @_;
+
+    for my $subsec_name (keys %$subsec_ref) {
+       my @values = @{$subsec_ref->{$subsec_name}};
+       
+       if ($subsec_type eq "holdingdisk") {
+           print $amanda_conf "\nholdingdisk $subsec_name {\n";
+       } else {
+           print $amanda_conf "\ndefine $subsec_type $subsec_name {\n";
+       }
+
+       while (@values) {
+           $param = shift @values;
+           $value = shift @values;
+           print $amanda_conf "$param $value\n";
+       }
+       print $amanda_conf "}\n";
+    }
+}
+
+1;
diff --git a/installcheck/Makefile.am b/installcheck/Makefile.am
new file mode 100644 (file)
index 0000000..bb3e938
--- /dev/null
@@ -0,0 +1,59 @@
+# Note that this architecture assumes a full install -- not just server
+# or just client.  Neither is sufficiently test-able on its own.
+
+include $(top_srcdir)/config/automake/vars.am
+include $(top_srcdir)/config/automake/scripts.am
+
+# Add your tests here.
+
+common_tests = \
+       Amanda_Config \
+       Amanda_Types
+
+server_tests = \
+       Amanda_Changer \
+       Amanda_Cmdline \
+       Amanda_Logfile \
+       amcheckdump \
+       amdevcheck \
+       amgetconf
+
+tests = $(common_tests)
+if WANT_SERVER
+tests += $(server_tests)
+endif
+
+# Add any common files (that should not be run as tests) here:
+test_utils = Amconfig.pm
+
+SCRIPTS_PERL = $(common_tests) $(server_tests) $(test_utils)
+
+# we don't need to syntax check the test scripts..
+CHECK_PERL =
+
+.PHONY: clobber_my_config_is_ok
+clobber_my_config_is_ok:
+       @if test "$(CLOBBER_MY_CONFIG)" != "OK"; then \
+               echo ""; \
+               echo "'make installcheck' is a dangerous tool.  It will overwrite your"; \
+               echo "amanda-client.conf and amandates, and (if it"; \
+               echo "triggers an as-yet undetected bug) may do other unexpected things.  You are"; \
+               echo "strongly encouraged"; \
+               echo "  - not to run installchecks on a production install"; \
+               echo "  - not to run installchecks as root"; \
+               echo "See http://wiki.zmanda.com/index.php/Testing for instructions on setting up a"; \
+               echo "test environment in which"; \
+               echo "potential damage is limited by your filesystem's permissions.  To actually run"; \
+               echo "the installchecks, invoke make"; \
+               echo "as follows:"; \
+               echo "  $(MAKE) CLOBBER_MY_CONFIG=OK installcheck"; \
+               exit 1; \
+       fi
+
+installcheck-local: clobber_my_config_is_ok $(SCRIPTS_PERL)
+       $(mkdir_p) $(AMANDA_TMPDIR)
+       $(PERL) -I$(srcdir) -I$(builddir) -e 'use Test::Harness qw(&runtests); runtests(@ARGV);' $(tests)
+       rm -rf "$(CONFIG_DIR)/TESTCONF"
+       rm -rf "$(CONFIG_DIR)/amanda-client.conf"
+       rm -rf "$(DEFAULT_AMANDATES_FILE)"
+       rm -rf "$(GNUTAR_LISTED_INCREMENTAL_DIR)"
diff --git a/installcheck/Makefile.in b/installcheck/Makefile.in
new file mode 100644 (file)
index 0000000..afbc373
--- /dev/null
@@ -0,0 +1,959 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Note that this architecture assumes a full install -- not just server
+# or just client.  Neither is sufficiently test-able on its own.
+
+# vim:ft=automake
+# Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+# 
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License version 2.1 as 
+# published by the Free Software Foundation.
+# 
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+# 
+# Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+# simple include file to pre-define variables which are then +='d by other
+# scripts in this directory.
+
+# vim:ft=automake
+# Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+# 
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License version 2.1 as 
+# published by the Free Software Foundation.
+# 
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+# 
+# Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+# SYNOPSIS:
+#
+# Automake magic to handle the various tasks of building scripts.  Scripts can
+# be built down to extensionless executables (e.g., foo.pl -> foo), or to 
+# files with the usual extension (foo-lib.sh.in -> foo.sh).
+#
+# Files which support it are syntax-checked when the user invokes 'make check'.
+#
+# All *target* filenames must be listed in SCRIPTS_SHELL, SCRIPTS_PERL, and 
+# SCRIPTS_AWK to support 'make check', 'make dist', and 'make distclean'.
+#
+# USAGE:
+#
+#   include $(top_srcdir)/config/automake/vars.am
+#   include $(top_srcdir)/config/automake/scripts.am
+#   ...
+#   SCRIPTS_PERL = fooscript barscript perl-lib.pl perlmod.pm
+#   SCRIPTS_SHELL = shell1 shell2 sh-lib.sh
+#   SCRIPTS_AWK = talk balk chalk awk-lib.awk
+#
+# with the corresponding files in the repository:
+#
+#   fooscript.pl barscript.pl perl-lib.pl.in perlmod.pm.in
+#   shell1.sh shell2.sh sh-lib.sh.in
+#   talk.awk balk.awk chalk.awk awk-lib.awk.in
+#
+# by default, all shell and perl scripts are syntax checked.  If this is
+# a problem (for example, perl scripts depending on Amanda extension 
+# modules), then assign to CHECK_{PERL,SHELL} the list of files you wish
+# to be checked (which can be empty).
+#
+# To add extra flags to the perl checks (e.g., to add new -I flags), set
+# CHECK_PERL_FLAGS.
+
+# Implementation note:
+#
+# This file uses config.status to substitute @foo@ in those scripts while
+# converting them. It also adds the executable bits (a+x) to extensionless
+# files.  The substitution works even though the files are not listed in 
+# configure.in
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(top_srcdir)/config/automake/scripts.am \
+       $(top_srcdir)/config/automake/vars.am
+@WANT_SERVER_TRUE@am__append_1 = $(server_tests)
+subdir = installcheck
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps =  \
+       $(top_srcdir)/config/macro-archive/ac_define_dir.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_perl_version.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_swig.m4 \
+       $(top_srcdir)/config/macro-archive/ax_compare_version.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-dtd.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt-min.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt.m4 \
+       $(top_srcdir)/config/macro-archive/xsltproc.m4 \
+       $(top_srcdir)/config/amanda/amplot.m4 \
+       $(top_srcdir)/config/amanda/bsd-security.m4 \
+       $(top_srcdir)/config/amanda/bsdtcp-security.m4 \
+       $(top_srcdir)/config/amanda/bsdudp-security.m4 \
+       $(top_srcdir)/config/amanda/changer.m4 \
+       $(top_srcdir)/config/amanda/components.m4 \
+       $(top_srcdir)/config/amanda/compress.m4 \
+       $(top_srcdir)/config/amanda/config.m4 \
+       $(top_srcdir)/config/amanda/debugging.m4 \
+       $(top_srcdir)/config/amanda/defaults.m4 \
+       $(top_srcdir)/config/amanda/devprefix.m4 \
+       $(top_srcdir)/config/amanda/dirs.m4 \
+       $(top_srcdir)/config/amanda/documentation.m4 \
+       $(top_srcdir)/config/amanda/dumpers.m4 \
+       $(top_srcdir)/config/amanda/flags.m4 \
+       $(top_srcdir)/config/amanda/flock.m4 \
+       $(top_srcdir)/config/amanda/funcs.m4 \
+       $(top_srcdir)/config/amanda/getfsent.m4 \
+       $(top_srcdir)/config/amanda/i18n.m4 \
+       $(top_srcdir)/config/amanda/ipv6.m4 \
+       $(top_srcdir)/config/amanda/krb4-security.m4 \
+       $(top_srcdir)/config/amanda/krb5-security.m4 \
+       $(top_srcdir)/config/amanda/lfs.m4 \
+       $(top_srcdir)/config/amanda/libs.m4 \
+       $(top_srcdir)/config/amanda/net.m4 \
+       $(top_srcdir)/config/amanda/progs.m4 \
+       $(top_srcdir)/config/amanda/readdir.m4 \
+       $(top_srcdir)/config/amanda/readline.m4 \
+       $(top_srcdir)/config/amanda/rsh-security.m4 \
+       $(top_srcdir)/config/amanda/s3-device.m4 \
+       $(top_srcdir)/config/amanda/shmem.m4 \
+       $(top_srcdir)/config/amanda/socklen_t_equiv.m4 \
+       $(top_srcdir)/config/amanda/ssh-security.m4 \
+       $(top_srcdir)/config/amanda/summary.m4 \
+       $(top_srcdir)/config/amanda/swig.m4 \
+       $(top_srcdir)/config/amanda/syshacks.m4 \
+       $(top_srcdir)/config/amanda/tape.m4 \
+       $(top_srcdir)/config/amanda/types.m4 \
+       $(top_srcdir)/config/amanda/userid.m4 \
+       $(top_srcdir)/config/amanda/version.m4 \
+       $(top_srcdir)/config/gnulib/alloca.m4 \
+       $(top_srcdir)/config/gnulib/arpa_inet_h.m4 \
+       $(top_srcdir)/config/gnulib/base64.m4 \
+       $(top_srcdir)/config/gnulib/eoverflow.m4 \
+       $(top_srcdir)/config/gnulib/extensions.m4 \
+       $(top_srcdir)/config/gnulib/float_h.m4 \
+       $(top_srcdir)/config/gnulib/fsusage.m4 \
+       $(top_srcdir)/config/gnulib/getaddrinfo.m4 \
+       $(top_srcdir)/config/gnulib/gettimeofday.m4 \
+       $(top_srcdir)/config/gnulib/gnulib-comp.m4 \
+       $(top_srcdir)/config/gnulib/include_next.m4 \
+       $(top_srcdir)/config/gnulib/inet_ntop.m4 \
+       $(top_srcdir)/config/gnulib/intmax_t.m4 \
+       $(top_srcdir)/config/gnulib/lock.m4 \
+       $(top_srcdir)/config/gnulib/longlong.m4 \
+       $(top_srcdir)/config/gnulib/malloc.m4 \
+       $(top_srcdir)/config/gnulib/mkdtemp.m4 \
+       $(top_srcdir)/config/gnulib/netinet_in_h.m4 \
+       $(top_srcdir)/config/gnulib/onceonly_2_57.m4 \
+       $(top_srcdir)/config/gnulib/physmem.m4 \
+       $(top_srcdir)/config/gnulib/safe-read.m4 \
+       $(top_srcdir)/config/gnulib/safe-write.m4 \
+       $(top_srcdir)/config/gnulib/snprintf.m4 \
+       $(top_srcdir)/config/gnulib/socklen.m4 \
+       $(top_srcdir)/config/gnulib/sockpfaf.m4 \
+       $(top_srcdir)/config/gnulib/ssize_t.m4 \
+       $(top_srcdir)/config/gnulib/stdbool.m4 \
+       $(top_srcdir)/config/gnulib/stdint.m4 \
+       $(top_srcdir)/config/gnulib/stdio_h.m4 \
+       $(top_srcdir)/config/gnulib/stdlib_h.m4 \
+       $(top_srcdir)/config/gnulib/strdup.m4 \
+       $(top_srcdir)/config/gnulib/string_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_socket_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_stat_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_time_h.m4 \
+       $(top_srcdir)/config/gnulib/tempname.m4 \
+       $(top_srcdir)/config/gnulib/ulonglong.m4 \
+       $(top_srcdir)/config/gnulib/unistd_h.m4 \
+       $(top_srcdir)/config/gnulib/vasnprintf.m4 \
+       $(top_srcdir)/config/gnulib/visibility.m4 \
+       $(top_srcdir)/config/gnulib/wchar.m4 \
+       $(top_srcdir)/config/gettext-macros/gettext.m4 \
+       $(top_srcdir)/config/gettext-macros/iconv.m4 \
+       $(top_srcdir)/config/gettext-macros/inttypes_h.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-ld.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-link.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-prefix.m4 \
+       $(top_srcdir)/config/gettext-macros/longlong.m4 \
+       $(top_srcdir)/config/gettext-macros/nls.m4 \
+       $(top_srcdir)/config/gettext-macros/po.m4 \
+       $(top_srcdir)/config/gettext-macros/progtest.m4 \
+       $(top_srcdir)/config/gettext-macros/size_max.m4 \
+       $(top_srcdir)/config/gettext-macros/stdint_h.m4 \
+       $(top_srcdir)/config/gettext-macros/wchar_t.m4 \
+       $(top_srcdir)/config/gettext-macros/wint_t.m4 \
+       $(top_srcdir)/config/gettext-macros/xsize.m4 \
+       $(top_srcdir)/config/libtool.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMANDA_DBGDIR = @AMANDA_DBGDIR@
+AMANDA_DEBUG_DAYS = @AMANDA_DEBUG_DAYS@
+AMANDA_STATIC_LDFLAGS = @AMANDA_STATIC_LDFLAGS@
+AMANDA_TMPDIR = @AMANDA_TMPDIR@
+AMANDA_WARNING_CFLAGS = @AMANDA_WARNING_CFLAGS@
+AMLINT = @AMLINT@
+AMLINTFLAGS = @AMLINTFLAGS@
+AMPLOT_CAT_COMPRESS = @AMPLOT_CAT_COMPRESS@
+AMPLOT_CAT_GZIP = @AMPLOT_CAT_GZIP@
+AMPLOT_CAT_PACK = @AMPLOT_CAT_PACK@
+AMPLOT_COMPRESS = @AMPLOT_COMPRESS@
+AMTAR = @AMTAR@
+AR = @AR@
+ARPA_INET_H = @ARPA_INET_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASH = @BASH@
+BINARY_OWNER = @BINARY_OWNER@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+CAT = @CAT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CHIO = @CHIO@
+CHS = @CHS@
+CLIENT_LOGIN = @CLIENT_LOGIN@
+CLIENT_SCRIPTS_OPT = @CLIENT_SCRIPTS_OPT@
+COMPRESS = @COMPRESS@
+CONFIG_DIR = @CONFIG_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURL_CONFIG = @CURL_CONFIG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DD = @DD@
+DEFAULT_AMANDATES_FILE = @DEFAULT_AMANDATES_FILE@
+DEFAULT_CHANGER_DEVICE = @DEFAULT_CHANGER_DEVICE@
+DEFAULT_CONFIG = @DEFAULT_CONFIG@
+DEFAULT_SERVER = @DEFAULT_SERVER@
+DEFAULT_TAPE_DEVICE = @DEFAULT_TAPE_DEVICE@
+DEFAULT_TAPE_SERVER = @DEFAULT_TAPE_SERVER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOC_BUILD_DATE = @DOC_BUILD_DATE@
+DUMP = @DUMP@
+DUMPER_DIR = @DUMPER_DIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXAMPLE_TAPEDEV = @EXAMPLE_TAPEDEV@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FLOAT_H = @FLOAT_H@
+GETCONF = @GETCONF@
+GETTEXT = @GETTEXT@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@
+GNULIB_CHOWN = @GNULIB_CHOWN@
+GNULIB_DUP2 = @GNULIB_DUP2@
+GNULIB_FCHDIR = @GNULIB_FCHDIR@
+GNULIB_FFLUSH = @GNULIB_FFLUSH@
+GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@
+GNULIB_FSEEK = @GNULIB_FSEEK@
+GNULIB_FSEEKO = @GNULIB_FSEEKO@
+GNULIB_FTELL = @GNULIB_FTELL@
+GNULIB_FTELLO = @GNULIB_FTELLO@
+GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@
+GNULIB_GETCWD = @GNULIB_GETCWD@
+GNULIB_GETDELIM = @GNULIB_GETDELIM@
+GNULIB_GETLINE = @GNULIB_GETLINE@
+GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@
+GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@
+GNULIB_LCHOWN = @GNULIB_LCHOWN@
+GNULIB_LSEEK = @GNULIB_LSEEK@
+GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@
+GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@
+GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@
+GNULIB_MBSCHR = @GNULIB_MBSCHR@
+GNULIB_MBSCSPN = @GNULIB_MBSCSPN@
+GNULIB_MBSLEN = @GNULIB_MBSLEN@
+GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@
+GNULIB_MBSNLEN = @GNULIB_MBSNLEN@
+GNULIB_MBSPBRK = @GNULIB_MBSPBRK@
+GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@
+GNULIB_MBSRCHR = @GNULIB_MBSRCHR@
+GNULIB_MBSSEP = @GNULIB_MBSSEP@
+GNULIB_MBSSPN = @GNULIB_MBSSPN@
+GNULIB_MBSSTR = @GNULIB_MBSSTR@
+GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@
+GNULIB_MEMMEM = @GNULIB_MEMMEM@
+GNULIB_MEMPCPY = @GNULIB_MEMPCPY@
+GNULIB_MEMRCHR = @GNULIB_MEMRCHR@
+GNULIB_MKDTEMP = @GNULIB_MKDTEMP@
+GNULIB_MKSTEMP = @GNULIB_MKSTEMP@
+GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@
+GNULIB_READLINK = @GNULIB_READLINK@
+GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@
+GNULIB_SLEEP = @GNULIB_SLEEP@
+GNULIB_SNPRINTF = @GNULIB_SNPRINTF@
+GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@
+GNULIB_STPCPY = @GNULIB_STPCPY@
+GNULIB_STPNCPY = @GNULIB_STPNCPY@
+GNULIB_STRCASESTR = @GNULIB_STRCASESTR@
+GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@
+GNULIB_STRDUP = @GNULIB_STRDUP@
+GNULIB_STRNDUP = @GNULIB_STRNDUP@
+GNULIB_STRNLEN = @GNULIB_STRNLEN@
+GNULIB_STRPBRK = @GNULIB_STRPBRK@
+GNULIB_STRSEP = @GNULIB_STRSEP@
+GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
+GNULIB_VASPRINTF = @GNULIB_VASPRINTF@
+GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@
+GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@
+GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@
+GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@
+GNULIB_WCWIDTH = @GNULIB_WCWIDTH@
+GNUPLOT = @GNUPLOT@
+GNUTAR = @GNUTAR@
+GNUTAR_LISTED_INCREMENTAL_DIR = @GNUTAR_LISTED_INCREMENTAL_DIR@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GZIP = @GZIP@
+HAVE_CALLOC_POSIX = @HAVE_CALLOC_POSIX@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_MKDIR = @HAVE_DECL_MKDIR@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DUP2 = @HAVE_DUP2@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_IO_H = @HAVE_IO_H@
+HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MALLOC_POSIX = @HAVE_MALLOC_POSIX@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_REALLOC_POSIX = @HAVE_REALLOC_POSIX@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRNDUP = @HAVE_STRNDUP@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE__BOOL = @HAVE__BOOL@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPTH = @LIBPTH@
+LIBS = @LIBS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBPTH = @LTLIBPTH@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAILER = @MAILER@
+MAKEINFO = @MAKEINFO@
+MAXTAPEBLOCKSIZE = @MAXTAPEBLOCKSIZE@
+MCUTIL = @MCUTIL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+MT = @MT@
+MTX = @MTX@
+MT_FILE_FLAG = @MT_FILE_FLAG@
+NETINET_IN_H = @NETINET_IN_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCAT = @PCAT@
+PERL = @PERL@
+PERLEXTLIBS = @PERLEXTLIBS@
+PERL_INC = @PERL_INC@
+PKG_CONFIG = @PKG_CONFIG@
+POSUB = @POSUB@
+PRINT = @PRINT@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_FCHDIR = @REPLACE_FCHDIR@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+RESTORE = @RESTORE@
+SAMBA_CLIENT = @SAMBA_CLIENT@
+SERVICE_SUFFIX = @SERVICE_SUFFIX@
+SETUID_GROUP = @SETUID_GROUP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+SNAPSHOT_STAMP = @SNAPSHOT_STAMP@
+SORT = @SORT@
+SSH = @SSH@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SVN = @SVN@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYS_SOCKET_H = @SYS_SOCKET_H@
+SYS_STAT_H = @SYS_STAT_H@
+SYS_TIME_H = @SYS_TIME_H@
+USE_NLS = @USE_NLS@
+USE_VERSION_SUFFIXES = @USE_VERSION_SUFFIXES@
+VDUMP = @VDUMP@
+VERSION = @VERSION@
+VERSION_COMMENT = @VERSION_COMMENT@
+VERSION_MAJOR = @VERSION_MAJOR@
+VERSION_MINOR = @VERSION_MINOR@
+VERSION_PATCH = @VERSION_PATCH@
+VERSION_SUFFIX = @VERSION_SUFFIX@
+VRESTORE = @VRESTORE@
+VXDUMP = @VXDUMP@
+VXRESTORE = @VXRESTORE@
+WCHAR_H = @WCHAR_H@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+XFSDUMP = @XFSDUMP@
+XFSRESTORE = @XFSRESTORE@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XSLREL = @XSLREL@
+XSLTPROC = @XSLTPROC@
+XSLTPROC_FLAGS = @XSLTPROC_FLAGS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+amincludedir = @amincludedir@
+amlibdir = @amlibdir@
+amlibexecdir = @amlibexecdir@
+amperldir = @amperldir@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUFFIXES = 
+EXTRA_DIST = 
+BUILT_SOURCES = 
+MOSTLYCLEANFILES = 
+
+# config.status leaves config.log files around
+CLEANFILES = config.log
+
+# and we'll need to clean up our generated files for distclean
+DISTCLEANFILES = $(SCRIPTS_SHELL) $(SCRIPTS_PERL) $(SCRIPTS_AWK)
+MAINTAINERCLEANFILES = 
+
+# syntax-check shell scripts on 'make check'
+CHECK_SHELL = $(SCRIPTS_SHELL)
+
+# Add your tests here.
+common_tests = \
+       Amanda_Config \
+       Amanda_Types
+
+server_tests = \
+       Amanda_Changer \
+       Amanda_Cmdline \
+       Amanda_Logfile \
+       amcheckdump \
+       amdevcheck \
+       amgetconf
+
+tests = $(common_tests) $(am__append_1)
+
+# Add any common files (that should not be run as tests) here:
+test_utils = Amconfig.pm
+SCRIPTS_PERL = $(common_tests) $(server_tests) $(test_utils)
+
+# we don't need to syntax check the test scripts..
+CHECK_PERL = 
+all: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: 
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/config/automake/vars.am $(top_srcdir)/config/automake/scripts.am $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  installcheck/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --gnu  installcheck/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+       $(MAKE) $(AM_MAKEFLAGS) \
+         top_distdir="$(top_distdir)" distdir="$(distdir)" \
+         dist-hook
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) check-local
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am: installcheck-local
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am check-local clean clean-generic \
+       clean-libtool dist-hook distclean distclean-generic \
+       distclean-libtool distdir dvi dvi-am html html-am info info-am \
+       install install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installcheck-local \
+       installdirs maintainer-clean maintainer-clean-generic \
+       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+       ps ps-am uninstall uninstall-am
+
+
+# Perl
+%: %.pl $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+       chmod a+x $@
+
+%.pl: %.pl.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+%.pm: %.pm.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+# Shell
+%: %.sh $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+       chmod a+x $@
+
+%.sh: %.sh.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+# Awk
+%: %.awk $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+       chmod a+x $@
+
+%.awk: %.awk.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+# syntax-check perl scripts on 'make check'
+check-perl: $(CHECK_PERL)
+       @CHECK_PERL="$(CHECK_PERL)"; \
+       if test -n "$(PERL)"; then \
+               for perlobj in $$CHECK_PERL; do \
+                       $(PERL) $(CHECK_PERL_FLAGS) -c -w -T $$perlobj || exit 1; \
+               done; \
+       fi
+check-local: check-perl
+check-shell: $(CHECK_SHELL)
+       @CHECK_SHELL="$(CHECK_SHELL)"; \
+       if test -n "$$CHECK_SHELL"; then \
+               if test -n "$(BASH)"; then \
+                       for shobj in $$CHECK_SHELL; do \
+                               if $(BASH) -n $$shobj; then \
+                                       echo "$$shobj syntax OK"; \
+                               else \
+                                       echo "$$shobj syntax error"; \
+                                       exit 1; \
+                               fi; \
+                       done; \
+               else \
+                       echo "No 'bash' available -- cannot syntax-check shell scripts"; \
+               fi; \
+       fi
+check-local: check-shell
+
+# make sure that the sources for all shell and perl scripts get included
+# in the distribution
+dist-scripts:
+       SCRIPTS_PERL="$(SCRIPTS_PERL)"; SCRIPTS_SHELL="$(SCRIPTS_SHELL)"; SCRIPTS_AWK="$(SCRIPTS_AWK)"; \
+       for script in $$SCRIPTS_PERL; do \
+               test -f $(srcdir)/$${script}.pl && { cp -p $(srcdir)/$${script}.pl $(distdir)/ || exit 1; } \
+       done; \
+       for script in $$SCRIPTS_SHELL; do \
+               test -f $(srcdir)/$${script}.sh && { cp -p $(srcdir)/$${script}.sh $(distdir)/ || exit 1; } \
+       done; \
+       for script in $$SCRIPTS_AWK; do \
+               test -f $(srcdir)/$${script}.awk && { cp -p $(srcdir)/$${script}.awk $(distdir)/ || exit 1; } \
+       done; \
+       for script in $$SCRIPTS_SHELL $$SCRIPTS_PERL $$SCRIPTS_AWK; do \
+               test -f $(srcdir)/$${script}.in && { cp -p $(srcdir)/$${script}.in $(distdir)/ || exit 1; } \
+       done; \
+       true
+dist-hook: dist-scripts
+
+.PHONY: clobber_my_config_is_ok
+clobber_my_config_is_ok:
+       @if test "$(CLOBBER_MY_CONFIG)" != "OK"; then \
+               echo ""; \
+               echo "'make installcheck' is a dangerous tool.  It will overwrite your"; \
+               echo "amanda-client.conf and amandates, and (if it"; \
+               echo "triggers an as-yet undetected bug) may do other unexpected things.  You are"; \
+               echo "strongly encouraged"; \
+               echo "  - not to run installchecks on a production install"; \
+               echo "  - not to run installchecks as root"; \
+               echo "See http://wiki.zmanda.com/index.php/Testing for instructions on setting up a"; \
+               echo "test environment in which"; \
+               echo "potential damage is limited by your filesystem's permissions.  To actually run"; \
+               echo "the installchecks, invoke make"; \
+               echo "as follows:"; \
+               echo "  $(MAKE) CLOBBER_MY_CONFIG=OK installcheck"; \
+               exit 1; \
+       fi
+
+installcheck-local: clobber_my_config_is_ok $(SCRIPTS_PERL)
+       $(mkdir_p) $(AMANDA_TMPDIR)
+       $(PERL) -I$(srcdir) -I$(builddir) -e 'use Test::Harness qw(&runtests); runtests(@ARGV);' $(tests)
+       rm -rf "$(CONFIG_DIR)/TESTCONF"
+       rm -rf "$(CONFIG_DIR)/amanda-client.conf"
+       rm -rf "$(DEFAULT_AMANDATES_FILE)"
+       rm -rf "$(GNUTAR_LISTED_INCREMENTAL_DIR)"
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/installcheck/amcheckdump.pl b/installcheck/amcheckdump.pl
new file mode 100644 (file)
index 0000000..ff6a150
--- /dev/null
@@ -0,0 +1,34 @@
+use Test::More qw( no_plan );
+
+use Amconfig;
+
+use lib "@amperldir@";
+use Amanda::Paths;
+
+sub amcheckdump {
+    my $cmd = "$sbindir/amcheckdump " . join(" ", @_) . " 2>&1";
+    my $result = `$cmd`;
+    chomp $result;
+    return $result;
+}
+
+my $testconf;
+
+##
+# First, try amgetconf out without a config
+
+like(amcheckdump(), qr/\AUSAGE:/i, 
+    "bare 'amcheckdump' gives usage message");
+like(amcheckdump("this-probably-doesnt-exist"), qr(could not open conf file)i, 
+    "error message when configuration parameter doesn't exist");
+
+##
+# Now use a config with a vtape
+
+# this is re-created for each test
+$testconf = Amconfig->new();
+$testconf->setup_vtape();
+$testconf->write();
+
+like(amcheckdump("TESTCONF"), qr(could not find)i,
+     "'amcheckdump' on a brand-new config finds no dumps.");
diff --git a/installcheck/amdevcheck.pl b/installcheck/amdevcheck.pl
new file mode 100644 (file)
index 0000000..895f73a
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+use Test::More qw( no_plan );
+
+use Amconfig;
+use lib "@amperldir@";
+use Amanda::Paths;
+
+sub amdevcheck {
+    my $cmd = "$sbindir/amdevcheck " . join(" ", @_) . " 2>&1";
+    my $result = `$cmd`;
+    chomp $result;
+    return $result;
+}
+
+my $testconf;
+
+##
+# First, try amgetconf out without a config
+
+like(amdevcheck(), qr(\AUsage: )i, 
+    "bare 'amdevcheck' gives usage message");
+like(amdevcheck("this-probably-doesnt-exist"), qr(could not open conf file)i, 
+    "error message when configuration parameter doesn't exist");
+
+##
+# Next, work against a basically empty config
+
+# this is re-created for each test
+$testconf = Amconfig->new();
+$testconf->add_param("tapedev", '"/dev/null"');
+$testconf->write();
+
+# test some defaults
+like(amdevcheck('TESTCONF'), qr{File /dev/null is not a tape device},
+    "uses tapedev by default");
+
+##
+# Now use a config with a vtape
+
+# this is re-created for each test
+$testconf = Amconfig->new();
+$testconf->setup_vtape();
+$testconf->write();
+
+is_deeply([ sort split "\n", amdevcheck('TESTCONF') ],
+         [ sort "VOLUME_UNLABELED", "VOLUME_ERROR", "DEVICE_ERROR" ],
+    "empty vtape described as VOLUME_UNLABELED, VOLUME_ERROR, DEVICE_ERROR");
+
+like(amdevcheck('TESTCONF', "/dev/null"), qr{File /dev/null is not a tape device},
+    "can override device on the command line");
diff --git a/installcheck/amgetconf.pl b/installcheck/amgetconf.pl
new file mode 100644 (file)
index 0000000..31ea204
--- /dev/null
@@ -0,0 +1,189 @@
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+use Test::More qw(no_plan);
+
+use Amconfig;
+use lib "@amperldir@";
+use Amanda::Paths;
+
+# wrapper to call amgetconf and return the results
+sub amgetconf {
+    # open amgetconf and read from it
+    my $cmd = "$sbindir/amgetconf " . join(" ", @_) . " 2>&1";
+    my $result = `$cmd`;
+    chomp $result;
+    return $result;
+}
+
+# this is re-created for each test
+my $testconf;
+
+##
+# First, try amgetconf out without a config
+
+like(amgetconf(), qr(\AUsage: )i, 
+    "bare 'amgetconf' gives usage message");
+like(amgetconf("this-probably-doesnt-exist"), qr(could not open conf file)i, 
+    "error message when configuration parameter doesn't exist");
+
+##
+# Next, work against a basically empty config
+
+$testconf = Amconfig->new();
+$testconf->write();
+
+# test some defaults
+is(amgetconf('TESTCONF', "reserve"), "100", 
+    "reserve defaults to 100");
+is(amgetconf('TESTCONF', "tapelist"), "tapelist", 
+    "tapelist defaults to 'tapelist'");
+is(amgetconf('TESTCONF', "usetimestamps"), "yes", 
+    "usetimestamps defaults to 'yes'");
+
+# test a nonexistent parameter
+like(amgetconf('TESTCONF', "foos_per_bar"), qr/no such parameter/, 
+    "handles nonexistent parameters");
+
+# test build parameters (just the most common)
+is(amgetconf('TESTCONF', "build.bindir"), $bindir, "build.bindir is correct");
+is(amgetconf('TESTCONF', "build.sbindir"), $sbindir, "build.sbindir is correct");
+is(amgetconf('TESTCONF', "build.amlibexecdir"), $amlibexecdir, "build.amlibexecdir is correct");
+is(amgetconf('TESTCONF', "build.mandir"), $mandir, "build.mandir is correct");
+is(amgetconf('TESTCONF', "build.AMANDA_DBGDIR"), $AMANDA_DBGDIR, "build.AMANDA_DBGDIR is correct");
+is(amgetconf('TESTCONF', "build.AMANDA_TMPDIR"), $AMANDA_TMPDIR, "build.AMANDA_TMPDIR is correct");
+is(amgetconf('TESTCONF', "build.CONFIG_DIR"), $CONFIG_DIR, "build.CONFIG_DIR is correct");
+
+# dbopen, dbclose
+my $dbfile = amgetconf('TESTCONF', "dbopen.foo");
+like($dbfile, qr(^$AMANDA_DBGDIR/server/foo.[0-9]*.debug$),
+    "'amgetconf dbopen.foo' returns a proper debug filename");
+ok(-f $dbfile,
+    "'amgetconf dbopen.foo' creates the debug file");
+like(amgetconf('TESTCONF', "dbclose.foo"), qr/cannot parse/,
+    "dbclose without filename fails");
+is(amgetconf('TESTCONF', "dbclose.foo:$dbfile"), $dbfile, 
+    "'amgetconf dbclose.foo:<filename>' returns the debug filename");
+
+##
+# Test an invalid config file
+
+$testconf = Amconfig->new();
+$testconf->add_param("foos_per_bar", "10");
+$testconf->write();
+
+like(amgetconf('TESTCONF', "foos_per_bar"), qr/errors processing config file/, 
+    "gives error on invalid configuration");
+
+##
+# Now let's fill in some interesting values
+
+$testconf = Amconfig->new();
+$testconf->add_param("reserved-udp-port", '100,200');
+$testconf->add_param("printer", '"/dev/lp"');
+$testconf->add_param("reserve", '27');
+$testconf->write();
+
+is(amgetconf('TESTCONF', "reserved-udp-port"), "100,200", 
+    "correctly returns intrange parameters from the file");
+is(amgetconf('TESTCONF', "printer"), "/dev/lp", 
+    "correctly returns string parameters from the file");
+is(amgetconf('TESTCONF', "reserve"), "27", 
+    "correctly returns integer parameters from the file");
+is(amgetconf('TESTCONF', "rEsErVe"), "27", 
+    "is case-insensitive");
+
+##
+# device_property can appear multiple times
+
+$testconf = Amconfig->new();
+$testconf->add_param("device_property", '"power" "on"');
+$testconf->add_param("device_property", '"turbo" "engaged"');
+$testconf->write();
+
+is_deeply([sort(+split(qr/\n/, amgetconf('TESTCONF', 'device_property')))],
+         [sort('"power" "on"', '"turbo" "engaged"')],
+    "device_property can have multiple values");
+
+##
+# Subsections
+
+$testconf = Amconfig->new();
+$testconf->add_tapetype("cassette", [ length => "32 k" ]);
+$testconf->add_tapetype("reel2reel", [ length => "1 M" ]);
+$testconf->add_tapetype("scotch", [ length => "500 bytes" ]); # (use a sharpie)
+$testconf->add_dumptype("testdump", [ comment => '"testdump-dumptype"' ]);
+$testconf->add_interface("testiface", [ use => '10' ]);
+$testconf->add_holdingdisk("hd17", [ chunksize => '128' ]);
+$testconf->write();
+
+is_deeply([sort(+split(/\n/, amgetconf('TESTCONF', '--list', 'tapetype')))],
+         [sort("cassette", "reel2reel", "scotch", "TEST-TAPE")],
+       "--list returns correct set of tapetypes");
+is(amgetconf('TESTCONF', 'tapetype:scotch:length'), '500', 
+    "returns tapetype parameter correctly");
+
+ok(grep { $_ eq 'testdump' } split(/\n/, amgetconf('TESTCONF', '--list', 'dumptype')),
+       "--list returns a test dumptype among the default dumptypes");
+is(amgetconf('TESTCONF', 'dumptype:testdump:comment'), 'testdump-dumptype', 
+    "returns dumptype parameter correctly");
+
+is_deeply([sort(+split(/\n/, amgetconf('TESTCONF', '--list', 'interface')))],
+          [sort("testiface", "default")],
+       "--list returns correct set of interfaces");
+is(amgetconf('TESTCONF', 'interface:testiface:use'), '10', 
+    "returns interface parameter correctly");
+
+is_deeply([sort(+split(/\n/, amgetconf('TESTCONF', '--list', 'holdingdisk')))],
+         [sort("hd17")],
+       "--list returns correct set of holdingdisks");
+is(amgetconf('TESTCONF', 'holdingdisk:hd17:chunksize'), '128',
+    "returns holdingdisk parameter correctly");
+
+# non-existent subsection types, names, and parameters
+like(amgetconf('TESTCONF', 'NOSUCHTYPE:testiface:comment'), qr/no such parameter/, 
+    "handles bad subsection type");
+like(amgetconf('TESTCONF', 'dumptype:NOSUCHDUMP:comment'), qr/no such parameter/, 
+    "handles bad dumptype namek");
+like(amgetconf('TESTCONF', 'dumptype:testdump:NOSUCHPARAM'), qr/no such parameter/, 
+    "handles bad dumptype parameter name");
+
+##
+# exclude lists are a bit funny, too
+
+$testconf = Amconfig->new();
+$testconf->add_dumptype("testdump", [
+    "exclude file optional" => '"f1"', # this optional will have no effect
+    "exclude file append" => '"f2"',
+    "exclude list" => '"l1"',
+    "exclude list append" => '"l2"',
+    "include file" => '"ifo"',
+    "include list optional" => '"ilo"',
+    ]);
+$testconf->write();
+
+is_deeply([sort(+split(qr/\n/, amgetconf('TESTCONF', 'dumptype:testdump:exclude')))],
+         [sort('FILE "f1" "f2"',
+               'LIST "l1" "l2"')],
+    "exclude files and lists displayed correctly; a non-final optional is ignored");
+
+is_deeply([sort(+split(qr/\n/, amgetconf('TESTCONF', 'dumptype:testdump:include')))],
+         [sort('FILE OPTIONAL "ifo"',
+               'LIST OPTIONAL "ilo"')],
+    "a final 'OPTIONAL' makes the whole include/exclude optional")
+
diff --git a/man/amaddclient.8 b/man/amaddclient.8
new file mode 100644 (file)
index 0000000..0857293
--- /dev/null
@@ -0,0 +1,212 @@
+.\"     Title: amaddclient
+.\"    Author: 
+.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
+.\"      Date: 08/22/2008
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMADDCLIENT" "8" "08/22/2008" "" ""
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+amaddclient - program to add client to an existing Amanda configuration
+.SH "SYNOPSIS"
+.HP 12
+\fBamaddclient\fR \-\-config \fIconfig\fR ||
+ \-\-client \fIclient\ name\fR ||
+ \-\-diskdev \fIdirectory\ to\ backup\fR [\-\-m] [\-\-dumptype\ \fIstring\fR] [\-\-includefile\ \fIstring\fR] [\-\-includelist\ \fIstring\fR] [\-\-excludefile\ \fIstring\fR] [\-\-excludelist\ \fIstring\fR] [\-\-user\ \fIstring\fR] [\-\-auth\ \fIstring\fR] [\-\-gnutar_list_dir\ \fIstring\fR] [\-\-amandates\ \fIstring\fR] [\-\-no\-client\-update] [\-\-batch] [\-\-help]
+.SH "DESCRIPTION"
+.PP
+After Amanda rpms are successfully installed and
+\fBamserverconfig\fR
+is run,
+\fBamaddclient\fR
+will add client to the
+\fIAmanda\fR
+configuration\.
+\fBamaddclient\fR
+create or update
+\fIAmanda\fR
+disklist file and create or update /var/lib/amanda/\.amandahosts file on the server\.
+.PP
+If \-\-no\-client\-update is not specified,
+\fBamaddclient\fR
+will attempt to update or create /var/lib/amanda/\.amandahost, amanda\-client\.conf and gnutar\-lists on the client\. (See
+ssh\-keygen(1)
+and
+ssh\-add(1)
+for detail\.)
+.PP
+
+\fBamaddclient\fR
+must be run by user amandabackup\.
+.PP
+\-\-config, \-\-client and \-\-diskdev must be specified\.
+.SH "OPTIONS"
+.PP
+.RS 4
+
+Options may be abbreviated, as long as the abbreviation is not ambiguous\. Option argument can either separated by \'=\' or a space\.
+Example: \-\-conf=v253, \-\-client client8\.zmanda\.com
+.RE
+.PP
+\fB\-\-config config\fR
+.RS 4
+\fIAmanda\fR
+configuration which this program will add the client to\.
+.RE
+.PP
+\fB\-\-client client\fR
+.RS 4
+The name of the client machine to add\. FQDN name recommended\.
+.RE
+.PP
+\fB\-\-diskdev diskdev\fR
+.RS 4
+Directory for this
+\fIAmanda\fR
+configuration to backup\.
+.RE
+.PP
+\fB\-\-m\fR
+.RS 4
+Modify existing entry in the disklist file\.
+.sp
+Note: if disklist file has been modified manually, this option might not work\.
+.RE
+.PP
+\fB\-\-dumptype dumptype\fR
+.RS 4
+dumptype to use\. Dumptype must be defined in /etc/amanda/template\.d/dumptypes or /etc/amanda/$config/amanda\.conf file\. Default: [user\-tar]
+.RE
+.PP
+\fB\-\-user string\fR
+.RS 4
+name of user using
+\fBamrecover\fR
+on the client, default is root\.
+.RE
+.PP
+\fB\-\-auth string\fR
+.RS 4
+authentication method to use when running
+\fBamrecover\fR
+from the client , default is bsdtcp\.
+.RE
+.PP
+\fB\-\-gnutar_list_dir string\fR
+.RS 4
+directory where gnutar keep its state file on the client\. Absolute path required\. Default is /var/lib/amanda/gnutar\-lists\. If \-\-no\-client\-update is not set, this program will attempt to create the directory on the client\.
+.RE
+.PP
+\fB\-\-amandates string\fR
+.RS 4
+file where amanda keep the date of each dumplevel on the client, default is /etc/amandates\.
+.RE
+.PP
+\fB\-\-batch\fR
+.RS 4
+Turn on batch mode when copying files to the client, default is off
+.RE
+.PP
+\fB\-\-no\-client\-update\fR
+.RS 4
+If this option is set,
+\fBamaddclient\fR
+will not attempt to update/create \.amandahosts, amanda\-client\.conf and gnutar\-lists file on the client\.
+.RE
+.PP
+\fB\-\-help\fR
+.RS 4
+Display usage\.
+.RE
+.PP
+.RS 4
+If any of the following four options are used,  \fBamaddclient\fR will extend the dumptype definition to an in\-line definition in the disklist file\. See \fBamanda\fR(8) DISKLIST FILE section for detail\.
+.RE
+.PP
+\fB\-\-includefile string\fR
+.RS 4
+string is a glob expression
+.RE
+.PP
+\fB\-\-includelist string\fR
+.RS 4
+string is a file name on the client containing glob expressions\. Specify either \-\-includefile or \-\-includelist\.
+.RE
+.PP
+\fB\-\-excludefile string\fR
+.RS 4
+string is a glob expression
+.RE
+.PP
+\fB\-\-excludelist string\fR
+.RS 4
+string is a file name on the client containing glob expressions\. Specify either \-\-excludefile or \-\-excludelist\.
+.RE
+.SH "FILES"
+.PP
+\fB/var/lib/amanda/template\.d\fR
+.RS 4
+Amanda configuration template files install location
+.RE
+.PP
+\fB/var/lib/amanda\fR
+.RS 4
+amandabackup home directory
+.RE
+.PP
+\fB/var/lib/amanda/\.amandahosts\fR
+.RS 4
+\fIAmanda\fR
+authentication file\.
+.RE
+.PP
+\fB/var/lib/amanda/gnutar\-lists\fR
+.RS 4
+A directory which contains backup timestamp and list of files backed up\.
+.RE
+.PP
+\fB/etc/amanda/$config\fR
+.RS 4
+\fIAmanda\fR
+configuration files location for $config(e\.g: DailySet1)\.
+.RE
+.PP
+\fB/etc/amanda/template\.d\fR
+.RS 4
+A directory contains dumptypes and tapetypes files used by all
+\fIAmanda\fR
+configurations\.
+.RE
+.PP
+\fB/etc/amandates\fR
+.RS 4
+\fIAmanda\fR
+file on the client\. It keeps track of structures of previous dumps\.
+.RE
+.PP
+\fB/tmp/amanda\fR
+.RS 4
+directory contains
+\fIAmanda\fR
+debug log files\.
+.RE
+.SH "RETURN VALUE"
+
+On success, zero is returned\.  On error, 1 is returned\.
+.SH "AUTHOR"
+.PP
+The tool and its documentation was written by Zmanda, Inc (http://www\.zmanda\.com/)\.
+.SH "SEE ALSO"
+.PP
+\fBamanda\fR(8),
+\fBamanda.conf\fR(5),
+\fBamserverconfig\fR(8)
+\fBssh-keygen\fR(1)
+\fBssh-add\fR(1)
+\fBscp\fR(1)
+: http://wiki.zmanda.com
diff --git a/man/amaespipe.8.BACKUP.16324.8 b/man/amaespipe.8.BACKUP.16324.8
new file mode 100644 (file)
index 0000000..b61cac1
--- /dev/null
@@ -0,0 +1,94 @@
+.\"     Title: amaespipe
+.\"    Author: 
+<<<<<<< HEAD:man/amaespipe.8
+.\" Generator: DocBook XSL Stylesheets v1.72.0 <http://docbook.sf.net/>
+.\"      Date: 06/06/2007
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMAESPIPE" "8" "06/06/2007" "" ""
+=======
+.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
+.\"      Date: 08/22/2008
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMAESPIPE" "8" "08/22/2008" "" ""
+>>>>>>> upstream:man/amaespipe.8
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+<<<<<<< HEAD:man/amaespipe.8
+amaespipe \- wrapper program for aespipe
+=======
+amaespipe - wrapper program for aespipe
+>>>>>>> upstream:man/amaespipe.8
+.SH "SYNOPSIS"
+.HP 10
+\fBamaespipe\fR
+.SH "DESCRIPTION"
+.PP
+
+\fBamaespipe\fR
+requires
+\fBaespipe\fR,
+\fBuuencode\fR
+and
+\fBgpg\fR
+<<<<<<< HEAD:man/amaespipe.8
+to work. Aespipe is available from
+\fI\%http://loop\-aes.sourceforge.net\fR
+.PP
+
+\fBamaespipe\fR
+will search for the aespipe program in the following directories: /usr/bin:/usr/local/bin:/sbin:/usr/sbin.
+=======
+to work\. Aespipe is available from
+: http://loop-aes.sourceforge.net
+.PP
+
+\fBamaespipe\fR
+will search for the aespipe program in the following directories: /usr/bin:/usr/local/bin:/sbin:/usr/sbin\.
+>>>>>>> upstream:man/amaespipe.8
+.PP
+
+\fBamaespipe\fR
+is called by
+\fBamcrypt\fR
+for
+\fIAmanda\fR
+<<<<<<< HEAD:man/amaespipe.8
+data encryption.
+.PP
+
+\fBamaespipe\fR
+is based on aespipe's bzaespipe program. It calls aespipe to encrypt data using AES256 as the encryption and SHA256 as the hash function. GPG key should be stored in $AMANDA_HOME/.gnupg/am_key.gpg.
+\fBamaespipe\fR
+reads passphrase from file descriptor 3. During decryption,
+\fBamaespipe\fR
+autodects encryption type and hash function from the encrypted image.
+=======
+data encryption\.
+.PP
+
+\fBamaespipe\fR
+is based on aespipe\'s bzaespipe program\. It calls aespipe to encrypt data using AES256 as the encryption and SHA256 as the hash function\. GPG key should be stored in $AMANDA_HOME/\.gnupg/am_key\.gpg\.
+\fBamaespipe\fR
+reads passphrase from file descriptor 3\. During decryption,
+\fBamaespipe\fR
+autodects encryption type and hash function from the encrypted image\.
+>>>>>>> upstream:man/amaespipe.8
+.SH "SEE ALSO"
+.PP
+\fBamanda\fR(8),
+\fBamanda.conf\fR(5),
+\fBaespipe\fR(1),
+\fBamcrypt\fR(8),
+<<<<<<< HEAD:man/amaespipe.8
+\fBgpg\fR(1)
+=======
+\fBgpg\fR(1),
+: http://wiki.zmanda.com
+>>>>>>> upstream:man/amaespipe.8
diff --git a/man/amaespipe.8.LOCAL.16324.8 b/man/amaespipe.8.LOCAL.16324.8
new file mode 100644 (file)
index 0000000..ae0d536
--- /dev/null
@@ -0,0 +1,55 @@
+.\"     Title: amaespipe
+.\"    Author: 
+.\" Generator: DocBook XSL Stylesheets v1.72.0 <http://docbook.sf.net/>
+.\"      Date: 06/06/2007
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMAESPIPE" "8" "06/06/2007" "" ""
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+amaespipe \- wrapper program for aespipe
+.SH "SYNOPSIS"
+.HP 10
+\fBamaespipe\fR
+.SH "DESCRIPTION"
+.PP
+
+\fBamaespipe\fR
+requires
+\fBaespipe\fR,
+\fBuuencode\fR
+and
+\fBgpg\fR
+to work. Aespipe is available from
+\fI\%http://loop\-aes.sourceforge.net\fR
+.PP
+
+\fBamaespipe\fR
+will search for the aespipe program in the following directories: /usr/bin:/usr/local/bin:/sbin:/usr/sbin.
+.PP
+
+\fBamaespipe\fR
+is called by
+\fBamcrypt\fR
+for
+\fIAmanda\fR
+data encryption.
+.PP
+
+\fBamaespipe\fR
+is based on aespipe's bzaespipe program. It calls aespipe to encrypt data using AES256 as the encryption and SHA256 as the hash function. GPG key should be stored in $AMANDA_HOME/.gnupg/am_key.gpg.
+\fBamaespipe\fR
+reads passphrase from file descriptor 3. During decryption,
+\fBamaespipe\fR
+autodects encryption type and hash function from the encrypted image.
+.SH "SEE ALSO"
+.PP
+\fBamanda\fR(8),
+\fBamanda.conf\fR(5),
+\fBaespipe\fR(1),
+\fBamcrypt\fR(8),
+\fBgpg\fR(1)
diff --git a/man/amaespipe.8.REMOTE.16324.8 b/man/amaespipe.8.REMOTE.16324.8
new file mode 100644 (file)
index 0000000..5bf7451
--- /dev/null
@@ -0,0 +1,56 @@
+.\"     Title: amaespipe
+.\"    Author: 
+.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
+.\"      Date: 08/22/2008
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMAESPIPE" "8" "08/22/2008" "" ""
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+amaespipe - wrapper program for aespipe
+.SH "SYNOPSIS"
+.HP 10
+\fBamaespipe\fR
+.SH "DESCRIPTION"
+.PP
+
+\fBamaespipe\fR
+requires
+\fBaespipe\fR,
+\fBuuencode\fR
+and
+\fBgpg\fR
+to work\. Aespipe is available from
+: http://loop-aes.sourceforge.net
+.PP
+
+\fBamaespipe\fR
+will search for the aespipe program in the following directories: /usr/bin:/usr/local/bin:/sbin:/usr/sbin\.
+.PP
+
+\fBamaespipe\fR
+is called by
+\fBamcrypt\fR
+for
+\fIAmanda\fR
+data encryption\.
+.PP
+
+\fBamaespipe\fR
+is based on aespipe\'s bzaespipe program\. It calls aespipe to encrypt data using AES256 as the encryption and SHA256 as the hash function\. GPG key should be stored in $AMANDA_HOME/\.gnupg/am_key\.gpg\.
+\fBamaespipe\fR
+reads passphrase from file descriptor 3\. During decryption,
+\fBamaespipe\fR
+autodects encryption type and hash function from the encrypted image\.
+.SH "SEE ALSO"
+.PP
+\fBamanda\fR(8),
+\fBamanda.conf\fR(5),
+\fBaespipe\fR(1),
+\fBamcrypt\fR(8),
+\fBgpg\fR(1),
+: http://wiki.zmanda.com
diff --git a/man/amanda.css b/man/amanda.css
new file mode 100644 (file)
index 0000000..d6ee054
--- /dev/null
@@ -0,0 +1,48 @@
+/* Taken from the Zmanda wiki, for at least a little bit of visual continuity */
+body {
+    font: small sans-serif;
+    background: #82B1C8 0 0 no-repeat;
+    color: black;
+}
+
+div.refentry {
+    background: white;
+    margin-left: 11em;
+    margin-top: 2em;
+    padding: .6em;
+    padding-top: 0;
+    border: thin gray ridge;
+}
+
+pre {
+    padding: 1em;
+    border: 1px dashed #2f6fab;
+    color: black;
+    background-color: #f9f9f9;
+    line-height: 1.1em;
+}
+
+/* browsers override this for some reason */
+table {
+    font-size: small;
+}
+
+h1, h2, h3, h4, h5, h6 {
+    color: black;
+    background: none;
+    font-weight: normal;
+    margin: 0;
+    padding-top: .5em;
+    padding-bottom: .17em;
+    border-bottom: 1px solid #5C706D;
+}
+h1 { font-size: 188%; }
+h2 { font-size: 150%; }
+h3, h4, h5, h6 {
+    border-bottom: none;
+    font-weight: bold;
+}
+h3 { font-size: 132%; }
+h4 { font-size: 116%; }
+h5 { font-size: 100%; }
+h6 { font-size: 80%;  }
diff --git a/man/amcheckdump.8 b/man/amcheckdump.8
new file mode 100644 (file)
index 0000000..4371b83
--- /dev/null
@@ -0,0 +1,54 @@
+.\"     Title: amcheckdump
+.\"    Author: 
+.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
+.\"      Date: 08/22/2008
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMCHECKDUMP" "8" "08/22/2008" "" ""
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+amcheckdump - check the results of an Amanda dump
+.SH "SYNOPSIS"
+.HP 12
+\fBamcheckdump\fR \fIconfig\fR [\-\-timestamp|\-t\ \fItimestamp\fR] [\-o\ \fIconfigoption\fR]...
+.SH "DESCRIPTION"
+.PP
+\fBAmcheckdump\fR
+verifies
+\fIAmanda\fR
+dump images by reading them from storage volume(s) and verifying that the images can be parsed by the appropriate application (if available)\. For example, a GNUTAR image is passed to GNU Tar for parsing, and any errors (e\.g\., corrupt or missing data) are noted\.
+.PP
+The application runs on the most recent dump or, if
+\fI\-\-timestamp\fR
+is specified, on the most recent dump with that timestamp\. Note that the verification is local to the
+\fIAmanda\fR
+server; if the dump application is not available, or is configured differently on the server than on the client, then the verification will most likely fail\.
+.PP
+If a changer is available, it is used to load the required tapes\. Otherwise, the application interactively requests the tapes\.
+.PP
+See the "\fBCONFIGURATION OVERRIDE\fR" section in
+\fBamanda\fR(8)
+for information on the
+\-o
+option\.
+.SH "SEE ALSO"
+.PP
+\fBamanda\fR(8),
+: http://wiki.zmanda.com
+.SH "EXAMPLE"
+.PP
+.nf
+# check the most recent dump
+amcheckdump MYCONFIG
+
+# check a specific dump from back in \'78
+amcheckdump MYCONFIG \-\-timestamp 19780615
+.fi
+.SH "SEE ALSO"
+.PP
+\fBamanda\fR(8),
+\fBhttp://wiki.zmanda.com\fR()
diff --git a/man/amcryptsimple.8 b/man/amcryptsimple.8
new file mode 100644 (file)
index 0000000..cecbd1f
--- /dev/null
@@ -0,0 +1,66 @@
+.\"     Title: amcryptsimple
+.\"    Author: 
+.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
+.\"      Date: 08/22/2008
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMCRYPTSIMPLE" "8" "08/22/2008" "" ""
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+amcryptsimple - reference simple crypt program for Amanda symmetric data encryption
+.SH "SYNOPSIS"
+.HP 14
+\fBamcryptsimple\fR  to be called by \fIAmanda\fR only 
+.SH "DESCRIPTION"
+.PP
+
+\fBamcryptsimple\fR
+calls
+\fBgpg\fR
+to perform symmetric data encryption on
+\fIAmanda\fR
+backup\.
+\fBamcryptsimple\fR
+will search for the gpg program in the following directories: /usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
+.PP
+
+\fBamcryptsimple\fR
+uses one passphrase to encrypt the
+\fIAmanda\fR
+data and uses the same passphrase to decrypt the
+\fIAmanda\fR
+backup data\.
+\fBamcryptsimple\fR
+uses AES256 as the symmetric cipher\.
+.SH "HOW TO CREATE PASSPHRASE"
+
+
+Store  the  passphrase  inside the home\-directory of the AMANDA\-user($amanda_user) and protect it with proper permissions:
+
+   echo my_secret_passphrase > ~$amanda_user/\.am_passphrase
+   chown $amanda_user:disk ~$amanda_user/\.am_passphrase
+   chmod 700 ~$amanda_user/\.am_passphrase
+.SH "NOTES"
+.PP
+Choose a good passphrase and protect it properly\. Backup data can only be restored with the passphrase\. There is no backdoor\.
+.PP
+If storing and securing passphrase in your environment presents challenges,
+\fIAmanda\fR
+provide public\-key data encryption through
+\fBamgpgcrypt\fR\. Public\-key encryption uses the public key to encrypt and uses the private key to decrypt\.
+.SH "AUTHOR"
+.PP
+The tool and its documentation was written by Zmanda, Inc (http://www\.zmanda\.com/)\.
+.SH "SEE ALSO"
+.PP
+\fBamanda\fR(8),
+\fBamanda.conf\fR(5),
+\fBamcrypt\fR(8),
+\fBamgpgcrypt\fR(8),
+\fBamrestore\fR(8),
+\fBgpg\fR(1),
+: http://wiki.zmanda.com
diff --git a/man/amdevcheck.8 b/man/amdevcheck.8
new file mode 100644 (file)
index 0000000..a9b403e
--- /dev/null
@@ -0,0 +1,69 @@
+.\"     Title: amdevcheck
+.\"    Author: 
+.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
+.\"      Date: 08/22/2008
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMDEVCHECK" "8" "08/22/2008" "" ""
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+amdevcheck - Validate an Amanda device and volume.
+.SH "SYNOPSIS"
+.HP 11
+\fBamdevcheck\fR \fIconfig\fR [\fIdevice\ name\fR] [\-o\ \fIconfigoption\fR]...
+.SH "DESCRIPTION"
+.PP
+
+\fBAmdevcheck\fR
+provides a way to check that a particular
+\fIAmanda\fR
+device is accessible, whether or not it contains a volume, and whether or not that volume is labeled\. Some devices can\'t distinguish between all of these cases; a missing volume and an unlabeled volume might generate the same error code, for example\. In those cases, this tool reports all possible causes of the error\.
+.PP
+See the
+\fBamanda\fR(8)
+man page for more details about
+\fIAmanda\fR\. See the
+\fBOUTPUT DRIVERS\fR
+section of
+\fIamanda(8)\fR
+for more information on the
+\fIAmanda\fR
+output drivers\.
+.SH "OPTIONS"
+.PP
+\fIconfig\fR
+.RS 4
+
+\fIAmanda\fR
+configuration to use\. Note that
+\fBamdevcheck\fR
+ignores any tape changer configuration\.
+.RE
+.PP
+\fI device\fR
+.RS 4
+
+\fIAmanda\fR
+device to use\. This option overrides any tapedev configuration specified in the configuration file\.
+.RE
+.PP
+\fB\-o\fR \fIclientconfigoption\fR
+.RS 4
+See the "\fBCONFIGURATION OVERRIDE\fR" section in
+\fBamanda\fR(8)\.
+.RE
+.SH "AUTHOR"
+.PP
+Ian Turner
+<ian@zmanda\.com>
+and others\. Authorship of this tool and its documentation was funded by Zmanda, Inc\.
+.SH "SEE ALSO"
+.PP
+
+\fBamanda\fR(8),
+\fBammt\fR(8),
+: http://wiki.zmanda.com
diff --git a/man/amgpgcrypt.8 b/man/amgpgcrypt.8
new file mode 100644 (file)
index 0000000..ad36e69
--- /dev/null
@@ -0,0 +1,153 @@
+.\"     Title: amgpgcrypt
+.\"    Author: 
+.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
+.\"      Date: 08/22/2008
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMGPGCRYPT" "8" "08/22/2008" "" ""
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+amgpgcrypt - reference crypt program for Amanda public-key data encryption
+.SH "SYNOPSIS"
+.HP 11
+\fBamgpgcrypt\fR  to be called by \fIAmanda\fR only 
+.SH "DESCRIPTION"
+.PP
+
+\fBamgpgcrypt\fR
+calls
+\fBgpg\fR
+to perform public\-key data encryption on
+\fIAmanda\fR
+backup\.
+\fBamgpgcrypt\fR
+will search for the gpg program in the following directories: /usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
+.PP
+
+\fBamgpgcrypt\fR
+sets GNUPGHOME to $AMANDA_HOME/\.gnupg where gpg will look for the gpg keys\.
+\fBamgpgcrypt\fR
+uses the public key to encrypt the
+\fIAmanda\fR
+data and uses the private key to decrypt the
+\fIAmanda\fR
+backup data\. Thus, passphrase is only required at the time of data restore\.
+.SH "KEY AND PASSPHRASE"
+.PP
+
+\fBamgpgcrypt\fR
+uses the private key to decrypt
+\fIAmanda\fR
+backup data\.
+
+It is very important to store, manage and  protect the key and the passphrase
+properly\. Encrypted backup data can \fBonly\fR be recovered with the correct key and
+passphrase\.
+.SH "HOW TO CREATE ENCRYPTION KEYS AND PASSPHRASE FOR AMGPGCRYPT"
+.PP
+Store the passphrase that you used in following "gpg \-\-gen\-key" command inside the home\-directory of the AMANDA\-user($amanda_user) and protect it with proper permissions:
+
+   echo my_secret_passphrase > ~$amanda_user/\.am_passphrase
+   chown $amanda_user:disk ~$amanda_user/\.am_passphrase
+   chmod 700 ~$amanda_user/\.am_passphrase
+.PP
+Run "gpg \-\-gen\-key"\. Below is an example:
+.nf
+$ gpg \-\-gen\-key
+gpg (GnuPG) 1\.2\.6; Copyright (C) 2004 Free Software Foundation, Inc\.
+This program comes with ABSOLUTELY NO WARRANTY\.
+This is free software, and you are welcome to redistribute it
+under certain conditions\. See the file COPYING for details\.
+
+Please select what kind of key you want:
+   (1) DSA and ElGamal (default)
+   (2) DSA (sign only)
+   (4) RSA (sign only)
+Your selection? 1
+DSA keypair will have 1024 bits\.
+About to generate a new ELG\-E keypair\.
+              minimum keysize is  768 bits
+              default keysize is 1024 bits
+    highest suggested keysize is 2048 bits
+What keysize do you want? (1024)
+Requested keysize is 1024 bits
+Please specify how long the key should be valid\.
+         0 = key does not expire
+      (n)  = key expires in n days
+      (n)w = key expires in n weeks
+      (n)m = key expires in n months
+      (n)y = key expires in n years
+Key is valid for? (0) 6m
+Key expires at Sun 06 Aug 2006 03:51:25 PM PDT
+Is this correct (y/n)? y
+
+You need a User\-ID to identify your key; the software constructs the user id
+from Real Name, Comment and Email Address in this form:
+    "Heinrich Heine (Der Dichter) (heinrichh@duesseldorf\.de)"
+
+Real name: amandabackup
+Email address:
+Comment: gpg keys for amandabackup
+You selected this USER\-ID:
+    "amandabackup (gpg keys for amandabackup)"
+
+Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
+You need a Passphrase to protect your secret key\.
+
+We need to generate a lot of random bytes\. It is a good idea to perform
+some other action (type on the keyboard, move the mouse, utilize the
+disks) during the prime generation; this gives the random number
+generator a better chance to gain enough entropy\.
+
+We need to generate a lot of random bytes\. It is a good idea to perform
+some other action (type on the keyboard, move the mouse, utilize the
+disks) during the prime generation; this gives the random number
+generator a better chance to gain enough entropy\.
+
+public and secret key created and signed\.
+key marked as ultimately trusted\.
+
+pub  1024D/4417A8CB 2006\-02\-07 amandabackup (gpg keys for amandabackup)
+     Key fingerprint = 139C 6369 44FC 7F1A 655C  E5E9 7EAA 515A 4417 A8CB
+sub  1024g/8C3A6A78 2006\-02\-07 [expires: 2006\-08\-06]
+.fi
+.SH "FILES"
+.PP
+\fB$AMANDA_HOME/\.gnupg/pubring\.gpg\fR
+.RS 4
+The public key\.
+\fBamgpgcrypt\fR
+encrypt data with this public key along with the cipher algorithm\.
+.RE
+.PP
+\fB$AMANDA_HOME/\.gnupg/secring\.gpg\fR
+.RS 4
+The private/secret key\. It\'s only needed during amrecover/amrestore\. Store and protect it properly during other time\.
+.RE
+.PP
+\fB$AMANDA_HOME/\.am_passphrase\fR
+.RS 4
+The passphrase\. It\'s only needed during amrecover/amrestore\. Store and protect it properly during other time\.
+.RE
+.SH "BUGS"
+.PP
+\fIAmanda\fR
+has problem with gpg mdc(modification detection code) in the binary mode\.
+\fBamgpgcrypt\fR
+calls gpg with mdc disabled
+.SH "AUTHOR"
+.PP
+The tool and its documentation was written by Zmanda, Inc (http://www\.zmanda\.com/)\.
+.SH "SEE ALSO"
+.PP
+
+\fBamanda\fR(8),
+\fBamanda.conf\fR(5),
+\fBamcrypt\fR(8),
+\fBamrestore\fR(8),
+\fBgpg\fR(1),
+: http://wiki.zmanda.com
diff --git a/man/amserverconfig.8 b/man/amserverconfig.8
new file mode 100644 (file)
index 0000000..093899d
--- /dev/null
@@ -0,0 +1,181 @@
+.\"     Title: amserverconfig
+.\"    Author: 
+.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
+.\"      Date: 08/22/2008
+.\"    Manual: 
+.\"    Source: 
+.\"
+.TH "AMSERVERCONFIG" "8" "08/22/2008" "" ""
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+amserverconfig - program to setup initial Amanda configuration
+.SH "SYNOPSIS"
+.HP 15
+\fBamserverconfig\fR \fIconfig\fR [\-\-template\ \fItemplate\fR] [\-\-no\-vtape] [\-\-tapetype\ \fItapetype\fR] [\-\-tpchanger\ \fItpchanger\fR] [\-\-tapedev\ \fItapedev\fR] [\-\-changerfile\ \fIchangerfile\fR] [\-\-changerdev\ \fIchangerdev\fR] [\-\-labelstr\ \fIlabelstr\fR] [\-\-mailto\ \fImailto\fR] [\-\-dumpcycle\ \fIdumpcycle\fR] [\-\-runspercycle\ \fIrunspercycle\fR] [\-\-runtapes\ \fIruntapes\fR] [\-\-tapecycle\ \fItapecycle\fR] [\-\-help]
+.SH "DESCRIPTION"
+.PP
+After Amanda rpms are successfully installed,
+\fBamserverconfig\fR
+will setup initial
+\fIAmanda\fR
+configuration files\. It will create /var/lib/amanda/guntar\-lists directory if one does not exist\.
+\fBamserverconfig\fR
+does not change existing
+\fIAmanda\fR
+configurations\.
+\fBamserverconfig\fR
+must be run by user amandabackup\.
+.SH "OPTIONS"
+.PP
+Options may be abbreviated, as long as the abbreviation is not ambiguous\. Option argument can either separated by \'=\' or a space\. Example: \-\-templ=harddisk \-\-tapedev /dev/nst0
+.PP
+
+\fBamserverconfig\fR
+builds a new "config"
+\fIAmanda\fR
+configuration\. Customize the configuration with the options below\.
+.PP
+\fB\-\-template template\fR
+.RS 4
+build
+\fIAmanda\fR
+configuration with pre\-configured template files\. Currently,
+\fBharddisk\fR,
+\fBsingle\-tape\fR,
+\fBtape\-changer\fR
+and
+\fBS3\fR
+are the valid inputs for this option\. Pre\-configured template files can be found in /var/lib/amanda/template\.d\. This option may be combined with other options\.
+.sp
+If tape\-changer is chosen for this option, program mtx is required\.
+\fBamserverconfig\fR
+will search for mtx in the following directory: "/usr/sbin", "/usr/local/sbin", "/usr/local/bin", "/usr/bin", "/bin" and amandabackup\'s PATH\.
+.sp
+If harddisk is chosen and \-\-no\-vtape is not specified,
+\fBamserverconfig\fR
+will create and label virtual tape file://var/lib/amanda/vtapes/$config\.
+.RE
+.PP
+\fB\-\-no\-vtape\fR
+.RS 4
+Do not create virtual tapes in the harddisk template case\.
+.RE
+.PP
+\fB\-\-tapedev tapedev\fR
+.RS 4
+The path name of non\-rewinding tape device\. default [file://var/lib/amanda/vtapes/$config]
+.RE
+.PP
+\fB\-\-tpchanger tpchanger\fR
+.RS 4
+The name of the tape changer\. default [chg\-disk]
+.RE
+.PP
+\fB\-\-changerdev changerdev\fR
+.RS 4
+A tape changer configuration parameter\. default [/dev/null]
+.RE
+.PP
+\fB\-\-changerfile changerfile\fR
+.RS 4
+A tape changer configuration parameter\. default [/etc/amanda/$config/changer\.conf]
+.RE
+.PP
+\fB\-\-labelstr labelstr\fR
+.RS 4
+The tape label constraint regular expression\. default [^$config\-[0\-9][0\-9]*$]
+.sp
+If this option is used with \-\-template=harddisk, only alphanumeric string is supported\.
+.RE
+.PP
+\fB\-\-tapetype tapetype\fR
+.RS 4
+The type of tape drive associated with tapedev or tpchanger\. default [HARDDISK]
+.RE
+.PP
+\fB\-\-mailto mailto\fR
+.RS 4
+A space separated list of recipients for mail reports\. default [amandabackup]
+.RE
+.PP
+\fB\-\-dumpcycle dumpcycle\fR
+.RS 4
+The number of days in the backup cycle\. default [1week]
+.RE
+.PP
+\fB\-\-runspercycle runspercycle\fR
+.RS 4
+The number of days in the backup cycle\. default [5]
+.RE
+.PP
+\fB\-\-runtapes runtapes\fR
+.RS 4
+The maximum number of tapes used in a single run\. default [1]
+.RE
+.PP
+\fB\-\-tapecycle tapecycle\fR
+.RS 4
+The size of tape rotation\. default [25]
+.RE
+.PP
+\fB\-\-help\fR
+.RS 4
+Display usage\.
+.RE
+.SH "FILES"
+.PP
+\fB/var/lib/amanda/template\.d\fR
+.RS 4
+Amanda configuration template files install location
+.RE
+.PP
+\fB/var/lib/amanda\fR
+.RS 4
+amandabackup home directory
+.RE
+.PP
+\fB/var/lib/amanda/gnutar\-lists\fR
+.RS 4
+A directory which contains backup timestamp and list of files backed up\.
+.RE
+.PP
+\fB/etc/amanda/$config\fR
+.RS 4
+\fIAmanda\fR
+configuration files location for $config(e\.g: DailySet1)\.
+.RE
+.PP
+\fB/etc/amanda/template\.d\fR
+.RS 4
+A directory contains dumptypes and tapetypes files used by all
+\fIAmanda\fR
+configurations\.
+.RE
+.PP
+\fB/etc/amandates\fR
+.RS 4
+\fIAmanda\fR
+file on the client\. It keeps track of structures of previous dumps\.
+.RE
+.PP
+\fB/tmp/amanda\fR
+.RS 4
+directory contains
+\fIAmanda\fR
+debug log files\.
+.RE
+.SH "RETURN VALUE"
+
+On success, zero is returned\.  On error, 1 is returned\.
+.SH "AUTHOR"
+.PP
+The tool and its documentation was written by Zmanda, Inc (http://www\.zmanda\.com/)\.
+.SH "SEE ALSO"
+.PP
+\fBamanda\fR(8),
+\fBamanda.conf\fR(5),
+\fBamaddclient\fR(8),
+: http://wiki.zmanda.com
diff --git a/man/index.php b/man/index.php
new file mode 100644 (file)
index 0000000..5322dd6
--- /dev/null
@@ -0,0 +1,4 @@
+<?php
+/* send the user straight to the amanda(8) manpage */
+header("Location: amanda.8.html");
+exit;
diff --git a/man/xml-source/amaddclient.8.xml b/man/xml-source/amaddclient.8.xml
new file mode 100644 (file)
index 0000000..36bb72a
--- /dev/null
@@ -0,0 +1,286 @@
+
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+                   "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"
+[
+  <!-- entities files to use -->
+  <!ENTITY % global_entities SYSTEM '../entities/global.entities'>
+  %global_entities;
+]>
+
+<refentry id='amaddclient.8'>
+<refmeta>
+<refentrytitle>amaddclient</refentrytitle>
+<manvolnum>8</manvolnum>
+</refmeta>
+<refnamediv>
+<refname>amaddclient</refname>
+<refpurpose>program to add client to an existing &A; configuration</refpurpose>
+</refnamediv>
+<!-- body begins here -->
+<refsynopsisdiv>
+<cmdsynopsis>
+  <command>amaddclient</command>  
+<arg choice='plain'>--config </arg>
+<arg choice='plain'><replaceable>config</replaceable></arg> ||
+<arg choice='plain'>--client </arg><arg
+    choice='plain'><replaceable>client name</replaceable></arg> ||
+<arg choice='plain'>--diskdev </arg><arg
+    choice='plain'><replaceable>directory to backup</replaceable></arg>
+<arg choice='opt'>--m </arg>
+<arg choice='opt'>--dumptype <replaceable>string</replaceable></arg>
+<arg choice='opt'>--includefile <replaceable>string</replaceable></arg>
+<arg choice='opt'>--includelist <replaceable>string</replaceable></arg>
+<arg choice='opt'>--excludefile <replaceable>string</replaceable></arg>
+<arg choice='opt'>--excludelist <replaceable>string</replaceable></arg>
+<arg choice='opt'>--user <replaceable>string</replaceable></arg>
+<arg choice='opt'>--auth <replaceable>string</replaceable></arg>
+<arg choice='opt'>--gnutar_list_dir <replaceable>string</replaceable></arg>
+<arg choice='opt'>--amandates <replaceable>string</replaceable></arg>
+<arg choice='opt'>--no-client-update </arg>
+<arg choice='opt'>--batch </arg>
+<arg choice='opt'>--help </arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>After Amanda rpms are successfully installed and
+&amserverconfig; is run,
+         &amaddclient; will add client to the  &A; configuration.
+&amaddclient; create or update &A; disklist file and create or update
+/var/lib/amanda/.amandahosts file on the server.</para>
+<para> If --no-client-update is not specified,
+&amaddclient; will attempt to update or create /var/lib/amanda/.amandahost,
+amanda-client.conf and gnutar-lists on
+the client.
+(See <refentrytitle>ssh-keygen</refentrytitle><manvolnum>1</manvolnum> and
+<refentrytitle>ssh-add</refentrytitle><manvolnum>1</manvolnum> for detail.)</para>
+<para>
+&amaddclient; must be run by user amandabackup.</para>
+<para> --config, --client and --diskdev must be specified.
+</para> 
+</refsect1>
+
+
+<refsect1><title>Options</title>
+<variablelist remap='TP'>
+ <varlistentry>
+Options may be abbreviated, as long as the abbreviation is not ambiguous. Option argument can either separated by '=' or a space.
+Example: --conf=v253, --client client8.zmanda.com
+</varlistentry>
+
+
+  <varlistentry>
+  <term><option>--config config</option></term>
+  <listitem>
+<para>&A; configuration which this program will add the client to.  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--client client</option></term>
+  <listitem>
+<para>The name of the client machine to add. FQDN name recommended. </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--diskdev diskdev</option></term>
+  <listitem>
+<para>Directory for this &A; configuration to backup.</para>
+  </listitem>
+  </varlistentry>
+
+
+  <varlistentry>
+  <term><option>--m</option></term>
+  <listitem>
+<para>Modify existing entry in the disklist file.</para>
+<para>Note: if disklist file has been modified manually, this option might not work.</para>
+  </listitem>
+  </varlistentry>
+
+
+  <varlistentry>
+  <term><option>--dumptype dumptype</option></term>
+  <listitem>
+<para>dumptype to use. Dumptype must be defined in
+/etc/amanda/template.d/dumptypes or /etc/amanda/$config/amanda.conf file.  Default: [user-tar]</para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--user string</option></term>
+  <listitem>
+<para> name of user using &amrecover; on the client, default is root.</para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--auth string</option></term>
+  <listitem>
+<para> authentication method to use when running &amrecover; from the client , default is bsdtcp.</para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--gnutar_list_dir string</option></term>
+  <listitem>
+<para> directory where gnutar keep its state file on the client. Absolute path
+required. Default is /var/lib/amanda/gnutar-lists. If --no-client-update is not
+set, this program will attempt to create the directory on the client. </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--amandates string</option></term>
+  <listitem>
+<para> file where amanda keep the date of each dumplevel on the client, default is /etc/amandates.</para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--batch</option></term>
+  <listitem>
+<para>Turn on batch mode when copying files to the client, default is off</para>
+  </listitem>
+  </varlistentry>
+
+<varlistentry>
+  <term><option>--no-client-update</option></term>
+  <listitem>
+<para>If this option is set,  &amaddclient; will not attempt to update/create
+.amandahosts, amanda-client.conf and gnutar-lists file on the client.</para>
+  </listitem>
+  </varlistentry>
+
+
+  <varlistentry>
+  <term><option>--help</option></term>
+  <listitem>
+<para>Display usage. </para>
+  </listitem>
+  </varlistentry>
+
+<varlistentry> 
+If any of the following four options are used, &amaddclient; will extend the dumptype definition to an in-line definition in the disklist file. See <citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry> DISKLIST FILE section for detail.
+</varlistentry>
+
+  <varlistentry>
+  <term><option>--includefile string</option></term>
+  <listitem>
+<para>string is a glob expression  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--includelist string</option></term>
+  <listitem>
+<para> string is a file name on the client containing glob expressions.
+Specify either --includefile or --includelist. </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--excludefile string</option></term>
+  <listitem>
+<para>string is a glob expression  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--excludelist string</option></term>
+  <listitem>
+<para> string is a file name on the client containing glob expressions.
+Specify either --excludefile or --excludelist. </para>
+  </listitem>
+  </varlistentry>
+
+
+
+</variablelist>
+</refsect1>
+
+<refsect1><title>Files</title>
+<variablelist remap='TP'>
+ <varlistentry>
+ <term><option>/var/lib/amanda/template.d</option></term>
+  <listitem>
+<para>Amanda configuration template files install location</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/var/lib/amanda</option></term>
+  <listitem>
+<para>amandabackup home directory</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/var/lib/amanda/.amandahosts</option></term>
+  <listitem>
+<para>&A; authentication file.</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/var/lib/amanda/gnutar-lists</option></term>
+  <listitem>
+<para>A directory which contains backup timestamp and list of files backed up.</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/etc/amanda/$config</option></term>
+  <listitem>
+<para>&A; configuration files location for $config(e.g: DailySet1).</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/etc/amanda/template.d</option></term>
+  <listitem>
+<para>A directory contains dumptypes and tapetypes files used by all &A; configurations.</para>
+  </listitem>
+  </varlistentry>
+
+
+ <varlistentry>
+ <term><option>/etc/amandates</option></term>
+  <listitem>
+<para>&A; file on the client. It keeps track of structures of previous dumps.</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/tmp/amanda</option></term>
+  <listitem>
+<para>directory contains &A; debug log files.</para>
+  </listitem>
+  </varlistentry>
+
+</variablelist>
+</refsect1>        
+
+<refsect1><title>RETURN VALUE</title>
+On success, zero is returned.  On error, 1 is returned.
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+  <para>
+    The tool and its documentation was written by Zmanda, Inc (http://www.zmanda.com/). 
+  </para>
+</refsect1>
+
+<refsect1><title>SEE ALSO</title>
+<para><citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>amanda.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>amserverconfig</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+<citerefentry><refentrytitle>ssh-keygen</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+<citerefentry><refentrytitle>ssh-add</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+<citerefentry><refentrytitle>scp</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+<ulink url="http://wiki.zmanda.com"/>
+</para>
+</refsect1>
+</refentry>
+
diff --git a/man/xml-source/amcheckdump.8.xml b/man/xml-source/amcheckdump.8.xml
new file mode 100644 (file)
index 0000000..e37da35
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+                   "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"
+[
+  <!-- entities files to use -->
+  <!ENTITY % global_entities SYSTEM '../entities/global.entities'>
+  %global_entities;
+]>
+
+<refentry id='amcheckdump.8'>
+<refmeta>
+<refentrytitle>amcheckdump</refentrytitle>
+<manvolnum>8</manvolnum>
+</refmeta>
+<refnamediv>
+<refname>amcheckdump</refname>
+<refpurpose>check the results of an &A; dump</refpurpose>
+</refnamediv>
+<!-- body begins here -->
+<refsynopsisdiv>
+<cmdsynopsis>
+  <command>amcheckdump</command>    
+    <arg choice='plain'><replaceable>config</replaceable></arg>
+    <arg choice='opt'>--timestamp|-t <replaceable>timestamp</replaceable></arg>
+    <arg choice='plain' rep='repeat'><group><arg choice='plain'>-o </arg><replaceable>configoption</replaceable></group></arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+
+<para><emphasis remap='B'>Amcheckdump</emphasis> verifies &A; dump images by
+reading them from storage volume(s) and verifying that the images can be parsed
+by the appropriate application (if available).  For example, a GNUTAR
+image is passed to GNU Tar for parsing, and any errors
+(e.g., corrupt or missing data) are noted.</para>
+
+<para>The application runs on the most recent dump or, if <emphasis
+remap='I'>--timestamp</emphasis> is specified, on the most recent dump with
+that timestamp.  Note that the verification is local to the &A; server; if the
+dump application is not available, or is configured differently on the server
+than on the client, then the verification will most likely fail.</para>
+
+<para>If a changer is available, it is used to load the required
+tapes.  Otherwise, the application interactively requests the tapes.</para>
+
+<para>See the "<emphasis
+remap='B'>CONFIGURATION OVERRIDE</emphasis>" section in
+<citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+for information on the <literal>-o</literal> option.</para>
+</refsect1>
+ <refsect1><title>SEE ALSO</title>
+ <para><citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <ulink url="http://wiki.zmanda.com"/>
+ </para>
+ </refsect1> 
+
+<refsect1><title>EXAMPLE</title>
+<para><programlisting>
+# check the most recent dump
+amcheckdump MYCONFIG
+
+# check a specific dump from back in '78
+amcheckdump MYCONFIG --timestamp 19780615
+</programlisting></para>
+</refsect1>
+ <refsect1><title>SEE ALSO</title>
+ <para><citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>,  
+ <citerefentry><refentrytitle>http://wiki.zmanda.com</refentrytitle></citerefentry>          
+ </para>
+ </refsect1>                                                                          
+</refentry>
diff --git a/man/xml-source/amcryptsimple.8.xml b/man/xml-source/amcryptsimple.8.xml
new file mode 100644 (file)
index 0000000..29151e1
--- /dev/null
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+                   "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"
+[
+  <!-- entities files to use -->
+  <!ENTITY % global_entities SYSTEM '../entities/global.entities'>
+  %global_entities;
+]>
+
+<refentry id='amcryptsimple.8'>
+<refmeta>
+<refentrytitle>amcryptsimple</refentrytitle>
+<manvolnum>8</manvolnum>
+</refmeta>
+<refnamediv>
+<refname>amcryptsimple</refname>
+<refpurpose>reference simple crypt program for &A; symmetric data encryption</refpurpose>
+</refnamediv>
+<!-- body begins here -->
+<refsynopsisdiv>
+<cmdsynopsis>
+  <command>amcryptsimple</command>  to be called by &A; only 
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>&amcryptsimple;
+calls <emphasis remap='B'>gpg</emphasis> to perform symmetric data encryption
+on &A; backup.
+&amcryptsimple; will search for the gpg program in the following directories:
+/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin</para>
+<para>&amcryptsimple; uses one passphrase to encrypt the &A; data
+and uses the same passphrase to decrypt the &A; backup data. &amcryptsimple; uses
+AES256 as the symmetric cipher.</para> 
+</refsect1>
+
+
+<refsect1><title>How to Create Passphrase</title>
+
+Store  the  passphrase  inside the home-directory of the AMANDA-user($amanda_user) and protect it with proper permissions:
+
+   echo my_secret_passphrase > ~$amanda_user/.am_passphrase
+   chown $amanda_user:disk ~$amanda_user/.am_passphrase
+   chmod 700 ~$amanda_user/.am_passphrase
+</refsect1>
+
+<refsect1><title>NOTES</title>
+<para>Choose a good passphrase and protect it properly. Backup data can only be
+restored with the passphrase. There is no backdoor.</para>
+<para>If storing and securing passphrase in your environment presents challenges,
+&A; provide public-key data encryption through &amgpgcrypt;. Public-key
+encryption uses the public key to encrypt and uses the private key to decrypt.</para>
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+  <para>
+    The tool and its documentation was written by Zmanda, Inc (http://www.zmanda.com/). 
+  </para>
+</refsect1>
+
+<refsect1><title>SEE ALSO</title>
+<para><citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>amanda.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>amcrypt</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>amgpgcrypt</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>amrestore</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>gpg</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+<ulink url="http://wiki.zmanda.com"/>
+</para>
+</refsect1>
+</refentry>
+
diff --git a/man/xml-source/amdevcheck.8.xml b/man/xml-source/amdevcheck.8.xml
new file mode 100644 (file)
index 0000000..d4ca82d
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+                   "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"
+[
+  <!-- entities files to use -->
+  <!ENTITY % global_entities SYSTEM '../entities/global.entities'>
+  %global_entities;
+]>
+
+<refentry id='amdevcheck.8'>
+
+  <refmeta>
+    <refentrytitle>amdevcheck</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>amdevcheck</refname>
+    <refpurpose>Validate an &A; device and volume.</refpurpose>
+  </refnamediv>
+  <!-- body begins here -->
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>amdevcheck</command>
+      <arg choice='plain'><replaceable>config</replaceable></arg>
+      <group choice='opt'>
+        <arg choice='plain'><replaceable>device name</replaceable></arg>
+      </group>
+      <arg choice='plain' rep='repeat'><group><arg choice='plain'>-o
+      </arg><replaceable>configoption</replaceable></group></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1><title>DESCRIPTION</title>
+    <para>
+      <emphasis remap='B'>Amdevcheck</emphasis> provides a way to check that a
+      particular &A; device is accessible, whether or not it contains a volume,
+      and whether or not that volume is labeled. Some devices can't distinguish
+      between all of these cases; a missing volume and an unlabeled volume might
+      generate the same error code, for example. In those cases, this tool
+      reports all possible causes of the error.
+    </para>
+    
+    <para>See the
+      <citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      man page for more details about &A;.
+      See the
+      <emphasis remap='B'>OUTPUT DRIVERS</emphasis>
+      section of
+      <emphasis remap='I'>amanda(8)</emphasis>
+      for more information on the &A; output drivers.
+  </para>
+  </refsect1>
+
+  <refsect1><title>OPTIONS</title>
+    <variablelist remap='TP'>
+      <varlistentry>
+        <term><replaceable>config</replaceable></term>
+        <listitem>
+          <para>
+            &A; configuration to use. Note that <command>amdevcheck</command>
+            ignores any tape changer configuration.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><replaceable> device</replaceable></term>
+        <listitem>
+          <para>
+            &A; device to use. This option overrides any tapedev configuration
+            specified in the configuration file.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><emphasis remap='B'>-o</emphasis> <replaceable>clientconfigoption</replaceable></term>
+        <listitem>
+          <para>See the "<emphasis remap='B'>CONFIGURATION OVERRIDE</emphasis>"
+            section in
+            <citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>AUTHOR</title>
+    <para>
+      Ian Turner <email>ian@zmanda.com</email> and others. Authorship of this
+      tool and its documentation was funded by Zmanda, Inc.
+    </para>
+  </refsect1>
+
+  <refsect1><title>SEE ALSO</title>
+    <para>
+      <citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>ammt</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <ulink url="http://wiki.zmanda.com"/>
+    </para>
+  </refsect1>
+</refentry>
diff --git a/man/xml-source/amgpgcrypt.8.xml b/man/xml-source/amgpgcrypt.8.xml
new file mode 100644 (file)
index 0000000..a2db468
--- /dev/null
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+                   "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"
+[
+  <!-- entities files to use -->
+  <!ENTITY % global_entities SYSTEM '../entities/global.entities'>
+  %global_entities;
+]>
+
+<refentry id='amgpgcrypt.8'>
+<refmeta>
+<refentrytitle>amgpgcrypt</refentrytitle>
+<manvolnum>8</manvolnum>
+</refmeta>
+<refnamediv>
+<refname>amgpgcrypt</refname>
+<refpurpose>reference crypt program for &A; public-key data encryption</refpurpose>
+</refnamediv>
+<!-- body begins here -->
+<refsynopsisdiv>
+<cmdsynopsis>
+  <command>amgpgcrypt</command>  to be called by &A; only 
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>&amgpgcrypt;
+calls <emphasis remap='B'>gpg</emphasis> to perform public-key data encryption
+on &A; backup.
+&amgpgcrypt; will search for the gpg program in the following directories:
+/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin</para>
+<para>&amgpgcrypt; sets GNUPGHOME to $AMANDA_HOME/.gnupg where gpg will look for the
+gpg keys.
+&amgpgcrypt; uses the public key to encrypt the &A; data
+and uses the private key to decrypt the &A; backup data. Thus, passphrase is only
+required at the time of data restore.</para> 
+</refsect1>
+
+
+<refsect1><title>Key and Passphrase</title>
+<para>&amgpgcrypt; uses the  private key to decrypt &A; backup data.</para>
+It is very important to store, manage and  protect the key and the passphrase
+properly. Encrypted backup data can <emphasis remap='B'>only</emphasis> be recovered with the correct key and
+passphrase.
+</refsect1>
+
+
+
+<refsect1><title>How to create encryption keys and Passphrase for amgpgcrypt</title>
+
+<para>Store the  passphrase that you used in following "gpg --gen-key" command  inside the home-directory of the AMANDA-user($amanda_user) and protect it with proper permissions:</para>
+   echo my_secret_passphrase > ~$amanda_user/.am_passphrase
+   chown $amanda_user:disk ~$amanda_user/.am_passphrase
+   chmod 700 ~$amanda_user/.am_passphrase
+<para> Run "gpg --gen-key". Below is an example:</para>
+<programlisting>
+$ gpg --gen-key
+gpg (GnuPG) 1.2.6; Copyright (C) 2004 Free Software Foundation, Inc.
+This program comes with ABSOLUTELY NO WARRANTY.
+This is free software, and you are welcome to redistribute it
+under certain conditions. See the file COPYING for details.
+
+Please select what kind of key you want:
+   (1) DSA and ElGamal (default)
+   (2) DSA (sign only)
+   (4) RSA (sign only)
+Your selection? 1
+DSA keypair will have 1024 bits.
+About to generate a new ELG-E keypair.
+              minimum keysize is  768 bits
+              default keysize is 1024 bits
+    highest suggested keysize is 2048 bits
+What keysize do you want? (1024)
+Requested keysize is 1024 bits
+Please specify how long the key should be valid.
+         0 = key does not expire
+      (n)  = key expires in n days
+      (n)w = key expires in n weeks
+      (n)m = key expires in n months
+      (n)y = key expires in n years
+Key is valid for? (0) 6m
+Key expires at Sun 06 Aug 2006 03:51:25 PM PDT
+Is this correct (y/n)? y
+
+You need a User-ID to identify your key; the software constructs the user id
+from Real Name, Comment and Email Address in this form:
+    "Heinrich Heine (Der Dichter) (heinrichh@duesseldorf.de)"
+
+Real name: amandabackup
+Email address:
+Comment: gpg keys for amandabackup
+You selected this USER-ID:
+    "amandabackup (gpg keys for amandabackup)"
+
+Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
+You need a Passphrase to protect your secret key.
+
+We need to generate a lot of random bytes. It is a good idea to perform
+some other action (type on the keyboard, move the mouse, utilize the
+disks) during the prime generation; this gives the random number
+generator a better chance to gain enough entropy.
+
+We need to generate a lot of random bytes. It is a good idea to perform
+some other action (type on the keyboard, move the mouse, utilize the
+disks) during the prime generation; this gives the random number
+generator a better chance to gain enough entropy.
+
+public and secret key created and signed.
+key marked as ultimately trusted.
+
+pub  1024D/4417A8CB 2006-02-07 amandabackup (gpg keys for amandabackup)
+     Key fingerprint = 139C 6369 44FC 7F1A 655C  E5E9 7EAA 515A 4417 A8CB
+sub  1024g/8C3A6A78 2006-02-07 [expires: 2006-08-06]
+
+</programlisting>
+</refsect1>
+
+
+<refsect1><title>Files</title>
+<variablelist remap='TP'>
+ <varlistentry>
+ <term><option>$AMANDA_HOME/.gnupg/pubring.gpg</option></term>
+  <listitem>
+<para>The public key. &amgpgcrypt; encrypt data with this public key along with the
+cipher algorithm.</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>$AMANDA_HOME/.gnupg/secring.gpg</option></term>
+  <listitem>
+<para>The private/secret key. It's only needed during amrecover/amrestore. Store
+and protect it properly during other time.</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>$AMANDA_HOME/.am_passphrase</option></term>
+  <listitem>
+<para>The passphrase. It's only needed during amrecover/amrestore. Store
+and protect it properly during other time.</para>
+  </listitem>
+  </varlistentry>
+
+
+</variablelist>
+</refsect1>
+
+
+<refsect1><title>BUGS</title>
+<para>&A; has problem with gpg mdc(modification detection code) in the binary
+mode. &amgpgcrypt; calls gpg with mdc disabled</para>
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+  <para>
+    The tool and its documentation was written by Zmanda, Inc (http://www.zmanda.com/). 
+  </para>
+</refsect1>
+
+<refsect1><title>SEE ALSO</title>
+<para>
+  <citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+  <citerefentry><refentrytitle>amanda.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+  <citerefentry><refentrytitle>amcrypt</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+  <citerefentry><refentrytitle>amrestore</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+  <citerefentry><refentrytitle>gpg</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+  <ulink url="http://wiki.zmanda.com"/>
+</para>
+</refsect1>
+</refentry>
+
diff --git a/man/xml-source/amserverconfig.8.xml b/man/xml-source/amserverconfig.8.xml
new file mode 100644 (file)
index 0000000..22a4f44
--- /dev/null
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+                   "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"
+[
+  <!-- entities files to use -->
+  <!ENTITY % global_entities SYSTEM '../entities/global.entities'>
+  %global_entities;
+]>
+
+<refentry id='amserverconfig.8'>
+<refmeta>
+<refentrytitle>amserverconfig</refentrytitle>
+<manvolnum>8</manvolnum>
+</refmeta>
+<refnamediv>
+<refname>amserverconfig</refname>
+<refpurpose>program to setup initial &A; configuration</refpurpose>
+</refnamediv>
+<!-- body begins here -->
+<refsynopsisdiv>
+<cmdsynopsis>
+  <command>amserverconfig</command>  
+<arg choice='plain'><replaceable>config</replaceable></arg>
+<arg choice='opt'>--template <replaceable>template</replaceable></arg>
+<arg choice='opt'>--no-vtape </arg>
+<arg choice='opt'>--tapetype <replaceable>tapetype</replaceable></arg>
+<arg choice='opt'>--tpchanger <replaceable>tpchanger</replaceable></arg>
+<arg choice='opt'>--tapedev <replaceable>tapedev</replaceable></arg>
+<arg choice='opt'>--changerfile <replaceable>changerfile</replaceable></arg>
+<arg choice='opt'>--changerdev <replaceable>changerdev</replaceable></arg>
+<arg choice='opt'>--labelstr <replaceable>labelstr</replaceable></arg>
+<arg choice='opt'>--mailto <replaceable>mailto</replaceable></arg>
+<arg choice='opt'>--dumpcycle <replaceable>dumpcycle</replaceable></arg>
+<arg choice='opt'>--runspercycle <replaceable>runspercycle</replaceable></arg>
+<arg choice='opt'>--runtapes <replaceable>runtapes</replaceable></arg>
+<arg choice='opt'>--tapecycle <replaceable>tapecycle</replaceable></arg>
+<arg choice='opt'>--help </arg>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1><title>DESCRIPTION</title>
+<para>After Amanda rpms are successfully installed,
+         &amserverconfig; will setup initial &A; configuration files.
+It will create /var/lib/amanda/guntar-lists directory if one does
+         not exist.
+&amserverconfig; does not change existing &A; configurations.
+&amserverconfig; must be run by user amandabackup.
+</para> 
+</refsect1>
+
+
+<refsect1><title>Options</title>
+<para>Options may be abbreviated, as long as the abbreviation is not ambiguous. Option argument can either separated by '=' or a space.
+Example:  --templ=harddisk --tapedev /dev/nst0</para>
+
+<para>&amserverconfig; builds a new "config" &A; configuration. Customize the configuration with the options below.</para>
+
+<variablelist remap='TP'>
+  <varlistentry>
+  <term><option>--template template</option></term>
+  <listitem>
+<para>build &A; configuration with pre-configured template files. Currently,
+                <emphasis remap='B'>harddisk</emphasis>, <emphasis
+               remap='B'>single-tape</emphasis>, <emphasis remap='B'>tape-changer</emphasis> and <emphasis remap='B'>S3</emphasis> 
+               are the valid inputs for this option. Pre-configured template files can be found in 
+               /var/lib/amanda/template.d. This option may be combined with other options.
+               </para>
+<para>If tape-changer is chosen for this option, program mtx is required. &amserverconfig; will
+search for mtx in the following directory: "/usr/sbin", "/usr/local/sbin",
+"/usr/local/bin", "/usr/bin", "/bin" and amandabackup's PATH.
+</para>
+<para>
+If harddisk is chosen and --no-vtape is not specified, &amserverconfig; will create and label virtual tape
+file://var/lib/amanda/vtapes/$config.
+</para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--no-vtape</option></term>
+  <listitem>
+<para>Do not create virtual tapes in the harddisk template case. </para>
+  </listitem>
+  </varlistentry>
+
+
+  <varlistentry>
+  <term><option>--tapedev tapedev</option></term>
+  <listitem>
+<para>The path name of non-rewinding tape device. 
+default [file://var/lib/amanda/vtapes/$config]  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--tpchanger tpchanger</option></term>
+  <listitem>
+<para>The name of the tape changer. default [chg-disk]  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--changerdev changerdev</option></term>
+  <listitem>
+<para>A tape changer configuration parameter. default [/dev/null]  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--changerfile changerfile</option></term>
+  <listitem>
+<para>A tape changer configuration parameter. default [/etc/amanda/$config/changer.conf]  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--labelstr labelstr</option></term>
+  <listitem>
+<para>The tape label constraint regular expression. default [^$config-[0-9][0-9]*$]  </para>
+<para>If this option is used with --template=harddisk, only alphanumeric string
+is supported.</para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--tapetype tapetype</option></term>
+  <listitem>
+<para>The type of tape drive associated with tapedev or  tpchanger. default [HARDDISK]  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--mailto mailto</option></term>
+  <listitem>
+<para> A space separated list of recipients for mail reports. default [amandabackup]  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--dumpcycle dumpcycle</option></term>
+  <listitem>
+<para>The number of days in the backup cycle. default [1week]  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--runspercycle runspercycle</option></term>
+  <listitem>
+<para>The number of days in the backup cycle. default [5]  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--runtapes runtapes</option></term>
+  <listitem>
+<para>The maximum number of tapes used in a single run. default [1]  </para>
+  </listitem>
+  </varlistentry>
+
+  <varlistentry>
+  <term><option>--tapecycle tapecycle</option></term>
+  <listitem>
+<para>The size of tape rotation. default [25]  </para>
+  </listitem>
+  </varlistentry>
+
+
+  <varlistentry>
+  <term><option>--help</option></term>
+  <listitem>
+<para>Display usage. </para>
+  </listitem>
+  </varlistentry>
+
+</variablelist>
+</refsect1>
+
+<refsect1><title>Files</title>
+<variablelist remap='TP'>
+ <varlistentry>
+ <term><option>/var/lib/amanda/template.d</option></term>
+  <listitem>
+<para>Amanda configuration template files install location</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/var/lib/amanda</option></term>
+  <listitem>
+<para>amandabackup home directory</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/var/lib/amanda/gnutar-lists</option></term>
+  <listitem>
+<para>A directory which contains backup timestamp and list of files backed up.</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/etc/amanda/$config</option></term>
+  <listitem>
+<para>&A; configuration files location for $config(e.g: DailySet1).</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/etc/amanda/template.d</option></term>
+  <listitem>
+<para>A directory contains dumptypes and tapetypes files used by all &A; configurations.</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/etc/amandates</option></term>
+  <listitem>
+<para>&A; file on the client. It keeps track of structures of previous dumps.</para>
+  </listitem>
+  </varlistentry>
+
+ <varlistentry>
+ <term><option>/tmp/amanda</option></term>
+  <listitem>
+<para>directory contains &A; debug log files.</para>
+  </listitem>
+  </varlistentry>
+
+</variablelist>
+</refsect1>
+
+<refsect1><title>RETURN VALUE</title>
+On success, zero is returned.  On error, 1 is returned.
+</refsect1>
+
+<refsect1><title>AUTHOR</title>
+  <para>
+    The tool and its documentation was written by Zmanda, Inc (http://www.zmanda.com/). 
+  </para>
+</refsect1>
+
+
+<refsect1><title>SEE ALSO</title>
+<para><citerefentry><refentrytitle>amanda</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>amanda.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>amaddclient</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+<ulink url="http://wiki.zmanda.com"/>
+</para>
+</refsect1>
+</refentry>
+
diff --git a/man/xslt/html.xsl.in b/man/xslt/html.xsl.in
new file mode 100644 (file)
index 0000000..03ae385
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version='1.0'?>
+<!-- vim:set sts=2 shiftwidth=2 syntax=xml: -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version='1.0'>
+
+
+<!-- the @..@ is substituted by config.status to contain the XSL release selected
+     at configure time -->
+<xsl:import href="http://docbook.sourceforge.net/release/xsl/@XSLREL@/html/docbook.xsl"/>
+
+<xsl:import href="settings.xsl"/>
+
+<xsl:param name="citerefentry.link" select="'1'"/>
+<xsl:param name="css.decoration" select="1"/>
+<xsl:param name="html.stylesheet" select="'amanda.css'"/>
+<xsl:param name="html.stylesheet.type">text/css</xsl:param>
+<xsl:param name="html.cleanup" select="1"/>
+<xsl:param name="use.extensions" select="'0'"/>
+<xsl:param name="use.id.as.filename" select="'0'"/>
+<xsl:param name="use.local.olink.style" select="1"/>
+<xsl:param name="use.role.as.xrefstyle" select="1"/>
+
+<!-- generate correct links to other manpages -->
+<xsl:template name="generate.citerefentry.link">
+  <xsl:value-of select="refentrytitle"/><xsl:text>.</xsl:text><xsl:value-of select="manvolnum"/><xsl:text>.html</xsl:text>
+</xsl:template>
+
+<xsl:template match="author">
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/man/xslt/man.xsl.in b/man/xslt/man.xsl.in
new file mode 100644 (file)
index 0000000..2453bc0
--- /dev/null
@@ -0,0 +1,72 @@
+<?xml version='1.0'?>
+<!-- vim:set sts=2 shiftwidth=2 syntax=xml: -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version='1.0'>
+
+
+<!-- the @..@ is substituted by config.status to contain the XSL release selected
+     at configure time -->
+<xsl:import href="http://docbook.sourceforge.net/release/xsl/@XSLREL@/manpages/docbook.xsl"/>
+
+<xsl:import href="settings.xsl"/>
+
+<xsl:param name="chunk.section.depth" select="0"/>
+<xsl:param name="chunk.first.sections" select="1"/>
+<xsl:param name="use.id.as.filename" select="0"/>
+
+<!--
+    Our ulink stylesheet omits @url part if content was specified
+-->
+<xsl:template match="ulink">
+  <xsl:variable name="content">
+    <xsl:apply-templates/>
+  </xsl:variable>
+  <xsl:if test="$content = ''">
+    <xsl:text>: </xsl:text>
+  </xsl:if>
+  <xsl:if test="$content != ''">
+    <xsl:value-of select="$content" />
+  </xsl:if>
+  <xsl:if test="$content = ''">
+    <xsl:apply-templates mode="italic" select="@url" />
+  </xsl:if>
+</xsl:template>
+
+<xsl:template match="informalexample|screen|programlisting">
+  <xsl:text>.nf&#10;</xsl:text>
+  <xsl:apply-templates/>
+  <xsl:text>.fi&#10;</xsl:text>
+</xsl:template>
+
+<xsl:template match="para|simpara|remark" mode="list">
+  <xsl:variable name="foo">
+    <xsl:apply-templates/>
+  </xsl:variable>
+  <xsl:choose match="node()">
+    <!-- Don't normalize-space() for verbatim paragraphs        -->
+    <xsl:when test="informalexample|screen|programlisting">
+      <xsl:value-of select="$foo"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:value-of select="normalize-space($foo)"/>
+      <xsl:text>&#10;</xsl:text>
+    </xsl:otherwise>
+  </xsl:choose>
+  <xsl:text>&#10;</xsl:text>
+  <xsl:if test="following-sibling::para or following-sibling::simpara or
+               following-sibling::remark">
+    <!-- Make sure multiple paragraphs within a list item don't -->
+    <!-- merge together.                                        -->
+    <xsl:text>&#10;</xsl:text>
+  </xsl:if>
+</xsl:template>
+
+<xsl:template match="refsect3">
+  <xsl:text>&#10;.SS "</xsl:text>
+  <xsl:value-of select="title[1]"/>
+  <xsl:text>"&#10;</xsl:text>
+  <xsl:apply-templates/>
+</xsl:template>
+
+
+</xsl:stylesheet>
diff --git a/packaging/Makefile.am b/packaging/Makefile.am
new file mode 100644 (file)
index 0000000..db33d59
--- /dev/null
@@ -0,0 +1,8 @@
+EXTRA_DIST = \
+       deb \
+       rpm \
+       Makefile.am \
+       README 
+
+dist-hook:
+       rm -rf `find ${distdir} -name .svn`
diff --git a/packaging/Makefile.in b/packaging/Makefile.in
new file mode 100644 (file)
index 0000000..1952026
--- /dev/null
@@ -0,0 +1,734 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = packaging
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps =  \
+       $(top_srcdir)/config/macro-archive/ac_define_dir.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_perl_version.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_swig.m4 \
+       $(top_srcdir)/config/macro-archive/ax_compare_version.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-dtd.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt-min.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt.m4 \
+       $(top_srcdir)/config/macro-archive/xsltproc.m4 \
+       $(top_srcdir)/config/amanda/amplot.m4 \
+       $(top_srcdir)/config/amanda/bsd-security.m4 \
+       $(top_srcdir)/config/amanda/bsdtcp-security.m4 \
+       $(top_srcdir)/config/amanda/bsdudp-security.m4 \
+       $(top_srcdir)/config/amanda/changer.m4 \
+       $(top_srcdir)/config/amanda/components.m4 \
+       $(top_srcdir)/config/amanda/compress.m4 \
+       $(top_srcdir)/config/amanda/config.m4 \
+       $(top_srcdir)/config/amanda/debugging.m4 \
+       $(top_srcdir)/config/amanda/defaults.m4 \
+       $(top_srcdir)/config/amanda/devprefix.m4 \
+       $(top_srcdir)/config/amanda/dirs.m4 \
+       $(top_srcdir)/config/amanda/documentation.m4 \
+       $(top_srcdir)/config/amanda/dumpers.m4 \
+       $(top_srcdir)/config/amanda/flags.m4 \
+       $(top_srcdir)/config/amanda/flock.m4 \
+       $(top_srcdir)/config/amanda/funcs.m4 \
+       $(top_srcdir)/config/amanda/getfsent.m4 \
+       $(top_srcdir)/config/amanda/i18n.m4 \
+       $(top_srcdir)/config/amanda/ipv6.m4 \
+       $(top_srcdir)/config/amanda/krb4-security.m4 \
+       $(top_srcdir)/config/amanda/krb5-security.m4 \
+       $(top_srcdir)/config/amanda/lfs.m4 \
+       $(top_srcdir)/config/amanda/libs.m4 \
+       $(top_srcdir)/config/amanda/net.m4 \
+       $(top_srcdir)/config/amanda/progs.m4 \
+       $(top_srcdir)/config/amanda/readdir.m4 \
+       $(top_srcdir)/config/amanda/readline.m4 \
+       $(top_srcdir)/config/amanda/rsh-security.m4 \
+       $(top_srcdir)/config/amanda/s3-device.m4 \
+       $(top_srcdir)/config/amanda/shmem.m4 \
+       $(top_srcdir)/config/amanda/socklen_t_equiv.m4 \
+       $(top_srcdir)/config/amanda/ssh-security.m4 \
+       $(top_srcdir)/config/amanda/summary.m4 \
+       $(top_srcdir)/config/amanda/swig.m4 \
+       $(top_srcdir)/config/amanda/syshacks.m4 \
+       $(top_srcdir)/config/amanda/tape.m4 \
+       $(top_srcdir)/config/amanda/types.m4 \
+       $(top_srcdir)/config/amanda/userid.m4 \
+       $(top_srcdir)/config/amanda/version.m4 \
+       $(top_srcdir)/config/gnulib/alloca.m4 \
+       $(top_srcdir)/config/gnulib/arpa_inet_h.m4 \
+       $(top_srcdir)/config/gnulib/base64.m4 \
+       $(top_srcdir)/config/gnulib/eoverflow.m4 \
+       $(top_srcdir)/config/gnulib/extensions.m4 \
+       $(top_srcdir)/config/gnulib/float_h.m4 \
+       $(top_srcdir)/config/gnulib/fsusage.m4 \
+       $(top_srcdir)/config/gnulib/getaddrinfo.m4 \
+       $(top_srcdir)/config/gnulib/gettimeofday.m4 \
+       $(top_srcdir)/config/gnulib/gnulib-comp.m4 \
+       $(top_srcdir)/config/gnulib/include_next.m4 \
+       $(top_srcdir)/config/gnulib/inet_ntop.m4 \
+       $(top_srcdir)/config/gnulib/intmax_t.m4 \
+       $(top_srcdir)/config/gnulib/lock.m4 \
+       $(top_srcdir)/config/gnulib/longlong.m4 \
+       $(top_srcdir)/config/gnulib/malloc.m4 \
+       $(top_srcdir)/config/gnulib/mkdtemp.m4 \
+       $(top_srcdir)/config/gnulib/netinet_in_h.m4 \
+       $(top_srcdir)/config/gnulib/onceonly_2_57.m4 \
+       $(top_srcdir)/config/gnulib/physmem.m4 \
+       $(top_srcdir)/config/gnulib/safe-read.m4 \
+       $(top_srcdir)/config/gnulib/safe-write.m4 \
+       $(top_srcdir)/config/gnulib/snprintf.m4 \
+       $(top_srcdir)/config/gnulib/socklen.m4 \
+       $(top_srcdir)/config/gnulib/sockpfaf.m4 \
+       $(top_srcdir)/config/gnulib/ssize_t.m4 \
+       $(top_srcdir)/config/gnulib/stdbool.m4 \
+       $(top_srcdir)/config/gnulib/stdint.m4 \
+       $(top_srcdir)/config/gnulib/stdio_h.m4 \
+       $(top_srcdir)/config/gnulib/stdlib_h.m4 \
+       $(top_srcdir)/config/gnulib/strdup.m4 \
+       $(top_srcdir)/config/gnulib/string_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_socket_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_stat_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_time_h.m4 \
+       $(top_srcdir)/config/gnulib/tempname.m4 \
+       $(top_srcdir)/config/gnulib/ulonglong.m4 \
+       $(top_srcdir)/config/gnulib/unistd_h.m4 \
+       $(top_srcdir)/config/gnulib/vasnprintf.m4 \
+       $(top_srcdir)/config/gnulib/visibility.m4 \
+       $(top_srcdir)/config/gnulib/wchar.m4 \
+       $(top_srcdir)/config/gettext-macros/gettext.m4 \
+       $(top_srcdir)/config/gettext-macros/iconv.m4 \
+       $(top_srcdir)/config/gettext-macros/inttypes_h.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-ld.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-link.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-prefix.m4 \
+       $(top_srcdir)/config/gettext-macros/longlong.m4 \
+       $(top_srcdir)/config/gettext-macros/nls.m4 \
+       $(top_srcdir)/config/gettext-macros/po.m4 \
+       $(top_srcdir)/config/gettext-macros/progtest.m4 \
+       $(top_srcdir)/config/gettext-macros/size_max.m4 \
+       $(top_srcdir)/config/gettext-macros/stdint_h.m4 \
+       $(top_srcdir)/config/gettext-macros/wchar_t.m4 \
+       $(top_srcdir)/config/gettext-macros/wint_t.m4 \
+       $(top_srcdir)/config/gettext-macros/xsize.m4 \
+       $(top_srcdir)/config/libtool.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMANDA_DBGDIR = @AMANDA_DBGDIR@
+AMANDA_DEBUG_DAYS = @AMANDA_DEBUG_DAYS@
+AMANDA_STATIC_LDFLAGS = @AMANDA_STATIC_LDFLAGS@
+AMANDA_TMPDIR = @AMANDA_TMPDIR@
+AMANDA_WARNING_CFLAGS = @AMANDA_WARNING_CFLAGS@
+AMLINT = @AMLINT@
+AMLINTFLAGS = @AMLINTFLAGS@
+AMPLOT_CAT_COMPRESS = @AMPLOT_CAT_COMPRESS@
+AMPLOT_CAT_GZIP = @AMPLOT_CAT_GZIP@
+AMPLOT_CAT_PACK = @AMPLOT_CAT_PACK@
+AMPLOT_COMPRESS = @AMPLOT_COMPRESS@
+AMTAR = @AMTAR@
+AR = @AR@
+ARPA_INET_H = @ARPA_INET_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASH = @BASH@
+BINARY_OWNER = @BINARY_OWNER@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+CAT = @CAT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CHIO = @CHIO@
+CHS = @CHS@
+CLIENT_LOGIN = @CLIENT_LOGIN@
+CLIENT_SCRIPTS_OPT = @CLIENT_SCRIPTS_OPT@
+COMPRESS = @COMPRESS@
+CONFIG_DIR = @CONFIG_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURL_CONFIG = @CURL_CONFIG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DD = @DD@
+DEFAULT_AMANDATES_FILE = @DEFAULT_AMANDATES_FILE@
+DEFAULT_CHANGER_DEVICE = @DEFAULT_CHANGER_DEVICE@
+DEFAULT_CONFIG = @DEFAULT_CONFIG@
+DEFAULT_SERVER = @DEFAULT_SERVER@
+DEFAULT_TAPE_DEVICE = @DEFAULT_TAPE_DEVICE@
+DEFAULT_TAPE_SERVER = @DEFAULT_TAPE_SERVER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOC_BUILD_DATE = @DOC_BUILD_DATE@
+DUMP = @DUMP@
+DUMPER_DIR = @DUMPER_DIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXAMPLE_TAPEDEV = @EXAMPLE_TAPEDEV@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FLOAT_H = @FLOAT_H@
+GETCONF = @GETCONF@
+GETTEXT = @GETTEXT@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@
+GNULIB_CHOWN = @GNULIB_CHOWN@
+GNULIB_DUP2 = @GNULIB_DUP2@
+GNULIB_FCHDIR = @GNULIB_FCHDIR@
+GNULIB_FFLUSH = @GNULIB_FFLUSH@
+GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@
+GNULIB_FSEEK = @GNULIB_FSEEK@
+GNULIB_FSEEKO = @GNULIB_FSEEKO@
+GNULIB_FTELL = @GNULIB_FTELL@
+GNULIB_FTELLO = @GNULIB_FTELLO@
+GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@
+GNULIB_GETCWD = @GNULIB_GETCWD@
+GNULIB_GETDELIM = @GNULIB_GETDELIM@
+GNULIB_GETLINE = @GNULIB_GETLINE@
+GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@
+GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@
+GNULIB_LCHOWN = @GNULIB_LCHOWN@
+GNULIB_LSEEK = @GNULIB_LSEEK@
+GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@
+GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@
+GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@
+GNULIB_MBSCHR = @GNULIB_MBSCHR@
+GNULIB_MBSCSPN = @GNULIB_MBSCSPN@
+GNULIB_MBSLEN = @GNULIB_MBSLEN@
+GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@
+GNULIB_MBSNLEN = @GNULIB_MBSNLEN@
+GNULIB_MBSPBRK = @GNULIB_MBSPBRK@
+GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@
+GNULIB_MBSRCHR = @GNULIB_MBSRCHR@
+GNULIB_MBSSEP = @GNULIB_MBSSEP@
+GNULIB_MBSSPN = @GNULIB_MBSSPN@
+GNULIB_MBSSTR = @GNULIB_MBSSTR@
+GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@
+GNULIB_MEMMEM = @GNULIB_MEMMEM@
+GNULIB_MEMPCPY = @GNULIB_MEMPCPY@
+GNULIB_MEMRCHR = @GNULIB_MEMRCHR@
+GNULIB_MKDTEMP = @GNULIB_MKDTEMP@
+GNULIB_MKSTEMP = @GNULIB_MKSTEMP@
+GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@
+GNULIB_READLINK = @GNULIB_READLINK@
+GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@
+GNULIB_SLEEP = @GNULIB_SLEEP@
+GNULIB_SNPRINTF = @GNULIB_SNPRINTF@
+GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@
+GNULIB_STPCPY = @GNULIB_STPCPY@
+GNULIB_STPNCPY = @GNULIB_STPNCPY@
+GNULIB_STRCASESTR = @GNULIB_STRCASESTR@
+GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@
+GNULIB_STRDUP = @GNULIB_STRDUP@
+GNULIB_STRNDUP = @GNULIB_STRNDUP@
+GNULIB_STRNLEN = @GNULIB_STRNLEN@
+GNULIB_STRPBRK = @GNULIB_STRPBRK@
+GNULIB_STRSEP = @GNULIB_STRSEP@
+GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
+GNULIB_VASPRINTF = @GNULIB_VASPRINTF@
+GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@
+GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@
+GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@
+GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@
+GNULIB_WCWIDTH = @GNULIB_WCWIDTH@
+GNUPLOT = @GNUPLOT@
+GNUTAR = @GNUTAR@
+GNUTAR_LISTED_INCREMENTAL_DIR = @GNUTAR_LISTED_INCREMENTAL_DIR@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GZIP = @GZIP@
+HAVE_CALLOC_POSIX = @HAVE_CALLOC_POSIX@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_MKDIR = @HAVE_DECL_MKDIR@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DUP2 = @HAVE_DUP2@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_IO_H = @HAVE_IO_H@
+HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MALLOC_POSIX = @HAVE_MALLOC_POSIX@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_REALLOC_POSIX = @HAVE_REALLOC_POSIX@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRNDUP = @HAVE_STRNDUP@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE__BOOL = @HAVE__BOOL@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPTH = @LIBPTH@
+LIBS = @LIBS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBPTH = @LTLIBPTH@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAILER = @MAILER@
+MAKEINFO = @MAKEINFO@
+MAXTAPEBLOCKSIZE = @MAXTAPEBLOCKSIZE@
+MCUTIL = @MCUTIL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+MT = @MT@
+MTX = @MTX@
+MT_FILE_FLAG = @MT_FILE_FLAG@
+NETINET_IN_H = @NETINET_IN_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCAT = @PCAT@
+PERL = @PERL@
+PERLEXTLIBS = @PERLEXTLIBS@
+PERL_INC = @PERL_INC@
+PKG_CONFIG = @PKG_CONFIG@
+POSUB = @POSUB@
+PRINT = @PRINT@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_FCHDIR = @REPLACE_FCHDIR@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+RESTORE = @RESTORE@
+SAMBA_CLIENT = @SAMBA_CLIENT@
+SERVICE_SUFFIX = @SERVICE_SUFFIX@
+SETUID_GROUP = @SETUID_GROUP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+SNAPSHOT_STAMP = @SNAPSHOT_STAMP@
+SORT = @SORT@
+SSH = @SSH@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SVN = @SVN@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYS_SOCKET_H = @SYS_SOCKET_H@
+SYS_STAT_H = @SYS_STAT_H@
+SYS_TIME_H = @SYS_TIME_H@
+USE_NLS = @USE_NLS@
+USE_VERSION_SUFFIXES = @USE_VERSION_SUFFIXES@
+VDUMP = @VDUMP@
+VERSION = @VERSION@
+VERSION_COMMENT = @VERSION_COMMENT@
+VERSION_MAJOR = @VERSION_MAJOR@
+VERSION_MINOR = @VERSION_MINOR@
+VERSION_PATCH = @VERSION_PATCH@
+VERSION_SUFFIX = @VERSION_SUFFIX@
+VRESTORE = @VRESTORE@
+VXDUMP = @VXDUMP@
+VXRESTORE = @VXRESTORE@
+WCHAR_H = @WCHAR_H@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+XFSDUMP = @XFSDUMP@
+XFSRESTORE = @XFSRESTORE@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XSLREL = @XSLREL@
+XSLTPROC = @XSLTPROC@
+XSLTPROC_FLAGS = @XSLTPROC_FLAGS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+amincludedir = @amincludedir@
+amlibdir = @amlibdir@
+amlibexecdir = @amlibexecdir@
+amperldir = @amperldir@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+       deb \
+       rpm \
+       Makefile.am \
+       README 
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  packaging/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --gnu  packaging/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+       $(MAKE) $(AM_MAKEFLAGS) \
+         top_distdir="$(top_distdir)" distdir="$(distdir)" \
+         dist-hook
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+       dist-hook distclean distclean-generic distclean-libtool \
+       distdir dvi dvi-am html html-am info info-am install \
+       install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       uninstall uninstall-am
+
+
+dist-hook:
+       rm -rf `find ${distdir} -name .svn`
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/packaging/README b/packaging/README
new file mode 100644 (file)
index 0000000..ea5689b
--- /dev/null
@@ -0,0 +1,25 @@
+This directory contains scripts and data files necessary to build various binary
+(or source) installation packages.  These are the currently functional packages:
+       -Macintosh OS X >=10.4 .pkg files
+       -RPMs for various OSes that use them.  TODO: Wiki page with a full
+        list of RPM using distros and versions the .spec supports.
+       -Solaris .pkg files for 9,10
+Coming soon:
+       -ebuilds for Gentoo
+       -.deb Debian style packages for various OSes that use them.
+       -.msi packages for Windows XP and Server 2003 
+
+The Directory layout is as follows:
+packaging/
+       common/         # Common files which can be shared by all packages such
+                       # License.txt, README, or Copyrights.  So far, empty :-)
+       deb/            # Debian
+       macosx-pkg/     # Macintosh OSX 
+       msi/            # MicroSoft Installer for Windows
+       rpm/            # RPM
+       sun-pkg/        # Solaris .pkg 
+
+Each subdirectory (except common) has a shell script named buildpkg.  This script will 
+actually build the package with Zmanda's defaults for you.
+
+See http://wiki.zmanda.com/index.php/Installation for more information.
diff --git a/packaging/deb/amanda-backup-client.README.Debian b/packaging/deb/amanda-backup-client.README.Debian
new file mode 100644 (file)
index 0000000..5a73992
--- /dev/null
@@ -0,0 +1,2 @@
+Amanda Forums are located at: http://forums.zmanda.com/                                                                                            
+Amanda Documentation is available at: http://wiki.zmanda.com/
diff --git a/packaging/deb/amanda-backup-client.dirs b/packaging/deb/amanda-backup-client.dirs
new file mode 100644 (file)
index 0000000..35eb344
--- /dev/null
@@ -0,0 +1,11 @@
+etc/amanda
+usr/lib/amanda
+usr/libexec/amanda
+usr/share/lintian/overrides
+usr/share/man/man5
+usr/share/man/man8
+var/amanda
+var/lib/amanda
+var/lib/amanda/gnutar-lists
+var/lib/amanda/example
+var/log/amanda
diff --git a/packaging/deb/amanda-backup-client.install b/packaging/deb/amanda-backup-client.install
new file mode 100644 (file)
index 0000000..3e572ef
--- /dev/null
@@ -0,0 +1,19 @@
+usr/lib/amanda/*
+usr/lib/amanda/application/*
+usr/libexec/amanda/*
+usr/libexec/amanda/application/*
+usr/sbin/amaespipe
+usr/sbin/amcryp*
+usr/sbin/amgpgcrypt
+usr/sbin/amoldrecover
+usr/sbin/amrecover
+usr/share/man/man5/amanda.conf.5
+usr/share/man/man5/amanda-client.conf.5
+usr/share/man/man8/amanda.8
+usr/share/man/man8/amcheckdump.8
+usr/share/man/man8/amrecover.8
+var/lib/amanda/*
+var/lib/amanda/gnutar-lists/*
+var/lib/amanda/example/xinetd.amandaclient
+var/lib/amanda/example/amanda-client.conf
+var/log/amanda/*
diff --git a/packaging/deb/amanda-backup-client.lintian b/packaging/deb/amanda-backup-client.lintian
new file mode 100644 (file)
index 0000000..b7069a4
--- /dev/null
@@ -0,0 +1,20 @@
+amanda-backup-client: binary-or-shlib-defines-rpath usr/lib/amanda/*
+amanda-backup-client: binary-or-shlib-defines-rpath usr/libexec/amanda/*
+amanda-backup-client: binary-or-shlib-defines-rpath amoldrecover amrecover
+amanda-backup-client: binary-without-manpage amaespipe
+amanda-backup-client: binary-without-manpage amcryp*
+amanda-backup-client: binary-without-manpage amgpgcrypt
+amanda-backup-client: binary-without-manpage amoldrecover
+amanda-backup-client: file-in-unusual-dir usr/libexec/amanda/*
+amanda-backup-client: manpage-has-bad-whatis-entry
+amanda-backup-client: non-standard-dir-in-usr usr/libexec
+amanda-backup-client: non-standard-dir-in-var var/log/amanda
+amanda-backup-client: non-standard-dir-in-var var/amanda
+amanda-backup-client: non-standard-dir-perm var/lib/amanda/gnutar-lists
+amanda-backup-client: non-standard-dir-perm var/log/amanda 
+amanda-backup-client: package-name-doesnt-match-sonames
+amanda-backup-client: setuid-binary usr/libexec/amanda/calcsize 
+amanda-backup-client: setuid-binary usr/libexec/amanda/killgrp 
+amanda-backup-client: setuid-binary usr/libexec/amanda/planner 
+amanda-backup-client: setuid-binary usr/libexec/amanda/rundump 
+amanda-backup-client: setuid-binary usr/libexec/amanda/runtar
diff --git a/packaging/deb/amanda-backup-client.postinst b/packaging/deb/amanda-backup-client.postinst
new file mode 100755 (executable)
index 0000000..c91894e
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+SYSCONFDIR="/etc"
+LOCALSTATEDIR="/var"
+LOGDIR="${LOCALSTATEDIR}/log/amanda/"
+AMHOMEDIR="${LOCALSTATEDIR}/lib/amanda"
+amanda_user=amandabackup
+amanda_group=disk
+xinetd_reload="restart"
+
+
+# Installing xinetd config and make it active.
+if [ -e /etc/xinetd.d ] && [ -d /etc/xinetd.d ] ; then
+       if [ ! -f /etc/xinetd.d/amandaclient ] ; then
+               cp ${AMHOMEDIR}/example/xinetd.amandaclient /etc/xinetd.d/amandaclient || exit 1
+               echo -n "`date +'%b %e %Y %T'`: Reloading xinetd configuration..." 
+               if [ "${xinetd_reload}" = "reload" ] ; then
+                       /usr/sbin/invoke-rc.d xinetd ${xinetd_reload} # don't exit yet...
+                       if [ $? -ne 0 ] ; then
+                               echo -n "reload failed.  Attempting restart..." 
+                               /usr/sbin/invoke-rc.d xinetd restart || exit 1
+                       fi
+               else
+                       /usr/sbin/invoke-rc.d xinetd ${xinetd_reload} || exit 1
+               fi
+       fi
+fi
+
+echo "`date +'%b %e %Y %T'`: Installing '${LOCALSTATEDIR}/amanda/amandates'." 
+if [ ! -f ${LOCALSTATEDIR}/amanda/amandates ] ; then
+       touch ${LOCALSTATEDIR}/amanda/amandates || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '${LOCALSTATEDIR}/amanda/amandates'." 
+chown ${amanda_user}:${amanda_group} ${LOCALSTATEDIR}/amanda/amandates || exit 1
+chmod 0640 ${LOCALSTATEDIR}/amanda/amandates || exit 1
+if [ -x /sbin/restorecon ] ; then
+      /sbin/restorecon ${LOCALSTATEDIR}/amanda/amandates  || exit 1
+fi
+
+# Install .amandahosts to client
+echo "`date +'%b %e %Y %T'`: Checking '${AMHOMEDIR}/.amandahosts' file." 
+if [ ! -f ${AMHOMEDIR}/.amandahosts ] ; then
+       touch ${AMHOMEDIR}/.amandahosts || exit 1
+fi
+for host in localhost localhost.localdomain ; do
+               if [ -z "`grep \"^${host}[[:blank:]]\+${amanda_user}[[:blank:]]\+amdump\" ${AMHOMEDIR}/.amandahosts`" ] ; then
+                       echo "${host} ${amanda_user} amdump" >> "${AMHOMEDIR}/.amandahosts" || exit 1
+               fi
+done
+chown ${amanda_user}:${amanda_group} ${AMHOMEDIR}/.amandahosts || exit 1
+chmod 0600 ${AMHOMEDIR}/.amandahosts || exit 1
+
+# Install amanda client configuration file
+echo "`date +'%b %e %Y %T'`: Checking '${SYSCONFDIR}/amanda/amanda-client.conf' file." 
+if [ ! -f ${SYSCONFDIR}/amanda/amanda-client.conf ] ; then
+       cp ${AMHOMEDIR}/example/amanda-client.conf ${SYSCONFDIR}/amanda/amanda-client.conf || exit 1
+fi
+chown ${amanda_user}:${amanda_group} ${SYSCONFDIR}/amanda/amanda-client.conf || exit 1
+chmod 0600 ${SYSCONFDIR}/amanda/amanda-client.conf || exit 1
+
+# Install .gnupg directory
+echo "`date +'%b %e %Y %T'`: Installing '${AMHOMEDIR}/.gnupg'." 
+if [ ! -d ${AMHOMEDIR}/.gnupg ] ; then
+       echo "`date +'%b %e %Y %T'`: '${AMHOMEDIR}/.gnupg' will be created." 
+       mkdir ${AMHOMEDIR}/.gnupg || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '${AMHOMEDIR}/.gnupg'." 
+chown ${amanda_user}:${amanda_group} ${AMHOMEDIR}/.gnupg || exit 1
+chmod 700 ${AMHOMEDIR}/.gnupg || exit 1
+
+# SSH RSA key generation on client for amrecover
+KEYDIR="${AMHOMEDIR}/.ssh"
+KEYFILE="id_rsa_amrecover"
+COMMENT="root@client"
+if [ ! -d ${KEYDIR} ] ; then
+       if [ -f ${KEYDIR} ] ; then
+               echo "`date +'%b %e %Y %T'`: Directory '${KEYDIR}' exists as a file.  Renaming to '${KEYDIR}.save'." 
+               mv ${KEYDIR} ${KEYDIR}.save || exit 1
+       fi
+       echo "`date +'%b %e %Y %T'`: Creating directory '${KEYDIR}'." 
+       mkdir ${KEYDIR} || exit 1
+fi
+if [ ! -f ${KEYDIR}/${KEYFILE} ] ; then
+       echo "`date +'%b %e %Y %T'`: Creating ssh RSA key in '${KEYDIR}/${KEYFILE}'" 
+       ssh-keygen -q -C $COMMENT -t rsa -f ${KEYDIR}/${KEYFILE} -N '' || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Setting permissions for '${KEYDIR}' and '${KEYDIR}/${KEYFILE}*'" 
+chown ${amanda_user}:${amanda_group} ${KEYDIR} || exit 1
+chmod 0750 ${KEYDIR} || exit 1
+chmod 0600 ${KEYDIR}/${KEYFILE}* || exit 1
+
+# environment variables (~amandabackup/.profile)
+echo "`date +'%b %e %Y %T'`: Checking for '${AMHOMEDIR}/.profile' and ensuring correct environment." 
+if [ ! -f ${AMHOMEDIR}/.profile ] ; then
+       touch ${AMHOMEDIR}/.profile || exit 1
+fi
+if [ -z "`grep PATH ${AMHOMEDIR}/.profile | grep '/usr/sbin'`" ] ; then
+       echo "export PATH=\"\$PATH:/usr/sbin/\"" >> "${AMHOMEDIR}/.profile" || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Setting ownership and permissions for '${AMHOMEDIR}/.profile'" 
+chown ${amanda_user}:${amanda_group} ${AMHOMEDIR}/.profile || exit 1
+chmod 0640 ${AMHOMEDIR}/.profile || exit 1
+
+echo "`date +'%b %e %Y %T'`: === Amanda backup client installation complete. ===" 
diff --git a/packaging/deb/amanda-backup-client.postrm b/packaging/deb/amanda-backup-client.postrm
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/packaging/deb/amanda-backup-client.substvars b/packaging/deb/amanda-backup-client.substvars
new file mode 100644 (file)
index 0000000..751fe57
--- /dev/null
@@ -0,0 +1 @@
+shlibs:Depends=amanda-backup-server, libc6 (>= 2.3.2.ds1-21), libncurses5 (>= 5.4-1), libreadline5
diff --git a/packaging/deb/amanda-backup-server.README.Debian b/packaging/deb/amanda-backup-server.README.Debian
new file mode 100644 (file)
index 0000000..3149356
--- /dev/null
@@ -0,0 +1,2 @@
+Amanda Forums are located at: http://forums.zmanda.com/                                                                                            
+Amanda Documentation is available at: http://wiki.zmanda.com/  
diff --git a/packaging/deb/amanda-backup-server.dirs b/packaging/deb/amanda-backup-server.dirs
new file mode 100644 (file)
index 0000000..084741f
--- /dev/null
@@ -0,0 +1,9 @@
+etc/amanda
+usr/share/lintian/overrides
+usr/share/man/man5
+usr/share/man/man8
+var/amanda
+var/lib/amanda
+var/lib/amanda/gnutar-lists
+var/lib/amanda/example/label-templates
+var/log/amanda
diff --git a/packaging/deb/amanda-backup-server.install b/packaging/deb/amanda-backup-server.install
new file mode 100644 (file)
index 0000000..42e429d
--- /dev/null
@@ -0,0 +1,12 @@
+usr/lib/amanda/* 
+usr/lib/amanda/application/*
+usr/libexec/amanda/*
+usr/libexec/amanda/application/*
+usr/sbin/*
+usr/share/man/man5/*
+usr/share/man/man8/*
+var/lib/amanda/*
+var/lib/amanda/gnutar-lists/*
+var/lib/amanda/example/*
+var/lib/amanda/example/label-templates/*
+var/log/amanda/*
diff --git a/packaging/deb/amanda-backup-server.lintian b/packaging/deb/amanda-backup-server.lintian
new file mode 100644 (file)
index 0000000..a6d62ac
--- /dev/null
@@ -0,0 +1,16 @@
+amanda-backup-server: binary-or-shlib-defines-rpath usr/lib/amanda/*
+amanda-backup-server: binary-or-shlib-defines-rpath usr/libexec/amanda/*
+amanda-backup-server: binary-or-shlib-defines-rpath usr/sbin/am*
+amanda-backup-server: binary-without-manpage amoldrecover
+amanda-backup-server: manpage-has-bad-whatis-entry
+amanda-backup-server: file-in-unusual-dir usr/libexec/amanda/*
+amanda-backup-server: non-standard-dir-in-usr usr/libexec
+amanda-backup-server: non-standard-dir-perm var/lib/amanda/gnutar-lists
+amanda-backup-server: non-standard-dir-perm var/log/amanda 
+amanda-backup-server: package-name-doesnt-match-sonames
+amanda-backup-server: setuid-binary usr/libexec/amanda/calcsize 
+amanda-backup-server: setuid-binary usr/libexec/amanda/dumper 
+amanda-backup-server: setuid-binary usr/libexec/amanda/killgrp 
+amanda-backup-server: setuid-binary usr/libexec/amanda/planner 
+amanda-backup-server: setuid-binary usr/libexec/amanda/rundump 
+amanda-backup-server: setuid-binary usr/libexec/amanda/runtar
diff --git a/packaging/deb/amanda-backup-server.postinst b/packaging/deb/amanda-backup-server.postinst
new file mode 100755 (executable)
index 0000000..260db60
--- /dev/null
@@ -0,0 +1,132 @@
+#!/bin/sh
+# Debian recommends this.  Script exits on simple command failure.
+# set -e
+LOGDIR="/var/log/amanda/"
+SYSCONFDIR="/etc"
+LOCALSTATEDIR="/var"
+AMHOMEDIR="${LOCALSTATEDIR}/lib/amanda"
+AMTMP="/tmp/amanda"
+amanda_user=amandabackup
+amanda_group=disk
+xinetd_reload="restart"
+
+if [ -d /etc/xinetd.d ] ; then
+       if [ ! -f /etc/xinetd.d/amandaserver ] ; then
+               cp ${AMHOMEDIR}/example/xinetd.amandaserver /etc/xinetd.d/amandaserver || exit 1
+               chmod 0644 /etc/xinetd.d/amandaserver || exit 1
+               if [ -f /etc/xinetd.d/amandaclient ] ; then
+                       rm /etc/xinetd.d/amandaclient || exit 1
+               fi
+               echo -n "`date +'%b %e %Y %T'`: Reloading xinetd configuration..." 
+               if [ "${xinetd_reload}" = "reload" ] ; then
+                       /usr/sbin/invoke-rc.d xinetd ${xinetd_reload} # don't exit yet!
+                       if [ $? -ne 0 ] ; then
+                               echo -n "reload failed.  Attempting restart..." 
+                               /usr/sbin/invoke-rc.d xinetd restart || exit 1
+                       fi
+               else
+                       /usr/sbin/invoke-rc.d xinetd ${xinetd_reload} || exit 1
+               fi
+       fi
+fi
+
+echo "`date +'%b %e %Y %T'`: Installing '${LOCALSTATEDIR}/amanda/amandates'." 
+if [ ! -f ${LOCALSTATEDIR}/amanda/amandates ] ; then
+       touch ${LOCALSTATEDIR}/amanda/amandates || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '${LOCALSTATEDIR}/amanda/amandates'." 
+chown ${amanda_user}:${amanda_group} ${LOCALSTATEDIR}/amanda/amandates || exit 1
+chmod 0640 ${LOCALSTATEDIR}/amanda/amandates || exit 1
+if [ -x /sbin/restorecon ] ; then
+      /sbin/restorecon ${LOCALSTATEDIR}/amanda/amandates  || exit 1
+fi
+
+# Check for existence of and permissions on ${AMTMP}
+if [ ! -d ${AMTMP} ]; then
+       mkdir ${AMTMP} || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '${AMTMP}'." 
+chown ${amanda_user}:${amanda_group} ${AMTMP} || exit 1
+chmod 0640 ${AMTMP} || exit 1
+
+# Install .gnupg directory
+echo "`date +'%b %e %Y %T'`: Installing '${AMHOMEDIR}/.gnupg'." 
+if [ ! -d ${AMHOMEDIR}/.gnupg ] ; then
+       echo "`date +'%b %e %Y %T'`: '${AMHOMEDIR}/.gnupg' will be created." 
+       mkdir ${AMHOMEDIR}/.gnupg || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '${AMHOMEDIR}/.gnupg'." 
+chown ${amanda_user}:${amanda_group} ${AMHOMEDIR}/.gnupg || exit 1
+chmod 700 ${AMHOMEDIR}/.gnupg || exit 1
+
+# Install .amandahosts to server
+echo "`date +'%b %e %Y %T'`: Checking '${AMHOMEDIR}/.amandahosts' file." 
+if [ ! -f ${AMHOMEDIR}/.amandahosts ] ; then
+       touch ${AMHOMEDIR}/.amandahosts || exit 1
+fi
+for host in localhost localhost.localdomain ; do
+       if [ -z "`grep \"^${host}[[:blank:]]\+root[[:blank:]]\+amindexd[[:blank:]]\+amidxtaped\" ${AMHOMEDIR}/.amandahosts`" ] ; then
+               echo "${host}   root amindexd amidxtaped" >>${AMHOMEDIR}/.amandahosts || exit 1
+       fi
+       if [ -z "`grep \"^${host}[[:blank:]]\+${amanda_user}[[:blank:]]\+amdump\" ${AMHOMEDIR}/.amandahosts`" ] ; then
+                echo "${host} ${amanda_user} amdump" >>${AMHOMEDIR}/.amandahosts || exit 1
+       fi
+done
+chown ${amanda_user}:${amanda_group} ${AMHOMEDIR}/.amandahosts || exit 1
+chmod 0600 ${AMHOMEDIR}/.amandahosts || exit 1
+
+# SSH RSA key generation for amdump
+KEYDIR="${AMHOMEDIR}/.ssh"
+KEYFILE="id_rsa_amdump"
+COMMENT="${amanda_user}@server"
+if [ ! -d ${KEYDIR} ] ; then
+       if [ -f ${KEYDIR} ] ; then
+               echo "`date +'%b %e %Y %T'`: Directory '${KEYDIR}' exists as a file.  Renaming to '${KEYDIR}.save'." 
+               mv ${KEYDIR} ${KEYDIR}.save || exit 1
+       fi
+       echo "`date +'%b %e %Y %T'`: Creating directory '${KEYDIR}'." 
+       mkdir ${KEYDIR} || exit 1
+fi
+if [ ! -f ${KEYDIR}/${KEYFILE} ] ; then
+       echo "`date +'%b %e %Y %T'`: Creating ssh RSA key in '${KEYDIR}/${KEYFILE}'" 
+       ssh-keygen -q -C $COMMENT -t rsa -f ${KEYDIR}/${KEYFILE} -N '' || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Setting ownership and permissions for '${KEYDIR}' and '${KEYDIR}/${KEYFILE}*'" 
+chown ${amanda_user}:${amanda_group} ${KEYDIR} ${KEYDIR}/${KEYFILE}* || exit 1
+chmod 0750 ${KEYDIR} || exit 1
+chmod 0600 ${KEYDIR}/${KEYFILE}* || exit 1
+
+# SSH RSA key generation on client for amrecover
+KEYDIR="${AMHOMEDIR}/.ssh"
+KEYFILE="id_rsa_amrecover"
+COMMENT="root@client"
+if [ ! -d ${KEYDIR} ] ; then
+       if [ -f ${KEYDIR} ] ; then
+               echo "`date +'%b %e %Y %T'`: Directory '${KEYDIR}' exists as a file.  Renaming to '${KEYDIR}.save'." 
+               mv ${KEYDIR} ${KEYDIR}.save || exit 1
+       fi
+       echo "`date +'%b %e %Y %T'`: Creating directory '${KEYDIR}'." 
+       mkdir ${KEYDIR} || exit 1
+fi
+if [ ! -f ${KEYDIR}/${KEYFILE} ] ; then
+       echo "`date +'%b %e %Y %T'`: Creating ssh RSA key in '${KEYDIR}/${KEYFILE}'" 
+       ssh-keygen -q -C $COMMENT -t rsa -f ${KEYDIR}/${KEYFILE} -N '' || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Setting permissions for '${KEYDIR}'" 
+chown ${amanda_user}:${amanda_group} ${KEYDIR} || exit 1
+chmod 0750 ${KEYDIR} || exit 1
+chmod 0600 ${KEYDIR}/${KEYFILE}* || exit 1
+
+# environment variables (~amandabackup/.profile)
+echo "`date +'%b %e %Y %T'`: Checking for '${AMHOMEDIR}/.profile' and ensuring correct environment." 
+if [ ! -f ${AMHOMEDIR}/.profile ] ; then
+       touch ${AMHOMEDIR}/.profile || exit 1
+fi
+if [ -z "`grep PATH ${AMHOMEDIR}/.profile | grep '/usr/sbin'`" ] ; then
+       echo "export PATH=\"\$PATH:/usr/sbin/\"" >> "${AMHOMEDIR}/.profile" || exit 1
+fi
+echo "`date +'%b %e %Y %T'`: Setting ownership and permissions for '${AMHOMEDIR}/.profile'" 
+chown ${amanda_user}:${amanda_group} ${AMHOMEDIR}/.profile || exit 1
+chmod 0640 ${AMHOMEDIR}/.profile || exit 1
+
+echo "`date +'%b %e %Y %T'`: === Amanda backup server installation complete. ===" 
diff --git a/packaging/deb/amanda-backup-server.postrm b/packaging/deb/amanda-backup-server.postrm
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/packaging/deb/amanda-backup-server.substvars b/packaging/deb/amanda-backup-server.substvars
new file mode 100644 (file)
index 0000000..c27ee0c
--- /dev/null
@@ -0,0 +1 @@
+shlibs:Depends=libc6 (>= 2.3.2.ds1-21), libncurses5 (>= 5.4-1), libreadline5
diff --git a/packaging/deb/buildpkg b/packaging/deb/buildpkg
new file mode 100755 (executable)
index 0000000..4cee2d6
--- /dev/null
@@ -0,0 +1,128 @@
+#! /bin/bash
+set -x
+#### Configure variables.  Feel free to change these, but be careful!
+SRCDIR=$(pwd)
+# You can pass your own temp directory as an environment variable.
+if [ -z $TMPDIR ]
+then
+    TMPDIR="/tmp/buildpkg.deb"
+fi
+# This prefix is prepended to all directories during "make install" 
+FAKEROOT="${TMPDIR}/froot"
+# Configure and Compilation directory.
+BUILDDIR="${TMPDIR}/build"
+# Config variables to mirror those in RPM .spec file
+amanda_user=amandabackup
+amanda_group=admin
+udpportrange="700,740"
+tcpportrange="11000,11040"
+low_tcpportrange="700,710"
+PREFIX="/usr"
+EPREFIX="${PREFIX}"
+BINDIR="${EPREFIX}/bin"
+SBINDIR="${EPREFIX}/sbin"
+LIBEXECDIR="${EPREFIX}/lib/amanda"
+DATADIR="${PREFIX}/share"
+SYSCONFDIR="/etc"
+LOCALSTATEDIR="/var"
+AMANDAHOMEDIR="${LOCALSTATEDIR}/lib/amanda"
+LIBDIR="${EPREFIX}/lib"
+INCLUDEDIR="${PREFIX}/include"
+INFODIR="${PREFIX}/info"
+MANDIR="${DATADIR}/man"
+LOGDIR="${LOCALSTATEDIR}/log/amanda"                  
+
+#### CHECKS
+
+if [ ! -f common-src/amanda.h ]
+then
+    echo "'buildpkg' must be run from the root of an otherwise unused amanda source directory." >&2
+    exit 1
+fi
+
+if [ ! -f configure ]
+then
+    echo "The source directory has not been autogen'd -- please download a source distribution tarball or run ./autogen."
+    echo "You will need autoconf, automake, and libtool to run autogen (but not to compile from a distribution tarball)."
+    exit 1
+fi
+
+if [ -z $AMVER ]
+then
+    AMVER=amanda-2.6.0p2
+fi
+
+if [ -z $AMTARBALL ]
+then
+    AMTARBALL=$AMVER.tar.gz
+fi
+
+#### Build functions
+
+do_build() {
+
+    echo "Running configure"
+    ./configure --quiet \
+        --prefix=${PREFIX} \
+        --bindir=${BINDIR} \
+        --sbindir=${SBINDIR} \
+        --mandir=${MANDIR} \
+        --libexecdir=${LIBEXECDIR} \
+        --sysconfdir=${SYSCONFDIR} \
+        --localstatedir=${LOCALSTATEDIR} \
+        --with-star=/bin/star \
+        --with-gnutar=/bin/tar \
+        --with-gnutar-listdir=${AMANDAHOMEDIR}/gnutar-lists \
+        --with-index-server=localhost \
+        --with-tape-server=localhost \
+        --with-user=${amanda_user} \
+        --with-group=${amanda_group} \
+        --with-owner=${amanda_user} \
+        --with-fqdn \
+        --with-bsd-security \
+        --with-bsdtcp-security \
+        --with-bsdudp-security \
+        --with-amandahosts \
+        --with-smbclient=/usr/bin/smbclient \
+        --with-ssh-security \
+        --with-udpportrange=${udpportrange} \
+        --with-tcpportrange=${tcpportrange} \
+        --with-low-tcpportrange=${low_tcpportrange} \
+        --with-debugging=${LOGDIR} \
+        --disable-installperms \
+        --enable-s3-device \
+        --with-assertions \
+       || exit 1
+
+}
+
+do_resources() {
+    # Setup directories and files as dpkg-buildpkg expects.
+    if [ -d debian ]; then
+        rm -rf debian
+    fi
+    cp -Rf packaging/deb debian
+    if [ -d $AMVER ]; then
+        rm -rf $AMVER
+    fi
+    mkdir $AMVER
+    cp -Rfp * $AMVER
+}
+
+do_package() {
+
+    echo "Building package"
+    cd $AMVER
+    # Create unsigned packages
+    dpkg-buildpackage -rfakeroot -uc -us
+}
+
+
+do_all() {
+    do_build $1
+    do_resources $1
+    do_package $1
+}
+
+do_resources
+do_package
diff --git a/packaging/deb/changelog b/packaging/deb/changelog
new file mode 100644 (file)
index 0000000..63eabb3
--- /dev/null
@@ -0,0 +1,9 @@
+amanda (2.6.0p1-1) unstable; urgency=low
+
+  * Initial debian release: This package is based on Bdale Garbee's work as
+    the official debian maintainer for amanda.
+  * Found by Daniel_p: Fixed typos in preinst and postrm.  Added permission
+    check for /tmp/amanda.  Fixed rules to append default perl site_lib to
+    .install file so that perl modules are installed.
+
+ -- Zmanda <support@zmanda.com>  Mon, 10 Mar 2008 1:00:09 -0600
diff --git a/packaging/deb/compat b/packaging/deb/compat
new file mode 100644 (file)
index 0000000..b8626c4
--- /dev/null
@@ -0,0 +1 @@
+4
diff --git a/packaging/deb/control b/packaging/deb/control
new file mode 100644 (file)
index 0000000..c74248d
--- /dev/null
@@ -0,0 +1,37 @@
+Source: amanda
+Section: utils
+Priority: optional
+Maintainer: Zmanda Inc <support@zmanda.com>
+Build-Depends: debhelper, dump, fakeroot, flex, gnuplot, libtool, mailx, mtx, perl (>=5.6.0), smbclient,
+       libcurl-dev, libncurses5-dev, libreadline5-dev | libreadline-dev, libssl-dev
+Standards-Version: 3.6.1
+
+Package: amanda-backup-server
+Architecture: any
+Depends: xinetd, perl (>=5.6.0), mailx, gnuplot, tar (>=1.15), libcurl3 (>=7.10.0), libglib2.0-0 (>=2.2.0), libssl | libssl0.9.8
+Suggests: amanda-backup-client (= ${Source-Version})
+Description: Amanda Network Backup and Archiving software
+ .
+ Amanda is the leading Open-Source Backup and Archiving software.
+ .
+ This package contains the Amanda server.  The amanda-backup_server package 
+ should be installed on the Amanda server, i.e. the machine attached to backup 
+ media (such as a tape drive or disk drives) where backups will be written.  The 
+ amanda-backup_server package includes Amanda client.
+ .
+ Amanda Forums are located at: http://forums.zmanda.com/
+ Amanda Documentation is available at: http://wiki.zmanda.com/
+
+Package: amanda-backup-client
+Architecture: any
+Depends: xinetd, perl (>=5.6.0), grep, libcurl3 (>=7.10.0), libglib2.0-0 (>=2.2.0), libssl | libssl0.9.8
+Conflicts: amanda-backup-server (>=${Source-Version})
+Description: Amanda Network Backup and Archiving software
+ .
+ Amanda is the leading Open-Source Backup and Archiving software.
+ .
+ This package contains the Amanda client.  The amanda-backup_client package
+ needs to be installed on every system that is being backed up.
+ .
+ Amanda Forums are located at: http://forums.zmanda.com/
+ Amanda Documentation is available at: http://wiki.zmanda.com/
diff --git a/packaging/deb/copyright b/packaging/deb/copyright
new file mode 100644 (file)
index 0000000..51bf3d5
--- /dev/null
@@ -0,0 +1,26 @@
+
+Builder: Zmanda 
+Amanda copyright: http://wiki.zmanda.com/index.php/Amanda_Copyright
+
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991, 1996 University of Maryland at College Park
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
diff --git a/packaging/deb/debian-binary b/packaging/deb/debian-binary
new file mode 100644 (file)
index 0000000..6ec12fe
--- /dev/null
@@ -0,0 +1 @@
+version: 2.0
diff --git a/packaging/deb/docs b/packaging/deb/docs
new file mode 100644 (file)
index 0000000..6f83607
--- /dev/null
@@ -0,0 +1,3 @@
+AUTHORS
+NEWS
+README
diff --git a/packaging/deb/postrm b/packaging/deb/postrm
new file mode 100755 (executable)
index 0000000..e972af6
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh -e
+case "$1" in
+  purge)
+       if [ -d /etc/amanda ]; then
+               # remove /etc amanda if there are no files left
+               rmdir /etc/amanda 2> /dev/null || true
+       fi
+       if [ -d /var/log/amanda ]; then
+               rm -rf /var/log/amanda
+       fi
+       if [ -d /var/lib/amanda/gnutar-lists ]; then
+               rm -rf /var/lib/amanda/gnutar-lists
+       fi
+       if [ -d /var/lib/amanda ]; then
+               rm -rf /var/lib/amanda
+       fi
+       if which deluser >/dev/null 2>&1 ; then
+               for group in disk; do
+                       # only call deluser when amandabackup is in $group
+                       if getent group "$group" |
+                          awk -F: '{ print $4 }' |
+                          awk -F, '{ for (i=1; i <= NF; i++ ) print $i }' |
+                          grep '^amandabackup$' > /dev/null; then
+                               deluser "amandabackup $group" || true
+                       fi
+               done
+       fi
+  ;;
+  remove|upgrade|deconfigure)
+  ;;
+
+  failed-upgrade)
+  ;;
+
+  *)
+        echo "unknown argument --> $1" >&2
+        exit 0
+  ;;
+esac
diff --git a/packaging/deb/preinst b/packaging/deb/preinst
new file mode 100755 (executable)
index 0000000..645a662
--- /dev/null
@@ -0,0 +1,127 @@
+#!/bin/sh 
+
+amanda_user=amandabackup
+amanda_group=disk
+
+TMPFILE=`mktemp /tmp/deb-amanda.XXXXXXXXXXX`
+if [ $? -ne 0 ]; then
+       echo "Unable to mktemp!" 1>&2
+       exit 1
+fi
+LOGDIR="/var/log/amanda"
+INSTALL_LOG="${LOGDIR}/install.log"
+INSTALL_ERR="${LOGDIR}/install.err"
+
+echo "`date +'%b %e %Y %T'`: Preparing to install Amanda" >${TMPFILE}
+
+# Check for the '${amanda_user}' user
+echo "`date +'%b %e %Y %T'`: Checking for ${amanda_user} user..." >>${TMPFILE}
+if [ "`id -u ${amanda_user} >/dev/null 2>&1 && echo 0 || echo 1`" != "0" ] ; then
+       useradd -c "Amanda" -g ${amanda_group} -d /var/lib/amanda -s /bin/sh ${amanda_user}
+       # Lock the ${amanda_user} account until admin sets password
+       passwd -l ${amanda_user} >>/dev/null
+       PASSWD_EXIT=$?
+       if [ ${PASSWD_EXIT} -eq 0 ] ; then
+               echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  The ${amanda_user} user account has been successfully created." >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  Furthermore, the account has been automatically locked for you" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  for security purposes.  Once a password for the  '${amanda_user}'" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  account has been set, the user can be unlocked by issuing" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  the following command as root.:" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  # passwd -u ${amanda_user}" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  If this is not a new installation of Amanda and you have" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  pre-existing Amanda configurations in /etc/amanda" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  you should ensure that 'dumpuser' is set to '${amanda_user}'" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  in those configurations.  Additionally, you should ensure" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  that /var/lib/amanda/.amandahosts on your client systems" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  is properly configured to allow connections for the user" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  '${amanda_user}'." >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+               PASSWD_OK=0
+       else
+               echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!  The '${amanda_user}' user account for this system has been   !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!  created, however the user has no password set. For   !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!  security purposes this account  is normally locked   !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!  after creation.  Unfortunately,  when locking this   !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!  account an error occurred.  To ensure the security   !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!  of your system  you should set a password  for the   !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!  user account '${amanda_user}' immediately!  To set  such a   !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!  password, please issue the following command.:       !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!   # passwd ${amanda_user}" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+               PASSWD_OK=1
+       fi
+else
+       # log information about '${amanda_user}' user parameters
+       echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:  The Amanda backup software is configured to operate as the" >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:  user '${amanda_user}'.  This user exists on your system and has not" >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:  been modified.  To ensure that Amanda functions properly," >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:  please see that the following parameters are set for that" >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:  user.:" >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:  SHELL:          /bin/sh" >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:  HOME:           /var/lib/amanda" >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:  Default group:  ${amanda_group}" >>${TMPFILE}
+       echo "`date +'%b %e %Y %T'`:  Verifying ${amanda_user} user parameters :" >>${TMPFILE}
+       
+
+        if [ "`id -gn ${amanda_user}`" != "${amanda_group}" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! user '${amanda_user}' is not part of the ${amanda_group} group, !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! please make sure it is corrected before start using amanda  !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified group name of user '${amanda_user}'" >>${TMPFILE}
+        fi
+
+       echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+       PASSWD_OK=0
+fi
+if [ -d /var/lib/amanda ] ; then
+       echo -n "`date +'%b %e %Y %T'`:  Checking ownership of '/var/lib/amanda'... " >>${TMPFILE}
+       if [ "`ls -dl /var/lib/amanda | awk '//{split($_,x); print x[3]}'`" = "${amanda_user}" ] && \
+          [ "`ls -dl /var/lib/amanda | awk '//{split($_,x); print x[4]}'`" = "${amanda_group}" ] ; then
+               echo "correct." >>${TMPFILE}
+               VARLIB_OK=0
+       else
+               echo "incorrect!" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  Please ensure that the directory '/var/lib/amanda' is owned by" >>${TMPFILE}
+               echo "`date +'%b %e %Y %T'`:  the user '${amanda_user}' and group '${amanda_group}'." >>${TMPFILE}
+               VARLIB_OK=1
+       fi
+else
+       VARLIB_OK=0
+fi
+echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+if [ ! -e ${LOGDIR} ] ; then
+       # create log directory
+       mkdir -m 0750 ${LOGDIR} >>${TMPFILE} 2>&1
+       chown ${amanda_user}:${amanda_group} ${LOGDIR} >>${TMPFILE} 2>&1
+fi
+
+if [ ${PASSWD_OK} -eq 1 ] || [ ${VARLIB_OK} -eq 1 ] ; then
+       cat ${TMPFILE}
+       cat ${TMPFILE} >>${INSTALL_ERR}
+       echo "Please review '${INSTALL_ERR}' to correct errors which have prevented the Amanda installation." >&2
+       echo "Amanda installation log can be found in '${INSTALL_LOG}' and errors (if any) in '${INSTALL_ERR}'."
+       exit 1
+else
+       cat ${TMPFILE}
+       cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+
+echo "`date +'%b %e %Y %T'`: === Amanda installation started. ===" >${TMPFILE}
+
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+if [ -f "${TMPFILE}" ]; then
+       rm -f "${TMPFILE}"
+fi
+
diff --git a/packaging/deb/rules b/packaging/deb/rules
new file mode 100755 (executable)
index 0000000..bae37a0
--- /dev/null
@@ -0,0 +1,201 @@
+#!/usr/bin/make -f
+# debian/rules for amanda using debhelper. GNU copyright 2008 by Dan Locks, 
+# based on work by Bdale Garbee.
+# requires automake 1.2d (from experimental tree)
+
+#      Warning - do *not* use -j on an SMP machine, or the build gets
+#              confused... some sort of race condition in the makefiles?
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+AMVER=2.6.0p2
+
+# These are variables that the user can override.  They get used in various
+# places during configure, build, and install.
+PREFIX=/usr
+BINDIR=$(PREFIX)/bin
+LIBDIR=$(PREFIX)/lib
+AMLIBDIR=$(LIBDIR)/amanda
+LIBEXECDIR=$(PREFIX)/libexec
+AMLIBEXECDIR=$(LIBEXECDIR)/amanda
+MANDIR=$(PREFIX)/share/man
+DOCDIR=$(PREFIX)/share/doc
+SYSCONFDIR=/etc
+LOCALSTATEDIR=/var
+AMHOMEDIR=$(LOCALSTATEDIR)/lib/amanda
+LOGDIR=$(LOCALSTATEDIR)/log/amanda
+# Extract the perl site_lib directory.  This is used to install amanda's perl 
+# libs. If configure finds a different install or you specify a different path using
+# --with-amperldir= make sure you change this variable as well.
+PERLSITELIB=$(shell perl -V:installsitelib|sed -e"s:installsitelib='/::;s:'\;::")
+AMANDAUSER=amandabackup
+AMANDAGROUP=disk
+WITHOUT_SERVER="False"
+WITHOUT_CLIENT="False"
+
+r=$(shell pwd)/debian/amanda-common
+server=$(shell pwd)/debian/amanda-backup-server
+client=$(shell pwd)/debian/amanda-backup-client
+
+log=$(shell pwd)/debian/dpkg.log
+
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+build: build-stamp 
+build-stamp: /sbin/dump /usr/bin/smbclient 
+       dh_testdir
+       ./configure \
+               MAKEFLAGS="-j1 " \
+               CFLAGS="-DIGNORE_TAR_ERRORS " \
+               MAILER=/usr/bin/mail \
+               --quiet \
+               --host=$(DEB_HOST_GNU_TYPE) \
+               --build=$(DEB_BUILD_GNU_TYPE) \
+               --prefix=$(PREFIX) \
+               --bindir=$(BINDIR) \
+               --mandir=$(MANDIR) \
+               --libexecdir=$(LIBEXECDIR) \
+               --enable-shared \
+               --sysconfdir=$(SYSCONFDIR) \
+               --localstatedir=$(LOCALSTATEDIR)\
+               --with-gnutar-listdir=$(AMHOMEDIR)/gnutar-lists \
+               --with-index-server=localhost \
+               --with-tape-server=localhost \
+               --with-user=$(AMANDAUSER) \
+               --with-group=$(AMANDAGROUP) \
+                --with-fqdn \
+               --with-bsd-security \
+                --with-bsdtcp-security \
+                --with-bsdudp-security \
+               --with-amandahosts \
+               --with-smbclient=$(BINDIR)/smbclient \
+               --with-debugging=$(LOGDIR) \
+               --with-tcpportrange=11000,11040 \
+               --with-udpportrange=700,740 \
+                --with-low-udpportrange=700,710 \
+               --with-ssh-security \
+               --with-assertions \
+               --enable-s3-device \
+               --disable-installperms
+       touch missing
+       # There's probably a better way to do this.  Preinst and postrm are the
+       # same for client and server, but we leave room for differences by just
+       # appending here.
+       cat $(shell pwd)/debian/preinst >> $(shell pwd)/debian/amanda-backup-client.preinst
+       cat $(shell pwd)/debian/preinst >> $(shell pwd)/debian/amanda-backup-server.preinst
+       cat $(shell pwd)/debian/postrm >> $(shell pwd)/debian/amanda-backup-client.postrm
+       cat $(shell pwd)/debian/postrm >> $(shell pwd)/debian/amanda-backup-server.postrm
+       make 
+       touch build-stamp
+
+clean:
+       dh_testdir >> $(log) 2>&1
+       dh_testroot >> $(log) 2>&1
+       -make clean
+       -make distclean
+       -rm -f build-stamp missing config/config.h common-src/genversion
+       -find . -type d -name .deps -exec rm -rf {} \;
+       -test -r /usr/share/misc/config.sub && \
+               cp -f /usr/share/misc/config.sub config/config.sub
+       -test -r /usr/share/misc/config.guess && \
+               cp -f /usr/share/misc/config.guess config/config.guess
+       dh_clean >> $(log) 2>&1
+
+# Build architecture-dependent files here.
+binary-arch: build
+       echo "---->dh_testdir: " >> $(log)
+       dh_testdir >> $(log) 2>&1
+       echo "---->dh_testroot: " >> $(log)
+       dh_testroot >> $(log) 2>&1
+       echo "---->dh_clean: " >> $(log)
+       dh_clean -k >> $(log) 2>&1
+       echo "---->dh_installdirs: " >> $(log)
+       dh_installdirs -v >> $(log) 2>&1
+       make install DESTDIR=$(r)
+       echo "---->dh_installdocs: " >> $(log)
+       dh_installdocs -v >> $(log) 2>&1
+       install -d $(r)/$(DOCDIR)/amanda-common/examples
+       cp -a example/* $(r)/$(DOCDIR)/amanda-common/examples
+       cp ChangeLog $(r)/$(DOCDIR)/amanda-common/changelog
+       echo "---->dh_installmenu: " >> $(log)
+       dh_installmenu -v >> $(log) 2>&1
+       echo "---->dh_installcron: " >> $(log)
+       dh_installcron >> $(log) 2>&1
+       echo "---->dh_installchangelogs: " >> $(log)
+       dh_installchangelogs -v >> $(log) 2>&1
+       echo "---->dh_installdebconf: " >> $(log)
+       dh_installdebconf -v >> $(log) 2>&1
+       # Here's how we get the perl modules installed into sitelib
+       echo $(PERLSITELIB)/* >> debian/amanda-backup-server.install
+       echo "---->dh_install -v --fail-missing: " >> $(log)
+       dh_install -v --sourcedir=debian/amanda-common >> $(log) 2>&1
+       echo "---->dh_strip: " >> $(log)
+       dh_strip >> $(log) 2>&1
+       echo "---->dh_compress: " >> $(log)
+       dh_compress >> $(log) 2>&1
+       echo "---->dh_fixperms: " >> $(log)
+       dh_fixperms -v >> $(log) 2>&1
+       # fix perms manually
+       chown -R $(AMANDAUSER):$(AMANDAGROUP) debian/*/var/lib/*
+       #chmod -R u=rwX,g=rwX,o-rwx debian/*/var/lib/*
+       chown -R $(AMANDAUSER):$(AMANDAGROUP) $(client)/$(LOGDIR) $(server)/$(LOGDIR)
+       #chmod -R u=rwX,g=rwX,o-rwx $(server)/$(LOGDIR)
+       chown -R $(AMANDAUSER):$(AMANDAGROUP)  $(client)/$(SYSCONFDIR)/amanda $(server)/$(SYSCONFDIR)/amanda
+       #chmod -R u=rwX,g=rwX,o-rwx $(server)/$(SYSCONFDIR)/amanda
+       chown -R $(AMANDAUSER):$(AMANDAGROUP) $(client)/$(AMHOMEDIR)/gnutar-lists $(server)/$(AMHOMEDIR)/gnutar-lists
+       chmod -R u=rwX,g=rwX,o-rwx  $(client)/$(AMHOMEDIR)/gnutar-lists $(server)/$(AMHOMEDIR)/gnutar-lists
+       # .. setuid
+       chown root:disk \
+               $(client)/$(AMLIBEXECDIR)/killpgrp \
+               $(client)/$(AMLIBEXECDIR)/rundump \
+               $(client)/$(AMLIBEXECDIR)/runtar \
+               $(client)/$(AMLIBEXECDIR)/calcsize \
+               $(server)/$(AMLIBEXECDIR)/killpgrp \
+               $(server)/$(AMLIBEXECDIR)/rundump \
+               $(server)/$(AMLIBEXECDIR)/runtar \
+               $(server)/$(AMLIBEXECDIR)/calcsize \
+               $(server)/$(AMLIBEXECDIR)/dumper \
+               $(server)/$(AMLIBEXECDIR)/planner \
+               $(server)/usr/sbin/amcheck
+       chmod u=srwx,g=rx,o=r \
+               $(client)$(AMLIBEXECDIR)/killpgrp \
+               $(client)$(AMLIBEXECDIR)/rundump \
+               $(client)$(AMLIBEXECDIR)/runtar \
+               $(client)$(AMLIBEXECDIR)/calcsize \
+               $(server)$(AMLIBEXECDIR)/killpgrp \
+               $(server)$(AMLIBEXECDIR)/rundump \
+               $(server)$(AMLIBEXECDIR)/runtar \
+               $(server)$(AMLIBEXECDIR)/calcsize \
+               $(server)$(AMLIBEXECDIR)/dumper \
+               $(server)$(AMLIBEXECDIR)/planner \
+               $(server)/usr/sbin/amcheck
+       echo "Amanda version $(AMVER)" >  $(server)/$(AMHOMEDIR)/amanda-release 
+       echo "Amanda version $(AMVER)" >  $(client)/$(AMHOMEDIR)/amanda-release 
+       install -o root -g root -m 0644 debian/amanda-backup-client.lintian \
+               $(client)/usr/share/lintian/overrides/amanda-backup-client
+       #install -o root -g root -m 0644 debian/amanda-common.lintian \
+       #       $(r)/usr/share/lintian/overrides/amanda-common
+       install -o root -g root -m 0644 debian/amanda-backup-server.lintian \
+               $(server)/usr/share/lintian/overrides/amanda-backup-server
+       dh_makeshlibs  >> $(log) 2>&1
+       dh_installdeb >> $(log) 2>&1
+       dh_perl >> $(log) 2>&1
+       dh_shlibdeps -l"debian/$(r)/usr/lib:debian/$(client)/usr/lib:debian/$(server)/usr/lib" >> $(log) 2>&1
+       # strip out the non-versioned amanda-common references, we need
+       # the versioned ones in the control file and dupes are ugly...
+       sed -e 's/amanda-common, //' < debian/amanda-backup-server.substvars > debian/blah
+       mv debian/blah debian/amanda-backup-server.substvars
+       sed -e 's/amanda-common, //' < debian/amanda-backup-client.substvars > debian/blah
+       mv debian/blah debian/amanda-backup-client.substvars
+       dh_gencontrol >> $(log) 2>&1
+       dh_md5sums  >> $(log) 2>&1
+       dh_builddeb  >> $(log) 2>&1
+
+source diff:                                                                  
+       @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
+
+binary: binary-arch
+.PHONY: build clean binary-arch binary
diff --git a/packaging/deb/watch b/packaging/deb/watch
new file mode 100644 (file)
index 0000000..d1101ce
--- /dev/null
@@ -0,0 +1,2 @@
+# Compulsory line, this is a version 2 file
+version=2
diff --git a/packaging/rpm/amanda.spec b/packaging/rpm/amanda.spec
new file mode 100644 (file)
index 0000000..64deb84
--- /dev/null
@@ -0,0 +1,1794 @@
+#
+#                  Copyright (C) 2005 Zmanda Incorporated.
+#                            All Rights Reserved.
+#
+#  This program is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License version 2 as published
+#  by the Free Software Foundation.
+# 
+#  This program is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+# 
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+# 
+#  Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+#  Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+#
+
+
+%define build_srpm 0
+%{?srpm_only: %define build_srpm 1}
+
+# Pkg-config sometimes needs its own path set, and we need to allow users to
+# override our guess during detection.  This macro takes care of that.
+# If no --define PKG_CONFIG_PATH was passed and env var $PKG_CONFIG_PATH is 
+# set then use the env var.
+%{!?PKG_CONFIG_PATH: %{expand:%(echo ${PKG_CONFIG_PATH:+"%%define PKG_CONFIG_PATH $PKG_CONFIG_PATH"})}}
+
+%{?PKG_CONFIG_PATH:%{echo:PKG_CONFIG_PATH = %{PKG_CONFIG_PATH}}}
+
+# Define which Distribution we are building:
+# Try to detect the distribution we are building:
+%if %{_vendor} == redhat 
+    # Fedora symlinks /etc/fedora-release to /etc/redhat-release for at least
+    # fc3-8.  So RHEL and Fedora look at the same file.  Different versions have
+    # different numbers of spaces; hence the use if $3 vs. $4..
+    %if %(awk '$1 == "Fedora" && $4 ~ /3.*/ { exit 1; }' /etc/redhat-release; echo $?)
+        %define dist fedora
+        %define disttag fc
+        %define distver 3
+    %endif
+    %if %(awk '$1 == "Fedora" && $4 ~ /4.*/ { exit 1; }' /etc/redhat-release; echo $?)
+        %define dist fedora
+        %define disttag fc
+        %define distver 4
+    %endif
+    %if %(awk '$1 == "Fedora" && $4 ~ /5.*/ { exit 1; }' /etc/redhat-release; echo $?)
+        %define dist fedora
+        %define disttag fc
+        %define distver 5
+    %endif
+    %if %(awk '$1 == "Fedora" && $4 ~ /6.*/ { exit 1; }' /etc/redhat-release; echo $?)
+        %define dist fedora
+        %define disttag fc
+        %define distver 6
+    %endif
+    %if %(awk '$1 == "Fedora" && $3 ~ /7.*/ { exit 1; }' /etc/redhat-release; echo $?)
+        %define dist fedora
+        %define disttag fc
+        %define distver 7
+    %endif
+    %if %(awk '$1 == "Fedora" && $3 ~ /8.*/ { exit 1; }' /etc/redhat-release; echo $?)
+        %define dist fedora
+        %define disttag fc
+        %define distver 8
+        # TODO: generalize this so that any platform can cross compile
+        %if %{_host_cpu} == x86_64 && %{_target_cpu} == i686
+                # Do nothing if PKG_CONFIG_PATH was set by the user above.
+                %{!?PKG_CONFIG_PATH: %define PKG_CONFIG_PATH /usr/lib/pkgconfig}
+        %endif
+    %endif
+    %if %(awk '$1 == "Red" && $7 ~ /3.*/ { exit 1; }' /etc/redhat-release; echo $?)
+        %define dist redhat
+        %define disttag rhel
+        %define distver 3
+        %define tarver 1.14
+    %endif
+    %if %(awk '$1 == "Red" && $7 ~ /4.*/ { exit 1; }' /etc/redhat-release; echo $?)
+        %define dist redhat
+        %define disttag rhel
+        %define distver 4
+        %define tarver 1.14
+    %endif
+    %if %(awk '$1 == "Red" && $7 ~ /5.*/ { exit 1; }' /etc/redhat-release; echo $?)
+        %define dist redhat
+        %define disttag rhel
+        %define distver 5
+    %endif
+%endif
+# Detect Suse variants.  Suse gives us some nice macros in their rpms
+%if %{_vendor} == "suse"
+    %if %{suse_version} == 910
+        %define dist SuSE
+        %define disttag sles
+        %define distver 9
+    %endif
+    %if %{suse_version} == 1010
+        %define dist SuSE
+        %define disttag sles
+        %define distver 10
+    %endif
+    %if %{suse_version} == 1000
+        %define dist SuSE
+        %define disttag suse
+        %define distver 10
+    %endif
+%endif
+
+# Set options per distribution
+%if %{dist} == redhat || %{dist} == fedora
+    %define rpm_group Applications/Archiving
+    %define xinetd_reload restart
+%endif
+%if %{dist} == SuSE
+    %define rpm_group Productivity/Archiving/Backup
+    %define xinetd_reload restart
+%endif
+
+# Set minimum tar version if it wasn't set in the per-distro section
+%{!?tarver: %define tarver 1.15}
+
+%define packer %(%{__id_u} -n)
+
+# --- Definitions ---
+
+# Define amanda_version if it is not already defined.
+%{!?amanda_version: %define amanda_version 2.6.0p2}
+%{!?amanda_release: %define amanda_release 1}
+%define amanda_version_info "Amanda Community Edition - version %{amanda_version}"
+%define amanda_user amandabackup
+%define amanda_group disk
+%define udpportrange "700,740"
+%define tcpportrange "11000,11040"
+%define low_tcpportrange "700,710"
+
+Summary: The Amanda Backup and Archiving System
+Name: amanda
+Version: %{amanda_version}
+%define rpm_release %{amanda_release}.%{disttag}%{distver}
+%if %{build_srpm}
+%define rpm_release %{amanda_release}
+%endif
+Release: %{rpm_release}
+Source: %{name}-%{version}.tar.gz
+License: http://wiki.zmanda.com/index.php/Amanda_Copyright
+Vendor: Zmanda, Inc.
+Packager: www.zmanda.com
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%{packer}-buildroot
+Group: %{rpm_group}
+# TODO - Need required versions for these:
+BuildRequires: autoconf
+BuildRequires: automake
+BuildRequires: binutils
+BuildRequires: bison
+BuildRequires: flex
+BuildRequires: gcc
+BuildRequires: glibc >= 2.2.0
+BuildRequires: readline
+BuildRequires: curl >= 7.10.0
+Requires: /bin/awk
+Requires: /bin/date
+Requires: /usr/bin/id
+Requires: /sbin/ldconfig
+Requires: /bin/sh
+Requires: /usr/sbin/useradd
+Requires: /usr/sbin/usermod
+Requires: fileutils
+Requires: grep
+Requires: gnuplot
+Requires: libc.so.6
+Requires: libm.so.6
+Requires: libnsl.so.1
+Requires: curl >= 7.10.0
+Requires: xinetd
+Requires: perl >= 5.6.0
+Requires: tar >= %{tarver}
+%if  %{dist} == redhat || %{dist}== fedora
+Requires: libtermcap.so.2
+Requires: initscripts
+%endif
+Provides: amanda-backup_client = %{amanda_version}, amanda-backup_server = %{amanda_version}
+
+%package backup_client
+Summary: The Amanda Backup and Archiving Client
+Group: %{rpm_group}
+Requires: /bin/awk
+Requires: fileutils
+Requires: grep
+%if  %{dist} == redhat || %{dist}== fedora
+Requires: libtermcap.so.2
+Requires: initscripts
+%endif
+Requires: xinetd
+Requires: libc.so.6
+Requires: libm.so.6
+Requires: libnsl.so.1
+Requires: perl >= 5.6.0
+Requires: tar >= 1.15
+Provides: amanda-backup_client = %{amanda_version}
+Provides: libamclient-%{version}.so = %{amanda_version}
+Provides: libamanda-%{version}.so = %{amanda_version}
+Conflicts: amanda-backup_server 
+
+%package backup_server
+Summary: The Amanda Backup and Archiving Server
+Group: %{rpm_group}
+Requires: /bin/awk
+Requires: fileutils
+Requires: grep
+Requires: libc.so.6
+Requires: libm.so.6
+Requires: libnsl.so.1
+%if  %{dist} == redhat || %{dist}== fedora
+Requires: libtermcap.so.2
+Requires: initscripts
+%endif
+Requires: xinetd
+Requires: perl >= 5.6.0
+Requires: tar >= 1.15
+Provides: amanda-backup_server = %{amanda_version}
+Provides: libamclient-%{version}.so = %{amanda_version}
+Provides: libamanda-%{version}.so = %{amanda_version}
+Provides: libamserver-%{version}.so = %{amanda_version}
+Provides: librestore-%{version}.so = %{amanda_version}
+Provides: libamtape-%{version}.so = %{amanda_version}
+Provides: libamdevice-%{version}.so = %{amanda_version}
+
+# --- Package descriptions ---
+
+%description
+Amanda is the leading Open-Source Backup and Archiving software.
+
+The amanda-backup_server package should be installed on the Amanda server, i.e. 
+the machine attached to backup media (such as a tape drive or disk 
+drives) where backups will be written. The amanda-backup_server package
+includes Amanda client.  The amanda-backup_client package needs 
+to be installed on every system that is being backed up.
+
+Amanda Forums is located at: http://forums.zmanda.com/
+Amanda Documentation is available at: http://wiki.zmanda.com/
+
+
+
+%description backup_server
+Amanda is the leading Open-Source Backup and Archiving software.
+
+This package contains the Amanda server.  The amanda-backup_server package 
+should be installed on the Amanda server, i.e. the machine attached 
+to backup media (such as a tape drive or disk drives) where backups 
+will be written.  The amanda-backup_server package includes Amanda client.
+
+Amanda Forums is located at: http://forums.zmanda.com/
+Amanda Documentation is available at: http://wiki.zmanda.com/
+
+
+
+%description backup_client
+Amanda is the leading Open-Source Backup and Archiving software.
+
+This package contains the Amanda client.  The amanda-backup_client package  
+needs to be installed on every system that is being backed up.
+
+Amanda Forums is located at: http://forums.zmanda.com/
+Amanda Documentation is available at: http://wiki.zmanda.com/
+
+# --- Directory setup ---
+
+# Configure directories:
+%define PREFIX          /usr
+%define EPREFIX         %{PREFIX}
+%define BINDIR          %{EPREFIX}/bin
+%define SBINDIR         %{EPREFIX}/sbin
+%define LIBEXECDIR      %{EPREFIX}/libexec
+%define AMLIBEXECDIR    %{LIBEXECDIR}/amanda
+%define DATADIR         %{PREFIX}/share
+%define SYSCONFDIR      /etc
+%define LOCALSTATEDIR   /var
+%define AMANDAHOMEDIR   %{LOCALSTATEDIR}/lib/amanda
+%ifarch x86_64
+%define LIBDIR          %{EPREFIX}/lib64
+%else
+%define LIBDIR          %{EPREFIX}/lib
+%endif
+%define AMLIBDIR        %{LIBDIR}/amanda
+%define INCLUDEDIR      %{PREFIX}/include
+%define MANDIR          %{DATADIR}/man
+%define LOGDIR          /var/log/amanda
+%define PERLSITELIB     %(eval "`perl -V:installsitelib`"; echo $installsitelib)
+
+# Installation directories:
+%define ROOT_SBINDIR            %{buildroot}/%{SBINDIR}
+%define ROOT_LIBEXECDIR         %{buildroot}/%{LIBEXECDIR}
+%define ROOT_DATADIR            %{buildroot}/%{DATADIR}
+%define ROOT_LOCALSTATEDIR      %{buildroot}/%{LOCALSTATEDIR}
+%define ROOT_SYSCONFDIR         %{buildroot}/%{SYSCONFDIR}
+%define ROOT_AMANDAHOMEDIR      %{buildroot}/%{AMANDAHOMEDIR}
+%define ROOT_LIBDIR             %{buildroot}/%{LIBDIR}
+%define ROOT_MANDIR             %{buildroot}/%{MANDIR}
+%define ROOT_LOGDIR             %{buildroot}/%{LOGDIR}
+
+# --- Unpack ---
+
+%prep
+%setup -q
+# --- Configure and compile ---
+
+%build
+%define config_user %{amanda_user}
+%define config_group %{amanda_group}
+
+%if  %{disttag} == rhel && %{distver} == 3
+./configure \
+        CFLAGS="%{optflags} -g" CXXFLAGS="%{optflags}" \
+        --quiet \
+        --prefix=%{PREFIX} \
+        --sysconfdir=%{SYSCONFDIR} \
+        --sharedstatedir=%{LOCALSTATEDIR} \
+        --localstatedir=%{LOCALSTATEDIR} \
+        --libdir=%{LIBDIR} \
+        --includedir=%{INCLUDEDIR} \
+        --with-gnuplot=/usr/bin/gnuplot \
+        --with-gnutar=/bin/tar \
+        --with-gnutar-listdir=%{AMANDAHOMEDIR}/gnutar-lists \
+        --with-index-server=localhost \
+        --with-tape-server=localhost \
+        --with-user=%{config_user} \
+        --with-group=%{config_group} \
+        --with-owner=%{packer} \
+        --with-fqdn \
+        --with-bsd-security \
+        --with-bsdtcp-security \
+        --with-bsdudp-security \
+        --with-ssh-security \
+        --with-udpportrange=%{udpportrange} \
+        --with-tcpportrange=%{tcpportrange} \
+        --with-low-tcpportrange=%{low_tcpportrange} \
+        --with-debugging=%{LOGDIR} \
+        --with-assertions \
+        --disable-installperms \
+        --without-ipv6 
+%else
+# This confusing macro results in PKG_CONFIG_PATH=some/path if some/path
+# was set on the command line, or by the platform detection bits.
+./configure \
+        %{?PKG_CONFIG_PATH: PKG_CONFIG_PATH=%PKG_CONFIG_PATH} \
+        CFLAGS="%{optflags} -g" CXXFLAGS="%{optflags}" \
+        --quiet \
+        --prefix=%{PREFIX} \
+        --sysconfdir=%{SYSCONFDIR} \
+        --sharedstatedir=%{LOCALSTATEDIR} \
+        --localstatedir=%{LOCALSTATEDIR} \
+        --libdir=%{LIBDIR} \
+        --includedir=%{INCLUDEDIR} \
+        --with-star=/usr/bin/star \
+        --with-gnuplot=/usr/bin/gnuplot \
+        --with-gnutar=/bin/tar \
+        --with-gnutar-listdir=%{AMANDAHOMEDIR}/gnutar-lists \
+        --with-index-server=localhost \
+        --with-tape-server=localhost \
+        --with-user=%{config_user} \
+        --with-group=%{config_group} \
+        --with-owner=%{packer} \
+        --with-fqdn \
+        --with-bsd-security \
+        --with-bsdtcp-security \
+        --with-bsdudp-security \
+        --with-ssh-security \
+        --with-udpportrange=%{udpportrange} \
+        --with-tcpportrange=%{tcpportrange} \
+        --with-low-tcpportrange=%{low_tcpportrange} \
+        --with-debugging=%{LOGDIR} \
+        --with-assertions \
+        --disable-installperms
+%endif
+
+make
+
+# --- Install to buildroot ---
+
+%install
+if [ "%{buildroot}" != "/" ]; then
+        if [ -d "%{buildroot}" ] ; then
+                rm -rf %{buildroot}
+        fi
+else
+        echo "BuildRoot was somehow set to / !"
+        exit -1
+fi
+
+make -j1 DESTDIR=%{buildroot} install
+
+rm -rf %{ROOT_DATADIR}/amanda
+rm -f %{ROOT_AMANDAHOMEDIR}/example/inetd.conf.amandaclient
+mkdir %{buildroot}/{etc,var/log}
+mkdir %{ROOT_LOCALSTATEDIR}/amanda 
+mkdir %{ROOT_SYSCONFDIR}/amanda
+mkdir %{ROOT_AMANDAHOMEDIR}/gnutar-lists
+mkdir %{ROOT_LOGDIR}
+
+echo "%{amanda_version_info}" >%{ROOT_AMANDAHOMEDIR}/amanda-release
+
+# --- Clean up buildroot ---
+
+%clean
+if [ "%{buildroot}" != "/" ]; then
+        if [ -d "%{buildroot}" ] ; then
+                rm -rf %{buildroot}
+        fi
+else
+        echo "BuildRoot was somehow set to / !"
+        exit -1
+fi
+
+# --- Pre/post (un)installation scripts ---
+
+%pre
+TMPFILE=`mktemp /tmp/rpm-amanda.XXXXXXXXXXX`
+if [ $? -ne 0 ]; then
+        echo "Unable to mktemp!" 1>&2
+        exit 1
+fi
+LOGDIR="%{LOGDIR}"
+INSTALL_LOG="${LOGDIR}/install.log"
+INSTALL_ERR="${LOGDIR}/install.err"
+
+echo "`date +'%b %e %Y %T'`: Preparing to install: %{amanda_version_info}" >${TMPFILE}
+
+# Check for the 'amanda' user
+echo "`date +'%b %e %Y %T'`: Checking for '%{amanda_user}' user..." >>${TMPFILE}
+if [ "`id -u %{amanda_user} > /dev/null 2>&1 && echo 0 || echo 1`" != "0" ] ; then
+        useradd -c "Amanda" -M -g %{amanda_group} -d %{AMANDAHOMEDIR} -s /bin/sh %{amanda_user}
+        if [ %{dist} = "SuSE" ]; then
+                PASSWD_EXIT=$?
+        else
+                # Lock the amanda account until admin sets password
+                passwd -l %{amanda_user} >>/dev/null
+                PASSWD_EXIT=$?
+        fi
+        if [ ${PASSWD_EXIT} -eq 0 ] ; then
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  The '%{amanda_user}; user account has been successfully created." >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  Furthermore, the account has been automatically locked for you" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  for security purposes.  Once a password for the  '%{amanda_user}'" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  account has been set, the user can be unlocked by issuing" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  the following command as root.:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  # passwd -u %{amanda_user}" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  If this is not a new installation of Amanda and you have" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  pre-existing Amanda configurations in %{SYSCONFDIR}/amanda" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  you should ensure that 'dumpuser' is set to '%{amanda_user}'" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  in those configurations.  Additionally, you should ensure" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  that %{AMANDAHOMEDIR}/.amandahosts on your client systems" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  is properly configured to allow connections for the user" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  '%{amanda_user}'." >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                PASSWD_OK=0
+        else
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  The '%{amanda_user}' user account for this system has been   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  created, however the user has no password set. For   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  security purposes this account  is normally locked   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  after creation.  Unfortunately,  when locking this   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  account an error occurred.  To ensure the security   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  of your system  you should set a password  for the   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  user account '%{amanda_user}' immediately!  To set  such a   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  password, please issue the following command.:       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!   # passwd %{amanda_user}                                   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                PASSWD_OK=1
+        fi
+else
+        # log information about 'amanda' user parameters
+        echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  The Amanda backup software is configured to operate as the" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  user '%{amanda_user}'.  This user exists on your system and has not" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  been modified.  To ensure that Amanda functions properly," >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  please see that the following parameters are set for that" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  user.:" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  SHELL:          /bin/sh" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  HOME:           %{AMANDAHOMEDIR}" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  Default group:  %{amanda_group}" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  Verifying %{amanda_user} parameters :" >>${TMPFILE}
+
+        if [ "`id -gn %{amanda_user}`" != "disk" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  user 'amandabackup' is not part of the disk group,Pl !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  make sure it is corrected before start using amanda  !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified group name of user 'amandabackup'" >>${TMPFILE}
+        fi
+
+        if [ "`grep ^%{amanda_user} /etc/passwd|cut -d: -f7`" != "/bin/sh" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! user 'amandabackup' default shell should be set to    !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! /bin/sh, pl correct before start using Amanda         !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified Default shell for user 'amandabackup'" >>${TMPFILE}
+        fi
+
+        if [ "`grep ^%{amanda_user} /etc/passwd|cut -d: -f6`" != "%{AMANDAHOMEDIR}" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! user 'amandabackup' home directory should be set to   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! %{AMANDAHOMEDIR} Pl correct before using Amanda       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified Default home directory for user amandabackup" >>${TMPFILE}
+        fi
+        echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+        PASSWD_OK=0
+fi
+if [ -d %{AMANDAHOMEDIR} ] ; then
+        echo -n "`date +'%b %e %Y %T'`:  Checking ownership of '%{AMANDAHOMEDIR}'... " >>${TMPFILE}
+        if [ "`ls -dl %{AMANDAHOMEDIR} | awk '//{split($_,x); print x[3]}'`" = "%{amanda_user}" ] && \
+           [ "`ls -dl %{AMANDAHOMEDIR} | awk '//{split($_,x); print x[4]}'`" = "%{amanda_group}" ] ; then
+                echo "correct." >>${TMPFILE}
+                VARLIB_OK=0
+        else
+                echo "incorrect!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  Please ensure that the directory '%{AMANDAHOMEDIR}' is owned by" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  the user '%{amanda_user}' and group '%{amanda_group}'." >>${TMPFILE}
+                VARLIB_OK=1
+        fi
+else
+        VARLIB_OK=0
+fi
+echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+if [ ! -e ${LOGDIR} ] ; then
+        # create log directory
+        mkdir -m 0750 ${LOGDIR} >>${TMPFILE} 2>&1
+        chown %{amanda_user}:%{amanda_group} ${LOGDIR} >>${TMPFILE} 2>&1
+elif [ ! -d ${LOGDIR} ] ; then
+        mv ${LOGDIR} ${LOGDIR}.rpmsave >>${TMPFILE} 2>&1
+        mkdir -m 0750 ${LOGDIR} >>${TMPFILE} 2>&1
+        chown %{amanda_user}:%{amanda_group} ${LOGDIR} >>${TMPFILE} 2>&1
+        mv ${LOGDIR}.rpmsave ${LOGDIR}/ >>${TMPFILE} 2>&1
+fi
+
+if [ ${PASSWD_OK} -eq 1 ] || [ ${VARLIB_OK} -eq 1 ] ; then
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_ERR}
+        echo "Please review '${INSTALL_ERR}' to correct errors which have prevented the Amanda installaton." >&2
+        echo "Amanda installation log can be found in '${INSTALL_LOG}' and errors (if any) in '${INSTALL_ERR}'."
+        exit 1
+else
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+
+echo "`date +'%b %e %Y %T'`: === Amanda installation started. ===" >${TMPFILE}
+
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+if [ -f "${TMPFILE}" ]; then
+        rm -f "${TMPFILE}"
+fi
+
+%post
+TMPFILE=`mktemp /tmp/rpm-amanda.XXXXXXXXXXX
+if [ $? -ne 0 ]; then
+        echo "Unable to mktemp!" 1>&2
+        exit 1
+fi
+LOGDIR="%{LOGDIR}"
+INSTALL_LOG="${LOGDIR}/install.log"
+INSTALL_ERR="${LOGDIR}/install.err"
+
+echo -n "`date +'%b %e %Y %T'`: Updating library cache..." >${TMPFILE}
+/sbin/ldconfig >>${TMPFILE} 2>&1
+echo "done." >>${TMPFILE}
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+if [ -e /etc/xinetd.d ] && [ -d /etc/xinetd.d ] ; then
+        if [ ! -f /etc/xinetd.d/amandaserver ] ; then
+                cp %{AMANDAHOMEDIR}/example/xinetd.amandaserver /etc/xinetd.d/amandaserver
+                chmod 0644 /etc/xinetd.d/amandaserver >>${TMPFILE} 2>&1
+                if [ -f /etc/xinetd.d/amandaclient ] ; then
+                        rm /etc/xinetd.d/amandaclient
+                fi
+                echo -n "`date +'%b %e %Y %T'`: Reloading xinetd configuration..." >${TMPFILE}
+                if [ "%{xinetd_reload}" == "reload" ] ; then
+                        /etc/init.d/xinetd %{xinetd_reload} >>${TMPFILE} 2>&1
+                        ret_val=$?
+                        if [ ${ret_val} -ne 0 ] ; then
+                                echo -n "reload failed.  Attempting restart..." >>${TMPFILE}
+                                /etc/init.d/xinetd restart >>${TMPFILE} 2>&1
+                                ret_val=$?
+                        fi
+                else
+                        /etc/init.d/xinetd %{xinetd_reload} >>${TMPFILE} 2>&1
+                        ret_val=$?
+                fi
+                if [ ${ret_val} -eq 0 ] ; then
+                        echo "success." >>${TMPFILE}
+                        cat ${TMPFILE}
+                        cat ${TMPFILE} >>${INSTALL_LOG}
+                else
+                        echo "failed.  Please check your system logs." >>${TMPFILE}
+                        cat ${TMPFILE} 1>&2
+                        cat ${TMPFILE} >>${INSTALL_ERR}
+                fi
+        fi
+fi
+
+echo "`date +'%b %e %Y %T'`: Installing '%{LOCALSTATEDIR}/amanda/amandates'." >${TMPFILE}
+ret_val=0
+if [ ! -f %{LOCALSTATEDIR}/amanda/amandates ] ; then
+        touch %{LOCALSTATEDIR}/amanda/amandates >>${TMPFILE} 2>&1
+        ret_val=$?
+        if [ ${ret_val} -eq 0 ]; then
+                echo "`date +'%b %e %Y %T'`: The file '%{LOCALSTATEDIR}/amanda/amandates' has been created." >>${TMPFILE}
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '%{LOCALSTATEDIR}/amanda/amandates'." >>${TMPFILE}
+        chown %{amanda_user}:%{amanda_group} %{LOCALSTATEDIR}/amanda/amandates >>${TMPFILE} 2>&1
+        chmod 0640 %{LOCALSTATEDIR}/amanda/amandates >>${TMPFILE} 2>&1
+        if [ -x /sbin/restorecon ] ; then
+              /sbin/restorecon %{LOCALSTATEDIR}/amanda/amandates  >>${TMPFILE} 2>&1
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: '%{LOCALSTATEDIR}/amanda/amandates' Installation successful." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+else
+        echo "`date +'%b %e %Y %T'`: '%{LOCALSTATEDIR}/amanda/amandates' Installation failed." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_ERR}
+fi
+
+
+# Install .gnupg directory
+echo "`date +'%b %e %Y %T'`: Installing '%{AMANDAHOMEDIR}/.gnupg'." >${TMPFILE}
+ret_val=0
+if [ ! -d %{AMANDAHOMEDIR}/.gnupg ] ; then
+        echo "`date +'%b %e %Y %T'`: '%{AMANDAHOMEDIR}/.gnupg' will be created." >>${TMPFILE}
+        mkdir %{AMANDAHOMEDIR}/.gnupg >>${TMPFILE} 2>&1
+        ret_val=$?
+        if [ ${ret_val} -eq 0 ]; then
+                echo "`date +'%b %e %Y %T'`: The directory '%{AMANDAHOMEDIR}/.gnupg' created successfully." >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`: The directory '%{AMANDAHOMEDIR}/.gnupg' creation failed." >>${TMPFILE}
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '%{AMANDAHOMEDIR}/.gnupg'." >>${TMPFILE}
+        chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.gnupg >>${TMPFILE} 2>&1
+        ret_val=$?
+        if [ ${ret_val} -eq 0 ]; then
+                chmod 700 %{AMANDAHOMEDIR}/.gnupg >>${TMPFILE} 2>&1
+                ret_val=$?
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: '%{AMANDAHOMEDIR}/.gnupg' Installation successful." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+else
+        echo "`date +'%b %e %Y %T'`: '%{AMANDAHOMEDIR}/.gnupg' Installation failed." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_ERR}
+fi
+
+# Install .amandahosts
+echo "`date +'%b %e %Y %T'`: Checking '%{AMANDAHOMEDIR}/.amandahosts' file." >${TMPFILE}
+if [ ! -f %{AMANDAHOMEDIR}/.amandahosts ] ; then
+        touch %{AMANDAHOMEDIR}/.amandahosts >>${TMPFILE} 2>&1
+fi
+for host in localhost localhost.localdomain ; do
+        if [ -z "`grep \"^${host}[[:blank:]]\+root[[:blank:]]\+amindexd[[:blank:]]\+amidxtaped\" %{AMANDAHOMEDIR}/.amandahosts`" ] ; then
+                echo "${host}   root amindexd amidxtaped" >>%{AMANDAHOMEDIR}/.amandahosts
+        fi
+        if [ -z "`grep \"^${host}[[:blank:]]\+%{amanda_user}[[:blank:]]\+amdump\" %{AMANDAHOMEDIR}/.amandahosts`" ] ; then
+                echo "${host}   %{amanda_user} amdump" >>%{AMANDAHOMEDIR}/.amandahosts
+        fi
+done
+chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.amandahosts >>${TMPFILE} 2>&1
+chmod 0600 %{AMANDAHOMEDIR}/.amandahosts >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# SSH RSA key generation for amdump
+KEYDIR="%{AMANDAHOMEDIR}/.ssh"
+KEYFILE="id_rsa_amdump"
+COMMENT="%{amanda_user}@server"
+if [ ! -d ${KEYDIR} ] ; then
+        if [ -f ${KEYDIR} ] ; then
+                echo "`date +'%b %e %Y %T'`: Directory '${KEYDIR}' exists as a file.  Renaming to '${KEYDIR}.rpmsave'." >${TMPFILE}
+                mv ${KEYDIR} ${KEYDIR}.rpmsave
+                cat ${TMPFILE}
+                cat ${TMPFILE} >>${INSTALL_LOG}
+        fi
+        echo "`date +'%b %e %Y %T'`: Creating directory '${KEYDIR}'." >${TMPFILE}
+        mkdir ${KEYDIR} >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+if [ ! -f ${KEYDIR}/${KEYFILE} ] ; then
+        echo "`date +'%b %e %Y %T'`: Creating ssh RSA key in '${KEYDIR}/${KEYFILE}'" >${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+        ssh-keygen -q -C $COMMENT -t rsa -f ${KEYDIR}/${KEYFILE} -N '' >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+echo "`date +'%b %e %Y %T'`: Setting ownership and permissions for '${KEYDIR}' and '${KEYDIR}/${KEYFILE}*'" >${TMPFILE}
+chown %{amanda_user}:%{amanda_group} ${KEYDIR} ${KEYDIR}/${KEYFILE}* >>${TMPFILE} 2>&1
+chmod 0750 ${KEYDIR} >>${TMPFILE} 2>&1
+chmod 0600 ${KEYDIR}/${KEYFILE}* >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# SSH RSA key generation on client for amrecover
+KEYDIR="%{AMANDAHOMEDIR}/.ssh"
+KEYFILE="id_rsa_amrecover"
+COMMENT="root@client"
+if [ ! -d ${KEYDIR} ] ; then
+        if [ -f ${KEYDIR} ] ; then
+                echo "`date +'%b %e %Y %T'`: Directory '${KEYDIR}' exists as a file.  Renaming to '${KEYDIR}.rpmsave'." >${TMPFILE}
+                mv ${KEYDIR} ${KEYDIR}.rpmsave >>${TMPFILE} 2>&1
+                cat ${TMPFILE}
+                cat ${TMPFILE} >>${INSTALL_LOG}
+        fi
+        echo "`date +'%b %e %Y %T'`: Creating directory '${KEYDIR}'." >${TMPFILE}
+        mkdir ${KEYDIR} >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+if [ ! -f ${KEYDIR}/${KEYFILE} ] ; then
+        echo "`date +'%b %e %Y %T'`: Creating ssh RSA key in '${KEYDIR}/${KEYFILE}'" >${TMPFILE}
+        ssh-keygen -q -C $COMMENT -t rsa -f ${KEYDIR}/${KEYFILE} -N '' >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+echo "`date +'%b %e %Y %T'`: Setting permissions for '${KEYDIR}'" >${TMPFILE}
+chown %{amanda_user}:%{amanda_group} ${KEYDIR} >>${TMPFILE} 2>&1
+chmod 0750 ${KEYDIR} >>${TMPFILE} 2>&1
+chmod 0600 ${KEYDIR}/${KEYFILE}* >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# environment variables (~amandabackup/.profile)
+echo "`date +'%b %e %Y %T'`: Checking for '%{AMANDAHOMEDIR}/.profile' and ensuring correct environment." >${TMPFILE}
+if [ ! -f %{AMANDAHOMEDIR}/.profile ] ; then
+        touch %{AMANDAHOMEDIR}/.profile >>${TMPFILE} 2>&1
+fi
+if [ -z "`grep PATH %{AMANDAHOMEDIR}/.profile | grep '%{SBINDIR}'`" ] ; then
+        echo "export PATH=\"\$PATH:%{SBINDIR}\"" >>%{AMANDAHOMEDIR}/.profile 2>>${TMPFILE}
+fi
+echo "`date +'%b %e %Y %T'`: Setting ownership and permissions for '%{AMANDAHOMEDIR}/.profile'" >>${TMPFILE}
+chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.profile >>${TMPFILE} 2>&1
+chmod 0640 %{AMANDAHOMEDIR}/.profile >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+echo "`date +'%b %e %Y %T'`: Sending anonymous distribution and version information to Zmanda" >> ${INSTALL_LOG}
+if [ -x /usr/bin/wget ]; then 
+        /usr/bin/wget -q -o /dev/null -O - --timeout=5 http://www.zmanda.com/amanda-tips.php\?version=%{amanda_version}\&os=%{disttag}%{distver}\&type=server 
+fi
+
+echo "`date +'%b %e %Y %T'`: === Amanda installation complete. ===" >${TMPFILE}
+
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+if [ -f "${TMPFILE}" ]; then
+        rm -f "${TMPFILE}"
+fi
+
+echo "Amanda installation log can be found in '${INSTALL_LOG}' and errors (if any) in '${INSTALL_ERR}'."
+%postun
+/sbin/ldconfig
+%pre backup_server
+TMPFILE=`mktemp /tmp/rpm-amanda.XXXXXXXXXXX`
+if [ $? -ne 0 ]; then
+        echo "Unable to mktemp!" 1>&2
+        exit 1
+fi
+
+LOGDIR="%{LOGDIR}"
+INSTALL_LOG="${LOGDIR}/install.log"
+INSTALL_ERR="${LOGDIR}/install.err"
+
+echo "`date +'%b %e %Y %T'`: Preparing to install: %{amanda_version_info}" >${TMPFILE}
+
+# Check for the 'amanda' user
+echo "`date +'%b %e %Y %T'`: Checking for '%{amanda_user}' user..." >>${TMPFILE}
+if [ "`id -u %{amanda_user} > /dev/null 2>&1 && echo 0 || echo 1`" != "0" ] ; then
+        useradd -c "Amanda" -M -g %{amanda_group} -d %{AMANDAHOMEDIR} -s /bin/sh %{amanda_user}
+        if [ %{dist} = "SuSE" ]; then
+                PASSWD_EXIT=$?
+        else
+                # Lock the amanda account until admin sets password
+                passwd -l %{amanda_user} >>/dev/null
+                PASSWD_EXIT=$?
+        fi
+        if [ ${PASSWD_EXIT} -eq 0 ] ; then
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  The '%{amanda_user}; user account has been successfully created." >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  Furthermore, the account has been automatically locked for you" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  for security purposes.  Once a password for the  '%{amanda_user}'" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  account has been set, the user can be unlocked by issuing" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  the following command as root.:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  # passwd -u %{amanda_user}" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  If this is not a new installation of Amanda and you have" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  pre-existing Amanda configurations in %{SYSCONFDIR}/amanda" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  you should ensure that 'dumpuser' is set to '%{amanda_user}'" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  in those configurations.  Additionally, you should ensure" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  that %{AMANDAHOMEDIR}/.amandahosts on your client systems" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  is properly configured to allow connections for the user" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  '%{amanda_user}'." >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                PASSWD_OK=0
+        else
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  The '%{amanda_user}' user account for this system has been   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  created, however the user has no password set. For   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  security purposes this account  is normally locked   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  after creation.  Unfortunately,  when locking this   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  account an error occurred.  To ensure the security   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  of your system  you should set a password  for the   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  user account '%{amanda_user}' immediately!  To set  such a   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  password, please issue the following command.:       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!   # passwd %{amanda_user}                                     !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                PASSWD_OK=1
+        fi
+else
+        # log information about 'amanda' user parameters
+        echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  The Amanda backup software is configured to operate as the" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  user '%{amanda_user}'.  This user exists on your system and has not" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  been modified.  To ensure that Amanda functions properly," >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  please see that the following parameters are set for that" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  user.:" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  SHELL:          /bin/sh" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  HOME:           %{AMANDAHOMEDIR}" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  Default group:  %{amanda_group}" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  Verifying %{amanda_user} parameters :" >>${TMPFILE}
+
+        if [ "`id -gn %{amanda_user}`" != "disk" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! user 'amandabackup' is not part of the disk group,Pl  !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! make sure it is corrected before start using Amanda   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified group name of user 'amandabackup'" >>${TMPFILE}
+        fi
+
+        if [ "`grep ^%{amanda_user} /etc/passwd|cut -d: -f7`" != "/bin/sh" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! user 'amandabackup' default shell should be set to    !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! /bin/sh, pl correct before start using Amanda         !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified Default shell for user 'amandabackup'" >>${TMPFILE}
+        fi
+
+        if [ "`grep ^%{amanda_user} /etc/passwd|cut -d: -f6`" != "%{AMANDAHOMEDIR}" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! user 'amandabackup' home directory should be set to   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! %{AMANDAHOMEDIR} Pl correct before using Amanda       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified Default home directory for user amandabackup" >>${TMPFILE}
+        fi
+        echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+        PASSWD_OK=0
+fi
+if [ -d %{AMANDAHOMEDIR} ] ; then
+        echo -n "`date +'%b %e %Y %T'`:  Checking ownership of '%{AMANDAHOMEDIR}'... " >>${TMPFILE}
+        if [ "`ls -dl %{AMANDAHOMEDIR} | awk '//{split($_,x); print x[3]}'`" = "%{amanda_user}" ] && \
+           [ "`ls -dl %{AMANDAHOMEDIR} | awk '//{split($_,x); print x[4]}'`" = "%{amanda_group}" ] ; then
+                echo "correct." >>${TMPFILE}
+                VARLIB_OK=0
+        else
+                echo "incorrect!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  Please ensure that the directory '%{AMANDAHOMEDIR}' is owned by" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  the user '%{amanda_user}' and group '%{amanda_group}'." >>${TMPFILE}
+                VARLIB_OK=1
+        fi
+else
+        VARLIB_OK=0
+fi
+echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+
+if [ ! -e ${LOGDIR} ] ; then
+        # create log directory
+        mkdir -m 0750 ${LOGDIR} >>${TMPFILE} 2>&1
+        chown %{amanda_user}:%{amanda_group} ${LOGDIR} >>${TMPFILE} 2>&1
+elif [ ! -d ${LOGDIR} ] ; then
+        mv ${LOGDIR} ${LOGDIR}.rpmsave >>${TMPFILE} 2>&1
+        mkdir -m 0750 ${LOGDIR} >>${TMPFILE} 2>&1
+        chown %{amanda_user}:%{amanda_group} ${LOGDIR} >>${TMPFILE} 2>&1
+        mv ${LOGDIR}.rpmsave ${LOGDIR}/ >>${TMPFILE} 2>&1
+fi
+if [ ${PASSWD_OK} -eq 1 ] || [ ${VARLIB_OK} -eq 1 ] ; then
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_ERR}
+        echo "Please review '${INSTALL_ERR}' to correct errors which have prevented the Amanda installaton." >&2
+        echo "Amanda installation log can be found in '${INSTALL_LOG}' and errors (if any) in '${INSTALL_ERR}'."
+        exit 1
+else
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+
+echo "`date +'%b %e %Y %T'`: === Amanda backup server installation started. ===" >${TMPFILE}
+
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+if [ -f "${TMPFILE}" ]; then
+        rm -f "${TMPFILE}"
+fi
+%post backup_server
+TMPFILE=`mktemp /tmp/rpm-amanda.XXXXXXXXXXX`
+if [ $? -ne 0 ]; then
+        echo "Unable to mktemp!" 1>&2
+        exit 1
+fi
+LOGDIR="%{LOGDIR}"
+INSTALL_LOG="${LOGDIR}/install.log"
+INSTALL_ERR="${LOGDIR}/install.err"
+
+echo -n "`date +'%b %e %Y %T'`: Updating system library cache..." >${TMPFILE}
+/sbin/ldconfig
+echo "done." >>${TMPFILE}
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+if [ -e /etc/xinetd.d ] && [ -d /etc/xinetd.d ] ; then
+        if [ ! -f /etc/xinetd.d/amandaserver ] ; then
+                cp %{AMANDAHOMEDIR}/example/xinetd.amandaserver /etc/xinetd.d/amandaserver
+                chmod 0644 /etc/xinetd.d/amandaserver >>${TMPFILE} 2>&1
+                if [ -f /etc/xinetd.d/amandaclient ] ; then
+                        rm /etc/xinetd.d/amandaclient
+                fi
+
+                echo -n "`date +'%b %e %Y %T'`: Reloading xinetd configuration..." >${TMPFILE}
+                if [ "%{xinetd_reload}" == "reload" ] ; then
+                        /etc/init.d/xinetd %{xinetd_reload} >>${TMPFILE} 2>&1
+                        ret_val=$?
+                        if [ ${ret_val} -ne 0 ] ; then
+                                echo -n "reload failed.  Attempting restart..." >>${TMPFILE}
+                                /etc/init.d/xinetd restart >>${TMPFILE} 2>&1
+                                ret_val=$?
+                        fi
+                else
+                        /etc/init.d/xinetd %{xinetd_reload} >>${TMPFILE} 2>&1
+                        ret_val=$?
+                fi
+                if [ ${ret_val} -eq 0 ] ; then
+                        echo "success." >>${TMPFILE}
+                        cat ${TMPFILE}
+                        cat ${TMPFILE} >>${INSTALL_LOG}
+                else
+                        echo "failed.  Please check your system logs." >>${TMPFILE}
+                        cat ${TMPFILE} 1>&2
+                        cat ${TMPFILE} >>${INSTALL_ERR}
+                fi
+        fi
+fi
+
+echo "`date +'%b %e %Y %T'`: Installing '%{LOCALSTATEDIR}/amanda/amandates'." >${TMPFILE}
+ret_val=0
+if [ ! -f %{LOCALSTATEDIR}/amanda/amandates ] ; then
+        touch %{LOCALSTATEDIR}/amanda/amandates >>${TMPFILE} 2>&1
+        ret_val=$?
+        if [ ${ret_val} -eq 0 ]; then
+                echo "`date +'%b %e %Y %T'`: The file '%{LOCALSTATEDIR}/amanda/amandates' has been created." >>${TMPFILE}
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '%{LOCALSTATEDIR}/amanda/amandates'." >>${TMPFILE}
+        chown %{amanda_user}:%{amanda_group} %{LOCALSTATEDIR}/amanda/amandates >>${TMPFILE} 2>&1
+        chmod 0640 %{LOCALSTATEDIR}/amanda/amandates >>${TMPFILE} 2>&1
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: '%{LOCALSTATEDIR}/amanda/amandates' Installation successful." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+else
+        echo "`date +'%b %e %Y %T'`: '%{LOCALSTATEDIR}/amanda/amandates' Installation failed." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_ERR}
+fi
+
+# Install .amandahosts to server
+echo "`date +'%b %e %Y %T'`: Checking '%{AMANDAHOMEDIR}/.amandahosts' file." >${TMPFILE}
+if [ ! -f %{AMANDAHOMEDIR}/.amandahosts ] ; then
+        touch %{AMANDAHOMEDIR}/.amandahosts >>${TMPFILE} 2>&1
+fi
+for host in localhost localhost.localdomain ; do
+        if [ -z "`grep \"^${host}[[:blank:]]\+root[[:blank:]]\+amindexd[[:blank:]]\+amidxtaped\" %{AMANDAHOMEDIR}/.amandahosts`" ] ; then
+                echo "${host}   root amindexd amidxtaped" >>%{AMANDAHOMEDIR}/.amandahosts
+        fi
+        if [ -z "`grep \"^${host}[[:blank:]]\+%{amanda_user}[[:blank:]]\+amdump\" %{AMANDAHOMEDIR}/.amandahosts`" ] ; then
+                echo "${host}   %{amanda_user} amdump" >>%{AMANDAHOMEDIR}/.amandahosts
+        fi
+done
+chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.amandahosts >>${TMPFILE} 2>&1
+chmod 0600 %{AMANDAHOMEDIR}/.amandahosts >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# Install amanda client configuration file
+echo "`date +'%b %e %Y %T'`: Checking '%{SYSCONFDIR}/amanda/amanda-client.conf' file." >${TMPFILE}
+if [ ! -f %{SYSCONFDIR}/amanda/amanda-client.conf ] ; then
+        cp %{AMANDAHOMEDIR}/example/amanda-client.conf %{SYSCONFDIR}/amanda/amanda-client.conf >>${TMPFILE} 2>&1
+fi
+chown %{amanda_user}:%{amanda_group} %{SYSCONFDIR}/amanda/amanda-client.conf >>${TMPFILE} 2>&1
+chmod 0600 %{SYSCONFDIR}/amanda/amanda-client.conf >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# install am_passphrase file to server
+echo "`date +'%b %e %Y %T'`: Checking '%{AMANDAHOMEDIR}/.am_passphrase' file." >${TMPFILE}
+if [ ! -f %{AMANDAHOMEDIR}/.am_passphrase ] ; then
+        echo "`date +'%b %e %Y %T'`: Create '%{AMANDAHOMEDIR}/.am_passphrase' file." >${TMPFILE}
+        touch %{AMANDAHOMEDIR}/.am_passphrase >>${TMPFILE} 2>&1
+        phrase=`echo "amandabackup" | md5sum | awk '{print $1}'`
+        echo ${phrase} >>%{AMANDAHOMEDIR}/.am_passphrase
+
+        chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.am_passphrase >>${TMPFILE} 2>&1
+        chmod 0700 %{AMANDAHOMEDIR}/.am_passphrase >>${TMPFILE} 2>&1
+fi
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# Install .gnupg directory
+echo "`date +'%b %e %Y %T'`: Installing '%{AMANDAHOMEDIR}/.gnupg'." >${TMPFILE}
+ret_val=0
+if [ ! -d %{AMANDAHOMEDIR}/.gnupg ] ; then
+        echo "`date +'%b %e %Y %T'`: '%{AMANDAHOMEDIR}/.gnupg' will be created." >>${TMPFILE}
+        mkdir %{AMANDAHOMEDIR}/.gnupg >>${TMPFILE} 2>&1
+        ret_val=$?
+        if [ ${ret_val} -eq 0 ]; then
+                echo "`date +'%b %e %Y %T'`: The directory '%{AMANDAHOMEDIR}/.gnupg' created successfully." >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`: The directory '%{AMANDAHOMEDIR}/.gnupg' creation failed." >>${TMPFILE}
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '%{AMANDAHOMEDIR}/.gnupg'." >>${TMPFILE}
+        chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.gnupg >>${TMPFILE} 2>&1
+        ret_val=$?
+        if [ ${ret_val} -eq 0 ]; then
+                chmod 700 %{AMANDAHOMEDIR}/.gnupg >>${TMPFILE} 2>&1
+                ret_val=$?
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: '%{AMANDAHOMEDIR}/.gnupg' Installation successful." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+else
+        echo "`date +'%b %e %Y %T'`: '%{AMANDAHOMEDIR}/.gnupg' Installation failed." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_ERR}
+fi
+
+# SSH RSA key generation on server for amdump
+KEYDIR="%{AMANDAHOMEDIR}/.ssh"
+KEYFILE="id_rsa_amdump"
+COMMENT="%{amanda_user}@server"
+if [ ! -d ${KEYDIR} ] ; then
+        if [ -f ${KEYDIR} ] ; then
+                echo "`date +'%b %e %Y %T'`: Directory '${KEYDIR}' exists as a file.  Renaming to '${KEYDIR}.rpmsave'." >${TMPFILE}
+                mv ${KEYDIR} ${KEYDIR}.rpmsave >>${TMPFILE} 2>&1
+                cat ${TMPFILE}
+                cat ${TMPFILE} >>${INSTALL_LOG}
+        fi
+        echo "`date +'%b %e %Y %T'`: Creating directory '${KEYDIR}'." >${TMPFILE}
+        mkdir ${KEYDIR} >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+if [ ! -f ${KEYDIR}/${KEYFILE} ] ; then
+        echo "`date +'%b %e %Y %T'`: Creating ssh RSA key in '${KEYDIR}/${KEYFILE}'" >${TMPFILE}
+        ssh-keygen -q -C $COMMENT -t rsa -f ${KEYDIR}/${KEYFILE} -N '' >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+echo "`date +'%b %e %Y %T'`: Setting ownership and permissions for '${KEYDIR}' and '${KEYDIR}/${KEYFILE}*'" >${TMPFILE}
+chown %{amanda_user}:%{amanda_group} ${KEYDIR} ${KEYDIR}/${KEYFILE}* >>${TMPFILE} 2>&1
+chmod 0750 ${KEYDIR} >>${TMPFILE} 2>&1
+chmod 0600 ${KEYDIR}/${KEYFILE}* >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# SSH RSA key generation on client for amrecover
+KEYDIR="%{AMANDAHOMEDIR}/.ssh"
+KEYFILE="id_rsa_amrecover"
+COMMENT="root@client"
+if [ ! -d ${KEYDIR} ] ; then
+        if [ -f ${KEYDIR} ] ; then
+                echo "`date +'%b %e %Y %T'`: Directory '${KEYDIR}' exists as a file.  Renaming to '${KEYDIR}.rpmsave'." >${TMPFILE}
+                mv ${KEYDIR} ${KEYDIR}.rpmsave >>${TMPFILE} 2>&1
+                cat ${TMPFILE}
+                cat ${TMPFILE} >>${INSTALL_LOG}
+        fi
+        echo "`date +'%b %e %Y %T'`: Creating directory '${KEYDIR}'." >${TMPFILE}
+        mkdir ${KEYDIR} >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+if [ ! -f ${KEYDIR}/${KEYFILE} ] ; then
+        echo "`date +'%b %e %Y %T'`: Creating ssh RSA key in '${KEYDIR}/${KEYFILE}'" >${TMPFILE}
+        ssh-keygen -q -C $COMMENT -t rsa -f ${KEYDIR}/${KEYFILE} -N '' >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+echo "`date +'%b %e %Y %T'`: Setting ownership and permissions for '${KEYDIR}'" >${TMPFILE}
+chown %{amanda_user}:%{amanda_group} ${KEYDIR} >>${TMPFILE} 2>&1
+chmod 0750 ${KEYDIR} >>${TMPFILE} 2>&1
+chmod 0600 ${KEYDIR}/${KEYFILE}* >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# environment variables (~amandabackup/.profile)
+echo "`date +'%b %e %Y %T'`: Checking for '%{AMANDAHOMEDIR}/.profile' and ensuring correct environment." >${TMPFILE}
+if [ ! -f %{AMANDAHOMEDIR}/.profile ] ; then
+        touch %{AMANDAHOMEDIR}/.profile >>${TMPFILE} 2>&1
+fi
+if [ -z "`grep PATH %{AMANDAHOMEDIR}/.profile | grep '%{SBINDIR}'`" ] ; then
+        echo "export PATH=\"\$PATH:%{SBINDIR}\"" >>%{AMANDAHOMEDIR}/.profile 2>>${TMPFILE}
+fi
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+echo "`date +'%b %e %Y %T'`: Setting ownership and permissions for '%{AMANDAHOMEDIR}/.profile'" >${TMPFILE}
+chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.profile >>${TMPFILE} 2>&1
+chmod 0640 %{AMANDAHOMEDIR}/.profile >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+echo "`date +'%b %e %Y %T'`: Sending anonymous distribution and version information to Zmanda" >> ${INSTALL_LOG}
+if [ -x /usr/bin/wget ]; then 
+        /usr/bin/wget -q -o /dev/null -O - --timeout=5 http://www.zmanda.com/amanda-tips.php\?version=%{amanda_version}\&os=%{disttag}%{distver}\&type=server 
+fi
+
+echo "`date +'%b %e %Y %T'`: === Amanda backup server installation complete. ===" >${TMPFILE}
+
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+if [ -f "${TMPFILE}" ]; then
+        rm -f "${TMPFILE}" >>${TMPFILE} 2>&1
+fi
+
+echo "Amanda installation log can be found in '${INSTALL_LOG}' and errors (if any) in '${INSTALL_ERR}'."
+%postun backup_server
+/sbin/ldconfig
+%pre backup_client
+TMPFILE=`mktemp /tmp/rpm-amanda.XXXXXXXXXXX`
+if [ $? -ne 0 ]; then
+        echo "Unable to mktemp!" 1>&2
+        exit 1
+fi
+LOGDIR="%{LOGDIR}"
+INSTALL_LOG="${LOGDIR}/install.log"
+INSTALL_ERR="${LOGDIR}/install.err"
+
+echo "`date +'%b %e %Y %T'`: Preparing to install: %{amanda_version_info}" >${TMPFILE}
+
+# Check for the 'amanda' user
+echo "`date +'%b %e %Y %T'`: Checking for '%{amanda_user}' user..." >>${TMPFILE}
+if [ "`id -u %{amanda_user} > /dev/null 2>&1 && echo 0 || echo 1`" != "0" ] ; then
+        useradd -c "Amanda" -M -g %{amanda_group} -d %{AMANDAHOMEDIR} -s /bin/sh %{amanda_user} >>${TMPFILE} 2>&1
+        if [ %{dist} = "SuSE" ]; then
+                PASSWD_EXIT=$?
+        else
+                # Lock the amanda account until admin sets password
+                passwd -l %{amanda_user} >>/dev/null
+                PASSWD_EXIT=$?
+        fi
+        if [ ${PASSWD_EXIT} -eq 0 ] ; then
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  The '%{amanda_user}; user account has been successfully created." >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  Furthermore, the account has been automatically locked for you" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  for security purposes.  Once a password for the  '%{amanda_user}'" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  account has been set, the user can be unlocked by issuing" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  the following command as root.:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  # passwd -u %{amanda_user}" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  If this is not a new installation of Amanda and you have" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  pre-existing Amanda configurations in %{SYSCONFDIR}/amanda" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  you should ensure that 'dumpuser' is set to '%{amanda_user}'" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  in those configurations.  Additionally, you should ensure" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  that %{AMANDAHOMEDIR}/.amandahosts on your client systems" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  is properly configured to allow connections for the user" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  '%{amanda_user}'." >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+                PASSWD_OK=0
+        else
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  The '%{amanda_user}' user account for this system has been   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  created, however the user has no password set. For   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  security purposes this account  is normally locked   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  after creation.  Unfortunately,  when locking this   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  account an error occurred.  To ensure the security   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  of your system  you should set a password  for the   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  user account '%{amanda_user}' immediately!  To set  such a   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!  password, please issue the following command.:       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!   # passwd %{amanda_user}                                     !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!!                                                       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                PASSWD_OK=1
+        fi
+else
+        # log information about 'amanda' user parameters
+        echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  The Amanda backup software is configured to operate as the" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  user '%{amanda_user}'.  This user exists on your system and has not" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  been modified.  To ensure that Amanda functions properly," >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  please see that the following parameters are set for that" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  user.:" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  SHELL:          /bin/sh" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  HOME:           %{AMANDAHOMEDIR}" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  Default group:  %{amanda_group}" >>${TMPFILE}
+        echo "`date +'%b %e %Y %T'`:  Verifying %{amanda_user} parameters :" >>${TMPFILE}
+
+        if [ "`id -gn %{amanda_user}`" != "disk" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! user 'amandabackup' is not part of the disk group,Pl  !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! make sure it is corrected before start using Amanda   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified group name of user 'amandabackup'" >>${TMPFILE}
+        fi
+
+        if [ "`grep ^%{amanda_user} /etc/passwd|cut -d: -f7`" != "/bin/sh" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! user 'amandabackup' default shell should be set to    !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! /bin/sh, pl correct before start using Amanda         !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified Default shell for user 'amandabackup'" >>${TMPFILE}
+        fi
+
+        if [ "`grep ^%{amanda_user} /etc/passwd|cut -d: -f6`" != "%{AMANDAHOMEDIR}" ] ; then
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! user 'amandabackup' home directory should be set to   !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! %{AMANDAHOMEDIR} Pl correct before using Amanda       !!!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  !!! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! !!!" >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`:  Verified Default home directory for user amandabackup" >>${TMPFILE}
+        fi
+        echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+        PASSWD_OK=0
+fi
+if [ -d %{AMANDAHOMEDIR} ] ; then
+        echo -n "`date +'%b %e %Y %T'`:  Checking ownership of '%{AMANDAHOMEDIR}'... " >>${TMPFILE}
+        if [ "`ls -dl %{AMANDAHOMEDIR} | awk '//{split($_,x); print x[3]}'`" = "%{amanda_user}" ] && \
+           [ "`ls -dl %{AMANDAHOMEDIR} | awk '//{split($_,x); print x[4]}'`" = "%{amanda_group}" ] ; then
+                echo "correct." >>${TMPFILE}
+                VARLIB_OK=0
+        else
+                echo "incorrect!" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  Please ensure that the directory '%{AMANDAHOMEDIR}' is owned by" >>${TMPFILE}
+                echo "`date +'%b %e %Y %T'`:  the user '%{amanda_user}' and group '%{amanda_group}'." >>${TMPFILE}
+                VARLIB_OK=1
+        fi
+else
+        VARLIB_OK=0
+fi
+echo "`date +'%b %e %Y %T'`:" >>${TMPFILE}
+
+if [ ! -e ${LOGDIR} ] ; then
+        # create log directory
+        mkdir -m 0750 ${LOGDIR} >>${TMPFILE} 2>&1
+        chown %{amanda_user}:%{amanda_group} ${LOGDIR} >>${TMPFILE} 2>&1
+elif [ ! -d ${LOGDIR} ] ; then
+        mv ${LOGDIR} ${LOGDIR}.rpmsave >>${TMPFILE} 2>&1
+        mkdir -m 0750 ${LOGDIR} >>${TMPFILE} 2>&1
+        chown %{amanda_user}:%{amanda_group} ${LOGDIR} >>${TMPFILE} 2>&1
+        mv ${LOGDIR}.rpmsave ${LOGDIR}/ >>${TMPFILE} 2>&1
+fi
+if [ ${PASSWD_OK} -eq 1 ] || [ ${VARLIB_OK} -eq 1 ] ; then
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_ERR}
+        echo "Please review '${INSTALL_ERR}' to correct errors which have prevented the Amanda installaton." >&2
+        echo "Amanda installation log can be found in '${INSTALL_LOG}' and errors (if any) in '${INSTALL_ERR}'."
+        exit 1
+else
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+
+echo "`date +'%b %e %Y %T'`: === Amanda backup client installation started. ===" >${TMPFILE}
+
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+if [ -f "${TMPFILE}" ]; then
+        rm -f "${TMPFILE}"
+fi
+
+%post backup_client
+TMPFILE=`mktemp /tmp/rpm-amanda.XXXXXXXXXXX`
+if [ $? -ne 0 ]; then
+        echo "Unable to mktemp!" 1>&2
+        exit 1
+fi
+LOGDIR="%{LOGDIR}"
+INSTALL_LOG="${LOGDIR}/install.log"
+INSTALL_ERR="${LOGDIR}/install.err"
+
+echo -n "`date +'%b %e %Y %T'`: Updating system library cache..." >${TMPFILE}
+/sbin/ldconfig
+echo "done." >>${TMPFILE}
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+if [ -e /etc/xinetd.d ] && [ -d /etc/xinetd.d ] ; then
+        if [ ! -f /etc/xinetd.d/amandaclient ] ; then
+                cp %{AMANDAHOMEDIR}/example/xinetd.amandaclient /etc/xinetd.d/amandaclient
+
+                echo -n "`date +'%b %e %Y %T'`: Reloading xinetd configuration..." >${TMPFILE}
+                if [ "%{xinetd_reload}" == "reload" ] ; then
+                        /etc/init.d/xinetd %{xinetd_reload} >>${TMPFILE} 2>&1
+                        ret_val=$?
+                        if [ ${ret_val} -ne 0 ] ; then
+                                echo -n "reload failed.  Attempting restart..." >>${TMPFILE}
+                                /etc/init.d/xinetd restart >>${TMPFILE} 2>&1
+                                ret_val=$?
+                        fi
+                else
+                        /etc/init.d/xinetd %{xinetd_reload} >>${TMPFILE} 2>&1
+                        ret_val=$?
+                fi
+                if [ ${ret_val} -eq 0 ] ; then
+                        echo "success." >>${TMPFILE}
+                        cat ${TMPFILE}
+                        cat ${TMPFILE} >>${INSTALL_LOG}
+                else
+                        echo "failed.  Please check your system logs." >>${TMPFILE}
+                        cat ${TMPFILE}
+                        cat ${TMPFILE} >>${INSTALL_LOG}
+                fi
+        fi
+fi
+
+echo "`date +'%b %e %Y %T'`: Installing '%{LOCALSTATEDIR}/amanda/amandates'." >${TMPFILE}
+ret_val=0
+if [ ! -f %{LOCALSTATEDIR}/amanda/amandates ] ; then
+        touch %{LOCALSTATEDIR}/amanda/amandates >>${TMPFILE} 2>&1
+        ret_val=$?
+        if [ ${ret_val} -eq 0 ]; then
+                echo "`date +'%b %e %Y %T'`: The file '%{LOCALSTATEDIR}/amanda/amandates' has been created." >>${TMPFILE}
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '%{LOCALSTATEDIR}/amanda/amandates'." >>${TMPFILE}
+        chown %{amanda_user}:%{amanda_group} %{LOCALSTATEDIR}/amanda/amandates >>${TMPFILE} 2>&1
+        chmod 0640 %{LOCALSTATEDIR}/amanda/amandates >>${TMPFILE} 2>&1
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: '%{LOCALSTATEDIR}/amanda/amandates' Installation successful." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+else
+        echo "`date +'%b %e %Y %T'`: '%{LOCALSTATEDIR}/amanda/amandates' Installation failed." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_ERR}
+fi
+
+# Install .amandahosts to client
+echo "`date +'%b %e %Y %T'`: Checking '%{AMANDAHOMEDIR}/.amandahosts' file." >${TMPFILE}
+if [ ! -f %{AMANDAHOMEDIR}/.amandahosts ] ; then
+        touch %{AMANDAHOMEDIR}/.amandahosts >>${TMPFILE} 2>&1
+fi
+for host in localhost localhost.localdomain ; do
+                if [ -z "`grep \"^${host}[[:blank:]]\+\" %{AMANDAHOMEDIR}/.amandahosts | grep \"[[:blank:]]\+%{amanda_user}[[:blank:]]\+amdump\"`" ] ; then
+                        echo "${host}   %{amanda_user} amdump" >>%{AMANDAHOMEDIR}/.amandahosts
+                fi
+done
+chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.amandahosts >>${TMPFILE} 2>&1
+chmod 0600 %{AMANDAHOMEDIR}/.amandahosts >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# Install amanda client configuration file
+echo "`date +'%b %e %Y %T'`: Checking '%{SYSCONFDIR}/amanda/amanda-client.conf' file." >${TMPFILE}
+if [ ! -f %{SYSCONFDIR}/amanda/amanda-client.conf ] ; then
+        cp %{AMANDAHOMEDIR}/example/amanda-client.conf %{SYSCONFDIR}/amanda/amanda-client.conf >>${TMPFILE} 2>&1
+fi
+chown %{amanda_user}:%{amanda_group} %{SYSCONFDIR}/amanda/amanda-client.conf >>${TMPFILE} 2>&1
+chmod 0600 %{SYSCONFDIR}/amanda/amanda-client.conf >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# Install .gnupg directory
+echo "`date +'%b %e %Y %T'`: Installing '%{AMANDAHOMEDIR}/.gnupg'." >${TMPFILE}
+ret_val=0
+if [ ! -d %{AMANDAHOMEDIR}/.gnupg ] ; then
+        echo "`date +'%b %e %Y %T'`: '%{AMANDAHOMEDIR}/.gnupg' will be created." >>${TMPFILE}
+        mkdir %{AMANDAHOMEDIR}/.gnupg >>${TMPFILE} 2>&1
+        ret_val=$?
+        if [ ${ret_val} -eq 0 ]; then
+                echo "`date +'%b %e %Y %T'`: The directory '%{AMANDAHOMEDIR}/.gnupg' created successfully." >>${TMPFILE}
+        else
+                echo "`date +'%b %e %Y %T'`: The directory '%{AMANDAHOMEDIR}/.gnupg' creation failed." >>${TMPFILE}
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: Ensuring correct permissions for '%{AMANDAHOMEDIR}/.gnupg'." >>${TMPFILE}
+        chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.gnupg >>${TMPFILE} 2>&1
+        ret_val=$?
+        if [ ${ret_val} -eq 0 ]; then
+                chmod 700 %{AMANDAHOMEDIR}/.gnupg >>${TMPFILE} 2>&1
+                ret_val=$?
+        fi
+fi
+if [ ${ret_val} -eq 0 ]; then
+        echo "`date +'%b %e %Y %T'`: '%{AMANDAHOMEDIR}/.gnupg' Installation successful." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+else
+        echo "`date +'%b %e %Y %T'`: '%{AMANDAHOMEDIR}/.gnupg' Installation failed." >>${TMPFILE}
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_ERR}
+fi
+
+# SSH RSA key generation on client for amrecover
+KEYDIR="%{AMANDAHOMEDIR}/.ssh"
+KEYFILE="id_rsa_amrecover"
+COMMENT="root@client"
+if [ ! -d ${KEYDIR} ] ; then
+        if [ -f ${KEYDIR} ] ; then
+                echo "`date +'%b %e %Y %T'`: Directory '${KEYDIR}' exists as a file.  Renaming to '${KEYDIR}.rpmsave'." >${TMPFILE}
+                mv ${KEYDIR} ${KEYDIR}.rpmsave >>${TMPFILE} 2>&1
+                cat ${TMPFILE}
+                cat ${TMPFILE} >>${INSTALL_LOG}
+        fi
+        echo "`date +'%b %e %Y %T'`: Creating directory '${KEYDIR}'." >${TMPFILE}
+        mkdir ${KEYDIR} >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+if [ ! -f ${KEYDIR}/${KEYFILE} ] ; then
+        echo "`date +'%b %e %Y %T'`: Creating ssh RSA key in '${KEYDIR}/${KEYFILE}'" >${TMPFILE}
+        ssh-keygen -q -C $COMMENT -t rsa -f ${KEYDIR}/${KEYFILE} -N '' >>${TMPFILE} 2>&1
+        cat ${TMPFILE}
+        cat ${TMPFILE} >>${INSTALL_LOG}
+fi
+echo "`date +'%b %e %Y %T'`: Setting permissions for '${KEYDIR}' and '${KEYDIR}/${KEYFILE}*'" >${TMPFILE}
+chown %{amanda_user}:%{amanda_group} ${KEYDIR} >>${TMPFILE} 2>&1
+chmod 0750 ${KEYDIR} >>${TMPFILE} 2>&1
+chmod 0600 ${KEYDIR}/${KEYFILE}* >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+# environment variables (~amandabackup/.profile)
+echo "`date +'%b %e %Y %T'`: Checking for '%{AMANDAHOMEDIR}/.profile' and ensuring correct environment." >${TMPFILE}
+if [ ! -f %{AMANDAHOMEDIR}/.profile ] ; then
+        touch %{AMANDAHOMEDIR}/.profile >>${TMPFILE} 2>&1
+fi
+if [ -z "`grep PATH %{AMANDAHOMEDIR}/.profile | grep '%{SBINDIR}'`" ] ; then
+        echo "export PATH=\"\$PATH:%{SBINDIR}\"" >>%{AMANDAHOMEDIR}/.profile 2>>${TMPFILE}
+fi
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+echo "`date +'%b %e %Y %T'`: Setting ownership and permissions for '%{AMANDAHOMEDIR}/.profile'" >${TMPFILE}
+chown %{amanda_user}:%{amanda_group} %{AMANDAHOMEDIR}/.profile >>${TMPFILE} 2>&1
+chmod 0640 %{AMANDAHOMEDIR}/.profile >>${TMPFILE} 2>&1
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+echo "`date +'%b %e %Y %T'`: Sending anonymous distribution and version information to Zmanda" >> ${INSTALL_LOG}
+if [ -x /usr/bin/wget ]; then 
+        /usr/bin/wget -q -o /dev/null -O - --timeout=5 http://www.zmanda.com/amanda-tips.php\?version=%{amanda_version}\&os=%{disttag}%{distver}\&type=client 
+fi
+
+echo "`date +'%b %e %Y %T'`: === Amanda backup client installation complete. ===" >>${TMPFILE}
+cat ${TMPFILE}
+cat ${TMPFILE} >>${INSTALL_LOG}
+
+if [ -f "${TMPFILE}" ]; then
+        rm -f "${TMPFILE}"
+fi
+
+echo "Amanda installation log can be found in '${INSTALL_LOG}' and errors (if any) in '${INSTALL_ERR}'."
+%postun backup_client
+/sbin/ldconfig
+
+# --- Files to install ---
+# Notes:  Do not use wildcards on directories not wholly owned by amanda.  An
+# uninstall of the software will attempt to delete whatever matches here.
+%files backup_client
+%defattr(0755,%{amanda_user},%{amanda_group})
+%{SYSCONFDIR}/amanda
+%{AMANDAHOMEDIR}
+%{AMLIBEXECDIR}
+%{AMLIBDIR}
+%{AMLIBEXECDIR}/amanda-sh-lib.sh
+%{LOCALSTATEDIR}/amanda
+%defattr(4750,root,disk)
+%{AMLIBEXECDIR}/calcsize
+%{AMLIBEXECDIR}/killpgrp
+%{AMLIBEXECDIR}/rundump
+%{AMLIBEXECDIR}/runtar
+%defattr(0750,%{amanda_user},%{amanda_group})
+%{LOGDIR}
+%{SBINDIR}/amaespipe
+%{SBINDIR}/amcryp*
+%{SBINDIR}/amgpgcrypt
+%{SBINDIR}/amoldrecover
+%{SBINDIR}/amrecover
+%defattr(0644,%{amanda_user},%{amanda_group})
+%docdir %{MANDIR}
+%{MANDIR}/man5/amanda.conf.5.gz
+%{MANDIR}/man5/amanda-client.conf.5.gz
+%{MANDIR}/man8/amanda.8.gz
+%{MANDIR}/man8/amcheckdump.8.gz
+%{MANDIR}/man8/amrecover.8.gz
+%{AMLIBEXECDIR}/amcat.awk
+%{AMANDAHOMEDIR}/amanda-release
+%{AMANDAHOMEDIR}/example/xinetd.amandaclient
+%{AMANDAHOMEDIR}/example/amanda-client.conf
+
+%files backup_server
+%defattr(0755,%{amanda_user},%{amanda_group})
+%{SYSCONFDIR}/amanda
+%{AMLIBEXECDIR}
+%{AMLIBDIR}
+%{PERLSITELIB}/Amanda
+%{PERLSITELIB}/auto/Amanda
+%{AMANDAHOMEDIR}
+%{LOCALSTATEDIR}/amanda
+%{SBINDIR}/amaddclient
+%{SBINDIR}/amadmin
+%{SBINDIR}/amcheckdb
+%{SBINDIR}/amcheckdump
+%{SBINDIR}/amcleanup
+%{SBINDIR}/amdd
+%{SBINDIR}/amdevcheck
+%{SBINDIR}/amdump
+%{SBINDIR}/amfetchdump
+%{SBINDIR}/amflush
+%{SBINDIR}/amgetconf
+%{SBINDIR}/amlabel
+%{SBINDIR}/ammt
+%{SBINDIR}/amoverview
+%{SBINDIR}/amplot
+%{SBINDIR}/amreport
+%{SBINDIR}/amrestore
+%{SBINDIR}/amrmtape
+%{SBINDIR}/amserverconfig
+%{SBINDIR}/amstatus
+%{SBINDIR}/amtape
+%{SBINDIR}/amtapetype
+%{SBINDIR}/amtoc
+%{SBINDIR}/amverify
+%{SBINDIR}/amverifyrun
+%{AMLIBEXECDIR}/amanda-sh-lib.sh
+%defattr(4750,root,disk)
+%{AMLIBEXECDIR}/calcsize
+%{AMLIBEXECDIR}/killpgrp
+%{AMLIBEXECDIR}/rundump
+%{AMLIBEXECDIR}/runtar
+%{AMLIBEXECDIR}/dumper
+%{AMLIBEXECDIR}/planner
+%{SBINDIR}/amcheck
+%defattr(0750,%{amanda_user},%{amanda_group})
+%{LOGDIR}
+%{SBINDIR}/amaespipe
+%{SBINDIR}/amcrypt
+%{SBINDIR}/amcrypt-ossl
+%{SBINDIR}/amcrypt-ossl-asym
+%{SBINDIR}/amcryptsimple
+%{SBINDIR}/amgpgcrypt
+%{SBINDIR}/amoldrecover
+%{SBINDIR}/amrecover
+%defattr(0644,%{amanda_user},%{amanda_group})
+%{AMLIBEXECDIR}/amcat.awk
+%{AMLIBEXECDIR}/amplot.awk
+%{AMLIBEXECDIR}/amplot.g
+%{AMLIBEXECDIR}/amplot.gp
+%docdir %{MANDIR}
+%{MANDIR}/man5/amanda.conf.5.gz
+%{MANDIR}/man5/amanda-client.conf.5.gz
+%{MANDIR}/man8/amaddclient.8.gz
+%{MANDIR}/man8/amadmin.8.gz
+%{MANDIR}/man8/amanda.8.gz
+%{MANDIR}/man8/amcheck.8.gz
+%{MANDIR}/man8/amcheckdb.8.gz
+%{MANDIR}/man8/amcheckdump.8.gz
+%{MANDIR}/man8/amcleanup.8.gz
+%{MANDIR}/man8/amdd.8.gz
+%{MANDIR}/man8/amdump.8.gz
+%{MANDIR}/man8/amfetchdump.8.gz
+%{MANDIR}/man8/amflush.8.gz
+%{MANDIR}/man8/amgetconf.8.gz
+%{MANDIR}/man8/amlabel.8.gz
+%{MANDIR}/man8/ammt.8.gz
+%{MANDIR}/man8/amoverview.8.gz
+%{MANDIR}/man8/amplot.8.gz
+%{MANDIR}/man8/amrecover.8.gz
+%{MANDIR}/man8/amreport.8.gz
+%{MANDIR}/man8/amrestore.8.gz
+%{MANDIR}/man8/amrmtape.8.gz
+%{MANDIR}/man8/amserverconfig.8.gz
+%{MANDIR}/man8/amstatus.8.gz
+%{MANDIR}/man8/amtape.8.gz
+%{MANDIR}/man8/amtapetype.8.gz
+%{MANDIR}/man8/amtoc.8.gz
+%{MANDIR}/man8/amverify.8.gz
+%{MANDIR}/man8/amverifyrun.8.gz
+%{MANDIR}/man8/amcrypt.8.gz
+%{MANDIR}/man8/amcrypt-ossl.8.gz
+%{MANDIR}/man8/amcrypt-ossl-asym.8.gz
+%{MANDIR}/man8/amcryptsimple.8.gz
+%{MANDIR}/man8/amgpgcrypt.8.gz
+%{MANDIR}/man8/amaespipe.8.gz
+%{MANDIR}/man8/amdevcheck.8.gz
+%{AMANDAHOMEDIR}/amanda-release
+%{AMANDAHOMEDIR}/example/amanda-client.conf
+%{AMANDAHOMEDIR}/example/xinetd.amandaserver
+
+# --- ChangeLog
+
+%changelog
+* Fri May 02 2008 Dan Locks <dwlocks at zmanda dot com>
+- Changed instances of ${ to %%{ where applicable
+* Tue Mar 11 2008 Dan Locks <dwlocks at zmanda dot com>
+- fixed many rpmlint complaints
+- added --quiet to configure statements
+- moved PERLSITELIB to definitions section
+* Wed Feb 13 2008 Dan Locks <dwlocks at zmanda dot com>
+- added an environment check for PKG_CONFIG_PATH
+- added PKG_CONFIG_PATH conditional to handle cross comp on FC8 (environment 
+  var is used if provided)
+* Fri Feb 01 2008 Dan Locks <dwlocks at zmanda dot com>
+- Removed amplot executable and manpages from client installation
+- Added amcheckdump.8 manpage
+- Fixed %%{LOCALSTATEDIR}/amanda dir creation.
+* Wed Jan 23 2008  Dan Locks <dwlocks at zmanda dot com>
+- Change %%{SYSCONFDIR}/amanda/amandates to %%{LOCALSTATEDIR}/amanda/amandates,
+  and added %%{LOCALSTATEDIR}/amanda to the files lists.
+* Mon Jan 14 2008  Dan Locks <dwlocks at zmanda dot com>
+- Updates for perlified amanda, file location moves, gpg setup.
+* Tue Nov  13 2007 Paddy Sreenivasan <paddy at zmanda dot com>
+- Added SYSCONFDIR to client rpm
+- Set xinetd and amanda-client.conf configuration files as part of postinstall
+* Thu Nov  8 2007 Dan Locks <dwlocks at zmanda dot com>
+- Added Linux distribution detection
+* Wed Nov 7 2007 Paddy Sreenivasan <paddy at zmanda dot com>
+- Added amserverconfig, amaddclient, amgpgcrypt, amcryptsimple and libamdevice.
+- Added amanda configuration template files
+* Fri Sep 21 2007 Paddy Sreenivasan <paddy at zmanda dot com>
+- Remove libamserver, libamtape from client rpm
+* Wed Sep 19 2007 Paddy Sreenivasan <paddy at zmanda dot com>
+- Added Fedora 7
+* Tue Jun 26 2007 Kevin Till <ktill at zmanda dot com>
+- set debug log to /var/log/amanda
+* Fri Jan 12 2007 Paddy Sreenivasan <paddy at zmanda dot com>
+- Added label templates
+* Thu Dec 07 2006 Paddy Sreenivasan <paddy at zmanda dot com>
+- Application API changes
+* Fri Jun 16 2006 Kevin Till <ktill at zmanda dot com>
+- make install will install necessary example files. 
+  No need to "cp"
+* Wed Jun 07 2006 Paddy Sreenivasan <paddy at zmanda dot com> -
+- Added amoldrecover and amanda-client.conf man page.
+* Thu Jun 01 2006 Kevin Till <ktill at zmanda dot com> -
+- Added amcrypt-ossl, amcrypt-ossl-asym by Ben Slusky.
+* Thu May 18 2006 Paddy Sreenivasan <paddy at zmanda dot com> -
+- Added SLES10, RHEL3 build options.
+* Tue May 09 2006 Chris Lee <cmlee at zmanda dot com> -
+- Added amanda-release file to amandabackup home directory.
+- Installation message logging cleanup.
+* Thu Apr 27 2006 Paddy Sreenivasan <paddy at zmanda dot com> -
+- Removed dependency on tar version.
+- Moved log directory creation after backup user creation.
+* Wed Apr 19 2006 Chris Lee <cmlee at zmanda dot com> -
+- Added informative message to note the location of pre- and post-
+- install script logs files.
+* Mon Apr 17 2006 Chris Lee <cmlee at zmanda dot com> -
+- Reworked installation message logging and reporting.
+* Fri Apr 14 2006 Chris Lee <cmlee at zmanda dot com> -
+- Changed behavior for creating required localhost entries in the
+- amandahosts file to check for these entries even when the file
+- already exists.
+* Wed Apr 12 2006 Chris Lee <cmlee at zmanda dot com> -
+- Removed pre-install check for "disk" group.  This group should exist
+- by default on almost all modern distributions.
+* Tue Apr 11 2006 Chris Lee <cmlee at zmanda dot com> -
+- Added amandahosts entry for "localhost" without domain.
+* Fri Apr 07 2006 Chris Lee <cmlee at zmanda dot com> -
+- Changed default entries in .amandahosts to use "localdomain" instead
+- of "localnet".
+- Updated amanda_version and release.
+* Mon Apr 03 2006 Chris Lee <cmlee at zmanda dot com> -
+- Added example amanda.conf to files.
+* Thu Mar 16 2006 Chris Lee <cmlee at zmanda dot com> -
+- Corrected an issue with pre-install scripts wrt bug #218.
+- Corrected an issue with post-install scripts and added testing .profile 
+- in amandabackup's home directory for setting environment variables wrt
+- bug #220.
+* Mon Mar 13 2006 Chris Lee <cmlee at zmanda dot com> -
+- Corrected a syntactical error with setting ownership of amandates file
+- wrt bug #216.
+* Wed Mar 08 2006 Chris Lee <cmlee at zmanda dot com> -
+- Added pre-install scripts to verify proper ownership of
+- amandabackup home directory.
+* Thu Feb 2 2006 Paddy Sreenivasan <paddy at zmanda dot com> -
+- Require xinetd. Require termcap and initscripts for Fedora and Redhat.
+* Mon Jan 09 2006 Chris Lee <cmlee at zmanda dot com> -
+- Pre/post install scripts updated:
+- o Resolved an issue where an empty amandates file was installed
+-   even if the file already existed on the system.
+- o If .amandahosts does not exist a default is now created.
+- The Amanda user account has been changed to 'amandabackup' for
+- additional security.
+* Tue Jan 03 2006 Paddy Sreenivasan <paddy at zmanda dot com> -
+- Removed amandates from files list.
+* Thu Dec 29 2005 Chris Lee <cmlee at zmanda dot com> -
+- Corrected dependency for awk to "/bin/awk".
+* Thu Dec 29 2005 Kevin Till <ktill at zmanda dot com> -
+- add man pages for amcrypt and amaespipe
+* Thu Dec 29 2005 Chris Lee <cmlee at zmanda dot com> -
+- Updated dependancy info to depend on tar >= 1.15.
+- Included dependancies from top-level package in backup_client and
+- backup_server packages.
+- Reorganized files lists for readability (alphabetically).
+- Updated backup_client files list to include some missing files per
+- bug #129.
+- Updated pre- and post-install to handle potential issue when
+- /var/log/amanda exists and is a file rather than a directory.
+- Corrected permissions for /var/log/amanda in pre-install scripts
+- per bug #78 and 13 December change.
+* Thu Dec 22 2005 Paddy Sreenivasan <paddy at zmanda dot com> -
+- Added amaespipe and amcrypt
+- Added sles9 build definitions
+* Tue Dec 13 2005 Chris Lee <cmlee at zmanda dot com> -
+- Changed permissions for /var/log/amanda, removing set group id bit.
+- Added /etc/amandates to backup_client package.
+* Thu Dec 08 2005 Chris Lee <cmlee at zmanda dot com> -
+- Corrected an issue with detection of existing 'amanda' user account.
+- Corrected ownership of setuid executables per Bug #66.
+- Moved the gnutar and noop files to the backup_client package (where
+- they sould be).
+- Removed amqde from files list.
+- Added logging features to pre- and post-install scripts.
+* Wed Dec 07 2005 Chris Lee <cmlee at zmanda dot com> -
+- Changed a number of directory and file permissions from amanda:root
+- to amanda:disk in response to Bug #57.
+* Fri Dec 02 2005 Chris Lee <cmlee at zmanda dot com> -
+- Corrected SYSCONFDIR path definition.  Closes Bug #58.
+* Mon Nov 28 2005 Chris Lee <cmlee at zmanda dot com> -
+- Really fixed user creation preinstall scripts.
+* Wed Nov 23 2005 Paddy Sreenivasan <paddy at zmanda dot com> -
+- Updated package description.
+- Changed Group for packages.
+* Tue Nov 22 2005 Chris Lee <cmlee at zmanda dot com> -
+- Corrected dependancy packaging issue with amanda libraries.
+- Fixed creation of amanda user on systems which it does not exist.
+- Corrected Group definition for SuSE.
+- Updated descriptions to include amanda-libs package.
+- Updated release number to 2.
+* Tue Nov 08 2005 Chris Lee <cmlee at zmanda dot com> -
+- Permissions changes: now using user=amanda, group=disk
+* Sun Oct 30 2005 Chris Lee <cmlee at zmanda dot com> -
+- Parameters to configure options --with-user and --with-group changed
+- such that when test_build is set to '1' the username of the user who
+- runs rpmbuild is used for both values.  If test_build is set to '0'
+- then root is used for both values.
+- The release field was also changed to automatically reflect the
+- distribution and distribution release version for which the RPM was
+- built.
+* Tue Oct 18 2005 Chris Lee <cmlee at zmanda dot com> - 
+- Initial RPM SPEC file created.
+
diff --git a/packaging/rpm/buildpkg b/packaging/rpm/buildpkg
new file mode 100755 (executable)
index 0000000..6361d14
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+# Buildpkg script for producing RPM packages. Does not require root access.
+
+# This is useful for debugging
+set -x
+# Buildbot exports some useful env variables.
+# Check for $AMVER.  I couldn't come up with a good way to detect it.
+if [ -z $AMVER ]; then
+    AMVER=amanda-2.6.0p2
+fi
+# Check for AMTARBALL variable.
+if [ -z $AMTARBALL ]; then 
+    AMTARBALL=$AMVER.tar.gz
+fi
+
+# Check for AMTARBALL file, if it's not there, create it.
+if [ ! -f ${AMTARBALL} ]; then
+    mkdir ${AMVER}
+    cp -Rfp * ${AMVER}/
+    tar -cf ${AMTARBALL} -z ${AMVER}
+    rm -rf ${AMVER}
+fi
+
+# Check for the packaging dirs.
+if [ -z $AMPKGDIR ]; then
+    AMPKGDIR=${PWD}
+fi
+if [ ! -d ${AMPKGDIR} ]; then
+    mkdir ${AMPKGDIR}
+fi
+cd ${AMPKGDIR}
+
+if [ -d rpm ]; then
+    rm -rf rpm
+fi
+mkdir rpm
+mkdir rpm/SOURCES
+mkdir rpm/SRPMS
+mkdir rpm/SPECS
+mkdir rpm/BUILD
+mkdir rpm/RPMS
+
+# Make a copy of the tarball with the name that rpmbuild expects
+cp ${AMTARBALL} rpm/SOURCES/${AMVER}.tar.gz
+cp packaging/rpm/amanda.spec rpm/SPECS/amanda.spec
+# Rpmbuild requires absolute paths.  annoying.  If you need to change the 
+# default value of some rpm.spec variable, just pass extra --define options.
+# this is useful for changing %amanda_release or %amanda_version
+rpmbuild -ba --define "_topdir ${AMPKGDIR}/rpm" \
+             ${AMPKGDIR}/rpm/SPECS/amanda.spec 
+cp rpm/RPMS/*/*.rpm . || exit 1
+cp rpm/SRPMS/*.rpm . || exit 1
diff --git a/perl/Amanda/Changer.pm b/perl/Amanda/Changer.pm
new file mode 100644 (file)
index 0000000..bfad1bf
--- /dev/null
@@ -0,0 +1,349 @@
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+package Amanda::Changer;
+
+use Carp;
+use POSIX ();
+use Exporter;
+@ISA = qw( Exporter );
+
+@EXPORT_OK = qw(
+    reset clean eject label
+    query loadslot find scan
+);
+
+use Amanda::Paths;
+use Amanda::Util;
+use Amanda::Device qw( :constants );
+use Amanda::Config qw( :getconf );
+
+=head1 NAME
+
+Amanda::Changer -- interface to changer scripts
+
+=head1 SYNOPSIS
+
+  use Amanda::Changer;
+
+  my ($error, $slot) = Amanda::Changer::reset();
+
+  my ($nslots, $curslot, $backwards, $searchable) = Amanda::Changer::query();
+
+  my ($tpslot, $tpdevice) = Amanda::Changer::find("TAPE018");
+
+  sub slot_callback {
+    my ($slot, $device, $error) = @_;
+    if (!$error) print "Slot $slot: $device\n";
+    return 0;
+  }
+  Amanda::Changer::scan(\&slot_callback);
+
+=head1 API STATUS
+
+Stable
+
+=head1 FUNCTIONS
+
+All of these functions return an array of values, beginning with
+C<$error>, and containing any other results appropriate to the
+operation.
+
+The functions C<croak()> in the event of a serious error (problems
+running the changer script, or an exit status of 2 or higher).
+"Benign" errors, corresponding to an exit status of 1 or a slot named
+"<error>", result in the return of a single-element array containing
+the error message.  Error-handling for calls can be written
+
+C<$error> and C<$slot>.  The first is false unless a "benign"
+error, such as a positioning error, has occurred, in which case it
+contains the message from the changer script, and the other results
+are undefined.  C<$slot> is the first word returned from the changer
+script, and is usually a number, but occasionally a string such as
+"<none>".
+
+=over
+
+=item reset
+
+  my ($error, $slot) = reset();
+
+Resets the tape changer, if supported, by calling
+
+  $tpchanger -reset
+
+=item clean
+
+  my ($error, $slot) = clean();
+
+Triggers a cleaning cycle, if supported, by calling
+
+  $tpchanger -clean
+
+=item eject
+
+  my ($error, $slot) = eject();
+
+Ejects the tape in the current slot, if supported, by calling
+
+  $tpchanger -eject
+
+=item label
+
+  my ($error) = label($label);
+
+Inform the changer that the tape in the current slot is labeled C<$label>.  Calls
+
+  $tpchanger -label $label
+
+=item query
+
+  my ($error, $slot, $nslots, $backwards, $searchable) = query();
+
+Query the changer to determine the current slot (C<$slot>), the
+number of slots (C<$nslots>), whether it can move backward through tapes
+(C<$backwards>), and whether it is searchable (that is, has a barcode
+reader; C<$searchable>).  A changer which cannot move backward through
+tapes is also known as a gravity feeder.
+
+This function runs
+
+  $tpchanger -info
+
+=item loadslot
+
+  my ($error, $slot, $device) = loadslot($desired_slot);
+
+Load the tape in the given slot, returning its slot and device.
+C<$desired_slot> can be a numeric slot number or one of the symbolic
+names defined by the changer API, e.g., "next", "current", or "first".
+
+  $tpchanger -slot $slot
+
+=item find
+
+  my ($error, $tpslot, $tpdevice) = Amanda::Changer::find($label);
+
+Search the changer for a tape with the given label, returning with
+C<$tpslot = "<none>"> if the given label is not found.
+
+If the changer is searchable, this function calls
+
+  $tpchanger -search $label
+
+Otherwise it scans all slots in order, beginning with the current slot,
+until it finds one with a label equal to C<$label> or exhausts all
+slots.  Note that it is considered a fatal error if the label is not
+found.
+
+=item scan
+
+  my ($error) = Amanda::Changer::scan(\&slot_callback);
+
+Call C<slot_callback> for all slots, beginning with the current slot,
+until C<slot_callback> returns a nonzero value or all slots are
+exhausted.  C<slot_callback> gets three arguments: a slot number, a
+device name for that slot, and a boolean value which is true if the
+changer successfully loaded the slot.
+
+=back
+
+=cut
+
+sub reset {
+    my ($error, $slot, $rest) = run_tpchanger("-reset");
+    return ($error) if $error;
+
+    return (0, $slot);
+}
+
+sub clean {
+    my ($error, $slot, $rest) = run_tpchanger("-clean");
+    return ($error) if $error;
+
+    return (0, $slot);
+}
+
+sub eject {
+    my ($error, $slot, $rest) = run_tpchanger("-eject");
+    return ($error) if $error;
+
+    return (0, $slot);
+}
+
+sub label {
+    my ($label) = @_;
+
+    my ($error, $slot, $rest) = run_tpchanger("-label", $label);
+    return ($error) if $error;
+
+    return (0);
+}
+
+sub query {
+    my ($error, $slot, $rest) = run_tpchanger("-info");
+    return ($error) if $error;
+
+    # old, unsearchable changers don't return the third result, so it's optional in the regex
+    $rest =~ /(\d+) (\d+) ?(\d+)?/ or croak("Malformed response from changer -seek: $rest");
+
+    # return array: error, nslots, curslot, backwards, searchable
+    return (0, $slot, $1, $2, $3?1:0);
+}
+
+sub loadslot {
+    my ($desired_slot) = @_;
+
+    my ($error, $slot, $rest) = run_tpchanger("-slot", $desired_slot);
+    return ($error) if $error;
+
+    return (0, $slot, $rest);
+}
+
+sub find {
+    my ($label) = @_;
+
+    my ($error, $curslot, $nslots, $backwards, $searchable) = query();
+    return ($error) if $error;
+
+    if ($searchable) {
+        # search using the barcode reader, etc.
+        my ($error, $slot, $rest) = run_tpchanger("-search", $label);
+        return ($error) if $error;
+        return ($error, $slot, $rest);
+    } else {
+        # search manually, starting with "current"
+        my $slotstr = "current";
+        for (my $checked = 0; $checked < $nslots; $checked++) {
+            my ($error, $slot, $rest) = run_tpchanger("-slot", $slotstr);
+            $slotstr = "next";
+
+            # ignore "benign" errors
+            next if $error;
+
+            my $device = Amanda::Device->new($rest);
+            next if (!$device);
+            next if ($device->read_label() != $READ_LABEL_STATUS_SUCESS);
+
+            # we found it!
+            if ($device->{'volume_label'} eq $label) {
+                return (0, $slot, $rest);
+            }
+        }
+
+        croak("Label $label not found in any slot");
+    }
+}
+
+sub scan {
+    my ($slot_callback) = @_;
+
+    my ($error, $curslot, $nslots, $backwards, $searchable) = query();
+    return ($error) if $error;
+
+    my $slotstr = "current";
+    my $done = 0;
+    for (my $checked = 0; $checked < $nslots; $checked++) {
+        my ($error, $slot, $rest) = run_tpchanger("-slot", $slotstr);
+        $slotstr = "next";
+
+        if ($error) {
+            $done = $slot_callback->(undef, undef, $error);
+        } else {
+            $done = $slot_callback->($slot, $rest, 0);
+        }
+
+        last if $done;
+    }
+    
+    return (0);
+}
+
+# Internal-use function to actually invoke a changer script and parse 
+# its output.  If the script's exit status is neither 0 nor 1, or if an error
+# occurs running the script, then run_tpchanger croaks with the error message.
+#
+# @params @args: command-line arguments to follow the name of the changer
+# @returns: array ($error, $slot, $rest), where $error is an error message if
+#       a benign error occurred, or 0 if no error occurred
+sub run_tpchanger {
+    my @args = @_;
+
+    # get the tape changer and extend it to a full path
+    my $tapechanger = getconf($CNF_TPCHANGER);
+    if ($tapechanger !~ qr(^/)) {
+        $tapechanger = "$amlibexecdir/$tapechanger";
+    }
+
+    my $pid = open(my $child, "-|");
+    if (!defined($pid)) {
+        croak("Can't fork to run changer script: $!");
+    }
+
+    if (!$pid) {
+        # child
+
+        # cd into the config dir, if one exists
+        # TODO: construct a "fake" config dir including any "-o" overrides
+        my $config_dir = Amanda::Config::get_config_dir();
+        if ($config_dir) {
+            if (!chdir($config_dir)) {
+                print "<error> Could not chdir to '$config_dir'\n";
+                exit(2);
+            }
+        }
+
+        %ENV = Amanda::Util::safe_env();
+
+        exec { $tapechanger } $tapechanger, @args or
+            print "<error> Could not exec $tapechanger: $!\n";
+        exit 2;
+    }
+
+    # parent
+    my @child_output = <$child>;
+
+    # close the child and get its exit status
+    my $child_exit = 0;
+    if (!close($child)) {
+        if ($!) {
+            croak("Error running changer script: $!");
+        } else {
+            $child_exit = $?;
+        }
+    }
+
+    # parse the response
+    croak("Malformed output from changer script -- no output")
+        if (@child_output < 1);
+    croak("Malformed output from changer script -- too many lines")
+        if (@child_output > 1);
+    croak("Malformed output from changer script: '$child_output[0]'")
+        if ($child_output[0] !~ /\s*([^\s]+)\s+(.+)?/);
+    my ($slot, $rest) = ($1, $2);
+
+    if ($child_exit == 0) {
+        return (0, $slot, $rest);
+    } elsif (POSIX::WIFEXITED($child_exit) && POSIX::WEXITSTATUS($child_exit) == 1) {
+        return ($rest); # non-fatal error
+    } else {
+        croak("Fatal error from changer script: $rest");
+    }
+}
+
+1;
diff --git a/perl/Amanda/Cmdline.c b/perl/Amanda/Cmdline.c
new file mode 100644 (file)
index 0000000..d23c52a
--- /dev/null
@@ -0,0 +1,2478 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.33
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPERL
+#define SWIG_CASTRANK_MODE
+/* -----------------------------------------------------------------------------
+ *  This section contains generic SWIG labels for method/variable
+ *  declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+#  define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+#   define SWIGINLINE inline
+# else
+#   define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define SWIGUNUSED __attribute__ ((__unused__)) 
+#   else
+#     define SWIGUNUSED
+#   endif
+# elif defined(__ICC)
+#   define SWIGUNUSED __attribute__ ((__unused__)) 
+# else
+#   define SWIGUNUSED 
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+#   define SWIGUNUSEDPARM(p)
+# else
+#   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#  ifndef GCC_HASCLASSVISIBILITY
+#    define GCC_HASCLASSVISIBILITY
+#  endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   if defined(STATIC_LINKED)
+#     define SWIGEXPORT
+#   else
+#     define SWIGEXPORT __declspec(dllexport)
+#   endif
+# else
+#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+#     define SWIGEXPORT __attribute__ ((visibility("default")))
+#   else
+#     define SWIGEXPORT
+#   endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   define SWIGSTDCALL __stdcall
+# else
+#   define SWIGSTDCALL
+# endif 
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+   or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "3"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+  You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+  creating a static or dynamic library from the swig runtime code.
+  In 99.9% of the cases, swig just needs to declare them as 'static'.
+  
+  But only do this if is strictly necessary, ie, if you have problems
+  with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/*  Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN        0x1
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN           0x1
+
+
+/* 
+   Flags/methods for returning states.
+   
+   The swig conversion methods, as ConvertPtr, return and integer 
+   that tells if the conversion was successful or not. And if not,
+   an error code can be returned (see swigerrors.swg for the codes).
+   
+   Use the following macros/flags to set or process the returning
+   states.
+   
+   In old swig versions, you usually write code as:
+
+     if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+       // success code
+     } else {
+       //fail code
+     }
+
+   Now you can be more explicit as:
+
+    int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+    } else {
+      // fail code
+    }
+
+   that seems to be the same, but now you can also do
+
+    Type *ptr;
+    int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+      if (SWIG_IsNewObj(res) {
+        ...
+       delete *ptr;
+      } else {
+        ...
+      }
+    } else {
+      // fail code
+    }
+    
+   I.e., now SWIG_ConvertPtr can return new objects and you can
+   identify the case and take care of the deallocation. Of course that
+   requires also to SWIG_ConvertPtr to return new result values, as
+
+      int SWIG_ConvertPtr(obj, ptr,...) {         
+        if (<obj is ok>) {                            
+          if (<need new object>) {                    
+            *ptr = <ptr to new allocated object>; 
+            return SWIG_NEWOBJ;                       
+          } else {                                    
+            *ptr = <ptr to old object>;               
+            return SWIG_OLDOBJ;                       
+          }                                   
+        } else {                                      
+          return SWIG_BADOBJ;                 
+        }                                             
+      }
+
+   Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+   more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+   swig errors code.
+
+   Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+   allows to return the 'cast rank', for example, if you have this
+
+       int food(double)
+       int fooi(int);
+
+   and you call
+      food(1)   // cast rank '1'  (1 -> 1.0)
+      fooi(1)   // cast rank '0'
+
+   just use the SWIG_AddCast()/SWIG_CheckState()
+
+
+ */
+#define SWIG_OK                    (0) 
+#define SWIG_ERROR                 (-1)
+#define SWIG_IsOK(r)               (r >= 0)
+#define SWIG_ArgError(r)           ((r != SWIG_ERROR) ? r : SWIG_TypeError)  
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT         (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK            (SWIG_CASTRANKLIMIT  << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK            (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ                (SWIG_ERROR)
+#define SWIG_OLDOBJ                (SWIG_OK)
+#define SWIG_NEWOBJ                (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ                (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r)         (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r)           (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r)         (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r)           (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+#  ifndef SWIG_TypeRank
+#    define SWIG_TypeRank             unsigned long
+#  endif
+#  ifndef SWIG_MAXCASTRANK            /* Default cast allowed */
+#    define SWIG_MAXCASTRANK          (2)
+#  endif
+#  define SWIG_CASTRANKMASK          ((SWIG_CASTRANKLIMIT) -1)
+#  define SWIG_CastRank(r)           (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) { 
+  return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) { 
+  return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; 
+}
+#else /* no cast-rank mode */
+#  define SWIG_AddCast
+#  define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store inforomation on one type */
+typedef struct swig_type_info {
+  const char             *name;                        /* mangled name of this type */
+  const char             *str;                 /* human readable name of this type */
+  swig_dycast_func        dcast;               /* dynamic cast function down a hierarchy */
+  struct swig_cast_info  *cast;                        /* linked list of types that can cast into this type */
+  void                   *clientdata;          /* language specific type data */
+  int                    owndata;              /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+  swig_type_info         *type;                        /* pointer to type that is equivalent to this type */
+  swig_converter_func     converter;           /* function to cast the void pointers */
+  struct swig_cast_info  *next;                        /* pointer to next cast in linked list */
+  struct swig_cast_info  *prev;                        /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+  swig_type_info         **types;              /* Array of pointers to swig_type_info structures that are in this module */
+  size_t                 size;                 /* Number of types in this module */
+  struct swig_module_info *next;               /* Pointer to next element in circularly linked list */
+  swig_type_info         **type_initial;       /* Array of initially generated type structures */
+  swig_cast_info         **cast_initial;       /* Array of initially generated casting structures */
+  void                    *clientdata;         /* Language specific module data */
+} swig_module_info;
+
+/* 
+  Compare two type names skipping the space characters, therefore
+  "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+  Return 0 when the two name types are equivalent, as in
+  strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+                 const char *f2, const char *l2) {
+  for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+    while ((*f1 == ' ') && (f1 != l1)) ++f1;
+    while ((*f2 == ' ') && (f2 != l2)) ++f2;
+    if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+  }
+  return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty)         \
+  if (ty) {                                             \
+    swig_cast_info *iter = ty->cast;                    \
+    while (iter) {                                      \
+      if (comparison) {                                 \
+        if (iter == ty->cast) return iter;              \
+        /* Move iter to the top of the linked list */   \
+        iter->prev->next = iter->next;                  \
+        if (iter->next)                                 \
+          iter->next->prev = iter->prev;                \
+        iter->next = ty->cast;                          \
+        iter->prev = 0;                                 \
+        if (ty->cast) ty->cast->prev = iter;            \
+        ty->cast = iter;                                \
+        return iter;                                    \
+      }                                                 \
+      iter = iter->next;                                \
+    }                                                   \
+  }                                                     \
+  return 0
+
+/*
+  Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+  SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+  Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr) {
+  return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/* 
+   Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/*
+  Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/*
+  Return the pretty name associated with this type,
+  that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+  /* The "str" field contains the equivalent pretty names of the
+     type, separated by vertical-bar characters.  We choose
+     to print the last name, as it is often (?) the most
+     specific. */
+  if (!type) return NULL;
+  if (type->str != NULL) {
+    const char *last_name = type->str;
+    const char *s;
+    for (s = type->str; *s; s++)
+      if (*s == '|') last_name = s+1;
+    return last_name;
+  }
+  else
+    return type->name;
+}
+
+/* 
+   Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  swig_cast_info *cast = ti->cast;
+  /* if (ti->clientdata == clientdata) return; */
+  ti->clientdata = clientdata;
+  
+  while (cast) {
+    if (!cast->converter) {
+      swig_type_info *tc = cast->type;
+      if (!tc->clientdata) {
+       SWIG_TypeClientData(tc, clientdata);
+      }
+    }    
+    cast = cast->next;
+  }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+  SWIG_TypeClientData(ti, clientdata);
+  ti->owndata = 1;
+}
+  
+/*
+  Search for a swig_type_info structure only by mangled name
+  Search is a O(log #types)
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start, 
+                            swig_module_info *end, 
+                           const char *name) {
+  swig_module_info *iter = start;
+  do {
+    if (iter->size) {
+      register size_t l = 0;
+      register size_t r = iter->size - 1;
+      do {
+       /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+       register size_t i = (l + r) >> 1; 
+       const char *iname = iter->types[i]->name;
+       if (iname) {
+         register int compare = strcmp(name, iname);
+         if (compare == 0) {       
+           return iter->types[i];
+         } else if (compare < 0) {
+           if (i) {
+             r = i - 1;
+           } else {
+             break;
+           }
+         } else if (compare > 0) {
+           l = i + 1;
+         }
+       } else {
+         break; /* should never happen */
+       }
+      } while (l <= r);
+    }
+    iter = iter->next;
+  } while (iter != end);
+  return 0;
+}
+
+/*
+  Search for a swig_type_info structure for either a mangled name or a human readable name.
+  It first searches the mangled names of the types, which is a O(log #types)
+  If a type is not found it then searches the human readable names, which is O(#types).
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start, 
+                     swig_module_info *end, 
+                    const char *name) {
+  /* STEP 1: Search the name field using binary search */
+  swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+  if (ret) {
+    return ret;
+  } else {
+    /* STEP 2: If the type hasn't been found, do a complete search
+       of the str field (the human readable name) */
+    swig_module_info *iter = start;
+    do {
+      register size_t i = 0;
+      for (; i < iter->size; ++i) {
+       if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+         return iter->types[i];
+      }
+      iter = iter->next;
+    } while (iter != end);
+  }
+  
+  /* neither found a match */
+  return 0;
+}
+
+/* 
+   Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+  static const char hex[17] = "0123456789abcdef";
+  register const unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu =  u + sz;
+  for (; u != eu; ++u) {
+    register unsigned char uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* 
+   Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+  register unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu = u + sz;
+  for (; u != eu; ++u) {
+    register char d = *(c++);
+    register unsigned char uu;
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    else 
+      return (char *) 0;
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    else 
+      return (char *) 0;
+    *u = uu;
+  }
+  return c;
+}
+
+/* 
+   Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+  char *r = buff;
+  if ((2*sizeof(void *) + 2) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,&ptr,sizeof(void *));
+  if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+  strcpy(r,name);
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      *ptr = (void *) 0;
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+  char *r = buff;
+  size_t lname = (name ? strlen(name) : 0);
+  if ((2*sz + 2 + lname) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  if (lname) {
+    strncpy(r,name,lname+1);
+  } else {
+    *r = 0;
+  }
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      memset(ptr,0,sz);
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*  Errors in SWIG */
+#define  SWIG_UnknownError        -1 
+#define  SWIG_IOError             -2 
+#define  SWIG_RuntimeError        -3 
+#define  SWIG_IndexError          -4 
+#define  SWIG_TypeError           -5 
+#define  SWIG_DivisionByZero      -6 
+#define  SWIG_OverflowError       -7 
+#define  SWIG_SyntaxError         -8 
+#define  SWIG_ValueError          -9 
+#define  SWIG_SystemError         -10
+#define  SWIG_AttributeError      -11
+#define  SWIG_MemoryError         -12 
+#define  SWIG_NullReferenceError   -13
+
+
+
+#ifdef __cplusplus
+/* Needed on some windows machines---since MS plays funny games with the header files under C++ */
+#include <math.h>
+#include <stdlib.h>
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* Add in functionality missing in older versions of Perl. Much of this is based on Devel-PPPort on cpan. */
+
+/* Add PERL_REVISION, PERL_VERSION, PERL_SUBVERSION if missing */
+#ifndef PERL_REVISION
+#  if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+#    define PERL_PATCHLEVEL_H_IMPLICIT
+#    include <patchlevel.h>
+#  endif
+#  if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+#    include <could_not_find_Perl_patchlevel.h>
+#  endif
+#  ifndef PERL_REVISION
+#    define PERL_REVISION       (5)
+#    define PERL_VERSION        PATCHLEVEL
+#    define PERL_SUBVERSION     SUBVERSION
+#  endif
+#endif
+
+#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE)
+#define PerlIO_exportFILE(fh,fl) (FILE*)(fh)
+#endif
+
+#ifndef SvIOK_UV
+# define SvIOK_UV(sv)       (SvIOK(sv) && (SvUVX(sv) == SvIVX(sv)))
+#endif
+
+#ifndef SvUOK
+# define SvUOK(sv)           SvIOK_UV(sv)
+#endif
+
+#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5)))
+#  define PL_sv_undef               sv_undef
+#  define PL_na                            na
+#  define PL_errgv                  errgv
+#  define PL_sv_no                  sv_no
+#  define PL_sv_yes                 sv_yes
+#  define PL_markstack_ptr          markstack_ptr
+#endif
+
+#ifndef IVSIZE
+#  ifdef LONGSIZE
+#    define IVSIZE LONGSIZE
+#  else
+#    define IVSIZE 4 /* A bold guess, but the best we can make. */
+#  endif
+#endif
+
+#ifndef INT2PTR
+#  if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#    define PTRV                  UV
+#    define INT2PTR(any,d)        (any)(d)
+#  else
+#    if PTRSIZE == LONGSIZE
+#      define PTRV                unsigned long
+#    else
+#      define PTRV                unsigned
+#    endif
+#    define INT2PTR(any,d)        (any)(PTRV)(d)
+#  endif
+
+#  define NUM2PTR(any,d)  (any)(PTRV)(d)
+#  define PTR2IV(p)       INT2PTR(IV,p)
+#  define PTR2UV(p)       INT2PTR(UV,p)
+#  define PTR2NV(p)       NUM2PTR(NV,p)
+
+#  if PTRSIZE == LONGSIZE
+#    define PTR2ul(p)     (unsigned long)(p)
+#  else
+#    define PTR2ul(p)     INT2PTR(unsigned long,p)
+#  endif
+#endif /* !INT2PTR */
+
+#ifndef SvPV_nolen
+# define SvPV_nolen(x) SvPV(x,PL_na)
+#endif
+
+#ifndef get_sv
+#  define get_sv perl_get_sv
+#endif
+
+#ifndef ERRSV
+#  define ERRSV get_sv("@",FALSE)
+#endif
+
+#ifndef pTHX_
+#define pTHX_
+#endif   
+
+#include <string.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGINTERN const char*
+SWIG_Perl_ErrorType(int code) {
+  const char* type = 0;
+  switch(code) {
+  case SWIG_MemoryError:
+    type = "MemoryError";
+    break;
+  case SWIG_IOError:
+    type = "IOError";
+    break;
+  case SWIG_RuntimeError:
+    type = "RuntimeError";
+    break;
+  case SWIG_IndexError:
+    type = "IndexError";
+    break;
+  case SWIG_TypeError:
+    type = "TypeError";
+    break;
+  case SWIG_DivisionByZero:
+    type = "ZeroDivisionError";
+    break;
+  case SWIG_OverflowError:
+    type = "OverflowError";
+    break;
+  case SWIG_SyntaxError:
+    type = "SyntaxError";
+    break;
+  case SWIG_ValueError:
+    type = "ValueError";
+    break;
+  case SWIG_SystemError:
+    type = "SystemError";
+    break;
+  case SWIG_AttributeError:
+    type = "AttributeError";
+    break;
+  default:
+    type = "RuntimeError";
+  }
+  return type;
+}
+
+
+
+
+/* -----------------------------------------------------------------------------
+ * perlrun.swg
+ *
+ * This file contains the runtime support for Perl modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef PERL_OBJECT
+#define SWIG_PERL_OBJECT_DECL CPerlObj *SWIGUNUSEDPARM(pPerl),
+#define SWIG_PERL_OBJECT_CALL pPerl,
+#else
+#define SWIG_PERL_OBJECT_DECL
+#define SWIG_PERL_OBJECT_CALL
+#endif
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_ConvertPtr(obj, pp, type, flags)           SWIG_Perl_ConvertPtr(SWIG_PERL_OBJECT_CALL obj, pp, type, flags)
+#define SWIG_NewPointerObj(p, type, flags)              SWIG_Perl_NewPointerObj(SWIG_PERL_OBJECT_CALL p, type, flags)
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, p, s, type)             SWIG_Perl_ConvertPacked(SWIG_PERL_OBJECT_CALL obj, p, s, type)
+#define SWIG_NewPackedObj(p, s, type)                  SWIG_Perl_NewPackedObj(SWIG_PERL_OBJECT_CALL p, s, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags)    SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags)           SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type)        SWIG_ConvertPtr(obj, pptr, type, 0)
+#define SWIG_NewFunctionPtrObj(ptr, type)               SWIG_NewPointerObj(ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty)            SWIG_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type)                SWIG_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata)                      SWIG_Perl_GetModule()
+#define SWIG_SetModule(clientdata, pointer)             SWIG_Perl_SetModule(pointer)
+
+
+/* Error manipulation */
+
+#define SWIG_ErrorType(code)                            SWIG_Perl_ErrorType(code)               
+#define SWIG_Error(code, msg)                          sv_setpvf(GvSV(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg)
+#define SWIG_fail                                      goto fail                                                   
+
+/* Perl-specific SWIG API */
+
+#define SWIG_MakePtr(sv, ptr, type, flags)              SWIG_Perl_MakePtr(SWIG_PERL_OBJECT_CALL sv, ptr, type, flags)
+#define SWIG_MakePackedObj(sv, p, s, type)             SWIG_Perl_MakePackedObj(SWIG_PERL_OBJECT_CALL sv, p, s, type)
+#define SWIG_SetError(str)                              SWIG_Error(SWIG_RuntimeError, str)
+
+
+#define SWIG_PERL_DECL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_DECL arg1)
+#define SWIG_PERL_CALL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_CALL arg1)
+#define SWIG_PERL_DECL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_DECL arg1, arg2)
+#define SWIG_PERL_CALL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_CALL arg1, arg2)
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+/* For backward compatibility only */
+#define SWIG_POINTER_EXCEPTION  0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_OWNER   SWIG_POINTER_OWN
+#define SWIG_SHADOW  SWIG_OWNER << 1
+
+#define SWIG_MAYBE_PERL_OBJECT SWIG_PERL_OBJECT_DECL
+
+/* SWIG Perl macros */
+
+/* Macro to declare an XS function */
+#ifndef XSPROTO
+#   define XSPROTO(name) void name(pTHX_ CV* cv)
+#endif
+
+/* Macro to call an XS function */
+#ifdef PERL_OBJECT 
+#  define SWIG_CALLXS(_name) _name(cv,pPerl) 
+#else 
+#  ifndef MULTIPLICITY 
+#    define SWIG_CALLXS(_name) _name(cv) 
+#  else 
+#    define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) 
+#  endif 
+#endif 
+
+#ifdef PERL_OBJECT
+#define MAGIC_PPERL  CPerlObj *pPerl = (CPerlObj *) this;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+#define SWIGCLASS_STATIC
+
+#else /* PERL_OBJECT */
+
+#define MAGIC_PPERL
+#define SWIGCLASS_STATIC static SWIGUNUSED
+
+#ifndef MULTIPLICITY
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MULTIPLICITY */
+
+#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MULTIPLICITY */
+#endif /* PERL_OBJECT */
+
+/* Workaround for bug in perl 5.6.x croak and earlier */
+#if (PERL_VERSION < 8)
+#  ifdef PERL_OBJECT
+#    define SWIG_croak_null() SWIG_Perl_croak_null(pPerl)
+static void SWIG_Perl_croak_null(CPerlObj *pPerl)
+#  else
+static void SWIG_croak_null()
+#  endif
+{
+  SV *err=ERRSV;
+#  if (PERL_VERSION < 6)
+  croak("%_", err);
+#  else
+  if (SvOK(err) && !SvROK(err)) croak("%_", err);
+  croak(Nullch);
+#  endif
+}
+#else
+#  define SWIG_croak_null() croak(Nullch)
+#endif
+
+
+/* 
+   Define how strict is the cast between strings and integers/doubles
+   when overloading between these types occurs.
+   
+   The default is making it as strict as possible by using SWIG_AddCast
+   when needed.
+   
+   You can use -DSWIG_PERL_NO_STRICT_STR2NUM at compilation time to
+   disable the SWIG_AddCast, making the casting between string and
+   numbers less strict.
+
+   In the end, we try to solve the overloading between strings and
+   numerical types in the more natural way, but if you can avoid it,
+   well, avoid it using %rename, for example.
+*/
+#ifndef SWIG_PERL_NO_STRICT_STR2NUM
+# ifndef SWIG_PERL_STRICT_STR2NUM
+#  define SWIG_PERL_STRICT_STR2NUM
+# endif
+#endif
+#ifdef SWIG_PERL_STRICT_STR2NUM
+/* string takes precedence */
+#define SWIG_Str2NumCast(x) SWIG_AddCast(x)  
+#else
+/* number takes precedence */
+#define SWIG_Str2NumCast(x) x
+#endif
+
+
+
+#include <stdlib.h>
+
+SWIGRUNTIME const char *
+SWIG_Perl_TypeProxyName(const swig_type_info *type) {
+  if (!type) return NULL;
+  if (type->clientdata != NULL) {
+    return (const char*) type->clientdata;
+  } 
+  else {
+    return type->name;
+  }
+}
+
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeProxyCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(( (!iter->type->clientdata && (strcmp((char*)iter->type->name, c) == 0)) 
+                           || (iter->type->clientdata && (strcmp((char*)iter->type->clientdata, c) == 0))), ty);
+}
+
+
+/* Function for getting a pointer value */
+
+SWIGRUNTIME int
+SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) {
+  swig_cast_info *tc;
+  void *voidptr = (void *)0;
+  SV *tsv = 0;
+  /* If magical, apply more magic */
+  if (SvGMAGICAL(sv))
+    mg_get(sv);
+
+  /* Check to see if this is an object */
+  if (sv_isobject(sv)) {
+    IV tmp = 0;
+    tsv = (SV*) SvRV(sv);
+    if ((SvTYPE(tsv) == SVt_PVHV)) {
+      MAGIC *mg;
+      if (SvMAGICAL(tsv)) {
+        mg = mg_find(tsv,'P');
+        if (mg) {
+          sv = mg->mg_obj;
+          if (sv_isobject(sv)) {
+           tsv = (SV*)SvRV(sv);
+            tmp = SvIV(tsv);
+          }
+        }
+      } else {
+        return SWIG_ERROR;
+      }
+    } else {
+      tmp = SvIV(tsv);
+    }
+    voidptr = INT2PTR(void *,tmp);
+  } else if (! SvOK(sv)) {            /* Check for undef */
+    *(ptr) = (void *) 0;
+    return SWIG_OK;
+  } else if (SvTYPE(sv) == SVt_RV) {  /* Check for NULL pointer */
+    if (!SvROK(sv)) {
+      *(ptr) = (void *) 0;
+      return SWIG_OK;
+    } else {
+      return SWIG_ERROR;
+    }
+  } else {                            /* Don't know what it is */
+    return SWIG_ERROR;
+  }
+  if (_t) {
+    /* Now see if the types match */
+    char *_c = HvNAME(SvSTASH(SvRV(sv)));
+    tc = SWIG_TypeProxyCheck(_c,_t);
+    if (!tc) {
+      return SWIG_ERROR;
+    }
+    *ptr = SWIG_TypeCast(tc,voidptr);
+  } else {
+    *ptr = voidptr;
+  }
+
+  /* 
+   *  DISOWN implementation: we need a perl guru to check this one.
+   */
+  if (tsv && (flags & SWIG_POINTER_DISOWN)) {
+    /* 
+     *  almost copy paste code from below SWIG_POINTER_OWN setting
+     */
+    SV *obj = sv;
+    HV *stash = SvSTASH(SvRV(obj));
+    GV *gv = *(GV**) hv_fetch(stash, "OWNER", 5, TRUE);
+    if (isGV(gv)) {
+      HV *hv = GvHVn(gv);
+      /*
+       * To set ownership (see below), a newSViv(1) entry is added. 
+       * Hence, to remove ownership, we delete the entry.
+       */
+      if (hv_exists_ent(hv, obj, 0)) {
+       hv_delete_ent(hv, obj, 0, 0);
+      }
+    }
+  }
+  return SWIG_OK;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) {
+  if (ptr && (flags & SWIG_SHADOW)) {
+    SV *self;
+    SV *obj=newSV(0);
+    HV *hash=newHV();
+    HV *stash;
+    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+    stash=SvSTASH(SvRV(obj));
+    if (flags & SWIG_POINTER_OWN) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+      if (!isGV(gv))
+        gv_init(gv, stash, "OWNER", 5, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newSViv(1), 0);
+    }
+    sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0);
+    SvREFCNT_dec(obj);
+    self=newRV_noinc((SV *)hash);
+    sv_setsv(sv, self);
+    SvREFCNT_dec((SV *)self);
+    sv_bless(sv, stash);
+  }
+  else {
+    sv_setref_pv(sv, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+  }
+}
+
+SWIGRUNTIMEINLINE SV *
+SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+  SV *result = sv_newmortal();
+  SWIG_MakePtr(result, ptr, t, flags);
+  return result;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) {
+  char result[1024];
+  char *r = result;
+  if ((2*sz + 1 + strlen(SWIG_Perl_TypeProxyName(type))) > 1000) return;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  strcpy(r,SWIG_Perl_TypeProxyName(type));
+  sv_setpv(sv, result);
+}
+
+SWIGRUNTIME SV *
+SWIG_Perl_NewPackedObj(SWIG_MAYBE_PERL_OBJECT void *ptr, int sz, swig_type_info *type) {
+  SV *result = sv_newmortal();
+  SWIG_Perl_MakePackedObj(result, ptr, sz, type);
+  return result;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME int
+SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty) {
+  swig_cast_info *tc;
+  const char  *c = 0;
+
+  if ((!obj) || (!SvOK(obj))) return SWIG_ERROR;
+  c = SvPV_nolen(obj);
+  /* Pointer values must start with leading underscore */
+  if (*c != '_') return SWIG_ERROR;
+  c++;
+  c = SWIG_UnpackData(c,ptr,sz);
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) return SWIG_ERROR;
+  }
+  return SWIG_OK;
+}
+
+
+/* Macros for low-level exception handling */
+#define SWIG_croak(x)    { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail; }
+
+
+typedef XSPROTO(SwigPerlWrapper);
+typedef SwigPerlWrapper *SwigPerlWrapperPtr;
+
+/* Structure for command table */
+typedef struct {
+  const char         *name;
+  SwigPerlWrapperPtr  wrapper;
+} swig_command_info;
+
+/* Information for constant table */
+
+#define SWIG_INT     1
+#define SWIG_FLOAT   2
+#define SWIG_STRING  3
+#define SWIG_POINTER 4
+#define SWIG_BINARY  5
+
+/* Constant information structure */
+typedef struct swig_constant_info {
+    int              type;
+    const char      *name;
+    long             lvalue;
+    double           dvalue;
+    void            *pvalue;
+    swig_type_info **ptype;
+} swig_constant_info;
+
+
+/* Structure for variable table */
+typedef struct {
+  const char   *name;
+  SwigMagicFunc   set;
+  SwigMagicFunc   get;
+  swig_type_info  **type;
+} swig_variable_info;
+
+/* Magic variable code */
+#ifndef PERL_OBJECT
+#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c)
+  #ifndef MULTIPLICITY
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) 
+  #else
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) 
+  #endif
+#else
+#  define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c)
+SWIGRUNTIME void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) 
+#endif
+{
+  MAGIC *mg;
+  sv_magic(sv,sv,'U',(char *) name,strlen(name));
+  mg = mg_find(sv,'U');
+  mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
+  mg->mg_virtual->svt_get = (SwigMagicFunc) get;
+  mg->mg_virtual->svt_set = (SwigMagicFunc) set;
+  mg->mg_virtual->svt_len = 0;
+  mg->mg_virtual->svt_clear = 0;
+  mg->mg_virtual->svt_free = 0;
+}
+
+
+SWIGRUNTIME swig_module_info *
+SWIG_Perl_GetModule(void) {
+  static void *type_pointer = (void *)0;
+  SV *pointer;
+
+  /* first check if pointer already created */
+  if (!type_pointer) {
+    pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE);
+    if (pointer && SvOK(pointer)) {
+      type_pointer = INT2PTR(swig_type_info **, SvIV(pointer));
+    }
+  }
+
+  return (swig_module_info *) type_pointer;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_SetModule(swig_module_info *module) {
+  SV *pointer;
+
+  /* create a new pointer */
+  pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE);
+  sv_setiv(pointer, PTR2IV(module));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Workaround perl5 global namespace pollution. Note that undefining library
+ * functions like fopen will not solve the problem on all platforms as fopen
+ * might be a macro on Windows but not necessarily on other operating systems. */
+#ifdef do_open
+  #undef do_open
+#endif
+#ifdef do_close
+  #undef do_close
+#endif
+#ifdef scalar
+  #undef scalar
+#endif
+#ifdef list
+  #undef list
+#endif
+#ifdef apply
+  #undef apply
+#endif
+#ifdef convert
+  #undef convert
+#endif
+#ifdef Error
+  #undef Error
+#endif
+#ifdef form
+  #undef form
+#endif
+#ifdef vform
+  #undef vform
+#endif
+#ifdef LABEL
+  #undef LABEL
+#endif
+#ifdef METHOD
+  #undef METHOD
+#endif
+#ifdef Move
+  #undef Move
+#endif
+#ifdef yylex
+  #undef yylex
+#endif
+#ifdef yyparse
+  #undef yyparse
+#endif
+#ifdef yyerror
+  #undef yyerror
+#endif
+#ifdef invert
+  #undef invert
+#endif
+#ifdef ref
+  #undef ref
+#endif
+#ifdef read
+  #undef read
+#endif
+#ifdef write
+  #undef write
+#endif
+#ifdef eof
+  #undef eof
+#endif
+#ifdef bool
+  #undef bool
+#endif
+#ifdef close
+  #undef close
+#endif
+#ifdef rewind
+  #undef rewind
+#endif
+#ifdef free
+  #undef free
+#endif
+#ifdef malloc
+  #undef malloc
+#endif
+#ifdef calloc
+  #undef calloc
+#endif
+#ifdef Stat
+  #undef Stat
+#endif
+#ifdef check
+  #undef check
+#endif
+#ifdef seekdir
+  #undef seekdir
+#endif
+#ifdef open
+  #undef open
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) 
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else 
+
+
+
+  #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) 
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_GSList swig_types[0]
+#define SWIGTYPE_p_char swig_types[1]
+#define SWIGTYPE_p_double swig_types[2]
+#define SWIGTYPE_p_dumpspec_t swig_types[3]
+#define SWIGTYPE_p_float swig_types[4]
+#define SWIGTYPE_p_int swig_types[5]
+#define SWIGTYPE_p_p_char swig_types[6]
+#define SWIGTYPE_p_unsigned_char swig_types[7]
+static swig_type_info *swig_types[9];
+static swig_module_info swig_module = {swig_types, 8, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init    boot_Amanda__Cmdline
+
+#define SWIG_name   "Amanda::Cmdlinec::boot_Amanda__Cmdline"
+#define SWIG_prefix "Amanda::Cmdlinec::"
+
+#define SWIGVERSION 0x010333 
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a)) 
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) 
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifndef PERL_OBJECT
+#ifndef MULTIPLICITY
+SWIGEXPORT void SWIG_init (CV* cv);
+#else
+SWIGEXPORT void SWIG_init (pTHXo_ CV* cv);
+#endif
+#else
+SWIGEXPORT void SWIG_init (CV *cv, CPerlObj *);
+#endif
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "cmdline.h"
+
+
+typedef GSList amglue_dumpspec_list;
+
+
+#include <glib.h>
+#include "cmdline.h"
+
+
+SWIGINTERNINLINE SV *
+SWIG_FromCharPtrAndSize(const char* carray, size_t size)
+{
+  SV *obj = sv_newmortal();
+  if (carray) {
+    sv_setpvn(obj, carray, size);
+  } else {
+    sv_setsv(obj, &PL_sv_undef);
+  }
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV * 
+SWIG_FromCharPtr(const char *cptr)
+{ 
+  return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0));
+}
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+  static int init = 0;
+  static swig_type_info* info = 0;
+  if (!init) {
+    info = SWIG_TypeQuery("_p_char");
+    init = 1;
+  }
+  return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(SV *obj, char** cptr, size_t* psize, int *alloc)
+{
+  if (SvPOK(obj)) {
+    STRLEN len = 0;
+    char *cstr = SvPV(obj, len); 
+    size_t size = len + 1;
+    if (cptr)  {
+      if (alloc) {
+       if (*alloc == SWIG_NEWOBJ) {
+         *cptr = (char *)memcpy((char *)malloc((size)*sizeof(char)), cstr, sizeof(char)*(size));
+       } else {
+         *cptr = cstr;
+         *alloc = SWIG_OLDOBJ;
+       }
+      }
+    }
+    if (psize) *psize = size;
+    return SWIG_OK;
+  } else {
+    swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+    if (pchar_descriptor) {
+      char* vptr = 0; 
+      if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_descriptor, 0) == SWIG_OK) {
+       if (cptr) *cptr = vptr;
+       if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0;
+       if (alloc) *alloc = SWIG_OLDOBJ;
+       return SWIG_OK;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+
+
+SWIGINTERN dumpspec_t *new_dumpspec_t(char *host,char *disk,char *datestamp,char *level){
+           return dumpspec_new(host, disk, datestamp, level);
+       }
+SWIGINTERN void delete_dumpspec_t(dumpspec_t *self){
+           dumpspec_free(self);
+       }
+SWIGINTERN char *dumpspec_t_format(dumpspec_t *self){
+           return cmdline_format_dumpspec(self);
+       }
+
+SWIGINTERNINLINE SV *
+SWIG_From_long  SWIG_PERL_DECL_ARGS_1(long value)
+{    
+  SV *obj = sv_newmortal();
+  sv_setiv(obj, (IV) value);
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_int  SWIG_PERL_DECL_ARGS_1(int value)
+{    
+  return SWIG_From_long  SWIG_PERL_CALL_ARGS_1(value);
+}
+
+
+#include <limits.h>
+#if !defined(SWIG_NO_LLONG_MAX)
+# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__)
+#   define LLONG_MAX __LONG_LONG_MAX__
+#   define LLONG_MIN (-LLONG_MAX - 1LL)
+#   define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+# endif
+#endif
+
+
+SWIGINTERN int
+SWIG_AsVal_double SWIG_PERL_DECL_ARGS_2(SV *obj, double *val)
+{
+  if (SvNIOK(obj)) {
+    if (val) *val = SvNV(obj);
+    return SWIG_OK;
+  } else if (SvIOK(obj)) {
+    if (val) *val = (double) SvIV(obj);
+    return SWIG_AddCast(SWIG_OK);
+  } else {
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      double v = strtod(nptr, &endptr);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+#include <float.h>
+
+
+#include <math.h>
+
+
+SWIGINTERNINLINE int
+SWIG_CanCastAsInteger(double *d, double min, double max) {
+  double x = *d;
+  if ((min <= x && x <= max)) {
+   double fx = floor(x);
+   double cx = ceil(x);
+   double rd =  ((x - fx) < 0.5) ? fx : cx; /* simple rint */
+   if ((errno == EDOM) || (errno == ERANGE)) {
+     errno = 0;
+   } else {
+     double summ, reps, diff;
+     if (rd < x) {
+       diff = x - rd;
+     } else if (rd > x) {
+       diff = rd - x;
+     } else {
+       return 1;
+     }
+     summ = rd + x;
+     reps = diff/summ;
+     if (reps < 8*DBL_EPSILON) {
+       *d = rd;
+       return 1;
+     }
+   }
+  }
+  return 0;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_long SWIG_PERL_DECL_ARGS_2(SV *obj, long* val)
+{
+  if (SvIOK(obj)) {
+    if (val) *val = SvIV(obj);
+    return SWIG_OK;
+  } else {
+    int dispatch = 0;
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      long v;
+      errno = 0;
+      v = strtol(nptr, &endptr,0);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+    if (!dispatch) {
+      double d;
+      int res = SWIG_AddCast(SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj,&d));
+      if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
+       if (val) *val = (long)(d);
+       return res;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_int SWIG_PERL_DECL_ARGS_2(SV * obj, int *val)
+{
+  long v;
+  int res = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v < INT_MIN || v > INT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = (int)(v);
+    }
+  }  
+  return res;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef PERL_OBJECT
+#define MAGIC_CLASS _wrap_Amanda::Cmdline_var::
+class _wrap_Amanda::Cmdline_var : public CPerlObj {
+public:
+#else
+#define MAGIC_CLASS
+#endif
+SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {
+    MAGIC_PPERL
+    croak("Value is read-only.");
+    return 0;
+}
+
+
+#ifdef PERL_OBJECT
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+XS(_wrap_dumpspec_t_host_get) {
+  {
+    dumpspec_t *arg1 = (dumpspec_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpspec_t_host_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpspec_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpspec_t_host_get" "', argument " "1"" of type '" "dumpspec_t *""'"); 
+    }
+    arg1 = (dumpspec_t *)(argp1);
+    result = (char *) ((arg1)->host);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpspec_t_disk_get) {
+  {
+    dumpspec_t *arg1 = (dumpspec_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpspec_t_disk_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpspec_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpspec_t_disk_get" "', argument " "1"" of type '" "dumpspec_t *""'"); 
+    }
+    arg1 = (dumpspec_t *)(argp1);
+    result = (char *) ((arg1)->disk);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpspec_t_datestamp_get) {
+  {
+    dumpspec_t *arg1 = (dumpspec_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpspec_t_datestamp_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpspec_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpspec_t_datestamp_get" "', argument " "1"" of type '" "dumpspec_t *""'"); 
+    }
+    arg1 = (dumpspec_t *)(argp1);
+    result = (char *) ((arg1)->datestamp);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpspec_t_level_get) {
+  {
+    dumpspec_t *arg1 = (dumpspec_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpspec_t_level_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpspec_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpspec_t_level_get" "', argument " "1"" of type '" "dumpspec_t *""'"); 
+    }
+    arg1 = (dumpspec_t *)(argp1);
+    result = (char *) ((arg1)->level);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_new_dumpspec_t) {
+  {
+    char *arg1 = (char *) 0 ;
+    char *arg2 = (char *) 0 ;
+    char *arg3 = (char *) 0 ;
+    char *arg4 = (char *) 0 ;
+    dumpspec_t *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int res3 ;
+    char *buf3 = 0 ;
+    int alloc3 = 0 ;
+    int res4 ;
+    char *buf4 = 0 ;
+    int alloc4 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 4) || (items > 4)) {
+      SWIG_croak("Usage: new_dumpspec_t(host,disk,datestamp,level);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_dumpspec_t" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_dumpspec_t" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    res3 = SWIG_AsCharPtrAndSize(ST(2), &buf3, NULL, &alloc3);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "new_dumpspec_t" "', argument " "3"" of type '" "char *""'");
+    }
+    arg3 = (char *)(buf3);
+    res4 = SWIG_AsCharPtrAndSize(ST(3), &buf4, NULL, &alloc4);
+    if (!SWIG_IsOK(res4)) {
+      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "new_dumpspec_t" "', argument " "4"" of type '" "char *""'");
+    }
+    arg4 = (char *)(buf4);
+    result = (dumpspec_t *)new_dumpspec_t(arg1,arg2,arg3,arg4);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_dumpspec_t, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_delete_dumpspec_t) {
+  {
+    dumpspec_t *arg1 = (dumpspec_t *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: delete_dumpspec_t(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpspec_t, SWIG_POINTER_DISOWN |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_dumpspec_t" "', argument " "1"" of type '" "dumpspec_t *""'"); 
+    }
+    arg1 = (dumpspec_t *)(argp1);
+    delete_dumpspec_t(arg1);
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpspec_t_format) {
+  {
+    dumpspec_t *arg1 = (dumpspec_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpspec_t_format(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpspec_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpspec_t_format" "', argument " "1"" of type '" "dumpspec_t *""'"); 
+    }
+    arg1 = (dumpspec_t *)(argp1);
+    result = (char *)dumpspec_t_format(arg1);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    free((char*)result);
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_format_dumpspec_components) {
+  {
+    char *arg1 = (char *) 0 ;
+    char *arg2 = (char *) 0 ;
+    char *arg3 = (char *) 0 ;
+    char *arg4 = (char *) 0 ;
+    char *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int res3 ;
+    char *buf3 = 0 ;
+    int alloc3 = 0 ;
+    int res4 ;
+    char *buf4 = 0 ;
+    int alloc4 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 4) || (items > 4)) {
+      SWIG_croak("Usage: format_dumpspec_components(host,disk,datestamp,level);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "format_dumpspec_components" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "format_dumpspec_components" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    res3 = SWIG_AsCharPtrAndSize(ST(2), &buf3, NULL, &alloc3);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "format_dumpspec_components" "', argument " "3"" of type '" "char *""'");
+    }
+    arg3 = (char *)(buf3);
+    res4 = SWIG_AsCharPtrAndSize(ST(3), &buf4, NULL, &alloc4);
+    if (!SWIG_IsOK(res4)) {
+      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "format_dumpspec_components" "', argument " "4"" of type '" "char *""'");
+    }
+    arg4 = (char *)(buf4);
+    result = (char *)cmdline_format_dumpspec_components(arg1,arg2,arg3,arg4);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_parse_dumpspecs) {
+  {
+    int arg1 ;
+    char **arg2 = (char **) 0 ;
+    int arg3 ;
+    amglue_dumpspec_list *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: parse_dumpspecs(argc,argv,flags);");
+    }
+    {
+      AV *av;
+      int i;
+      
+      if (!SvROK(ST(0)) || SvTYPE(SvRV(ST(0))) != SVt_PVAV) {
+        SWIG_exception(SWIG_TypeError, "Expected an arrayref");
+      }
+      av = (AV *)SvRV(ST(0));
+      
+      arg1 = av_len(av)+1; /* av_len(av) is like $#av */
+      arg2 = malloc(sizeof(char *) * arg1);
+      for (i = 0; i < arg1; i++) {
+        SV **elt = av_fetch(av, i, 0);
+        if (!elt || !SvPOK(*elt)) {
+          SWIG_exception(SWIG_TypeError, "Non-string in arrayref");
+        }
+        arg2[i] = SvPV_nolen(*elt); /* TODO: handle unicode here */
+      }
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg3 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg3 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg3 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg3 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (amglue_dumpspec_list *)cmdline_parse_dumpspecs(arg1,arg2,arg3);
+    {
+      if (result) {
+        GSList *iter;
+        EXTEND(SP, g_slist_length(result)); /* make room for return values */
+        
+        iter = result;
+        while (iter) {
+          /* Let SWIG take ownership of the object; we'll free the GSList momentarily */
+          ST(argvi) = SWIG_NewPointerObj(iter->data, SWIGTYPE_p_dumpspec_t, SWIG_OWNER | SWIG_SHADOW);
+          argvi++;
+          iter = iter->next;
+        }
+        
+        /* Now free the GSList, but *not* its contents (which are now "owned" by SWIG) */
+        g_slist_free(result);
+      }
+    }
+    {
+      free(arg2);
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    {
+      free(arg2);
+    }
+    
+    SWIG_croak_null();
+  }
+}
+
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_GSList = {"_p_GSList", "amglue_dumpspec_list *|GSList *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_char = {"_p_char", "gchar *|char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_double = {"_p_double", "double *|gdouble *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_dumpspec_t = {"_p_dumpspec_t", "struct dumpspec_t *|dumpspec_t *", 0, 0, (void*)"Amanda::Cmdline::dumpspec_t", 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *|gfloat *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "int *|gboolean *|cmdline_parse_dumpspecs_flags *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "guchar *|unsigned char *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_GSList,
+  &_swigt__p_char,
+  &_swigt__p_double,
+  &_swigt__p_dumpspec_t,
+  &_swigt__p_float,
+  &_swigt__p_int,
+  &_swigt__p_p_char,
+  &_swigt__p_unsigned_char,
+};
+
+static swig_cast_info _swigc__p_GSList[] = {  {&_swigt__p_GSList, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_dumpspec_t[] = {  {&_swigt__p_dumpspec_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_p_char[] = {  {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_char[] = {  {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_GSList,
+  _swigc__p_char,
+  _swigc__p_double,
+  _swigc__p_dumpspec_t,
+  _swigc__p_float,
+  _swigc__p_int,
+  _swigc__p_p_char,
+  _swigc__p_unsigned_char,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_constant_info swig_constants[] = {
+{0,0,0,0,0,0}
+};
+#ifdef __cplusplus
+}
+#endif
+static swig_variable_info swig_variables[] = {
+{0,0,0,0}
+};
+static swig_command_info swig_commands[] = {
+{"Amanda::Cmdlinec::dumpspec_t_host_get", _wrap_dumpspec_t_host_get},
+{"Amanda::Cmdlinec::dumpspec_t_disk_get", _wrap_dumpspec_t_disk_get},
+{"Amanda::Cmdlinec::dumpspec_t_datestamp_get", _wrap_dumpspec_t_datestamp_get},
+{"Amanda::Cmdlinec::dumpspec_t_level_get", _wrap_dumpspec_t_level_get},
+{"Amanda::Cmdlinec::new_dumpspec_t", _wrap_new_dumpspec_t},
+{"Amanda::Cmdlinec::delete_dumpspec_t", _wrap_delete_dumpspec_t},
+{"Amanda::Cmdlinec::dumpspec_t_format", _wrap_dumpspec_t_format},
+{"Amanda::Cmdlinec::format_dumpspec_components", _wrap_format_dumpspec_components},
+{"Amanda::Cmdlinec::parse_dumpspecs", _wrap_parse_dumpspecs},
+{0,0}
+};
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic 
+ * memory is used. Also, since swig_type_info structures store pointers to 
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization. 
+ * The idea is that swig generates all the structures that are needed. 
+ * The runtime then collects these partially filled structures. 
+ * The SWIG_InitializeModule function takes these initial arrays out of 
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned staticly to an initial 
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it 
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded. 
+ * There are three cases to handle:
+ *  1) If the cast->type has already been loaded AND the type we are adding
+ *     casting info to has not been loaded (it is in this module), THEN we
+ *     replace the cast->type pointer with the type pointer that has already
+ *     been loaded.
+ *  2) If BOTH types (the one we are adding casting info to, and the 
+ *     cast->type) are loaded, THEN the cast info has already been loaded by
+ *     the previous module so we just ignore it.
+ *  3) Finally, if cast->type has not already been loaded, then we add that
+ *     swig_cast_info to the linked list (because the cast->type) pointer will
+ *     be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+  size_t i;
+  swig_module_info *module_head, *iter;
+  int found;
+  
+  clientdata = clientdata;
+  
+  /* check to see if the circular list has been setup, if not, set it up */
+  if (swig_module.next==0) {
+    /* Initialize the swig_module */
+    swig_module.type_initial = swig_type_initial;
+    swig_module.cast_initial = swig_cast_initial;
+    swig_module.next = &swig_module;
+  }
+  
+  /* Try and load any already created modules */
+  module_head = SWIG_GetModule(clientdata);
+  if (!module_head) {
+    /* This is the first module loaded for this interpreter */
+    /* so set the swig module into the interpreter */
+    SWIG_SetModule(clientdata, &swig_module);
+    module_head = &swig_module;
+  } else {
+    /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+    found=0;
+    iter=module_head;
+    do {
+      if (iter==&swig_module) {
+        found=1;
+        break;
+      }
+      iter=iter->next;
+    } while (iter!= module_head);
+    
+    /* if the is found in the list, then all is done and we may leave */
+    if (found) return;
+    /* otherwise we must add out module into the list */
+    swig_module.next = module_head->next;
+    module_head->next = &swig_module;
+  }
+  
+  /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+  printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+  for (i = 0; i < swig_module.size; ++i) {
+    swig_type_info *type = 0;
+    swig_type_info *ret;
+    swig_cast_info *cast;
+    
+#ifdef SWIGRUNTIME_DEBUG
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+    
+    /* if there is another module already loaded */
+    if (swig_module.next != &swig_module) {
+      type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+    }
+    if (type) {
+      /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+      if (swig_module.type_initial[i]->clientdata) {
+        type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+      }
+    } else {
+      type = swig_module.type_initial[i];
+    }
+    
+    /* Insert casting types */
+    cast = swig_module.cast_initial[i];
+    while (cast->type) {
+      /* Don't need to add information already in the list */
+      ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+      if (swig_module.next != &swig_module) {
+        ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+        if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+      }
+      if (ret) {
+        if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+          printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+          cast->type = ret;
+          ret = 0;
+        } else {
+          /* Check for casting already in the list */
+          swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+          if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+          if (!ocast) ret = 0;
+        }
+      }
+      
+      if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+        if (type->cast) {
+          type->cast->prev = cast;
+          cast->next = type->cast;
+        }
+        type->cast = cast;
+      }
+      cast++;
+    }
+    /* Set entry in modules->types array equal to the type */
+    swig_module.types[i] = type;
+  }
+  swig_module.types[i] = 0;
+  
+#ifdef SWIGRUNTIME_DEBUG
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+  for (i = 0; i < swig_module.size; ++i) {
+    int j = 0;
+    swig_cast_info *cast = swig_module.cast_initial[i];
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+    while (cast->type) {
+      printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+      cast++;
+      ++j;
+    }
+    printf("---- Total casts: %d\n",j);
+  }
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types.  It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+  size_t i;
+  swig_cast_info *equiv;
+  static int init_run = 0;
+  
+  if (init_run) return;
+  init_run = 1;
+  
+  for (i = 0; i < swig_module.size; i++) {
+    if (swig_module.types[i]->clientdata) {
+      equiv = swig_module.types[i]->cast;
+      while (equiv) {
+        if (!equiv->converter) {
+          if (equiv->type && !equiv->type->clientdata)
+          SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+        }
+        equiv = equiv->next;
+      }
+    }
+  }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+  /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(SWIG_init) {
+  dXSARGS;
+  int i;
+  
+  SWIG_InitializeModule(0);
+  
+  /* Install commands */
+  for (i = 0; swig_commands[i].name; i++) {
+    newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__);
+  }
+  
+  /* Install variables */
+  for (i = 0; swig_variables[i].name; i++) {
+    SV *sv;
+    sv = get_sv((char*) swig_variables[i].name, TRUE | 0x2);
+    if (swig_variables[i].type) {
+      SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0);
+    } else {
+      sv_setiv(sv,(IV) 0);
+    }
+    swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); 
+  }
+  
+  /* Install constant */
+  for (i = 0; swig_constants[i].type; i++) {
+    SV *sv;
+    sv = get_sv((char*)swig_constants[i].name, TRUE | 0x2);
+    switch(swig_constants[i].type) {
+    case SWIG_INT:
+      sv_setiv(sv, (IV) swig_constants[i].lvalue);
+      break;
+    case SWIG_FLOAT:
+      sv_setnv(sv, (double) swig_constants[i].dvalue);
+      break;
+    case SWIG_STRING:
+      sv_setpv(sv, (char *) swig_constants[i].pvalue);
+      break;
+    case SWIG_POINTER:
+      SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
+      break;
+    case SWIG_BINARY:
+      SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
+      break;
+    default:
+      break;
+    }
+    SvREADONLY_on(sv);
+  }
+  
+  SWIG_TypeClientData(SWIGTYPE_p_dumpspec_t, (void*) "Amanda::Cmdline::dumpspec_t");
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CMDLINE_PARSE_DATESTAMP", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CMDLINE_PARSE_DATESTAMP)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CMDLINE_PARSE_LEVEL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CMDLINE_PARSE_LEVEL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CMDLINE_EMPTY_TO_WILDCARD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CMDLINE_EMPTY_TO_WILDCARD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  ST(0) = &PL_sv_yes;
+  XSRETURN(1);
+}
+
diff --git a/perl/Amanda/Cmdline.pm b/perl/Amanda/Cmdline.pm
new file mode 100644 (file)
index 0000000..fa99ed1
--- /dev/null
@@ -0,0 +1,220 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 1.3.33
+#
+# Don't modify this file, modify the SWIG interface instead.
+
+package Amanda::Cmdline;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+package Amanda::Cmdlinec;
+bootstrap Amanda::Cmdline;
+package Amanda::Cmdline;
+@EXPORT = qw( );
+
+# ---------- BASE METHODS -------------
+
+package Amanda::Cmdline;
+
+sub TIEHASH {
+    my ($classname,$obj) = @_;
+    return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+    my ($self,$field) = @_;
+    my $member_func = "swig_${field}_get";
+    $self->$member_func();
+}
+
+sub STORE {
+    my ($self,$field,$newval) = @_;
+    my $member_func = "swig_${field}_set";
+    $self->$member_func($newval);
+}
+
+sub this {
+    my $ptr = shift;
+    return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package Amanda::Cmdline;
+
+*format_dumpspec_components = *Amanda::Cmdlinec::format_dumpspec_components;
+*parse_dumpspecs = *Amanda::Cmdlinec::parse_dumpspecs;
+
+############# Class : Amanda::Cmdline::dumpspec_t ##############
+
+package Amanda::Cmdline::dumpspec_t;
+use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
+@ISA = qw( Amanda::Cmdline );
+%OWNER = ();
+%ITERATORS = ();
+*swig_host_get = *Amanda::Cmdlinec::dumpspec_t_host_get;
+*swig_host_set = *Amanda::Cmdlinec::dumpspec_t_host_set;
+*swig_disk_get = *Amanda::Cmdlinec::dumpspec_t_disk_get;
+*swig_disk_set = *Amanda::Cmdlinec::dumpspec_t_disk_set;
+*swig_datestamp_get = *Amanda::Cmdlinec::dumpspec_t_datestamp_get;
+*swig_datestamp_set = *Amanda::Cmdlinec::dumpspec_t_datestamp_set;
+*swig_level_get = *Amanda::Cmdlinec::dumpspec_t_level_get;
+*swig_level_set = *Amanda::Cmdlinec::dumpspec_t_level_set;
+sub new {
+    my $pkg = shift;
+    my $self = Amanda::Cmdlinec::new_dumpspec_t(@_);
+    bless $self, $pkg if defined($self);
+}
+
+sub DESTROY {
+    return unless $_[0]->isa('HASH');
+    my $self = tied(%{$_[0]});
+    return unless defined $self;
+    delete $ITERATORS{$self};
+    if (exists $OWNER{$self}) {
+        Amanda::Cmdlinec::delete_dumpspec_t($self);
+        delete $OWNER{$self};
+    }
+}
+
+*format = *Amanda::Cmdlinec::dumpspec_t_format;
+sub DISOWN {
+    my $self = shift;
+    my $ptr = tied(%$self);
+    delete $OWNER{$ptr};
+}
+
+sub ACQUIRE {
+    my $self = shift;
+    my $ptr = tied(%$self);
+    $OWNER{$ptr} = 1;
+}
+
+
+# ------- VARIABLE STUBS --------
+
+package Amanda::Cmdline;
+
+*CMDLINE_PARSE_DATESTAMP = *Amanda::Cmdlinec::CMDLINE_PARSE_DATESTAMP;
+*CMDLINE_PARSE_LEVEL = *Amanda::Cmdlinec::CMDLINE_PARSE_LEVEL;
+*CMDLINE_EMPTY_TO_WILDCARD = *Amanda::Cmdlinec::CMDLINE_EMPTY_TO_WILDCARD;
+
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+
+=head1 NAME
+
+Amanda::Cmdline - utilities for handling command lines
+
+=head1 SYNOPSIS
+
+  use Amanda::Cmdline;
+
+  my $spec = Amanda::Cmdline::dumpspec_t->new($host, $disk, $datestamp, $level);
+  print "host: $spec->{'host'}; disk: $spec->{'disk'}\n";
+
+  my @specs = Amanda::Cmdline::parse_dumpspecs(["host", "disk", "date"],
+                           $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP);
+
+=head1 API STATUS
+
+Will change.
+
+=head1 Amanda::Cmdline::dumpspec_t Objects
+
+=head2 Instance Variables
+
+=over
+
+=item C<$host>
+
+=item C<$disk>
+
+=item C<$datestamp>
+
+=item C<$level>
+
+=back
+
+=head2 Methods
+
+=over
+
+=item C<format()>
+
+Format the dumpspec as a string.
+
+=back
+
+=head1 Functions
+
+=over
+
+=item C<format_dumpspec_components($host, $disk, $datestamp, $level)>
+
+This function returns a string representing the formatted form of the given dumpspec.  This formatting
+is the same as performed by C<format_dumpspec_components>, but does not need a C<dumpspec_t>.
+
+=item C<parse_dumpspecs(@cmdline, $flags)> 
+
+This function parses C<@cmdline> into a list of C<dumpspec_t> objects,
+according to C<$flags>, which is a logical combination of zero or
+more of C<$CMDLINE_PARSE_DATESTAMP> to recognize datestamps and
+C<$CMDLINE_PARSE_LEVEL> to recognize levels.
+
+=back
+
+=head1 SEE ALSO
+
+L<Amanda::Config> handles C<-o> options itself, through C<config_overwrites>.
+
+=cut
+
+push @EXPORT_OK, qw(cmdline_parse_dumpspecs_flags_to_strings);
+push @{$EXPORT_TAGS{"cmdline_parse_dumpspecs_flags"}}, qw(cmdline_parse_dumpspecs_flags_to_strings);
+
+my %_cmdline_parse_dumpspecs_flags_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub cmdline_parse_dumpspecs_flags_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_cmdline_parse_dumpspecs_flags_VALUES) {
+       my $v = $_cmdline_parse_dumpspecs_flags_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($CMDLINE_PARSE_DATESTAMP);
+push @{$EXPORT_TAGS{"cmdline_parse_dumpspecs_flags"}}, qw($CMDLINE_PARSE_DATESTAMP);
+
+$_cmdline_parse_dumpspecs_flags_VALUES{"CMDLINE_PARSE_DATESTAMP"} = $CMDLINE_PARSE_DATESTAMP;
+
+push @EXPORT_OK, qw($CMDLINE_PARSE_LEVEL);
+push @{$EXPORT_TAGS{"cmdline_parse_dumpspecs_flags"}}, qw($CMDLINE_PARSE_LEVEL);
+
+$_cmdline_parse_dumpspecs_flags_VALUES{"CMDLINE_PARSE_LEVEL"} = $CMDLINE_PARSE_LEVEL;
+
+push @EXPORT_OK, qw($CMDLINE_EMPTY_TO_WILDCARD);
+push @{$EXPORT_TAGS{"cmdline_parse_dumpspecs_flags"}}, qw($CMDLINE_EMPTY_TO_WILDCARD);
+
+$_cmdline_parse_dumpspecs_flags_VALUES{"CMDLINE_EMPTY_TO_WILDCARD"} = $CMDLINE_EMPTY_TO_WILDCARD;
+1;
diff --git a/perl/Amanda/Cmdline.swg b/perl/Amanda/Cmdline.swg
new file mode 100644 (file)
index 0000000..953edab
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%module "Amanda::Cmdline"
+%include "amglue/amglue.swg"
+%include "exception.i"
+%include "amglue/dumpspecs.swg"
+
+%{
+#include <glib.h>
+#include "cmdline.h"
+%}
+
+%perlcode %{
+=head1 NAME
+
+Amanda::Cmdline - utilities for handling command lines
+
+=head1 SYNOPSIS
+
+  use Amanda::Cmdline;
+
+  my $spec = Amanda::Cmdline::dumpspec_t->new($host, $disk, $datestamp, $level);
+  print "host: $spec->{'host'}; disk: $spec->{'disk'}\n";
+
+  my @specs = Amanda::Cmdline::parse_dumpspecs(["host", "disk", "date"],
+                           $Amanda::Cmdline::CMDLINE_PARSE_DATESTAMP);
+
+=head1 API STATUS
+
+Will change.
+
+=head1 Amanda::Cmdline::dumpspec_t Objects
+
+=head2 Instance Variables
+
+=over
+
+=item C<$host>
+
+=item C<$disk>
+
+=item C<$datestamp>
+
+=item C<$level>
+
+=back
+
+=head2 Methods
+
+=over
+
+=item C<format()>
+
+Format the dumpspec as a string.
+
+=back
+
+=head1 Functions
+
+=over
+
+=item C<format_dumpspec_components($host, $disk, $datestamp, $level)>
+
+This function returns a string representing the formatted form of the given dumpspec.  This formatting
+is the same as performed by C<format_dumpspec_components>, but does not need a C<dumpspec_t>.
+
+=item C<parse_dumpspecs(@cmdline, $flags)> 
+
+This function parses C<@cmdline> into a list of C<dumpspec_t> objects,
+according to C<$flags>, which is a logical combination of zero or
+more of C<$CMDLINE_PARSE_DATESTAMP> to recognize datestamps and
+C<$CMDLINE_PARSE_LEVEL> to recognize levels.
+
+=back
+
+=head1 SEE ALSO
+
+L<Amanda::Config> handles C<-o> options itself, through C<config_overwrites>.
+
+=cut
+%}
+
+/* Add a few methods to make this type act like a class */
+typedef struct dumpspec_t {
+    %immutable;
+    char *host;
+    char *disk;
+    char *datestamp;
+    char *level;
+    %mutable;
+
+    %extend {
+       /* constructor */
+       dumpspec_t(char *host, char *disk, char *datestamp, char *level) {
+           return dumpspec_new(host, disk, datestamp, level);
+       }
+
+       ~dumpspec_t() {
+           dumpspec_free(self);
+       }
+
+       %newobject format;
+       char *format() {
+           return cmdline_format_dumpspec(self);
+       }
+    }
+} dumpspec_t;
+
+%rename(format_dumpspec_components) cmdline_format_dumpspec_components;
+char *cmdline_format_dumpspec_components(char *host, char *disk, char *datestamp, char *level);
+
+/* Typemap to convert a perl list of strings to the strv that 
+ * cmdline_parse_dumpspecs expects.
+ */
+%typemap(in, numinputs=1) (int argc, char **argv) {
+    AV *av;
+    int i;
+
+    if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
+       SWIG_exception(SWIG_TypeError, "Expected an arrayref");
+    }
+    av = (AV *)SvRV($input);
+
+    $1 = av_len(av)+1; /* av_len(av) is like $#av */
+    $2 = malloc(sizeof(char *) * $1);
+    for (i = 0; i < $1; i++) {
+       SV **elt = av_fetch(av, i, 0);
+       if (!elt || !SvPOK(*elt)) {
+           SWIG_exception(SWIG_TypeError, "Non-string in arrayref");
+       }
+       $2[i] = SvPV_nolen(*elt); /* TODO: handle unicode here */
+    }
+}
+
+/* Free the space allocated by the previous typemap */
+%typemap(freearg) (int argc, char **argv) {
+    free($2);
+}
+
+amglue_add_flag_tag_fns(cmdline_parse_dumpspecs_flags);
+amglue_add_constant(CMDLINE_PARSE_DATESTAMP, cmdline_parse_dumpspecs_flags);
+amglue_add_constant(CMDLINE_PARSE_LEVEL, cmdline_parse_dumpspecs_flags);
+amglue_add_constant(CMDLINE_EMPTY_TO_WILDCARD, cmdline_parse_dumpspecs_flags);
+
+%rename(parse_dumpspecs) cmdline_parse_dumpspecs;
+amglue_dumpspec_list *cmdline_parse_dumpspecs(int argc, char **argv, int flags);
+
+/* TODO:
+ * convert AV back to GSList as input, convert resulting GSList into an AV of strings
+ * on output
+ */
+/* amglue_dumpspec_list * cmdline_match_holding(amglue_dumpspec_list *dumpspec_list); */
+
diff --git a/perl/Amanda/Config.c b/perl/Amanda/Config.c
new file mode 100644 (file)
index 0000000..dfd13c5
--- /dev/null
@@ -0,0 +1,5280 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.33
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPERL
+#define SWIG_CASTRANK_MODE
+/* -----------------------------------------------------------------------------
+ *  This section contains generic SWIG labels for method/variable
+ *  declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+#  define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+#   define SWIGINLINE inline
+# else
+#   define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define SWIGUNUSED __attribute__ ((__unused__)) 
+#   else
+#     define SWIGUNUSED
+#   endif
+# elif defined(__ICC)
+#   define SWIGUNUSED __attribute__ ((__unused__)) 
+# else
+#   define SWIGUNUSED 
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+#   define SWIGUNUSEDPARM(p)
+# else
+#   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#  ifndef GCC_HASCLASSVISIBILITY
+#    define GCC_HASCLASSVISIBILITY
+#  endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   if defined(STATIC_LINKED)
+#     define SWIGEXPORT
+#   else
+#     define SWIGEXPORT __declspec(dllexport)
+#   endif
+# else
+#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+#     define SWIGEXPORT __attribute__ ((visibility("default")))
+#   else
+#     define SWIGEXPORT
+#   endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   define SWIGSTDCALL __stdcall
+# else
+#   define SWIGSTDCALL
+# endif 
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+   or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "3"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+  You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+  creating a static or dynamic library from the swig runtime code.
+  In 99.9% of the cases, swig just needs to declare them as 'static'.
+  
+  But only do this if is strictly necessary, ie, if you have problems
+  with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/*  Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN        0x1
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN           0x1
+
+
+/* 
+   Flags/methods for returning states.
+   
+   The swig conversion methods, as ConvertPtr, return and integer 
+   that tells if the conversion was successful or not. And if not,
+   an error code can be returned (see swigerrors.swg for the codes).
+   
+   Use the following macros/flags to set or process the returning
+   states.
+   
+   In old swig versions, you usually write code as:
+
+     if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+       // success code
+     } else {
+       //fail code
+     }
+
+   Now you can be more explicit as:
+
+    int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+    } else {
+      // fail code
+    }
+
+   that seems to be the same, but now you can also do
+
+    Type *ptr;
+    int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+      if (SWIG_IsNewObj(res) {
+        ...
+       delete *ptr;
+      } else {
+        ...
+      }
+    } else {
+      // fail code
+    }
+    
+   I.e., now SWIG_ConvertPtr can return new objects and you can
+   identify the case and take care of the deallocation. Of course that
+   requires also to SWIG_ConvertPtr to return new result values, as
+
+      int SWIG_ConvertPtr(obj, ptr,...) {         
+        if (<obj is ok>) {                            
+          if (<need new object>) {                    
+            *ptr = <ptr to new allocated object>; 
+            return SWIG_NEWOBJ;                       
+          } else {                                    
+            *ptr = <ptr to old object>;               
+            return SWIG_OLDOBJ;                       
+          }                                   
+        } else {                                      
+          return SWIG_BADOBJ;                 
+        }                                             
+      }
+
+   Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+   more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+   swig errors code.
+
+   Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+   allows to return the 'cast rank', for example, if you have this
+
+       int food(double)
+       int fooi(int);
+
+   and you call
+      food(1)   // cast rank '1'  (1 -> 1.0)
+      fooi(1)   // cast rank '0'
+
+   just use the SWIG_AddCast()/SWIG_CheckState()
+
+
+ */
+#define SWIG_OK                    (0) 
+#define SWIG_ERROR                 (-1)
+#define SWIG_IsOK(r)               (r >= 0)
+#define SWIG_ArgError(r)           ((r != SWIG_ERROR) ? r : SWIG_TypeError)  
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT         (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK            (SWIG_CASTRANKLIMIT  << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK            (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ                (SWIG_ERROR)
+#define SWIG_OLDOBJ                (SWIG_OK)
+#define SWIG_NEWOBJ                (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ                (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r)         (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r)           (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r)         (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r)           (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+#  ifndef SWIG_TypeRank
+#    define SWIG_TypeRank             unsigned long
+#  endif
+#  ifndef SWIG_MAXCASTRANK            /* Default cast allowed */
+#    define SWIG_MAXCASTRANK          (2)
+#  endif
+#  define SWIG_CASTRANKMASK          ((SWIG_CASTRANKLIMIT) -1)
+#  define SWIG_CastRank(r)           (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) { 
+  return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) { 
+  return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; 
+}
+#else /* no cast-rank mode */
+#  define SWIG_AddCast
+#  define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store inforomation on one type */
+typedef struct swig_type_info {
+  const char             *name;                        /* mangled name of this type */
+  const char             *str;                 /* human readable name of this type */
+  swig_dycast_func        dcast;               /* dynamic cast function down a hierarchy */
+  struct swig_cast_info  *cast;                        /* linked list of types that can cast into this type */
+  void                   *clientdata;          /* language specific type data */
+  int                    owndata;              /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+  swig_type_info         *type;                        /* pointer to type that is equivalent to this type */
+  swig_converter_func     converter;           /* function to cast the void pointers */
+  struct swig_cast_info  *next;                        /* pointer to next cast in linked list */
+  struct swig_cast_info  *prev;                        /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+  swig_type_info         **types;              /* Array of pointers to swig_type_info structures that are in this module */
+  size_t                 size;                 /* Number of types in this module */
+  struct swig_module_info *next;               /* Pointer to next element in circularly linked list */
+  swig_type_info         **type_initial;       /* Array of initially generated type structures */
+  swig_cast_info         **cast_initial;       /* Array of initially generated casting structures */
+  void                    *clientdata;         /* Language specific module data */
+} swig_module_info;
+
+/* 
+  Compare two type names skipping the space characters, therefore
+  "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+  Return 0 when the two name types are equivalent, as in
+  strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+                 const char *f2, const char *l2) {
+  for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+    while ((*f1 == ' ') && (f1 != l1)) ++f1;
+    while ((*f2 == ' ') && (f2 != l2)) ++f2;
+    if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+  }
+  return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty)         \
+  if (ty) {                                             \
+    swig_cast_info *iter = ty->cast;                    \
+    while (iter) {                                      \
+      if (comparison) {                                 \
+        if (iter == ty->cast) return iter;              \
+        /* Move iter to the top of the linked list */   \
+        iter->prev->next = iter->next;                  \
+        if (iter->next)                                 \
+          iter->next->prev = iter->prev;                \
+        iter->next = ty->cast;                          \
+        iter->prev = 0;                                 \
+        if (ty->cast) ty->cast->prev = iter;            \
+        ty->cast = iter;                                \
+        return iter;                                    \
+      }                                                 \
+      iter = iter->next;                                \
+    }                                                   \
+  }                                                     \
+  return 0
+
+/*
+  Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+  SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+  Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr) {
+  return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/* 
+   Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/*
+  Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/*
+  Return the pretty name associated with this type,
+  that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+  /* The "str" field contains the equivalent pretty names of the
+     type, separated by vertical-bar characters.  We choose
+     to print the last name, as it is often (?) the most
+     specific. */
+  if (!type) return NULL;
+  if (type->str != NULL) {
+    const char *last_name = type->str;
+    const char *s;
+    for (s = type->str; *s; s++)
+      if (*s == '|') last_name = s+1;
+    return last_name;
+  }
+  else
+    return type->name;
+}
+
+/* 
+   Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  swig_cast_info *cast = ti->cast;
+  /* if (ti->clientdata == clientdata) return; */
+  ti->clientdata = clientdata;
+  
+  while (cast) {
+    if (!cast->converter) {
+      swig_type_info *tc = cast->type;
+      if (!tc->clientdata) {
+       SWIG_TypeClientData(tc, clientdata);
+      }
+    }    
+    cast = cast->next;
+  }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+  SWIG_TypeClientData(ti, clientdata);
+  ti->owndata = 1;
+}
+  
+/*
+  Search for a swig_type_info structure only by mangled name
+  Search is a O(log #types)
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start, 
+                            swig_module_info *end, 
+                           const char *name) {
+  swig_module_info *iter = start;
+  do {
+    if (iter->size) {
+      register size_t l = 0;
+      register size_t r = iter->size - 1;
+      do {
+       /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+       register size_t i = (l + r) >> 1; 
+       const char *iname = iter->types[i]->name;
+       if (iname) {
+         register int compare = strcmp(name, iname);
+         if (compare == 0) {       
+           return iter->types[i];
+         } else if (compare < 0) {
+           if (i) {
+             r = i - 1;
+           } else {
+             break;
+           }
+         } else if (compare > 0) {
+           l = i + 1;
+         }
+       } else {
+         break; /* should never happen */
+       }
+      } while (l <= r);
+    }
+    iter = iter->next;
+  } while (iter != end);
+  return 0;
+}
+
+/*
+  Search for a swig_type_info structure for either a mangled name or a human readable name.
+  It first searches the mangled names of the types, which is a O(log #types)
+  If a type is not found it then searches the human readable names, which is O(#types).
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start, 
+                     swig_module_info *end, 
+                    const char *name) {
+  /* STEP 1: Search the name field using binary search */
+  swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+  if (ret) {
+    return ret;
+  } else {
+    /* STEP 2: If the type hasn't been found, do a complete search
+       of the str field (the human readable name) */
+    swig_module_info *iter = start;
+    do {
+      register size_t i = 0;
+      for (; i < iter->size; ++i) {
+       if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+         return iter->types[i];
+      }
+      iter = iter->next;
+    } while (iter != end);
+  }
+  
+  /* neither found a match */
+  return 0;
+}
+
+/* 
+   Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+  static const char hex[17] = "0123456789abcdef";
+  register const unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu =  u + sz;
+  for (; u != eu; ++u) {
+    register unsigned char uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* 
+   Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+  register unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu = u + sz;
+  for (; u != eu; ++u) {
+    register char d = *(c++);
+    register unsigned char uu;
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    else 
+      return (char *) 0;
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    else 
+      return (char *) 0;
+    *u = uu;
+  }
+  return c;
+}
+
+/* 
+   Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+  char *r = buff;
+  if ((2*sizeof(void *) + 2) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,&ptr,sizeof(void *));
+  if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+  strcpy(r,name);
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      *ptr = (void *) 0;
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+  char *r = buff;
+  size_t lname = (name ? strlen(name) : 0);
+  if ((2*sz + 2 + lname) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  if (lname) {
+    strncpy(r,name,lname+1);
+  } else {
+    *r = 0;
+  }
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      memset(ptr,0,sz);
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*  Errors in SWIG */
+#define  SWIG_UnknownError        -1 
+#define  SWIG_IOError             -2 
+#define  SWIG_RuntimeError        -3 
+#define  SWIG_IndexError          -4 
+#define  SWIG_TypeError           -5 
+#define  SWIG_DivisionByZero      -6 
+#define  SWIG_OverflowError       -7 
+#define  SWIG_SyntaxError         -8 
+#define  SWIG_ValueError          -9 
+#define  SWIG_SystemError         -10
+#define  SWIG_AttributeError      -11
+#define  SWIG_MemoryError         -12 
+#define  SWIG_NullReferenceError   -13
+
+
+
+#ifdef __cplusplus
+/* Needed on some windows machines---since MS plays funny games with the header files under C++ */
+#include <math.h>
+#include <stdlib.h>
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* Add in functionality missing in older versions of Perl. Much of this is based on Devel-PPPort on cpan. */
+
+/* Add PERL_REVISION, PERL_VERSION, PERL_SUBVERSION if missing */
+#ifndef PERL_REVISION
+#  if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+#    define PERL_PATCHLEVEL_H_IMPLICIT
+#    include <patchlevel.h>
+#  endif
+#  if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+#    include <could_not_find_Perl_patchlevel.h>
+#  endif
+#  ifndef PERL_REVISION
+#    define PERL_REVISION       (5)
+#    define PERL_VERSION        PATCHLEVEL
+#    define PERL_SUBVERSION     SUBVERSION
+#  endif
+#endif
+
+#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE)
+#define PerlIO_exportFILE(fh,fl) (FILE*)(fh)
+#endif
+
+#ifndef SvIOK_UV
+# define SvIOK_UV(sv)       (SvIOK(sv) && (SvUVX(sv) == SvIVX(sv)))
+#endif
+
+#ifndef SvUOK
+# define SvUOK(sv)           SvIOK_UV(sv)
+#endif
+
+#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5)))
+#  define PL_sv_undef               sv_undef
+#  define PL_na                            na
+#  define PL_errgv                  errgv
+#  define PL_sv_no                  sv_no
+#  define PL_sv_yes                 sv_yes
+#  define PL_markstack_ptr          markstack_ptr
+#endif
+
+#ifndef IVSIZE
+#  ifdef LONGSIZE
+#    define IVSIZE LONGSIZE
+#  else
+#    define IVSIZE 4 /* A bold guess, but the best we can make. */
+#  endif
+#endif
+
+#ifndef INT2PTR
+#  if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#    define PTRV                  UV
+#    define INT2PTR(any,d)        (any)(d)
+#  else
+#    if PTRSIZE == LONGSIZE
+#      define PTRV                unsigned long
+#    else
+#      define PTRV                unsigned
+#    endif
+#    define INT2PTR(any,d)        (any)(PTRV)(d)
+#  endif
+
+#  define NUM2PTR(any,d)  (any)(PTRV)(d)
+#  define PTR2IV(p)       INT2PTR(IV,p)
+#  define PTR2UV(p)       INT2PTR(UV,p)
+#  define PTR2NV(p)       NUM2PTR(NV,p)
+
+#  if PTRSIZE == LONGSIZE
+#    define PTR2ul(p)     (unsigned long)(p)
+#  else
+#    define PTR2ul(p)     INT2PTR(unsigned long,p)
+#  endif
+#endif /* !INT2PTR */
+
+#ifndef SvPV_nolen
+# define SvPV_nolen(x) SvPV(x,PL_na)
+#endif
+
+#ifndef get_sv
+#  define get_sv perl_get_sv
+#endif
+
+#ifndef ERRSV
+#  define ERRSV get_sv("@",FALSE)
+#endif
+
+#ifndef pTHX_
+#define pTHX_
+#endif   
+
+#include <string.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGINTERN const char*
+SWIG_Perl_ErrorType(int code) {
+  const char* type = 0;
+  switch(code) {
+  case SWIG_MemoryError:
+    type = "MemoryError";
+    break;
+  case SWIG_IOError:
+    type = "IOError";
+    break;
+  case SWIG_RuntimeError:
+    type = "RuntimeError";
+    break;
+  case SWIG_IndexError:
+    type = "IndexError";
+    break;
+  case SWIG_TypeError:
+    type = "TypeError";
+    break;
+  case SWIG_DivisionByZero:
+    type = "ZeroDivisionError";
+    break;
+  case SWIG_OverflowError:
+    type = "OverflowError";
+    break;
+  case SWIG_SyntaxError:
+    type = "SyntaxError";
+    break;
+  case SWIG_ValueError:
+    type = "ValueError";
+    break;
+  case SWIG_SystemError:
+    type = "SystemError";
+    break;
+  case SWIG_AttributeError:
+    type = "AttributeError";
+    break;
+  default:
+    type = "RuntimeError";
+  }
+  return type;
+}
+
+
+
+
+/* -----------------------------------------------------------------------------
+ * perlrun.swg
+ *
+ * This file contains the runtime support for Perl modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef PERL_OBJECT
+#define SWIG_PERL_OBJECT_DECL CPerlObj *SWIGUNUSEDPARM(pPerl),
+#define SWIG_PERL_OBJECT_CALL pPerl,
+#else
+#define SWIG_PERL_OBJECT_DECL
+#define SWIG_PERL_OBJECT_CALL
+#endif
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_ConvertPtr(obj, pp, type, flags)           SWIG_Perl_ConvertPtr(SWIG_PERL_OBJECT_CALL obj, pp, type, flags)
+#define SWIG_NewPointerObj(p, type, flags)              SWIG_Perl_NewPointerObj(SWIG_PERL_OBJECT_CALL p, type, flags)
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, p, s, type)             SWIG_Perl_ConvertPacked(SWIG_PERL_OBJECT_CALL obj, p, s, type)
+#define SWIG_NewPackedObj(p, s, type)                  SWIG_Perl_NewPackedObj(SWIG_PERL_OBJECT_CALL p, s, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags)    SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags)           SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type)        SWIG_ConvertPtr(obj, pptr, type, 0)
+#define SWIG_NewFunctionPtrObj(ptr, type)               SWIG_NewPointerObj(ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty)            SWIG_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type)                SWIG_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata)                      SWIG_Perl_GetModule()
+#define SWIG_SetModule(clientdata, pointer)             SWIG_Perl_SetModule(pointer)
+
+
+/* Error manipulation */
+
+#define SWIG_ErrorType(code)                            SWIG_Perl_ErrorType(code)               
+#define SWIG_Error(code, msg)                          sv_setpvf(GvSV(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg)
+#define SWIG_fail                                      goto fail                                                   
+
+/* Perl-specific SWIG API */
+
+#define SWIG_MakePtr(sv, ptr, type, flags)              SWIG_Perl_MakePtr(SWIG_PERL_OBJECT_CALL sv, ptr, type, flags)
+#define SWIG_MakePackedObj(sv, p, s, type)             SWIG_Perl_MakePackedObj(SWIG_PERL_OBJECT_CALL sv, p, s, type)
+#define SWIG_SetError(str)                              SWIG_Error(SWIG_RuntimeError, str)
+
+
+#define SWIG_PERL_DECL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_DECL arg1)
+#define SWIG_PERL_CALL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_CALL arg1)
+#define SWIG_PERL_DECL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_DECL arg1, arg2)
+#define SWIG_PERL_CALL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_CALL arg1, arg2)
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+/* For backward compatibility only */
+#define SWIG_POINTER_EXCEPTION  0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_OWNER   SWIG_POINTER_OWN
+#define SWIG_SHADOW  SWIG_OWNER << 1
+
+#define SWIG_MAYBE_PERL_OBJECT SWIG_PERL_OBJECT_DECL
+
+/* SWIG Perl macros */
+
+/* Macro to declare an XS function */
+#ifndef XSPROTO
+#   define XSPROTO(name) void name(pTHX_ CV* cv)
+#endif
+
+/* Macro to call an XS function */
+#ifdef PERL_OBJECT 
+#  define SWIG_CALLXS(_name) _name(cv,pPerl) 
+#else 
+#  ifndef MULTIPLICITY 
+#    define SWIG_CALLXS(_name) _name(cv) 
+#  else 
+#    define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) 
+#  endif 
+#endif 
+
+#ifdef PERL_OBJECT
+#define MAGIC_PPERL  CPerlObj *pPerl = (CPerlObj *) this;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+#define SWIGCLASS_STATIC
+
+#else /* PERL_OBJECT */
+
+#define MAGIC_PPERL
+#define SWIGCLASS_STATIC static SWIGUNUSED
+
+#ifndef MULTIPLICITY
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MULTIPLICITY */
+
+#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MULTIPLICITY */
+#endif /* PERL_OBJECT */
+
+/* Workaround for bug in perl 5.6.x croak and earlier */
+#if (PERL_VERSION < 8)
+#  ifdef PERL_OBJECT
+#    define SWIG_croak_null() SWIG_Perl_croak_null(pPerl)
+static void SWIG_Perl_croak_null(CPerlObj *pPerl)
+#  else
+static void SWIG_croak_null()
+#  endif
+{
+  SV *err=ERRSV;
+#  if (PERL_VERSION < 6)
+  croak("%_", err);
+#  else
+  if (SvOK(err) && !SvROK(err)) croak("%_", err);
+  croak(Nullch);
+#  endif
+}
+#else
+#  define SWIG_croak_null() croak(Nullch)
+#endif
+
+
+/* 
+   Define how strict is the cast between strings and integers/doubles
+   when overloading between these types occurs.
+   
+   The default is making it as strict as possible by using SWIG_AddCast
+   when needed.
+   
+   You can use -DSWIG_PERL_NO_STRICT_STR2NUM at compilation time to
+   disable the SWIG_AddCast, making the casting between string and
+   numbers less strict.
+
+   In the end, we try to solve the overloading between strings and
+   numerical types in the more natural way, but if you can avoid it,
+   well, avoid it using %rename, for example.
+*/
+#ifndef SWIG_PERL_NO_STRICT_STR2NUM
+# ifndef SWIG_PERL_STRICT_STR2NUM
+#  define SWIG_PERL_STRICT_STR2NUM
+# endif
+#endif
+#ifdef SWIG_PERL_STRICT_STR2NUM
+/* string takes precedence */
+#define SWIG_Str2NumCast(x) SWIG_AddCast(x)  
+#else
+/* number takes precedence */
+#define SWIG_Str2NumCast(x) x
+#endif
+
+
+
+#include <stdlib.h>
+
+SWIGRUNTIME const char *
+SWIG_Perl_TypeProxyName(const swig_type_info *type) {
+  if (!type) return NULL;
+  if (type->clientdata != NULL) {
+    return (const char*) type->clientdata;
+  } 
+  else {
+    return type->name;
+  }
+}
+
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeProxyCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(( (!iter->type->clientdata && (strcmp((char*)iter->type->name, c) == 0)) 
+                           || (iter->type->clientdata && (strcmp((char*)iter->type->clientdata, c) == 0))), ty);
+}
+
+
+/* Function for getting a pointer value */
+
+SWIGRUNTIME int
+SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) {
+  swig_cast_info *tc;
+  void *voidptr = (void *)0;
+  SV *tsv = 0;
+  /* If magical, apply more magic */
+  if (SvGMAGICAL(sv))
+    mg_get(sv);
+
+  /* Check to see if this is an object */
+  if (sv_isobject(sv)) {
+    IV tmp = 0;
+    tsv = (SV*) SvRV(sv);
+    if ((SvTYPE(tsv) == SVt_PVHV)) {
+      MAGIC *mg;
+      if (SvMAGICAL(tsv)) {
+        mg = mg_find(tsv,'P');
+        if (mg) {
+          sv = mg->mg_obj;
+          if (sv_isobject(sv)) {
+           tsv = (SV*)SvRV(sv);
+            tmp = SvIV(tsv);
+          }
+        }
+      } else {
+        return SWIG_ERROR;
+      }
+    } else {
+      tmp = SvIV(tsv);
+    }
+    voidptr = INT2PTR(void *,tmp);
+  } else if (! SvOK(sv)) {            /* Check for undef */
+    *(ptr) = (void *) 0;
+    return SWIG_OK;
+  } else if (SvTYPE(sv) == SVt_RV) {  /* Check for NULL pointer */
+    if (!SvROK(sv)) {
+      *(ptr) = (void *) 0;
+      return SWIG_OK;
+    } else {
+      return SWIG_ERROR;
+    }
+  } else {                            /* Don't know what it is */
+    return SWIG_ERROR;
+  }
+  if (_t) {
+    /* Now see if the types match */
+    char *_c = HvNAME(SvSTASH(SvRV(sv)));
+    tc = SWIG_TypeProxyCheck(_c,_t);
+    if (!tc) {
+      return SWIG_ERROR;
+    }
+    *ptr = SWIG_TypeCast(tc,voidptr);
+  } else {
+    *ptr = voidptr;
+  }
+
+  /* 
+   *  DISOWN implementation: we need a perl guru to check this one.
+   */
+  if (tsv && (flags & SWIG_POINTER_DISOWN)) {
+    /* 
+     *  almost copy paste code from below SWIG_POINTER_OWN setting
+     */
+    SV *obj = sv;
+    HV *stash = SvSTASH(SvRV(obj));
+    GV *gv = *(GV**) hv_fetch(stash, "OWNER", 5, TRUE);
+    if (isGV(gv)) {
+      HV *hv = GvHVn(gv);
+      /*
+       * To set ownership (see below), a newSViv(1) entry is added. 
+       * Hence, to remove ownership, we delete the entry.
+       */
+      if (hv_exists_ent(hv, obj, 0)) {
+       hv_delete_ent(hv, obj, 0, 0);
+      }
+    }
+  }
+  return SWIG_OK;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) {
+  if (ptr && (flags & SWIG_SHADOW)) {
+    SV *self;
+    SV *obj=newSV(0);
+    HV *hash=newHV();
+    HV *stash;
+    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+    stash=SvSTASH(SvRV(obj));
+    if (flags & SWIG_POINTER_OWN) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+      if (!isGV(gv))
+        gv_init(gv, stash, "OWNER", 5, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newSViv(1), 0);
+    }
+    sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0);
+    SvREFCNT_dec(obj);
+    self=newRV_noinc((SV *)hash);
+    sv_setsv(sv, self);
+    SvREFCNT_dec((SV *)self);
+    sv_bless(sv, stash);
+  }
+  else {
+    sv_setref_pv(sv, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+  }
+}
+
+SWIGRUNTIMEINLINE SV *
+SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+  SV *result = sv_newmortal();
+  SWIG_MakePtr(result, ptr, t, flags);
+  return result;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) {
+  char result[1024];
+  char *r = result;
+  if ((2*sz + 1 + strlen(SWIG_Perl_TypeProxyName(type))) > 1000) return;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  strcpy(r,SWIG_Perl_TypeProxyName(type));
+  sv_setpv(sv, result);
+}
+
+SWIGRUNTIME SV *
+SWIG_Perl_NewPackedObj(SWIG_MAYBE_PERL_OBJECT void *ptr, int sz, swig_type_info *type) {
+  SV *result = sv_newmortal();
+  SWIG_Perl_MakePackedObj(result, ptr, sz, type);
+  return result;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME int
+SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty) {
+  swig_cast_info *tc;
+  const char  *c = 0;
+
+  if ((!obj) || (!SvOK(obj))) return SWIG_ERROR;
+  c = SvPV_nolen(obj);
+  /* Pointer values must start with leading underscore */
+  if (*c != '_') return SWIG_ERROR;
+  c++;
+  c = SWIG_UnpackData(c,ptr,sz);
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) return SWIG_ERROR;
+  }
+  return SWIG_OK;
+}
+
+
+/* Macros for low-level exception handling */
+#define SWIG_croak(x)    { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail; }
+
+
+typedef XSPROTO(SwigPerlWrapper);
+typedef SwigPerlWrapper *SwigPerlWrapperPtr;
+
+/* Structure for command table */
+typedef struct {
+  const char         *name;
+  SwigPerlWrapperPtr  wrapper;
+} swig_command_info;
+
+/* Information for constant table */
+
+#define SWIG_INT     1
+#define SWIG_FLOAT   2
+#define SWIG_STRING  3
+#define SWIG_POINTER 4
+#define SWIG_BINARY  5
+
+/* Constant information structure */
+typedef struct swig_constant_info {
+    int              type;
+    const char      *name;
+    long             lvalue;
+    double           dvalue;
+    void            *pvalue;
+    swig_type_info **ptype;
+} swig_constant_info;
+
+
+/* Structure for variable table */
+typedef struct {
+  const char   *name;
+  SwigMagicFunc   set;
+  SwigMagicFunc   get;
+  swig_type_info  **type;
+} swig_variable_info;
+
+/* Magic variable code */
+#ifndef PERL_OBJECT
+#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c)
+  #ifndef MULTIPLICITY
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) 
+  #else
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) 
+  #endif
+#else
+#  define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c)
+SWIGRUNTIME void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) 
+#endif
+{
+  MAGIC *mg;
+  sv_magic(sv,sv,'U',(char *) name,strlen(name));
+  mg = mg_find(sv,'U');
+  mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
+  mg->mg_virtual->svt_get = (SwigMagicFunc) get;
+  mg->mg_virtual->svt_set = (SwigMagicFunc) set;
+  mg->mg_virtual->svt_len = 0;
+  mg->mg_virtual->svt_clear = 0;
+  mg->mg_virtual->svt_free = 0;
+}
+
+
+SWIGRUNTIME swig_module_info *
+SWIG_Perl_GetModule(void) {
+  static void *type_pointer = (void *)0;
+  SV *pointer;
+
+  /* first check if pointer already created */
+  if (!type_pointer) {
+    pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE);
+    if (pointer && SvOK(pointer)) {
+      type_pointer = INT2PTR(swig_type_info **, SvIV(pointer));
+    }
+  }
+
+  return (swig_module_info *) type_pointer;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_SetModule(swig_module_info *module) {
+  SV *pointer;
+
+  /* create a new pointer */
+  pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE);
+  sv_setiv(pointer, PTR2IV(module));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Workaround perl5 global namespace pollution. Note that undefining library
+ * functions like fopen will not solve the problem on all platforms as fopen
+ * might be a macro on Windows but not necessarily on other operating systems. */
+#ifdef do_open
+  #undef do_open
+#endif
+#ifdef do_close
+  #undef do_close
+#endif
+#ifdef scalar
+  #undef scalar
+#endif
+#ifdef list
+  #undef list
+#endif
+#ifdef apply
+  #undef apply
+#endif
+#ifdef convert
+  #undef convert
+#endif
+#ifdef Error
+  #undef Error
+#endif
+#ifdef form
+  #undef form
+#endif
+#ifdef vform
+  #undef vform
+#endif
+#ifdef LABEL
+  #undef LABEL
+#endif
+#ifdef METHOD
+  #undef METHOD
+#endif
+#ifdef Move
+  #undef Move
+#endif
+#ifdef yylex
+  #undef yylex
+#endif
+#ifdef yyparse
+  #undef yyparse
+#endif
+#ifdef yyerror
+  #undef yyerror
+#endif
+#ifdef invert
+  #undef invert
+#endif
+#ifdef ref
+  #undef ref
+#endif
+#ifdef read
+  #undef read
+#endif
+#ifdef write
+  #undef write
+#endif
+#ifdef eof
+  #undef eof
+#endif
+#ifdef bool
+  #undef bool
+#endif
+#ifdef close
+  #undef close
+#endif
+#ifdef rewind
+  #undef rewind
+#endif
+#ifdef free
+  #undef free
+#endif
+#ifdef malloc
+  #undef malloc
+#endif
+#ifdef calloc
+  #undef calloc
+#endif
+#ifdef Stat
+  #undef Stat
+#endif
+#ifdef check
+  #undef check
+#endif
+#ifdef seekdir
+  #undef seekdir
+#endif
+#ifdef open
+  #undef open
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) 
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else 
+
+
+
+  #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) 
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_char swig_types[0]
+#define SWIGTYPE_p_config_overwrites_t swig_types[1]
+#define SWIGTYPE_p_double swig_types[2]
+#define SWIGTYPE_p_dumptype_t swig_types[3]
+#define SWIGTYPE_p_float swig_types[4]
+#define SWIGTYPE_p_holdingdisk_t swig_types[5]
+#define SWIGTYPE_p_int swig_types[6]
+#define SWIGTYPE_p_interface_t swig_types[7]
+#define SWIGTYPE_p_p_char swig_types[8]
+#define SWIGTYPE_p_tapetype_t swig_types[9]
+#define SWIGTYPE_p_unsigned_char swig_types[10]
+static swig_type_info *swig_types[12];
+static swig_module_info swig_module = {swig_types, 11, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init    boot_Amanda__Config
+
+#define SWIG_name   "Amanda::Configc::boot_Amanda__Config"
+#define SWIG_prefix "Amanda::Configc::"
+
+#define SWIGVERSION 0x010333 
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a)) 
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) 
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifndef PERL_OBJECT
+#ifndef MULTIPLICITY
+SWIGEXPORT void SWIG_init (CV* cv);
+#else
+SWIGEXPORT void SWIG_init (pTHXo_ CV* cv);
+#endif
+#else
+SWIGEXPORT void SWIG_init (CV *cv, CPerlObj *);
+#endif
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "conffile.h"
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_long  SWIG_PERL_DECL_ARGS_1(long value)
+{    
+  SV *obj = sv_newmortal();
+  sv_setiv(obj, (IV) value);
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_int  SWIG_PERL_DECL_ARGS_1(int value)
+{    
+  return SWIG_From_long  SWIG_PERL_CALL_ARGS_1(value);
+}
+
+
+#include <limits.h>
+#if !defined(SWIG_NO_LLONG_MAX)
+# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__)
+#   define LLONG_MAX __LONG_LONG_MAX__
+#   define LLONG_MIN (-LLONG_MAX - 1LL)
+#   define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+# endif
+#endif
+
+
+SWIGINTERN int
+SWIG_AsVal_double SWIG_PERL_DECL_ARGS_2(SV *obj, double *val)
+{
+  if (SvNIOK(obj)) {
+    if (val) *val = SvNV(obj);
+    return SWIG_OK;
+  } else if (SvIOK(obj)) {
+    if (val) *val = (double) SvIV(obj);
+    return SWIG_AddCast(SWIG_OK);
+  } else {
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      double v = strtod(nptr, &endptr);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+#include <float.h>
+
+
+#include <math.h>
+
+
+SWIGINTERNINLINE int
+SWIG_CanCastAsInteger(double *d, double min, double max) {
+  double x = *d;
+  if ((min <= x && x <= max)) {
+   double fx = floor(x);
+   double cx = ceil(x);
+   double rd =  ((x - fx) < 0.5) ? fx : cx; /* simple rint */
+   if ((errno == EDOM) || (errno == ERANGE)) {
+     errno = 0;
+   } else {
+     double summ, reps, diff;
+     if (rd < x) {
+       diff = x - rd;
+     } else if (rd > x) {
+       diff = rd - x;
+     } else {
+       return 1;
+     }
+     summ = rd + x;
+     reps = diff/summ;
+     if (reps < 8*DBL_EPSILON) {
+       *d = rd;
+       return 1;
+     }
+   }
+  }
+  return 0;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_long SWIG_PERL_DECL_ARGS_2(SV *obj, long* val)
+{
+  if (SvIOK(obj)) {
+    if (val) *val = SvIV(obj);
+    return SWIG_OK;
+  } else {
+    int dispatch = 0;
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      long v;
+      errno = 0;
+      v = strtol(nptr, &endptr,0);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+    if (!dispatch) {
+      double d;
+      int res = SWIG_AddCast(SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj,&d));
+      if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
+       if (val) *val = (long)(d);
+       return res;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_int SWIG_PERL_DECL_ARGS_2(SV * obj, int *val)
+{
+  long v;
+  int res = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v < INT_MIN || v > INT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = (int)(v);
+    }
+  }  
+  return res;
+}
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+  static int init = 0;
+  static swig_type_info* info = 0;
+  if (!init) {
+    info = SWIG_TypeQuery("_p_char");
+    init = 1;
+  }
+  return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(SV *obj, char** cptr, size_t* psize, int *alloc)
+{
+  if (SvPOK(obj)) {
+    STRLEN len = 0;
+    char *cstr = SvPV(obj, len); 
+    size_t size = len + 1;
+    if (cptr)  {
+      if (alloc) {
+       if (*alloc == SWIG_NEWOBJ) {
+         *cptr = (char *)memcpy((char *)malloc((size)*sizeof(char)), cstr, sizeof(char)*(size));
+       } else {
+         *cptr = cstr;
+         *alloc = SWIG_OLDOBJ;
+       }
+      }
+    }
+    if (psize) *psize = size;
+    return SWIG_OK;
+  } else {
+    swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+    if (pchar_descriptor) {
+      char* vptr = 0; 
+      if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_descriptor, 0) == SWIG_OK) {
+       if (cptr) *cptr = vptr;
+       if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0;
+       if (alloc) *alloc = SWIG_OLDOBJ;
+       return SWIG_OK;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+
+
+
+SWIGINTERNINLINE SV *
+SWIG_FromCharPtrAndSize(const char* carray, size_t size)
+{
+  SV *obj = sv_newmortal();
+  if (carray) {
+    sv_setpvn(obj, carray, size);
+  } else {
+    sv_setsv(obj, &PL_sv_undef);
+  }
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV * 
+SWIG_FromCharPtr(const char *cptr)
+{ 
+  return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0));
+}
+
+
+    char *get_config_name(void) { return config_name; }
+    char *get_config_dir(void) { return config_dir; }
+    char *get_config_filename(void) { return config_filename; }
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef PERL_OBJECT
+#define MAGIC_CLASS _wrap_Amanda::Config_var::
+class _wrap_Amanda::Config_var : public CPerlObj {
+public:
+#else
+#define MAGIC_CLASS
+#endif
+SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {
+    MAGIC_PPERL
+    croak("Value is read-only.");
+    return 0;
+}
+SWIGCLASS_STATIC int _wrap_debug_amandad_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_amandad""' of type '""int""'");
+    }
+    debug_amandad = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_amandad_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_amandad)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_amidxtaped_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_amidxtaped""' of type '""int""'");
+    }
+    debug_amidxtaped = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_amidxtaped_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_amidxtaped)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_amindexd_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_amindexd""' of type '""int""'");
+    }
+    debug_amindexd = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_amindexd_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_amindexd)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_amrecover_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_amrecover""' of type '""int""'");
+    }
+    debug_amrecover = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_amrecover_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_amrecover)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_auth_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_auth""' of type '""int""'");
+    }
+    debug_auth = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_auth_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_auth)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_event_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_event""' of type '""int""'");
+    }
+    debug_event = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_event_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_event)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_holding_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_holding""' of type '""int""'");
+    }
+    debug_holding = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_holding_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_holding)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_protocol_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_protocol""' of type '""int""'");
+    }
+    debug_protocol = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_protocol_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_protocol)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_planner_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_planner""' of type '""int""'");
+    }
+    debug_planner = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_planner_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_planner)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_driver_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_driver""' of type '""int""'");
+    }
+    debug_driver = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_driver_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_driver)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_dumper_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_dumper""' of type '""int""'");
+    }
+    debug_dumper = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_dumper_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_dumper)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_chunker_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_chunker""' of type '""int""'");
+    }
+    debug_chunker = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_chunker_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_chunker)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_taper_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_taper""' of type '""int""'");
+    }
+    debug_taper = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_taper_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_taper)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_selfcheck_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_selfcheck""' of type '""int""'");
+    }
+    debug_selfcheck = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_selfcheck_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_selfcheck)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_sendsize_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_sendsize""' of type '""int""'");
+    }
+    debug_sendsize = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_sendsize_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_sendsize)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_sendbackup_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""debug_sendbackup""' of type '""int""'");
+    }
+    debug_sendbackup = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_debug_sendbackup_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(debug_sendbackup)))  ;
+  return 1;
+}
+
+
+
+
+#ifdef PERL_OBJECT
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+XS(_wrap_getconf) {
+  {
+    confparm_key arg1 ;
+    val_t *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: getconf(key);");
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg1 = amglue_SvI8(ST(0));
+      } else if (sizeof(signed int) == 2) {
+        arg1 = amglue_SvI16(ST(0));
+      } else if (sizeof(signed int) == 4) {
+        arg1 = amglue_SvI32(ST(0));
+      } else if (sizeof(signed int) == 8) {
+        arg1 = amglue_SvI64(ST(0));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (val_t *)getconf(arg1);
+    {
+      switch (result->type) {
+        case CONFTYPE_RATE: {
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[1]);
+          argvi++;
+          break;
+        }
+        
+        case CONFTYPE_INTRANGE: {
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[1]);
+          argvi++;
+          break;
+          break;
+        }
+        
+        case CONFTYPE_EXINCLUDE: {
+          /* exincludes are represented in perl as {
+                    *  'list' : [ 'list1', 'list2', ..],
+                    *  'file' : [ 'file1', 'file2', ..],
+                    *  'optional' : 1,
+                    * }
+                    */
+          exinclude_t *ei = &val_t__exinclude(result);
+          AV *list_entries = (AV *)sv_2mortal((SV *)newAV());
+          AV *file_entries = (AV *)sv_2mortal((SV *)newAV());
+          SV *optional = sv_newmortal();
+          HV *hv;
+          sle_t *iter;
+          
+          /* first set up each of the hash values */
+          
+          if (ei->sl_list) {
+            for (iter = ei->sl_list->first; iter != NULL; iter = iter->next) {
+              av_push(list_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          if(ei->sl_file) {
+            for (iter = ei->sl_file->first; iter != NULL; iter = iter->next) {
+              av_push(file_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          sv_setiv(optional, ei->optional);
+          
+          /* now build the hash */
+          hv = (HV *)sv_2mortal((SV *)newHV());
+          
+          hv_store(hv, "file", 4, newRV((SV *)file_entries), 0);
+          hv_store(hv, "list", 4, newRV((SV *)list_entries), 0);
+          hv_store(hv, "optional", 8, optional, 0);
+          SvREFCNT_inc(optional);
+          
+          ST(argvi) = sv_2mortal(newRV((SV *)hv));
+          argvi++;
+          break;
+        }
+        
+      case CONFTYPE_PROPLIST:
+        ST(argvi) = sv_2mortal(g_hash_table_to_hashref(val_t__proplist(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_SIZE:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__size(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_AM64:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__am64(result)));
+        argvi++;
+        break;
+        
+        case CONFTYPE_BOOLEAN:     /* all same as INT.. */
+      case CONFTYPE_COMPRESS:
+      case CONFTYPE_ENCRYPT:
+      case CONFTYPE_ESTIMATE:
+      case CONFTYPE_STRATEGY:
+      case CONFTYPE_TAPERALGO:
+      case CONFTYPE_PRIORITY:
+      case CONFTYPE_HOLDING:
+      case CONFTYPE_INT:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__int(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_TIME:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__time(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_REAL:
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), val_t__real(result));
+        argvi++;
+        break;
+        
+        case CONFTYPE_IDENT:       /* same as STRING */
+      case CONFTYPE_STR:
+        ST(argvi) = sv_newmortal();
+        sv_setpv(ST(argvi), val_t__str(result));
+        argvi++;
+        break;
+        
+        /* No match yet -> not one of the "complex" types */
+      default:
+        SWIG_exception(SWIG_TypeError, "Unknown val_t conftype");
+        break;
+      }
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_getconf_seen) {
+  {
+    confparm_key arg1 ;
+    gboolean result;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: getconf_seen(key);");
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg1 = amglue_SvI8(ST(0));
+      } else if (sizeof(signed int) == 2) {
+        arg1 = amglue_SvI16(ST(0));
+      } else if (sizeof(signed int) == 4) {
+        arg1 = amglue_SvI32(ST(0));
+      } else if (sizeof(signed int) == 8) {
+        arg1 = amglue_SvI64(ST(0));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)getconf_seen(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_getconf_byname) {
+  {
+    char *arg1 = (char *) 0 ;
+    val_t *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: getconf_byname(key);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "getconf_byname" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (val_t *)getconf_byname(arg1);
+    {
+      switch (result->type) {
+        case CONFTYPE_RATE: {
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[1]);
+          argvi++;
+          break;
+        }
+        
+        case CONFTYPE_INTRANGE: {
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[1]);
+          argvi++;
+          break;
+          break;
+        }
+        
+        case CONFTYPE_EXINCLUDE: {
+          /* exincludes are represented in perl as {
+                    *  'list' : [ 'list1', 'list2', ..],
+                    *  'file' : [ 'file1', 'file2', ..],
+                    *  'optional' : 1,
+                    * }
+                    */
+          exinclude_t *ei = &val_t__exinclude(result);
+          AV *list_entries = (AV *)sv_2mortal((SV *)newAV());
+          AV *file_entries = (AV *)sv_2mortal((SV *)newAV());
+          SV *optional = sv_newmortal();
+          HV *hv;
+          sle_t *iter;
+          
+          /* first set up each of the hash values */
+          
+          if (ei->sl_list) {
+            for (iter = ei->sl_list->first; iter != NULL; iter = iter->next) {
+              av_push(list_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          if(ei->sl_file) {
+            for (iter = ei->sl_file->first; iter != NULL; iter = iter->next) {
+              av_push(file_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          sv_setiv(optional, ei->optional);
+          
+          /* now build the hash */
+          hv = (HV *)sv_2mortal((SV *)newHV());
+          
+          hv_store(hv, "file", 4, newRV((SV *)file_entries), 0);
+          hv_store(hv, "list", 4, newRV((SV *)list_entries), 0);
+          hv_store(hv, "optional", 8, optional, 0);
+          SvREFCNT_inc(optional);
+          
+          ST(argvi) = sv_2mortal(newRV((SV *)hv));
+          argvi++;
+          break;
+        }
+        
+      case CONFTYPE_PROPLIST:
+        ST(argvi) = sv_2mortal(g_hash_table_to_hashref(val_t__proplist(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_SIZE:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__size(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_AM64:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__am64(result)));
+        argvi++;
+        break;
+        
+        case CONFTYPE_BOOLEAN:     /* all same as INT.. */
+      case CONFTYPE_COMPRESS:
+      case CONFTYPE_ENCRYPT:
+      case CONFTYPE_ESTIMATE:
+      case CONFTYPE_STRATEGY:
+      case CONFTYPE_TAPERALGO:
+      case CONFTYPE_PRIORITY:
+      case CONFTYPE_HOLDING:
+      case CONFTYPE_INT:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__int(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_TIME:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__time(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_REAL:
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), val_t__real(result));
+        argvi++;
+        break;
+        
+        case CONFTYPE_IDENT:       /* same as STRING */
+      case CONFTYPE_STR:
+        ST(argvi) = sv_newmortal();
+        sv_setpv(ST(argvi), val_t__str(result));
+        argvi++;
+        break;
+        
+        /* No match yet -> not one of the "complex" types */
+      default:
+        SWIG_exception(SWIG_TypeError, "Unknown val_t conftype");
+        break;
+      }
+    }
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_getconf_list) {
+  {
+    char *arg1 = (char *) 0 ;
+    GSList *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: getconf_list(listname);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "getconf_list" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (GSList *)getconf_list(arg1);
+    {
+      GSList *it = result;
+      
+      while (it) {
+        ST(argvi) = sv_2mortal(newSVpv(it->data, 0));
+        argvi++;
+        it = it->next;
+      }
+      
+      g_slist_free(result);
+    }
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_lookup_tapetype) {
+  {
+    char *arg1 = (char *) 0 ;
+    tapetype_t *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: lookup_tapetype(identifier);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "lookup_tapetype" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (tapetype_t *)lookup_tapetype(arg1);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_tapetype_t, 0 | 0); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_tapetype_getconf) {
+  {
+    tapetype_t *arg1 = (tapetype_t *) 0 ;
+    tapetype_key arg2 ;
+    val_t *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: tapetype_getconf(ttyp,key);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_tapetype_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "tapetype_getconf" "', argument " "1"" of type '" "tapetype_t *""'"); 
+    }
+    arg1 = (tapetype_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (val_t *)tapetype_getconf(arg1,arg2);
+    {
+      switch (result->type) {
+        case CONFTYPE_RATE: {
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[1]);
+          argvi++;
+          break;
+        }
+        
+        case CONFTYPE_INTRANGE: {
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[1]);
+          argvi++;
+          break;
+          break;
+        }
+        
+        case CONFTYPE_EXINCLUDE: {
+          /* exincludes are represented in perl as {
+                    *  'list' : [ 'list1', 'list2', ..],
+                    *  'file' : [ 'file1', 'file2', ..],
+                    *  'optional' : 1,
+                    * }
+                    */
+          exinclude_t *ei = &val_t__exinclude(result);
+          AV *list_entries = (AV *)sv_2mortal((SV *)newAV());
+          AV *file_entries = (AV *)sv_2mortal((SV *)newAV());
+          SV *optional = sv_newmortal();
+          HV *hv;
+          sle_t *iter;
+          
+          /* first set up each of the hash values */
+          
+          if (ei->sl_list) {
+            for (iter = ei->sl_list->first; iter != NULL; iter = iter->next) {
+              av_push(list_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          if(ei->sl_file) {
+            for (iter = ei->sl_file->first; iter != NULL; iter = iter->next) {
+              av_push(file_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          sv_setiv(optional, ei->optional);
+          
+          /* now build the hash */
+          hv = (HV *)sv_2mortal((SV *)newHV());
+          
+          hv_store(hv, "file", 4, newRV((SV *)file_entries), 0);
+          hv_store(hv, "list", 4, newRV((SV *)list_entries), 0);
+          hv_store(hv, "optional", 8, optional, 0);
+          SvREFCNT_inc(optional);
+          
+          ST(argvi) = sv_2mortal(newRV((SV *)hv));
+          argvi++;
+          break;
+        }
+        
+      case CONFTYPE_PROPLIST:
+        ST(argvi) = sv_2mortal(g_hash_table_to_hashref(val_t__proplist(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_SIZE:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__size(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_AM64:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__am64(result)));
+        argvi++;
+        break;
+        
+        case CONFTYPE_BOOLEAN:     /* all same as INT.. */
+      case CONFTYPE_COMPRESS:
+      case CONFTYPE_ENCRYPT:
+      case CONFTYPE_ESTIMATE:
+      case CONFTYPE_STRATEGY:
+      case CONFTYPE_TAPERALGO:
+      case CONFTYPE_PRIORITY:
+      case CONFTYPE_HOLDING:
+      case CONFTYPE_INT:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__int(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_TIME:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__time(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_REAL:
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), val_t__real(result));
+        argvi++;
+        break;
+        
+        case CONFTYPE_IDENT:       /* same as STRING */
+      case CONFTYPE_STR:
+        ST(argvi) = sv_newmortal();
+        sv_setpv(ST(argvi), val_t__str(result));
+        argvi++;
+        break;
+        
+        /* No match yet -> not one of the "complex" types */
+      default:
+        SWIG_exception(SWIG_TypeError, "Unknown val_t conftype");
+        break;
+      }
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_tapetype_name) {
+  {
+    tapetype_t *arg1 = (tapetype_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: tapetype_name(ttyp);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_tapetype_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "tapetype_name" "', argument " "1"" of type '" "tapetype_t *""'"); 
+    }
+    arg1 = (tapetype_t *)(argp1);
+    result = (char *)tapetype_name(arg1);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_tapetype_seen) {
+  {
+    tapetype_t *arg1 = (tapetype_t *) 0 ;
+    tapetype_key arg2 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: tapetype_seen(ttyp,key);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_tapetype_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "tapetype_seen" "', argument " "1"" of type '" "tapetype_t *""'"); 
+    }
+    arg1 = (tapetype_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)tapetype_seen(arg1,arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_lookup_dumptype) {
+  {
+    char *arg1 = (char *) 0 ;
+    dumptype_t *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: lookup_dumptype(identifier);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "lookup_dumptype" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (dumptype_t *)lookup_dumptype(arg1);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_dumptype_t, 0 | 0); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumptype_getconf) {
+  {
+    dumptype_t *arg1 = (dumptype_t *) 0 ;
+    dumptype_key arg2 ;
+    val_t *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumptype_getconf(dtyp,key);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumptype_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumptype_getconf" "', argument " "1"" of type '" "dumptype_t *""'"); 
+    }
+    arg1 = (dumptype_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (val_t *)dumptype_getconf(arg1,arg2);
+    {
+      switch (result->type) {
+        case CONFTYPE_RATE: {
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[1]);
+          argvi++;
+          break;
+        }
+        
+        case CONFTYPE_INTRANGE: {
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[1]);
+          argvi++;
+          break;
+          break;
+        }
+        
+        case CONFTYPE_EXINCLUDE: {
+          /* exincludes are represented in perl as {
+                    *  'list' : [ 'list1', 'list2', ..],
+                    *  'file' : [ 'file1', 'file2', ..],
+                    *  'optional' : 1,
+                    * }
+                    */
+          exinclude_t *ei = &val_t__exinclude(result);
+          AV *list_entries = (AV *)sv_2mortal((SV *)newAV());
+          AV *file_entries = (AV *)sv_2mortal((SV *)newAV());
+          SV *optional = sv_newmortal();
+          HV *hv;
+          sle_t *iter;
+          
+          /* first set up each of the hash values */
+          
+          if (ei->sl_list) {
+            for (iter = ei->sl_list->first; iter != NULL; iter = iter->next) {
+              av_push(list_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          if(ei->sl_file) {
+            for (iter = ei->sl_file->first; iter != NULL; iter = iter->next) {
+              av_push(file_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          sv_setiv(optional, ei->optional);
+          
+          /* now build the hash */
+          hv = (HV *)sv_2mortal((SV *)newHV());
+          
+          hv_store(hv, "file", 4, newRV((SV *)file_entries), 0);
+          hv_store(hv, "list", 4, newRV((SV *)list_entries), 0);
+          hv_store(hv, "optional", 8, optional, 0);
+          SvREFCNT_inc(optional);
+          
+          ST(argvi) = sv_2mortal(newRV((SV *)hv));
+          argvi++;
+          break;
+        }
+        
+      case CONFTYPE_PROPLIST:
+        ST(argvi) = sv_2mortal(g_hash_table_to_hashref(val_t__proplist(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_SIZE:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__size(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_AM64:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__am64(result)));
+        argvi++;
+        break;
+        
+        case CONFTYPE_BOOLEAN:     /* all same as INT.. */
+      case CONFTYPE_COMPRESS:
+      case CONFTYPE_ENCRYPT:
+      case CONFTYPE_ESTIMATE:
+      case CONFTYPE_STRATEGY:
+      case CONFTYPE_TAPERALGO:
+      case CONFTYPE_PRIORITY:
+      case CONFTYPE_HOLDING:
+      case CONFTYPE_INT:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__int(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_TIME:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__time(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_REAL:
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), val_t__real(result));
+        argvi++;
+        break;
+        
+        case CONFTYPE_IDENT:       /* same as STRING */
+      case CONFTYPE_STR:
+        ST(argvi) = sv_newmortal();
+        sv_setpv(ST(argvi), val_t__str(result));
+        argvi++;
+        break;
+        
+        /* No match yet -> not one of the "complex" types */
+      default:
+        SWIG_exception(SWIG_TypeError, "Unknown val_t conftype");
+        break;
+      }
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumptype_name) {
+  {
+    dumptype_t *arg1 = (dumptype_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumptype_name(dtyp);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumptype_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumptype_name" "', argument " "1"" of type '" "dumptype_t *""'"); 
+    }
+    arg1 = (dumptype_t *)(argp1);
+    result = (char *)dumptype_name(arg1);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumptype_seen) {
+  {
+    dumptype_t *arg1 = (dumptype_t *) 0 ;
+    dumptype_key arg2 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumptype_seen(dtyp,key);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumptype_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumptype_seen" "', argument " "1"" of type '" "dumptype_t *""'"); 
+    }
+    arg1 = (dumptype_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)dumptype_seen(arg1,arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_lookup_interface) {
+  {
+    char *arg1 = (char *) 0 ;
+    interface_t *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: lookup_interface(identifier);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "lookup_interface" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (interface_t *)lookup_interface(arg1);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_interface_t, 0 | 0); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_interface_getconf) {
+  {
+    interface_t *arg1 = (interface_t *) 0 ;
+    interface_key arg2 ;
+    val_t *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: interface_getconf(iface,key);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_interface_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "interface_getconf" "', argument " "1"" of type '" "interface_t *""'"); 
+    }
+    arg1 = (interface_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (val_t *)interface_getconf(arg1,arg2);
+    {
+      switch (result->type) {
+        case CONFTYPE_RATE: {
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[1]);
+          argvi++;
+          break;
+        }
+        
+        case CONFTYPE_INTRANGE: {
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[1]);
+          argvi++;
+          break;
+          break;
+        }
+        
+        case CONFTYPE_EXINCLUDE: {
+          /* exincludes are represented in perl as {
+                    *  'list' : [ 'list1', 'list2', ..],
+                    *  'file' : [ 'file1', 'file2', ..],
+                    *  'optional' : 1,
+                    * }
+                    */
+          exinclude_t *ei = &val_t__exinclude(result);
+          AV *list_entries = (AV *)sv_2mortal((SV *)newAV());
+          AV *file_entries = (AV *)sv_2mortal((SV *)newAV());
+          SV *optional = sv_newmortal();
+          HV *hv;
+          sle_t *iter;
+          
+          /* first set up each of the hash values */
+          
+          if (ei->sl_list) {
+            for (iter = ei->sl_list->first; iter != NULL; iter = iter->next) {
+              av_push(list_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          if(ei->sl_file) {
+            for (iter = ei->sl_file->first; iter != NULL; iter = iter->next) {
+              av_push(file_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          sv_setiv(optional, ei->optional);
+          
+          /* now build the hash */
+          hv = (HV *)sv_2mortal((SV *)newHV());
+          
+          hv_store(hv, "file", 4, newRV((SV *)file_entries), 0);
+          hv_store(hv, "list", 4, newRV((SV *)list_entries), 0);
+          hv_store(hv, "optional", 8, optional, 0);
+          SvREFCNT_inc(optional);
+          
+          ST(argvi) = sv_2mortal(newRV((SV *)hv));
+          argvi++;
+          break;
+        }
+        
+      case CONFTYPE_PROPLIST:
+        ST(argvi) = sv_2mortal(g_hash_table_to_hashref(val_t__proplist(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_SIZE:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__size(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_AM64:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__am64(result)));
+        argvi++;
+        break;
+        
+        case CONFTYPE_BOOLEAN:     /* all same as INT.. */
+      case CONFTYPE_COMPRESS:
+      case CONFTYPE_ENCRYPT:
+      case CONFTYPE_ESTIMATE:
+      case CONFTYPE_STRATEGY:
+      case CONFTYPE_TAPERALGO:
+      case CONFTYPE_PRIORITY:
+      case CONFTYPE_HOLDING:
+      case CONFTYPE_INT:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__int(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_TIME:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__time(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_REAL:
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), val_t__real(result));
+        argvi++;
+        break;
+        
+        case CONFTYPE_IDENT:       /* same as STRING */
+      case CONFTYPE_STR:
+        ST(argvi) = sv_newmortal();
+        sv_setpv(ST(argvi), val_t__str(result));
+        argvi++;
+        break;
+        
+        /* No match yet -> not one of the "complex" types */
+      default:
+        SWIG_exception(SWIG_TypeError, "Unknown val_t conftype");
+        break;
+      }
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_interface_name) {
+  {
+    interface_t *arg1 = (interface_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: interface_name(iface);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_interface_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "interface_name" "', argument " "1"" of type '" "interface_t *""'"); 
+    }
+    arg1 = (interface_t *)(argp1);
+    result = (char *)interface_name(arg1);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_interface_seen) {
+  {
+    interface_t *arg1 = (interface_t *) 0 ;
+    interface_key arg2 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: interface_seen(iface,key);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_interface_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "interface_seen" "', argument " "1"" of type '" "interface_t *""'"); 
+    }
+    arg1 = (interface_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)interface_seen(arg1,arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_lookup_holdingdisk) {
+  {
+    char *arg1 = (char *) 0 ;
+    holdingdisk_t *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: lookup_holdingdisk(identifier);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "lookup_holdingdisk" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (holdingdisk_t *)lookup_holdingdisk(arg1);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_holdingdisk_t, 0 | 0); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_getconf_holdingdisks) {
+  {
+    holdingdisk_t *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: getconf_holdingdisks();");
+    }
+    result = (holdingdisk_t *)getconf_holdingdisks();
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_holdingdisk_t, 0 | 0); argvi++ ;
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_holdingdisk_next) {
+  {
+    holdingdisk_t *arg1 = (holdingdisk_t *) 0 ;
+    holdingdisk_t *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: holdingdisk_next(hdisk);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_holdingdisk_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "holdingdisk_next" "', argument " "1"" of type '" "holdingdisk_t *""'"); 
+    }
+    arg1 = (holdingdisk_t *)(argp1);
+    result = (holdingdisk_t *)holdingdisk_next(arg1);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_holdingdisk_t, 0 | 0); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_holdingdisk_getconf) {
+  {
+    holdingdisk_t *arg1 = (holdingdisk_t *) 0 ;
+    holdingdisk_key arg2 ;
+    val_t *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: holdingdisk_getconf(hdisk,key);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_holdingdisk_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "holdingdisk_getconf" "', argument " "1"" of type '" "holdingdisk_t *""'"); 
+    }
+    arg1 = (holdingdisk_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (val_t *)holdingdisk_getconf(arg1,arg2);
+    {
+      switch (result->type) {
+        case CONFTYPE_RATE: {
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setnv(ST(argvi), val_t__rate(result)[1]);
+          argvi++;
+          break;
+        }
+        
+        case CONFTYPE_INTRANGE: {
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[0]);
+          argvi++;
+          
+          ST(argvi)= sv_newmortal();
+          sv_setiv(ST(argvi), val_t__intrange(result)[1]);
+          argvi++;
+          break;
+          break;
+        }
+        
+        case CONFTYPE_EXINCLUDE: {
+          /* exincludes are represented in perl as {
+                    *  'list' : [ 'list1', 'list2', ..],
+                    *  'file' : [ 'file1', 'file2', ..],
+                    *  'optional' : 1,
+                    * }
+                    */
+          exinclude_t *ei = &val_t__exinclude(result);
+          AV *list_entries = (AV *)sv_2mortal((SV *)newAV());
+          AV *file_entries = (AV *)sv_2mortal((SV *)newAV());
+          SV *optional = sv_newmortal();
+          HV *hv;
+          sle_t *iter;
+          
+          /* first set up each of the hash values */
+          
+          if (ei->sl_list) {
+            for (iter = ei->sl_list->first; iter != NULL; iter = iter->next) {
+              av_push(list_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          if(ei->sl_file) {
+            for (iter = ei->sl_file->first; iter != NULL; iter = iter->next) {
+              av_push(file_entries, newSVpv(iter->name, 0));
+            }
+          }
+          
+          sv_setiv(optional, ei->optional);
+          
+          /* now build the hash */
+          hv = (HV *)sv_2mortal((SV *)newHV());
+          
+          hv_store(hv, "file", 4, newRV((SV *)file_entries), 0);
+          hv_store(hv, "list", 4, newRV((SV *)list_entries), 0);
+          hv_store(hv, "optional", 8, optional, 0);
+          SvREFCNT_inc(optional);
+          
+          ST(argvi) = sv_2mortal(newRV((SV *)hv));
+          argvi++;
+          break;
+        }
+        
+      case CONFTYPE_PROPLIST:
+        ST(argvi) = sv_2mortal(g_hash_table_to_hashref(val_t__proplist(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_SIZE:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__size(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_AM64:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__am64(result)));
+        argvi++;
+        break;
+        
+        case CONFTYPE_BOOLEAN:     /* all same as INT.. */
+      case CONFTYPE_COMPRESS:
+      case CONFTYPE_ENCRYPT:
+      case CONFTYPE_ESTIMATE:
+      case CONFTYPE_STRATEGY:
+      case CONFTYPE_TAPERALGO:
+      case CONFTYPE_PRIORITY:
+      case CONFTYPE_HOLDING:
+      case CONFTYPE_INT:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__int(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_TIME:
+        ST(argvi) = sv_2mortal(amglue_newSVi64(val_t__time(result)));
+        argvi++;
+        break;
+        
+      case CONFTYPE_REAL:
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), val_t__real(result));
+        argvi++;
+        break;
+        
+        case CONFTYPE_IDENT:       /* same as STRING */
+      case CONFTYPE_STR:
+        ST(argvi) = sv_newmortal();
+        sv_setpv(ST(argvi), val_t__str(result));
+        argvi++;
+        break;
+        
+        /* No match yet -> not one of the "complex" types */
+      default:
+        SWIG_exception(SWIG_TypeError, "Unknown val_t conftype");
+        break;
+      }
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_holdingdisk_name) {
+  {
+    holdingdisk_t *arg1 = (holdingdisk_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: holdingdisk_name(hdisk);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_holdingdisk_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "holdingdisk_name" "', argument " "1"" of type '" "holdingdisk_t *""'"); 
+    }
+    arg1 = (holdingdisk_t *)(argp1);
+    result = (char *)holdingdisk_name(arg1);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_holdingdisk_seen) {
+  {
+    holdingdisk_t *arg1 = (holdingdisk_t *) 0 ;
+    holdingdisk_key arg2 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: holdingdisk_seen(hdisk,key);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_holdingdisk_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "holdingdisk_seen" "', argument " "1"" of type '" "holdingdisk_t *""'"); 
+    }
+    arg1 = (holdingdisk_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)holdingdisk_seen(arg1,arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_getconf_unit_divisor) {
+  {
+    long result;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: getconf_unit_divisor();");
+    }
+    result = (long)getconf_unit_divisor();
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_new_config_overwrites) {
+  {
+    int arg1 ;
+    config_overwrites_t *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: new_config_overwrites(size_estimate);");
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg1 = amglue_SvI8(ST(0));
+      } else if (sizeof(signed int) == 2) {
+        arg1 = amglue_SvI16(ST(0));
+      } else if (sizeof(signed int) == 4) {
+        arg1 = amglue_SvI32(ST(0));
+      } else if (sizeof(signed int) == 8) {
+        arg1 = amglue_SvI64(ST(0));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (config_overwrites_t *)new_config_overwrites(arg1);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_config_overwrites_t, 0 | 0); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_free_config_overwrites) {
+  {
+    config_overwrites_t *arg1 = (config_overwrites_t *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: free_config_overwrites(co);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_config_overwrites_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "free_config_overwrites" "', argument " "1"" of type '" "config_overwrites_t *""'"); 
+    }
+    arg1 = (config_overwrites_t *)(argp1);
+    free_config_overwrites(arg1);
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_add_config_overwrite) {
+  {
+    config_overwrites_t *arg1 = (config_overwrites_t *) 0 ;
+    char *arg2 = (char *) 0 ;
+    char *arg3 = (char *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int res3 ;
+    char *buf3 = 0 ;
+    int alloc3 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 3) || (items > 3)) {
+      SWIG_croak("Usage: add_config_overwrite(co,key,value);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_config_overwrites_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "add_config_overwrite" "', argument " "1"" of type '" "config_overwrites_t *""'"); 
+    }
+    arg1 = (config_overwrites_t *)(argp1);
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "add_config_overwrite" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    res3 = SWIG_AsCharPtrAndSize(ST(2), &buf3, NULL, &alloc3);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "add_config_overwrite" "', argument " "3"" of type '" "char *""'");
+    }
+    arg3 = (char *)(buf3);
+    add_config_overwrite(arg1,arg2,arg3);
+    
+    
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    XSRETURN(argvi);
+  fail:
+    
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_add_config_overwrite_opt) {
+  {
+    config_overwrites_t *arg1 = (config_overwrites_t *) 0 ;
+    char *arg2 = (char *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: add_config_overwrite_opt(co,optarg);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_config_overwrites_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "add_config_overwrite_opt" "', argument " "1"" of type '" "config_overwrites_t *""'"); 
+    }
+    arg1 = (config_overwrites_t *)(argp1);
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "add_config_overwrite_opt" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    add_config_overwrite_opt(arg1,arg2);
+    
+    
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    XSRETURN(argvi);
+  fail:
+    
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_apply_config_overwrites) {
+  {
+    config_overwrites_t *arg1 = (config_overwrites_t *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: apply_config_overwrites(co);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_config_overwrites_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "apply_config_overwrites" "', argument " "1"" of type '" "config_overwrites_t *""'"); 
+    }
+    arg1 = (config_overwrites_t *)(argp1);
+    apply_config_overwrites(arg1);
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_config_init) {
+  {
+    config_init_flags arg1 ;
+    char *arg2 = (char *) 0 ;
+    gboolean result;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: config_init(flags,arg_config_name);");
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg1 = amglue_SvI8(ST(0));
+      } else if (sizeof(signed int) == 2) {
+        arg1 = amglue_SvI16(ST(0));
+      } else if (sizeof(signed int) == 4) {
+        arg1 = amglue_SvI32(ST(0));
+      } else if (sizeof(signed int) == 8) {
+        arg1 = amglue_SvI64(ST(0));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "config_init" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    result = (gboolean)config_init(arg1,arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    XSRETURN(argvi);
+  fail:
+    
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_config_uninit) {
+  {
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: config_uninit();");
+    }
+    config_uninit();
+    
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_get_config_options) {
+  {
+    int arg1 ;
+    char **result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: get_config_options(first);");
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg1 = amglue_SvI8(ST(0));
+      } else if (sizeof(signed int) == 2) {
+        arg1 = amglue_SvI16(ST(0));
+      } else if (sizeof(signed int) == 4) {
+        arg1 = amglue_SvI32(ST(0));
+      } else if (sizeof(signed int) == 8) {
+        arg1 = amglue_SvI64(ST(0));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (char **)get_config_options(arg1);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_p_char, 0 | 0); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_get_config_name) {
+  {
+    char *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: get_config_name();");
+    }
+    result = (char *)get_config_name();
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_get_config_dir) {
+  {
+    char *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: get_config_dir();");
+    }
+    result = (char *)get_config_dir();
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_get_config_filename) {
+  {
+    char *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: get_config_filename();");
+    }
+    result = (char *)get_config_filename();
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dump_configuration) {
+  {
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: dump_configuration();");
+    }
+    dump_configuration();
+    
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_config_dir_relative) {
+  {
+    char *arg1 = (char *) 0 ;
+    char *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: config_dir_relative(filename);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "config_dir_relative" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (char *)config_dir_relative(arg1);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_taperalgo2str) {
+  {
+    taperalgo_t arg1 ;
+    char *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: taperalgo2str(taperalgo);");
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg1 = amglue_SvI8(ST(0));
+      } else if (sizeof(signed int) == 2) {
+        arg1 = amglue_SvI16(ST(0));
+      } else if (sizeof(signed int) == 4) {
+        arg1 = amglue_SvI32(ST(0));
+      } else if (sizeof(signed int) == 8) {
+        arg1 = amglue_SvI64(ST(0));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (char *)taperalgo2str(arg1);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_multiplier) {
+  {
+    char *arg1 = (char *) 0 ;
+    gint64 result;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: find_multiplier(casestr);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "find_multiplier" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = find_multiplier(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_char = {"_p_char", "gchar *|char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_config_overwrites_t = {"_p_config_overwrites_t", "config_overwrites_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_double = {"_p_double", "double *|gdouble *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_dumptype_t = {"_p_dumptype_t", "dumptype_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *|gfloat *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_holdingdisk_t = {"_p_holdingdisk_t", "holdingdisk_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "strategy_t *|int *|comp_t *|dump_holdingdisk_t *|holdingdisk_key *|interface_key *|confparm_key *|dumptype_key *|tapetype_key *|encrypt_t *|taperalgo_t *|gboolean *|estimate_t *|config_init_flags *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_interface_t = {"_p_interface_t", "interface_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_tapetype_t = {"_p_tapetype_t", "tapetype_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "guchar *|unsigned char *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_char,
+  &_swigt__p_config_overwrites_t,
+  &_swigt__p_double,
+  &_swigt__p_dumptype_t,
+  &_swigt__p_float,
+  &_swigt__p_holdingdisk_t,
+  &_swigt__p_int,
+  &_swigt__p_interface_t,
+  &_swigt__p_p_char,
+  &_swigt__p_tapetype_t,
+  &_swigt__p_unsigned_char,
+};
+
+static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_config_overwrites_t[] = {  {&_swigt__p_config_overwrites_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_dumptype_t[] = {  {&_swigt__p_dumptype_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_holdingdisk_t[] = {  {&_swigt__p_holdingdisk_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_interface_t[] = {  {&_swigt__p_interface_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_p_char[] = {  {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_tapetype_t[] = {  {&_swigt__p_tapetype_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_char[] = {  {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_char,
+  _swigc__p_config_overwrites_t,
+  _swigc__p_double,
+  _swigc__p_dumptype_t,
+  _swigc__p_float,
+  _swigc__p_holdingdisk_t,
+  _swigc__p_int,
+  _swigc__p_interface_t,
+  _swigc__p_p_char,
+  _swigc__p_tapetype_t,
+  _swigc__p_unsigned_char,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_constant_info swig_constants[] = {
+{0,0,0,0,0,0}
+};
+#ifdef __cplusplus
+}
+#endif
+static swig_variable_info swig_variables[] = {
+    { "Amanda::Configc::debug_amandad", MAGIC_CLASS _wrap_debug_amandad_set, MAGIC_CLASS _wrap_debug_amandad_get,0 },
+    { "Amanda::Configc::debug_amidxtaped", MAGIC_CLASS _wrap_debug_amidxtaped_set, MAGIC_CLASS _wrap_debug_amidxtaped_get,0 },
+    { "Amanda::Configc::debug_amindexd", MAGIC_CLASS _wrap_debug_amindexd_set, MAGIC_CLASS _wrap_debug_amindexd_get,0 },
+    { "Amanda::Configc::debug_amrecover", MAGIC_CLASS _wrap_debug_amrecover_set, MAGIC_CLASS _wrap_debug_amrecover_get,0 },
+    { "Amanda::Configc::debug_auth", MAGIC_CLASS _wrap_debug_auth_set, MAGIC_CLASS _wrap_debug_auth_get,0 },
+    { "Amanda::Configc::debug_event", MAGIC_CLASS _wrap_debug_event_set, MAGIC_CLASS _wrap_debug_event_get,0 },
+    { "Amanda::Configc::debug_holding", MAGIC_CLASS _wrap_debug_holding_set, MAGIC_CLASS _wrap_debug_holding_get,0 },
+    { "Amanda::Configc::debug_protocol", MAGIC_CLASS _wrap_debug_protocol_set, MAGIC_CLASS _wrap_debug_protocol_get,0 },
+    { "Amanda::Configc::debug_planner", MAGIC_CLASS _wrap_debug_planner_set, MAGIC_CLASS _wrap_debug_planner_get,0 },
+    { "Amanda::Configc::debug_driver", MAGIC_CLASS _wrap_debug_driver_set, MAGIC_CLASS _wrap_debug_driver_get,0 },
+    { "Amanda::Configc::debug_dumper", MAGIC_CLASS _wrap_debug_dumper_set, MAGIC_CLASS _wrap_debug_dumper_get,0 },
+    { "Amanda::Configc::debug_chunker", MAGIC_CLASS _wrap_debug_chunker_set, MAGIC_CLASS _wrap_debug_chunker_get,0 },
+    { "Amanda::Configc::debug_taper", MAGIC_CLASS _wrap_debug_taper_set, MAGIC_CLASS _wrap_debug_taper_get,0 },
+    { "Amanda::Configc::debug_selfcheck", MAGIC_CLASS _wrap_debug_selfcheck_set, MAGIC_CLASS _wrap_debug_selfcheck_get,0 },
+    { "Amanda::Configc::debug_sendsize", MAGIC_CLASS _wrap_debug_sendsize_set, MAGIC_CLASS _wrap_debug_sendsize_get,0 },
+    { "Amanda::Configc::debug_sendbackup", MAGIC_CLASS _wrap_debug_sendbackup_set, MAGIC_CLASS _wrap_debug_sendbackup_get,0 },
+{0,0,0,0}
+};
+static swig_command_info swig_commands[] = {
+{"Amanda::Configc::getconf", _wrap_getconf},
+{"Amanda::Configc::getconf_seen", _wrap_getconf_seen},
+{"Amanda::Configc::getconf_byname", _wrap_getconf_byname},
+{"Amanda::Configc::getconf_list", _wrap_getconf_list},
+{"Amanda::Configc::lookup_tapetype", _wrap_lookup_tapetype},
+{"Amanda::Configc::tapetype_getconf", _wrap_tapetype_getconf},
+{"Amanda::Configc::tapetype_name", _wrap_tapetype_name},
+{"Amanda::Configc::tapetype_seen", _wrap_tapetype_seen},
+{"Amanda::Configc::lookup_dumptype", _wrap_lookup_dumptype},
+{"Amanda::Configc::dumptype_getconf", _wrap_dumptype_getconf},
+{"Amanda::Configc::dumptype_name", _wrap_dumptype_name},
+{"Amanda::Configc::dumptype_seen", _wrap_dumptype_seen},
+{"Amanda::Configc::lookup_interface", _wrap_lookup_interface},
+{"Amanda::Configc::interface_getconf", _wrap_interface_getconf},
+{"Amanda::Configc::interface_name", _wrap_interface_name},
+{"Amanda::Configc::interface_seen", _wrap_interface_seen},
+{"Amanda::Configc::lookup_holdingdisk", _wrap_lookup_holdingdisk},
+{"Amanda::Configc::getconf_holdingdisks", _wrap_getconf_holdingdisks},
+{"Amanda::Configc::holdingdisk_next", _wrap_holdingdisk_next},
+{"Amanda::Configc::holdingdisk_getconf", _wrap_holdingdisk_getconf},
+{"Amanda::Configc::holdingdisk_name", _wrap_holdingdisk_name},
+{"Amanda::Configc::holdingdisk_seen", _wrap_holdingdisk_seen},
+{"Amanda::Configc::getconf_unit_divisor", _wrap_getconf_unit_divisor},
+{"Amanda::Configc::new_config_overwrites", _wrap_new_config_overwrites},
+{"Amanda::Configc::free_config_overwrites", _wrap_free_config_overwrites},
+{"Amanda::Configc::add_config_overwrite", _wrap_add_config_overwrite},
+{"Amanda::Configc::add_config_overwrite_opt", _wrap_add_config_overwrite_opt},
+{"Amanda::Configc::apply_config_overwrites", _wrap_apply_config_overwrites},
+{"Amanda::Configc::config_init", _wrap_config_init},
+{"Amanda::Configc::config_uninit", _wrap_config_uninit},
+{"Amanda::Configc::get_config_options", _wrap_get_config_options},
+{"Amanda::Configc::get_config_name", _wrap_get_config_name},
+{"Amanda::Configc::get_config_dir", _wrap_get_config_dir},
+{"Amanda::Configc::get_config_filename", _wrap_get_config_filename},
+{"Amanda::Configc::dump_configuration", _wrap_dump_configuration},
+{"Amanda::Configc::config_dir_relative", _wrap_config_dir_relative},
+{"Amanda::Configc::taperalgo2str", _wrap_taperalgo2str},
+{"Amanda::Configc::find_multiplier", _wrap_find_multiplier},
+{0,0}
+};
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic 
+ * memory is used. Also, since swig_type_info structures store pointers to 
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization. 
+ * The idea is that swig generates all the structures that are needed. 
+ * The runtime then collects these partially filled structures. 
+ * The SWIG_InitializeModule function takes these initial arrays out of 
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned staticly to an initial 
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it 
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded. 
+ * There are three cases to handle:
+ *  1) If the cast->type has already been loaded AND the type we are adding
+ *     casting info to has not been loaded (it is in this module), THEN we
+ *     replace the cast->type pointer with the type pointer that has already
+ *     been loaded.
+ *  2) If BOTH types (the one we are adding casting info to, and the 
+ *     cast->type) are loaded, THEN the cast info has already been loaded by
+ *     the previous module so we just ignore it.
+ *  3) Finally, if cast->type has not already been loaded, then we add that
+ *     swig_cast_info to the linked list (because the cast->type) pointer will
+ *     be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+  size_t i;
+  swig_module_info *module_head, *iter;
+  int found;
+  
+  clientdata = clientdata;
+  
+  /* check to see if the circular list has been setup, if not, set it up */
+  if (swig_module.next==0) {
+    /* Initialize the swig_module */
+    swig_module.type_initial = swig_type_initial;
+    swig_module.cast_initial = swig_cast_initial;
+    swig_module.next = &swig_module;
+  }
+  
+  /* Try and load any already created modules */
+  module_head = SWIG_GetModule(clientdata);
+  if (!module_head) {
+    /* This is the first module loaded for this interpreter */
+    /* so set the swig module into the interpreter */
+    SWIG_SetModule(clientdata, &swig_module);
+    module_head = &swig_module;
+  } else {
+    /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+    found=0;
+    iter=module_head;
+    do {
+      if (iter==&swig_module) {
+        found=1;
+        break;
+      }
+      iter=iter->next;
+    } while (iter!= module_head);
+    
+    /* if the is found in the list, then all is done and we may leave */
+    if (found) return;
+    /* otherwise we must add out module into the list */
+    swig_module.next = module_head->next;
+    module_head->next = &swig_module;
+  }
+  
+  /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+  printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+  for (i = 0; i < swig_module.size; ++i) {
+    swig_type_info *type = 0;
+    swig_type_info *ret;
+    swig_cast_info *cast;
+    
+#ifdef SWIGRUNTIME_DEBUG
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+    
+    /* if there is another module already loaded */
+    if (swig_module.next != &swig_module) {
+      type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+    }
+    if (type) {
+      /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+      if (swig_module.type_initial[i]->clientdata) {
+        type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+      }
+    } else {
+      type = swig_module.type_initial[i];
+    }
+    
+    /* Insert casting types */
+    cast = swig_module.cast_initial[i];
+    while (cast->type) {
+      /* Don't need to add information already in the list */
+      ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+      if (swig_module.next != &swig_module) {
+        ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+        if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+      }
+      if (ret) {
+        if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+          printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+          cast->type = ret;
+          ret = 0;
+        } else {
+          /* Check for casting already in the list */
+          swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+          if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+          if (!ocast) ret = 0;
+        }
+      }
+      
+      if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+        if (type->cast) {
+          type->cast->prev = cast;
+          cast->next = type->cast;
+        }
+        type->cast = cast;
+      }
+      cast++;
+    }
+    /* Set entry in modules->types array equal to the type */
+    swig_module.types[i] = type;
+  }
+  swig_module.types[i] = 0;
+  
+#ifdef SWIGRUNTIME_DEBUG
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+  for (i = 0; i < swig_module.size; ++i) {
+    int j = 0;
+    swig_cast_info *cast = swig_module.cast_initial[i];
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+    while (cast->type) {
+      printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+      cast++;
+      ++j;
+    }
+    printf("---- Total casts: %d\n",j);
+  }
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types.  It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+  size_t i;
+  swig_cast_info *equiv;
+  static int init_run = 0;
+  
+  if (init_run) return;
+  init_run = 1;
+  
+  for (i = 0; i < swig_module.size; i++) {
+    if (swig_module.types[i]->clientdata) {
+      equiv = swig_module.types[i]->cast;
+      while (equiv) {
+        if (!equiv->converter) {
+          if (equiv->type && !equiv->type->clientdata)
+          SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+        }
+        equiv = equiv->next;
+      }
+    }
+  }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+  /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(SWIG_init) {
+  dXSARGS;
+  int i;
+  
+  SWIG_InitializeModule(0);
+  
+  /* Install commands */
+  for (i = 0; swig_commands[i].name; i++) {
+    newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__);
+  }
+  
+  /* Install variables */
+  for (i = 0; swig_variables[i].name; i++) {
+    SV *sv;
+    sv = get_sv((char*) swig_variables[i].name, TRUE | 0x2);
+    if (swig_variables[i].type) {
+      SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0);
+    } else {
+      sv_setiv(sv,(IV) 0);
+    }
+    swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); 
+  }
+  
+  /* Install constant */
+  for (i = 0; swig_constants[i].type; i++) {
+    SV *sv;
+    sv = get_sv((char*)swig_constants[i].name, TRUE | 0x2);
+    switch(swig_constants[i].type) {
+    case SWIG_INT:
+      sv_setiv(sv, (IV) swig_constants[i].lvalue);
+      break;
+    case SWIG_FLOAT:
+      sv_setnv(sv, (double) swig_constants[i].dvalue);
+      break;
+    case SWIG_STRING:
+      sv_setpv(sv, (char *) swig_constants[i].pvalue);
+      break;
+    case SWIG_POINTER:
+      SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
+      break;
+    case SWIG_BINARY:
+      SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
+      break;
+    default:
+      break;
+    }
+    SvREADONLY_on(sv);
+  }
+  
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_ORG", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_ORG)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_CONF", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_CONF)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_INDEX_SERVER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_INDEX_SERVER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_TAPE_SERVER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_TAPE_SERVER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_AUTH", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_AUTH)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_SSH_KEYS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_SSH_KEYS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_AMANDAD_PATH", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_AMANDAD_PATH)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_CLIENT_USERNAME", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_CLIENT_USERNAME)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_GNUTAR_LIST_DIR", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_GNUTAR_LIST_DIR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_AMANDATES", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_AMANDATES)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_MAILTO", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_MAILTO)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DUMPUSER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DUMPUSER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_TAPEDEV", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_TAPEDEV)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEVICE_PROPERTY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEVICE_PROPERTY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_CHANGERDEV", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_CHANGERDEV)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_CHANGERFILE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_CHANGERFILE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_LABELSTR", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_LABELSTR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_TAPELIST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_TAPELIST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DISKFILE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DISKFILE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_INFOFILE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_INFOFILE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_LOGDIR", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_LOGDIR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_INDEXDIR", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_INDEXDIR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_TAPETYPE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_TAPETYPE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DUMPCYCLE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DUMPCYCLE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_RUNSPERCYCLE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_RUNSPERCYCLE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_TAPECYCLE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_TAPECYCLE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_NETUSAGE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_NETUSAGE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_INPARALLEL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_INPARALLEL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DUMPORDER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DUMPORDER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_BUMPPERCENT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_BUMPPERCENT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_BUMPSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_BUMPSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_BUMPMULT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_BUMPMULT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_BUMPDAYS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_BUMPDAYS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_TPCHANGER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_TPCHANGER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_RUNTAPES", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_RUNTAPES)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_MAXDUMPS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_MAXDUMPS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_ETIMEOUT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_ETIMEOUT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DTIMEOUT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DTIMEOUT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_CTIMEOUT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_CTIMEOUT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_TAPEBUFS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_TAPEBUFS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEVICE_OUTPUT_BUFFER_SIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEVICE_OUTPUT_BUFFER_SIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_PRINTER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_PRINTER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_AUTOFLUSH", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_AUTOFLUSH)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_RESERVE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_RESERVE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_MAXDUMPSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_MAXDUMPSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_COLUMNSPEC", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_COLUMNSPEC)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_AMRECOVER_DO_FSF", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_AMRECOVER_DO_FSF)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_AMRECOVER_CHECK_LABEL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_AMRECOVER_CHECK_LABEL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_AMRECOVER_CHANGER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_AMRECOVER_CHANGER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_TAPERALGO", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_TAPERALGO)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_FLUSH_THRESHOLD_DUMPED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_FLUSH_THRESHOLD_DUMPED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_FLUSH_THRESHOLD_SCHEDULED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_FLUSH_THRESHOLD_SCHEDULED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_TAPERFLUSH", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_TAPERFLUSH)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DISPLAYUNIT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DISPLAYUNIT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_KRB5KEYTAB", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_KRB5KEYTAB)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_KRB5PRINCIPAL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_KRB5PRINCIPAL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_LABEL_NEW_TAPES", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_LABEL_NEW_TAPES)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_USETIMESTAMPS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_USETIMESTAMPS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_REP_TRIES", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_REP_TRIES)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_CONNECT_TRIES", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_CONNECT_TRIES)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_REQ_TRIES", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_REQ_TRIES)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_AMANDAD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_AMANDAD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_AMIDXTAPED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_AMIDXTAPED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_AMINDEXD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_AMINDEXD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_AMRECOVER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_AMRECOVER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_AUTH", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_AUTH)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_EVENT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_EVENT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_HOLDING", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_HOLDING)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_PROTOCOL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_PROTOCOL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_PLANNER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_PLANNER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_DRIVER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_DRIVER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_DUMPER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_DUMPER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_CHUNKER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_CHUNKER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_TAPER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_TAPER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_SELFCHECK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_SELFCHECK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_SENDSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_SENDSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_DEBUG_SENDBACKUP", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_DEBUG_SENDBACKUP)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_RESERVED_UDP_PORT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_RESERVED_UDP_PORT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_RESERVED_TCP_PORT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_RESERVED_TCP_PORT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CNF_UNRESERVED_TCP_PORT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CNF_UNRESERVED_TCP_PORT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "TAPETYPE_COMMENT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(TAPETYPE_COMMENT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "TAPETYPE_LBL_TEMPL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(TAPETYPE_LBL_TEMPL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "TAPETYPE_BLOCKSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(TAPETYPE_BLOCKSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "TAPETYPE_READBLOCKSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(TAPETYPE_READBLOCKSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "TAPETYPE_LENGTH", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(TAPETYPE_LENGTH)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "TAPETYPE_FILEMARK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(TAPETYPE_FILEMARK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "TAPETYPE_SPEED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(TAPETYPE_SPEED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "TAPETYPE_FILE_PAD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(TAPETYPE_FILE_PAD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_COMMENT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_COMMENT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_PROGRAM", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_PROGRAM)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_SRVCOMPPROG", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_SRVCOMPPROG)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_CLNTCOMPPROG", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_CLNTCOMPPROG)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_SRV_ENCRYPT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_SRV_ENCRYPT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_CLNT_ENCRYPT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_CLNT_ENCRYPT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_AMANDAD_PATH", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_AMANDAD_PATH)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_CLIENT_USERNAME", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_CLIENT_USERNAME)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_SSH_KEYS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_SSH_KEYS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_SECURITY_DRIVER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_SECURITY_DRIVER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_EXCLUDE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_EXCLUDE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_INCLUDE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_INCLUDE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_PRIORITY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_PRIORITY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_DUMPCYCLE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_DUMPCYCLE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_MAXDUMPS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_MAXDUMPS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_MAXPROMOTEDAY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_MAXPROMOTEDAY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_BUMPPERCENT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_BUMPPERCENT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_BUMPSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_BUMPSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_BUMPDAYS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_BUMPDAYS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_BUMPMULT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_BUMPMULT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_STARTTIME", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_STARTTIME)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_STRATEGY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_STRATEGY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_ESTIMATE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_ESTIMATE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_COMPRESS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_COMPRESS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_ENCRYPT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_ENCRYPT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_SRV_DECRYPT_OPT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_SRV_DECRYPT_OPT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_CLNT_DECRYPT_OPT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_CLNT_DECRYPT_OPT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_COMPRATE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_COMPRATE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_TAPE_SPLITSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_TAPE_SPLITSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_FALLBACK_SPLITSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_FALLBACK_SPLITSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_SPLIT_DISKBUFFER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_SPLIT_DISKBUFFER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_RECORD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_RECORD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_SKIP_INCR", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_SKIP_INCR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_SKIP_FULL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_SKIP_FULL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_HOLDINGDISK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_HOLDINGDISK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_KENCRYPT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_KENCRYPT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_IGNORE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_IGNORE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DUMPTYPE_INDEX", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DUMPTYPE_INDEX)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "INTER_COMMENT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(INTER_COMMENT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "INTER_MAXUSAGE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(INTER_MAXUSAGE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "HOLDING_COMMENT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(HOLDING_COMMENT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "HOLDING_DISKDIR", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(HOLDING_DISKDIR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "HOLDING_DISKSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(HOLDING_DISKSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "HOLDING_CHUNKSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(HOLDING_CHUNKSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "HOLD_NEVER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(HOLD_NEVER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "HOLD_AUTO", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(HOLD_AUTO)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "HOLD_REQUIRED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(HOLD_REQUIRED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "COMP_NONE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(COMP_NONE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "COMP_FAST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(COMP_FAST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "COMP_BEST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(COMP_BEST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "COMP_CUST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(COMP_CUST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "COMP_SERVER_FAST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(COMP_SERVER_FAST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "COMP_SERVER_BEST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(COMP_SERVER_BEST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "COMP_SERVER_CUST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(COMP_SERVER_CUST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ENCRYPT_NONE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ENCRYPT_NONE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ENCRYPT_CUST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ENCRYPT_CUST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ENCRYPT_SERV_CUST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ENCRYPT_SERV_CUST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DS_SKIP", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DS_SKIP)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DS_STANDARD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DS_STANDARD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DS_NOFULL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DS_NOFULL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DS_NOINC", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DS_NOINC)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DS_4", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DS_4)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DS_5", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DS_5)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DS_HANOI", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DS_HANOI)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DS_INCRONLY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(DS_INCRONLY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ES_CLIENT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ES_CLIENT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ES_SERVER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ES_SERVER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ES_CALCSIZE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ES_CALCSIZE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ALGO_FIRST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ALGO_FIRST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ALGO_FIRSTFIT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ALGO_FIRSTFIT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ALGO_LARGEST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ALGO_LARGEST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ALGO_LARGESTFIT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ALGO_LARGESTFIT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ALGO_SMALLEST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ALGO_SMALLEST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ALGO_LAST", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ALGO_LAST)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CONFIG_INIT_EXPLICIT_NAME", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CONFIG_INIT_EXPLICIT_NAME)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CONFIG_INIT_USE_CWD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CONFIG_INIT_USE_CWD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CONFIG_INIT_CLIENT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CONFIG_INIT_CLIENT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CONFIG_INIT_OVERLAY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CONFIG_INIT_OVERLAY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CONFIG_INIT_FATAL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CONFIG_INIT_FATAL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  ST(0) = &PL_sv_yes;
+  XSRETURN(1);
+}
+
diff --git a/perl/Amanda/Config.pm b/perl/Amanda/Config.pm
new file mode 100644 (file)
index 0000000..b254c92
--- /dev/null
@@ -0,0 +1,1673 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 1.3.33
+#
+# Don't modify this file, modify the SWIG interface instead.
+
+package Amanda::Config;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+package Amanda::Configc;
+bootstrap Amanda::Config;
+package Amanda::Config;
+@EXPORT = qw( );
+
+# ---------- BASE METHODS -------------
+
+package Amanda::Config;
+
+sub TIEHASH {
+    my ($classname,$obj) = @_;
+    return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+    my ($self,$field) = @_;
+    my $member_func = "swig_${field}_get";
+    $self->$member_func();
+}
+
+sub STORE {
+    my ($self,$field,$newval) = @_;
+    my $member_func = "swig_${field}_set";
+    $self->$member_func($newval);
+}
+
+sub this {
+    my $ptr = shift;
+    return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package Amanda::Config;
+
+*getconf = *Amanda::Configc::getconf;
+*getconf_seen = *Amanda::Configc::getconf_seen;
+*getconf_byname = *Amanda::Configc::getconf_byname;
+*getconf_list = *Amanda::Configc::getconf_list;
+*lookup_tapetype = *Amanda::Configc::lookup_tapetype;
+*tapetype_getconf = *Amanda::Configc::tapetype_getconf;
+*tapetype_name = *Amanda::Configc::tapetype_name;
+*tapetype_seen = *Amanda::Configc::tapetype_seen;
+*lookup_dumptype = *Amanda::Configc::lookup_dumptype;
+*dumptype_getconf = *Amanda::Configc::dumptype_getconf;
+*dumptype_name = *Amanda::Configc::dumptype_name;
+*dumptype_seen = *Amanda::Configc::dumptype_seen;
+*lookup_interface = *Amanda::Configc::lookup_interface;
+*interface_getconf = *Amanda::Configc::interface_getconf;
+*interface_name = *Amanda::Configc::interface_name;
+*interface_seen = *Amanda::Configc::interface_seen;
+*lookup_holdingdisk = *Amanda::Configc::lookup_holdingdisk;
+*getconf_holdingdisks = *Amanda::Configc::getconf_holdingdisks;
+*holdingdisk_next = *Amanda::Configc::holdingdisk_next;
+*holdingdisk_getconf = *Amanda::Configc::holdingdisk_getconf;
+*holdingdisk_name = *Amanda::Configc::holdingdisk_name;
+*holdingdisk_seen = *Amanda::Configc::holdingdisk_seen;
+*getconf_unit_divisor = *Amanda::Configc::getconf_unit_divisor;
+*new_config_overwrites = *Amanda::Configc::new_config_overwrites;
+*free_config_overwrites = *Amanda::Configc::free_config_overwrites;
+*add_config_overwrite = *Amanda::Configc::add_config_overwrite;
+*add_config_overwrite_opt = *Amanda::Configc::add_config_overwrite_opt;
+*apply_config_overwrites = *Amanda::Configc::apply_config_overwrites;
+*config_init = *Amanda::Configc::config_init;
+*config_uninit = *Amanda::Configc::config_uninit;
+*get_config_options = *Amanda::Configc::get_config_options;
+*get_config_name = *Amanda::Configc::get_config_name;
+*get_config_dir = *Amanda::Configc::get_config_dir;
+*get_config_filename = *Amanda::Configc::get_config_filename;
+*dump_configuration = *Amanda::Configc::dump_configuration;
+*config_dir_relative = *Amanda::Configc::config_dir_relative;
+*taperalgo2str = *Amanda::Configc::taperalgo2str;
+*find_multiplier = *Amanda::Configc::find_multiplier;
+
+# ------- VARIABLE STUBS --------
+
+package Amanda::Config;
+
+*CNF_ORG = *Amanda::Configc::CNF_ORG;
+*CNF_CONF = *Amanda::Configc::CNF_CONF;
+*CNF_INDEX_SERVER = *Amanda::Configc::CNF_INDEX_SERVER;
+*CNF_TAPE_SERVER = *Amanda::Configc::CNF_TAPE_SERVER;
+*CNF_AUTH = *Amanda::Configc::CNF_AUTH;
+*CNF_SSH_KEYS = *Amanda::Configc::CNF_SSH_KEYS;
+*CNF_AMANDAD_PATH = *Amanda::Configc::CNF_AMANDAD_PATH;
+*CNF_CLIENT_USERNAME = *Amanda::Configc::CNF_CLIENT_USERNAME;
+*CNF_GNUTAR_LIST_DIR = *Amanda::Configc::CNF_GNUTAR_LIST_DIR;
+*CNF_AMANDATES = *Amanda::Configc::CNF_AMANDATES;
+*CNF_MAILTO = *Amanda::Configc::CNF_MAILTO;
+*CNF_DUMPUSER = *Amanda::Configc::CNF_DUMPUSER;
+*CNF_TAPEDEV = *Amanda::Configc::CNF_TAPEDEV;
+*CNF_DEVICE_PROPERTY = *Amanda::Configc::CNF_DEVICE_PROPERTY;
+*CNF_CHANGERDEV = *Amanda::Configc::CNF_CHANGERDEV;
+*CNF_CHANGERFILE = *Amanda::Configc::CNF_CHANGERFILE;
+*CNF_LABELSTR = *Amanda::Configc::CNF_LABELSTR;
+*CNF_TAPELIST = *Amanda::Configc::CNF_TAPELIST;
+*CNF_DISKFILE = *Amanda::Configc::CNF_DISKFILE;
+*CNF_INFOFILE = *Amanda::Configc::CNF_INFOFILE;
+*CNF_LOGDIR = *Amanda::Configc::CNF_LOGDIR;
+*CNF_INDEXDIR = *Amanda::Configc::CNF_INDEXDIR;
+*CNF_TAPETYPE = *Amanda::Configc::CNF_TAPETYPE;
+*CNF_DUMPCYCLE = *Amanda::Configc::CNF_DUMPCYCLE;
+*CNF_RUNSPERCYCLE = *Amanda::Configc::CNF_RUNSPERCYCLE;
+*CNF_TAPECYCLE = *Amanda::Configc::CNF_TAPECYCLE;
+*CNF_NETUSAGE = *Amanda::Configc::CNF_NETUSAGE;
+*CNF_INPARALLEL = *Amanda::Configc::CNF_INPARALLEL;
+*CNF_DUMPORDER = *Amanda::Configc::CNF_DUMPORDER;
+*CNF_BUMPPERCENT = *Amanda::Configc::CNF_BUMPPERCENT;
+*CNF_BUMPSIZE = *Amanda::Configc::CNF_BUMPSIZE;
+*CNF_BUMPMULT = *Amanda::Configc::CNF_BUMPMULT;
+*CNF_BUMPDAYS = *Amanda::Configc::CNF_BUMPDAYS;
+*CNF_TPCHANGER = *Amanda::Configc::CNF_TPCHANGER;
+*CNF_RUNTAPES = *Amanda::Configc::CNF_RUNTAPES;
+*CNF_MAXDUMPS = *Amanda::Configc::CNF_MAXDUMPS;
+*CNF_ETIMEOUT = *Amanda::Configc::CNF_ETIMEOUT;
+*CNF_DTIMEOUT = *Amanda::Configc::CNF_DTIMEOUT;
+*CNF_CTIMEOUT = *Amanda::Configc::CNF_CTIMEOUT;
+*CNF_TAPEBUFS = *Amanda::Configc::CNF_TAPEBUFS;
+*CNF_DEVICE_OUTPUT_BUFFER_SIZE = *Amanda::Configc::CNF_DEVICE_OUTPUT_BUFFER_SIZE;
+*CNF_PRINTER = *Amanda::Configc::CNF_PRINTER;
+*CNF_AUTOFLUSH = *Amanda::Configc::CNF_AUTOFLUSH;
+*CNF_RESERVE = *Amanda::Configc::CNF_RESERVE;
+*CNF_MAXDUMPSIZE = *Amanda::Configc::CNF_MAXDUMPSIZE;
+*CNF_COLUMNSPEC = *Amanda::Configc::CNF_COLUMNSPEC;
+*CNF_AMRECOVER_DO_FSF = *Amanda::Configc::CNF_AMRECOVER_DO_FSF;
+*CNF_AMRECOVER_CHECK_LABEL = *Amanda::Configc::CNF_AMRECOVER_CHECK_LABEL;
+*CNF_AMRECOVER_CHANGER = *Amanda::Configc::CNF_AMRECOVER_CHANGER;
+*CNF_TAPERALGO = *Amanda::Configc::CNF_TAPERALGO;
+*CNF_FLUSH_THRESHOLD_DUMPED = *Amanda::Configc::CNF_FLUSH_THRESHOLD_DUMPED;
+*CNF_FLUSH_THRESHOLD_SCHEDULED = *Amanda::Configc::CNF_FLUSH_THRESHOLD_SCHEDULED;
+*CNF_TAPERFLUSH = *Amanda::Configc::CNF_TAPERFLUSH;
+*CNF_DISPLAYUNIT = *Amanda::Configc::CNF_DISPLAYUNIT;
+*CNF_KRB5KEYTAB = *Amanda::Configc::CNF_KRB5KEYTAB;
+*CNF_KRB5PRINCIPAL = *Amanda::Configc::CNF_KRB5PRINCIPAL;
+*CNF_LABEL_NEW_TAPES = *Amanda::Configc::CNF_LABEL_NEW_TAPES;
+*CNF_USETIMESTAMPS = *Amanda::Configc::CNF_USETIMESTAMPS;
+*CNF_REP_TRIES = *Amanda::Configc::CNF_REP_TRIES;
+*CNF_CONNECT_TRIES = *Amanda::Configc::CNF_CONNECT_TRIES;
+*CNF_REQ_TRIES = *Amanda::Configc::CNF_REQ_TRIES;
+*CNF_DEBUG_AMANDAD = *Amanda::Configc::CNF_DEBUG_AMANDAD;
+*CNF_DEBUG_AMIDXTAPED = *Amanda::Configc::CNF_DEBUG_AMIDXTAPED;
+*CNF_DEBUG_AMINDEXD = *Amanda::Configc::CNF_DEBUG_AMINDEXD;
+*CNF_DEBUG_AMRECOVER = *Amanda::Configc::CNF_DEBUG_AMRECOVER;
+*CNF_DEBUG_AUTH = *Amanda::Configc::CNF_DEBUG_AUTH;
+*CNF_DEBUG_EVENT = *Amanda::Configc::CNF_DEBUG_EVENT;
+*CNF_DEBUG_HOLDING = *Amanda::Configc::CNF_DEBUG_HOLDING;
+*CNF_DEBUG_PROTOCOL = *Amanda::Configc::CNF_DEBUG_PROTOCOL;
+*CNF_DEBUG_PLANNER = *Amanda::Configc::CNF_DEBUG_PLANNER;
+*CNF_DEBUG_DRIVER = *Amanda::Configc::CNF_DEBUG_DRIVER;
+*CNF_DEBUG_DUMPER = *Amanda::Configc::CNF_DEBUG_DUMPER;
+*CNF_DEBUG_CHUNKER = *Amanda::Configc::CNF_DEBUG_CHUNKER;
+*CNF_DEBUG_TAPER = *Amanda::Configc::CNF_DEBUG_TAPER;
+*CNF_DEBUG_SELFCHECK = *Amanda::Configc::CNF_DEBUG_SELFCHECK;
+*CNF_DEBUG_SENDSIZE = *Amanda::Configc::CNF_DEBUG_SENDSIZE;
+*CNF_DEBUG_SENDBACKUP = *Amanda::Configc::CNF_DEBUG_SENDBACKUP;
+*CNF_RESERVED_UDP_PORT = *Amanda::Configc::CNF_RESERVED_UDP_PORT;
+*CNF_RESERVED_TCP_PORT = *Amanda::Configc::CNF_RESERVED_TCP_PORT;
+*CNF_UNRESERVED_TCP_PORT = *Amanda::Configc::CNF_UNRESERVED_TCP_PORT;
+*TAPETYPE_COMMENT = *Amanda::Configc::TAPETYPE_COMMENT;
+*TAPETYPE_LBL_TEMPL = *Amanda::Configc::TAPETYPE_LBL_TEMPL;
+*TAPETYPE_BLOCKSIZE = *Amanda::Configc::TAPETYPE_BLOCKSIZE;
+*TAPETYPE_READBLOCKSIZE = *Amanda::Configc::TAPETYPE_READBLOCKSIZE;
+*TAPETYPE_LENGTH = *Amanda::Configc::TAPETYPE_LENGTH;
+*TAPETYPE_FILEMARK = *Amanda::Configc::TAPETYPE_FILEMARK;
+*TAPETYPE_SPEED = *Amanda::Configc::TAPETYPE_SPEED;
+*TAPETYPE_FILE_PAD = *Amanda::Configc::TAPETYPE_FILE_PAD;
+*DUMPTYPE_COMMENT = *Amanda::Configc::DUMPTYPE_COMMENT;
+*DUMPTYPE_PROGRAM = *Amanda::Configc::DUMPTYPE_PROGRAM;
+*DUMPTYPE_SRVCOMPPROG = *Amanda::Configc::DUMPTYPE_SRVCOMPPROG;
+*DUMPTYPE_CLNTCOMPPROG = *Amanda::Configc::DUMPTYPE_CLNTCOMPPROG;
+*DUMPTYPE_SRV_ENCRYPT = *Amanda::Configc::DUMPTYPE_SRV_ENCRYPT;
+*DUMPTYPE_CLNT_ENCRYPT = *Amanda::Configc::DUMPTYPE_CLNT_ENCRYPT;
+*DUMPTYPE_AMANDAD_PATH = *Amanda::Configc::DUMPTYPE_AMANDAD_PATH;
+*DUMPTYPE_CLIENT_USERNAME = *Amanda::Configc::DUMPTYPE_CLIENT_USERNAME;
+*DUMPTYPE_SSH_KEYS = *Amanda::Configc::DUMPTYPE_SSH_KEYS;
+*DUMPTYPE_SECURITY_DRIVER = *Amanda::Configc::DUMPTYPE_SECURITY_DRIVER;
+*DUMPTYPE_EXCLUDE = *Amanda::Configc::DUMPTYPE_EXCLUDE;
+*DUMPTYPE_INCLUDE = *Amanda::Configc::DUMPTYPE_INCLUDE;
+*DUMPTYPE_PRIORITY = *Amanda::Configc::DUMPTYPE_PRIORITY;
+*DUMPTYPE_DUMPCYCLE = *Amanda::Configc::DUMPTYPE_DUMPCYCLE;
+*DUMPTYPE_MAXDUMPS = *Amanda::Configc::DUMPTYPE_MAXDUMPS;
+*DUMPTYPE_MAXPROMOTEDAY = *Amanda::Configc::DUMPTYPE_MAXPROMOTEDAY;
+*DUMPTYPE_BUMPPERCENT = *Amanda::Configc::DUMPTYPE_BUMPPERCENT;
+*DUMPTYPE_BUMPSIZE = *Amanda::Configc::DUMPTYPE_BUMPSIZE;
+*DUMPTYPE_BUMPDAYS = *Amanda::Configc::DUMPTYPE_BUMPDAYS;
+*DUMPTYPE_BUMPMULT = *Amanda::Configc::DUMPTYPE_BUMPMULT;
+*DUMPTYPE_STARTTIME = *Amanda::Configc::DUMPTYPE_STARTTIME;
+*DUMPTYPE_STRATEGY = *Amanda::Configc::DUMPTYPE_STRATEGY;
+*DUMPTYPE_ESTIMATE = *Amanda::Configc::DUMPTYPE_ESTIMATE;
+*DUMPTYPE_COMPRESS = *Amanda::Configc::DUMPTYPE_COMPRESS;
+*DUMPTYPE_ENCRYPT = *Amanda::Configc::DUMPTYPE_ENCRYPT;
+*DUMPTYPE_SRV_DECRYPT_OPT = *Amanda::Configc::DUMPTYPE_SRV_DECRYPT_OPT;
+*DUMPTYPE_CLNT_DECRYPT_OPT = *Amanda::Configc::DUMPTYPE_CLNT_DECRYPT_OPT;
+*DUMPTYPE_COMPRATE = *Amanda::Configc::DUMPTYPE_COMPRATE;
+*DUMPTYPE_TAPE_SPLITSIZE = *Amanda::Configc::DUMPTYPE_TAPE_SPLITSIZE;
+*DUMPTYPE_FALLBACK_SPLITSIZE = *Amanda::Configc::DUMPTYPE_FALLBACK_SPLITSIZE;
+*DUMPTYPE_SPLIT_DISKBUFFER = *Amanda::Configc::DUMPTYPE_SPLIT_DISKBUFFER;
+*DUMPTYPE_RECORD = *Amanda::Configc::DUMPTYPE_RECORD;
+*DUMPTYPE_SKIP_INCR = *Amanda::Configc::DUMPTYPE_SKIP_INCR;
+*DUMPTYPE_SKIP_FULL = *Amanda::Configc::DUMPTYPE_SKIP_FULL;
+*DUMPTYPE_HOLDINGDISK = *Amanda::Configc::DUMPTYPE_HOLDINGDISK;
+*DUMPTYPE_KENCRYPT = *Amanda::Configc::DUMPTYPE_KENCRYPT;
+*DUMPTYPE_IGNORE = *Amanda::Configc::DUMPTYPE_IGNORE;
+*DUMPTYPE_INDEX = *Amanda::Configc::DUMPTYPE_INDEX;
+*INTER_COMMENT = *Amanda::Configc::INTER_COMMENT;
+*INTER_MAXUSAGE = *Amanda::Configc::INTER_MAXUSAGE;
+*HOLDING_COMMENT = *Amanda::Configc::HOLDING_COMMENT;
+*HOLDING_DISKDIR = *Amanda::Configc::HOLDING_DISKDIR;
+*HOLDING_DISKSIZE = *Amanda::Configc::HOLDING_DISKSIZE;
+*HOLDING_CHUNKSIZE = *Amanda::Configc::HOLDING_CHUNKSIZE;
+*HOLD_NEVER = *Amanda::Configc::HOLD_NEVER;
+*HOLD_AUTO = *Amanda::Configc::HOLD_AUTO;
+*HOLD_REQUIRED = *Amanda::Configc::HOLD_REQUIRED;
+*COMP_NONE = *Amanda::Configc::COMP_NONE;
+*COMP_FAST = *Amanda::Configc::COMP_FAST;
+*COMP_BEST = *Amanda::Configc::COMP_BEST;
+*COMP_CUST = *Amanda::Configc::COMP_CUST;
+*COMP_SERVER_FAST = *Amanda::Configc::COMP_SERVER_FAST;
+*COMP_SERVER_BEST = *Amanda::Configc::COMP_SERVER_BEST;
+*COMP_SERVER_CUST = *Amanda::Configc::COMP_SERVER_CUST;
+*ENCRYPT_NONE = *Amanda::Configc::ENCRYPT_NONE;
+*ENCRYPT_CUST = *Amanda::Configc::ENCRYPT_CUST;
+*ENCRYPT_SERV_CUST = *Amanda::Configc::ENCRYPT_SERV_CUST;
+*DS_SKIP = *Amanda::Configc::DS_SKIP;
+*DS_STANDARD = *Amanda::Configc::DS_STANDARD;
+*DS_NOFULL = *Amanda::Configc::DS_NOFULL;
+*DS_NOINC = *Amanda::Configc::DS_NOINC;
+*DS_4 = *Amanda::Configc::DS_4;
+*DS_5 = *Amanda::Configc::DS_5;
+*DS_HANOI = *Amanda::Configc::DS_HANOI;
+*DS_INCRONLY = *Amanda::Configc::DS_INCRONLY;
+*ES_CLIENT = *Amanda::Configc::ES_CLIENT;
+*ES_SERVER = *Amanda::Configc::ES_SERVER;
+*ES_CALCSIZE = *Amanda::Configc::ES_CALCSIZE;
+*ALGO_FIRST = *Amanda::Configc::ALGO_FIRST;
+*ALGO_FIRSTFIT = *Amanda::Configc::ALGO_FIRSTFIT;
+*ALGO_LARGEST = *Amanda::Configc::ALGO_LARGEST;
+*ALGO_LARGESTFIT = *Amanda::Configc::ALGO_LARGESTFIT;
+*ALGO_SMALLEST = *Amanda::Configc::ALGO_SMALLEST;
+*ALGO_LAST = *Amanda::Configc::ALGO_LAST;
+*debug_amandad = *Amanda::Configc::debug_amandad;
+*debug_amidxtaped = *Amanda::Configc::debug_amidxtaped;
+*debug_amindexd = *Amanda::Configc::debug_amindexd;
+*debug_amrecover = *Amanda::Configc::debug_amrecover;
+*debug_auth = *Amanda::Configc::debug_auth;
+*debug_event = *Amanda::Configc::debug_event;
+*debug_holding = *Amanda::Configc::debug_holding;
+*debug_protocol = *Amanda::Configc::debug_protocol;
+*debug_planner = *Amanda::Configc::debug_planner;
+*debug_driver = *Amanda::Configc::debug_driver;
+*debug_dumper = *Amanda::Configc::debug_dumper;
+*debug_chunker = *Amanda::Configc::debug_chunker;
+*debug_taper = *Amanda::Configc::debug_taper;
+*debug_selfcheck = *Amanda::Configc::debug_selfcheck;
+*debug_sendsize = *Amanda::Configc::debug_sendsize;
+*debug_sendbackup = *Amanda::Configc::debug_sendbackup;
+*CONFIG_INIT_EXPLICIT_NAME = *Amanda::Configc::CONFIG_INIT_EXPLICIT_NAME;
+*CONFIG_INIT_USE_CWD = *Amanda::Configc::CONFIG_INIT_USE_CWD;
+*CONFIG_INIT_CLIENT = *Amanda::Configc::CONFIG_INIT_CLIENT;
+*CONFIG_INIT_OVERLAY = *Amanda::Configc::CONFIG_INIT_OVERLAY;
+*CONFIG_INIT_FATAL = *Amanda::Configc::CONFIG_INIT_FATAL;
+
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+
+=head1 NAME
+
+Amanda::Config - access to Amanda configuration parameters
+
+=head1 SYNOPSIS
+
+  use Amanda::Config qw( :init :getconf );
+
+  config_init($CONFIG_INIT_EXPLICIT_NAME, $ARGV[1])
+    or die("errors processing config file " . $Amanda::Config::get_config_filename());
+
+  print "tape device is ", getconf($CNF_TAPEDEV), "\n";
+
+This API closely parallels the C API.  See F<conffile.h> for details
+on the functions and constants available here.
+
+=head1 API STATUS
+
+Stable
+
+=head1 INITIALIZATION
+
+The Amanda configuration is treated as a global state for the
+application.  It is not possible to load two configurations
+simultaneously.
+
+All initialization-related symbols can be imported with the tag
+C<:init>.
+
+=head2 LOADING CONFIGURATION
+
+The Amanda configuration is loaded with the aptly named
+C<config_init($flags, $name)>.  Because of the great variety in
+invocation method among Amanda applications, this function has a number
+of flags that affect its behavior.  These flags can be OR'd together.
+
+=over
+
+=item If C<CONFIG_INIT_EXPLICIT_NAME> is given, then the C<$name>
+parameter can contain the name of a configuration to load.
+
+=item If C<CONFIG_INIT_USE_CWD> is given, and if the current directory
+contains C<amanda.conf>, then that file is loaded.
+
+=item If C<CONFIG_INIT_CLIENT> is given, then a client configuration
+is loaded.
+
+=item If C<CONFIG_INIT_OVERLAY> is given, then any existing
+configuration is not reset.
+
+=item If C<CONFIG_INIT_FATAL> is given, then any errors are considered
+fatal, and C<config_init> does not return.
+
+=back
+
+See C<conffile.h> for more detailed information on these flags and
+their interactions.
+
+C<config_uninit()> reverses the effects of C<config_init>.  It is
+not often used.
+
+Once the configuration is loaded, the configuration name
+(e.g., "DailySet1"), directory (C</etc/amanda/DailySet1>),
+and filename (C</etc/amanda/DailySet1/amanda.conf>) are
+available from C<get_config_name()>, C<get_config_dir()>, and
+C<get_config_filename()>, respectively.
+
+=head2 CONFIG OVERWRITES
+
+Most Amanda applications accept the command-line option C<-o>
+to "overwrite" configuration values in C<amanda.conf>.  In Perl
+applications, these options should be parsed with L<Getopt::Long|Getopt::Long>, with
+the action being a call to C<add_config_overwrite_opt>.  For example:
+
+  my $config_overwrites = new_config_overwrites($#ARGV+1);
+    GetOptions(
+       # ...
+       'o=s' => sub { add_config_overwrite_opt($config_overwrites, $_[1]); },
+    ) or usage();
+  my $cfg_ok = config_init($CONFIG_INIT_EXPLICIT_NAME | $CONFIG_INIT_USE_CWD, $config_name);
+  apply_config_overwrites($config_overwrites);
+
+C<new_config_overwrites($size_estimate)> creates a new
+overwrites object, using the given size as an estimate of
+the number of items it will contain (C<$#ARGC/2> is a good
+estimate).  Individual configuration options are then added via
+C<add_config_overwrite($co, $key, $value)> (which takes a key/value
+pair) or C<add_config_overwrite_opt($co, $optarg)>, which parses a
+string following C<-o> on the command line.
+
+Once the overwrites are gathered, they are applied with
+C<apply_config_overwrites($co)>, which applies the overwrites to the
+active configuration.  No further operations can be performed on the
+overwrites object after C<apply_config_overwrites> has been called.
+
+The utility function C<get_config_options()> returns a list of
+command-line arguments to represent any overwrites that were used
+to generate the current configuration.  (TODO: this function isn't
+available yet)
+
+=head1 PARAMETER ACCESS
+
+Amanda configurations consist of "global" parameters and several
+sets of "subsections" -- one set for dumptypes, one for tapetypes,
+and so on.
+
+All of the global parameters are represented by a constant beginning
+with C<$CNF_>, e.g., C<$CNF_LABELSTR>.  The function C<getconf($cnf)>
+returns the value of parameter C<$cnf>, in whatever format is
+appropriate for the parameter.  C<getconf_seen($cnf)> returns a true
+value if C<$cnf> was seen in the configuration file.  If it was not
+seen, then it will have its default value.
+
+Some parameters have enumerated types.  The values for those
+enumerations are available from this module with the same name as
+in C<conffile.h>.  For example, C<$CNF_TAPERALGO> will yield a value
+from the enumeration C<taperalgo_t>, the constants for which all
+begin with C<$ALGO_>.  See C<conffile.h> for the details.
+
+Each subsection type has the following functions:
+
+=over
+
+=item C<lookup_TYP($subsec_name)>
+
+which returns an opaque object
+(C<$ss>) representing the subsection, or C<undef> if no subsection
+with that name exists;
+
+=item C<TYP_name($ss)>
+
+returning the name of the subsection;
+
+=item C<TYP_getconf($ss, $cnf)>
+
+which fetches a parameter value from C<$ss>; and
+
+=item C<TYP_seen($ss, $cnf)>
+
+which returns a true value if <$cnf> was seen in the subsection.
+
+=back
+
+The subsections are:
+
+=over
+
+=item C<tapetype>
+
+with constants beginning with C<$TAPETYPE_>
+
+=item C<dumptype>
+
+with constants beginning with C<$DUMPTYPE_>
+
+=item C<holdingdisk>
+
+with constants beginning with C<$HOLDING_>
+
+=item C<application>
+
+with constants beginning with C<$APPLICATION_>
+
+=item C<script>
+
+with constants beginning with C<$PP_SCRIPT_>
+
+=back
+
+See C<conffile.h> for the names of the constants themselves.
+
+Parameter values are available by name from C<getconf_byname($name)>.
+This function implements the C<TYP:NAME:PARAM> syntax advertised by
+C<amgetconf> to access values in subsections.  C<getconf_list($typ)>
+returns a list of the names of all subsections of the given type.
+
+The C<$CNF_DISPLAYUNIT> implies a certain divisor to convert from
+kilobytes to the desired unit.  This divisor is available from
+C<getconf_unit_divisor()>.  Note carefully that it is a I<divisor>
+for a value in I<kilobytes>!
+
+Finally, various subsections of Amanda enable verbose debugging via
+configuration parameters.  The status of each parameter is available
+a similarly-named variable, e.g., C<$debug_auth>.
+
+All parameter access functions and constants can be imported with
+the tag C<:getconf>.
+
+=head1 MISCELLANEOUS
+
+These functions defy categorization.
+
+The function C<config_dir_relative> will interpret a path relative to
+the current configuration directory.  Absolute paths are passed through
+unchanged, while relative paths are converted to absolute paths.
+
+C<dump_configuration()> dumps the current configuration, in a format
+suitable for re-evaluation for this module, to standard output.
+This function may be revised to return a string.
+
+Several parts of Amanda need to convert unit modifier value like
+"gbytes" to a multiplier.  The function C<find_multiplier($str)>
+returns the unit multiplier for such a string.  For example, "mbytes"
+is converted to 1048576 (1024*1024).
+
+=cut
+
+push @EXPORT_OK, qw(confparm_key_to_string);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw(confparm_key_to_string);
+
+my %_confparm_key_VALUES;
+#Convert an enum value to a single string
+sub confparm_key_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_confparm_key_VALUES) {
+       my $v = $_confparm_key_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($CNF_ORG);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_ORG);
+
+$_confparm_key_VALUES{"CNF_ORG"} = $CNF_ORG;
+
+push @EXPORT_OK, qw($CNF_CONF);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_CONF);
+
+$_confparm_key_VALUES{"CNF_CONF"} = $CNF_CONF;
+
+push @EXPORT_OK, qw($CNF_INDEX_SERVER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_INDEX_SERVER);
+
+$_confparm_key_VALUES{"CNF_INDEX_SERVER"} = $CNF_INDEX_SERVER;
+
+push @EXPORT_OK, qw($CNF_TAPE_SERVER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_TAPE_SERVER);
+
+$_confparm_key_VALUES{"CNF_TAPE_SERVER"} = $CNF_TAPE_SERVER;
+
+push @EXPORT_OK, qw($CNF_AUTH);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_AUTH);
+
+$_confparm_key_VALUES{"CNF_AUTH"} = $CNF_AUTH;
+
+push @EXPORT_OK, qw($CNF_SSH_KEYS);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_SSH_KEYS);
+
+$_confparm_key_VALUES{"CNF_SSH_KEYS"} = $CNF_SSH_KEYS;
+
+push @EXPORT_OK, qw($CNF_AMANDAD_PATH);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_AMANDAD_PATH);
+
+$_confparm_key_VALUES{"CNF_AMANDAD_PATH"} = $CNF_AMANDAD_PATH;
+
+push @EXPORT_OK, qw($CNF_CLIENT_USERNAME);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_CLIENT_USERNAME);
+
+$_confparm_key_VALUES{"CNF_CLIENT_USERNAME"} = $CNF_CLIENT_USERNAME;
+
+push @EXPORT_OK, qw($CNF_GNUTAR_LIST_DIR);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_GNUTAR_LIST_DIR);
+
+$_confparm_key_VALUES{"CNF_GNUTAR_LIST_DIR"} = $CNF_GNUTAR_LIST_DIR;
+
+push @EXPORT_OK, qw($CNF_AMANDATES);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_AMANDATES);
+
+$_confparm_key_VALUES{"CNF_AMANDATES"} = $CNF_AMANDATES;
+
+push @EXPORT_OK, qw($CNF_MAILTO);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_MAILTO);
+
+$_confparm_key_VALUES{"CNF_MAILTO"} = $CNF_MAILTO;
+
+push @EXPORT_OK, qw($CNF_DUMPUSER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DUMPUSER);
+
+$_confparm_key_VALUES{"CNF_DUMPUSER"} = $CNF_DUMPUSER;
+
+push @EXPORT_OK, qw($CNF_TAPEDEV);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_TAPEDEV);
+
+$_confparm_key_VALUES{"CNF_TAPEDEV"} = $CNF_TAPEDEV;
+
+push @EXPORT_OK, qw($CNF_DEVICE_PROPERTY);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEVICE_PROPERTY);
+
+$_confparm_key_VALUES{"CNF_DEVICE_PROPERTY"} = $CNF_DEVICE_PROPERTY;
+
+push @EXPORT_OK, qw($CNF_CHANGERDEV);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_CHANGERDEV);
+
+$_confparm_key_VALUES{"CNF_CHANGERDEV"} = $CNF_CHANGERDEV;
+
+push @EXPORT_OK, qw($CNF_CHANGERFILE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_CHANGERFILE);
+
+$_confparm_key_VALUES{"CNF_CHANGERFILE"} = $CNF_CHANGERFILE;
+
+push @EXPORT_OK, qw($CNF_LABELSTR);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_LABELSTR);
+
+$_confparm_key_VALUES{"CNF_LABELSTR"} = $CNF_LABELSTR;
+
+push @EXPORT_OK, qw($CNF_TAPELIST);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_TAPELIST);
+
+$_confparm_key_VALUES{"CNF_TAPELIST"} = $CNF_TAPELIST;
+
+push @EXPORT_OK, qw($CNF_DISKFILE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DISKFILE);
+
+$_confparm_key_VALUES{"CNF_DISKFILE"} = $CNF_DISKFILE;
+
+push @EXPORT_OK, qw($CNF_INFOFILE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_INFOFILE);
+
+$_confparm_key_VALUES{"CNF_INFOFILE"} = $CNF_INFOFILE;
+
+push @EXPORT_OK, qw($CNF_LOGDIR);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_LOGDIR);
+
+$_confparm_key_VALUES{"CNF_LOGDIR"} = $CNF_LOGDIR;
+
+push @EXPORT_OK, qw($CNF_INDEXDIR);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_INDEXDIR);
+
+$_confparm_key_VALUES{"CNF_INDEXDIR"} = $CNF_INDEXDIR;
+
+push @EXPORT_OK, qw($CNF_TAPETYPE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_TAPETYPE);
+
+$_confparm_key_VALUES{"CNF_TAPETYPE"} = $CNF_TAPETYPE;
+
+push @EXPORT_OK, qw($CNF_DUMPCYCLE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DUMPCYCLE);
+
+$_confparm_key_VALUES{"CNF_DUMPCYCLE"} = $CNF_DUMPCYCLE;
+
+push @EXPORT_OK, qw($CNF_RUNSPERCYCLE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_RUNSPERCYCLE);
+
+$_confparm_key_VALUES{"CNF_RUNSPERCYCLE"} = $CNF_RUNSPERCYCLE;
+
+push @EXPORT_OK, qw($CNF_TAPECYCLE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_TAPECYCLE);
+
+$_confparm_key_VALUES{"CNF_TAPECYCLE"} = $CNF_TAPECYCLE;
+
+push @EXPORT_OK, qw($CNF_NETUSAGE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_NETUSAGE);
+
+$_confparm_key_VALUES{"CNF_NETUSAGE"} = $CNF_NETUSAGE;
+
+push @EXPORT_OK, qw($CNF_INPARALLEL);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_INPARALLEL);
+
+$_confparm_key_VALUES{"CNF_INPARALLEL"} = $CNF_INPARALLEL;
+
+push @EXPORT_OK, qw($CNF_DUMPORDER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DUMPORDER);
+
+$_confparm_key_VALUES{"CNF_DUMPORDER"} = $CNF_DUMPORDER;
+
+push @EXPORT_OK, qw($CNF_BUMPPERCENT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_BUMPPERCENT);
+
+$_confparm_key_VALUES{"CNF_BUMPPERCENT"} = $CNF_BUMPPERCENT;
+
+push @EXPORT_OK, qw($CNF_BUMPSIZE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_BUMPSIZE);
+
+$_confparm_key_VALUES{"CNF_BUMPSIZE"} = $CNF_BUMPSIZE;
+
+push @EXPORT_OK, qw($CNF_BUMPMULT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_BUMPMULT);
+
+$_confparm_key_VALUES{"CNF_BUMPMULT"} = $CNF_BUMPMULT;
+
+push @EXPORT_OK, qw($CNF_BUMPDAYS);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_BUMPDAYS);
+
+$_confparm_key_VALUES{"CNF_BUMPDAYS"} = $CNF_BUMPDAYS;
+
+push @EXPORT_OK, qw($CNF_TPCHANGER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_TPCHANGER);
+
+$_confparm_key_VALUES{"CNF_TPCHANGER"} = $CNF_TPCHANGER;
+
+push @EXPORT_OK, qw($CNF_RUNTAPES);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_RUNTAPES);
+
+$_confparm_key_VALUES{"CNF_RUNTAPES"} = $CNF_RUNTAPES;
+
+push @EXPORT_OK, qw($CNF_MAXDUMPS);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_MAXDUMPS);
+
+$_confparm_key_VALUES{"CNF_MAXDUMPS"} = $CNF_MAXDUMPS;
+
+push @EXPORT_OK, qw($CNF_ETIMEOUT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_ETIMEOUT);
+
+$_confparm_key_VALUES{"CNF_ETIMEOUT"} = $CNF_ETIMEOUT;
+
+push @EXPORT_OK, qw($CNF_DTIMEOUT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DTIMEOUT);
+
+$_confparm_key_VALUES{"CNF_DTIMEOUT"} = $CNF_DTIMEOUT;
+
+push @EXPORT_OK, qw($CNF_CTIMEOUT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_CTIMEOUT);
+
+$_confparm_key_VALUES{"CNF_CTIMEOUT"} = $CNF_CTIMEOUT;
+
+push @EXPORT_OK, qw($CNF_TAPEBUFS);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_TAPEBUFS);
+
+$_confparm_key_VALUES{"CNF_TAPEBUFS"} = $CNF_TAPEBUFS;
+
+push @EXPORT_OK, qw($CNF_DEVICE_OUTPUT_BUFFER_SIZE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEVICE_OUTPUT_BUFFER_SIZE);
+
+$_confparm_key_VALUES{"CNF_DEVICE_OUTPUT_BUFFER_SIZE"} = $CNF_DEVICE_OUTPUT_BUFFER_SIZE;
+
+push @EXPORT_OK, qw($CNF_PRINTER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_PRINTER);
+
+$_confparm_key_VALUES{"CNF_PRINTER"} = $CNF_PRINTER;
+
+push @EXPORT_OK, qw($CNF_AUTOFLUSH);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_AUTOFLUSH);
+
+$_confparm_key_VALUES{"CNF_AUTOFLUSH"} = $CNF_AUTOFLUSH;
+
+push @EXPORT_OK, qw($CNF_RESERVE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_RESERVE);
+
+$_confparm_key_VALUES{"CNF_RESERVE"} = $CNF_RESERVE;
+
+push @EXPORT_OK, qw($CNF_MAXDUMPSIZE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_MAXDUMPSIZE);
+
+$_confparm_key_VALUES{"CNF_MAXDUMPSIZE"} = $CNF_MAXDUMPSIZE;
+
+push @EXPORT_OK, qw($CNF_COLUMNSPEC);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_COLUMNSPEC);
+
+$_confparm_key_VALUES{"CNF_COLUMNSPEC"} = $CNF_COLUMNSPEC;
+
+push @EXPORT_OK, qw($CNF_AMRECOVER_DO_FSF);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_AMRECOVER_DO_FSF);
+
+$_confparm_key_VALUES{"CNF_AMRECOVER_DO_FSF"} = $CNF_AMRECOVER_DO_FSF;
+
+push @EXPORT_OK, qw($CNF_AMRECOVER_CHECK_LABEL);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_AMRECOVER_CHECK_LABEL);
+
+$_confparm_key_VALUES{"CNF_AMRECOVER_CHECK_LABEL"} = $CNF_AMRECOVER_CHECK_LABEL;
+
+push @EXPORT_OK, qw($CNF_AMRECOVER_CHANGER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_AMRECOVER_CHANGER);
+
+$_confparm_key_VALUES{"CNF_AMRECOVER_CHANGER"} = $CNF_AMRECOVER_CHANGER;
+
+push @EXPORT_OK, qw($CNF_TAPERALGO);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_TAPERALGO);
+
+$_confparm_key_VALUES{"CNF_TAPERALGO"} = $CNF_TAPERALGO;
+
+push @EXPORT_OK, qw($CNF_FLUSH_THRESHOLD_DUMPED);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_FLUSH_THRESHOLD_DUMPED);
+
+$_confparm_key_VALUES{"CNF_FLUSH_THRESHOLD_DUMPED"} = $CNF_FLUSH_THRESHOLD_DUMPED;
+
+push @EXPORT_OK, qw($CNF_FLUSH_THRESHOLD_SCHEDULED);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_FLUSH_THRESHOLD_SCHEDULED);
+
+$_confparm_key_VALUES{"CNF_FLUSH_THRESHOLD_SCHEDULED"} = $CNF_FLUSH_THRESHOLD_SCHEDULED;
+
+push @EXPORT_OK, qw($CNF_TAPERFLUSH);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_TAPERFLUSH);
+
+$_confparm_key_VALUES{"CNF_TAPERFLUSH"} = $CNF_TAPERFLUSH;
+
+push @EXPORT_OK, qw($CNF_DISPLAYUNIT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DISPLAYUNIT);
+
+$_confparm_key_VALUES{"CNF_DISPLAYUNIT"} = $CNF_DISPLAYUNIT;
+
+push @EXPORT_OK, qw($CNF_KRB5KEYTAB);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_KRB5KEYTAB);
+
+$_confparm_key_VALUES{"CNF_KRB5KEYTAB"} = $CNF_KRB5KEYTAB;
+
+push @EXPORT_OK, qw($CNF_KRB5PRINCIPAL);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_KRB5PRINCIPAL);
+
+$_confparm_key_VALUES{"CNF_KRB5PRINCIPAL"} = $CNF_KRB5PRINCIPAL;
+
+push @EXPORT_OK, qw($CNF_LABEL_NEW_TAPES);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_LABEL_NEW_TAPES);
+
+$_confparm_key_VALUES{"CNF_LABEL_NEW_TAPES"} = $CNF_LABEL_NEW_TAPES;
+
+push @EXPORT_OK, qw($CNF_USETIMESTAMPS);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_USETIMESTAMPS);
+
+$_confparm_key_VALUES{"CNF_USETIMESTAMPS"} = $CNF_USETIMESTAMPS;
+
+push @EXPORT_OK, qw($CNF_REP_TRIES);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_REP_TRIES);
+
+$_confparm_key_VALUES{"CNF_REP_TRIES"} = $CNF_REP_TRIES;
+
+push @EXPORT_OK, qw($CNF_CONNECT_TRIES);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_CONNECT_TRIES);
+
+$_confparm_key_VALUES{"CNF_CONNECT_TRIES"} = $CNF_CONNECT_TRIES;
+
+push @EXPORT_OK, qw($CNF_REQ_TRIES);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_REQ_TRIES);
+
+$_confparm_key_VALUES{"CNF_REQ_TRIES"} = $CNF_REQ_TRIES;
+
+push @EXPORT_OK, qw($CNF_DEBUG_AMANDAD);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_AMANDAD);
+
+$_confparm_key_VALUES{"CNF_DEBUG_AMANDAD"} = $CNF_DEBUG_AMANDAD;
+
+push @EXPORT_OK, qw($CNF_DEBUG_AMIDXTAPED);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_AMIDXTAPED);
+
+$_confparm_key_VALUES{"CNF_DEBUG_AMIDXTAPED"} = $CNF_DEBUG_AMIDXTAPED;
+
+push @EXPORT_OK, qw($CNF_DEBUG_AMINDEXD);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_AMINDEXD);
+
+$_confparm_key_VALUES{"CNF_DEBUG_AMINDEXD"} = $CNF_DEBUG_AMINDEXD;
+
+push @EXPORT_OK, qw($CNF_DEBUG_AMRECOVER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_AMRECOVER);
+
+$_confparm_key_VALUES{"CNF_DEBUG_AMRECOVER"} = $CNF_DEBUG_AMRECOVER;
+
+push @EXPORT_OK, qw($CNF_DEBUG_AUTH);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_AUTH);
+
+$_confparm_key_VALUES{"CNF_DEBUG_AUTH"} = $CNF_DEBUG_AUTH;
+
+push @EXPORT_OK, qw($CNF_DEBUG_EVENT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_EVENT);
+
+$_confparm_key_VALUES{"CNF_DEBUG_EVENT"} = $CNF_DEBUG_EVENT;
+
+push @EXPORT_OK, qw($CNF_DEBUG_HOLDING);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_HOLDING);
+
+$_confparm_key_VALUES{"CNF_DEBUG_HOLDING"} = $CNF_DEBUG_HOLDING;
+
+push @EXPORT_OK, qw($CNF_DEBUG_PROTOCOL);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_PROTOCOL);
+
+$_confparm_key_VALUES{"CNF_DEBUG_PROTOCOL"} = $CNF_DEBUG_PROTOCOL;
+
+push @EXPORT_OK, qw($CNF_DEBUG_PLANNER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_PLANNER);
+
+$_confparm_key_VALUES{"CNF_DEBUG_PLANNER"} = $CNF_DEBUG_PLANNER;
+
+push @EXPORT_OK, qw($CNF_DEBUG_DRIVER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_DRIVER);
+
+$_confparm_key_VALUES{"CNF_DEBUG_DRIVER"} = $CNF_DEBUG_DRIVER;
+
+push @EXPORT_OK, qw($CNF_DEBUG_DUMPER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_DUMPER);
+
+$_confparm_key_VALUES{"CNF_DEBUG_DUMPER"} = $CNF_DEBUG_DUMPER;
+
+push @EXPORT_OK, qw($CNF_DEBUG_CHUNKER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_CHUNKER);
+
+$_confparm_key_VALUES{"CNF_DEBUG_CHUNKER"} = $CNF_DEBUG_CHUNKER;
+
+push @EXPORT_OK, qw($CNF_DEBUG_TAPER);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_TAPER);
+
+$_confparm_key_VALUES{"CNF_DEBUG_TAPER"} = $CNF_DEBUG_TAPER;
+
+push @EXPORT_OK, qw($CNF_DEBUG_SELFCHECK);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_SELFCHECK);
+
+$_confparm_key_VALUES{"CNF_DEBUG_SELFCHECK"} = $CNF_DEBUG_SELFCHECK;
+
+push @EXPORT_OK, qw($CNF_DEBUG_SENDSIZE);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_SENDSIZE);
+
+$_confparm_key_VALUES{"CNF_DEBUG_SENDSIZE"} = $CNF_DEBUG_SENDSIZE;
+
+push @EXPORT_OK, qw($CNF_DEBUG_SENDBACKUP);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_DEBUG_SENDBACKUP);
+
+$_confparm_key_VALUES{"CNF_DEBUG_SENDBACKUP"} = $CNF_DEBUG_SENDBACKUP;
+
+push @EXPORT_OK, qw($CNF_RESERVED_UDP_PORT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_RESERVED_UDP_PORT);
+
+$_confparm_key_VALUES{"CNF_RESERVED_UDP_PORT"} = $CNF_RESERVED_UDP_PORT;
+
+push @EXPORT_OK, qw($CNF_RESERVED_TCP_PORT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_RESERVED_TCP_PORT);
+
+$_confparm_key_VALUES{"CNF_RESERVED_TCP_PORT"} = $CNF_RESERVED_TCP_PORT;
+
+push @EXPORT_OK, qw($CNF_UNRESERVED_TCP_PORT);
+push @{$EXPORT_TAGS{"confparm_key"}}, qw($CNF_UNRESERVED_TCP_PORT);
+
+$_confparm_key_VALUES{"CNF_UNRESERVED_TCP_PORT"} = $CNF_UNRESERVED_TCP_PORT;
+
+#copy symbols in confparm_key to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"confparm_key"}};
+
+push @EXPORT_OK, qw(tapetype_key_to_string);
+push @{$EXPORT_TAGS{"tapetype_key"}}, qw(tapetype_key_to_string);
+
+my %_tapetype_key_VALUES;
+#Convert an enum value to a single string
+sub tapetype_key_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_tapetype_key_VALUES) {
+       my $v = $_tapetype_key_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($TAPETYPE_COMMENT);
+push @{$EXPORT_TAGS{"tapetype_key"}}, qw($TAPETYPE_COMMENT);
+
+$_tapetype_key_VALUES{"TAPETYPE_COMMENT"} = $TAPETYPE_COMMENT;
+
+push @EXPORT_OK, qw($TAPETYPE_LBL_TEMPL);
+push @{$EXPORT_TAGS{"tapetype_key"}}, qw($TAPETYPE_LBL_TEMPL);
+
+$_tapetype_key_VALUES{"TAPETYPE_LBL_TEMPL"} = $TAPETYPE_LBL_TEMPL;
+
+push @EXPORT_OK, qw($TAPETYPE_BLOCKSIZE);
+push @{$EXPORT_TAGS{"tapetype_key"}}, qw($TAPETYPE_BLOCKSIZE);
+
+$_tapetype_key_VALUES{"TAPETYPE_BLOCKSIZE"} = $TAPETYPE_BLOCKSIZE;
+
+push @EXPORT_OK, qw($TAPETYPE_READBLOCKSIZE);
+push @{$EXPORT_TAGS{"tapetype_key"}}, qw($TAPETYPE_READBLOCKSIZE);
+
+$_tapetype_key_VALUES{"TAPETYPE_READBLOCKSIZE"} = $TAPETYPE_READBLOCKSIZE;
+
+push @EXPORT_OK, qw($TAPETYPE_LENGTH);
+push @{$EXPORT_TAGS{"tapetype_key"}}, qw($TAPETYPE_LENGTH);
+
+$_tapetype_key_VALUES{"TAPETYPE_LENGTH"} = $TAPETYPE_LENGTH;
+
+push @EXPORT_OK, qw($TAPETYPE_FILEMARK);
+push @{$EXPORT_TAGS{"tapetype_key"}}, qw($TAPETYPE_FILEMARK);
+
+$_tapetype_key_VALUES{"TAPETYPE_FILEMARK"} = $TAPETYPE_FILEMARK;
+
+push @EXPORT_OK, qw($TAPETYPE_SPEED);
+push @{$EXPORT_TAGS{"tapetype_key"}}, qw($TAPETYPE_SPEED);
+
+$_tapetype_key_VALUES{"TAPETYPE_SPEED"} = $TAPETYPE_SPEED;
+
+push @EXPORT_OK, qw($TAPETYPE_FILE_PAD);
+push @{$EXPORT_TAGS{"tapetype_key"}}, qw($TAPETYPE_FILE_PAD);
+
+$_tapetype_key_VALUES{"TAPETYPE_FILE_PAD"} = $TAPETYPE_FILE_PAD;
+
+#copy symbols in tapetype_key to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"tapetype_key"}};
+
+push @EXPORT_OK, qw(dumptype_key_to_string);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw(dumptype_key_to_string);
+
+my %_dumptype_key_VALUES;
+#Convert an enum value to a single string
+sub dumptype_key_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_dumptype_key_VALUES) {
+       my $v = $_dumptype_key_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($DUMPTYPE_COMMENT);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_COMMENT);
+
+$_dumptype_key_VALUES{"DUMPTYPE_COMMENT"} = $DUMPTYPE_COMMENT;
+
+push @EXPORT_OK, qw($DUMPTYPE_PROGRAM);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_PROGRAM);
+
+$_dumptype_key_VALUES{"DUMPTYPE_PROGRAM"} = $DUMPTYPE_PROGRAM;
+
+push @EXPORT_OK, qw($DUMPTYPE_SRVCOMPPROG);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_SRVCOMPPROG);
+
+$_dumptype_key_VALUES{"DUMPTYPE_SRVCOMPPROG"} = $DUMPTYPE_SRVCOMPPROG;
+
+push @EXPORT_OK, qw($DUMPTYPE_CLNTCOMPPROG);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_CLNTCOMPPROG);
+
+$_dumptype_key_VALUES{"DUMPTYPE_CLNTCOMPPROG"} = $DUMPTYPE_CLNTCOMPPROG;
+
+push @EXPORT_OK, qw($DUMPTYPE_SRV_ENCRYPT);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_SRV_ENCRYPT);
+
+$_dumptype_key_VALUES{"DUMPTYPE_SRV_ENCRYPT"} = $DUMPTYPE_SRV_ENCRYPT;
+
+push @EXPORT_OK, qw($DUMPTYPE_CLNT_ENCRYPT);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_CLNT_ENCRYPT);
+
+$_dumptype_key_VALUES{"DUMPTYPE_CLNT_ENCRYPT"} = $DUMPTYPE_CLNT_ENCRYPT;
+
+push @EXPORT_OK, qw($DUMPTYPE_AMANDAD_PATH);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_AMANDAD_PATH);
+
+$_dumptype_key_VALUES{"DUMPTYPE_AMANDAD_PATH"} = $DUMPTYPE_AMANDAD_PATH;
+
+push @EXPORT_OK, qw($DUMPTYPE_CLIENT_USERNAME);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_CLIENT_USERNAME);
+
+$_dumptype_key_VALUES{"DUMPTYPE_CLIENT_USERNAME"} = $DUMPTYPE_CLIENT_USERNAME;
+
+push @EXPORT_OK, qw($DUMPTYPE_SSH_KEYS);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_SSH_KEYS);
+
+$_dumptype_key_VALUES{"DUMPTYPE_SSH_KEYS"} = $DUMPTYPE_SSH_KEYS;
+
+push @EXPORT_OK, qw($DUMPTYPE_SECURITY_DRIVER);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_SECURITY_DRIVER);
+
+$_dumptype_key_VALUES{"DUMPTYPE_SECURITY_DRIVER"} = $DUMPTYPE_SECURITY_DRIVER;
+
+push @EXPORT_OK, qw($DUMPTYPE_EXCLUDE);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_EXCLUDE);
+
+$_dumptype_key_VALUES{"DUMPTYPE_EXCLUDE"} = $DUMPTYPE_EXCLUDE;
+
+push @EXPORT_OK, qw($DUMPTYPE_INCLUDE);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_INCLUDE);
+
+$_dumptype_key_VALUES{"DUMPTYPE_INCLUDE"} = $DUMPTYPE_INCLUDE;
+
+push @EXPORT_OK, qw($DUMPTYPE_PRIORITY);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_PRIORITY);
+
+$_dumptype_key_VALUES{"DUMPTYPE_PRIORITY"} = $DUMPTYPE_PRIORITY;
+
+push @EXPORT_OK, qw($DUMPTYPE_DUMPCYCLE);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_DUMPCYCLE);
+
+$_dumptype_key_VALUES{"DUMPTYPE_DUMPCYCLE"} = $DUMPTYPE_DUMPCYCLE;
+
+push @EXPORT_OK, qw($DUMPTYPE_MAXDUMPS);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_MAXDUMPS);
+
+$_dumptype_key_VALUES{"DUMPTYPE_MAXDUMPS"} = $DUMPTYPE_MAXDUMPS;
+
+push @EXPORT_OK, qw($DUMPTYPE_MAXPROMOTEDAY);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_MAXPROMOTEDAY);
+
+$_dumptype_key_VALUES{"DUMPTYPE_MAXPROMOTEDAY"} = $DUMPTYPE_MAXPROMOTEDAY;
+
+push @EXPORT_OK, qw($DUMPTYPE_BUMPPERCENT);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_BUMPPERCENT);
+
+$_dumptype_key_VALUES{"DUMPTYPE_BUMPPERCENT"} = $DUMPTYPE_BUMPPERCENT;
+
+push @EXPORT_OK, qw($DUMPTYPE_BUMPSIZE);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_BUMPSIZE);
+
+$_dumptype_key_VALUES{"DUMPTYPE_BUMPSIZE"} = $DUMPTYPE_BUMPSIZE;
+
+push @EXPORT_OK, qw($DUMPTYPE_BUMPDAYS);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_BUMPDAYS);
+
+$_dumptype_key_VALUES{"DUMPTYPE_BUMPDAYS"} = $DUMPTYPE_BUMPDAYS;
+
+push @EXPORT_OK, qw($DUMPTYPE_BUMPMULT);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_BUMPMULT);
+
+$_dumptype_key_VALUES{"DUMPTYPE_BUMPMULT"} = $DUMPTYPE_BUMPMULT;
+
+push @EXPORT_OK, qw($DUMPTYPE_STARTTIME);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_STARTTIME);
+
+$_dumptype_key_VALUES{"DUMPTYPE_STARTTIME"} = $DUMPTYPE_STARTTIME;
+
+push @EXPORT_OK, qw($DUMPTYPE_STRATEGY);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_STRATEGY);
+
+$_dumptype_key_VALUES{"DUMPTYPE_STRATEGY"} = $DUMPTYPE_STRATEGY;
+
+push @EXPORT_OK, qw($DUMPTYPE_ESTIMATE);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_ESTIMATE);
+
+$_dumptype_key_VALUES{"DUMPTYPE_ESTIMATE"} = $DUMPTYPE_ESTIMATE;
+
+push @EXPORT_OK, qw($DUMPTYPE_COMPRESS);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_COMPRESS);
+
+$_dumptype_key_VALUES{"DUMPTYPE_COMPRESS"} = $DUMPTYPE_COMPRESS;
+
+push @EXPORT_OK, qw($DUMPTYPE_ENCRYPT);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_ENCRYPT);
+
+$_dumptype_key_VALUES{"DUMPTYPE_ENCRYPT"} = $DUMPTYPE_ENCRYPT;
+
+push @EXPORT_OK, qw($DUMPTYPE_SRV_DECRYPT_OPT);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_SRV_DECRYPT_OPT);
+
+$_dumptype_key_VALUES{"DUMPTYPE_SRV_DECRYPT_OPT"} = $DUMPTYPE_SRV_DECRYPT_OPT;
+
+push @EXPORT_OK, qw($DUMPTYPE_CLNT_DECRYPT_OPT);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_CLNT_DECRYPT_OPT);
+
+$_dumptype_key_VALUES{"DUMPTYPE_CLNT_DECRYPT_OPT"} = $DUMPTYPE_CLNT_DECRYPT_OPT;
+
+push @EXPORT_OK, qw($DUMPTYPE_COMPRATE);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_COMPRATE);
+
+$_dumptype_key_VALUES{"DUMPTYPE_COMPRATE"} = $DUMPTYPE_COMPRATE;
+
+push @EXPORT_OK, qw($DUMPTYPE_TAPE_SPLITSIZE);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_TAPE_SPLITSIZE);
+
+$_dumptype_key_VALUES{"DUMPTYPE_TAPE_SPLITSIZE"} = $DUMPTYPE_TAPE_SPLITSIZE;
+
+push @EXPORT_OK, qw($DUMPTYPE_FALLBACK_SPLITSIZE);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_FALLBACK_SPLITSIZE);
+
+$_dumptype_key_VALUES{"DUMPTYPE_FALLBACK_SPLITSIZE"} = $DUMPTYPE_FALLBACK_SPLITSIZE;
+
+push @EXPORT_OK, qw($DUMPTYPE_SPLIT_DISKBUFFER);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_SPLIT_DISKBUFFER);
+
+$_dumptype_key_VALUES{"DUMPTYPE_SPLIT_DISKBUFFER"} = $DUMPTYPE_SPLIT_DISKBUFFER;
+
+push @EXPORT_OK, qw($DUMPTYPE_RECORD);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_RECORD);
+
+$_dumptype_key_VALUES{"DUMPTYPE_RECORD"} = $DUMPTYPE_RECORD;
+
+push @EXPORT_OK, qw($DUMPTYPE_SKIP_INCR);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_SKIP_INCR);
+
+$_dumptype_key_VALUES{"DUMPTYPE_SKIP_INCR"} = $DUMPTYPE_SKIP_INCR;
+
+push @EXPORT_OK, qw($DUMPTYPE_SKIP_FULL);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_SKIP_FULL);
+
+$_dumptype_key_VALUES{"DUMPTYPE_SKIP_FULL"} = $DUMPTYPE_SKIP_FULL;
+
+push @EXPORT_OK, qw($DUMPTYPE_HOLDINGDISK);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_HOLDINGDISK);
+
+$_dumptype_key_VALUES{"DUMPTYPE_HOLDINGDISK"} = $DUMPTYPE_HOLDINGDISK;
+
+push @EXPORT_OK, qw($DUMPTYPE_KENCRYPT);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_KENCRYPT);
+
+$_dumptype_key_VALUES{"DUMPTYPE_KENCRYPT"} = $DUMPTYPE_KENCRYPT;
+
+push @EXPORT_OK, qw($DUMPTYPE_IGNORE);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_IGNORE);
+
+$_dumptype_key_VALUES{"DUMPTYPE_IGNORE"} = $DUMPTYPE_IGNORE;
+
+push @EXPORT_OK, qw($DUMPTYPE_INDEX);
+push @{$EXPORT_TAGS{"dumptype_key"}}, qw($DUMPTYPE_INDEX);
+
+$_dumptype_key_VALUES{"DUMPTYPE_INDEX"} = $DUMPTYPE_INDEX;
+
+#copy symbols in dumptype_key to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"dumptype_key"}};
+
+push @EXPORT_OK, qw(interface_key_to_string);
+push @{$EXPORT_TAGS{"interface_key"}}, qw(interface_key_to_string);
+
+my %_interface_key_VALUES;
+#Convert an enum value to a single string
+sub interface_key_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_interface_key_VALUES) {
+       my $v = $_interface_key_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($INTER_COMMENT);
+push @{$EXPORT_TAGS{"interface_key"}}, qw($INTER_COMMENT);
+
+$_interface_key_VALUES{"INTER_COMMENT"} = $INTER_COMMENT;
+
+push @EXPORT_OK, qw($INTER_MAXUSAGE);
+push @{$EXPORT_TAGS{"interface_key"}}, qw($INTER_MAXUSAGE);
+
+$_interface_key_VALUES{"INTER_MAXUSAGE"} = $INTER_MAXUSAGE;
+
+#copy symbols in interface_key to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"interface_key"}};
+
+push @EXPORT_OK, qw(holdingdisk_key_to_string);
+push @{$EXPORT_TAGS{"holdingdisk_key"}}, qw(holdingdisk_key_to_string);
+
+my %_holdingdisk_key_VALUES;
+#Convert an enum value to a single string
+sub holdingdisk_key_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_holdingdisk_key_VALUES) {
+       my $v = $_holdingdisk_key_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($HOLDING_COMMENT);
+push @{$EXPORT_TAGS{"holdingdisk_key"}}, qw($HOLDING_COMMENT);
+
+$_holdingdisk_key_VALUES{"HOLDING_COMMENT"} = $HOLDING_COMMENT;
+
+push @EXPORT_OK, qw($HOLDING_DISKDIR);
+push @{$EXPORT_TAGS{"holdingdisk_key"}}, qw($HOLDING_DISKDIR);
+
+$_holdingdisk_key_VALUES{"HOLDING_DISKDIR"} = $HOLDING_DISKDIR;
+
+push @EXPORT_OK, qw($HOLDING_DISKSIZE);
+push @{$EXPORT_TAGS{"holdingdisk_key"}}, qw($HOLDING_DISKSIZE);
+
+$_holdingdisk_key_VALUES{"HOLDING_DISKSIZE"} = $HOLDING_DISKSIZE;
+
+push @EXPORT_OK, qw($HOLDING_CHUNKSIZE);
+push @{$EXPORT_TAGS{"holdingdisk_key"}}, qw($HOLDING_CHUNKSIZE);
+
+$_holdingdisk_key_VALUES{"HOLDING_CHUNKSIZE"} = $HOLDING_CHUNKSIZE;
+
+#copy symbols in holdingdisk_key to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"holdingdisk_key"}};
+
+push @EXPORT_OK, qw(dump_holdingdisk_t_to_string);
+push @{$EXPORT_TAGS{"dump_holdingdisk_t"}}, qw(dump_holdingdisk_t_to_string);
+
+my %_dump_holdingdisk_t_VALUES;
+#Convert an enum value to a single string
+sub dump_holdingdisk_t_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_dump_holdingdisk_t_VALUES) {
+       my $v = $_dump_holdingdisk_t_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($HOLD_NEVER);
+push @{$EXPORT_TAGS{"dump_holdingdisk_t"}}, qw($HOLD_NEVER);
+
+$_dump_holdingdisk_t_VALUES{"HOLD_NEVER"} = $HOLD_NEVER;
+
+push @EXPORT_OK, qw($HOLD_AUTO);
+push @{$EXPORT_TAGS{"dump_holdingdisk_t"}}, qw($HOLD_AUTO);
+
+$_dump_holdingdisk_t_VALUES{"HOLD_AUTO"} = $HOLD_AUTO;
+
+push @EXPORT_OK, qw($HOLD_REQUIRED);
+push @{$EXPORT_TAGS{"dump_holdingdisk_t"}}, qw($HOLD_REQUIRED);
+
+$_dump_holdingdisk_t_VALUES{"HOLD_REQUIRED"} = $HOLD_REQUIRED;
+
+#copy symbols in dump_holdingdisk_t to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"dump_holdingdisk_t"}};
+
+push @EXPORT_OK, qw(comp_t_to_string);
+push @{$EXPORT_TAGS{"comp_t"}}, qw(comp_t_to_string);
+
+my %_comp_t_VALUES;
+#Convert an enum value to a single string
+sub comp_t_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_comp_t_VALUES) {
+       my $v = $_comp_t_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($COMP_NONE);
+push @{$EXPORT_TAGS{"comp_t"}}, qw($COMP_NONE);
+
+$_comp_t_VALUES{"COMP_NONE"} = $COMP_NONE;
+
+push @EXPORT_OK, qw($COMP_FAST);
+push @{$EXPORT_TAGS{"comp_t"}}, qw($COMP_FAST);
+
+$_comp_t_VALUES{"COMP_FAST"} = $COMP_FAST;
+
+push @EXPORT_OK, qw($COMP_BEST);
+push @{$EXPORT_TAGS{"comp_t"}}, qw($COMP_BEST);
+
+$_comp_t_VALUES{"COMP_BEST"} = $COMP_BEST;
+
+push @EXPORT_OK, qw($COMP_CUST);
+push @{$EXPORT_TAGS{"comp_t"}}, qw($COMP_CUST);
+
+$_comp_t_VALUES{"COMP_CUST"} = $COMP_CUST;
+
+push @EXPORT_OK, qw($COMP_SERVER_FAST);
+push @{$EXPORT_TAGS{"comp_t"}}, qw($COMP_SERVER_FAST);
+
+$_comp_t_VALUES{"COMP_SERVER_FAST"} = $COMP_SERVER_FAST;
+
+push @EXPORT_OK, qw($COMP_SERVER_BEST);
+push @{$EXPORT_TAGS{"comp_t"}}, qw($COMP_SERVER_BEST);
+
+$_comp_t_VALUES{"COMP_SERVER_BEST"} = $COMP_SERVER_BEST;
+
+push @EXPORT_OK, qw($COMP_SERVER_CUST);
+push @{$EXPORT_TAGS{"comp_t"}}, qw($COMP_SERVER_CUST);
+
+$_comp_t_VALUES{"COMP_SERVER_CUST"} = $COMP_SERVER_CUST;
+
+#copy symbols in comp_t to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"comp_t"}};
+
+push @EXPORT_OK, qw(encrypt_t_to_string);
+push @{$EXPORT_TAGS{"encrypt_t"}}, qw(encrypt_t_to_string);
+
+my %_encrypt_t_VALUES;
+#Convert an enum value to a single string
+sub encrypt_t_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_encrypt_t_VALUES) {
+       my $v = $_encrypt_t_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($ENCRYPT_NONE);
+push @{$EXPORT_TAGS{"encrypt_t"}}, qw($ENCRYPT_NONE);
+
+$_encrypt_t_VALUES{"ENCRYPT_NONE"} = $ENCRYPT_NONE;
+
+push @EXPORT_OK, qw($ENCRYPT_CUST);
+push @{$EXPORT_TAGS{"encrypt_t"}}, qw($ENCRYPT_CUST);
+
+$_encrypt_t_VALUES{"ENCRYPT_CUST"} = $ENCRYPT_CUST;
+
+push @EXPORT_OK, qw($ENCRYPT_SERV_CUST);
+push @{$EXPORT_TAGS{"encrypt_t"}}, qw($ENCRYPT_SERV_CUST);
+
+$_encrypt_t_VALUES{"ENCRYPT_SERV_CUST"} = $ENCRYPT_SERV_CUST;
+
+#copy symbols in encrypt_t to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"encrypt_t"}};
+
+push @EXPORT_OK, qw(strategy_t_to_string);
+push @{$EXPORT_TAGS{"strategy_t"}}, qw(strategy_t_to_string);
+
+my %_strategy_t_VALUES;
+#Convert an enum value to a single string
+sub strategy_t_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_strategy_t_VALUES) {
+       my $v = $_strategy_t_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($DS_SKIP);
+push @{$EXPORT_TAGS{"strategy_t"}}, qw($DS_SKIP);
+
+$_strategy_t_VALUES{"DS_SKIP"} = $DS_SKIP;
+
+push @EXPORT_OK, qw($DS_STANDARD);
+push @{$EXPORT_TAGS{"strategy_t"}}, qw($DS_STANDARD);
+
+$_strategy_t_VALUES{"DS_STANDARD"} = $DS_STANDARD;
+
+push @EXPORT_OK, qw($DS_NOFULL);
+push @{$EXPORT_TAGS{"strategy_t"}}, qw($DS_NOFULL);
+
+$_strategy_t_VALUES{"DS_NOFULL"} = $DS_NOFULL;
+
+push @EXPORT_OK, qw($DS_NOINC);
+push @{$EXPORT_TAGS{"strategy_t"}}, qw($DS_NOINC);
+
+$_strategy_t_VALUES{"DS_NOINC"} = $DS_NOINC;
+
+push @EXPORT_OK, qw($DS_4);
+push @{$EXPORT_TAGS{"strategy_t"}}, qw($DS_4);
+
+$_strategy_t_VALUES{"DS_4"} = $DS_4;
+
+push @EXPORT_OK, qw($DS_5);
+push @{$EXPORT_TAGS{"strategy_t"}}, qw($DS_5);
+
+$_strategy_t_VALUES{"DS_5"} = $DS_5;
+
+push @EXPORT_OK, qw($DS_HANOI);
+push @{$EXPORT_TAGS{"strategy_t"}}, qw($DS_HANOI);
+
+$_strategy_t_VALUES{"DS_HANOI"} = $DS_HANOI;
+
+push @EXPORT_OK, qw($DS_INCRONLY);
+push @{$EXPORT_TAGS{"strategy_t"}}, qw($DS_INCRONLY);
+
+$_strategy_t_VALUES{"DS_INCRONLY"} = $DS_INCRONLY;
+
+#copy symbols in strategy_t to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"strategy_t"}};
+
+push @EXPORT_OK, qw(estimate_t_to_string);
+push @{$EXPORT_TAGS{"estimate_t"}}, qw(estimate_t_to_string);
+
+my %_estimate_t_VALUES;
+#Convert an enum value to a single string
+sub estimate_t_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_estimate_t_VALUES) {
+       my $v = $_estimate_t_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($ES_CLIENT);
+push @{$EXPORT_TAGS{"estimate_t"}}, qw($ES_CLIENT);
+
+$_estimate_t_VALUES{"ES_CLIENT"} = $ES_CLIENT;
+
+push @EXPORT_OK, qw($ES_SERVER);
+push @{$EXPORT_TAGS{"estimate_t"}}, qw($ES_SERVER);
+
+$_estimate_t_VALUES{"ES_SERVER"} = $ES_SERVER;
+
+push @EXPORT_OK, qw($ES_CALCSIZE);
+push @{$EXPORT_TAGS{"estimate_t"}}, qw($ES_CALCSIZE);
+
+$_estimate_t_VALUES{"ES_CALCSIZE"} = $ES_CALCSIZE;
+
+#copy symbols in estimate_t to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"estimate_t"}};
+
+push @EXPORT_OK, qw(taperalgo_t_to_string);
+push @{$EXPORT_TAGS{"taperalgo_t"}}, qw(taperalgo_t_to_string);
+
+my %_taperalgo_t_VALUES;
+#Convert an enum value to a single string
+sub taperalgo_t_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_taperalgo_t_VALUES) {
+       my $v = $_taperalgo_t_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($ALGO_FIRST);
+push @{$EXPORT_TAGS{"taperalgo_t"}}, qw($ALGO_FIRST);
+
+$_taperalgo_t_VALUES{"ALGO_FIRST"} = $ALGO_FIRST;
+
+push @EXPORT_OK, qw($ALGO_FIRSTFIT);
+push @{$EXPORT_TAGS{"taperalgo_t"}}, qw($ALGO_FIRSTFIT);
+
+$_taperalgo_t_VALUES{"ALGO_FIRSTFIT"} = $ALGO_FIRSTFIT;
+
+push @EXPORT_OK, qw($ALGO_LARGEST);
+push @{$EXPORT_TAGS{"taperalgo_t"}}, qw($ALGO_LARGEST);
+
+$_taperalgo_t_VALUES{"ALGO_LARGEST"} = $ALGO_LARGEST;
+
+push @EXPORT_OK, qw($ALGO_LARGESTFIT);
+push @{$EXPORT_TAGS{"taperalgo_t"}}, qw($ALGO_LARGESTFIT);
+
+$_taperalgo_t_VALUES{"ALGO_LARGESTFIT"} = $ALGO_LARGESTFIT;
+
+push @EXPORT_OK, qw($ALGO_SMALLEST);
+push @{$EXPORT_TAGS{"taperalgo_t"}}, qw($ALGO_SMALLEST);
+
+$_taperalgo_t_VALUES{"ALGO_SMALLEST"} = $ALGO_SMALLEST;
+
+push @EXPORT_OK, qw($ALGO_LAST);
+push @{$EXPORT_TAGS{"taperalgo_t"}}, qw($ALGO_LAST);
+
+$_taperalgo_t_VALUES{"ALGO_LAST"} = $ALGO_LAST;
+
+#copy symbols in taperalgo_t to getconf
+push @{$EXPORT_TAGS{"getconf"}},  @{$EXPORT_TAGS{"taperalgo_t"}};
+
+push @EXPORT_OK, qw(getconf getconf_seen 
+    getconf_byname getconf_list);
+push @{$EXPORT_TAGS{"getconf"}}, qw(getconf getconf_seen 
+    getconf_byname getconf_list);
+
+push @EXPORT_OK, qw(lookup_tapetype tapetype_getconf tapetype_name
+    tapetype_seen tapetype_seen);
+push @{$EXPORT_TAGS{"getconf"}}, qw(lookup_tapetype tapetype_getconf tapetype_name
+    tapetype_seen tapetype_seen);
+
+push @EXPORT_OK, qw(lookup_dumptype dumptype_getconf dumptype_name
+    dumptype_seen dumptype_seen);
+push @{$EXPORT_TAGS{"getconf"}}, qw(lookup_dumptype dumptype_getconf dumptype_name
+    dumptype_seen dumptype_seen);
+
+push @EXPORT_OK, qw(lookup_interface interface_getconf interface_name
+    interface_seen interface_seen);
+push @{$EXPORT_TAGS{"getconf"}}, qw(lookup_interface interface_getconf interface_name
+    interface_seen interface_seen);
+
+push @EXPORT_OK, qw(lookup_holdingdisk holdingdisk_getconf holdingdisk_name
+    getconf_holdingdisks holdingdisk_next
+    holdingdisk_seen holdingdisk_seen);
+push @{$EXPORT_TAGS{"getconf"}}, qw(lookup_holdingdisk holdingdisk_getconf holdingdisk_name
+    getconf_holdingdisks holdingdisk_next
+    holdingdisk_seen holdingdisk_seen);
+
+push @EXPORT_OK, qw(getconf_unit_divisor
+
+    $debug_amandad $debug_amidxtaped $debug_amindexd $debug_amrecover
+    $debug_auth $debug_event $debug_holding $debug_protocol
+    $debug_planner $debug_driver $debug_dumper $debug_chunker
+    $debug_taper $debug_selfcheck $debug_sendsize $debug_sendbackup);
+push @{$EXPORT_TAGS{"getconf"}}, qw(getconf_unit_divisor
+
+    $debug_amandad $debug_amidxtaped $debug_amindexd $debug_amrecover
+    $debug_auth $debug_event $debug_holding $debug_protocol
+    $debug_planner $debug_driver $debug_dumper $debug_chunker
+    $debug_taper $debug_selfcheck $debug_sendsize $debug_sendbackup);
+
+push @EXPORT_OK, qw(new_config_overwrites free_config_overwrites add_config_overwrite
+    add_config_overwrite_opt apply_config_overwrites);
+push @{$EXPORT_TAGS{"init"}}, qw(new_config_overwrites free_config_overwrites add_config_overwrite
+    add_config_overwrite_opt apply_config_overwrites);
+
+push @EXPORT_OK, qw(config_init_flags_to_strings);
+push @{$EXPORT_TAGS{"config_init_flags"}}, qw(config_init_flags_to_strings);
+
+my %_config_init_flags_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub config_init_flags_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_config_init_flags_VALUES) {
+       my $v = $_config_init_flags_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($CONFIG_INIT_EXPLICIT_NAME);
+push @{$EXPORT_TAGS{"config_init_flags"}}, qw($CONFIG_INIT_EXPLICIT_NAME);
+
+$_config_init_flags_VALUES{"CONFIG_INIT_EXPLICIT_NAME"} = $CONFIG_INIT_EXPLICIT_NAME;
+
+push @EXPORT_OK, qw($CONFIG_INIT_USE_CWD);
+push @{$EXPORT_TAGS{"config_init_flags"}}, qw($CONFIG_INIT_USE_CWD);
+
+$_config_init_flags_VALUES{"CONFIG_INIT_USE_CWD"} = $CONFIG_INIT_USE_CWD;
+
+push @EXPORT_OK, qw($CONFIG_INIT_CLIENT);
+push @{$EXPORT_TAGS{"config_init_flags"}}, qw($CONFIG_INIT_CLIENT);
+
+$_config_init_flags_VALUES{"CONFIG_INIT_CLIENT"} = $CONFIG_INIT_CLIENT;
+
+push @EXPORT_OK, qw($CONFIG_INIT_OVERLAY);
+push @{$EXPORT_TAGS{"config_init_flags"}}, qw($CONFIG_INIT_OVERLAY);
+
+$_config_init_flags_VALUES{"CONFIG_INIT_OVERLAY"} = $CONFIG_INIT_OVERLAY;
+
+push @EXPORT_OK, qw($CONFIG_INIT_FATAL);
+push @{$EXPORT_TAGS{"config_init_flags"}}, qw($CONFIG_INIT_FATAL);
+
+$_config_init_flags_VALUES{"CONFIG_INIT_FATAL"} = $CONFIG_INIT_FATAL;
+
+#copy symbols in config_init_flags to init
+push @{$EXPORT_TAGS{"init"}},  @{$EXPORT_TAGS{"config_init_flags"}};
+
+push @EXPORT_OK, qw(config_init config_uninit get_config_options);
+push @{$EXPORT_TAGS{"init"}}, qw(config_init config_uninit get_config_options);
+
+push @EXPORT_OK, qw(get_config_name 
+    get_config_dir 
+    get_config_filename);
+push @{$EXPORT_TAGS{"init"}}, qw(get_config_name 
+    get_config_dir 
+    get_config_filename);
+
+push @EXPORT_OK, qw(dump_configuration config_dir_relative taperalgo2str find_multiplier);
+1;
diff --git a/perl/Amanda/Config.swg b/perl/Amanda/Config.swg
new file mode 100644 (file)
index 0000000..ddeab5e
--- /dev/null
@@ -0,0 +1,735 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%module "Amanda::Config"
+%include "amglue/amglue.swg"
+%include "exception.i"
+
+%{
+#include "conffile.h"
+%}
+
+%perlcode %{
+=head1 NAME
+
+Amanda::Config - access to Amanda configuration parameters
+
+=head1 SYNOPSIS
+
+  use Amanda::Config qw( :init :getconf );
+
+  config_init($CONFIG_INIT_EXPLICIT_NAME, $ARGV[1])
+    or die("errors processing config file " . $Amanda::Config::get_config_filename());
+
+  print "tape device is ", getconf($CNF_TAPEDEV), "\n";
+
+This API closely parallels the C API.  See F<conffile.h> for details
+on the functions and constants available here.
+
+=head1 API STATUS
+
+Stable
+
+=head1 INITIALIZATION
+
+The Amanda configuration is treated as a global state for the
+application.  It is not possible to load two configurations
+simultaneously.
+
+All initialization-related symbols can be imported with the tag
+C<:init>.
+
+=head2 LOADING CONFIGURATION
+
+The Amanda configuration is loaded with the aptly named
+C<config_init($flags, $name)>.  Because of the great variety in
+invocation method among Amanda applications, this function has a number
+of flags that affect its behavior.  These flags can be OR'd together.
+
+=over
+
+=item If C<CONFIG_INIT_EXPLICIT_NAME> is given, then the C<$name>
+parameter can contain the name of a configuration to load.
+
+=item If C<CONFIG_INIT_USE_CWD> is given, and if the current directory
+contains C<amanda.conf>, then that file is loaded.
+
+=item If C<CONFIG_INIT_CLIENT> is given, then a client configuration
+is loaded.
+
+=item If C<CONFIG_INIT_OVERLAY> is given, then any existing
+configuration is not reset.
+
+=item If C<CONFIG_INIT_FATAL> is given, then any errors are considered
+fatal, and C<config_init> does not return.
+
+=back
+
+See C<conffile.h> for more detailed information on these flags and
+their interactions.
+
+C<config_uninit()> reverses the effects of C<config_init>.  It is
+not often used.
+
+Once the configuration is loaded, the configuration name
+(e.g., "DailySet1"), directory (C</etc/amanda/DailySet1>),
+and filename (C</etc/amanda/DailySet1/amanda.conf>) are
+available from C<get_config_name()>, C<get_config_dir()>, and
+C<get_config_filename()>, respectively.
+
+=head2 CONFIG OVERWRITES
+
+Most Amanda applications accept the command-line option C<-o>
+to "overwrite" configuration values in C<amanda.conf>.  In Perl
+applications, these options should be parsed with L<Getopt::Long|Getopt::Long>, with
+the action being a call to C<add_config_overwrite_opt>.  For example:
+
+  my $config_overwrites = new_config_overwrites($#ARGV+1);
+    GetOptions(
+       # ...
+       'o=s' => sub { add_config_overwrite_opt($config_overwrites, $_[1]); },
+    ) or usage();
+  my $cfg_ok = config_init($CONFIG_INIT_EXPLICIT_NAME | $CONFIG_INIT_USE_CWD, $config_name);
+  apply_config_overwrites($config_overwrites);
+
+C<new_config_overwrites($size_estimate)> creates a new
+overwrites object, using the given size as an estimate of
+the number of items it will contain (C<$#ARGC/2> is a good
+estimate).  Individual configuration options are then added via
+C<add_config_overwrite($co, $key, $value)> (which takes a key/value
+pair) or C<add_config_overwrite_opt($co, $optarg)>, which parses a
+string following C<-o> on the command line.
+
+Once the overwrites are gathered, they are applied with
+C<apply_config_overwrites($co)>, which applies the overwrites to the
+active configuration.  No further operations can be performed on the
+overwrites object after C<apply_config_overwrites> has been called.
+
+The utility function C<get_config_options()> returns a list of
+command-line arguments to represent any overwrites that were used
+to generate the current configuration.  (TODO: this function isn't
+available yet)
+
+=head1 PARAMETER ACCESS
+
+Amanda configurations consist of "global" parameters and several
+sets of "subsections" -- one set for dumptypes, one for tapetypes,
+and so on.
+
+All of the global parameters are represented by a constant beginning
+with C<$CNF_>, e.g., C<$CNF_LABELSTR>.  The function C<getconf($cnf)>
+returns the value of parameter C<$cnf>, in whatever format is
+appropriate for the parameter.  C<getconf_seen($cnf)> returns a true
+value if C<$cnf> was seen in the configuration file.  If it was not
+seen, then it will have its default value.
+
+Some parameters have enumerated types.  The values for those
+enumerations are available from this module with the same name as
+in C<conffile.h>.  For example, C<$CNF_TAPERALGO> will yield a value
+from the enumeration C<taperalgo_t>, the constants for which all
+begin with C<$ALGO_>.  See C<conffile.h> for the details.
+
+Each subsection type has the following functions:
+
+=over
+
+=item C<lookup_TYP($subsec_name)>
+
+which returns an opaque object
+(C<$ss>) representing the subsection, or C<undef> if no subsection
+with that name exists;
+
+=item C<TYP_name($ss)>
+
+returning the name of the subsection;
+
+=item C<TYP_getconf($ss, $cnf)>
+
+which fetches a parameter value from C<$ss>; and
+
+=item C<TYP_seen($ss, $cnf)>
+
+which returns a true value if <$cnf> was seen in the subsection.
+
+=back
+
+The subsections are:
+
+=over
+
+=item C<tapetype>
+
+with constants beginning with C<$TAPETYPE_>
+
+=item C<dumptype>
+
+with constants beginning with C<$DUMPTYPE_>
+
+=item C<holdingdisk>
+
+with constants beginning with C<$HOLDING_>
+
+=item C<application>
+
+with constants beginning with C<$APPLICATION_>
+
+=item C<script>
+
+with constants beginning with C<$PP_SCRIPT_>
+
+=back
+
+See C<conffile.h> for the names of the constants themselves.
+
+Parameter values are available by name from C<getconf_byname($name)>.
+This function implements the C<TYP:NAME:PARAM> syntax advertised by
+C<amgetconf> to access values in subsections.  C<getconf_list($typ)>
+returns a list of the names of all subsections of the given type.
+
+The C<$CNF_DISPLAYUNIT> implies a certain divisor to convert from
+kilobytes to the desired unit.  This divisor is available from
+C<getconf_unit_divisor()>.  Note carefully that it is a I<divisor>
+for a value in I<kilobytes>!
+
+Finally, various subsections of Amanda enable verbose debugging via
+configuration parameters.  The status of each parameter is available
+a similarly-named variable, e.g., C<$debug_auth>.
+
+All parameter access functions and constants can be imported with
+the tag C<:getconf>.
+
+=head1 MISCELLANEOUS
+
+These functions defy categorization.
+
+The function C<config_dir_relative> will interpret a path relative to
+the current configuration directory.  Absolute paths are passed through
+unchanged, while relative paths are converted to absolute paths.
+
+C<dump_configuration()> dumps the current configuration, in a format
+suitable for re-evaluation for this module, to standard output.
+This function may be revised to return a string.
+
+Several parts of Amanda need to convert unit modifier value like
+"gbytes" to a multiplier.  The function C<find_multiplier($str)>
+returns the unit multiplier for such a string.  For example, "mbytes"
+is converted to 1048576 (1024*1024).
+
+=cut
+%}
+
+/*
+ * Parameter access
+*/
+
+/* All of the CNF_ flags from conffile.h */
+
+amglue_add_enum_tag_fns(confparm_key);
+amglue_add_constant(CNF_ORG, confparm_key);
+amglue_add_constant(CNF_CONF, confparm_key);
+amglue_add_constant(CNF_INDEX_SERVER, confparm_key);
+amglue_add_constant(CNF_TAPE_SERVER, confparm_key);
+amglue_add_constant(CNF_AUTH, confparm_key);
+amglue_add_constant(CNF_SSH_KEYS, confparm_key);
+amglue_add_constant(CNF_AMANDAD_PATH, confparm_key);
+amglue_add_constant(CNF_CLIENT_USERNAME, confparm_key);
+amglue_add_constant(CNF_GNUTAR_LIST_DIR, confparm_key);
+amglue_add_constant(CNF_AMANDATES, confparm_key);
+amglue_add_constant(CNF_MAILTO, confparm_key);
+amglue_add_constant(CNF_DUMPUSER, confparm_key);
+amglue_add_constant(CNF_TAPEDEV, confparm_key);
+amglue_add_constant(CNF_DEVICE_PROPERTY, confparm_key);
+amglue_add_constant(CNF_CHANGERDEV, confparm_key);
+amglue_add_constant(CNF_CHANGERFILE, confparm_key);
+amglue_add_constant(CNF_LABELSTR, confparm_key);
+amglue_add_constant(CNF_TAPELIST, confparm_key);
+amglue_add_constant(CNF_DISKFILE, confparm_key);
+amglue_add_constant(CNF_INFOFILE, confparm_key);
+amglue_add_constant(CNF_LOGDIR, confparm_key);
+amglue_add_constant(CNF_INDEXDIR, confparm_key);
+amglue_add_constant(CNF_TAPETYPE, confparm_key);
+amglue_add_constant(CNF_DUMPCYCLE, confparm_key);
+amglue_add_constant(CNF_RUNSPERCYCLE, confparm_key);
+amglue_add_constant(CNF_TAPECYCLE, confparm_key);
+amglue_add_constant(CNF_NETUSAGE, confparm_key);
+amglue_add_constant(CNF_INPARALLEL, confparm_key);
+amglue_add_constant(CNF_DUMPORDER, confparm_key);
+amglue_add_constant(CNF_BUMPPERCENT, confparm_key);
+amglue_add_constant(CNF_BUMPSIZE, confparm_key);
+amglue_add_constant(CNF_BUMPMULT, confparm_key);
+amglue_add_constant(CNF_BUMPDAYS, confparm_key);
+amglue_add_constant(CNF_TPCHANGER, confparm_key);
+amglue_add_constant(CNF_RUNTAPES, confparm_key);
+amglue_add_constant(CNF_MAXDUMPS, confparm_key);
+amglue_add_constant(CNF_ETIMEOUT, confparm_key);
+amglue_add_constant(CNF_DTIMEOUT, confparm_key);
+amglue_add_constant(CNF_CTIMEOUT, confparm_key);
+amglue_add_constant(CNF_TAPEBUFS, confparm_key);
+amglue_add_constant(CNF_DEVICE_OUTPUT_BUFFER_SIZE, confparm_key);
+amglue_add_constant(CNF_PRINTER, confparm_key);
+amglue_add_constant(CNF_AUTOFLUSH, confparm_key);
+amglue_add_constant(CNF_RESERVE, confparm_key);
+amglue_add_constant(CNF_MAXDUMPSIZE, confparm_key);
+amglue_add_constant(CNF_COLUMNSPEC, confparm_key);
+amglue_add_constant(CNF_AMRECOVER_DO_FSF, confparm_key);
+amglue_add_constant(CNF_AMRECOVER_CHECK_LABEL, confparm_key);
+amglue_add_constant(CNF_AMRECOVER_CHANGER, confparm_key);
+amglue_add_constant(CNF_TAPERALGO, confparm_key);
+amglue_add_constant(CNF_FLUSH_THRESHOLD_DUMPED, confparm_key);
+amglue_add_constant(CNF_FLUSH_THRESHOLD_SCHEDULED, confparm_key);
+amglue_add_constant(CNF_TAPERFLUSH, confparm_key);
+amglue_add_constant(CNF_DISPLAYUNIT, confparm_key);
+amglue_add_constant(CNF_KRB5KEYTAB, confparm_key);
+amglue_add_constant(CNF_KRB5PRINCIPAL, confparm_key);
+amglue_add_constant(CNF_LABEL_NEW_TAPES, confparm_key);
+amglue_add_constant(CNF_USETIMESTAMPS, confparm_key);
+amglue_add_constant(CNF_REP_TRIES, confparm_key);
+amglue_add_constant(CNF_CONNECT_TRIES, confparm_key);
+amglue_add_constant(CNF_REQ_TRIES, confparm_key);
+amglue_add_constant(CNF_DEBUG_AMANDAD, confparm_key);
+amglue_add_constant(CNF_DEBUG_AMIDXTAPED, confparm_key);
+amglue_add_constant(CNF_DEBUG_AMINDEXD, confparm_key);
+amglue_add_constant(CNF_DEBUG_AMRECOVER, confparm_key);
+amglue_add_constant(CNF_DEBUG_AUTH, confparm_key);
+amglue_add_constant(CNF_DEBUG_EVENT, confparm_key);
+amglue_add_constant(CNF_DEBUG_HOLDING, confparm_key);
+amglue_add_constant(CNF_DEBUG_PROTOCOL, confparm_key);
+amglue_add_constant(CNF_DEBUG_PLANNER, confparm_key);
+amglue_add_constant(CNF_DEBUG_DRIVER, confparm_key);
+amglue_add_constant(CNF_DEBUG_DUMPER, confparm_key);
+amglue_add_constant(CNF_DEBUG_CHUNKER, confparm_key);
+amglue_add_constant(CNF_DEBUG_TAPER, confparm_key);
+amglue_add_constant(CNF_DEBUG_SELFCHECK, confparm_key);
+amglue_add_constant(CNF_DEBUG_SENDSIZE, confparm_key);
+amglue_add_constant(CNF_DEBUG_SENDBACKUP, confparm_key);
+amglue_add_constant(CNF_RESERVED_UDP_PORT, confparm_key);
+amglue_add_constant(CNF_RESERVED_TCP_PORT, confparm_key);
+amglue_add_constant(CNF_UNRESERVED_TCP_PORT, confparm_key);
+amglue_copy_to_tag(confparm_key, getconf);
+
+amglue_add_enum_tag_fns(tapetype_key);
+amglue_add_constant(TAPETYPE_COMMENT, tapetype_key);
+amglue_add_constant(TAPETYPE_LBL_TEMPL, tapetype_key);
+amglue_add_constant(TAPETYPE_BLOCKSIZE, tapetype_key);
+amglue_add_constant(TAPETYPE_READBLOCKSIZE, tapetype_key);
+amglue_add_constant(TAPETYPE_LENGTH, tapetype_key);
+amglue_add_constant(TAPETYPE_FILEMARK, tapetype_key);
+amglue_add_constant(TAPETYPE_SPEED, tapetype_key);
+amglue_add_constant(TAPETYPE_FILE_PAD, tapetype_key);
+amglue_copy_to_tag(tapetype_key, getconf);
+
+amglue_add_enum_tag_fns(dumptype_key);
+amglue_add_constant(DUMPTYPE_COMMENT, dumptype_key);
+amglue_add_constant(DUMPTYPE_PROGRAM, dumptype_key);
+amglue_add_constant(DUMPTYPE_SRVCOMPPROG, dumptype_key);
+amglue_add_constant(DUMPTYPE_CLNTCOMPPROG, dumptype_key);
+amglue_add_constant(DUMPTYPE_SRV_ENCRYPT, dumptype_key);
+amglue_add_constant(DUMPTYPE_CLNT_ENCRYPT, dumptype_key);
+amglue_add_constant(DUMPTYPE_AMANDAD_PATH, dumptype_key);
+amglue_add_constant(DUMPTYPE_CLIENT_USERNAME, dumptype_key);
+amglue_add_constant(DUMPTYPE_SSH_KEYS, dumptype_key);
+amglue_add_constant(DUMPTYPE_SECURITY_DRIVER, dumptype_key);
+amglue_add_constant(DUMPTYPE_EXCLUDE, dumptype_key);
+amglue_add_constant(DUMPTYPE_INCLUDE, dumptype_key);
+amglue_add_constant(DUMPTYPE_PRIORITY, dumptype_key);
+amglue_add_constant(DUMPTYPE_DUMPCYCLE, dumptype_key);
+amglue_add_constant(DUMPTYPE_MAXDUMPS, dumptype_key);
+amglue_add_constant(DUMPTYPE_MAXPROMOTEDAY, dumptype_key);
+amglue_add_constant(DUMPTYPE_BUMPPERCENT, dumptype_key);
+amglue_add_constant(DUMPTYPE_BUMPSIZE, dumptype_key);
+amglue_add_constant(DUMPTYPE_BUMPDAYS, dumptype_key);
+amglue_add_constant(DUMPTYPE_BUMPMULT, dumptype_key);
+amglue_add_constant(DUMPTYPE_STARTTIME, dumptype_key);
+amglue_add_constant(DUMPTYPE_STRATEGY, dumptype_key);
+amglue_add_constant(DUMPTYPE_ESTIMATE, dumptype_key);
+amglue_add_constant(DUMPTYPE_COMPRESS, dumptype_key);
+amglue_add_constant(DUMPTYPE_ENCRYPT, dumptype_key);
+amglue_add_constant(DUMPTYPE_SRV_DECRYPT_OPT, dumptype_key);
+amglue_add_constant(DUMPTYPE_CLNT_DECRYPT_OPT, dumptype_key);
+amglue_add_constant(DUMPTYPE_COMPRATE, dumptype_key);
+amglue_add_constant(DUMPTYPE_TAPE_SPLITSIZE, dumptype_key);
+amglue_add_constant(DUMPTYPE_FALLBACK_SPLITSIZE, dumptype_key);
+amglue_add_constant(DUMPTYPE_SPLIT_DISKBUFFER, dumptype_key);
+amglue_add_constant(DUMPTYPE_RECORD, dumptype_key);
+amglue_add_constant(DUMPTYPE_SKIP_INCR, dumptype_key);
+amglue_add_constant(DUMPTYPE_SKIP_FULL, dumptype_key);
+amglue_add_constant(DUMPTYPE_HOLDINGDISK, dumptype_key);
+amglue_add_constant(DUMPTYPE_KENCRYPT, dumptype_key);
+amglue_add_constant(DUMPTYPE_IGNORE, dumptype_key);
+amglue_add_constant(DUMPTYPE_INDEX, dumptype_key);
+amglue_copy_to_tag(dumptype_key, getconf);
+
+amglue_add_enum_tag_fns(interface_key);
+amglue_add_constant(INTER_COMMENT, interface_key);
+amglue_add_constant(INTER_MAXUSAGE, interface_key);
+amglue_copy_to_tag(interface_key, getconf);
+
+amglue_add_enum_tag_fns(holdingdisk_key);
+amglue_add_constant(HOLDING_COMMENT, holdingdisk_key);
+amglue_add_constant(HOLDING_DISKDIR, holdingdisk_key);
+amglue_add_constant(HOLDING_DISKSIZE, holdingdisk_key);
+amglue_add_constant(HOLDING_CHUNKSIZE, holdingdisk_key);
+amglue_copy_to_tag(holdingdisk_key, getconf);
+
+/*
+ * Various enumerated conftypes
+ */
+
+amglue_add_enum_tag_fns(dump_holdingdisk_t);
+amglue_add_constant(HOLD_NEVER, dump_holdingdisk_t);
+amglue_add_constant(HOLD_AUTO, dump_holdingdisk_t);
+amglue_add_constant(HOLD_REQUIRED, dump_holdingdisk_t);
+amglue_copy_to_tag(dump_holdingdisk_t, getconf);
+
+amglue_add_enum_tag_fns(comp_t);
+amglue_add_constant(COMP_NONE, comp_t);
+amglue_add_constant(COMP_FAST, comp_t);
+amglue_add_constant(COMP_BEST, comp_t);
+amglue_add_constant(COMP_CUST, comp_t);
+amglue_add_constant(COMP_SERVER_FAST, comp_t);
+amglue_add_constant(COMP_SERVER_BEST, comp_t);
+amglue_add_constant(COMP_SERVER_CUST, comp_t);
+amglue_copy_to_tag(comp_t, getconf);
+
+amglue_add_enum_tag_fns(encrypt_t);
+amglue_add_constant(ENCRYPT_NONE, encrypt_t);
+amglue_add_constant(ENCRYPT_CUST, encrypt_t);
+amglue_add_constant(ENCRYPT_SERV_CUST, encrypt_t);
+amglue_copy_to_tag(encrypt_t, getconf);
+
+amglue_add_enum_tag_fns(strategy_t);
+amglue_add_constant(DS_SKIP, strategy_t);
+amglue_add_constant(DS_STANDARD, strategy_t);
+amglue_add_constant(DS_NOFULL, strategy_t);
+amglue_add_constant(DS_NOINC, strategy_t);
+amglue_add_constant(DS_4, strategy_t);
+amglue_add_constant(DS_5, strategy_t);
+amglue_add_constant(DS_HANOI, strategy_t);
+amglue_add_constant(DS_INCRONLY, strategy_t);
+amglue_copy_to_tag(strategy_t, getconf);
+
+amglue_add_enum_tag_fns(estimate_t);
+amglue_add_constant(ES_CLIENT, estimate_t);
+amglue_add_constant(ES_SERVER, estimate_t);
+amglue_add_constant(ES_CALCSIZE, estimate_t);
+amglue_copy_to_tag(estimate_t, getconf);
+
+amglue_add_enum_tag_fns(taperalgo_t);
+amglue_add_constant(ALGO_FIRST, taperalgo_t);
+amglue_add_constant(ALGO_FIRSTFIT, taperalgo_t);
+amglue_add_constant(ALGO_LARGEST, taperalgo_t);
+amglue_add_constant(ALGO_LARGESTFIT, taperalgo_t);
+amglue_add_constant(ALGO_SMALLEST, taperalgo_t);
+amglue_add_constant(ALGO_LAST, taperalgo_t);
+amglue_copy_to_tag(taperalgo_t, getconf);
+
+/*
+ * val_t typemaps
+ */
+
+/* Typemap to convert a val_t, the union in which config values are
+ * stored, to a Perl value of the appropriate type.  This converts:
+ *  - CONFTYPE_SIZE, CONFTYPE_INT, CONFTYPE_AM64,
+ *    CONFTYPE_BOOLEAN -> IV
+ *  - CONFTYPE_REAL -> NV
+ *  - CONFTYPE_STR, CONFTYPE_IDENT -> PV
+ *  - CONFTYPE_TIME -> IV (epoch timestamp)
+ *  - CONFTYPE_COMPRESS, CONFTYPE_ENCRYPT, CONFTYPE_ESTIMATE, CONFTYPE_STRATEGY,
+ *    CONFTYPE_TAPERALGO, CONFTYPE_PRIORITY, CONFTYPE_HOLDING -> IV (enums)
+ *  - CONFTYPE_RATE -> list of two NVs
+ *  - CONFTYPE_INTRANGE -> list of two IVs
+ *  - CONFTYPE_EXINCLUDE -> hashref with keys 'list' (listref), 'file' (listref), 
+ *    and 'optional' (int)
+ *  - CONFTYPE_PROPLIST -> hashref
+ */
+%typemap (out) val_t * {
+    switch ($1->type) {
+       case CONFTYPE_RATE: {
+           $result= sv_newmortal();
+           sv_setnv($result, val_t__rate($1)[0]);
+           argvi++;
+
+           $result= sv_newmortal();
+           sv_setnv($result, val_t__rate($1)[1]);
+           argvi++;
+           break;
+       }
+
+       case CONFTYPE_INTRANGE: {
+           $result= sv_newmortal();
+           sv_setiv($result, val_t__intrange($1)[0]);
+           argvi++;
+
+           $result= sv_newmortal();
+           sv_setiv($result, val_t__intrange($1)[1]);
+           argvi++;
+           break;
+           break;
+       }
+
+       case CONFTYPE_EXINCLUDE: {
+           /* exincludes are represented in perl as {
+            *  'list' : [ 'list1', 'list2', ..],
+            *  'file' : [ 'file1', 'file2', ..],
+            *  'optional' : 1,
+            * }
+            */
+           exinclude_t *ei = &val_t__exinclude($1);
+           AV *list_entries = (AV *)sv_2mortal((SV *)newAV());
+           AV *file_entries = (AV *)sv_2mortal((SV *)newAV());
+           SV *optional = sv_newmortal();
+           HV *hv;
+           sle_t *iter;
+
+           /* first set up each of the hash values */
+
+           if (ei->sl_list) {
+               for (iter = ei->sl_list->first; iter != NULL; iter = iter->next) {
+                   av_push(list_entries, newSVpv(iter->name, 0));
+               }
+           }
+
+           if(ei->sl_file) {
+               for (iter = ei->sl_file->first; iter != NULL; iter = iter->next) {
+                   av_push(file_entries, newSVpv(iter->name, 0));
+               }
+           }
+
+           sv_setiv(optional, ei->optional);
+
+           /* now build the hash */
+           hv = (HV *)sv_2mortal((SV *)newHV());
+           
+           hv_store(hv, "file", 4, newRV((SV *)file_entries), 0);
+           hv_store(hv, "list", 4, newRV((SV *)list_entries), 0);
+           hv_store(hv, "optional", 8, optional, 0);
+           SvREFCNT_inc(optional);
+
+           $result = sv_2mortal(newRV((SV *)hv));
+           argvi++;
+           break;
+       }
+
+       case CONFTYPE_PROPLIST:
+           $result = sv_2mortal(g_hash_table_to_hashref(val_t__proplist($1)));
+           argvi++;
+           break;
+
+       case CONFTYPE_SIZE:
+           $result = sv_2mortal(amglue_newSVi64(val_t__size($1)));
+           argvi++;
+           break;
+
+       case CONFTYPE_AM64:
+           $result = sv_2mortal(amglue_newSVi64(val_t__am64($1)));
+           argvi++;
+           break;
+
+       case CONFTYPE_BOOLEAN:      /* all same as INT.. */
+       case CONFTYPE_COMPRESS:
+       case CONFTYPE_ENCRYPT:
+       case CONFTYPE_ESTIMATE:
+       case CONFTYPE_STRATEGY:
+       case CONFTYPE_TAPERALGO:
+       case CONFTYPE_PRIORITY:
+       case CONFTYPE_HOLDING:
+       case CONFTYPE_INT:
+           $result = sv_2mortal(amglue_newSVi64(val_t__int($1)));
+           argvi++;
+           break;
+
+       case CONFTYPE_TIME:
+           $result = sv_2mortal(amglue_newSVi64(val_t__time($1)));
+           argvi++;
+           break;
+
+       case CONFTYPE_REAL:
+           $result = sv_newmortal();
+           sv_setnv($result, val_t__real($1));
+           argvi++;
+           break;
+
+       case CONFTYPE_IDENT:        /* same as STRING */
+       case CONFTYPE_STR:
+           $result = sv_newmortal();
+           sv_setpv($result, val_t__str($1));
+           argvi++;
+           break;
+
+       /* No match yet -> not one of the "complex" types */
+       default:
+           SWIG_exception(SWIG_TypeError, "Unknown val_t conftype");
+           break;
+    }
+}
+
+/* Typemap for the return value of getconf_list; this assumes that
+ * the GSList contains strings, and that it should be freed; both
+ * are true for getconf_list.
+ */
+%typemap (out) GSList * {
+    GSList *it = $1;
+
+    while (it) {
+       $result = sv_2mortal(newSVpv(it->data, 0));
+       argvi++;
+       it = it->next;
+    }
+
+    g_slist_free($1);
+}
+
+val_t *getconf(confparm_key key);
+gboolean getconf_seen(confparm_key key);
+val_t *getconf_byname(char *key);
+GSList *getconf_list(char *listname);
+amglue_export_tag(getconf,
+    getconf getconf_seen 
+    getconf_byname getconf_list
+);
+
+tapetype_t *lookup_tapetype(char *identifier);
+val_t *tapetype_getconf(tapetype_t *ttyp, tapetype_key key);
+char *tapetype_name(tapetype_t *ttyp);
+gboolean tapetype_seen(tapetype_t *ttyp, tapetype_key key);
+amglue_export_tag(getconf,
+    lookup_tapetype tapetype_getconf tapetype_name
+    tapetype_seen tapetype_seen
+);
+
+dumptype_t *lookup_dumptype(char *identifier);
+val_t *dumptype_getconf(dumptype_t *dtyp, dumptype_key key);
+char *dumptype_name(dumptype_t *dtyp);
+gboolean dumptype_seen(dumptype_t *dtyp, dumptype_key key);
+amglue_export_tag(getconf,
+    lookup_dumptype dumptype_getconf dumptype_name
+    dumptype_seen dumptype_seen
+);
+
+interface_t *lookup_interface(char *identifier);
+val_t *interface_getconf(interface_t *iface, interface_key key);
+char *interface_name(interface_t *iface);
+gboolean interface_seen(interface_t *iface, interface_key key);
+amglue_export_tag(getconf,
+    lookup_interface interface_getconf interface_name
+    interface_seen interface_seen
+);
+
+holdingdisk_t *lookup_holdingdisk(char *identifier);
+holdingdisk_t *getconf_holdingdisks(void);
+holdingdisk_t *holdingdisk_next(holdingdisk_t *hdisk);
+val_t *holdingdisk_getconf(holdingdisk_t *hdisk, holdingdisk_key key);
+char *holdingdisk_name(holdingdisk_t *hdisk);
+gboolean holdingdisk_seen(holdingdisk_t *hdisk, holdingdisk_key key);
+amglue_export_tag(getconf,
+    lookup_holdingdisk holdingdisk_getconf holdingdisk_name
+    getconf_holdingdisks holdingdisk_next
+    holdingdisk_seen holdingdisk_seen
+);
+
+long int getconf_unit_divisor(void);
+
+extern int debug_amandad;
+extern int debug_amidxtaped;
+extern int debug_amindexd;
+extern int debug_amrecover;
+extern int debug_auth;
+extern int debug_event;
+extern int debug_holding;
+extern int debug_protocol;
+extern int debug_planner;
+extern int debug_driver;
+extern int debug_dumper;
+extern int debug_chunker;
+extern int debug_taper;
+extern int debug_selfcheck;
+extern int debug_sendsize;
+extern int debug_sendbackup;
+amglue_export_tag(getconf,
+    getconf_unit_divisor
+
+    $debug_amandad $debug_amidxtaped $debug_amindexd $debug_amrecover
+    $debug_auth $debug_event $debug_holding $debug_protocol
+    $debug_planner $debug_driver $debug_dumper $debug_chunker
+    $debug_taper $debug_selfcheck $debug_sendsize $debug_sendbackup
+);
+
+/*
+ * Initialization
+ */
+
+config_overwrites_t *new_config_overwrites(int size_estimate);
+void free_config_overwrites(config_overwrites_t *co);
+void add_config_overwrite(config_overwrites_t *co,
+                        char *key,
+                        char *value);
+void add_config_overwrite_opt(config_overwrites_t *co,
+                             char *optarg);
+void apply_config_overwrites(config_overwrites_t *co);
+amglue_export_tag(init,
+    new_config_overwrites free_config_overwrites add_config_overwrite
+    add_config_overwrite_opt apply_config_overwrites
+);
+
+
+
+
+amglue_add_flag_tag_fns(config_init_flags);
+amglue_add_constant(CONFIG_INIT_EXPLICIT_NAME, config_init_flags);
+amglue_add_constant(CONFIG_INIT_USE_CWD, config_init_flags);
+amglue_add_constant(CONFIG_INIT_CLIENT, config_init_flags);
+amglue_add_constant(CONFIG_INIT_OVERLAY, config_init_flags);
+amglue_add_constant(CONFIG_INIT_FATAL, config_init_flags);
+amglue_copy_to_tag(config_init_flags, init);
+
+gboolean config_init(config_init_flags flags,
+                    char *arg_config_name);
+void config_uninit(void);
+char **get_config_options(int first);
+amglue_export_tag(init,
+    config_init config_uninit get_config_options
+);
+
+/* These are accessor functions, because SWIG's wrapping of global string
+ * variables is no so good -- the resulting strings can't be passed to other
+ * functions expecting char * arguments.  */
+%inline %{
+    char *get_config_name(void) { return config_name; }
+    char *get_config_dir(void) { return config_dir; }
+    char *get_config_filename(void) { return config_filename; }
+%}
+amglue_export_tag(init,
+    get_config_name 
+    get_config_dir 
+    get_config_filename
+);
+
+/*
+ * Miscellaneous
+ */
+
+void dump_configuration(void);
+char *config_dir_relative(char *filename);
+char *taperalgo2str(taperalgo_t taperalgo);
+gint64 find_multiplier(char * casestr);
+amglue_export_ok(
+    dump_configuration config_dir_relative taperalgo2str find_multiplier
+);
+
diff --git a/perl/Amanda/Debug.c b/perl/Amanda/Debug.c
new file mode 100644 (file)
index 0000000..b3ff7ae
--- /dev/null
@@ -0,0 +1,2482 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.33
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPERL
+#define SWIG_CASTRANK_MODE
+/* -----------------------------------------------------------------------------
+ *  This section contains generic SWIG labels for method/variable
+ *  declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+#  define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+#   define SWIGINLINE inline
+# else
+#   define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define SWIGUNUSED __attribute__ ((__unused__)) 
+#   else
+#     define SWIGUNUSED
+#   endif
+# elif defined(__ICC)
+#   define SWIGUNUSED __attribute__ ((__unused__)) 
+# else
+#   define SWIGUNUSED 
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+#   define SWIGUNUSEDPARM(p)
+# else
+#   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#  ifndef GCC_HASCLASSVISIBILITY
+#    define GCC_HASCLASSVISIBILITY
+#  endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   if defined(STATIC_LINKED)
+#     define SWIGEXPORT
+#   else
+#     define SWIGEXPORT __declspec(dllexport)
+#   endif
+# else
+#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+#     define SWIGEXPORT __attribute__ ((visibility("default")))
+#   else
+#     define SWIGEXPORT
+#   endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   define SWIGSTDCALL __stdcall
+# else
+#   define SWIGSTDCALL
+# endif 
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+   or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "3"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+  You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+  creating a static or dynamic library from the swig runtime code.
+  In 99.9% of the cases, swig just needs to declare them as 'static'.
+  
+  But only do this if is strictly necessary, ie, if you have problems
+  with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/*  Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN        0x1
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN           0x1
+
+
+/* 
+   Flags/methods for returning states.
+   
+   The swig conversion methods, as ConvertPtr, return and integer 
+   that tells if the conversion was successful or not. And if not,
+   an error code can be returned (see swigerrors.swg for the codes).
+   
+   Use the following macros/flags to set or process the returning
+   states.
+   
+   In old swig versions, you usually write code as:
+
+     if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+       // success code
+     } else {
+       //fail code
+     }
+
+   Now you can be more explicit as:
+
+    int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+    } else {
+      // fail code
+    }
+
+   that seems to be the same, but now you can also do
+
+    Type *ptr;
+    int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+      if (SWIG_IsNewObj(res) {
+        ...
+       delete *ptr;
+      } else {
+        ...
+      }
+    } else {
+      // fail code
+    }
+    
+   I.e., now SWIG_ConvertPtr can return new objects and you can
+   identify the case and take care of the deallocation. Of course that
+   requires also to SWIG_ConvertPtr to return new result values, as
+
+      int SWIG_ConvertPtr(obj, ptr,...) {         
+        if (<obj is ok>) {                            
+          if (<need new object>) {                    
+            *ptr = <ptr to new allocated object>; 
+            return SWIG_NEWOBJ;                       
+          } else {                                    
+            *ptr = <ptr to old object>;               
+            return SWIG_OLDOBJ;                       
+          }                                   
+        } else {                                      
+          return SWIG_BADOBJ;                 
+        }                                             
+      }
+
+   Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+   more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+   swig errors code.
+
+   Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+   allows to return the 'cast rank', for example, if you have this
+
+       int food(double)
+       int fooi(int);
+
+   and you call
+      food(1)   // cast rank '1'  (1 -> 1.0)
+      fooi(1)   // cast rank '0'
+
+   just use the SWIG_AddCast()/SWIG_CheckState()
+
+
+ */
+#define SWIG_OK                    (0) 
+#define SWIG_ERROR                 (-1)
+#define SWIG_IsOK(r)               (r >= 0)
+#define SWIG_ArgError(r)           ((r != SWIG_ERROR) ? r : SWIG_TypeError)  
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT         (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK            (SWIG_CASTRANKLIMIT  << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK            (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ                (SWIG_ERROR)
+#define SWIG_OLDOBJ                (SWIG_OK)
+#define SWIG_NEWOBJ                (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ                (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r)         (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r)           (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r)         (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r)           (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+#  ifndef SWIG_TypeRank
+#    define SWIG_TypeRank             unsigned long
+#  endif
+#  ifndef SWIG_MAXCASTRANK            /* Default cast allowed */
+#    define SWIG_MAXCASTRANK          (2)
+#  endif
+#  define SWIG_CASTRANKMASK          ((SWIG_CASTRANKLIMIT) -1)
+#  define SWIG_CastRank(r)           (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) { 
+  return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) { 
+  return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; 
+}
+#else /* no cast-rank mode */
+#  define SWIG_AddCast
+#  define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store inforomation on one type */
+typedef struct swig_type_info {
+  const char             *name;                        /* mangled name of this type */
+  const char             *str;                 /* human readable name of this type */
+  swig_dycast_func        dcast;               /* dynamic cast function down a hierarchy */
+  struct swig_cast_info  *cast;                        /* linked list of types that can cast into this type */
+  void                   *clientdata;          /* language specific type data */
+  int                    owndata;              /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+  swig_type_info         *type;                        /* pointer to type that is equivalent to this type */
+  swig_converter_func     converter;           /* function to cast the void pointers */
+  struct swig_cast_info  *next;                        /* pointer to next cast in linked list */
+  struct swig_cast_info  *prev;                        /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+  swig_type_info         **types;              /* Array of pointers to swig_type_info structures that are in this module */
+  size_t                 size;                 /* Number of types in this module */
+  struct swig_module_info *next;               /* Pointer to next element in circularly linked list */
+  swig_type_info         **type_initial;       /* Array of initially generated type structures */
+  swig_cast_info         **cast_initial;       /* Array of initially generated casting structures */
+  void                    *clientdata;         /* Language specific module data */
+} swig_module_info;
+
+/* 
+  Compare two type names skipping the space characters, therefore
+  "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+  Return 0 when the two name types are equivalent, as in
+  strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+                 const char *f2, const char *l2) {
+  for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+    while ((*f1 == ' ') && (f1 != l1)) ++f1;
+    while ((*f2 == ' ') && (f2 != l2)) ++f2;
+    if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+  }
+  return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty)         \
+  if (ty) {                                             \
+    swig_cast_info *iter = ty->cast;                    \
+    while (iter) {                                      \
+      if (comparison) {                                 \
+        if (iter == ty->cast) return iter;              \
+        /* Move iter to the top of the linked list */   \
+        iter->prev->next = iter->next;                  \
+        if (iter->next)                                 \
+          iter->next->prev = iter->prev;                \
+        iter->next = ty->cast;                          \
+        iter->prev = 0;                                 \
+        if (ty->cast) ty->cast->prev = iter;            \
+        ty->cast = iter;                                \
+        return iter;                                    \
+      }                                                 \
+      iter = iter->next;                                \
+    }                                                   \
+  }                                                     \
+  return 0
+
+/*
+  Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+  SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+  Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr) {
+  return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/* 
+   Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/*
+  Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/*
+  Return the pretty name associated with this type,
+  that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+  /* The "str" field contains the equivalent pretty names of the
+     type, separated by vertical-bar characters.  We choose
+     to print the last name, as it is often (?) the most
+     specific. */
+  if (!type) return NULL;
+  if (type->str != NULL) {
+    const char *last_name = type->str;
+    const char *s;
+    for (s = type->str; *s; s++)
+      if (*s == '|') last_name = s+1;
+    return last_name;
+  }
+  else
+    return type->name;
+}
+
+/* 
+   Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  swig_cast_info *cast = ti->cast;
+  /* if (ti->clientdata == clientdata) return; */
+  ti->clientdata = clientdata;
+  
+  while (cast) {
+    if (!cast->converter) {
+      swig_type_info *tc = cast->type;
+      if (!tc->clientdata) {
+       SWIG_TypeClientData(tc, clientdata);
+      }
+    }    
+    cast = cast->next;
+  }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+  SWIG_TypeClientData(ti, clientdata);
+  ti->owndata = 1;
+}
+  
+/*
+  Search for a swig_type_info structure only by mangled name
+  Search is a O(log #types)
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start, 
+                            swig_module_info *end, 
+                           const char *name) {
+  swig_module_info *iter = start;
+  do {
+    if (iter->size) {
+      register size_t l = 0;
+      register size_t r = iter->size - 1;
+      do {
+       /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+       register size_t i = (l + r) >> 1; 
+       const char *iname = iter->types[i]->name;
+       if (iname) {
+         register int compare = strcmp(name, iname);
+         if (compare == 0) {       
+           return iter->types[i];
+         } else if (compare < 0) {
+           if (i) {
+             r = i - 1;
+           } else {
+             break;
+           }
+         } else if (compare > 0) {
+           l = i + 1;
+         }
+       } else {
+         break; /* should never happen */
+       }
+      } while (l <= r);
+    }
+    iter = iter->next;
+  } while (iter != end);
+  return 0;
+}
+
+/*
+  Search for a swig_type_info structure for either a mangled name or a human readable name.
+  It first searches the mangled names of the types, which is a O(log #types)
+  If a type is not found it then searches the human readable names, which is O(#types).
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start, 
+                     swig_module_info *end, 
+                    const char *name) {
+  /* STEP 1: Search the name field using binary search */
+  swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+  if (ret) {
+    return ret;
+  } else {
+    /* STEP 2: If the type hasn't been found, do a complete search
+       of the str field (the human readable name) */
+    swig_module_info *iter = start;
+    do {
+      register size_t i = 0;
+      for (; i < iter->size; ++i) {
+       if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+         return iter->types[i];
+      }
+      iter = iter->next;
+    } while (iter != end);
+  }
+  
+  /* neither found a match */
+  return 0;
+}
+
+/* 
+   Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+  static const char hex[17] = "0123456789abcdef";
+  register const unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu =  u + sz;
+  for (; u != eu; ++u) {
+    register unsigned char uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* 
+   Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+  register unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu = u + sz;
+  for (; u != eu; ++u) {
+    register char d = *(c++);
+    register unsigned char uu;
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    else 
+      return (char *) 0;
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    else 
+      return (char *) 0;
+    *u = uu;
+  }
+  return c;
+}
+
+/* 
+   Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+  char *r = buff;
+  if ((2*sizeof(void *) + 2) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,&ptr,sizeof(void *));
+  if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+  strcpy(r,name);
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      *ptr = (void *) 0;
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+  char *r = buff;
+  size_t lname = (name ? strlen(name) : 0);
+  if ((2*sz + 2 + lname) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  if (lname) {
+    strncpy(r,name,lname+1);
+  } else {
+    *r = 0;
+  }
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      memset(ptr,0,sz);
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*  Errors in SWIG */
+#define  SWIG_UnknownError        -1 
+#define  SWIG_IOError             -2 
+#define  SWIG_RuntimeError        -3 
+#define  SWIG_IndexError          -4 
+#define  SWIG_TypeError           -5 
+#define  SWIG_DivisionByZero      -6 
+#define  SWIG_OverflowError       -7 
+#define  SWIG_SyntaxError         -8 
+#define  SWIG_ValueError          -9 
+#define  SWIG_SystemError         -10
+#define  SWIG_AttributeError      -11
+#define  SWIG_MemoryError         -12 
+#define  SWIG_NullReferenceError   -13
+
+
+
+#ifdef __cplusplus
+/* Needed on some windows machines---since MS plays funny games with the header files under C++ */
+#include <math.h>
+#include <stdlib.h>
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* Add in functionality missing in older versions of Perl. Much of this is based on Devel-PPPort on cpan. */
+
+/* Add PERL_REVISION, PERL_VERSION, PERL_SUBVERSION if missing */
+#ifndef PERL_REVISION
+#  if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+#    define PERL_PATCHLEVEL_H_IMPLICIT
+#    include <patchlevel.h>
+#  endif
+#  if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+#    include <could_not_find_Perl_patchlevel.h>
+#  endif
+#  ifndef PERL_REVISION
+#    define PERL_REVISION       (5)
+#    define PERL_VERSION        PATCHLEVEL
+#    define PERL_SUBVERSION     SUBVERSION
+#  endif
+#endif
+
+#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE)
+#define PerlIO_exportFILE(fh,fl) (FILE*)(fh)
+#endif
+
+#ifndef SvIOK_UV
+# define SvIOK_UV(sv)       (SvIOK(sv) && (SvUVX(sv) == SvIVX(sv)))
+#endif
+
+#ifndef SvUOK
+# define SvUOK(sv)           SvIOK_UV(sv)
+#endif
+
+#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5)))
+#  define PL_sv_undef               sv_undef
+#  define PL_na                            na
+#  define PL_errgv                  errgv
+#  define PL_sv_no                  sv_no
+#  define PL_sv_yes                 sv_yes
+#  define PL_markstack_ptr          markstack_ptr
+#endif
+
+#ifndef IVSIZE
+#  ifdef LONGSIZE
+#    define IVSIZE LONGSIZE
+#  else
+#    define IVSIZE 4 /* A bold guess, but the best we can make. */
+#  endif
+#endif
+
+#ifndef INT2PTR
+#  if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#    define PTRV                  UV
+#    define INT2PTR(any,d)        (any)(d)
+#  else
+#    if PTRSIZE == LONGSIZE
+#      define PTRV                unsigned long
+#    else
+#      define PTRV                unsigned
+#    endif
+#    define INT2PTR(any,d)        (any)(PTRV)(d)
+#  endif
+
+#  define NUM2PTR(any,d)  (any)(PTRV)(d)
+#  define PTR2IV(p)       INT2PTR(IV,p)
+#  define PTR2UV(p)       INT2PTR(UV,p)
+#  define PTR2NV(p)       NUM2PTR(NV,p)
+
+#  if PTRSIZE == LONGSIZE
+#    define PTR2ul(p)     (unsigned long)(p)
+#  else
+#    define PTR2ul(p)     INT2PTR(unsigned long,p)
+#  endif
+#endif /* !INT2PTR */
+
+#ifndef SvPV_nolen
+# define SvPV_nolen(x) SvPV(x,PL_na)
+#endif
+
+#ifndef get_sv
+#  define get_sv perl_get_sv
+#endif
+
+#ifndef ERRSV
+#  define ERRSV get_sv("@",FALSE)
+#endif
+
+#ifndef pTHX_
+#define pTHX_
+#endif   
+
+#include <string.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGINTERN const char*
+SWIG_Perl_ErrorType(int code) {
+  const char* type = 0;
+  switch(code) {
+  case SWIG_MemoryError:
+    type = "MemoryError";
+    break;
+  case SWIG_IOError:
+    type = "IOError";
+    break;
+  case SWIG_RuntimeError:
+    type = "RuntimeError";
+    break;
+  case SWIG_IndexError:
+    type = "IndexError";
+    break;
+  case SWIG_TypeError:
+    type = "TypeError";
+    break;
+  case SWIG_DivisionByZero:
+    type = "ZeroDivisionError";
+    break;
+  case SWIG_OverflowError:
+    type = "OverflowError";
+    break;
+  case SWIG_SyntaxError:
+    type = "SyntaxError";
+    break;
+  case SWIG_ValueError:
+    type = "ValueError";
+    break;
+  case SWIG_SystemError:
+    type = "SystemError";
+    break;
+  case SWIG_AttributeError:
+    type = "AttributeError";
+    break;
+  default:
+    type = "RuntimeError";
+  }
+  return type;
+}
+
+
+
+
+/* -----------------------------------------------------------------------------
+ * perlrun.swg
+ *
+ * This file contains the runtime support for Perl modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef PERL_OBJECT
+#define SWIG_PERL_OBJECT_DECL CPerlObj *SWIGUNUSEDPARM(pPerl),
+#define SWIG_PERL_OBJECT_CALL pPerl,
+#else
+#define SWIG_PERL_OBJECT_DECL
+#define SWIG_PERL_OBJECT_CALL
+#endif
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_ConvertPtr(obj, pp, type, flags)           SWIG_Perl_ConvertPtr(SWIG_PERL_OBJECT_CALL obj, pp, type, flags)
+#define SWIG_NewPointerObj(p, type, flags)              SWIG_Perl_NewPointerObj(SWIG_PERL_OBJECT_CALL p, type, flags)
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, p, s, type)             SWIG_Perl_ConvertPacked(SWIG_PERL_OBJECT_CALL obj, p, s, type)
+#define SWIG_NewPackedObj(p, s, type)                  SWIG_Perl_NewPackedObj(SWIG_PERL_OBJECT_CALL p, s, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags)    SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags)           SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type)        SWIG_ConvertPtr(obj, pptr, type, 0)
+#define SWIG_NewFunctionPtrObj(ptr, type)               SWIG_NewPointerObj(ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty)            SWIG_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type)                SWIG_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata)                      SWIG_Perl_GetModule()
+#define SWIG_SetModule(clientdata, pointer)             SWIG_Perl_SetModule(pointer)
+
+
+/* Error manipulation */
+
+#define SWIG_ErrorType(code)                            SWIG_Perl_ErrorType(code)               
+#define SWIG_Error(code, msg)                          sv_setpvf(GvSV(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg)
+#define SWIG_fail                                      goto fail                                                   
+
+/* Perl-specific SWIG API */
+
+#define SWIG_MakePtr(sv, ptr, type, flags)              SWIG_Perl_MakePtr(SWIG_PERL_OBJECT_CALL sv, ptr, type, flags)
+#define SWIG_MakePackedObj(sv, p, s, type)             SWIG_Perl_MakePackedObj(SWIG_PERL_OBJECT_CALL sv, p, s, type)
+#define SWIG_SetError(str)                              SWIG_Error(SWIG_RuntimeError, str)
+
+
+#define SWIG_PERL_DECL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_DECL arg1)
+#define SWIG_PERL_CALL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_CALL arg1)
+#define SWIG_PERL_DECL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_DECL arg1, arg2)
+#define SWIG_PERL_CALL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_CALL arg1, arg2)
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+/* For backward compatibility only */
+#define SWIG_POINTER_EXCEPTION  0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_OWNER   SWIG_POINTER_OWN
+#define SWIG_SHADOW  SWIG_OWNER << 1
+
+#define SWIG_MAYBE_PERL_OBJECT SWIG_PERL_OBJECT_DECL
+
+/* SWIG Perl macros */
+
+/* Macro to declare an XS function */
+#ifndef XSPROTO
+#   define XSPROTO(name) void name(pTHX_ CV* cv)
+#endif
+
+/* Macro to call an XS function */
+#ifdef PERL_OBJECT 
+#  define SWIG_CALLXS(_name) _name(cv,pPerl) 
+#else 
+#  ifndef MULTIPLICITY 
+#    define SWIG_CALLXS(_name) _name(cv) 
+#  else 
+#    define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) 
+#  endif 
+#endif 
+
+#ifdef PERL_OBJECT
+#define MAGIC_PPERL  CPerlObj *pPerl = (CPerlObj *) this;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+#define SWIGCLASS_STATIC
+
+#else /* PERL_OBJECT */
+
+#define MAGIC_PPERL
+#define SWIGCLASS_STATIC static SWIGUNUSED
+
+#ifndef MULTIPLICITY
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MULTIPLICITY */
+
+#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MULTIPLICITY */
+#endif /* PERL_OBJECT */
+
+/* Workaround for bug in perl 5.6.x croak and earlier */
+#if (PERL_VERSION < 8)
+#  ifdef PERL_OBJECT
+#    define SWIG_croak_null() SWIG_Perl_croak_null(pPerl)
+static void SWIG_Perl_croak_null(CPerlObj *pPerl)
+#  else
+static void SWIG_croak_null()
+#  endif
+{
+  SV *err=ERRSV;
+#  if (PERL_VERSION < 6)
+  croak("%_", err);
+#  else
+  if (SvOK(err) && !SvROK(err)) croak("%_", err);
+  croak(Nullch);
+#  endif
+}
+#else
+#  define SWIG_croak_null() croak(Nullch)
+#endif
+
+
+/* 
+   Define how strict is the cast between strings and integers/doubles
+   when overloading between these types occurs.
+   
+   The default is making it as strict as possible by using SWIG_AddCast
+   when needed.
+   
+   You can use -DSWIG_PERL_NO_STRICT_STR2NUM at compilation time to
+   disable the SWIG_AddCast, making the casting between string and
+   numbers less strict.
+
+   In the end, we try to solve the overloading between strings and
+   numerical types in the more natural way, but if you can avoid it,
+   well, avoid it using %rename, for example.
+*/
+#ifndef SWIG_PERL_NO_STRICT_STR2NUM
+# ifndef SWIG_PERL_STRICT_STR2NUM
+#  define SWIG_PERL_STRICT_STR2NUM
+# endif
+#endif
+#ifdef SWIG_PERL_STRICT_STR2NUM
+/* string takes precedence */
+#define SWIG_Str2NumCast(x) SWIG_AddCast(x)  
+#else
+/* number takes precedence */
+#define SWIG_Str2NumCast(x) x
+#endif
+
+
+
+#include <stdlib.h>
+
+SWIGRUNTIME const char *
+SWIG_Perl_TypeProxyName(const swig_type_info *type) {
+  if (!type) return NULL;
+  if (type->clientdata != NULL) {
+    return (const char*) type->clientdata;
+  } 
+  else {
+    return type->name;
+  }
+}
+
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeProxyCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(( (!iter->type->clientdata && (strcmp((char*)iter->type->name, c) == 0)) 
+                           || (iter->type->clientdata && (strcmp((char*)iter->type->clientdata, c) == 0))), ty);
+}
+
+
+/* Function for getting a pointer value */
+
+SWIGRUNTIME int
+SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) {
+  swig_cast_info *tc;
+  void *voidptr = (void *)0;
+  SV *tsv = 0;
+  /* If magical, apply more magic */
+  if (SvGMAGICAL(sv))
+    mg_get(sv);
+
+  /* Check to see if this is an object */
+  if (sv_isobject(sv)) {
+    IV tmp = 0;
+    tsv = (SV*) SvRV(sv);
+    if ((SvTYPE(tsv) == SVt_PVHV)) {
+      MAGIC *mg;
+      if (SvMAGICAL(tsv)) {
+        mg = mg_find(tsv,'P');
+        if (mg) {
+          sv = mg->mg_obj;
+          if (sv_isobject(sv)) {
+           tsv = (SV*)SvRV(sv);
+            tmp = SvIV(tsv);
+          }
+        }
+      } else {
+        return SWIG_ERROR;
+      }
+    } else {
+      tmp = SvIV(tsv);
+    }
+    voidptr = INT2PTR(void *,tmp);
+  } else if (! SvOK(sv)) {            /* Check for undef */
+    *(ptr) = (void *) 0;
+    return SWIG_OK;
+  } else if (SvTYPE(sv) == SVt_RV) {  /* Check for NULL pointer */
+    if (!SvROK(sv)) {
+      *(ptr) = (void *) 0;
+      return SWIG_OK;
+    } else {
+      return SWIG_ERROR;
+    }
+  } else {                            /* Don't know what it is */
+    return SWIG_ERROR;
+  }
+  if (_t) {
+    /* Now see if the types match */
+    char *_c = HvNAME(SvSTASH(SvRV(sv)));
+    tc = SWIG_TypeProxyCheck(_c,_t);
+    if (!tc) {
+      return SWIG_ERROR;
+    }
+    *ptr = SWIG_TypeCast(tc,voidptr);
+  } else {
+    *ptr = voidptr;
+  }
+
+  /* 
+   *  DISOWN implementation: we need a perl guru to check this one.
+   */
+  if (tsv && (flags & SWIG_POINTER_DISOWN)) {
+    /* 
+     *  almost copy paste code from below SWIG_POINTER_OWN setting
+     */
+    SV *obj = sv;
+    HV *stash = SvSTASH(SvRV(obj));
+    GV *gv = *(GV**) hv_fetch(stash, "OWNER", 5, TRUE);
+    if (isGV(gv)) {
+      HV *hv = GvHVn(gv);
+      /*
+       * To set ownership (see below), a newSViv(1) entry is added. 
+       * Hence, to remove ownership, we delete the entry.
+       */
+      if (hv_exists_ent(hv, obj, 0)) {
+       hv_delete_ent(hv, obj, 0, 0);
+      }
+    }
+  }
+  return SWIG_OK;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) {
+  if (ptr && (flags & SWIG_SHADOW)) {
+    SV *self;
+    SV *obj=newSV(0);
+    HV *hash=newHV();
+    HV *stash;
+    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+    stash=SvSTASH(SvRV(obj));
+    if (flags & SWIG_POINTER_OWN) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+      if (!isGV(gv))
+        gv_init(gv, stash, "OWNER", 5, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newSViv(1), 0);
+    }
+    sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0);
+    SvREFCNT_dec(obj);
+    self=newRV_noinc((SV *)hash);
+    sv_setsv(sv, self);
+    SvREFCNT_dec((SV *)self);
+    sv_bless(sv, stash);
+  }
+  else {
+    sv_setref_pv(sv, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+  }
+}
+
+SWIGRUNTIMEINLINE SV *
+SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+  SV *result = sv_newmortal();
+  SWIG_MakePtr(result, ptr, t, flags);
+  return result;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) {
+  char result[1024];
+  char *r = result;
+  if ((2*sz + 1 + strlen(SWIG_Perl_TypeProxyName(type))) > 1000) return;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  strcpy(r,SWIG_Perl_TypeProxyName(type));
+  sv_setpv(sv, result);
+}
+
+SWIGRUNTIME SV *
+SWIG_Perl_NewPackedObj(SWIG_MAYBE_PERL_OBJECT void *ptr, int sz, swig_type_info *type) {
+  SV *result = sv_newmortal();
+  SWIG_Perl_MakePackedObj(result, ptr, sz, type);
+  return result;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME int
+SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty) {
+  swig_cast_info *tc;
+  const char  *c = 0;
+
+  if ((!obj) || (!SvOK(obj))) return SWIG_ERROR;
+  c = SvPV_nolen(obj);
+  /* Pointer values must start with leading underscore */
+  if (*c != '_') return SWIG_ERROR;
+  c++;
+  c = SWIG_UnpackData(c,ptr,sz);
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) return SWIG_ERROR;
+  }
+  return SWIG_OK;
+}
+
+
+/* Macros for low-level exception handling */
+#define SWIG_croak(x)    { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail; }
+
+
+typedef XSPROTO(SwigPerlWrapper);
+typedef SwigPerlWrapper *SwigPerlWrapperPtr;
+
+/* Structure for command table */
+typedef struct {
+  const char         *name;
+  SwigPerlWrapperPtr  wrapper;
+} swig_command_info;
+
+/* Information for constant table */
+
+#define SWIG_INT     1
+#define SWIG_FLOAT   2
+#define SWIG_STRING  3
+#define SWIG_POINTER 4
+#define SWIG_BINARY  5
+
+/* Constant information structure */
+typedef struct swig_constant_info {
+    int              type;
+    const char      *name;
+    long             lvalue;
+    double           dvalue;
+    void            *pvalue;
+    swig_type_info **ptype;
+} swig_constant_info;
+
+
+/* Structure for variable table */
+typedef struct {
+  const char   *name;
+  SwigMagicFunc   set;
+  SwigMagicFunc   get;
+  swig_type_info  **type;
+} swig_variable_info;
+
+/* Magic variable code */
+#ifndef PERL_OBJECT
+#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c)
+  #ifndef MULTIPLICITY
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) 
+  #else
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) 
+  #endif
+#else
+#  define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c)
+SWIGRUNTIME void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) 
+#endif
+{
+  MAGIC *mg;
+  sv_magic(sv,sv,'U',(char *) name,strlen(name));
+  mg = mg_find(sv,'U');
+  mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
+  mg->mg_virtual->svt_get = (SwigMagicFunc) get;
+  mg->mg_virtual->svt_set = (SwigMagicFunc) set;
+  mg->mg_virtual->svt_len = 0;
+  mg->mg_virtual->svt_clear = 0;
+  mg->mg_virtual->svt_free = 0;
+}
+
+
+SWIGRUNTIME swig_module_info *
+SWIG_Perl_GetModule(void) {
+  static void *type_pointer = (void *)0;
+  SV *pointer;
+
+  /* first check if pointer already created */
+  if (!type_pointer) {
+    pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE);
+    if (pointer && SvOK(pointer)) {
+      type_pointer = INT2PTR(swig_type_info **, SvIV(pointer));
+    }
+  }
+
+  return (swig_module_info *) type_pointer;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_SetModule(swig_module_info *module) {
+  SV *pointer;
+
+  /* create a new pointer */
+  pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE);
+  sv_setiv(pointer, PTR2IV(module));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Workaround perl5 global namespace pollution. Note that undefining library
+ * functions like fopen will not solve the problem on all platforms as fopen
+ * might be a macro on Windows but not necessarily on other operating systems. */
+#ifdef do_open
+  #undef do_open
+#endif
+#ifdef do_close
+  #undef do_close
+#endif
+#ifdef scalar
+  #undef scalar
+#endif
+#ifdef list
+  #undef list
+#endif
+#ifdef apply
+  #undef apply
+#endif
+#ifdef convert
+  #undef convert
+#endif
+#ifdef Error
+  #undef Error
+#endif
+#ifdef form
+  #undef form
+#endif
+#ifdef vform
+  #undef vform
+#endif
+#ifdef LABEL
+  #undef LABEL
+#endif
+#ifdef METHOD
+  #undef METHOD
+#endif
+#ifdef Move
+  #undef Move
+#endif
+#ifdef yylex
+  #undef yylex
+#endif
+#ifdef yyparse
+  #undef yyparse
+#endif
+#ifdef yyerror
+  #undef yyerror
+#endif
+#ifdef invert
+  #undef invert
+#endif
+#ifdef ref
+  #undef ref
+#endif
+#ifdef read
+  #undef read
+#endif
+#ifdef write
+  #undef write
+#endif
+#ifdef eof
+  #undef eof
+#endif
+#ifdef bool
+  #undef bool
+#endif
+#ifdef close
+  #undef close
+#endif
+#ifdef rewind
+  #undef rewind
+#endif
+#ifdef free
+  #undef free
+#endif
+#ifdef malloc
+  #undef malloc
+#endif
+#ifdef calloc
+  #undef calloc
+#endif
+#ifdef Stat
+  #undef Stat
+#endif
+#ifdef check
+  #undef check
+#endif
+#ifdef seekdir
+  #undef seekdir
+#endif
+#ifdef open
+  #undef open
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) 
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else 
+
+
+
+  #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) 
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_char swig_types[0]
+#define SWIGTYPE_p_double swig_types[1]
+#define SWIGTYPE_p_float swig_types[2]
+#define SWIGTYPE_p_int swig_types[3]
+#define SWIGTYPE_p_unsigned_char swig_types[4]
+static swig_type_info *swig_types[6];
+static swig_module_info swig_module = {swig_types, 5, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init    boot_Amanda__Debug
+
+#define SWIG_name   "Amanda::Debugc::boot_Amanda__Debug"
+#define SWIG_prefix "Amanda::Debugc::"
+
+#define SWIGVERSION 0x010333 
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a)) 
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) 
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifndef PERL_OBJECT
+#ifndef MULTIPLICITY
+SWIGEXPORT void SWIG_init (CV* cv);
+#else
+SWIGEXPORT void SWIG_init (pTHXo_ CV* cv);
+#endif
+#else
+SWIGEXPORT void SWIG_init (CV *cv, CPerlObj *);
+#endif
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include <glib.h>
+#include "debug.h"
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+  static int init = 0;
+  static swig_type_info* info = 0;
+  if (!init) {
+    info = SWIG_TypeQuery("_p_char");
+    init = 1;
+  }
+  return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(SV *obj, char** cptr, size_t* psize, int *alloc)
+{
+  if (SvPOK(obj)) {
+    STRLEN len = 0;
+    char *cstr = SvPV(obj, len); 
+    size_t size = len + 1;
+    if (cptr)  {
+      if (alloc) {
+       if (*alloc == SWIG_NEWOBJ) {
+         *cptr = (char *)memcpy((char *)malloc((size)*sizeof(char)), cstr, sizeof(char)*(size));
+       } else {
+         *cptr = cstr;
+         *alloc = SWIG_OLDOBJ;
+       }
+      }
+    }
+    if (psize) *psize = size;
+    return SWIG_OK;
+  } else {
+    swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+    if (pchar_descriptor) {
+      char* vptr = 0; 
+      if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_descriptor, 0) == SWIG_OK) {
+       if (cptr) *cptr = vptr;
+       if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0;
+       if (alloc) *alloc = SWIG_OLDOBJ;
+       return SWIG_OK;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_long  SWIG_PERL_DECL_ARGS_1(long value)
+{    
+  SV *obj = sv_newmortal();
+  sv_setiv(obj, (IV) value);
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_int  SWIG_PERL_DECL_ARGS_1(int value)
+{    
+  return SWIG_From_long  SWIG_PERL_CALL_ARGS_1(value);
+}
+
+
+#include <limits.h>
+#if !defined(SWIG_NO_LLONG_MAX)
+# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__)
+#   define LLONG_MAX __LONG_LONG_MAX__
+#   define LLONG_MIN (-LLONG_MAX - 1LL)
+#   define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+# endif
+#endif
+
+
+SWIGINTERN int
+SWIG_AsVal_double SWIG_PERL_DECL_ARGS_2(SV *obj, double *val)
+{
+  if (SvNIOK(obj)) {
+    if (val) *val = SvNV(obj);
+    return SWIG_OK;
+  } else if (SvIOK(obj)) {
+    if (val) *val = (double) SvIV(obj);
+    return SWIG_AddCast(SWIG_OK);
+  } else {
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      double v = strtod(nptr, &endptr);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+#include <float.h>
+
+
+#include <math.h>
+
+
+SWIGINTERNINLINE int
+SWIG_CanCastAsInteger(double *d, double min, double max) {
+  double x = *d;
+  if ((min <= x && x <= max)) {
+   double fx = floor(x);
+   double cx = ceil(x);
+   double rd =  ((x - fx) < 0.5) ? fx : cx; /* simple rint */
+   if ((errno == EDOM) || (errno == ERANGE)) {
+     errno = 0;
+   } else {
+     double summ, reps, diff;
+     if (rd < x) {
+       diff = x - rd;
+     } else if (rd > x) {
+       diff = rd - x;
+     } else {
+       return 1;
+     }
+     summ = rd + x;
+     reps = diff/summ;
+     if (reps < 8*DBL_EPSILON) {
+       *d = rd;
+       return 1;
+     }
+   }
+  }
+  return 0;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_long SWIG_PERL_DECL_ARGS_2(SV *obj, long* val)
+{
+  if (SvIOK(obj)) {
+    if (val) *val = SvIV(obj);
+    return SWIG_OK;
+  } else {
+    int dispatch = 0;
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      long v;
+      errno = 0;
+      v = strtol(nptr, &endptr,0);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+    if (!dispatch) {
+      double d;
+      int res = SWIG_AddCast(SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj,&d));
+      if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
+       if (val) *val = (long)(d);
+       return res;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_int SWIG_PERL_DECL_ARGS_2(SV * obj, int *val)
+{
+  long v;
+  int res = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v < INT_MIN || v > INT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = (int)(v);
+    }
+  }  
+  return res;
+}
+
+
+void error__(char *msg) { g_error("%s", msg); }
+void critical(char *msg) { g_critical("%s", msg); }
+void warning(char *msg) { g_warning("%s", msg); }
+void message(char *msg) { g_message("%s", msg); }
+void info(char *msg) { g_info("%s", msg); }
+void debug(char *msg) { g_debug("%s", msg); }
+
+
+SWIGINTERNINLINE SV *
+SWIG_FromCharPtrAndSize(const char* carray, size_t size)
+{
+  SV *obj = sv_newmortal();
+  if (carray) {
+    sv_setpvn(obj, carray, size);
+  } else {
+    sv_setsv(obj, &PL_sv_undef);
+  }
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV * 
+SWIG_FromCharPtr(const char *cptr)
+{ 
+  return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0));
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef PERL_OBJECT
+#define MAGIC_CLASS _wrap_Amanda::Debug_var::
+class _wrap_Amanda::Debug_var : public CPerlObj {
+public:
+#else
+#define MAGIC_CLASS
+#endif
+SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {
+    MAGIC_PPERL
+    croak("Value is read-only.");
+    return 0;
+}
+SWIGCLASS_STATIC int _wrap_erroutput_type_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""erroutput_type""' of type '""erroutput_type_t""'");
+    }
+    erroutput_type = (erroutput_type_t)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_erroutput_type_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(erroutput_type)))  ;
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_error_exit_status_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  {
+    int val;
+    int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(sv, &val);
+    if (!SWIG_IsOK(res)) {
+      SWIG_exception_fail(SWIG_ArgError(res), "in variable '""error_exit_status""' of type '""int""'");
+    }
+    error_exit_status = (int)(val);
+  }
+fail:
+  return 1;
+}
+
+
+SWIGCLASS_STATIC int _wrap_error_exit_status_get(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {
+  MAGIC_PPERL
+  sv_setsv(sv,SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(error_exit_status)))  ;
+  return 1;
+}
+
+
+
+
+#ifdef PERL_OBJECT
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+XS(_wrap_dbopen) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dbopen(subdir);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dbopen" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    dbopen(arg1);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dbreopen) {
+  {
+    char *arg1 = (char *) 0 ;
+    char *arg2 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dbreopen(file,notation);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dbreopen" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dbreopen" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    dbreopen(arg1,arg2);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dbrename) {
+  {
+    char *arg1 = (char *) 0 ;
+    char *arg2 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dbrename(config,subdir);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dbrename" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dbrename" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    dbrename(arg1,arg2);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dbclose) {
+  {
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: dbclose();");
+    }
+    dbclose();
+    
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_error) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: error(msg);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "error" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    error__(arg1);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_critical) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: critical(msg);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "critical" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    critical(arg1);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_warning) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: warning(msg);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "warning" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    warning(arg1);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_message) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: message(msg);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "message" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    message(arg1);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_info) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: info(msg);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "info" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    info(arg1);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_debug) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: debug(msg);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "debug" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    debug(arg1);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dbfd) {
+  {
+    int result;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: dbfd();");
+    }
+    result = (int)dbfd();
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dbfn) {
+  {
+    char *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: dbfn();");
+    }
+    result = (char *)dbfn();
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_debug_dup_stderr_to_debug) {
+  {
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: debug_dup_stderr_to_debug();");
+    }
+    debug_dup_stderr_to_debug();
+    
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_char = {"_p_char", "gchar *|char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_double = {"_p_double", "double *|gdouble *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *|gfloat *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "int *|erroutput_type_t *|gboolean *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "guchar *|unsigned char *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_char,
+  &_swigt__p_double,
+  &_swigt__p_float,
+  &_swigt__p_int,
+  &_swigt__p_unsigned_char,
+};
+
+static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_char[] = {  {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_char,
+  _swigc__p_double,
+  _swigc__p_float,
+  _swigc__p_int,
+  _swigc__p_unsigned_char,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_constant_info swig_constants[] = {
+{0,0,0,0,0,0}
+};
+#ifdef __cplusplus
+}
+#endif
+static swig_variable_info swig_variables[] = {
+    { "Amanda::Debugc::erroutput_type", MAGIC_CLASS _wrap_erroutput_type_set, MAGIC_CLASS _wrap_erroutput_type_get,0 },
+    { "Amanda::Debugc::error_exit_status", MAGIC_CLASS _wrap_error_exit_status_set, MAGIC_CLASS _wrap_error_exit_status_get,0 },
+{0,0,0,0}
+};
+static swig_command_info swig_commands[] = {
+{"Amanda::Debugc::dbopen", _wrap_dbopen},
+{"Amanda::Debugc::dbreopen", _wrap_dbreopen},
+{"Amanda::Debugc::dbrename", _wrap_dbrename},
+{"Amanda::Debugc::dbclose", _wrap_dbclose},
+{"Amanda::Debugc::error", _wrap_error},
+{"Amanda::Debugc::critical", _wrap_critical},
+{"Amanda::Debugc::warning", _wrap_warning},
+{"Amanda::Debugc::message", _wrap_message},
+{"Amanda::Debugc::info", _wrap_info},
+{"Amanda::Debugc::debug", _wrap_debug},
+{"Amanda::Debugc::dbfd", _wrap_dbfd},
+{"Amanda::Debugc::dbfn", _wrap_dbfn},
+{"Amanda::Debugc::debug_dup_stderr_to_debug", _wrap_debug_dup_stderr_to_debug},
+{0,0}
+};
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic 
+ * memory is used. Also, since swig_type_info structures store pointers to 
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization. 
+ * The idea is that swig generates all the structures that are needed. 
+ * The runtime then collects these partially filled structures. 
+ * The SWIG_InitializeModule function takes these initial arrays out of 
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned staticly to an initial 
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it 
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded. 
+ * There are three cases to handle:
+ *  1) If the cast->type has already been loaded AND the type we are adding
+ *     casting info to has not been loaded (it is in this module), THEN we
+ *     replace the cast->type pointer with the type pointer that has already
+ *     been loaded.
+ *  2) If BOTH types (the one we are adding casting info to, and the 
+ *     cast->type) are loaded, THEN the cast info has already been loaded by
+ *     the previous module so we just ignore it.
+ *  3) Finally, if cast->type has not already been loaded, then we add that
+ *     swig_cast_info to the linked list (because the cast->type) pointer will
+ *     be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+  size_t i;
+  swig_module_info *module_head, *iter;
+  int found;
+  
+  clientdata = clientdata;
+  
+  /* check to see if the circular list has been setup, if not, set it up */
+  if (swig_module.next==0) {
+    /* Initialize the swig_module */
+    swig_module.type_initial = swig_type_initial;
+    swig_module.cast_initial = swig_cast_initial;
+    swig_module.next = &swig_module;
+  }
+  
+  /* Try and load any already created modules */
+  module_head = SWIG_GetModule(clientdata);
+  if (!module_head) {
+    /* This is the first module loaded for this interpreter */
+    /* so set the swig module into the interpreter */
+    SWIG_SetModule(clientdata, &swig_module);
+    module_head = &swig_module;
+  } else {
+    /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+    found=0;
+    iter=module_head;
+    do {
+      if (iter==&swig_module) {
+        found=1;
+        break;
+      }
+      iter=iter->next;
+    } while (iter!= module_head);
+    
+    /* if the is found in the list, then all is done and we may leave */
+    if (found) return;
+    /* otherwise we must add out module into the list */
+    swig_module.next = module_head->next;
+    module_head->next = &swig_module;
+  }
+  
+  /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+  printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+  for (i = 0; i < swig_module.size; ++i) {
+    swig_type_info *type = 0;
+    swig_type_info *ret;
+    swig_cast_info *cast;
+    
+#ifdef SWIGRUNTIME_DEBUG
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+    
+    /* if there is another module already loaded */
+    if (swig_module.next != &swig_module) {
+      type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+    }
+    if (type) {
+      /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+      if (swig_module.type_initial[i]->clientdata) {
+        type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+      }
+    } else {
+      type = swig_module.type_initial[i];
+    }
+    
+    /* Insert casting types */
+    cast = swig_module.cast_initial[i];
+    while (cast->type) {
+      /* Don't need to add information already in the list */
+      ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+      if (swig_module.next != &swig_module) {
+        ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+        if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+      }
+      if (ret) {
+        if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+          printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+          cast->type = ret;
+          ret = 0;
+        } else {
+          /* Check for casting already in the list */
+          swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+          if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+          if (!ocast) ret = 0;
+        }
+      }
+      
+      if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+        if (type->cast) {
+          type->cast->prev = cast;
+          cast->next = type->cast;
+        }
+        type->cast = cast;
+      }
+      cast++;
+    }
+    /* Set entry in modules->types array equal to the type */
+    swig_module.types[i] = type;
+  }
+  swig_module.types[i] = 0;
+  
+#ifdef SWIGRUNTIME_DEBUG
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+  for (i = 0; i < swig_module.size; ++i) {
+    int j = 0;
+    swig_cast_info *cast = swig_module.cast_initial[i];
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+    while (cast->type) {
+      printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+      cast++;
+      ++j;
+    }
+    printf("---- Total casts: %d\n",j);
+  }
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types.  It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+  size_t i;
+  swig_cast_info *equiv;
+  static int init_run = 0;
+  
+  if (init_run) return;
+  init_run = 1;
+  
+  for (i = 0; i < swig_module.size; i++) {
+    if (swig_module.types[i]->clientdata) {
+      equiv = swig_module.types[i]->cast;
+      while (equiv) {
+        if (!equiv->converter) {
+          if (equiv->type && !equiv->type->clientdata)
+          SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+        }
+        equiv = equiv->next;
+      }
+    }
+  }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+  /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(SWIG_init) {
+  dXSARGS;
+  int i;
+  
+  SWIG_InitializeModule(0);
+  
+  /* Install commands */
+  for (i = 0; swig_commands[i].name; i++) {
+    newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__);
+  }
+  
+  /* Install variables */
+  for (i = 0; swig_variables[i].name; i++) {
+    SV *sv;
+    sv = get_sv((char*) swig_variables[i].name, TRUE | 0x2);
+    if (swig_variables[i].type) {
+      SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0);
+    } else {
+      sv_setiv(sv,(IV) 0);
+    }
+    swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); 
+  }
+  
+  /* Install constant */
+  for (i = 0; swig_constants[i].type; i++) {
+    SV *sv;
+    sv = get_sv((char*)swig_constants[i].name, TRUE | 0x2);
+    switch(swig_constants[i].type) {
+    case SWIG_INT:
+      sv_setiv(sv, (IV) swig_constants[i].lvalue);
+      break;
+    case SWIG_FLOAT:
+      sv_setnv(sv, (double) swig_constants[i].dvalue);
+      break;
+    case SWIG_STRING:
+      sv_setpv(sv, (char *) swig_constants[i].pvalue);
+      break;
+    case SWIG_POINTER:
+      SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
+      break;
+    case SWIG_BINARY:
+      SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
+      break;
+    default:
+      break;
+    }
+    SvREADONLY_on(sv);
+  }
+  
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ERR_INTERACTIVE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ERR_INTERACTIVE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ERR_SYSLOG", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ERR_SYSLOG)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ERR_AMANDALOG", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ERR_AMANDALOG)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  ST(0) = &PL_sv_yes;
+  XSRETURN(1);
+}
+
diff --git a/perl/Amanda/Debug.pm b/perl/Amanda/Debug.pm
new file mode 100644 (file)
index 0000000..ad6795f
--- /dev/null
@@ -0,0 +1,208 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 1.3.33
+#
+# Don't modify this file, modify the SWIG interface instead.
+
+package Amanda::Debug;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+package Amanda::Debugc;
+bootstrap Amanda::Debug;
+package Amanda::Debug;
+@EXPORT = qw( );
+
+# ---------- BASE METHODS -------------
+
+package Amanda::Debug;
+
+sub TIEHASH {
+    my ($classname,$obj) = @_;
+    return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+    my ($self,$field) = @_;
+    my $member_func = "swig_${field}_get";
+    $self->$member_func();
+}
+
+sub STORE {
+    my ($self,$field,$newval) = @_;
+    my $member_func = "swig_${field}_set";
+    $self->$member_func($newval);
+}
+
+sub this {
+    my $ptr = shift;
+    return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package Amanda::Debug;
+
+*dbopen = *Amanda::Debugc::dbopen;
+*dbreopen = *Amanda::Debugc::dbreopen;
+*dbrename = *Amanda::Debugc::dbrename;
+*dbclose = *Amanda::Debugc::dbclose;
+*error = *Amanda::Debugc::error;
+*critical = *Amanda::Debugc::critical;
+*warning = *Amanda::Debugc::warning;
+*message = *Amanda::Debugc::message;
+*info = *Amanda::Debugc::info;
+*debug = *Amanda::Debugc::debug;
+*dbfd = *Amanda::Debugc::dbfd;
+*dbfn = *Amanda::Debugc::dbfn;
+*debug_dup_stderr_to_debug = *Amanda::Debugc::debug_dup_stderr_to_debug;
+
+# ------- VARIABLE STUBS --------
+
+package Amanda::Debug;
+
+*ERR_INTERACTIVE = *Amanda::Debugc::ERR_INTERACTIVE;
+*ERR_SYSLOG = *Amanda::Debugc::ERR_SYSLOG;
+*ERR_AMANDALOG = *Amanda::Debugc::ERR_AMANDALOG;
+*erroutput_type = *Amanda::Debugc::erroutput_type;
+*error_exit_status = *Amanda::Debugc::error_exit_status;
+
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+
+=head1 NAME
+
+Amanda::Debug - support for debugging Amanda applications
+
+=head1 SYNOPSIS
+
+  use Amanda::Debug qw( :init :logging );
+
+  # (note: dbopen and such are usually handled by 
+  #  Amanda::Util::setup_applicaton)
+  dbopen("server");
+
+  debug("this is a debug message");
+
+See C<debug.h> for a more in-depth description of the functionality of
+this module.
+
+=head1 API STATUS
+
+Stable
+
+=head1 DEBUG LOGGING
+
+Several debug logging messages, each taking a single string, are
+available:
+
+=over
+
+=item C<error> - also aborts the program to produce a core dump
+
+=item C<critical> - exits the program with C<$error_exit_status>
+
+=item C<warning>
+
+=item C<message>
+
+=item C<info>
+
+=item C<debug>
+
+=back
+
+ALl of the debug logging functions are available via the export tag
+C<:logging>.
+
+=head1 ADVANCED USAGE
+
+Most applications should use L<Amanda::Util>'s C<setup_application>
+to initialize the debug libraries.  The initialization functions
+available from this module are thus considered "advanced", and the
+reader is advised to consult the C header, C<debug.h>, for details.
+
+Briefly, the functions C<dbopen> and C<dbrename> are used to
+open a debug file whose pathname includes all of the relevant
+information. C<dbclose> and C<dbreopen> are used to close that debug
+file before transferring control to another process.
+
+The variable C<$erroutput_type> can take on any combination
+of the flags C<$ERROUTPUT_INTERACTIVE>, C<$ERROUTPUT_SYSLOG>
+and C<$ERROUTPUT_AMANDALOG>.  C<$ERROUTPUT_INTERACTIVE>
+causes messages from C<error> and C<critical> to be sent
+to stderr. C<$ERROUTPUT_SYSLOG> sends it to syslog, and
+C<$ERROUTPUT_AMANDALOG> sends it to the current trace log (see
+L<Amanda::Logfile>).
+
+C<$error_exit_status> is the exit status with which C<critical>
+will exit.
+
+All of the initialization functions and variables are available via
+the export tag C<:init>.
+
+The current debug file's integer file descriptor (I<not> a Perl
+filehandle) is available from C<dbfd()>.  Likewise, C<dbfn()> returns
+the filename of the current debug file.
+
+C<debug_dup_stderr_to_debug()> redirects, at the file-descriptor level,
+C<STDERR> into the debug file.  This is useful when running external
+applications which may produce error output.
+
+=cut
+
+push @EXPORT_OK, qw(dbopen dbreopen dbrename dbclose
+    $erroutput_type $error_exit_status);
+push @{$EXPORT_TAGS{"init"}}, qw(dbopen dbreopen dbrename dbclose
+    $erroutput_type $error_exit_status);
+
+push @EXPORT_OK, qw(erroutput_type_t_to_strings);
+push @{$EXPORT_TAGS{"erroutput_type_t"}}, qw(erroutput_type_t_to_strings);
+
+my %_erroutput_type_t_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub erroutput_type_t_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_erroutput_type_t_VALUES) {
+       my $v = $_erroutput_type_t_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($ERR_INTERACTIVE);
+push @{$EXPORT_TAGS{"erroutput_type_t"}}, qw($ERR_INTERACTIVE);
+
+$_erroutput_type_t_VALUES{"INTERACTIVE"} = $ERR_INTERACTIVE;
+
+push @EXPORT_OK, qw($ERR_SYSLOG);
+push @{$EXPORT_TAGS{"erroutput_type_t"}}, qw($ERR_SYSLOG);
+
+$_erroutput_type_t_VALUES{"SYSLOG"} = $ERR_SYSLOG;
+
+push @EXPORT_OK, qw($ERR_AMANDALOG);
+push @{$EXPORT_TAGS{"erroutput_type_t"}}, qw($ERR_AMANDALOG);
+
+$_erroutput_type_t_VALUES{"AMANDALOG"} = $ERR_AMANDALOG;
+
+push @EXPORT_OK, qw(error critical warning message info debug);
+push @{$EXPORT_TAGS{"logging"}}, qw(error critical warning message info debug);
+1;
diff --git a/perl/Amanda/Debug.swg b/perl/Amanda/Debug.swg
new file mode 100644 (file)
index 0000000..e1285d6
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%module "Amanda::Debug"
+%include "amglue/amglue.swg"
+%include "exception.i"
+
+%{
+#include <glib.h>
+#include "debug.h"
+%}
+
+%perlcode %{
+=head1 NAME
+
+Amanda::Debug - support for debugging Amanda applications
+
+=head1 SYNOPSIS
+
+  use Amanda::Debug qw( :init :logging );
+
+  # (note: dbopen and such are usually handled by 
+  #  Amanda::Util::setup_applicaton)
+  dbopen("server");
+
+  debug("this is a debug message");
+
+See C<debug.h> for a more in-depth description of the functionality of
+this module.
+
+=head1 API STATUS
+
+Stable
+
+=head1 DEBUG LOGGING
+
+Several debug logging messages, each taking a single string, are
+available:
+
+=over
+
+=item C<error> - also aborts the program to produce a core dump
+
+=item C<critical> - exits the program with C<$error_exit_status>
+
+=item C<warning>
+
+=item C<message>
+
+=item C<info>
+
+=item C<debug>
+
+=back
+
+ALl of the debug logging functions are available via the export tag
+C<:logging>.
+
+=head1 ADVANCED USAGE
+
+Most applications should use L<Amanda::Util>'s C<setup_application>
+to initialize the debug libraries.  The initialization functions
+available from this module are thus considered "advanced", and the
+reader is advised to consult the C header, C<debug.h>, for details.
+
+Briefly, the functions C<dbopen> and C<dbrename> are used to
+open a debug file whose pathname includes all of the relevant
+information. C<dbclose> and C<dbreopen> are used to close that debug
+file before transferring control to another process.
+
+The variable C<$erroutput_type> can take on any combination
+of the flags C<$ERROUTPUT_INTERACTIVE>, C<$ERROUTPUT_SYSLOG>
+and C<$ERROUTPUT_AMANDALOG>.  C<$ERROUTPUT_INTERACTIVE>
+causes messages from C<error> and C<critical> to be sent
+to stderr. C<$ERROUTPUT_SYSLOG> sends it to syslog, and
+C<$ERROUTPUT_AMANDALOG> sends it to the current trace log (see
+L<Amanda::Logfile>).
+
+C<$error_exit_status> is the exit status with which C<critical>
+will exit.
+
+All of the initialization functions and variables are available via
+the export tag C<:init>.
+
+The current debug file's integer file descriptor (I<not> a Perl
+filehandle) is available from C<dbfd()>.  Likewise, C<dbfn()> returns
+the filename of the current debug file.
+
+C<debug_dup_stderr_to_debug()> redirects, at the file-descriptor level,
+C<STDERR> into the debug file.  This is useful when running external
+applications which may produce error output.
+
+=cut
+%}
+
+/*
+ * Initialization
+ */
+
+amglue_export_tag(init,
+    dbopen dbreopen dbrename dbclose
+    $erroutput_type $error_exit_status
+);
+
+void   dbopen(char *subdir);
+void   dbreopen(char *file, char *notation);
+void   dbrename(char *config, char *subdir);
+void   dbclose(void);
+
+amglue_add_flag_tag_fns(erroutput_type_t);
+amglue_add_constant_short(ERR_INTERACTIVE, INTERACTIVE, erroutput_type_t);
+amglue_add_constant_short(ERR_SYSLOG, SYSLOG, erroutput_type_t);
+amglue_add_constant_short(ERR_AMANDALOG, AMANDALOG, erroutput_type_t);
+amglue_copy_tag_to(erroutput_type_t, init);
+
+erroutput_type_t erroutput_type;
+int error_exit_status;
+
+/*
+ * Logging
+ */
+
+amglue_export_tag(logging,
+    error critical warning message info debug
+);
+
+%rename(error) error__; /* error() is a macro defined in debug.h .. just avoid that */
+%inline %{
+void error__(char *msg) { g_error("%s", msg); }
+void critical(char *msg) { g_critical("%s", msg); }
+void warning(char *msg) { g_warning("%s", msg); }
+void message(char *msg) { g_message("%s", msg); }
+void info(char *msg) { g_info("%s", msg); }
+void debug(char *msg) { g_debug("%s", msg); }
+%}
+
+/*
+ * Advanced
+ */
+
+int    dbfd(void);
+char * dbfn(void);
+void debug_dup_stderr_to_debug(void);
diff --git a/perl/Amanda/Device.c b/perl/Amanda/Device.c
new file mode 100644 (file)
index 0000000..0b41118
--- /dev/null
@@ -0,0 +1,3861 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.33
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPERL
+#define SWIG_CASTRANK_MODE
+/* -----------------------------------------------------------------------------
+ *  This section contains generic SWIG labels for method/variable
+ *  declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+#  define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+#   define SWIGINLINE inline
+# else
+#   define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define SWIGUNUSED __attribute__ ((__unused__)) 
+#   else
+#     define SWIGUNUSED
+#   endif
+# elif defined(__ICC)
+#   define SWIGUNUSED __attribute__ ((__unused__)) 
+# else
+#   define SWIGUNUSED 
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+#   define SWIGUNUSEDPARM(p)
+# else
+#   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#  ifndef GCC_HASCLASSVISIBILITY
+#    define GCC_HASCLASSVISIBILITY
+#  endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   if defined(STATIC_LINKED)
+#     define SWIGEXPORT
+#   else
+#     define SWIGEXPORT __declspec(dllexport)
+#   endif
+# else
+#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+#     define SWIGEXPORT __attribute__ ((visibility("default")))
+#   else
+#     define SWIGEXPORT
+#   endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   define SWIGSTDCALL __stdcall
+# else
+#   define SWIGSTDCALL
+# endif 
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+   or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "3"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+  You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+  creating a static or dynamic library from the swig runtime code.
+  In 99.9% of the cases, swig just needs to declare them as 'static'.
+  
+  But only do this if is strictly necessary, ie, if you have problems
+  with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/*  Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN        0x1
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN           0x1
+
+
+/* 
+   Flags/methods for returning states.
+   
+   The swig conversion methods, as ConvertPtr, return and integer 
+   that tells if the conversion was successful or not. And if not,
+   an error code can be returned (see swigerrors.swg for the codes).
+   
+   Use the following macros/flags to set or process the returning
+   states.
+   
+   In old swig versions, you usually write code as:
+
+     if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+       // success code
+     } else {
+       //fail code
+     }
+
+   Now you can be more explicit as:
+
+    int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+    } else {
+      // fail code
+    }
+
+   that seems to be the same, but now you can also do
+
+    Type *ptr;
+    int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+      if (SWIG_IsNewObj(res) {
+        ...
+       delete *ptr;
+      } else {
+        ...
+      }
+    } else {
+      // fail code
+    }
+    
+   I.e., now SWIG_ConvertPtr can return new objects and you can
+   identify the case and take care of the deallocation. Of course that
+   requires also to SWIG_ConvertPtr to return new result values, as
+
+      int SWIG_ConvertPtr(obj, ptr,...) {         
+        if (<obj is ok>) {                            
+          if (<need new object>) {                    
+            *ptr = <ptr to new allocated object>; 
+            return SWIG_NEWOBJ;                       
+          } else {                                    
+            *ptr = <ptr to old object>;               
+            return SWIG_OLDOBJ;                       
+          }                                   
+        } else {                                      
+          return SWIG_BADOBJ;                 
+        }                                             
+      }
+
+   Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+   more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+   swig errors code.
+
+   Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+   allows to return the 'cast rank', for example, if you have this
+
+       int food(double)
+       int fooi(int);
+
+   and you call
+      food(1)   // cast rank '1'  (1 -> 1.0)
+      fooi(1)   // cast rank '0'
+
+   just use the SWIG_AddCast()/SWIG_CheckState()
+
+
+ */
+#define SWIG_OK                    (0) 
+#define SWIG_ERROR                 (-1)
+#define SWIG_IsOK(r)               (r >= 0)
+#define SWIG_ArgError(r)           ((r != SWIG_ERROR) ? r : SWIG_TypeError)  
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT         (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK            (SWIG_CASTRANKLIMIT  << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK            (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ                (SWIG_ERROR)
+#define SWIG_OLDOBJ                (SWIG_OK)
+#define SWIG_NEWOBJ                (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ                (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r)         (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r)           (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r)         (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r)           (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+#  ifndef SWIG_TypeRank
+#    define SWIG_TypeRank             unsigned long
+#  endif
+#  ifndef SWIG_MAXCASTRANK            /* Default cast allowed */
+#    define SWIG_MAXCASTRANK          (2)
+#  endif
+#  define SWIG_CASTRANKMASK          ((SWIG_CASTRANKLIMIT) -1)
+#  define SWIG_CastRank(r)           (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) { 
+  return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) { 
+  return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; 
+}
+#else /* no cast-rank mode */
+#  define SWIG_AddCast
+#  define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store inforomation on one type */
+typedef struct swig_type_info {
+  const char             *name;                        /* mangled name of this type */
+  const char             *str;                 /* human readable name of this type */
+  swig_dycast_func        dcast;               /* dynamic cast function down a hierarchy */
+  struct swig_cast_info  *cast;                        /* linked list of types that can cast into this type */
+  void                   *clientdata;          /* language specific type data */
+  int                    owndata;              /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+  swig_type_info         *type;                        /* pointer to type that is equivalent to this type */
+  swig_converter_func     converter;           /* function to cast the void pointers */
+  struct swig_cast_info  *next;                        /* pointer to next cast in linked list */
+  struct swig_cast_info  *prev;                        /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+  swig_type_info         **types;              /* Array of pointers to swig_type_info structures that are in this module */
+  size_t                 size;                 /* Number of types in this module */
+  struct swig_module_info *next;               /* Pointer to next element in circularly linked list */
+  swig_type_info         **type_initial;       /* Array of initially generated type structures */
+  swig_cast_info         **cast_initial;       /* Array of initially generated casting structures */
+  void                    *clientdata;         /* Language specific module data */
+} swig_module_info;
+
+/* 
+  Compare two type names skipping the space characters, therefore
+  "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+  Return 0 when the two name types are equivalent, as in
+  strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+                 const char *f2, const char *l2) {
+  for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+    while ((*f1 == ' ') && (f1 != l1)) ++f1;
+    while ((*f2 == ' ') && (f2 != l2)) ++f2;
+    if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+  }
+  return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty)         \
+  if (ty) {                                             \
+    swig_cast_info *iter = ty->cast;                    \
+    while (iter) {                                      \
+      if (comparison) {                                 \
+        if (iter == ty->cast) return iter;              \
+        /* Move iter to the top of the linked list */   \
+        iter->prev->next = iter->next;                  \
+        if (iter->next)                                 \
+          iter->next->prev = iter->prev;                \
+        iter->next = ty->cast;                          \
+        iter->prev = 0;                                 \
+        if (ty->cast) ty->cast->prev = iter;            \
+        ty->cast = iter;                                \
+        return iter;                                    \
+      }                                                 \
+      iter = iter->next;                                \
+    }                                                   \
+  }                                                     \
+  return 0
+
+/*
+  Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+  SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+  Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr) {
+  return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/* 
+   Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/*
+  Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/*
+  Return the pretty name associated with this type,
+  that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+  /* The "str" field contains the equivalent pretty names of the
+     type, separated by vertical-bar characters.  We choose
+     to print the last name, as it is often (?) the most
+     specific. */
+  if (!type) return NULL;
+  if (type->str != NULL) {
+    const char *last_name = type->str;
+    const char *s;
+    for (s = type->str; *s; s++)
+      if (*s == '|') last_name = s+1;
+    return last_name;
+  }
+  else
+    return type->name;
+}
+
+/* 
+   Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  swig_cast_info *cast = ti->cast;
+  /* if (ti->clientdata == clientdata) return; */
+  ti->clientdata = clientdata;
+  
+  while (cast) {
+    if (!cast->converter) {
+      swig_type_info *tc = cast->type;
+      if (!tc->clientdata) {
+       SWIG_TypeClientData(tc, clientdata);
+      }
+    }    
+    cast = cast->next;
+  }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+  SWIG_TypeClientData(ti, clientdata);
+  ti->owndata = 1;
+}
+  
+/*
+  Search for a swig_type_info structure only by mangled name
+  Search is a O(log #types)
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start, 
+                            swig_module_info *end, 
+                           const char *name) {
+  swig_module_info *iter = start;
+  do {
+    if (iter->size) {
+      register size_t l = 0;
+      register size_t r = iter->size - 1;
+      do {
+       /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+       register size_t i = (l + r) >> 1; 
+       const char *iname = iter->types[i]->name;
+       if (iname) {
+         register int compare = strcmp(name, iname);
+         if (compare == 0) {       
+           return iter->types[i];
+         } else if (compare < 0) {
+           if (i) {
+             r = i - 1;
+           } else {
+             break;
+           }
+         } else if (compare > 0) {
+           l = i + 1;
+         }
+       } else {
+         break; /* should never happen */
+       }
+      } while (l <= r);
+    }
+    iter = iter->next;
+  } while (iter != end);
+  return 0;
+}
+
+/*
+  Search for a swig_type_info structure for either a mangled name or a human readable name.
+  It first searches the mangled names of the types, which is a O(log #types)
+  If a type is not found it then searches the human readable names, which is O(#types).
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start, 
+                     swig_module_info *end, 
+                    const char *name) {
+  /* STEP 1: Search the name field using binary search */
+  swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+  if (ret) {
+    return ret;
+  } else {
+    /* STEP 2: If the type hasn't been found, do a complete search
+       of the str field (the human readable name) */
+    swig_module_info *iter = start;
+    do {
+      register size_t i = 0;
+      for (; i < iter->size; ++i) {
+       if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+         return iter->types[i];
+      }
+      iter = iter->next;
+    } while (iter != end);
+  }
+  
+  /* neither found a match */
+  return 0;
+}
+
+/* 
+   Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+  static const char hex[17] = "0123456789abcdef";
+  register const unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu =  u + sz;
+  for (; u != eu; ++u) {
+    register unsigned char uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* 
+   Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+  register unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu = u + sz;
+  for (; u != eu; ++u) {
+    register char d = *(c++);
+    register unsigned char uu;
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    else 
+      return (char *) 0;
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    else 
+      return (char *) 0;
+    *u = uu;
+  }
+  return c;
+}
+
+/* 
+   Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+  char *r = buff;
+  if ((2*sizeof(void *) + 2) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,&ptr,sizeof(void *));
+  if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+  strcpy(r,name);
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      *ptr = (void *) 0;
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+  char *r = buff;
+  size_t lname = (name ? strlen(name) : 0);
+  if ((2*sz + 2 + lname) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  if (lname) {
+    strncpy(r,name,lname+1);
+  } else {
+    *r = 0;
+  }
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      memset(ptr,0,sz);
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*  Errors in SWIG */
+#define  SWIG_UnknownError        -1 
+#define  SWIG_IOError             -2 
+#define  SWIG_RuntimeError        -3 
+#define  SWIG_IndexError          -4 
+#define  SWIG_TypeError           -5 
+#define  SWIG_DivisionByZero      -6 
+#define  SWIG_OverflowError       -7 
+#define  SWIG_SyntaxError         -8 
+#define  SWIG_ValueError          -9 
+#define  SWIG_SystemError         -10
+#define  SWIG_AttributeError      -11
+#define  SWIG_MemoryError         -12 
+#define  SWIG_NullReferenceError   -13
+
+
+
+#ifdef __cplusplus
+/* Needed on some windows machines---since MS plays funny games with the header files under C++ */
+#include <math.h>
+#include <stdlib.h>
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* Add in functionality missing in older versions of Perl. Much of this is based on Devel-PPPort on cpan. */
+
+/* Add PERL_REVISION, PERL_VERSION, PERL_SUBVERSION if missing */
+#ifndef PERL_REVISION
+#  if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+#    define PERL_PATCHLEVEL_H_IMPLICIT
+#    include <patchlevel.h>
+#  endif
+#  if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+#    include <could_not_find_Perl_patchlevel.h>
+#  endif
+#  ifndef PERL_REVISION
+#    define PERL_REVISION       (5)
+#    define PERL_VERSION        PATCHLEVEL
+#    define PERL_SUBVERSION     SUBVERSION
+#  endif
+#endif
+
+#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE)
+#define PerlIO_exportFILE(fh,fl) (FILE*)(fh)
+#endif
+
+#ifndef SvIOK_UV
+# define SvIOK_UV(sv)       (SvIOK(sv) && (SvUVX(sv) == SvIVX(sv)))
+#endif
+
+#ifndef SvUOK
+# define SvUOK(sv)           SvIOK_UV(sv)
+#endif
+
+#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5)))
+#  define PL_sv_undef               sv_undef
+#  define PL_na                            na
+#  define PL_errgv                  errgv
+#  define PL_sv_no                  sv_no
+#  define PL_sv_yes                 sv_yes
+#  define PL_markstack_ptr          markstack_ptr
+#endif
+
+#ifndef IVSIZE
+#  ifdef LONGSIZE
+#    define IVSIZE LONGSIZE
+#  else
+#    define IVSIZE 4 /* A bold guess, but the best we can make. */
+#  endif
+#endif
+
+#ifndef INT2PTR
+#  if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#    define PTRV                  UV
+#    define INT2PTR(any,d)        (any)(d)
+#  else
+#    if PTRSIZE == LONGSIZE
+#      define PTRV                unsigned long
+#    else
+#      define PTRV                unsigned
+#    endif
+#    define INT2PTR(any,d)        (any)(PTRV)(d)
+#  endif
+
+#  define NUM2PTR(any,d)  (any)(PTRV)(d)
+#  define PTR2IV(p)       INT2PTR(IV,p)
+#  define PTR2UV(p)       INT2PTR(UV,p)
+#  define PTR2NV(p)       NUM2PTR(NV,p)
+
+#  if PTRSIZE == LONGSIZE
+#    define PTR2ul(p)     (unsigned long)(p)
+#  else
+#    define PTR2ul(p)     INT2PTR(unsigned long,p)
+#  endif
+#endif /* !INT2PTR */
+
+#ifndef SvPV_nolen
+# define SvPV_nolen(x) SvPV(x,PL_na)
+#endif
+
+#ifndef get_sv
+#  define get_sv perl_get_sv
+#endif
+
+#ifndef ERRSV
+#  define ERRSV get_sv("@",FALSE)
+#endif
+
+#ifndef pTHX_
+#define pTHX_
+#endif   
+
+#include <string.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGINTERN const char*
+SWIG_Perl_ErrorType(int code) {
+  const char* type = 0;
+  switch(code) {
+  case SWIG_MemoryError:
+    type = "MemoryError";
+    break;
+  case SWIG_IOError:
+    type = "IOError";
+    break;
+  case SWIG_RuntimeError:
+    type = "RuntimeError";
+    break;
+  case SWIG_IndexError:
+    type = "IndexError";
+    break;
+  case SWIG_TypeError:
+    type = "TypeError";
+    break;
+  case SWIG_DivisionByZero:
+    type = "ZeroDivisionError";
+    break;
+  case SWIG_OverflowError:
+    type = "OverflowError";
+    break;
+  case SWIG_SyntaxError:
+    type = "SyntaxError";
+    break;
+  case SWIG_ValueError:
+    type = "ValueError";
+    break;
+  case SWIG_SystemError:
+    type = "SystemError";
+    break;
+  case SWIG_AttributeError:
+    type = "AttributeError";
+    break;
+  default:
+    type = "RuntimeError";
+  }
+  return type;
+}
+
+
+
+
+/* -----------------------------------------------------------------------------
+ * perlrun.swg
+ *
+ * This file contains the runtime support for Perl modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef PERL_OBJECT
+#define SWIG_PERL_OBJECT_DECL CPerlObj *SWIGUNUSEDPARM(pPerl),
+#define SWIG_PERL_OBJECT_CALL pPerl,
+#else
+#define SWIG_PERL_OBJECT_DECL
+#define SWIG_PERL_OBJECT_CALL
+#endif
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_ConvertPtr(obj, pp, type, flags)           SWIG_Perl_ConvertPtr(SWIG_PERL_OBJECT_CALL obj, pp, type, flags)
+#define SWIG_NewPointerObj(p, type, flags)              SWIG_Perl_NewPointerObj(SWIG_PERL_OBJECT_CALL p, type, flags)
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, p, s, type)             SWIG_Perl_ConvertPacked(SWIG_PERL_OBJECT_CALL obj, p, s, type)
+#define SWIG_NewPackedObj(p, s, type)                  SWIG_Perl_NewPackedObj(SWIG_PERL_OBJECT_CALL p, s, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags)    SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags)           SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type)        SWIG_ConvertPtr(obj, pptr, type, 0)
+#define SWIG_NewFunctionPtrObj(ptr, type)               SWIG_NewPointerObj(ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty)            SWIG_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type)                SWIG_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata)                      SWIG_Perl_GetModule()
+#define SWIG_SetModule(clientdata, pointer)             SWIG_Perl_SetModule(pointer)
+
+
+/* Error manipulation */
+
+#define SWIG_ErrorType(code)                            SWIG_Perl_ErrorType(code)               
+#define SWIG_Error(code, msg)                          sv_setpvf(GvSV(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg)
+#define SWIG_fail                                      goto fail                                                   
+
+/* Perl-specific SWIG API */
+
+#define SWIG_MakePtr(sv, ptr, type, flags)              SWIG_Perl_MakePtr(SWIG_PERL_OBJECT_CALL sv, ptr, type, flags)
+#define SWIG_MakePackedObj(sv, p, s, type)             SWIG_Perl_MakePackedObj(SWIG_PERL_OBJECT_CALL sv, p, s, type)
+#define SWIG_SetError(str)                              SWIG_Error(SWIG_RuntimeError, str)
+
+
+#define SWIG_PERL_DECL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_DECL arg1)
+#define SWIG_PERL_CALL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_CALL arg1)
+#define SWIG_PERL_DECL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_DECL arg1, arg2)
+#define SWIG_PERL_CALL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_CALL arg1, arg2)
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+/* For backward compatibility only */
+#define SWIG_POINTER_EXCEPTION  0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_OWNER   SWIG_POINTER_OWN
+#define SWIG_SHADOW  SWIG_OWNER << 1
+
+#define SWIG_MAYBE_PERL_OBJECT SWIG_PERL_OBJECT_DECL
+
+/* SWIG Perl macros */
+
+/* Macro to declare an XS function */
+#ifndef XSPROTO
+#   define XSPROTO(name) void name(pTHX_ CV* cv)
+#endif
+
+/* Macro to call an XS function */
+#ifdef PERL_OBJECT 
+#  define SWIG_CALLXS(_name) _name(cv,pPerl) 
+#else 
+#  ifndef MULTIPLICITY 
+#    define SWIG_CALLXS(_name) _name(cv) 
+#  else 
+#    define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) 
+#  endif 
+#endif 
+
+#ifdef PERL_OBJECT
+#define MAGIC_PPERL  CPerlObj *pPerl = (CPerlObj *) this;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+#define SWIGCLASS_STATIC
+
+#else /* PERL_OBJECT */
+
+#define MAGIC_PPERL
+#define SWIGCLASS_STATIC static SWIGUNUSED
+
+#ifndef MULTIPLICITY
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MULTIPLICITY */
+
+#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MULTIPLICITY */
+#endif /* PERL_OBJECT */
+
+/* Workaround for bug in perl 5.6.x croak and earlier */
+#if (PERL_VERSION < 8)
+#  ifdef PERL_OBJECT
+#    define SWIG_croak_null() SWIG_Perl_croak_null(pPerl)
+static void SWIG_Perl_croak_null(CPerlObj *pPerl)
+#  else
+static void SWIG_croak_null()
+#  endif
+{
+  SV *err=ERRSV;
+#  if (PERL_VERSION < 6)
+  croak("%_", err);
+#  else
+  if (SvOK(err) && !SvROK(err)) croak("%_", err);
+  croak(Nullch);
+#  endif
+}
+#else
+#  define SWIG_croak_null() croak(Nullch)
+#endif
+
+
+/* 
+   Define how strict is the cast between strings and integers/doubles
+   when overloading between these types occurs.
+   
+   The default is making it as strict as possible by using SWIG_AddCast
+   when needed.
+   
+   You can use -DSWIG_PERL_NO_STRICT_STR2NUM at compilation time to
+   disable the SWIG_AddCast, making the casting between string and
+   numbers less strict.
+
+   In the end, we try to solve the overloading between strings and
+   numerical types in the more natural way, but if you can avoid it,
+   well, avoid it using %rename, for example.
+*/
+#ifndef SWIG_PERL_NO_STRICT_STR2NUM
+# ifndef SWIG_PERL_STRICT_STR2NUM
+#  define SWIG_PERL_STRICT_STR2NUM
+# endif
+#endif
+#ifdef SWIG_PERL_STRICT_STR2NUM
+/* string takes precedence */
+#define SWIG_Str2NumCast(x) SWIG_AddCast(x)  
+#else
+/* number takes precedence */
+#define SWIG_Str2NumCast(x) x
+#endif
+
+
+
+#include <stdlib.h>
+
+SWIGRUNTIME const char *
+SWIG_Perl_TypeProxyName(const swig_type_info *type) {
+  if (!type) return NULL;
+  if (type->clientdata != NULL) {
+    return (const char*) type->clientdata;
+  } 
+  else {
+    return type->name;
+  }
+}
+
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeProxyCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(( (!iter->type->clientdata && (strcmp((char*)iter->type->name, c) == 0)) 
+                           || (iter->type->clientdata && (strcmp((char*)iter->type->clientdata, c) == 0))), ty);
+}
+
+
+/* Function for getting a pointer value */
+
+SWIGRUNTIME int
+SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) {
+  swig_cast_info *tc;
+  void *voidptr = (void *)0;
+  SV *tsv = 0;
+  /* If magical, apply more magic */
+  if (SvGMAGICAL(sv))
+    mg_get(sv);
+
+  /* Check to see if this is an object */
+  if (sv_isobject(sv)) {
+    IV tmp = 0;
+    tsv = (SV*) SvRV(sv);
+    if ((SvTYPE(tsv) == SVt_PVHV)) {
+      MAGIC *mg;
+      if (SvMAGICAL(tsv)) {
+        mg = mg_find(tsv,'P');
+        if (mg) {
+          sv = mg->mg_obj;
+          if (sv_isobject(sv)) {
+           tsv = (SV*)SvRV(sv);
+            tmp = SvIV(tsv);
+          }
+        }
+      } else {
+        return SWIG_ERROR;
+      }
+    } else {
+      tmp = SvIV(tsv);
+    }
+    voidptr = INT2PTR(void *,tmp);
+  } else if (! SvOK(sv)) {            /* Check for undef */
+    *(ptr) = (void *) 0;
+    return SWIG_OK;
+  } else if (SvTYPE(sv) == SVt_RV) {  /* Check for NULL pointer */
+    if (!SvROK(sv)) {
+      *(ptr) = (void *) 0;
+      return SWIG_OK;
+    } else {
+      return SWIG_ERROR;
+    }
+  } else {                            /* Don't know what it is */
+    return SWIG_ERROR;
+  }
+  if (_t) {
+    /* Now see if the types match */
+    char *_c = HvNAME(SvSTASH(SvRV(sv)));
+    tc = SWIG_TypeProxyCheck(_c,_t);
+    if (!tc) {
+      return SWIG_ERROR;
+    }
+    *ptr = SWIG_TypeCast(tc,voidptr);
+  } else {
+    *ptr = voidptr;
+  }
+
+  /* 
+   *  DISOWN implementation: we need a perl guru to check this one.
+   */
+  if (tsv && (flags & SWIG_POINTER_DISOWN)) {
+    /* 
+     *  almost copy paste code from below SWIG_POINTER_OWN setting
+     */
+    SV *obj = sv;
+    HV *stash = SvSTASH(SvRV(obj));
+    GV *gv = *(GV**) hv_fetch(stash, "OWNER", 5, TRUE);
+    if (isGV(gv)) {
+      HV *hv = GvHVn(gv);
+      /*
+       * To set ownership (see below), a newSViv(1) entry is added. 
+       * Hence, to remove ownership, we delete the entry.
+       */
+      if (hv_exists_ent(hv, obj, 0)) {
+       hv_delete_ent(hv, obj, 0, 0);
+      }
+    }
+  }
+  return SWIG_OK;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) {
+  if (ptr && (flags & SWIG_SHADOW)) {
+    SV *self;
+    SV *obj=newSV(0);
+    HV *hash=newHV();
+    HV *stash;
+    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+    stash=SvSTASH(SvRV(obj));
+    if (flags & SWIG_POINTER_OWN) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+      if (!isGV(gv))
+        gv_init(gv, stash, "OWNER", 5, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newSViv(1), 0);
+    }
+    sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0);
+    SvREFCNT_dec(obj);
+    self=newRV_noinc((SV *)hash);
+    sv_setsv(sv, self);
+    SvREFCNT_dec((SV *)self);
+    sv_bless(sv, stash);
+  }
+  else {
+    sv_setref_pv(sv, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+  }
+}
+
+SWIGRUNTIMEINLINE SV *
+SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+  SV *result = sv_newmortal();
+  SWIG_MakePtr(result, ptr, t, flags);
+  return result;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) {
+  char result[1024];
+  char *r = result;
+  if ((2*sz + 1 + strlen(SWIG_Perl_TypeProxyName(type))) > 1000) return;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  strcpy(r,SWIG_Perl_TypeProxyName(type));
+  sv_setpv(sv, result);
+}
+
+SWIGRUNTIME SV *
+SWIG_Perl_NewPackedObj(SWIG_MAYBE_PERL_OBJECT void *ptr, int sz, swig_type_info *type) {
+  SV *result = sv_newmortal();
+  SWIG_Perl_MakePackedObj(result, ptr, sz, type);
+  return result;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME int
+SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty) {
+  swig_cast_info *tc;
+  const char  *c = 0;
+
+  if ((!obj) || (!SvOK(obj))) return SWIG_ERROR;
+  c = SvPV_nolen(obj);
+  /* Pointer values must start with leading underscore */
+  if (*c != '_') return SWIG_ERROR;
+  c++;
+  c = SWIG_UnpackData(c,ptr,sz);
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) return SWIG_ERROR;
+  }
+  return SWIG_OK;
+}
+
+
+/* Macros for low-level exception handling */
+#define SWIG_croak(x)    { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail; }
+
+
+typedef XSPROTO(SwigPerlWrapper);
+typedef SwigPerlWrapper *SwigPerlWrapperPtr;
+
+/* Structure for command table */
+typedef struct {
+  const char         *name;
+  SwigPerlWrapperPtr  wrapper;
+} swig_command_info;
+
+/* Information for constant table */
+
+#define SWIG_INT     1
+#define SWIG_FLOAT   2
+#define SWIG_STRING  3
+#define SWIG_POINTER 4
+#define SWIG_BINARY  5
+
+/* Constant information structure */
+typedef struct swig_constant_info {
+    int              type;
+    const char      *name;
+    long             lvalue;
+    double           dvalue;
+    void            *pvalue;
+    swig_type_info **ptype;
+} swig_constant_info;
+
+
+/* Structure for variable table */
+typedef struct {
+  const char   *name;
+  SwigMagicFunc   set;
+  SwigMagicFunc   get;
+  swig_type_info  **type;
+} swig_variable_info;
+
+/* Magic variable code */
+#ifndef PERL_OBJECT
+#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c)
+  #ifndef MULTIPLICITY
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) 
+  #else
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) 
+  #endif
+#else
+#  define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c)
+SWIGRUNTIME void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) 
+#endif
+{
+  MAGIC *mg;
+  sv_magic(sv,sv,'U',(char *) name,strlen(name));
+  mg = mg_find(sv,'U');
+  mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
+  mg->mg_virtual->svt_get = (SwigMagicFunc) get;
+  mg->mg_virtual->svt_set = (SwigMagicFunc) set;
+  mg->mg_virtual->svt_len = 0;
+  mg->mg_virtual->svt_clear = 0;
+  mg->mg_virtual->svt_free = 0;
+}
+
+
+SWIGRUNTIME swig_module_info *
+SWIG_Perl_GetModule(void) {
+  static void *type_pointer = (void *)0;
+  SV *pointer;
+
+  /* first check if pointer already created */
+  if (!type_pointer) {
+    pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE);
+    if (pointer && SvOK(pointer)) {
+      type_pointer = INT2PTR(swig_type_info **, SvIV(pointer));
+    }
+  }
+
+  return (swig_module_info *) type_pointer;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_SetModule(swig_module_info *module) {
+  SV *pointer;
+
+  /* create a new pointer */
+  pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE);
+  sv_setiv(pointer, PTR2IV(module));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Workaround perl5 global namespace pollution. Note that undefining library
+ * functions like fopen will not solve the problem on all platforms as fopen
+ * might be a macro on Windows but not necessarily on other operating systems. */
+#ifdef do_open
+  #undef do_open
+#endif
+#ifdef do_close
+  #undef do_close
+#endif
+#ifdef scalar
+  #undef scalar
+#endif
+#ifdef list
+  #undef list
+#endif
+#ifdef apply
+  #undef apply
+#endif
+#ifdef convert
+  #undef convert
+#endif
+#ifdef Error
+  #undef Error
+#endif
+#ifdef form
+  #undef form
+#endif
+#ifdef vform
+  #undef vform
+#endif
+#ifdef LABEL
+  #undef LABEL
+#endif
+#ifdef METHOD
+  #undef METHOD
+#endif
+#ifdef Move
+  #undef Move
+#endif
+#ifdef yylex
+  #undef yylex
+#endif
+#ifdef yyparse
+  #undef yyparse
+#endif
+#ifdef yyerror
+  #undef yyerror
+#endif
+#ifdef invert
+  #undef invert
+#endif
+#ifdef ref
+  #undef ref
+#endif
+#ifdef read
+  #undef read
+#endif
+#ifdef write
+  #undef write
+#endif
+#ifdef eof
+  #undef eof
+#endif
+#ifdef bool
+  #undef bool
+#endif
+#ifdef close
+  #undef close
+#endif
+#ifdef rewind
+  #undef rewind
+#endif
+#ifdef free
+  #undef free
+#endif
+#ifdef malloc
+  #undef malloc
+#endif
+#ifdef calloc
+  #undef calloc
+#endif
+#ifdef Stat
+  #undef Stat
+#endif
+#ifdef check
+  #undef check
+#endif
+#ifdef seekdir
+  #undef seekdir
+#endif
+#ifdef open
+  #undef open
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) 
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else 
+
+
+
+  #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) 
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_Device swig_types[0]
+#define SWIGTYPE_p_DevicePropertyBase swig_types[1]
+#define SWIGTYPE_p_GValue swig_types[2]
+#define SWIGTYPE_p_a_STRMAX__char swig_types[3]
+#define SWIGTYPE_p_char swig_types[4]
+#define SWIGTYPE_p_double swig_types[5]
+#define SWIGTYPE_p_dumpfile_t swig_types[6]
+#define SWIGTYPE_p_float swig_types[7]
+#define SWIGTYPE_p_guint swig_types[8]
+#define SWIGTYPE_p_guint64 swig_types[9]
+#define SWIGTYPE_p_int swig_types[10]
+#define SWIGTYPE_p_unsigned_char swig_types[11]
+static swig_type_info *swig_types[13];
+static swig_module_info swig_module = {swig_types, 12, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init    boot_Amanda__Device
+
+#define SWIG_name   "Amanda::Devicec::boot_Amanda__Device"
+#define SWIG_prefix "Amanda::Devicec::"
+
+#define SWIGVERSION 0x010333 
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a)) 
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) 
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifndef PERL_OBJECT
+#ifndef MULTIPLICITY
+SWIGEXPORT void SWIG_init (CV* cv);
+#else
+SWIGEXPORT void SWIG_init (pTHXo_ CV* cv);
+#endif
+#else
+SWIGEXPORT void SWIG_init (CV *cv, CPerlObj *);
+#endif
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "device.h"
+#include "property.h"
+#include "fileheader.h"
+
+
+
+/* Utility functions for typemaps, below */
+
+static SV *
+set_sv_from_gvalue(GValue *value)
+{
+    GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
+    SV *sv = NULL;
+
+    /* complex reference types */
+    switch (fundamental) {
+       case G_TYPE_LONG:
+           sv = sv_2mortal(amglue_newSVi64(g_value_get_long(value)));
+           break;
+
+       case G_TYPE_ULONG:
+           sv = sv_2mortal(amglue_newSVu64(g_value_get_ulong(value)));
+           break;
+
+       case G_TYPE_INT64:
+           sv = sv_2mortal(amglue_newSVi64(g_value_get_int64(value)));
+           break;
+
+       case G_TYPE_UINT64:
+           sv = sv_2mortal(amglue_newSVu64(g_value_get_uint64(value)));
+           break;
+
+       case G_TYPE_BOXED: {
+           GType boxed_type = G_VALUE_TYPE(value);
+           QualifiedSize qs;
+           HV *hv;
+
+           if (boxed_type == QUALIFIED_SIZE_TYPE) {
+               qs = *(QualifiedSize*)(g_value_get_boxed(value));
+               
+               /* build a hash */
+               hv = (HV *)sv_2mortal((SV *)newHV());
+               hv_store(hv, "accuracy", 8, newSViv(qs.accuracy), 0);
+               hv_store(hv, "bytes", 5, amglue_newSVi64(qs.bytes), 0);
+
+               sv = newRV((SV *)hv);
+               return newRV((SV *)hv);
+           } else {
+               warn("Unsupported boxed property type #%d", boxed_type);
+
+               sv = sv_newmortal();
+               sv_setsv(sv, &PL_sv_undef);
+               return sv;
+           }
+       }
+    }
+
+    /* simple types that can be constructed with sv_set*v */
+    sv = sv_newmortal();
+    switch (fundamental) {
+       case G_TYPE_CHAR:
+           sv_setiv(sv, g_value_get_char(value));
+           break;
+
+       case G_TYPE_UCHAR:
+           sv_setuv(sv, g_value_get_uchar(value));
+           break;
+
+       case G_TYPE_BOOLEAN:
+           sv_setiv(sv, g_value_get_boolean(value));
+           break;
+
+       case G_TYPE_INT:
+           sv_setiv(sv, g_value_get_int(value));
+           break;
+
+       case G_TYPE_UINT:
+           sv_setuv(sv, g_value_get_uint(value));
+           break;
+
+       case G_TYPE_FLOAT:
+           sv_setnv(sv, g_value_get_float(value));
+           break;
+
+       case G_TYPE_DOUBLE:
+           sv_setnv(sv, g_value_get_double(value));
+           break;
+
+       case G_TYPE_STRING:
+           sv_setpv(sv, g_value_get_string(value));
+           break;
+
+       case G_TYPE_ENUM:
+           sv_setiv(sv, g_value_get_enum(value));
+           break;
+
+       case G_TYPE_FLAGS:
+           sv_setiv(sv, g_value_get_flags(value));
+           break;
+
+       /* Unsupported */
+       default:
+       case G_TYPE_POINTER:
+       case G_TYPE_INTERFACE:
+       case G_TYPE_OBJECT:
+       case G_TYPE_PARAM:
+           warn("Unsupported fundamental property type #%d", fundamental);
+           sv_setsv(sv, &PL_sv_undef);
+           break;
+    }
+
+    return sv;
+}
+
+static gboolean
+set_gvalue_from_sv(SV *sv, GValue *value)
+{
+    GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
+    switch (fundamental) {
+       case G_TYPE_CHAR:
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_char(value, SvIV(sv));
+           break;
+
+       case G_TYPE_UCHAR:
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_uchar(value, SvUV(sv));
+           break;
+
+       case G_TYPE_BOOLEAN:
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_boolean(value, SvIV(sv));
+           break;
+
+       case G_TYPE_INT:
+           g_value_set_int(value, amglue_SvI32(sv));
+           break;
+
+       case G_TYPE_UINT:
+           g_value_set_uint(value, amglue_SvU32(sv));
+           break;
+
+       case G_TYPE_LONG:
+           g_value_set_int64(value, amglue_SvI64(sv));
+           break;
+
+       case G_TYPE_ULONG:
+           g_value_set_uint64(value, amglue_SvU64(sv));
+           break;
+
+       case G_TYPE_INT64:
+           g_value_set_int64(value, amglue_SvI64(sv));
+           break;
+
+       case G_TYPE_UINT64:
+           g_value_set_uint64(value, amglue_SvU64(sv));
+           break;
+
+       case G_TYPE_FLOAT:
+           if (!SvNOK(sv)) return FALSE;
+           g_value_set_float(value, SvNV(sv));
+           break;
+
+       case G_TYPE_DOUBLE:
+           if (!SvNOK(sv)) return FALSE;
+           g_value_set_double(value, SvNV(sv));
+           break;
+
+       case G_TYPE_STRING:
+           if (!SvPOK(sv)) return FALSE;
+           g_value_set_string(value, SvPV_nolen(sv));
+           break;
+
+       case G_TYPE_ENUM: 
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_enum(value, SvIV(sv));
+           break;
+
+       case G_TYPE_FLAGS:
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_flags(value, SvIV(sv));
+           break;
+
+       /* Unsupported */
+       default:
+       case G_TYPE_POINTER:
+       case G_TYPE_INTERFACE:
+       case G_TYPE_BOXED: /* note: *getting* boxed values is supported */
+       case G_TYPE_OBJECT:
+       case G_TYPE_PARAM:
+           return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+
+SWIGINTERNINLINE SV *
+SWIG_FromCharPtrAndSize(const char* carray, size_t size)
+{
+  SV *obj = sv_newmortal();
+  if (carray) {
+    sv_setpvn(obj, carray, size);
+  } else {
+    sv_setsv(obj, &PL_sv_undef);
+  }
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV * 
+SWIG_FromCharPtr(const char *cptr)
+{ 
+  return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0));
+}
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+  static int init = 0;
+  static swig_type_info* info = 0;
+  if (!init) {
+    info = SWIG_TypeQuery("_p_char");
+    init = 1;
+  }
+  return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(SV *obj, char** cptr, size_t* psize, int *alloc)
+{
+  if (SvPOK(obj)) {
+    STRLEN len = 0;
+    char *cstr = SvPV(obj, len); 
+    size_t size = len + 1;
+    if (cptr)  {
+      if (alloc) {
+       if (*alloc == SWIG_NEWOBJ) {
+         *cptr = (char *)memcpy((char *)malloc((size)*sizeof(char)), cstr, sizeof(char)*(size));
+       } else {
+         *cptr = cstr;
+         *alloc = SWIG_OLDOBJ;
+       }
+      }
+    }
+    if (psize) *psize = size;
+    return SWIG_OK;
+  } else {
+    swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+    if (pchar_descriptor) {
+      char* vptr = 0; 
+      if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_descriptor, 0) == SWIG_OK) {
+       if (cptr) *cptr = vptr;
+       if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0;
+       if (alloc) *alloc = SWIG_OLDOBJ;
+       return SWIG_OK;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+
+
+SWIGINTERN Device *new_Device(char *device_name){
+           return device_open(device_name);
+       }
+SWIGINTERN void delete_Device(Device *self){
+           g_object_unref(self);
+       }
+SWIGINTERN ReadLabelStatusFlags Device_read_label(Device *self){
+           return device_read_label(self);
+       }
+
+#include <limits.h>
+#if !defined(SWIG_NO_LLONG_MAX)
+# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__)
+#   define LLONG_MAX __LONG_LONG_MAX__
+#   define LLONG_MIN (-LLONG_MAX - 1LL)
+#   define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+# endif
+#endif
+
+
+SWIGINTERN int
+SWIG_AsVal_double SWIG_PERL_DECL_ARGS_2(SV *obj, double *val)
+{
+  if (SvNIOK(obj)) {
+    if (val) *val = SvNV(obj);
+    return SWIG_OK;
+  } else if (SvIOK(obj)) {
+    if (val) *val = (double) SvIV(obj);
+    return SWIG_AddCast(SWIG_OK);
+  } else {
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      double v = strtod(nptr, &endptr);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+#include <float.h>
+
+
+#include <math.h>
+
+
+SWIGINTERNINLINE int
+SWIG_CanCastAsInteger(double *d, double min, double max) {
+  double x = *d;
+  if ((min <= x && x <= max)) {
+   double fx = floor(x);
+   double cx = ceil(x);
+   double rd =  ((x - fx) < 0.5) ? fx : cx; /* simple rint */
+   if ((errno == EDOM) || (errno == ERANGE)) {
+     errno = 0;
+   } else {
+     double summ, reps, diff;
+     if (rd < x) {
+       diff = x - rd;
+     } else if (rd > x) {
+       diff = rd - x;
+     } else {
+       return 1;
+     }
+     summ = rd + x;
+     reps = diff/summ;
+     if (reps < 8*DBL_EPSILON) {
+       *d = rd;
+       return 1;
+     }
+   }
+  }
+  return 0;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_long SWIG_PERL_DECL_ARGS_2(SV *obj, long* val)
+{
+  if (SvIOK(obj)) {
+    if (val) *val = SvIV(obj);
+    return SWIG_OK;
+  } else {
+    int dispatch = 0;
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      long v;
+      errno = 0;
+      v = strtol(nptr, &endptr,0);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+    if (!dispatch) {
+      double d;
+      int res = SWIG_AddCast(SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj,&d));
+      if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
+       if (val) *val = (long)(d);
+       return res;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_int SWIG_PERL_DECL_ARGS_2(SV * obj, int *val)
+{
+  long v;
+  int res = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v < INT_MIN || v > INT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = (int)(v);
+    }
+  }  
+  return res;
+}
+
+SWIGINTERN gboolean Device_start(Device *self,DeviceAccessMode mode,char *label,char *timestamp){
+           return device_start(self, mode, label, timestamp);
+       }
+SWIGINTERN gboolean Device_finish(Device *self){
+           return device_finish(self);
+       }
+SWIGINTERN gboolean Device_start_file(Device *self,dumpfile_t const *jobInfo){
+           return device_start_file(self, jobInfo);
+       }
+SWIGINTERN guint Device_write_min_size(Device *self){
+           return device_write_min_size(self);
+       }
+SWIGINTERN guint Device_write_max_size(Device *self){
+           return device_write_max_size(self);
+       }
+SWIGINTERN guint Device_read_max_size(Device *self){
+           return device_read_max_size(self);
+       }
+SWIGINTERN gboolean Device_write_block(Device *self,guint size,gpointer data,gboolean short_block){
+           return device_write_block(self, size, data, short_block);
+       }
+SWIGINTERN gboolean Device_write_from_fd(Device *self,int fd){
+           return device_write_from_fd(self, fd);
+       }
+SWIGINTERN gboolean Device_finish_file(Device *self){
+           return device_finish_file(self);
+       }
+SWIGINTERN dumpfile_t *Device_seek_file(Device *self,guint file){
+           return device_seek_file(self, file);
+       }
+SWIGINTERN gboolean Device_seek_block(Device *self,guint64 block){
+           return device_seek_block(self, block);
+       }
+SWIGINTERN int Device_read_block(Device *self,gpointer buffer,int *size){
+           return device_read_block(self, buffer, size);
+       }
+SWIGINTERN gboolean Device_read_to_fd(Device *self,int fd){
+           return device_read_to_fd(self, fd);
+       }
+SWIGINTERN DeviceProperty const *Device_property_list(Device *self){
+           return device_property_get_list(self);
+       }
+SWIGINTERN void Device_property_get(Device *self,DevicePropertyBase *pbase,GValue *out_val,gboolean *val_found){
+           *val_found = device_property_get(self, pbase->ID, out_val);
+       }
+SWIGINTERN gboolean Device_property_set(Device *self,DevicePropertyBase *pbase,SV *sv){
+           GValue gval;
+           memset(&gval, 0, sizeof(gval));
+           g_value_init(&gval, pbase->type);
+           if (!set_gvalue_from_sv(sv, &gval))
+               goto fail;
+
+           if (!device_property_set(self, pbase->ID, &gval))
+               goto fail;
+
+           g_value_unset(&gval);
+           return TRUE;
+       fail:
+           g_value_unset(&gval);
+           return FALSE;
+       }
+SWIGINTERN gboolean Device_recycle_file(Device *self,guint filenum){
+           return device_recycle_file(self, filenum);
+       }
+SWIGINTERN void Device_set_startup_properties_from_config(Device *self){
+           device_set_startup_properties_from_config(self);
+       }
+
+SWIGINTERNINLINE SV *
+SWIG_From_long  SWIG_PERL_DECL_ARGS_1(long value)
+{    
+  SV *obj = sv_newmortal();
+  sv_setiv(obj, (IV) value);
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_int  SWIG_PERL_DECL_ARGS_1(int value)
+{    
+  return SWIG_From_long  SWIG_PERL_CALL_ARGS_1(value);
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef PERL_OBJECT
+#define MAGIC_CLASS _wrap_Amanda::Device_var::
+class _wrap_Amanda::Device_var : public CPerlObj {
+public:
+#else
+#define MAGIC_CLASS
+#endif
+SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {
+    MAGIC_PPERL
+    croak("Value is read-only.");
+    return 0;
+}
+
+
+#ifdef PERL_OBJECT
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+XS(_wrap_Device_file_get) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    int result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_file_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_file_get" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (int) ((arg1)->file);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_block_get) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    guint64 result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_block_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_block_get" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result =  ((arg1)->block);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVu64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_in_file_get) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_in_file_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_in_file_get" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (gboolean) ((arg1)->in_file);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_device_name_get) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_device_name_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_device_name_get" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (char *) ((arg1)->device_name);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_access_mode_get) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    DeviceAccessMode result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_access_mode_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_access_mode_get" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (DeviceAccessMode) ((arg1)->access_mode);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_is_eof_get) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_is_eof_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_is_eof_get" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (gboolean) ((arg1)->is_eof);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_volume_label_get) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_volume_label_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_volume_label_get" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (char *) ((arg1)->volume_label);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_volume_time_get) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_volume_time_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_volume_time_get" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (char *) ((arg1)->volume_time);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_new_Device) {
+  {
+    char *arg1 = (char *) 0 ;
+    Device *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: new_Device(device_name);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Device" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (Device *)new_Device(arg1);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Device, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_delete_Device) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: delete_Device(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, SWIG_POINTER_DISOWN |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Device" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    delete_Device(arg1);
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_read_label) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    ReadLabelStatusFlags result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_read_label(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_read_label" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (ReadLabelStatusFlags)Device_read_label(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_start) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    DeviceAccessMode arg2 ;
+    char *arg3 = (char *) 0 ;
+    char *arg4 = (char *) 0 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int res3 ;
+    char *buf3 = 0 ;
+    int alloc3 = 0 ;
+    int res4 ;
+    char *buf4 = 0 ;
+    int alloc4 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 4) || (items > 4)) {
+      SWIG_croak("Usage: Device_start(self,mode,label,timestamp);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_start" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    res3 = SWIG_AsCharPtrAndSize(ST(2), &buf3, NULL, &alloc3);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Device_start" "', argument " "3"" of type '" "char *""'");
+    }
+    arg3 = (char *)(buf3);
+    res4 = SWIG_AsCharPtrAndSize(ST(3), &buf4, NULL, &alloc4);
+    if (!SWIG_IsOK(res4)) {
+      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Device_start" "', argument " "4"" of type '" "char *""'");
+    }
+    arg4 = (char *)(buf4);
+    result = (gboolean)Device_start(arg1,arg2,arg3,arg4);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
+    XSRETURN(argvi);
+  fail:
+    
+    
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_finish) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_finish(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_finish" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (gboolean)Device_finish(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_start_file) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    dumpfile_t *arg2 = (dumpfile_t *) 0 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Device_start_file(self,jobInfo);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_start_file" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Device_start_file" "', argument " "2"" of type '" "dumpfile_t const *""'"); 
+    }
+    arg2 = (dumpfile_t *)(argp2);
+    result = (gboolean)Device_start_file(arg1,(dumpfile_t const *)arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_write_min_size) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    guint result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_write_min_size(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_write_min_size" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = Device_write_min_size(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVu64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_write_max_size) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    guint result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_write_max_size(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_write_max_size" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = Device_write_max_size(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVu64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_read_max_size) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    guint result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_read_max_size(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_read_max_size" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = Device_read_max_size(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVu64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_write_block) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    guint arg2 ;
+    gpointer arg3 = (gpointer) 0 ;
+    gboolean arg4 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int res3 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 4) || (items > 4)) {
+      SWIG_croak("Usage: Device_write_block(self,size,data,short_block);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_write_block" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    {
+      if (sizeof(guint) == 1) {
+        arg2 = amglue_SvU8(ST(1));
+      } else if (sizeof(guint) == 2) {
+        arg2 = amglue_SvU16(ST(1));
+      } else if (sizeof(guint) == 4) {
+        arg2 = amglue_SvU32(ST(1));
+      } else if (sizeof(guint) == 8) {
+        arg2 = amglue_SvU64(ST(1));
+      } else {
+        croak("Unexpected guint >64 bits?"); /* should be optimized out unless sizeof(guint) > 8 */
+      }
+    }
+    res3 = SWIG_ConvertPtr(ST(2),SWIG_as_voidptrptr(&arg3), 0, 0);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Device_write_block" "', argument " "3"" of type '" "gpointer""'"); 
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg4 = amglue_SvI8(ST(3));
+      } else if (sizeof(signed int) == 2) {
+        arg4 = amglue_SvI16(ST(3));
+      } else if (sizeof(signed int) == 4) {
+        arg4 = amglue_SvI32(ST(3));
+      } else if (sizeof(signed int) == 8) {
+        arg4 = amglue_SvI64(ST(3));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)Device_write_block(arg1,arg2,arg3,arg4);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_write_from_fd) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    int arg2 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Device_write_from_fd(self,fd);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_write_from_fd" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)Device_write_from_fd(arg1,arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_finish_file) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_finish_file(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_finish_file" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (gboolean)Device_finish_file(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_seek_file) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    guint arg2 ;
+    dumpfile_t *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Device_seek_file(self,file);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_seek_file" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    {
+      if (sizeof(guint) == 1) {
+        arg2 = amglue_SvU8(ST(1));
+      } else if (sizeof(guint) == 2) {
+        arg2 = amglue_SvU16(ST(1));
+      } else if (sizeof(guint) == 4) {
+        arg2 = amglue_SvU32(ST(1));
+      } else if (sizeof(guint) == 8) {
+        arg2 = amglue_SvU64(ST(1));
+      } else {
+        croak("Unexpected guint >64 bits?"); /* should be optimized out unless sizeof(guint) > 8 */
+      }
+    }
+    result = (dumpfile_t *)Device_seek_file(arg1,arg2);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_dumpfile_t, 0 | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_seek_block) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    guint64 arg2 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Device_seek_block(self,block);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_seek_block" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    {
+      arg2 = amglue_SvU64(ST(1));
+    }
+    result = (gboolean)Device_seek_block(arg1,arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_read_block) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    gpointer arg2 = (gpointer) 0 ;
+    int *arg3 = (int *) 0 ;
+    int result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int res2 ;
+    void *argp3 = 0 ;
+    int res3 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 3) || (items > 3)) {
+      SWIG_croak("Usage: Device_read_block(self,buffer,size);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_read_block" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    res2 = SWIG_ConvertPtr(ST(1),SWIG_as_voidptrptr(&arg2), 0, 0);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Device_read_block" "', argument " "2"" of type '" "gpointer""'"); 
+    }
+    res3 = SWIG_ConvertPtr(ST(2), &argp3,SWIGTYPE_p_int, 0 |  0 );
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Device_read_block" "', argument " "3"" of type '" "int *""'"); 
+    }
+    arg3 = (int *)(argp3);
+    result = (int)Device_read_block(arg1,arg2,arg3);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_read_to_fd) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    int arg2 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Device_read_to_fd(self,fd);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_read_to_fd" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)Device_read_to_fd(arg1,arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_property_list) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    DeviceProperty *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_property_list(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_property_list" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    result = (DeviceProperty *)Device_property_list(arg1);
+    {
+      int i = 0;
+      int len = 0;
+      
+      /* Count the DeviceProperties */
+      while (result[len].base) len++;
+      EXTEND(SP, len); /* make room for return values */
+      
+      /* Note that we set ST(argvi) several times. the nature of
+            * SWIG's wrapping is such that incrementing argvi points
+            * ST(argvi) to the next location in perl's argument stack.
+                   */
+      
+      for (i = 0; i < len ; i++) {
+        ST(argvi) = sv_newmortal(); 
+        sv_setpv(ST(argvi), result[i].base->name); 
+        argvi++;
+      }; 
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_property_get) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    DevicePropertyBase *arg2 = (DevicePropertyBase *) 0 ;
+    GValue *arg3 = (GValue *) 0 ;
+    gboolean *arg4 = (gboolean *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    GValue val3 ;
+    gboolean found3 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    {
+      memset(&val3, 0, sizeof(val3));
+      arg3 = &val3;
+      arg4 = &found3;
+    }
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Device_property_get(self,pbase,val_found);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_property_get" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    {
+      char *pname = NULL;
+      
+      if (SvPOK(ST(1)))
+      pname = SvPV_nolen(ST(1));
+      
+      if (pname) arg2 = (DevicePropertyBase *)device_property_get_by_name(pname);
+      if (!pname || !arg2) {
+        SWIG_exception_fail(SWIG_ValueError, "Invalid property name");
+      }
+    }
+    Device_property_get(arg1,arg2,arg3,arg4);
+    
+    {
+      /* if the result is valid */
+      if (*arg4) {
+        /* move data from arg3 to ST(argvi), somehow */
+        ST(argvi) = set_sv_from_gvalue(arg3);
+        
+        /* free any memory for the GValue */
+        g_value_unset(arg3);
+      } else {
+        /* silently return 'undef', the sentinel for "undefined" */
+        ST(argvi) = sv_newmortal();
+        sv_setsv(ST(argvi), &PL_sv_undef);
+      }
+      argvi++;
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_property_set) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    DevicePropertyBase *arg2 = (DevicePropertyBase *) 0 ;
+    SV *arg3 = (SV *) 0 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 3) || (items > 3)) {
+      SWIG_croak("Usage: Device_property_set(self,pbase,sv);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_property_set" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    {
+      char *pname = NULL;
+      
+      if (SvPOK(ST(1)))
+      pname = SvPV_nolen(ST(1));
+      
+      if (pname) arg2 = (DevicePropertyBase *)device_property_get_by_name(pname);
+      if (!pname || !arg2) {
+        SWIG_exception_fail(SWIG_ValueError, "Invalid property name");
+      }
+    }
+    arg3 = ST(2);
+    result = (gboolean)Device_property_set(arg1,arg2,arg3);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_recycle_file) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    guint arg2 ;
+    gboolean result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Device_recycle_file(self,filenum);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_recycle_file" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    {
+      if (sizeof(guint) == 1) {
+        arg2 = amglue_SvU8(ST(1));
+      } else if (sizeof(guint) == 2) {
+        arg2 = amglue_SvU16(ST(1));
+      } else if (sizeof(guint) == 4) {
+        arg2 = amglue_SvU32(ST(1));
+      } else if (sizeof(guint) == 8) {
+        arg2 = amglue_SvU64(ST(1));
+      } else {
+        croak("Unexpected guint >64 bits?"); /* should be optimized out unless sizeof(guint) > 8 */
+      }
+    }
+    result = (gboolean)Device_recycle_file(arg1,arg2);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Device_set_startup_properties_from_config) {
+  {
+    Device *arg1 = (Device *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Device_set_startup_properties_from_config(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Device, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Device_set_startup_properties_from_config" "', argument " "1"" of type '" "Device *""'"); 
+    }
+    arg1 = (Device *)(argp1);
+    Device_set_startup_properties_from_config(arg1);
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_IS_WRITABLE_ACCESS_MODE) {
+  {
+    DeviceAccessMode arg1 ;
+    gboolean result;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: IS_WRITABLE_ACCESS_MODE(mode);");
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg1 = amglue_SvI8(ST(0));
+      } else if (sizeof(signed int) == 2) {
+        arg1 = amglue_SvI16(ST(0));
+      } else if (sizeof(signed int) == 4) {
+        arg1 = amglue_SvI32(ST(0));
+      } else if (sizeof(signed int) == 8) {
+        arg1 = amglue_SvI64(ST(0));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)IS_WRITABLE_ACCESS_MODE(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_feature_support_flags_is_valid) {
+  {
+    FeatureSupportFlags arg1 ;
+    gboolean result;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: feature_support_flags_is_valid(FeatureSupportFlags);");
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg1 = amglue_SvI8(ST(0));
+      } else if (sizeof(signed int) == 2) {
+        arg1 = amglue_SvI16(ST(0));
+      } else if (sizeof(signed int) == 4) {
+        arg1 = amglue_SvI32(ST(0));
+      } else if (sizeof(signed int) == 8) {
+        arg1 = amglue_SvI64(ST(0));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (gboolean)feature_support_flags_is_valid(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_Device = {"_p_Device", "struct Device *|Device *", 0, 0, (void*)"Amanda::Device::Device", 0};
+static swig_type_info _swigt__p_DevicePropertyBase = {"_p_DevicePropertyBase", "DevicePropertyBase *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_GValue = {"_p_GValue", "GValue *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_a_STRMAX__char = {"_p_a_STRMAX__char", "char (*)[STRMAX]|string_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_char = {"_p_char", "gchar *|char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_double = {"_p_double", "double *|gdouble *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_dumpfile_t = {"_p_dumpfile_t", "dumpfile_t *", 0, 0, (void*)"Amanda::Types::dumpfile_t", 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *|gfloat *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_guint = {"_p_guint", "guint *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_guint64 = {"_p_guint64", "guint64 *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "int *|ConcurrencyParadigm *|filetype_t *|SizeAccuracy *|StreamingRequirement *|gboolean *|DeviceAccessMode *|MediaAccessMode *|FeatureSupportFlags *|ReadLabelStatusFlags *|PropertyPhaseFlags *|PropertyAccessFlags *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "guchar *|unsigned char *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_Device,
+  &_swigt__p_DevicePropertyBase,
+  &_swigt__p_GValue,
+  &_swigt__p_a_STRMAX__char,
+  &_swigt__p_char,
+  &_swigt__p_double,
+  &_swigt__p_dumpfile_t,
+  &_swigt__p_float,
+  &_swigt__p_guint,
+  &_swigt__p_guint64,
+  &_swigt__p_int,
+  &_swigt__p_unsigned_char,
+};
+
+static swig_cast_info _swigc__p_Device[] = {  {&_swigt__p_Device, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_DevicePropertyBase[] = {  {&_swigt__p_DevicePropertyBase, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_GValue[] = {  {&_swigt__p_GValue, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_a_STRMAX__char[] = {  {&_swigt__p_a_STRMAX__char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_dumpfile_t[] = {  {&_swigt__p_dumpfile_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_guint[] = {  {&_swigt__p_guint, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_guint64[] = {  {&_swigt__p_guint64, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_char[] = {  {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_Device,
+  _swigc__p_DevicePropertyBase,
+  _swigc__p_GValue,
+  _swigc__p_a_STRMAX__char,
+  _swigc__p_char,
+  _swigc__p_double,
+  _swigc__p_dumpfile_t,
+  _swigc__p_float,
+  _swigc__p_guint,
+  _swigc__p_guint64,
+  _swigc__p_int,
+  _swigc__p_unsigned_char,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_constant_info swig_constants[] = {
+{0,0,0,0,0,0}
+};
+#ifdef __cplusplus
+}
+#endif
+static swig_variable_info swig_variables[] = {
+{0,0,0,0}
+};
+static swig_command_info swig_commands[] = {
+{"Amanda::Devicec::Device_file_get", _wrap_Device_file_get},
+{"Amanda::Devicec::Device_block_get", _wrap_Device_block_get},
+{"Amanda::Devicec::Device_in_file_get", _wrap_Device_in_file_get},
+{"Amanda::Devicec::Device_device_name_get", _wrap_Device_device_name_get},
+{"Amanda::Devicec::Device_access_mode_get", _wrap_Device_access_mode_get},
+{"Amanda::Devicec::Device_is_eof_get", _wrap_Device_is_eof_get},
+{"Amanda::Devicec::Device_volume_label_get", _wrap_Device_volume_label_get},
+{"Amanda::Devicec::Device_volume_time_get", _wrap_Device_volume_time_get},
+{"Amanda::Devicec::new_Device", _wrap_new_Device},
+{"Amanda::Devicec::delete_Device", _wrap_delete_Device},
+{"Amanda::Devicec::Device_read_label", _wrap_Device_read_label},
+{"Amanda::Devicec::Device_start", _wrap_Device_start},
+{"Amanda::Devicec::Device_finish", _wrap_Device_finish},
+{"Amanda::Devicec::Device_start_file", _wrap_Device_start_file},
+{"Amanda::Devicec::Device_write_min_size", _wrap_Device_write_min_size},
+{"Amanda::Devicec::Device_write_max_size", _wrap_Device_write_max_size},
+{"Amanda::Devicec::Device_read_max_size", _wrap_Device_read_max_size},
+{"Amanda::Devicec::Device_write_block", _wrap_Device_write_block},
+{"Amanda::Devicec::Device_write_from_fd", _wrap_Device_write_from_fd},
+{"Amanda::Devicec::Device_finish_file", _wrap_Device_finish_file},
+{"Amanda::Devicec::Device_seek_file", _wrap_Device_seek_file},
+{"Amanda::Devicec::Device_seek_block", _wrap_Device_seek_block},
+{"Amanda::Devicec::Device_read_block", _wrap_Device_read_block},
+{"Amanda::Devicec::Device_read_to_fd", _wrap_Device_read_to_fd},
+{"Amanda::Devicec::Device_property_list", _wrap_Device_property_list},
+{"Amanda::Devicec::Device_property_get", _wrap_Device_property_get},
+{"Amanda::Devicec::Device_property_set", _wrap_Device_property_set},
+{"Amanda::Devicec::Device_recycle_file", _wrap_Device_recycle_file},
+{"Amanda::Devicec::Device_set_startup_properties_from_config", _wrap_Device_set_startup_properties_from_config},
+{"Amanda::Devicec::IS_WRITABLE_ACCESS_MODE", _wrap_IS_WRITABLE_ACCESS_MODE},
+{"Amanda::Devicec::feature_support_flags_is_valid", _wrap_feature_support_flags_is_valid},
+{0,0}
+};
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic 
+ * memory is used. Also, since swig_type_info structures store pointers to 
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization. 
+ * The idea is that swig generates all the structures that are needed. 
+ * The runtime then collects these partially filled structures. 
+ * The SWIG_InitializeModule function takes these initial arrays out of 
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned staticly to an initial 
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it 
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded. 
+ * There are three cases to handle:
+ *  1) If the cast->type has already been loaded AND the type we are adding
+ *     casting info to has not been loaded (it is in this module), THEN we
+ *     replace the cast->type pointer with the type pointer that has already
+ *     been loaded.
+ *  2) If BOTH types (the one we are adding casting info to, and the 
+ *     cast->type) are loaded, THEN the cast info has already been loaded by
+ *     the previous module so we just ignore it.
+ *  3) Finally, if cast->type has not already been loaded, then we add that
+ *     swig_cast_info to the linked list (because the cast->type) pointer will
+ *     be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+  size_t i;
+  swig_module_info *module_head, *iter;
+  int found;
+  
+  clientdata = clientdata;
+  
+  /* check to see if the circular list has been setup, if not, set it up */
+  if (swig_module.next==0) {
+    /* Initialize the swig_module */
+    swig_module.type_initial = swig_type_initial;
+    swig_module.cast_initial = swig_cast_initial;
+    swig_module.next = &swig_module;
+  }
+  
+  /* Try and load any already created modules */
+  module_head = SWIG_GetModule(clientdata);
+  if (!module_head) {
+    /* This is the first module loaded for this interpreter */
+    /* so set the swig module into the interpreter */
+    SWIG_SetModule(clientdata, &swig_module);
+    module_head = &swig_module;
+  } else {
+    /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+    found=0;
+    iter=module_head;
+    do {
+      if (iter==&swig_module) {
+        found=1;
+        break;
+      }
+      iter=iter->next;
+    } while (iter!= module_head);
+    
+    /* if the is found in the list, then all is done and we may leave */
+    if (found) return;
+    /* otherwise we must add out module into the list */
+    swig_module.next = module_head->next;
+    module_head->next = &swig_module;
+  }
+  
+  /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+  printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+  for (i = 0; i < swig_module.size; ++i) {
+    swig_type_info *type = 0;
+    swig_type_info *ret;
+    swig_cast_info *cast;
+    
+#ifdef SWIGRUNTIME_DEBUG
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+    
+    /* if there is another module already loaded */
+    if (swig_module.next != &swig_module) {
+      type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+    }
+    if (type) {
+      /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+      if (swig_module.type_initial[i]->clientdata) {
+        type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+      }
+    } else {
+      type = swig_module.type_initial[i];
+    }
+    
+    /* Insert casting types */
+    cast = swig_module.cast_initial[i];
+    while (cast->type) {
+      /* Don't need to add information already in the list */
+      ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+      if (swig_module.next != &swig_module) {
+        ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+        if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+      }
+      if (ret) {
+        if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+          printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+          cast->type = ret;
+          ret = 0;
+        } else {
+          /* Check for casting already in the list */
+          swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+          if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+          if (!ocast) ret = 0;
+        }
+      }
+      
+      if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+        if (type->cast) {
+          type->cast->prev = cast;
+          cast->next = type->cast;
+        }
+        type->cast = cast;
+      }
+      cast++;
+    }
+    /* Set entry in modules->types array equal to the type */
+    swig_module.types[i] = type;
+  }
+  swig_module.types[i] = 0;
+  
+#ifdef SWIGRUNTIME_DEBUG
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+  for (i = 0; i < swig_module.size; ++i) {
+    int j = 0;
+    swig_cast_info *cast = swig_module.cast_initial[i];
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+    while (cast->type) {
+      printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+      cast++;
+      ++j;
+    }
+    printf("---- Total casts: %d\n",j);
+  }
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types.  It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+  size_t i;
+  swig_cast_info *equiv;
+  static int init_run = 0;
+  
+  if (init_run) return;
+  init_run = 1;
+  
+  for (i = 0; i < swig_module.size; i++) {
+    if (swig_module.types[i]->clientdata) {
+      equiv = swig_module.types[i]->cast;
+      while (equiv) {
+        if (!equiv->converter) {
+          if (equiv->type && !equiv->type->clientdata)
+          SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+        }
+        equiv = equiv->next;
+      }
+    }
+  }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+  /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(SWIG_init) {
+  dXSARGS;
+  int i;
+  
+  SWIG_InitializeModule(0);
+  
+  /* Install commands */
+  for (i = 0; swig_commands[i].name; i++) {
+    newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__);
+  }
+  
+  /* Install variables */
+  for (i = 0; swig_variables[i].name; i++) {
+    SV *sv;
+    sv = get_sv((char*) swig_variables[i].name, TRUE | 0x2);
+    if (swig_variables[i].type) {
+      SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0);
+    } else {
+      sv_setiv(sv,(IV) 0);
+    }
+    swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); 
+  }
+  
+  /* Install constant */
+  for (i = 0; swig_constants[i].type; i++) {
+    SV *sv;
+    sv = get_sv((char*)swig_constants[i].name, TRUE | 0x2);
+    switch(swig_constants[i].type) {
+    case SWIG_INT:
+      sv_setiv(sv, (IV) swig_constants[i].lvalue);
+      break;
+    case SWIG_FLOAT:
+      sv_setnv(sv, (double) swig_constants[i].dvalue);
+      break;
+    case SWIG_STRING:
+      sv_setpv(sv, (char *) swig_constants[i].pvalue);
+      break;
+    case SWIG_POINTER:
+      SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
+      break;
+    case SWIG_BINARY:
+      SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
+      break;
+    default:
+      break;
+    }
+    SvREADONLY_on(sv);
+  }
+  
+  
+  /* Initialize the Device API on load */
+  device_api_init();
+  
+  SWIG_TypeClientData(SWIGTYPE_p_Device, (void*) "Amanda::Device::Device");
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ACCESS_NULL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ACCESS_NULL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ACCESS_READ", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ACCESS_READ)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ACCESS_WRITE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ACCESS_WRITE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ACCESS_APPEND", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(ACCESS_APPEND)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "READ_LABEL_STATUS_SUCCESS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(READ_LABEL_STATUS_SUCCESS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "READ_LABEL_STATUS_DEVICE_MISSING", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(READ_LABEL_STATUS_DEVICE_MISSING)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "READ_LABEL_STATUS_DEVICE_ERROR", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(READ_LABEL_STATUS_DEVICE_ERROR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "READ_LABEL_STATUS_VOLUME_MISSING", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(READ_LABEL_STATUS_VOLUME_MISSING)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "READ_LABEL_STATUS_VOLUME_UNLABELED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(READ_LABEL_STATUS_VOLUME_UNLABELED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "READ_LABEL_STATUS_VOLUME_ERROR", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(READ_LABEL_STATUS_VOLUME_ERROR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "READ_LABEL_STATUS_FLAGS_MAX", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(READ_LABEL_STATUS_FLAGS_MAX)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_PHASE_BEFORE_START", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_PHASE_BEFORE_START)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_PHASE_BETWEEN_FILE_WRITE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_PHASE_BETWEEN_FILE_WRITE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_PHASE_INSIDE_FILE_WRITE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_PHASE_INSIDE_FILE_WRITE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_PHASE_BETWEEN_FILE_READ", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_PHASE_BETWEEN_FILE_READ)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_PHASE_INSIDE_FILE_READ", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_PHASE_INSIDE_FILE_READ)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_PHASE_MAX", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_PHASE_MAX)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_PHASE_MASK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_PHASE_MASK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_PHASE_SHIFT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_PHASE_SHIFT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_GET_BEFORE_START", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_GET_BEFORE_START)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_GET_BETWEEN_FILE_READ", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_GET_BETWEEN_FILE_READ)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_GET_INSIDE_FILE_READ", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_GET_INSIDE_FILE_READ)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_SET_BEFORE_START", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_SET_BEFORE_START)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_SET_BETWEEN_FILE_READ", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_SET_BETWEEN_FILE_READ)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_SET_INSIDE_FILE_READ", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_SET_INSIDE_FILE_READ)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_GET_MASK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_GET_MASK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "PROPERTY_ACCESS_SET_MASK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(PROPERTY_ACCESS_SET_MASK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CONCURRENCY_PARADIGM_EXCLUSIVE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CONCURRENCY_PARADIGM_EXCLUSIVE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CONCURRENCY_PARADIGM_SHARED_READ", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CONCURRENCY_PARADIGM_SHARED_READ)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "CONCURRENCY_PARADIGM_RANDOM_ACCESS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CONCURRENCY_PARADIGM_RANDOM_ACCESS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "STREAMING_REQUIREMENT_NONE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(STREAMING_REQUIREMENT_NONE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "STREAMING_REQUIREMENT_DESIRED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(STREAMING_REQUIREMENT_DESIRED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "STREAMING_REQUIREMENT_REQUIRED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(STREAMING_REQUIREMENT_REQUIRED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "MEDIA_ACCESS_MODE_READ_ONLY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(MEDIA_ACCESS_MODE_READ_ONLY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "MEDIA_ACCESS_MODE_WORM", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(MEDIA_ACCESS_MODE_WORM)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "MEDIA_ACCESS_MODE_READ_WRITE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(MEDIA_ACCESS_MODE_READ_WRITE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "MEDIA_ACCESS_MODE_WRITE_ONLY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(MEDIA_ACCESS_MODE_WRITE_ONLY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SIZE_ACCURACY_UNKNOWN", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(SIZE_ACCURACY_UNKNOWN)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SIZE_ACCURACY_ESTIMATE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(SIZE_ACCURACY_ESTIMATE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SIZE_ACCURACY_REAL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(SIZE_ACCURACY_REAL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_STATUS_ENABLED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_STATUS_ENABLED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_STATUS_DISABLED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_STATUS_DISABLED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SURETY_BAD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SURETY_BAD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SURETY_GOOD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SURETY_GOOD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SOURCE_DEFAULT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SOURCE_DEFAULT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SOURCE_DETECTED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SOURCE_DETECTED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SOURCE_USER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SOURCE_USER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SUPPORT_FLAGS_MAX", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SUPPORT_FLAGS_MAX)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SUPPORT_FLAGS_MASK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SUPPORT_FLAGS_MASK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SUPPORT_FLAGS_STATUS_MASK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SUPPORT_FLAGS_STATUS_MASK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SUPPORT_FLAGS_SURETY_MASK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SUPPORT_FLAGS_SURETY_MASK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "FEATURE_SUPPORT_FLAGS_SOURCE_MASK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(FEATURE_SUPPORT_FLAGS_SOURCE_MASK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  ST(0) = &PL_sv_yes;
+  XSRETURN(1);
+}
+
diff --git a/perl/Amanda/Device.pm b/perl/Amanda/Device.pm
new file mode 100644 (file)
index 0000000..5549f11
--- /dev/null
@@ -0,0 +1,826 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 1.3.33
+#
+# Don't modify this file, modify the SWIG interface instead.
+
+package Amanda::Device;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+require Amanda::Types;
+package Amanda::Devicec;
+bootstrap Amanda::Device;
+package Amanda::Device;
+@EXPORT = qw( );
+
+# ---------- BASE METHODS -------------
+
+package Amanda::Device;
+
+sub TIEHASH {
+    my ($classname,$obj) = @_;
+    return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+    my ($self,$field) = @_;
+    my $member_func = "swig_${field}_get";
+    $self->$member_func();
+}
+
+sub STORE {
+    my ($self,$field,$newval) = @_;
+    my $member_func = "swig_${field}_set";
+    $self->$member_func($newval);
+}
+
+sub this {
+    my $ptr = shift;
+    return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package Amanda::Device;
+
+*IS_WRITABLE_ACCESS_MODE = *Amanda::Devicec::IS_WRITABLE_ACCESS_MODE;
+*feature_support_flags_is_valid = *Amanda::Devicec::feature_support_flags_is_valid;
+
+############# Class : Amanda::Device::Device ##############
+
+package Amanda::Device::Device;
+use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
+@ISA = qw( Amanda::Device );
+%OWNER = ();
+%ITERATORS = ();
+*swig_file_get = *Amanda::Devicec::Device_file_get;
+*swig_file_set = *Amanda::Devicec::Device_file_set;
+*swig_block_get = *Amanda::Devicec::Device_block_get;
+*swig_block_set = *Amanda::Devicec::Device_block_set;
+*swig_in_file_get = *Amanda::Devicec::Device_in_file_get;
+*swig_in_file_set = *Amanda::Devicec::Device_in_file_set;
+*swig_device_name_get = *Amanda::Devicec::Device_device_name_get;
+*swig_device_name_set = *Amanda::Devicec::Device_device_name_set;
+*swig_access_mode_get = *Amanda::Devicec::Device_access_mode_get;
+*swig_access_mode_set = *Amanda::Devicec::Device_access_mode_set;
+*swig_is_eof_get = *Amanda::Devicec::Device_is_eof_get;
+*swig_is_eof_set = *Amanda::Devicec::Device_is_eof_set;
+*swig_volume_label_get = *Amanda::Devicec::Device_volume_label_get;
+*swig_volume_label_set = *Amanda::Devicec::Device_volume_label_set;
+*swig_volume_time_get = *Amanda::Devicec::Device_volume_time_get;
+*swig_volume_time_set = *Amanda::Devicec::Device_volume_time_set;
+sub new {
+    my $pkg = shift;
+    my $self = Amanda::Devicec::new_Device(@_);
+    bless $self, $pkg if defined($self);
+}
+
+sub DESTROY {
+    return unless $_[0]->isa('HASH');
+    my $self = tied(%{$_[0]});
+    return unless defined $self;
+    delete $ITERATORS{$self};
+    if (exists $OWNER{$self}) {
+        Amanda::Devicec::delete_Device($self);
+        delete $OWNER{$self};
+    }
+}
+
+*read_label = *Amanda::Devicec::Device_read_label;
+*start = *Amanda::Devicec::Device_start;
+*finish = *Amanda::Devicec::Device_finish;
+*start_file = *Amanda::Devicec::Device_start_file;
+*write_min_size = *Amanda::Devicec::Device_write_min_size;
+*write_max_size = *Amanda::Devicec::Device_write_max_size;
+*read_max_size = *Amanda::Devicec::Device_read_max_size;
+*write_block = *Amanda::Devicec::Device_write_block;
+*write_from_fd = *Amanda::Devicec::Device_write_from_fd;
+*finish_file = *Amanda::Devicec::Device_finish_file;
+*seek_file = *Amanda::Devicec::Device_seek_file;
+*seek_block = *Amanda::Devicec::Device_seek_block;
+*read_block = *Amanda::Devicec::Device_read_block;
+*read_to_fd = *Amanda::Devicec::Device_read_to_fd;
+*property_list = *Amanda::Devicec::Device_property_list;
+*property_get = *Amanda::Devicec::Device_property_get;
+*property_set = *Amanda::Devicec::Device_property_set;
+*recycle_file = *Amanda::Devicec::Device_recycle_file;
+*set_startup_properties_from_config = *Amanda::Devicec::Device_set_startup_properties_from_config;
+sub DISOWN {
+    my $self = shift;
+    my $ptr = tied(%$self);
+    delete $OWNER{$ptr};
+}
+
+sub ACQUIRE {
+    my $self = shift;
+    my $ptr = tied(%$self);
+    $OWNER{$ptr} = 1;
+}
+
+
+# ------- VARIABLE STUBS --------
+
+package Amanda::Device;
+
+*ACCESS_NULL = *Amanda::Devicec::ACCESS_NULL;
+*ACCESS_READ = *Amanda::Devicec::ACCESS_READ;
+*ACCESS_WRITE = *Amanda::Devicec::ACCESS_WRITE;
+*ACCESS_APPEND = *Amanda::Devicec::ACCESS_APPEND;
+*READ_LABEL_STATUS_SUCCESS = *Amanda::Devicec::READ_LABEL_STATUS_SUCCESS;
+*READ_LABEL_STATUS_DEVICE_MISSING = *Amanda::Devicec::READ_LABEL_STATUS_DEVICE_MISSING;
+*READ_LABEL_STATUS_DEVICE_ERROR = *Amanda::Devicec::READ_LABEL_STATUS_DEVICE_ERROR;
+*READ_LABEL_STATUS_VOLUME_MISSING = *Amanda::Devicec::READ_LABEL_STATUS_VOLUME_MISSING;
+*READ_LABEL_STATUS_VOLUME_UNLABELED = *Amanda::Devicec::READ_LABEL_STATUS_VOLUME_UNLABELED;
+*READ_LABEL_STATUS_VOLUME_ERROR = *Amanda::Devicec::READ_LABEL_STATUS_VOLUME_ERROR;
+*READ_LABEL_STATUS_FLAGS_MAX = *Amanda::Devicec::READ_LABEL_STATUS_FLAGS_MAX;
+*PROPERTY_PHASE_BEFORE_START = *Amanda::Devicec::PROPERTY_PHASE_BEFORE_START;
+*PROPERTY_PHASE_BETWEEN_FILE_WRITE = *Amanda::Devicec::PROPERTY_PHASE_BETWEEN_FILE_WRITE;
+*PROPERTY_PHASE_INSIDE_FILE_WRITE = *Amanda::Devicec::PROPERTY_PHASE_INSIDE_FILE_WRITE;
+*PROPERTY_PHASE_BETWEEN_FILE_READ = *Amanda::Devicec::PROPERTY_PHASE_BETWEEN_FILE_READ;
+*PROPERTY_PHASE_INSIDE_FILE_READ = *Amanda::Devicec::PROPERTY_PHASE_INSIDE_FILE_READ;
+*PROPERTY_PHASE_MAX = *Amanda::Devicec::PROPERTY_PHASE_MAX;
+*PROPERTY_PHASE_MASK = *Amanda::Devicec::PROPERTY_PHASE_MASK;
+*PROPERTY_PHASE_SHIFT = *Amanda::Devicec::PROPERTY_PHASE_SHIFT;
+*PROPERTY_ACCESS_GET_BEFORE_START = *Amanda::Devicec::PROPERTY_ACCESS_GET_BEFORE_START;
+*PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE = *Amanda::Devicec::PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE;
+*PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE = *Amanda::Devicec::PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE;
+*PROPERTY_ACCESS_GET_BETWEEN_FILE_READ = *Amanda::Devicec::PROPERTY_ACCESS_GET_BETWEEN_FILE_READ;
+*PROPERTY_ACCESS_GET_INSIDE_FILE_READ = *Amanda::Devicec::PROPERTY_ACCESS_GET_INSIDE_FILE_READ;
+*PROPERTY_ACCESS_SET_BEFORE_START = *Amanda::Devicec::PROPERTY_ACCESS_SET_BEFORE_START;
+*PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE = *Amanda::Devicec::PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE;
+*PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE = *Amanda::Devicec::PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE;
+*PROPERTY_ACCESS_SET_BETWEEN_FILE_READ = *Amanda::Devicec::PROPERTY_ACCESS_SET_BETWEEN_FILE_READ;
+*PROPERTY_ACCESS_SET_INSIDE_FILE_READ = *Amanda::Devicec::PROPERTY_ACCESS_SET_INSIDE_FILE_READ;
+*PROPERTY_ACCESS_GET_MASK = *Amanda::Devicec::PROPERTY_ACCESS_GET_MASK;
+*PROPERTY_ACCESS_SET_MASK = *Amanda::Devicec::PROPERTY_ACCESS_SET_MASK;
+*CONCURRENCY_PARADIGM_EXCLUSIVE = *Amanda::Devicec::CONCURRENCY_PARADIGM_EXCLUSIVE;
+*CONCURRENCY_PARADIGM_SHARED_READ = *Amanda::Devicec::CONCURRENCY_PARADIGM_SHARED_READ;
+*CONCURRENCY_PARADIGM_RANDOM_ACCESS = *Amanda::Devicec::CONCURRENCY_PARADIGM_RANDOM_ACCESS;
+*STREAMING_REQUIREMENT_NONE = *Amanda::Devicec::STREAMING_REQUIREMENT_NONE;
+*STREAMING_REQUIREMENT_DESIRED = *Amanda::Devicec::STREAMING_REQUIREMENT_DESIRED;
+*STREAMING_REQUIREMENT_REQUIRED = *Amanda::Devicec::STREAMING_REQUIREMENT_REQUIRED;
+*MEDIA_ACCESS_MODE_READ_ONLY = *Amanda::Devicec::MEDIA_ACCESS_MODE_READ_ONLY;
+*MEDIA_ACCESS_MODE_WORM = *Amanda::Devicec::MEDIA_ACCESS_MODE_WORM;
+*MEDIA_ACCESS_MODE_READ_WRITE = *Amanda::Devicec::MEDIA_ACCESS_MODE_READ_WRITE;
+*MEDIA_ACCESS_MODE_WRITE_ONLY = *Amanda::Devicec::MEDIA_ACCESS_MODE_WRITE_ONLY;
+*SIZE_ACCURACY_UNKNOWN = *Amanda::Devicec::SIZE_ACCURACY_UNKNOWN;
+*SIZE_ACCURACY_ESTIMATE = *Amanda::Devicec::SIZE_ACCURACY_ESTIMATE;
+*SIZE_ACCURACY_REAL = *Amanda::Devicec::SIZE_ACCURACY_REAL;
+*FEATURE_STATUS_ENABLED = *Amanda::Devicec::FEATURE_STATUS_ENABLED;
+*FEATURE_STATUS_DISABLED = *Amanda::Devicec::FEATURE_STATUS_DISABLED;
+*FEATURE_SURETY_BAD = *Amanda::Devicec::FEATURE_SURETY_BAD;
+*FEATURE_SURETY_GOOD = *Amanda::Devicec::FEATURE_SURETY_GOOD;
+*FEATURE_SOURCE_DEFAULT = *Amanda::Devicec::FEATURE_SOURCE_DEFAULT;
+*FEATURE_SOURCE_DETECTED = *Amanda::Devicec::FEATURE_SOURCE_DETECTED;
+*FEATURE_SOURCE_USER = *Amanda::Devicec::FEATURE_SOURCE_USER;
+*FEATURE_SUPPORT_FLAGS_MAX = *Amanda::Devicec::FEATURE_SUPPORT_FLAGS_MAX;
+*FEATURE_SUPPORT_FLAGS_MASK = *Amanda::Devicec::FEATURE_SUPPORT_FLAGS_MASK;
+*FEATURE_SUPPORT_FLAGS_STATUS_MASK = *Amanda::Devicec::FEATURE_SUPPORT_FLAGS_STATUS_MASK;
+*FEATURE_SUPPORT_FLAGS_SURETY_MASK = *Amanda::Devicec::FEATURE_SUPPORT_FLAGS_SURETY_MASK;
+*FEATURE_SUPPORT_FLAGS_SOURCE_MASK = *Amanda::Devicec::FEATURE_SUPPORT_FLAGS_SOURCE_MASK;
+
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+
+=head1 NAME
+
+Amanda::Device - interact with Amanda data-storage devices
+
+=head1 SYNOPSIS
+
+  use Amanda::Device qw( :constants );
+
+  my $dev = Amanda::Device->new($device_name);
+  $dev->set_startup_properties_from_config();
+  if ($dev->read_label() == $READ_LABEL_STATUS_SUCCESS) {
+      print "Label on $device_name is '$dev->volume_label'\n";
+  }
+  
+See http://wiki.zmanda.com/index.php/Device_API for details on how Devices are used.
+
+=head1 API STATUS
+
+Stable
+
+=head1 Amanda::Device Objects
+
+=head2 Instance Variables
+
+=over
+
+=item C<$file>
+
+=item C<$block>
+
+=item C<$in_file>
+
+=item C<$device_name>
+
+=item C<$access_mode>
+
+=item C<$is_eof>
+
+=item C<$volume_label>
+
+=item C<$volume_time>
+
+=back
+
+=head2 Methods
+
+See the wiki for descriptions of these functions
+
+=over
+
+=item C<read_label()>
+
+=item C<start($mode, $label, $timestamp)>
+
+=item C<finish()>
+
+=item C<start_file($jobinfo)>
+
+where C<$jobinfo> is a C<dumpfile_t> (see L<Amanda::Datatypes>)
+
+=item C<write_min_size()>
+
+=item C<write_max_size()>
+
+=item C<read_max_size()>
+
+=item C<write_block($size, $data, $short_block)>
+
+Note that Perl code is not expected to handle on-device data, so there
+is currently no way to provide data to this function from Perl.  This may
+change in future revisions.
+
+=item C<write_from_fd($fd)>
+
+where C<$fd> is an integer file descriptor, not a filehandle
+
+=item C<finish_file()>
+
+=item C<seek_file($file)>
+
+=item C<seek_block($block)>
+
+=item C<read_block($size)>
+
+=item C<read_to_fd($fd)>
+
+where C<$fd> is an integer file descriptor, not a filehandle
+
+Note that Perl code is not expected to handle on-device data, so there
+is currently no way to access the data this function returns.  This may
+change in future revisions.
+
+=item C<property_list()>
+
+returns a list of property names.
+
+=item C<property_get($property_name)>
+
+returns the property as the appropriate Perl type.
+
+=item C<property_set($property_name, $value)>
+
+where $value is of an appropriate type for the given property
+
+=item C<recycle_file($filenum)>
+
+=item C<set_startup_properties_from_config()>
+
+=back
+
+=head1 CONSTANTS
+
+This module defines a large number of constants.  Again, consult the
+wiki or C<device.h> for the details on their meaning.  These constants
+are available from the package namespace (e.g.,
+C<Amanda::Device::ACCESS_WRITE>), of imported with the C<:constant>
+import tag.
+
+=cut
+
+push @EXPORT_OK, qw(DeviceAccessMode_to_strings);
+push @{$EXPORT_TAGS{"DeviceAccessMode"}}, qw(DeviceAccessMode_to_strings);
+
+my %_DeviceAccessMode_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub DeviceAccessMode_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_DeviceAccessMode_VALUES) {
+       my $v = $_DeviceAccessMode_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($ACCESS_NULL);
+push @{$EXPORT_TAGS{"DeviceAccessMode"}}, qw($ACCESS_NULL);
+
+$_DeviceAccessMode_VALUES{"NULL"} = $ACCESS_NULL;
+
+push @EXPORT_OK, qw($ACCESS_READ);
+push @{$EXPORT_TAGS{"DeviceAccessMode"}}, qw($ACCESS_READ);
+
+$_DeviceAccessMode_VALUES{"READ"} = $ACCESS_READ;
+
+push @EXPORT_OK, qw($ACCESS_WRITE);
+push @{$EXPORT_TAGS{"DeviceAccessMode"}}, qw($ACCESS_WRITE);
+
+$_DeviceAccessMode_VALUES{"WRITE"} = $ACCESS_WRITE;
+
+push @EXPORT_OK, qw($ACCESS_APPEND);
+push @{$EXPORT_TAGS{"DeviceAccessMode"}}, qw($ACCESS_APPEND);
+
+$_DeviceAccessMode_VALUES{"APPEND"} = $ACCESS_APPEND;
+
+push @EXPORT_OK, qw(IS_WRITABLE_ACCESS_MODE);
+push @{$EXPORT_TAGS{"DeviceAccessMode"}}, qw(IS_WRITABLE_ACCESS_MODE);
+
+#copy symbols in DeviceAccessMode to constants
+push @{$EXPORT_TAGS{"constants"}},  @{$EXPORT_TAGS{"DeviceAccessMode"}};
+
+push @EXPORT_OK, qw(ReadLabelStatusFlags_to_strings);
+push @{$EXPORT_TAGS{"ReadLabelStatusFlags"}}, qw(ReadLabelStatusFlags_to_strings);
+
+my %_ReadLabelStatusFlags_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub ReadLabelStatusFlags_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_ReadLabelStatusFlags_VALUES) {
+       my $v = $_ReadLabelStatusFlags_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($READ_LABEL_STATUS_SUCCESS);
+push @{$EXPORT_TAGS{"ReadLabelStatusFlags"}}, qw($READ_LABEL_STATUS_SUCCESS);
+
+$_ReadLabelStatusFlags_VALUES{"SUCCESS"} = $READ_LABEL_STATUS_SUCCESS;
+
+push @EXPORT_OK, qw($READ_LABEL_STATUS_DEVICE_MISSING);
+push @{$EXPORT_TAGS{"ReadLabelStatusFlags"}}, qw($READ_LABEL_STATUS_DEVICE_MISSING);
+
+$_ReadLabelStatusFlags_VALUES{"DEVICE_MISSING"} = $READ_LABEL_STATUS_DEVICE_MISSING;
+
+push @EXPORT_OK, qw($READ_LABEL_STATUS_DEVICE_ERROR);
+push @{$EXPORT_TAGS{"ReadLabelStatusFlags"}}, qw($READ_LABEL_STATUS_DEVICE_ERROR);
+
+$_ReadLabelStatusFlags_VALUES{"DEVICE_ERROR"} = $READ_LABEL_STATUS_DEVICE_ERROR;
+
+push @EXPORT_OK, qw($READ_LABEL_STATUS_VOLUME_MISSING);
+push @{$EXPORT_TAGS{"ReadLabelStatusFlags"}}, qw($READ_LABEL_STATUS_VOLUME_MISSING);
+
+$_ReadLabelStatusFlags_VALUES{"VOLUME_MISSING"} = $READ_LABEL_STATUS_VOLUME_MISSING;
+
+push @EXPORT_OK, qw($READ_LABEL_STATUS_VOLUME_UNLABELED);
+push @{$EXPORT_TAGS{"ReadLabelStatusFlags"}}, qw($READ_LABEL_STATUS_VOLUME_UNLABELED);
+
+$_ReadLabelStatusFlags_VALUES{"VOLUME_UNLABELED"} = $READ_LABEL_STATUS_VOLUME_UNLABELED;
+
+push @EXPORT_OK, qw($READ_LABEL_STATUS_VOLUME_ERROR);
+push @{$EXPORT_TAGS{"ReadLabelStatusFlags"}}, qw($READ_LABEL_STATUS_VOLUME_ERROR);
+
+$_ReadLabelStatusFlags_VALUES{"VOLUME_ERROR"} = $READ_LABEL_STATUS_VOLUME_ERROR;
+
+push @EXPORT_OK, qw($READ_LABEL_STATUS_FLAGS_MAX);
+push @{$EXPORT_TAGS{"ReadLabelStatusFlags"}}, qw($READ_LABEL_STATUS_FLAGS_MAX);
+
+#copy symbols in ReadLabelStatusFlags to constants
+push @{$EXPORT_TAGS{"constants"}},  @{$EXPORT_TAGS{"ReadLabelStatusFlags"}};
+
+push @EXPORT_OK, qw(PropertyPhaseFlags_to_strings);
+push @{$EXPORT_TAGS{"PropertyPhaseFlags"}}, qw(PropertyPhaseFlags_to_strings);
+
+my %_PropertyPhaseFlags_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub PropertyPhaseFlags_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_PropertyPhaseFlags_VALUES) {
+       my $v = $_PropertyPhaseFlags_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($PROPERTY_PHASE_BEFORE_START);
+push @{$EXPORT_TAGS{"PropertyPhaseFlags"}}, qw($PROPERTY_PHASE_BEFORE_START);
+
+$_PropertyPhaseFlags_VALUES{"BEFORE_START"} = $PROPERTY_PHASE_BEFORE_START;
+
+push @EXPORT_OK, qw($PROPERTY_PHASE_BETWEEN_FILE_WRITE);
+push @{$EXPORT_TAGS{"PropertyPhaseFlags"}}, qw($PROPERTY_PHASE_BETWEEN_FILE_WRITE);
+
+$_PropertyPhaseFlags_VALUES{"BETWEEN_FILE_WRITE"} = $PROPERTY_PHASE_BETWEEN_FILE_WRITE;
+
+push @EXPORT_OK, qw($PROPERTY_PHASE_INSIDE_FILE_WRITE);
+push @{$EXPORT_TAGS{"PropertyPhaseFlags"}}, qw($PROPERTY_PHASE_INSIDE_FILE_WRITE);
+
+$_PropertyPhaseFlags_VALUES{"INSIDE_FILE_WRITE"} = $PROPERTY_PHASE_INSIDE_FILE_WRITE;
+
+push @EXPORT_OK, qw($PROPERTY_PHASE_BETWEEN_FILE_READ);
+push @{$EXPORT_TAGS{"PropertyPhaseFlags"}}, qw($PROPERTY_PHASE_BETWEEN_FILE_READ);
+
+$_PropertyPhaseFlags_VALUES{"BETWEEN_FILE_READ"} = $PROPERTY_PHASE_BETWEEN_FILE_READ;
+
+push @EXPORT_OK, qw($PROPERTY_PHASE_INSIDE_FILE_READ);
+push @{$EXPORT_TAGS{"PropertyPhaseFlags"}}, qw($PROPERTY_PHASE_INSIDE_FILE_READ);
+
+$_PropertyPhaseFlags_VALUES{"INSIDE_FILE_READ"} = $PROPERTY_PHASE_INSIDE_FILE_READ;
+
+push @EXPORT_OK, qw($PROPERTY_PHASE_MAX);
+push @{$EXPORT_TAGS{"PropertyPhaseFlags"}}, qw($PROPERTY_PHASE_MAX);
+
+push @EXPORT_OK, qw($PROPERTY_PHASE_MASK);
+push @{$EXPORT_TAGS{"PropertyPhaseFlags"}}, qw($PROPERTY_PHASE_MASK);
+
+push @EXPORT_OK, qw($PROPERTY_PHASE_SHIFT);
+push @{$EXPORT_TAGS{"PropertyPhaseFlags"}}, qw($PROPERTY_PHASE_SHIFT);
+
+#copy symbols in PropertyPhaseFlags to constants
+push @{$EXPORT_TAGS{"constants"}},  @{$EXPORT_TAGS{"PropertyPhaseFlags"}};
+
+push @EXPORT_OK, qw(PropertyAccessFlags_to_strings);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw(PropertyAccessFlags_to_strings);
+
+my %_PropertyAccessFlags_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub PropertyAccessFlags_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_PropertyAccessFlags_VALUES) {
+       my $v = $_PropertyAccessFlags_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_GET_BEFORE_START);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_GET_BEFORE_START);
+
+$_PropertyAccessFlags_VALUES{"GET_BEFORE_START"} = $PROPERTY_ACCESS_GET_BEFORE_START;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE);
+
+$_PropertyAccessFlags_VALUES{"GET_BETWEEN_FILE_WRITE"} = $PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE);
+
+$_PropertyAccessFlags_VALUES{"GET_INSIDE_FILE_WRITE"} = $PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_GET_BETWEEN_FILE_READ);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_GET_BETWEEN_FILE_READ);
+
+$_PropertyAccessFlags_VALUES{"GET_BETWEEN_FILE_READ"} = $PROPERTY_ACCESS_GET_BETWEEN_FILE_READ;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_GET_INSIDE_FILE_READ);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_GET_INSIDE_FILE_READ);
+
+$_PropertyAccessFlags_VALUES{"GET_INSIDE_FILE_READ"} = $PROPERTY_ACCESS_GET_INSIDE_FILE_READ;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_SET_BEFORE_START);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_SET_BEFORE_START);
+
+$_PropertyAccessFlags_VALUES{"SET_BEFORE_START"} = $PROPERTY_ACCESS_SET_BEFORE_START;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE);
+
+$_PropertyAccessFlags_VALUES{"SET_BETWEEN_FILE_WRITE"} = $PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE);
+
+$_PropertyAccessFlags_VALUES{"SET_INSIDE_FILE_WRITE"} = $PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_SET_BETWEEN_FILE_READ);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_SET_BETWEEN_FILE_READ);
+
+$_PropertyAccessFlags_VALUES{"SET_BETWEEN_FILE_READ"} = $PROPERTY_ACCESS_SET_BETWEEN_FILE_READ;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_SET_INSIDE_FILE_READ);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_SET_INSIDE_FILE_READ);
+
+$_PropertyAccessFlags_VALUES{"SET_INSIDE_FILE_READ"} = $PROPERTY_ACCESS_SET_INSIDE_FILE_READ;
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_GET_MASK);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_GET_MASK);
+
+push @EXPORT_OK, qw($PROPERTY_ACCESS_SET_MASK);
+push @{$EXPORT_TAGS{"PropertyAccessFlags"}}, qw($PROPERTY_ACCESS_SET_MASK);
+
+#copy symbols in PropertyAccessFlags to constants
+push @{$EXPORT_TAGS{"constants"}},  @{$EXPORT_TAGS{"PropertyAccessFlags"}};
+
+push @EXPORT_OK, qw(ConcurrencyParadigm_to_string);
+push @{$EXPORT_TAGS{"ConcurrencyParadigm"}}, qw(ConcurrencyParadigm_to_string);
+
+my %_ConcurrencyParadigm_VALUES;
+#Convert an enum value to a single string
+sub ConcurrencyParadigm_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_ConcurrencyParadigm_VALUES) {
+       my $v = $_ConcurrencyParadigm_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($CONCURRENCY_PARADIGM_EXCLUSIVE);
+push @{$EXPORT_TAGS{"ConcurrencyParadigm"}}, qw($CONCURRENCY_PARADIGM_EXCLUSIVE);
+
+$_ConcurrencyParadigm_VALUES{"EXCLUSIVE"} = $CONCURRENCY_PARADIGM_EXCLUSIVE;
+
+push @EXPORT_OK, qw($CONCURRENCY_PARADIGM_SHARED_READ);
+push @{$EXPORT_TAGS{"ConcurrencyParadigm"}}, qw($CONCURRENCY_PARADIGM_SHARED_READ);
+
+$_ConcurrencyParadigm_VALUES{"SHARED_READ"} = $CONCURRENCY_PARADIGM_SHARED_READ;
+
+push @EXPORT_OK, qw($CONCURRENCY_PARADIGM_RANDOM_ACCESS);
+push @{$EXPORT_TAGS{"ConcurrencyParadigm"}}, qw($CONCURRENCY_PARADIGM_RANDOM_ACCESS);
+
+$_ConcurrencyParadigm_VALUES{"RANDOM_ACCESS"} = $CONCURRENCY_PARADIGM_RANDOM_ACCESS;
+
+#copy symbols in ConcurrencyParadigm to constants
+push @{$EXPORT_TAGS{"constants"}},  @{$EXPORT_TAGS{"ConcurrencyParadigm"}};
+
+push @EXPORT_OK, qw(StreamingRequirement_to_string);
+push @{$EXPORT_TAGS{"StreamingRequirement"}}, qw(StreamingRequirement_to_string);
+
+my %_StreamingRequirement_VALUES;
+#Convert an enum value to a single string
+sub StreamingRequirement_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_StreamingRequirement_VALUES) {
+       my $v = $_StreamingRequirement_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($STREAMING_REQUIREMENT_NONE);
+push @{$EXPORT_TAGS{"StreamingRequirement"}}, qw($STREAMING_REQUIREMENT_NONE);
+
+$_StreamingRequirement_VALUES{"NONE"} = $STREAMING_REQUIREMENT_NONE;
+
+push @EXPORT_OK, qw($STREAMING_REQUIREMENT_DESIRED);
+push @{$EXPORT_TAGS{"StreamingRequirement"}}, qw($STREAMING_REQUIREMENT_DESIRED);
+
+$_StreamingRequirement_VALUES{"DESIRED"} = $STREAMING_REQUIREMENT_DESIRED;
+
+push @EXPORT_OK, qw($STREAMING_REQUIREMENT_REQUIRED);
+push @{$EXPORT_TAGS{"StreamingRequirement"}}, qw($STREAMING_REQUIREMENT_REQUIRED);
+
+$_StreamingRequirement_VALUES{"REQUIRED"} = $STREAMING_REQUIREMENT_REQUIRED;
+
+#copy symbols in StreamingRequirement to constants
+push @{$EXPORT_TAGS{"constants"}},  @{$EXPORT_TAGS{"StreamingRequirement"}};
+
+push @EXPORT_OK, qw(MediaAccessMode_to_string);
+push @{$EXPORT_TAGS{"MediaAccessMode"}}, qw(MediaAccessMode_to_string);
+
+my %_MediaAccessMode_VALUES;
+#Convert an enum value to a single string
+sub MediaAccessMode_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_MediaAccessMode_VALUES) {
+       my $v = $_MediaAccessMode_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($MEDIA_ACCESS_MODE_READ_ONLY);
+push @{$EXPORT_TAGS{"MediaAccessMode"}}, qw($MEDIA_ACCESS_MODE_READ_ONLY);
+
+$_MediaAccessMode_VALUES{"READ_ONLY"} = $MEDIA_ACCESS_MODE_READ_ONLY;
+
+push @EXPORT_OK, qw($MEDIA_ACCESS_MODE_WORM);
+push @{$EXPORT_TAGS{"MediaAccessMode"}}, qw($MEDIA_ACCESS_MODE_WORM);
+
+$_MediaAccessMode_VALUES{"WORM"} = $MEDIA_ACCESS_MODE_WORM;
+
+push @EXPORT_OK, qw($MEDIA_ACCESS_MODE_READ_WRITE);
+push @{$EXPORT_TAGS{"MediaAccessMode"}}, qw($MEDIA_ACCESS_MODE_READ_WRITE);
+
+$_MediaAccessMode_VALUES{"READ_WRITE"} = $MEDIA_ACCESS_MODE_READ_WRITE;
+
+push @EXPORT_OK, qw($MEDIA_ACCESS_MODE_WRITE_ONLY);
+push @{$EXPORT_TAGS{"MediaAccessMode"}}, qw($MEDIA_ACCESS_MODE_WRITE_ONLY);
+
+$_MediaAccessMode_VALUES{"WRITE_ONLY"} = $MEDIA_ACCESS_MODE_WRITE_ONLY;
+
+#copy symbols in MediaAccessMode to constants
+push @{$EXPORT_TAGS{"constants"}},  @{$EXPORT_TAGS{"MediaAccessMode"}};
+
+push @EXPORT_OK, qw(SizeAccuracy_to_string);
+push @{$EXPORT_TAGS{"SizeAccuracy"}}, qw(SizeAccuracy_to_string);
+
+my %_SizeAccuracy_VALUES;
+#Convert an enum value to a single string
+sub SizeAccuracy_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_SizeAccuracy_VALUES) {
+       my $v = $_SizeAccuracy_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($SIZE_ACCURACY_UNKNOWN);
+push @{$EXPORT_TAGS{"SizeAccuracy"}}, qw($SIZE_ACCURACY_UNKNOWN);
+
+$_SizeAccuracy_VALUES{"UNKNOWN"} = $SIZE_ACCURACY_UNKNOWN;
+
+push @EXPORT_OK, qw($SIZE_ACCURACY_ESTIMATE);
+push @{$EXPORT_TAGS{"SizeAccuracy"}}, qw($SIZE_ACCURACY_ESTIMATE);
+
+$_SizeAccuracy_VALUES{"ESTIMATE"} = $SIZE_ACCURACY_ESTIMATE;
+
+push @EXPORT_OK, qw($SIZE_ACCURACY_REAL);
+push @{$EXPORT_TAGS{"SizeAccuracy"}}, qw($SIZE_ACCURACY_REAL);
+
+$_SizeAccuracy_VALUES{"REAL"} = $SIZE_ACCURACY_REAL;
+
+#copy symbols in SizeAccuracy to constants
+push @{$EXPORT_TAGS{"constants"}},  @{$EXPORT_TAGS{"SizeAccuracy"}};
+
+push @EXPORT_OK, qw(FeatureSupportFlags_to_strings);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw(FeatureSupportFlags_to_strings);
+
+my %_FeatureSupportFlags_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub FeatureSupportFlags_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_FeatureSupportFlags_VALUES) {
+       my $v = $_FeatureSupportFlags_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($FEATURE_STATUS_ENABLED);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_STATUS_ENABLED);
+
+$_FeatureSupportFlags_VALUES{"STATUS_ENABLED"} = $FEATURE_STATUS_ENABLED;
+
+push @EXPORT_OK, qw($FEATURE_STATUS_DISABLED);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_STATUS_DISABLED);
+
+$_FeatureSupportFlags_VALUES{"STATUS_DISABLED"} = $FEATURE_STATUS_DISABLED;
+
+push @EXPORT_OK, qw($FEATURE_SURETY_BAD);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SURETY_BAD);
+
+$_FeatureSupportFlags_VALUES{"SURETY_BAD"} = $FEATURE_SURETY_BAD;
+
+push @EXPORT_OK, qw($FEATURE_SURETY_GOOD);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SURETY_GOOD);
+
+$_FeatureSupportFlags_VALUES{"SURETY_GOOD"} = $FEATURE_SURETY_GOOD;
+
+push @EXPORT_OK, qw($FEATURE_SOURCE_DEFAULT);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SOURCE_DEFAULT);
+
+$_FeatureSupportFlags_VALUES{"SOURCE_DEFAULT"} = $FEATURE_SOURCE_DEFAULT;
+
+push @EXPORT_OK, qw($FEATURE_SOURCE_DETECTED);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SOURCE_DETECTED);
+
+$_FeatureSupportFlags_VALUES{"SOURCE_DETECTED"} = $FEATURE_SOURCE_DETECTED;
+
+push @EXPORT_OK, qw($FEATURE_SOURCE_USER);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SOURCE_USER);
+
+$_FeatureSupportFlags_VALUES{"SOURCE_USER"} = $FEATURE_SOURCE_USER;
+
+push @EXPORT_OK, qw($FEATURE_SUPPORT_FLAGS_MAX);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SUPPORT_FLAGS_MAX);
+
+push @EXPORT_OK, qw($FEATURE_SUPPORT_FLAGS_MASK);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SUPPORT_FLAGS_MASK);
+
+push @EXPORT_OK, qw($FEATURE_SUPPORT_FLAGS_STATUS_MASK);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SUPPORT_FLAGS_STATUS_MASK);
+
+push @EXPORT_OK, qw($FEATURE_SUPPORT_FLAGS_SURETY_MASK);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SUPPORT_FLAGS_SURETY_MASK);
+
+push @EXPORT_OK, qw($FEATURE_SUPPORT_FLAGS_SOURCE_MASK);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw($FEATURE_SUPPORT_FLAGS_SOURCE_MASK);
+
+push @EXPORT_OK, qw(feature_support_flags_is_valid);
+push @{$EXPORT_TAGS{"FeatureSupportFlags"}}, qw(feature_support_flags_is_valid);
+
+#copy symbols in FeatureSupportFlags to constants
+push @{$EXPORT_TAGS{"constants"}},  @{$EXPORT_TAGS{"FeatureSupportFlags"}};
+
+
+# SWIG produces a sub-package for the Device "class", in this case named 
+# Amanda::Device::Device.  For user convenience, we allow Amanda::Device->new(..) to
+# do the same thing.  This is a wrapper function, and not just a typeglob assignment,
+# because we want to get the right blessing.
+sub new {
+    my $pkg = shift;
+    Amanda::Device::Device->new(@_);
+}
+1;
diff --git a/perl/Amanda/Device.swg b/perl/Amanda/Device.swg
new file mode 100644 (file)
index 0000000..73aac31
--- /dev/null
@@ -0,0 +1,671 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%module "Amanda::Device"
+%include "amglue/amglue.swg"
+%include "exception.i"
+
+%{
+#include "device.h"
+#include "property.h"
+#include "fileheader.h"
+%}
+
+/* import dumptype_t, among others */
+%import "Amanda/Types.swg";
+
+%perlcode %{
+=head1 NAME
+
+Amanda::Device - interact with Amanda data-storage devices
+
+=head1 SYNOPSIS
+
+  use Amanda::Device qw( :constants );
+
+  my $dev = Amanda::Device->new($device_name);
+  $dev->set_startup_properties_from_config();
+  if ($dev->read_label() == $READ_LABEL_STATUS_SUCCESS) {
+      print "Label on $device_name is '$dev->volume_label'\n";
+  }
+  
+See http://wiki.zmanda.com/index.php/Device_API for details on how Devices are used.
+
+=head1 API STATUS
+
+Stable
+
+=head1 Amanda::Device Objects
+
+=head2 Instance Variables
+
+=over
+
+=item C<$file>
+
+=item C<$block>
+
+=item C<$in_file>
+
+=item C<$device_name>
+
+=item C<$access_mode>
+
+=item C<$is_eof>
+
+=item C<$volume_label>
+
+=item C<$volume_time>
+
+=back
+
+=head2 Methods
+
+See the wiki for descriptions of these functions
+
+=over
+
+=item C<read_label()>
+
+=item C<start($mode, $label, $timestamp)>
+
+=item C<finish()>
+
+=item C<start_file($jobinfo)>
+
+where C<$jobinfo> is a C<dumpfile_t> (see L<Amanda::Datatypes>)
+
+=item C<write_min_size()>
+
+=item C<write_max_size()>
+
+=item C<read_max_size()>
+
+=item C<write_block($size, $data, $short_block)>
+
+Note that Perl code is not expected to handle on-device data, so there
+is currently no way to provide data to this function from Perl.  This may
+change in future revisions.
+
+=item C<write_from_fd($fd)>
+
+where C<$fd> is an integer file descriptor, not a filehandle
+
+=item C<finish_file()>
+
+=item C<seek_file($file)>
+
+=item C<seek_block($block)>
+
+=item C<read_block($size)>
+
+=item C<read_to_fd($fd)>
+
+where C<$fd> is an integer file descriptor, not a filehandle
+
+Note that Perl code is not expected to handle on-device data, so there
+is currently no way to access the data this function returns.  This may
+change in future revisions.
+
+=item C<property_list()>
+
+returns a list of property names.
+
+=item C<property_get($property_name)>
+
+returns the property as the appropriate Perl type.
+
+=item C<property_set($property_name, $value)>
+
+where $value is of an appropriate type for the given property
+
+=item C<recycle_file($filenum)>
+
+=item C<set_startup_properties_from_config()>
+
+=back
+
+=head1 CONSTANTS
+
+This module defines a large number of constants.  Again, consult the
+wiki or C<device.h> for the details on their meaning.  These constants
+are available from the package namespace (e.g.,
+C<Amanda::Device::ACCESS_WRITE>), of imported with the C<:constant>
+import tag.
+
+=cut
+%}
+
+%init %{
+    /* Initialize the Device API on load */
+    device_api_init();
+%}
+
+%{
+
+/* Utility functions for typemaps, below */
+
+static SV *
+set_sv_from_gvalue(GValue *value)
+{
+    GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
+    SV *sv = NULL;
+
+    /* complex reference types */
+    switch (fundamental) {
+       case G_TYPE_LONG:
+           sv = sv_2mortal(amglue_newSVi64(g_value_get_long(value)));
+           break;
+
+       case G_TYPE_ULONG:
+           sv = sv_2mortal(amglue_newSVu64(g_value_get_ulong(value)));
+           break;
+
+       case G_TYPE_INT64:
+           sv = sv_2mortal(amglue_newSVi64(g_value_get_int64(value)));
+           break;
+
+       case G_TYPE_UINT64:
+           sv = sv_2mortal(amglue_newSVu64(g_value_get_uint64(value)));
+           break;
+
+       case G_TYPE_BOXED: {
+           GType boxed_type = G_VALUE_TYPE(value);
+           QualifiedSize qs;
+           HV *hv;
+
+           if (boxed_type == QUALIFIED_SIZE_TYPE) {
+               qs = *(QualifiedSize*)(g_value_get_boxed(value));
+               
+               /* build a hash */
+               hv = (HV *)sv_2mortal((SV *)newHV());
+               hv_store(hv, "accuracy", 8, newSViv(qs.accuracy), 0);
+               hv_store(hv, "bytes", 5, amglue_newSVi64(qs.bytes), 0);
+
+               sv = newRV((SV *)hv);
+               return newRV((SV *)hv);
+           } else {
+               warn("Unsupported boxed property type #%d", boxed_type);
+
+               sv = sv_newmortal();
+               sv_setsv(sv, &PL_sv_undef);
+               return sv;
+           }
+       }
+    }
+
+    /* simple types that can be constructed with sv_set*v */
+    sv = sv_newmortal();
+    switch (fundamental) {
+       case G_TYPE_CHAR:
+           sv_setiv(sv, g_value_get_char(value));
+           break;
+
+       case G_TYPE_UCHAR:
+           sv_setuv(sv, g_value_get_uchar(value));
+           break;
+
+       case G_TYPE_BOOLEAN:
+           sv_setiv(sv, g_value_get_boolean(value));
+           break;
+
+       case G_TYPE_INT:
+           sv_setiv(sv, g_value_get_int(value));
+           break;
+
+       case G_TYPE_UINT:
+           sv_setuv(sv, g_value_get_uint(value));
+           break;
+
+       case G_TYPE_FLOAT:
+           sv_setnv(sv, g_value_get_float(value));
+           break;
+
+       case G_TYPE_DOUBLE:
+           sv_setnv(sv, g_value_get_double(value));
+           break;
+
+       case G_TYPE_STRING:
+           sv_setpv(sv, g_value_get_string(value));
+           break;
+
+       case G_TYPE_ENUM:
+           sv_setiv(sv, g_value_get_enum(value));
+           break;
+
+       case G_TYPE_FLAGS:
+           sv_setiv(sv, g_value_get_flags(value));
+           break;
+
+       /* Unsupported */
+       default:
+       case G_TYPE_POINTER:
+       case G_TYPE_INTERFACE:
+       case G_TYPE_OBJECT:
+       case G_TYPE_PARAM:
+           warn("Unsupported fundamental property type #%d", fundamental);
+           sv_setsv(sv, &PL_sv_undef);
+           break;
+    }
+
+    return sv;
+}
+
+static gboolean
+set_gvalue_from_sv(SV *sv, GValue *value)
+{
+    GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
+    switch (fundamental) {
+       case G_TYPE_CHAR:
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_char(value, SvIV(sv));
+           break;
+
+       case G_TYPE_UCHAR:
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_uchar(value, SvUV(sv));
+           break;
+
+       case G_TYPE_BOOLEAN:
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_boolean(value, SvIV(sv));
+           break;
+
+       case G_TYPE_INT:
+           g_value_set_int(value, amglue_SvI32(sv));
+           break;
+
+       case G_TYPE_UINT:
+           g_value_set_uint(value, amglue_SvU32(sv));
+           break;
+
+       case G_TYPE_LONG:
+           g_value_set_int64(value, amglue_SvI64(sv));
+           break;
+
+       case G_TYPE_ULONG:
+           g_value_set_uint64(value, amglue_SvU64(sv));
+           break;
+
+       case G_TYPE_INT64:
+           g_value_set_int64(value, amglue_SvI64(sv));
+           break;
+
+       case G_TYPE_UINT64:
+           g_value_set_uint64(value, amglue_SvU64(sv));
+           break;
+
+       case G_TYPE_FLOAT:
+           if (!SvNOK(sv)) return FALSE;
+           g_value_set_float(value, SvNV(sv));
+           break;
+
+       case G_TYPE_DOUBLE:
+           if (!SvNOK(sv)) return FALSE;
+           g_value_set_double(value, SvNV(sv));
+           break;
+
+       case G_TYPE_STRING:
+           if (!SvPOK(sv)) return FALSE;
+           g_value_set_string(value, SvPV_nolen(sv));
+           break;
+
+       case G_TYPE_ENUM: 
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_enum(value, SvIV(sv));
+           break;
+
+       case G_TYPE_FLAGS:
+           if (!SvIOK(sv)) return FALSE;
+           g_value_set_flags(value, SvIV(sv));
+           break;
+
+       /* Unsupported */
+       default:
+       case G_TYPE_POINTER:
+       case G_TYPE_INTERFACE:
+       case G_TYPE_BOXED: /* note: *getting* boxed values is supported */
+       case G_TYPE_OBJECT:
+       case G_TYPE_PARAM:
+           return FALSE;
+    }
+
+    return TRUE;
+}
+
+%}
+
+/*
+ * Device struct, %extend-ed into a Perl class
+ */
+
+typedef struct Device {
+    /* Instance variables -- all readonly */
+    %immutable;
+    int file;
+    guint64 block;
+    gboolean in_file;
+    char * device_name;
+    DeviceAccessMode access_mode;
+    gboolean is_eof;
+    char * volume_label;
+    char * volume_time;
+    %mutable;
+
+    /* methods */
+    %extend {
+       /* constructor */
+       Device(char *device_name) {
+           return device_open(device_name);
+       }
+
+       ~Device() {
+           g_object_unref(self);
+       }
+
+       ReadLabelStatusFlags
+       read_label() {
+           return device_read_label(self);
+       }
+
+       gboolean
+       start(DeviceAccessMode mode, char *label, char *timestamp) {
+           return device_start(self, mode, label, timestamp);
+       }
+
+       gboolean
+       finish() {
+           return device_finish(self);
+       }
+
+       gboolean
+       start_file(const dumpfile_t *jobInfo) {
+           return device_start_file(self, jobInfo);
+       }
+
+       guint
+       write_min_size() {
+           return device_write_min_size(self);
+       }
+
+       guint
+       write_max_size() {
+           return device_write_max_size(self);
+       }
+
+       guint
+       read_max_size() {
+           return device_read_max_size(self);
+       }
+
+       gboolean
+       write_block(guint size, gpointer data, gboolean short_block) {
+           return device_write_block(self, size, data, short_block);
+       }
+
+       gboolean
+       write_from_fd(int fd) {
+           return device_write_from_fd(self, fd);
+       }
+
+       gboolean
+       finish_file() {
+           return device_finish_file(self);
+       }
+
+       dumpfile_t*
+       seek_file(guint file) {
+           return device_seek_file(self, file);
+       }
+
+       gboolean
+       seek_block(guint64 block) {
+           return device_seek_block(self, block);
+       }
+
+       int
+       read_block(gpointer buffer, int *size) {
+           return device_read_block(self, buffer, size);
+       }
+
+       gboolean read_to_fd(int fd) {
+           return device_read_to_fd(self, fd);
+       }
+
+       %typemap(out) const DeviceProperty * {
+           int i = 0;
+           int len = 0;
+
+           /* Count the DeviceProperties */
+           while ($1[len].base) len++;
+           EXTEND(SP, len); /* make room for return values */
+
+           /* Note that we set $result several times. the nature of
+            * SWIG's wrapping is such that incrementing argvi points
+            * $result to the next location in perl's argument stack.
+             */
+
+           for (i = 0; i < len ; i++) { 
+               $result = sv_newmortal(); 
+               sv_setpv($result, $1[i].base->name); 
+               argvi++;
+           }; 
+       }
+       const DeviceProperty * property_list(void) {
+           return device_property_get_list(self);
+       }
+
+       %typemap(out) const DeviceProperty *; /* remove typemap */
+
+       /* A typemap to convert a property name to a DevicePropertyBase. */
+       %typemap(in) DevicePropertyBase * {
+           char *pname = NULL;
+
+           if (SvPOK($input))
+               pname = SvPV_nolen($input);
+
+           if (pname) $1 = (DevicePropertyBase *)device_property_get_by_name(pname);
+           if (!pname || !$1) {
+               SWIG_exception_fail(SWIG_ValueError, "Invalid property name");
+           }
+       }
+
+       /* A typemap to convert the GValue in property_get to a return value.  The
+        * (in) typemap sets up storage for the parameters, while the (argout) converts
+        * them to a perl SV. */
+       %typemap(in,numinputs=0) (GValue *out_val, gboolean *val_found)
+                           (GValue val, gboolean found) {
+           memset(&val, 0, sizeof(val));
+           $1 = &val;
+           $2 = &found;
+       }
+       %typemap(argout) (GValue *out_val, gboolean *val_found) {
+           /* if the result is valid */
+           if (*$2) {
+               /* move data from $1 to $result, somehow */
+               $result = set_sv_from_gvalue($1);
+
+               /* free any memory for the GValue */
+               g_value_unset($1);
+           } else {
+               /* silently return 'undef', the sentinel for "undefined" */
+               $result = sv_newmortal();
+               sv_setsv($result, &PL_sv_undef);
+           }
+           argvi++;
+       }
+
+       void
+       property_get(DevicePropertyBase *pbase, GValue *out_val, gboolean *val_found) {
+           *val_found = device_property_get(self, pbase->ID, out_val);
+       }
+
+       /* delete typemaps */
+       %typemap(in) (GValue *out_val, gboolean *val_found);
+       %typemap(argout) (GValue *out_val, gboolean *val_found);
+
+       /* We cheat a little bit here and just pass the native Perl type in to
+        * the function.  This is the easiest way to make sure we know the property
+        * information (in particular, its type) before trying to convert the SV.  */
+       %typemap(in) SV *sv "$1 = $input;"
+
+       gboolean
+       property_set(DevicePropertyBase *pbase, SV *sv) {
+           GValue gval;
+           memset(&gval, 0, sizeof(gval));
+           g_value_init(&gval, pbase->type);
+           if (!set_gvalue_from_sv(sv, &gval))
+               goto fail;
+
+           if (!device_property_set(self, pbase->ID, &gval))
+               goto fail;
+
+           g_value_unset(&gval);
+           return TRUE;
+       fail:
+           g_value_unset(&gval);
+           return FALSE;
+       }
+
+       gboolean recycle_file(guint filenum) {
+           return device_recycle_file(self, filenum);
+       }
+       
+       void set_startup_properties_from_config(void) {
+           device_set_startup_properties_from_config(self);
+       }
+    };
+} Device;
+
+/*
+ * Constants
+ */
+
+amglue_add_flag_tag_fns(DeviceAccessMode);
+amglue_add_constant_short(ACCESS_NULL, "NULL", DeviceAccessMode);
+amglue_add_constant_short(ACCESS_READ, "READ", DeviceAccessMode);
+amglue_add_constant_short(ACCESS_WRITE, "WRITE", DeviceAccessMode);
+amglue_add_constant_short(ACCESS_APPEND, "APPEND", DeviceAccessMode);
+
+/* (this is really a macro, but SWIG will Do The Right Thing */
+gboolean IS_WRITABLE_ACCESS_MODE(DeviceAccessMode mode);
+amglue_export_tag(DeviceAccessMode, IS_WRITABLE_ACCESS_MODE);
+amglue_copy_to_tag(DeviceAccessMode, constants);
+
+amglue_add_flag_tag_fns(ReadLabelStatusFlags);
+amglue_add_constant_short(READ_LABEL_STATUS_SUCCESS, "SUCCESS", ReadLabelStatusFlags);
+amglue_add_constant_short(READ_LABEL_STATUS_DEVICE_MISSING, "DEVICE_MISSING", ReadLabelStatusFlags);
+amglue_add_constant_short(READ_LABEL_STATUS_DEVICE_ERROR, "DEVICE_ERROR", ReadLabelStatusFlags);
+amglue_add_constant_short(READ_LABEL_STATUS_VOLUME_MISSING, "VOLUME_MISSING", ReadLabelStatusFlags);
+amglue_add_constant_short(READ_LABEL_STATUS_VOLUME_UNLABELED, "VOLUME_UNLABELED", ReadLabelStatusFlags);
+amglue_add_constant_short(READ_LABEL_STATUS_VOLUME_ERROR, "VOLUME_ERROR", ReadLabelStatusFlags);
+amglue_add_constant_noshort(READ_LABEL_STATUS_FLAGS_MAX, ReadLabelStatusFlags);
+amglue_copy_to_tag(ReadLabelStatusFlags, constants);
+
+amglue_add_flag_tag_fns(PropertyPhaseFlags);
+amglue_add_constant_short(PROPERTY_PHASE_BEFORE_START, "BEFORE_START", PropertyPhaseFlags);
+amglue_add_constant_short(PROPERTY_PHASE_BETWEEN_FILE_WRITE, "BETWEEN_FILE_WRITE", PropertyPhaseFlags);
+amglue_add_constant_short(PROPERTY_PHASE_INSIDE_FILE_WRITE, "INSIDE_FILE_WRITE", PropertyPhaseFlags);
+amglue_add_constant_short(PROPERTY_PHASE_BETWEEN_FILE_READ, "BETWEEN_FILE_READ", PropertyPhaseFlags);
+amglue_add_constant_short(PROPERTY_PHASE_INSIDE_FILE_READ, "INSIDE_FILE_READ", PropertyPhaseFlags);
+amglue_add_constant_noshort(PROPERTY_PHASE_MAX, PropertyPhaseFlags);
+amglue_add_constant_noshort(PROPERTY_PHASE_MASK, PropertyPhaseFlags);
+amglue_add_constant_noshort(PROPERTY_PHASE_SHIFT, PropertyPhaseFlags);
+amglue_copy_to_tag(PropertyPhaseFlags, constants);
+
+amglue_add_flag_tag_fns(PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_GET_BEFORE_START, 
+                   "GET_BEFORE_START", PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE, 
+                   "GET_BETWEEN_FILE_WRITE", PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE, 
+                   "GET_INSIDE_FILE_WRITE", PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_READ, 
+                   "GET_BETWEEN_FILE_READ", PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_READ, 
+                   "GET_INSIDE_FILE_READ", PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_SET_BEFORE_START, 
+                   "SET_BEFORE_START", PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE, 
+                   "SET_BETWEEN_FILE_WRITE", PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE, 
+                   "SET_INSIDE_FILE_WRITE", PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_READ, 
+                   "SET_BETWEEN_FILE_READ", PropertyAccessFlags);
+amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_READ, 
+                   "SET_INSIDE_FILE_READ", PropertyAccessFlags);
+amglue_add_constant_noshort(PROPERTY_ACCESS_GET_MASK, PropertyAccessFlags);
+amglue_add_constant_noshort(PROPERTY_ACCESS_SET_MASK, PropertyAccessFlags);
+amglue_copy_to_tag(PropertyAccessFlags, constants);
+
+amglue_add_enum_tag_fns(ConcurrencyParadigm);
+amglue_add_constant_short(CONCURRENCY_PARADIGM_EXCLUSIVE, "EXCLUSIVE", ConcurrencyParadigm);
+amglue_add_constant_short(CONCURRENCY_PARADIGM_SHARED_READ, "SHARED_READ", ConcurrencyParadigm);
+amglue_add_constant_short(CONCURRENCY_PARADIGM_RANDOM_ACCESS, "RANDOM_ACCESS", ConcurrencyParadigm);
+amglue_copy_to_tag(ConcurrencyParadigm, constants);
+
+amglue_add_enum_tag_fns(StreamingRequirement);
+amglue_add_constant_short(STREAMING_REQUIREMENT_NONE, "NONE", StreamingRequirement);
+amglue_add_constant_short(STREAMING_REQUIREMENT_DESIRED, "DESIRED", StreamingRequirement);
+amglue_add_constant_short(STREAMING_REQUIREMENT_REQUIRED, "REQUIRED", StreamingRequirement);
+amglue_copy_to_tag(StreamingRequirement, constants);
+
+amglue_add_enum_tag_fns(MediaAccessMode);
+amglue_add_constant_short(MEDIA_ACCESS_MODE_READ_ONLY, "READ_ONLY", MediaAccessMode);
+amglue_add_constant_short(MEDIA_ACCESS_MODE_WORM, "WORM", MediaAccessMode);
+amglue_add_constant_short(MEDIA_ACCESS_MODE_READ_WRITE, "READ_WRITE", MediaAccessMode);
+amglue_add_constant_short(MEDIA_ACCESS_MODE_WRITE_ONLY, "WRITE_ONLY", MediaAccessMode);
+amglue_copy_to_tag(MediaAccessMode, constants);
+
+amglue_add_enum_tag_fns(SizeAccuracy);
+amglue_add_constant_short(SIZE_ACCURACY_UNKNOWN, "UNKNOWN", SizeAccuracy);
+amglue_add_constant_short(SIZE_ACCURACY_ESTIMATE, "ESTIMATE", SizeAccuracy);
+amglue_add_constant_short(SIZE_ACCURACY_REAL, "REAL", SizeAccuracy);
+amglue_copy_to_tag(SizeAccuracy, constants);
+
+amglue_add_flag_tag_fns(FeatureSupportFlags);
+amglue_add_constant_short(FEATURE_STATUS_ENABLED, "STATUS_ENABLED", FeatureSupportFlags);
+amglue_add_constant_short(FEATURE_STATUS_DISABLED, "STATUS_DISABLED", FeatureSupportFlags);
+amglue_add_constant_short(FEATURE_SURETY_BAD, "SURETY_BAD", FeatureSupportFlags);
+amglue_add_constant_short(FEATURE_SURETY_GOOD, "SURETY_GOOD", FeatureSupportFlags);
+amglue_add_constant_short(FEATURE_SOURCE_DEFAULT, "SOURCE_DEFAULT", FeatureSupportFlags);
+amglue_add_constant_short(FEATURE_SOURCE_DETECTED, "SOURCE_DETECTED", FeatureSupportFlags);
+amglue_add_constant_short(FEATURE_SOURCE_USER, "SOURCE_USER", FeatureSupportFlags);
+amglue_add_constant_noshort(FEATURE_SUPPORT_FLAGS_MAX, FeatureSupportFlags);
+amglue_add_constant_noshort(FEATURE_SUPPORT_FLAGS_MASK, FeatureSupportFlags);
+amglue_add_constant_noshort(FEATURE_SUPPORT_FLAGS_STATUS_MASK, FeatureSupportFlags);
+amglue_add_constant_noshort(FEATURE_SUPPORT_FLAGS_SURETY_MASK, FeatureSupportFlags);
+amglue_add_constant_noshort(FEATURE_SUPPORT_FLAGS_SOURCE_MASK, FeatureSupportFlags);
+
+gboolean feature_support_flags_is_valid(FeatureSupportFlags);
+amglue_export_tag(FeatureSupportFlags, feature_support_flags_is_valid);
+amglue_copy_to_tag(FeatureSupportFlags, constants);
+
+%perlcode %{
+
+# SWIG produces a sub-package for the Device "class", in this case named 
+# Amanda::Device::Device.  For user convenience, we allow Amanda::Device->new(..) to
+# do the same thing.  This is a wrapper function, and not just a typeglob assignment,
+# because we want to get the right blessing.
+sub new {
+    my $pkg = shift;
+    Amanda::Device::Device->new(@_);
+}
+%}
diff --git a/perl/Amanda/Logfile.c b/perl/Amanda/Logfile.c
new file mode 100644 (file)
index 0000000..a022c0f
--- /dev/null
@@ -0,0 +1,3058 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.33
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPERL
+#define SWIG_CASTRANK_MODE
+/* -----------------------------------------------------------------------------
+ *  This section contains generic SWIG labels for method/variable
+ *  declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+#  define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+#   define SWIGINLINE inline
+# else
+#   define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define SWIGUNUSED __attribute__ ((__unused__)) 
+#   else
+#     define SWIGUNUSED
+#   endif
+# elif defined(__ICC)
+#   define SWIGUNUSED __attribute__ ((__unused__)) 
+# else
+#   define SWIGUNUSED 
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+#   define SWIGUNUSEDPARM(p)
+# else
+#   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#  ifndef GCC_HASCLASSVISIBILITY
+#    define GCC_HASCLASSVISIBILITY
+#  endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   if defined(STATIC_LINKED)
+#     define SWIGEXPORT
+#   else
+#     define SWIGEXPORT __declspec(dllexport)
+#   endif
+# else
+#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+#     define SWIGEXPORT __attribute__ ((visibility("default")))
+#   else
+#     define SWIGEXPORT
+#   endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   define SWIGSTDCALL __stdcall
+# else
+#   define SWIGSTDCALL
+# endif 
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+   or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "3"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+  You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+  creating a static or dynamic library from the swig runtime code.
+  In 99.9% of the cases, swig just needs to declare them as 'static'.
+  
+  But only do this if is strictly necessary, ie, if you have problems
+  with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/*  Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN        0x1
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN           0x1
+
+
+/* 
+   Flags/methods for returning states.
+   
+   The swig conversion methods, as ConvertPtr, return and integer 
+   that tells if the conversion was successful or not. And if not,
+   an error code can be returned (see swigerrors.swg for the codes).
+   
+   Use the following macros/flags to set or process the returning
+   states.
+   
+   In old swig versions, you usually write code as:
+
+     if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+       // success code
+     } else {
+       //fail code
+     }
+
+   Now you can be more explicit as:
+
+    int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+    } else {
+      // fail code
+    }
+
+   that seems to be the same, but now you can also do
+
+    Type *ptr;
+    int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+      if (SWIG_IsNewObj(res) {
+        ...
+       delete *ptr;
+      } else {
+        ...
+      }
+    } else {
+      // fail code
+    }
+    
+   I.e., now SWIG_ConvertPtr can return new objects and you can
+   identify the case and take care of the deallocation. Of course that
+   requires also to SWIG_ConvertPtr to return new result values, as
+
+      int SWIG_ConvertPtr(obj, ptr,...) {         
+        if (<obj is ok>) {                            
+          if (<need new object>) {                    
+            *ptr = <ptr to new allocated object>; 
+            return SWIG_NEWOBJ;                       
+          } else {                                    
+            *ptr = <ptr to old object>;               
+            return SWIG_OLDOBJ;                       
+          }                                   
+        } else {                                      
+          return SWIG_BADOBJ;                 
+        }                                             
+      }
+
+   Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+   more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+   swig errors code.
+
+   Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+   allows to return the 'cast rank', for example, if you have this
+
+       int food(double)
+       int fooi(int);
+
+   and you call
+      food(1)   // cast rank '1'  (1 -> 1.0)
+      fooi(1)   // cast rank '0'
+
+   just use the SWIG_AddCast()/SWIG_CheckState()
+
+
+ */
+#define SWIG_OK                    (0) 
+#define SWIG_ERROR                 (-1)
+#define SWIG_IsOK(r)               (r >= 0)
+#define SWIG_ArgError(r)           ((r != SWIG_ERROR) ? r : SWIG_TypeError)  
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT         (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK            (SWIG_CASTRANKLIMIT  << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK            (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ                (SWIG_ERROR)
+#define SWIG_OLDOBJ                (SWIG_OK)
+#define SWIG_NEWOBJ                (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ                (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r)         (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r)           (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r)         (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r)           (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+#  ifndef SWIG_TypeRank
+#    define SWIG_TypeRank             unsigned long
+#  endif
+#  ifndef SWIG_MAXCASTRANK            /* Default cast allowed */
+#    define SWIG_MAXCASTRANK          (2)
+#  endif
+#  define SWIG_CASTRANKMASK          ((SWIG_CASTRANKLIMIT) -1)
+#  define SWIG_CastRank(r)           (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) { 
+  return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) { 
+  return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; 
+}
+#else /* no cast-rank mode */
+#  define SWIG_AddCast
+#  define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store inforomation on one type */
+typedef struct swig_type_info {
+  const char             *name;                        /* mangled name of this type */
+  const char             *str;                 /* human readable name of this type */
+  swig_dycast_func        dcast;               /* dynamic cast function down a hierarchy */
+  struct swig_cast_info  *cast;                        /* linked list of types that can cast into this type */
+  void                   *clientdata;          /* language specific type data */
+  int                    owndata;              /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+  swig_type_info         *type;                        /* pointer to type that is equivalent to this type */
+  swig_converter_func     converter;           /* function to cast the void pointers */
+  struct swig_cast_info  *next;                        /* pointer to next cast in linked list */
+  struct swig_cast_info  *prev;                        /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+  swig_type_info         **types;              /* Array of pointers to swig_type_info structures that are in this module */
+  size_t                 size;                 /* Number of types in this module */
+  struct swig_module_info *next;               /* Pointer to next element in circularly linked list */
+  swig_type_info         **type_initial;       /* Array of initially generated type structures */
+  swig_cast_info         **cast_initial;       /* Array of initially generated casting structures */
+  void                    *clientdata;         /* Language specific module data */
+} swig_module_info;
+
+/* 
+  Compare two type names skipping the space characters, therefore
+  "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+  Return 0 when the two name types are equivalent, as in
+  strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+                 const char *f2, const char *l2) {
+  for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+    while ((*f1 == ' ') && (f1 != l1)) ++f1;
+    while ((*f2 == ' ') && (f2 != l2)) ++f2;
+    if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+  }
+  return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty)         \
+  if (ty) {                                             \
+    swig_cast_info *iter = ty->cast;                    \
+    while (iter) {                                      \
+      if (comparison) {                                 \
+        if (iter == ty->cast) return iter;              \
+        /* Move iter to the top of the linked list */   \
+        iter->prev->next = iter->next;                  \
+        if (iter->next)                                 \
+          iter->next->prev = iter->prev;                \
+        iter->next = ty->cast;                          \
+        iter->prev = 0;                                 \
+        if (ty->cast) ty->cast->prev = iter;            \
+        ty->cast = iter;                                \
+        return iter;                                    \
+      }                                                 \
+      iter = iter->next;                                \
+    }                                                   \
+  }                                                     \
+  return 0
+
+/*
+  Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+  SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+  Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr) {
+  return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/* 
+   Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/*
+  Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/*
+  Return the pretty name associated with this type,
+  that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+  /* The "str" field contains the equivalent pretty names of the
+     type, separated by vertical-bar characters.  We choose
+     to print the last name, as it is often (?) the most
+     specific. */
+  if (!type) return NULL;
+  if (type->str != NULL) {
+    const char *last_name = type->str;
+    const char *s;
+    for (s = type->str; *s; s++)
+      if (*s == '|') last_name = s+1;
+    return last_name;
+  }
+  else
+    return type->name;
+}
+
+/* 
+   Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  swig_cast_info *cast = ti->cast;
+  /* if (ti->clientdata == clientdata) return; */
+  ti->clientdata = clientdata;
+  
+  while (cast) {
+    if (!cast->converter) {
+      swig_type_info *tc = cast->type;
+      if (!tc->clientdata) {
+       SWIG_TypeClientData(tc, clientdata);
+      }
+    }    
+    cast = cast->next;
+  }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+  SWIG_TypeClientData(ti, clientdata);
+  ti->owndata = 1;
+}
+  
+/*
+  Search for a swig_type_info structure only by mangled name
+  Search is a O(log #types)
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start, 
+                            swig_module_info *end, 
+                           const char *name) {
+  swig_module_info *iter = start;
+  do {
+    if (iter->size) {
+      register size_t l = 0;
+      register size_t r = iter->size - 1;
+      do {
+       /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+       register size_t i = (l + r) >> 1; 
+       const char *iname = iter->types[i]->name;
+       if (iname) {
+         register int compare = strcmp(name, iname);
+         if (compare == 0) {       
+           return iter->types[i];
+         } else if (compare < 0) {
+           if (i) {
+             r = i - 1;
+           } else {
+             break;
+           }
+         } else if (compare > 0) {
+           l = i + 1;
+         }
+       } else {
+         break; /* should never happen */
+       }
+      } while (l <= r);
+    }
+    iter = iter->next;
+  } while (iter != end);
+  return 0;
+}
+
+/*
+  Search for a swig_type_info structure for either a mangled name or a human readable name.
+  It first searches the mangled names of the types, which is a O(log #types)
+  If a type is not found it then searches the human readable names, which is O(#types).
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start, 
+                     swig_module_info *end, 
+                    const char *name) {
+  /* STEP 1: Search the name field using binary search */
+  swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+  if (ret) {
+    return ret;
+  } else {
+    /* STEP 2: If the type hasn't been found, do a complete search
+       of the str field (the human readable name) */
+    swig_module_info *iter = start;
+    do {
+      register size_t i = 0;
+      for (; i < iter->size; ++i) {
+       if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+         return iter->types[i];
+      }
+      iter = iter->next;
+    } while (iter != end);
+  }
+  
+  /* neither found a match */
+  return 0;
+}
+
+/* 
+   Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+  static const char hex[17] = "0123456789abcdef";
+  register const unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu =  u + sz;
+  for (; u != eu; ++u) {
+    register unsigned char uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* 
+   Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+  register unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu = u + sz;
+  for (; u != eu; ++u) {
+    register char d = *(c++);
+    register unsigned char uu;
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    else 
+      return (char *) 0;
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    else 
+      return (char *) 0;
+    *u = uu;
+  }
+  return c;
+}
+
+/* 
+   Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+  char *r = buff;
+  if ((2*sizeof(void *) + 2) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,&ptr,sizeof(void *));
+  if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+  strcpy(r,name);
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      *ptr = (void *) 0;
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+  char *r = buff;
+  size_t lname = (name ? strlen(name) : 0);
+  if ((2*sz + 2 + lname) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  if (lname) {
+    strncpy(r,name,lname+1);
+  } else {
+    *r = 0;
+  }
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      memset(ptr,0,sz);
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*  Errors in SWIG */
+#define  SWIG_UnknownError        -1 
+#define  SWIG_IOError             -2 
+#define  SWIG_RuntimeError        -3 
+#define  SWIG_IndexError          -4 
+#define  SWIG_TypeError           -5 
+#define  SWIG_DivisionByZero      -6 
+#define  SWIG_OverflowError       -7 
+#define  SWIG_SyntaxError         -8 
+#define  SWIG_ValueError          -9 
+#define  SWIG_SystemError         -10
+#define  SWIG_AttributeError      -11
+#define  SWIG_MemoryError         -12 
+#define  SWIG_NullReferenceError   -13
+
+
+
+#ifdef __cplusplus
+/* Needed on some windows machines---since MS plays funny games with the header files under C++ */
+#include <math.h>
+#include <stdlib.h>
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* Add in functionality missing in older versions of Perl. Much of this is based on Devel-PPPort on cpan. */
+
+/* Add PERL_REVISION, PERL_VERSION, PERL_SUBVERSION if missing */
+#ifndef PERL_REVISION
+#  if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+#    define PERL_PATCHLEVEL_H_IMPLICIT
+#    include <patchlevel.h>
+#  endif
+#  if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+#    include <could_not_find_Perl_patchlevel.h>
+#  endif
+#  ifndef PERL_REVISION
+#    define PERL_REVISION       (5)
+#    define PERL_VERSION        PATCHLEVEL
+#    define PERL_SUBVERSION     SUBVERSION
+#  endif
+#endif
+
+#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE)
+#define PerlIO_exportFILE(fh,fl) (FILE*)(fh)
+#endif
+
+#ifndef SvIOK_UV
+# define SvIOK_UV(sv)       (SvIOK(sv) && (SvUVX(sv) == SvIVX(sv)))
+#endif
+
+#ifndef SvUOK
+# define SvUOK(sv)           SvIOK_UV(sv)
+#endif
+
+#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5)))
+#  define PL_sv_undef               sv_undef
+#  define PL_na                            na
+#  define PL_errgv                  errgv
+#  define PL_sv_no                  sv_no
+#  define PL_sv_yes                 sv_yes
+#  define PL_markstack_ptr          markstack_ptr
+#endif
+
+#ifndef IVSIZE
+#  ifdef LONGSIZE
+#    define IVSIZE LONGSIZE
+#  else
+#    define IVSIZE 4 /* A bold guess, but the best we can make. */
+#  endif
+#endif
+
+#ifndef INT2PTR
+#  if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#    define PTRV                  UV
+#    define INT2PTR(any,d)        (any)(d)
+#  else
+#    if PTRSIZE == LONGSIZE
+#      define PTRV                unsigned long
+#    else
+#      define PTRV                unsigned
+#    endif
+#    define INT2PTR(any,d)        (any)(PTRV)(d)
+#  endif
+
+#  define NUM2PTR(any,d)  (any)(PTRV)(d)
+#  define PTR2IV(p)       INT2PTR(IV,p)
+#  define PTR2UV(p)       INT2PTR(UV,p)
+#  define PTR2NV(p)       NUM2PTR(NV,p)
+
+#  if PTRSIZE == LONGSIZE
+#    define PTR2ul(p)     (unsigned long)(p)
+#  else
+#    define PTR2ul(p)     INT2PTR(unsigned long,p)
+#  endif
+#endif /* !INT2PTR */
+
+#ifndef SvPV_nolen
+# define SvPV_nolen(x) SvPV(x,PL_na)
+#endif
+
+#ifndef get_sv
+#  define get_sv perl_get_sv
+#endif
+
+#ifndef ERRSV
+#  define ERRSV get_sv("@",FALSE)
+#endif
+
+#ifndef pTHX_
+#define pTHX_
+#endif   
+
+#include <string.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGINTERN const char*
+SWIG_Perl_ErrorType(int code) {
+  const char* type = 0;
+  switch(code) {
+  case SWIG_MemoryError:
+    type = "MemoryError";
+    break;
+  case SWIG_IOError:
+    type = "IOError";
+    break;
+  case SWIG_RuntimeError:
+    type = "RuntimeError";
+    break;
+  case SWIG_IndexError:
+    type = "IndexError";
+    break;
+  case SWIG_TypeError:
+    type = "TypeError";
+    break;
+  case SWIG_DivisionByZero:
+    type = "ZeroDivisionError";
+    break;
+  case SWIG_OverflowError:
+    type = "OverflowError";
+    break;
+  case SWIG_SyntaxError:
+    type = "SyntaxError";
+    break;
+  case SWIG_ValueError:
+    type = "ValueError";
+    break;
+  case SWIG_SystemError:
+    type = "SystemError";
+    break;
+  case SWIG_AttributeError:
+    type = "AttributeError";
+    break;
+  default:
+    type = "RuntimeError";
+  }
+  return type;
+}
+
+
+
+
+/* -----------------------------------------------------------------------------
+ * perlrun.swg
+ *
+ * This file contains the runtime support for Perl modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef PERL_OBJECT
+#define SWIG_PERL_OBJECT_DECL CPerlObj *SWIGUNUSEDPARM(pPerl),
+#define SWIG_PERL_OBJECT_CALL pPerl,
+#else
+#define SWIG_PERL_OBJECT_DECL
+#define SWIG_PERL_OBJECT_CALL
+#endif
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_ConvertPtr(obj, pp, type, flags)           SWIG_Perl_ConvertPtr(SWIG_PERL_OBJECT_CALL obj, pp, type, flags)
+#define SWIG_NewPointerObj(p, type, flags)              SWIG_Perl_NewPointerObj(SWIG_PERL_OBJECT_CALL p, type, flags)
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, p, s, type)             SWIG_Perl_ConvertPacked(SWIG_PERL_OBJECT_CALL obj, p, s, type)
+#define SWIG_NewPackedObj(p, s, type)                  SWIG_Perl_NewPackedObj(SWIG_PERL_OBJECT_CALL p, s, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags)    SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags)           SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type)        SWIG_ConvertPtr(obj, pptr, type, 0)
+#define SWIG_NewFunctionPtrObj(ptr, type)               SWIG_NewPointerObj(ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty)            SWIG_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type)                SWIG_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata)                      SWIG_Perl_GetModule()
+#define SWIG_SetModule(clientdata, pointer)             SWIG_Perl_SetModule(pointer)
+
+
+/* Error manipulation */
+
+#define SWIG_ErrorType(code)                            SWIG_Perl_ErrorType(code)               
+#define SWIG_Error(code, msg)                          sv_setpvf(GvSV(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg)
+#define SWIG_fail                                      goto fail                                                   
+
+/* Perl-specific SWIG API */
+
+#define SWIG_MakePtr(sv, ptr, type, flags)              SWIG_Perl_MakePtr(SWIG_PERL_OBJECT_CALL sv, ptr, type, flags)
+#define SWIG_MakePackedObj(sv, p, s, type)             SWIG_Perl_MakePackedObj(SWIG_PERL_OBJECT_CALL sv, p, s, type)
+#define SWIG_SetError(str)                              SWIG_Error(SWIG_RuntimeError, str)
+
+
+#define SWIG_PERL_DECL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_DECL arg1)
+#define SWIG_PERL_CALL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_CALL arg1)
+#define SWIG_PERL_DECL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_DECL arg1, arg2)
+#define SWIG_PERL_CALL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_CALL arg1, arg2)
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+/* For backward compatibility only */
+#define SWIG_POINTER_EXCEPTION  0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_OWNER   SWIG_POINTER_OWN
+#define SWIG_SHADOW  SWIG_OWNER << 1
+
+#define SWIG_MAYBE_PERL_OBJECT SWIG_PERL_OBJECT_DECL
+
+/* SWIG Perl macros */
+
+/* Macro to declare an XS function */
+#ifndef XSPROTO
+#   define XSPROTO(name) void name(pTHX_ CV* cv)
+#endif
+
+/* Macro to call an XS function */
+#ifdef PERL_OBJECT 
+#  define SWIG_CALLXS(_name) _name(cv,pPerl) 
+#else 
+#  ifndef MULTIPLICITY 
+#    define SWIG_CALLXS(_name) _name(cv) 
+#  else 
+#    define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) 
+#  endif 
+#endif 
+
+#ifdef PERL_OBJECT
+#define MAGIC_PPERL  CPerlObj *pPerl = (CPerlObj *) this;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+#define SWIGCLASS_STATIC
+
+#else /* PERL_OBJECT */
+
+#define MAGIC_PPERL
+#define SWIGCLASS_STATIC static SWIGUNUSED
+
+#ifndef MULTIPLICITY
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MULTIPLICITY */
+
+#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MULTIPLICITY */
+#endif /* PERL_OBJECT */
+
+/* Workaround for bug in perl 5.6.x croak and earlier */
+#if (PERL_VERSION < 8)
+#  ifdef PERL_OBJECT
+#    define SWIG_croak_null() SWIG_Perl_croak_null(pPerl)
+static void SWIG_Perl_croak_null(CPerlObj *pPerl)
+#  else
+static void SWIG_croak_null()
+#  endif
+{
+  SV *err=ERRSV;
+#  if (PERL_VERSION < 6)
+  croak("%_", err);
+#  else
+  if (SvOK(err) && !SvROK(err)) croak("%_", err);
+  croak(Nullch);
+#  endif
+}
+#else
+#  define SWIG_croak_null() croak(Nullch)
+#endif
+
+
+/* 
+   Define how strict is the cast between strings and integers/doubles
+   when overloading between these types occurs.
+   
+   The default is making it as strict as possible by using SWIG_AddCast
+   when needed.
+   
+   You can use -DSWIG_PERL_NO_STRICT_STR2NUM at compilation time to
+   disable the SWIG_AddCast, making the casting between string and
+   numbers less strict.
+
+   In the end, we try to solve the overloading between strings and
+   numerical types in the more natural way, but if you can avoid it,
+   well, avoid it using %rename, for example.
+*/
+#ifndef SWIG_PERL_NO_STRICT_STR2NUM
+# ifndef SWIG_PERL_STRICT_STR2NUM
+#  define SWIG_PERL_STRICT_STR2NUM
+# endif
+#endif
+#ifdef SWIG_PERL_STRICT_STR2NUM
+/* string takes precedence */
+#define SWIG_Str2NumCast(x) SWIG_AddCast(x)  
+#else
+/* number takes precedence */
+#define SWIG_Str2NumCast(x) x
+#endif
+
+
+
+#include <stdlib.h>
+
+SWIGRUNTIME const char *
+SWIG_Perl_TypeProxyName(const swig_type_info *type) {
+  if (!type) return NULL;
+  if (type->clientdata != NULL) {
+    return (const char*) type->clientdata;
+  } 
+  else {
+    return type->name;
+  }
+}
+
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeProxyCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(( (!iter->type->clientdata && (strcmp((char*)iter->type->name, c) == 0)) 
+                           || (iter->type->clientdata && (strcmp((char*)iter->type->clientdata, c) == 0))), ty);
+}
+
+
+/* Function for getting a pointer value */
+
+SWIGRUNTIME int
+SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) {
+  swig_cast_info *tc;
+  void *voidptr = (void *)0;
+  SV *tsv = 0;
+  /* If magical, apply more magic */
+  if (SvGMAGICAL(sv))
+    mg_get(sv);
+
+  /* Check to see if this is an object */
+  if (sv_isobject(sv)) {
+    IV tmp = 0;
+    tsv = (SV*) SvRV(sv);
+    if ((SvTYPE(tsv) == SVt_PVHV)) {
+      MAGIC *mg;
+      if (SvMAGICAL(tsv)) {
+        mg = mg_find(tsv,'P');
+        if (mg) {
+          sv = mg->mg_obj;
+          if (sv_isobject(sv)) {
+           tsv = (SV*)SvRV(sv);
+            tmp = SvIV(tsv);
+          }
+        }
+      } else {
+        return SWIG_ERROR;
+      }
+    } else {
+      tmp = SvIV(tsv);
+    }
+    voidptr = INT2PTR(void *,tmp);
+  } else if (! SvOK(sv)) {            /* Check for undef */
+    *(ptr) = (void *) 0;
+    return SWIG_OK;
+  } else if (SvTYPE(sv) == SVt_RV) {  /* Check for NULL pointer */
+    if (!SvROK(sv)) {
+      *(ptr) = (void *) 0;
+      return SWIG_OK;
+    } else {
+      return SWIG_ERROR;
+    }
+  } else {                            /* Don't know what it is */
+    return SWIG_ERROR;
+  }
+  if (_t) {
+    /* Now see if the types match */
+    char *_c = HvNAME(SvSTASH(SvRV(sv)));
+    tc = SWIG_TypeProxyCheck(_c,_t);
+    if (!tc) {
+      return SWIG_ERROR;
+    }
+    *ptr = SWIG_TypeCast(tc,voidptr);
+  } else {
+    *ptr = voidptr;
+  }
+
+  /* 
+   *  DISOWN implementation: we need a perl guru to check this one.
+   */
+  if (tsv && (flags & SWIG_POINTER_DISOWN)) {
+    /* 
+     *  almost copy paste code from below SWIG_POINTER_OWN setting
+     */
+    SV *obj = sv;
+    HV *stash = SvSTASH(SvRV(obj));
+    GV *gv = *(GV**) hv_fetch(stash, "OWNER", 5, TRUE);
+    if (isGV(gv)) {
+      HV *hv = GvHVn(gv);
+      /*
+       * To set ownership (see below), a newSViv(1) entry is added. 
+       * Hence, to remove ownership, we delete the entry.
+       */
+      if (hv_exists_ent(hv, obj, 0)) {
+       hv_delete_ent(hv, obj, 0, 0);
+      }
+    }
+  }
+  return SWIG_OK;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) {
+  if (ptr && (flags & SWIG_SHADOW)) {
+    SV *self;
+    SV *obj=newSV(0);
+    HV *hash=newHV();
+    HV *stash;
+    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+    stash=SvSTASH(SvRV(obj));
+    if (flags & SWIG_POINTER_OWN) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+      if (!isGV(gv))
+        gv_init(gv, stash, "OWNER", 5, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newSViv(1), 0);
+    }
+    sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0);
+    SvREFCNT_dec(obj);
+    self=newRV_noinc((SV *)hash);
+    sv_setsv(sv, self);
+    SvREFCNT_dec((SV *)self);
+    sv_bless(sv, stash);
+  }
+  else {
+    sv_setref_pv(sv, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+  }
+}
+
+SWIGRUNTIMEINLINE SV *
+SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+  SV *result = sv_newmortal();
+  SWIG_MakePtr(result, ptr, t, flags);
+  return result;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) {
+  char result[1024];
+  char *r = result;
+  if ((2*sz + 1 + strlen(SWIG_Perl_TypeProxyName(type))) > 1000) return;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  strcpy(r,SWIG_Perl_TypeProxyName(type));
+  sv_setpv(sv, result);
+}
+
+SWIGRUNTIME SV *
+SWIG_Perl_NewPackedObj(SWIG_MAYBE_PERL_OBJECT void *ptr, int sz, swig_type_info *type) {
+  SV *result = sv_newmortal();
+  SWIG_Perl_MakePackedObj(result, ptr, sz, type);
+  return result;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME int
+SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty) {
+  swig_cast_info *tc;
+  const char  *c = 0;
+
+  if ((!obj) || (!SvOK(obj))) return SWIG_ERROR;
+  c = SvPV_nolen(obj);
+  /* Pointer values must start with leading underscore */
+  if (*c != '_') return SWIG_ERROR;
+  c++;
+  c = SWIG_UnpackData(c,ptr,sz);
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) return SWIG_ERROR;
+  }
+  return SWIG_OK;
+}
+
+
+/* Macros for low-level exception handling */
+#define SWIG_croak(x)    { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail; }
+
+
+typedef XSPROTO(SwigPerlWrapper);
+typedef SwigPerlWrapper *SwigPerlWrapperPtr;
+
+/* Structure for command table */
+typedef struct {
+  const char         *name;
+  SwigPerlWrapperPtr  wrapper;
+} swig_command_info;
+
+/* Information for constant table */
+
+#define SWIG_INT     1
+#define SWIG_FLOAT   2
+#define SWIG_STRING  3
+#define SWIG_POINTER 4
+#define SWIG_BINARY  5
+
+/* Constant information structure */
+typedef struct swig_constant_info {
+    int              type;
+    const char      *name;
+    long             lvalue;
+    double           dvalue;
+    void            *pvalue;
+    swig_type_info **ptype;
+} swig_constant_info;
+
+
+/* Structure for variable table */
+typedef struct {
+  const char   *name;
+  SwigMagicFunc   set;
+  SwigMagicFunc   get;
+  swig_type_info  **type;
+} swig_variable_info;
+
+/* Magic variable code */
+#ifndef PERL_OBJECT
+#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c)
+  #ifndef MULTIPLICITY
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) 
+  #else
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) 
+  #endif
+#else
+#  define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c)
+SWIGRUNTIME void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) 
+#endif
+{
+  MAGIC *mg;
+  sv_magic(sv,sv,'U',(char *) name,strlen(name));
+  mg = mg_find(sv,'U');
+  mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
+  mg->mg_virtual->svt_get = (SwigMagicFunc) get;
+  mg->mg_virtual->svt_set = (SwigMagicFunc) set;
+  mg->mg_virtual->svt_len = 0;
+  mg->mg_virtual->svt_clear = 0;
+  mg->mg_virtual->svt_free = 0;
+}
+
+
+SWIGRUNTIME swig_module_info *
+SWIG_Perl_GetModule(void) {
+  static void *type_pointer = (void *)0;
+  SV *pointer;
+
+  /* first check if pointer already created */
+  if (!type_pointer) {
+    pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE);
+    if (pointer && SvOK(pointer)) {
+      type_pointer = INT2PTR(swig_type_info **, SvIV(pointer));
+    }
+  }
+
+  return (swig_module_info *) type_pointer;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_SetModule(swig_module_info *module) {
+  SV *pointer;
+
+  /* create a new pointer */
+  pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE);
+  sv_setiv(pointer, PTR2IV(module));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Workaround perl5 global namespace pollution. Note that undefining library
+ * functions like fopen will not solve the problem on all platforms as fopen
+ * might be a macro on Windows but not necessarily on other operating systems. */
+#ifdef do_open
+  #undef do_open
+#endif
+#ifdef do_close
+  #undef do_close
+#endif
+#ifdef scalar
+  #undef scalar
+#endif
+#ifdef list
+  #undef list
+#endif
+#ifdef apply
+  #undef apply
+#endif
+#ifdef convert
+  #undef convert
+#endif
+#ifdef Error
+  #undef Error
+#endif
+#ifdef form
+  #undef form
+#endif
+#ifdef vform
+  #undef vform
+#endif
+#ifdef LABEL
+  #undef LABEL
+#endif
+#ifdef METHOD
+  #undef METHOD
+#endif
+#ifdef Move
+  #undef Move
+#endif
+#ifdef yylex
+  #undef yylex
+#endif
+#ifdef yyparse
+  #undef yyparse
+#endif
+#ifdef yyerror
+  #undef yyerror
+#endif
+#ifdef invert
+  #undef invert
+#endif
+#ifdef ref
+  #undef ref
+#endif
+#ifdef read
+  #undef read
+#endif
+#ifdef write
+  #undef write
+#endif
+#ifdef eof
+  #undef eof
+#endif
+#ifdef bool
+  #undef bool
+#endif
+#ifdef close
+  #undef close
+#endif
+#ifdef rewind
+  #undef rewind
+#endif
+#ifdef free
+  #undef free
+#endif
+#ifdef malloc
+  #undef malloc
+#endif
+#ifdef calloc
+  #undef calloc
+#endif
+#ifdef Stat
+  #undef Stat
+#endif
+#ifdef check
+  #undef check
+#endif
+#ifdef seekdir
+  #undef seekdir
+#endif
+#ifdef open
+  #undef open
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) 
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else 
+
+
+
+  #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) 
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_FILE swig_types[0]
+#define SWIGTYPE_p_GSList swig_types[1]
+#define SWIGTYPE_p_char swig_types[2]
+#define SWIGTYPE_p_double swig_types[3]
+#define SWIGTYPE_p_dumpspec_t swig_types[4]
+#define SWIGTYPE_p_find_result_t swig_types[5]
+#define SWIGTYPE_p_float swig_types[6]
+#define SWIGTYPE_p_int swig_types[7]
+#define SWIGTYPE_p_unsigned_char swig_types[8]
+static swig_type_info *swig_types[10];
+static swig_module_info swig_module = {swig_types, 9, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init    boot_Amanda__Logfile
+
+#define SWIG_name   "Amanda::Logfilec::boot_Amanda__Logfile"
+#define SWIG_prefix "Amanda::Logfilec::"
+
+#define SWIGVERSION 0x010333 
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a)) 
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) 
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifndef PERL_OBJECT
+#ifndef MULTIPLICITY
+SWIGEXPORT void SWIG_init (CV* cv);
+#else
+SWIGEXPORT void SWIG_init (pTHXo_ CV* cv);
+#endif
+#else
+SWIGEXPORT void SWIG_init (CV *cv, CPerlObj *);
+#endif
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "cmdline.h"
+
+
+typedef GSList amglue_dumpspec_list;
+
+
+#include <glib.h>
+#include "logfile.h"
+#include "find.h"
+#include "diskfile.h" /* for the gross hack, below */
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_long  SWIG_PERL_DECL_ARGS_1(long value)
+{    
+  SV *obj = sv_newmortal();
+  sv_setiv(obj, (IV) value);
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_int  SWIG_PERL_DECL_ARGS_1(int value)
+{    
+  return SWIG_From_long  SWIG_PERL_CALL_ARGS_1(value);
+}
+
+
+/* open_ and close_logfile are both simple wrappers around fopen/fclose. */
+typedef FILE loghandle;
+
+loghandle *open_logfile(char *filename) {
+    return fopen(filename, "r");
+}
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+  static int init = 0;
+  static swig_type_info* info = 0;
+  if (!init) {
+    info = SWIG_TypeQuery("_p_char");
+    init = 1;
+  }
+  return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(SV *obj, char** cptr, size_t* psize, int *alloc)
+{
+  if (SvPOK(obj)) {
+    STRLEN len = 0;
+    char *cstr = SvPV(obj, len); 
+    size_t size = len + 1;
+    if (cptr)  {
+      if (alloc) {
+       if (*alloc == SWIG_NEWOBJ) {
+         *cptr = (char *)memcpy((char *)malloc((size)*sizeof(char)), cstr, sizeof(char)*(size));
+       } else {
+         *cptr = cstr;
+         *alloc = SWIG_OLDOBJ;
+       }
+      }
+    }
+    if (psize) *psize = size;
+    return SWIG_OK;
+  } else {
+    swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+    if (pchar_descriptor) {
+      char* vptr = 0; 
+      if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_descriptor, 0) == SWIG_OK) {
+       if (cptr) *cptr = vptr;
+       if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0;
+       if (alloc) *alloc = SWIG_OLDOBJ;
+       return SWIG_OK;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+
+
+
+void close_logfile(loghandle *logfile) {
+    if (logfile) fclose(logfile);
+}
+
+
+typedef int LOGLINE_RETURN;
+
+SWIGINTERN void delete_find_result_t(find_result_t *self){
+           find_result_t *selfp = self;
+           free_find_result(&selfp);
+       }
+
+SWIGINTERNINLINE SV *
+SWIG_FromCharPtrAndSize(const char* carray, size_t size)
+{
+  SV *obj = sv_newmortal();
+  if (carray) {
+    sv_setpvn(obj, carray, size);
+  } else {
+    sv_setsv(obj, &PL_sv_undef);
+  }
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV * 
+SWIG_FromCharPtr(const char *cptr)
+{ 
+  return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0));
+}
+
+
+find_result_t *search_logfile_wrap(char *label, char *datestamp, 
+                                  char *logfile, int add_missing_disks) {
+    find_result_t *rv = NULL;
+
+    /* We use a static variable to collect any unrecognized disks */
+    static disklist_t unrecognized_disks = { NULL, NULL };
+
+    search_logfile(&rv, label, datestamp, logfile, 
+       add_missing_disks? &unrecognized_disks : NULL);
+
+    return rv;
+}
+
+
+#include <limits.h>
+#if !defined(SWIG_NO_LLONG_MAX)
+# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__)
+#   define LLONG_MAX __LONG_LONG_MAX__
+#   define LLONG_MIN (-LLONG_MAX - 1LL)
+#   define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+# endif
+#endif
+
+
+SWIGINTERN int
+SWIG_AsVal_double SWIG_PERL_DECL_ARGS_2(SV *obj, double *val)
+{
+  if (SvNIOK(obj)) {
+    if (val) *val = SvNV(obj);
+    return SWIG_OK;
+  } else if (SvIOK(obj)) {
+    if (val) *val = (double) SvIV(obj);
+    return SWIG_AddCast(SWIG_OK);
+  } else {
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      double v = strtod(nptr, &endptr);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+#include <float.h>
+
+
+#include <math.h>
+
+
+SWIGINTERNINLINE int
+SWIG_CanCastAsInteger(double *d, double min, double max) {
+  double x = *d;
+  if ((min <= x && x <= max)) {
+   double fx = floor(x);
+   double cx = ceil(x);
+   double rd =  ((x - fx) < 0.5) ? fx : cx; /* simple rint */
+   if ((errno == EDOM) || (errno == ERANGE)) {
+     errno = 0;
+   } else {
+     double summ, reps, diff;
+     if (rd < x) {
+       diff = x - rd;
+     } else if (rd > x) {
+       diff = rd - x;
+     } else {
+       return 1;
+     }
+     summ = rd + x;
+     reps = diff/summ;
+     if (reps < 8*DBL_EPSILON) {
+       *d = rd;
+       return 1;
+     }
+   }
+  }
+  return 0;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_long SWIG_PERL_DECL_ARGS_2(SV *obj, long* val)
+{
+  if (SvIOK(obj)) {
+    if (val) *val = SvIV(obj);
+    return SWIG_OK;
+  } else {
+    int dispatch = 0;
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      long v;
+      errno = 0;
+      v = strtol(nptr, &endptr,0);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+    if (!dispatch) {
+      double d;
+      int res = SWIG_AddCast(SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj,&d));
+      if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
+       if (val) *val = (long)(d);
+       return res;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_int SWIG_PERL_DECL_ARGS_2(SV * obj, int *val)
+{
+  long v;
+  int res = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v < INT_MIN || v > INT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = (int)(v);
+    }
+  }  
+  return res;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef PERL_OBJECT
+#define MAGIC_CLASS _wrap_Amanda::Logfile_var::
+class _wrap_Amanda::Logfile_var : public CPerlObj {
+public:
+#else
+#define MAGIC_CLASS
+#endif
+SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {
+    MAGIC_PPERL
+    croak("Value is read-only.");
+    return 0;
+}
+
+
+#ifdef PERL_OBJECT
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+XS(_wrap_open_logfile) {
+  {
+    char *arg1 = (char *) 0 ;
+    loghandle *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: open_logfile(filename);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "open_logfile" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (loghandle *)open_logfile(arg1);
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_FILE, 0 | 0); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_close_logfile) {
+  {
+    loghandle *arg1 = (loghandle *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: close_logfile(logfile);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_FILE, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "close_logfile" "', argument " "1"" of type '" "loghandle *""'"); 
+    }
+    arg1 = (loghandle *)(argp1);
+    close_logfile(arg1);
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_get_logline) {
+  {
+    FILE *arg1 = (FILE *) 0 ;
+    LOGLINE_RETURN result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: get_logline(logfile);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_FILE, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "get_logline" "', argument " "1"" of type '" "FILE *""'"); 
+    }
+    arg1 = (FILE *)(argp1);
+    result = get_logline(arg1);
+    {
+      if (result != 0) {
+        EXTEND(SP, 3);
+        ST(argvi) = sv_2mortal(newSViv(curlog));
+        argvi++;
+        ST(argvi) = sv_2mortal(newSViv(curprog));
+        argvi++;
+        ST(argvi) = sv_2mortal(newSVpv(curstr, 0));
+        argvi++;
+      }
+      /* otherwise (end of logfile) return an empty list */
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_delete_find_result_t) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: delete_find_result_t(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_find_result_t, SWIG_POINTER_DISOWN |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_find_result_t" "', argument " "1"" of type '" "find_result_t *""'"); 
+    }
+    arg1 = (find_result_t *)(argp1);
+    delete_find_result_t(arg1);
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_result_t_timestamp_get) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: find_result_t_timestamp_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_find_result_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "find_result_t_timestamp_get" "', argument " "1"" of type '" "find_result_t *""'"); 
+    }
+    arg1 = (find_result_t *)(argp1);
+    result = (char *) ((arg1)->timestamp);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_result_t_hostname_get) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: find_result_t_hostname_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_find_result_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "find_result_t_hostname_get" "', argument " "1"" of type '" "find_result_t *""'"); 
+    }
+    arg1 = (find_result_t *)(argp1);
+    result = (char *) ((arg1)->hostname);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_result_t_diskname_get) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: find_result_t_diskname_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_find_result_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "find_result_t_diskname_get" "', argument " "1"" of type '" "find_result_t *""'"); 
+    }
+    arg1 = (find_result_t *)(argp1);
+    result = (char *) ((arg1)->diskname);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_result_t_level_get) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    int result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: find_result_t_level_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_find_result_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "find_result_t_level_get" "', argument " "1"" of type '" "find_result_t *""'"); 
+    }
+    arg1 = (find_result_t *)(argp1);
+    result = (int) ((arg1)->level);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_result_t_label_get) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: find_result_t_label_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_find_result_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "find_result_t_label_get" "', argument " "1"" of type '" "find_result_t *""'"); 
+    }
+    arg1 = (find_result_t *)(argp1);
+    result = (char *) ((arg1)->label);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_result_t_filenum_get) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    off_t result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: find_result_t_filenum_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_find_result_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "find_result_t_filenum_get" "', argument " "1"" of type '" "find_result_t *""'"); 
+    }
+    arg1 = (find_result_t *)(argp1);
+    result =  ((arg1)->filenum);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVu64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_result_t_status_get) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: find_result_t_status_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_find_result_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "find_result_t_status_get" "', argument " "1"" of type '" "find_result_t *""'"); 
+    }
+    arg1 = (find_result_t *)(argp1);
+    result = (char *) ((arg1)->status);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_result_t_partnum_get) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: find_result_t_partnum_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_find_result_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "find_result_t_partnum_get" "', argument " "1"" of type '" "find_result_t *""'"); 
+    }
+    arg1 = (find_result_t *)(argp1);
+    result = (char *) ((arg1)->partnum);
+    ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_new_find_result_t) {
+  {
+    find_result_t *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: new_find_result_t();");
+    }
+    result = (find_result_t *)(find_result_t *) calloc(1, sizeof(find_result_t));
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_find_result_t, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_find_log) {
+  {
+    char **result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: find_log();");
+    }
+    result = (char **)find_log();
+    {
+      char **iter;
+      int len, i;
+      
+      /* measure the length of the array and make sure perl has enough room */
+      for (len=0, iter=result; *iter; iter++) len++;
+      EXTEND(SP, len);
+      
+      /* now copy it to the perl stack */
+      for (i=0, iter=result; *iter; iter++, i++) {
+        ST(argvi) = sv_2mortal(newSVpv(*iter, 0));
+        argvi++;
+      }
+    }
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_search_logfile) {
+  {
+    char *arg1 = (char *) 0 ;
+    char *arg2 = (char *) 0 ;
+    char *arg3 = (char *) 0 ;
+    int arg4 ;
+    find_result_t *result = 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int res3 ;
+    char *buf3 = 0 ;
+    int alloc3 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 4) || (items > 4)) {
+      SWIG_croak("Usage: search_logfile(label,datestamp,logfile,add_missing_disks);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "search_logfile" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "search_logfile" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    res3 = SWIG_AsCharPtrAndSize(ST(2), &buf3, NULL, &alloc3);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "search_logfile" "', argument " "3"" of type '" "char *""'");
+    }
+    arg3 = (char *)(buf3);
+    {
+      if (sizeof(signed int) == 1) {
+        arg4 = amglue_SvI8(ST(3));
+      } else if (sizeof(signed int) == 2) {
+        arg4 = amglue_SvI16(ST(3));
+      } else if (sizeof(signed int) == 4) {
+        arg4 = amglue_SvI32(ST(3));
+      } else if (sizeof(signed int) == 8) {
+        arg4 = amglue_SvI64(ST(3));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (find_result_t *)search_logfile_wrap(arg1,arg2,arg3,arg4);
+    {
+      find_result_t *iter;
+      int len;
+      
+      /* measure the list and make room on the perl stack */
+      for (len=0, iter=result; iter; iter=iter->next) len++;
+      EXTEND(SP, len);
+      
+      iter = result;
+      while (iter) {
+        find_result_t *next;
+        /* Let SWIG take ownership of the object */
+        ST(argvi) = SWIG_NewPointerObj(iter, SWIGTYPE_p_find_result_t, SWIG_OWNER | SWIG_SHADOW);
+        argvi++;
+        
+        /* null out the 'next' field */
+        next = iter->next;
+        iter->next = NULL;
+        iter = next;
+      }
+    }
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumps_match) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    char *arg2 = (char *) 0 ;
+    char *arg3 = (char *) 0 ;
+    char *arg4 = (char *) 0 ;
+    char *arg5 = (char *) 0 ;
+    int arg6 ;
+    find_result_t *result = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int res3 ;
+    char *buf3 = 0 ;
+    int alloc3 = 0 ;
+    int res4 ;
+    char *buf4 = 0 ;
+    int alloc4 = 0 ;
+    int res5 ;
+    char *buf5 = 0 ;
+    int alloc5 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 6) || (items > 6)) {
+      SWIG_croak("Usage: dumps_match(output_find,hostname,diskname,datestamp,level,ok);");
+    }
+    {
+      AV *av;
+      I32 len, i;
+      find_result_t *head = NULL, *tail = NULL;
+      
+      if (!SvROK(ST(0)) || SvTYPE(SvRV(ST(0))) != SVt_PVAV) {
+        SWIG_exception(SWIG_TypeError, "expected an arrayref of find_result_t's");
+      }
+      
+      av = (AV *)SvRV(ST(0));
+      len = av_len(av) + 1;
+      
+      for (i = 0; i < len; i++) {
+        SV **val = av_fetch(av, i, 0);
+        find_result_t *r;
+        
+        if (!val || SWIG_ConvertPtr(*val, (void **)&r, SWIGTYPE_p_find_result_t, 0) == -1) {
+          SWIG_exception(SWIG_TypeError, "array member is not a find_result_t");
+        }
+        
+        if (!head) {
+          head = tail = r;
+        } else {
+          tail->next = r;
+          tail = r;
+        }
+        
+        tail->next = NULL;
+      }
+      
+      /* point to the head of that list */
+      arg1 = head;
+    }
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumps_match" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    res3 = SWIG_AsCharPtrAndSize(ST(2), &buf3, NULL, &alloc3);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "dumps_match" "', argument " "3"" of type '" "char *""'");
+    }
+    arg3 = (char *)(buf3);
+    res4 = SWIG_AsCharPtrAndSize(ST(3), &buf4, NULL, &alloc4);
+    if (!SWIG_IsOK(res4)) {
+      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "dumps_match" "', argument " "4"" of type '" "char *""'");
+    }
+    arg4 = (char *)(buf4);
+    res5 = SWIG_AsCharPtrAndSize(ST(4), &buf5, NULL, &alloc5);
+    if (!SWIG_IsOK(res5)) {
+      SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "dumps_match" "', argument " "5"" of type '" "char *""'");
+    }
+    arg5 = (char *)(buf5);
+    {
+      if (sizeof(signed int) == 1) {
+        arg6 = amglue_SvI8(ST(5));
+      } else if (sizeof(signed int) == 2) {
+        arg6 = amglue_SvI16(ST(5));
+      } else if (sizeof(signed int) == 4) {
+        arg6 = amglue_SvI32(ST(5));
+      } else if (sizeof(signed int) == 8) {
+        arg6 = amglue_SvI64(ST(5));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (find_result_t *)dumps_match(arg1,arg2,arg3,arg4,arg5,arg6);
+    {
+      find_result_t *iter;
+      int len;
+      
+      /* measure the list and make room on the perl stack */
+      for (len=0, iter=result; iter; iter=iter->next) len++;
+      EXTEND(SP, len);
+      
+      iter = result;
+      while (iter) {
+        find_result_t *next;
+        /* Let SWIG take ownership of the object */
+        ST(argvi) = SWIG_NewPointerObj(iter, SWIGTYPE_p_find_result_t, SWIG_OWNER | SWIG_SHADOW);
+        argvi++;
+        
+        /* null out the 'next' field */
+        next = iter->next;
+        iter->next = NULL;
+        iter = next;
+      }
+    }
+    {
+      find_result_t *iter = arg1, *next;
+      
+      /* undo all the links we added earlier */
+      while (iter) {
+        next = iter->next;
+        iter->next = NULL;
+        iter = next;
+      }
+    }
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
+    if (alloc5 == SWIG_NEWOBJ) free((char*)buf5);
+    
+    XSRETURN(argvi);
+  fail:
+    {
+      find_result_t *iter = arg1, *next;
+      
+      /* undo all the links we added earlier */
+      while (iter) {
+        next = iter->next;
+        iter->next = NULL;
+        iter = next;
+      }
+    }
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
+    if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
+    if (alloc5 == SWIG_NEWOBJ) free((char*)buf5);
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumps_match_dumpspecs) {
+  {
+    find_result_t *arg1 = (find_result_t *) 0 ;
+    amglue_dumpspec_list *arg2 = (amglue_dumpspec_list *) 0 ;
+    gboolean arg3 ;
+    find_result_t *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 3) || (items > 3)) {
+      SWIG_croak("Usage: dumps_match_dumpspecs(output_find,dumpspecs,ok);");
+    }
+    {
+      AV *av;
+      I32 len, i;
+      find_result_t *head = NULL, *tail = NULL;
+      
+      if (!SvROK(ST(0)) || SvTYPE(SvRV(ST(0))) != SVt_PVAV) {
+        SWIG_exception(SWIG_TypeError, "expected an arrayref of find_result_t's");
+      }
+      
+      av = (AV *)SvRV(ST(0));
+      len = av_len(av) + 1;
+      
+      for (i = 0; i < len; i++) {
+        SV **val = av_fetch(av, i, 0);
+        find_result_t *r;
+        
+        if (!val || SWIG_ConvertPtr(*val, (void **)&r, SWIGTYPE_p_find_result_t, 0) == -1) {
+          SWIG_exception(SWIG_TypeError, "array member is not a find_result_t");
+        }
+        
+        if (!head) {
+          head = tail = r;
+        } else {
+          tail->next = r;
+          tail = r;
+        }
+        
+        tail->next = NULL;
+      }
+      
+      /* point to the head of that list */
+      arg1 = head;
+    }
+    {
+      AV *av;
+      int len;
+      int i;
+      
+      if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV) {
+        SWIG_exception_fail(SWIG_TypeError, "Expected an arrayref of dumpspecs");
+      }
+      av = (AV *)SvRV(ST(1));
+      
+      len = av_len(av)+1;
+      arg2 = NULL;
+      for (i = 0; i < len; i++) {
+        dumpspec_t *ds = NULL;
+        SV **elt = av_fetch(av, i, 0);
+        if (elt)
+        SWIG_ConvertPtr(*elt, (void **)&ds, SWIGTYPE_p_dumpspec_t, 0);
+        if (!ds)
+        SWIG_exception_fail(SWIG_TypeError, "Expected an arrayref of dumpspecs");
+        arg2 = g_slist_append(arg2, ds);
+      }
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg3 = amglue_SvI8(ST(2));
+      } else if (sizeof(signed int) == 2) {
+        arg3 = amglue_SvI16(ST(2));
+      } else if (sizeof(signed int) == 4) {
+        arg3 = amglue_SvI32(ST(2));
+      } else if (sizeof(signed int) == 8) {
+        arg3 = amglue_SvI64(ST(2));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    result = (find_result_t *)dumps_match_dumpspecs(arg1,arg2,arg3);
+    {
+      find_result_t *iter;
+      int len;
+      
+      /* measure the list and make room on the perl stack */
+      for (len=0, iter=result; iter; iter=iter->next) len++;
+      EXTEND(SP, len);
+      
+      iter = result;
+      while (iter) {
+        find_result_t *next;
+        /* Let SWIG take ownership of the object */
+        ST(argvi) = SWIG_NewPointerObj(iter, SWIGTYPE_p_find_result_t, SWIG_OWNER | SWIG_SHADOW);
+        argvi++;
+        
+        /* null out the 'next' field */
+        next = iter->next;
+        iter->next = NULL;
+        iter = next;
+      }
+    }
+    {
+      find_result_t *iter = arg1, *next;
+      
+      /* undo all the links we added earlier */
+      while (iter) {
+        next = iter->next;
+        iter->next = NULL;
+        iter = next;
+      }
+    }
+    {
+      /* Free the GSList, but not its contents (which are still owned by SWIG) */
+      g_slist_free(arg2);
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    {
+      find_result_t *iter = arg1, *next;
+      
+      /* undo all the links we added earlier */
+      while (iter) {
+        next = iter->next;
+        iter->next = NULL;
+        iter = next;
+      }
+    }
+    {
+      /* Free the GSList, but not its contents (which are still owned by SWIG) */
+      g_slist_free(arg2);
+    }
+    
+    SWIG_croak_null();
+  }
+}
+
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_FILE = {"_p_FILE", "FILE *|loghandle *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_GSList = {"_p_GSList", "amglue_dumpspec_list *|GSList *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_char = {"_p_char", "gchar *|char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_double = {"_p_double", "double *|gdouble *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_dumpspec_t = {"_p_dumpspec_t", "struct dumpspec_t *|dumpspec_t *", 0, 0, (void*)"Amanda::Cmdline::dumpspec_t", 0};
+static swig_type_info _swigt__p_find_result_t = {"_p_find_result_t", "find_result_t *", 0, 0, (void*)"Amanda::Logfile::find_result_t", 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *|gfloat *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "int *|logtype_t *|program_t *|gboolean *|cmdline_parse_dumpspecs_flags *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "guchar *|unsigned char *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_FILE,
+  &_swigt__p_GSList,
+  &_swigt__p_char,
+  &_swigt__p_double,
+  &_swigt__p_dumpspec_t,
+  &_swigt__p_find_result_t,
+  &_swigt__p_float,
+  &_swigt__p_int,
+  &_swigt__p_unsigned_char,
+};
+
+static swig_cast_info _swigc__p_FILE[] = {  {&_swigt__p_FILE, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_GSList[] = {  {&_swigt__p_GSList, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_dumpspec_t[] = {  {&_swigt__p_dumpspec_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_find_result_t[] = {  {&_swigt__p_find_result_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_char[] = {  {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_FILE,
+  _swigc__p_GSList,
+  _swigc__p_char,
+  _swigc__p_double,
+  _swigc__p_dumpspec_t,
+  _swigc__p_find_result_t,
+  _swigc__p_float,
+  _swigc__p_int,
+  _swigc__p_unsigned_char,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_constant_info swig_constants[] = {
+{0,0,0,0,0,0}
+};
+#ifdef __cplusplus
+}
+#endif
+static swig_variable_info swig_variables[] = {
+{0,0,0,0}
+};
+static swig_command_info swig_commands[] = {
+{"Amanda::Logfilec::open_logfile", _wrap_open_logfile},
+{"Amanda::Logfilec::close_logfile", _wrap_close_logfile},
+{"Amanda::Logfilec::get_logline", _wrap_get_logline},
+{"Amanda::Logfilec::delete_find_result_t", _wrap_delete_find_result_t},
+{"Amanda::Logfilec::find_result_t_timestamp_get", _wrap_find_result_t_timestamp_get},
+{"Amanda::Logfilec::find_result_t_hostname_get", _wrap_find_result_t_hostname_get},
+{"Amanda::Logfilec::find_result_t_diskname_get", _wrap_find_result_t_diskname_get},
+{"Amanda::Logfilec::find_result_t_level_get", _wrap_find_result_t_level_get},
+{"Amanda::Logfilec::find_result_t_label_get", _wrap_find_result_t_label_get},
+{"Amanda::Logfilec::find_result_t_filenum_get", _wrap_find_result_t_filenum_get},
+{"Amanda::Logfilec::find_result_t_status_get", _wrap_find_result_t_status_get},
+{"Amanda::Logfilec::find_result_t_partnum_get", _wrap_find_result_t_partnum_get},
+{"Amanda::Logfilec::new_find_result_t", _wrap_new_find_result_t},
+{"Amanda::Logfilec::find_log", _wrap_find_log},
+{"Amanda::Logfilec::search_logfile", _wrap_search_logfile},
+{"Amanda::Logfilec::dumps_match", _wrap_dumps_match},
+{"Amanda::Logfilec::dumps_match_dumpspecs", _wrap_dumps_match_dumpspecs},
+{0,0}
+};
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic 
+ * memory is used. Also, since swig_type_info structures store pointers to 
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization. 
+ * The idea is that swig generates all the structures that are needed. 
+ * The runtime then collects these partially filled structures. 
+ * The SWIG_InitializeModule function takes these initial arrays out of 
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned staticly to an initial 
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it 
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded. 
+ * There are three cases to handle:
+ *  1) If the cast->type has already been loaded AND the type we are adding
+ *     casting info to has not been loaded (it is in this module), THEN we
+ *     replace the cast->type pointer with the type pointer that has already
+ *     been loaded.
+ *  2) If BOTH types (the one we are adding casting info to, and the 
+ *     cast->type) are loaded, THEN the cast info has already been loaded by
+ *     the previous module so we just ignore it.
+ *  3) Finally, if cast->type has not already been loaded, then we add that
+ *     swig_cast_info to the linked list (because the cast->type) pointer will
+ *     be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+  size_t i;
+  swig_module_info *module_head, *iter;
+  int found;
+  
+  clientdata = clientdata;
+  
+  /* check to see if the circular list has been setup, if not, set it up */
+  if (swig_module.next==0) {
+    /* Initialize the swig_module */
+    swig_module.type_initial = swig_type_initial;
+    swig_module.cast_initial = swig_cast_initial;
+    swig_module.next = &swig_module;
+  }
+  
+  /* Try and load any already created modules */
+  module_head = SWIG_GetModule(clientdata);
+  if (!module_head) {
+    /* This is the first module loaded for this interpreter */
+    /* so set the swig module into the interpreter */
+    SWIG_SetModule(clientdata, &swig_module);
+    module_head = &swig_module;
+  } else {
+    /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+    found=0;
+    iter=module_head;
+    do {
+      if (iter==&swig_module) {
+        found=1;
+        break;
+      }
+      iter=iter->next;
+    } while (iter!= module_head);
+    
+    /* if the is found in the list, then all is done and we may leave */
+    if (found) return;
+    /* otherwise we must add out module into the list */
+    swig_module.next = module_head->next;
+    module_head->next = &swig_module;
+  }
+  
+  /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+  printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+  for (i = 0; i < swig_module.size; ++i) {
+    swig_type_info *type = 0;
+    swig_type_info *ret;
+    swig_cast_info *cast;
+    
+#ifdef SWIGRUNTIME_DEBUG
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+    
+    /* if there is another module already loaded */
+    if (swig_module.next != &swig_module) {
+      type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+    }
+    if (type) {
+      /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+      if (swig_module.type_initial[i]->clientdata) {
+        type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+      }
+    } else {
+      type = swig_module.type_initial[i];
+    }
+    
+    /* Insert casting types */
+    cast = swig_module.cast_initial[i];
+    while (cast->type) {
+      /* Don't need to add information already in the list */
+      ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+      if (swig_module.next != &swig_module) {
+        ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+        if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+      }
+      if (ret) {
+        if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+          printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+          cast->type = ret;
+          ret = 0;
+        } else {
+          /* Check for casting already in the list */
+          swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+          if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+          if (!ocast) ret = 0;
+        }
+      }
+      
+      if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+        if (type->cast) {
+          type->cast->prev = cast;
+          cast->next = type->cast;
+        }
+        type->cast = cast;
+      }
+      cast++;
+    }
+    /* Set entry in modules->types array equal to the type */
+    swig_module.types[i] = type;
+  }
+  swig_module.types[i] = 0;
+  
+#ifdef SWIGRUNTIME_DEBUG
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+  for (i = 0; i < swig_module.size; ++i) {
+    int j = 0;
+    swig_cast_info *cast = swig_module.cast_initial[i];
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+    while (cast->type) {
+      printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+      cast++;
+      ++j;
+    }
+    printf("---- Total casts: %d\n",j);
+  }
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types.  It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+  size_t i;
+  swig_cast_info *equiv;
+  static int init_run = 0;
+  
+  if (init_run) return;
+  init_run = 1;
+  
+  for (i = 0; i < swig_module.size; i++) {
+    if (swig_module.types[i]->clientdata) {
+      equiv = swig_module.types[i]->cast;
+      while (equiv) {
+        if (!equiv->converter) {
+          if (equiv->type && !equiv->type->clientdata)
+          SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+        }
+        equiv = equiv->next;
+      }
+    }
+  }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+  /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(SWIG_init) {
+  dXSARGS;
+  int i;
+  
+  SWIG_InitializeModule(0);
+  
+  /* Install commands */
+  for (i = 0; swig_commands[i].name; i++) {
+    newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__);
+  }
+  
+  /* Install variables */
+  for (i = 0; swig_variables[i].name; i++) {
+    SV *sv;
+    sv = get_sv((char*) swig_variables[i].name, TRUE | 0x2);
+    if (swig_variables[i].type) {
+      SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0);
+    } else {
+      sv_setiv(sv,(IV) 0);
+    }
+    swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); 
+  }
+  
+  /* Install constant */
+  for (i = 0; swig_constants[i].type; i++) {
+    SV *sv;
+    sv = get_sv((char*)swig_constants[i].name, TRUE | 0x2);
+    switch(swig_constants[i].type) {
+    case SWIG_INT:
+      sv_setiv(sv, (IV) swig_constants[i].lvalue);
+      break;
+    case SWIG_FLOAT:
+      sv_setnv(sv, (double) swig_constants[i].dvalue);
+      break;
+    case SWIG_STRING:
+      sv_setpv(sv, (char *) swig_constants[i].pvalue);
+      break;
+    case SWIG_POINTER:
+      SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
+      break;
+    case SWIG_BINARY:
+      SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
+      break;
+    default:
+      break;
+    }
+    SvREADONLY_on(sv);
+  }
+  
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_BOGUS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_BOGUS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_FATAL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_FATAL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_ERROR", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_ERROR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_WARNING", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_WARNING)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_INFO", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_INFO)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_SUMMARY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_SUMMARY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_START", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_START)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_FINISH", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_FINISH)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_DISK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_DISK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_DONE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_DONE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_PART", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_PART)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_PARTPARTIAL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_PARTPARTIAL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_SUCCESS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_SUCCESS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_PARTIAL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_PARTIAL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_FAIL", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_FAIL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_STRANGE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_STRANGE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_CHUNK", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_CHUNK)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_CHUNKSUCCESS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_CHUNKSUCCESS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_STATS", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_STATS)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_MARKER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_MARKER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "L_CONT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(L_CONT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "P_UNKNOWN", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(P_UNKNOWN)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "P_PLANNER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(P_PLANNER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "P_DRIVER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(P_DRIVER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "P_REPORTER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(P_REPORTER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "P_DUMPER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(P_DUMPER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "P_CHUNKER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(P_CHUNKER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "P_TAPER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(P_TAPER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "P_AMFLUSH", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(P_AMFLUSH)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  SWIG_TypeClientData(SWIGTYPE_p_find_result_t, (void*) "Amanda::Logfile::find_result_t");
+  ST(0) = &PL_sv_yes;
+  XSRETURN(1);
+}
+
diff --git a/perl/Amanda/Logfile.pm b/perl/Amanda/Logfile.pm
new file mode 100644 (file)
index 0000000..4bec9e9
--- /dev/null
@@ -0,0 +1,466 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 1.3.33
+#
+# Don't modify this file, modify the SWIG interface instead.
+
+package Amanda::Logfile;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+require Amanda::Cmdline;
+package Amanda::Logfilec;
+bootstrap Amanda::Logfile;
+package Amanda::Logfile;
+@EXPORT = qw( );
+
+# ---------- BASE METHODS -------------
+
+package Amanda::Logfile;
+
+sub TIEHASH {
+    my ($classname,$obj) = @_;
+    return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+    my ($self,$field) = @_;
+    my $member_func = "swig_${field}_get";
+    $self->$member_func();
+}
+
+sub STORE {
+    my ($self,$field,$newval) = @_;
+    my $member_func = "swig_${field}_set";
+    $self->$member_func($newval);
+}
+
+sub this {
+    my $ptr = shift;
+    return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package Amanda::Logfile;
+
+*open_logfile = *Amanda::Logfilec::open_logfile;
+*close_logfile = *Amanda::Logfilec::close_logfile;
+*get_logline = *Amanda::Logfilec::get_logline;
+*find_log = *Amanda::Logfilec::find_log;
+*search_logfile = *Amanda::Logfilec::search_logfile;
+*dumps_match = *Amanda::Logfilec::dumps_match;
+*dumps_match_dumpspecs = *Amanda::Logfilec::dumps_match_dumpspecs;
+
+############# Class : Amanda::Logfile::find_result_t ##############
+
+package Amanda::Logfile::find_result_t;
+use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
+@ISA = qw( Amanda::Logfile );
+%OWNER = ();
+%ITERATORS = ();
+sub DESTROY {
+    return unless $_[0]->isa('HASH');
+    my $self = tied(%{$_[0]});
+    return unless defined $self;
+    delete $ITERATORS{$self};
+    if (exists $OWNER{$self}) {
+        Amanda::Logfilec::delete_find_result_t($self);
+        delete $OWNER{$self};
+    }
+}
+
+*swig_timestamp_get = *Amanda::Logfilec::find_result_t_timestamp_get;
+*swig_timestamp_set = *Amanda::Logfilec::find_result_t_timestamp_set;
+*swig_hostname_get = *Amanda::Logfilec::find_result_t_hostname_get;
+*swig_hostname_set = *Amanda::Logfilec::find_result_t_hostname_set;
+*swig_diskname_get = *Amanda::Logfilec::find_result_t_diskname_get;
+*swig_diskname_set = *Amanda::Logfilec::find_result_t_diskname_set;
+*swig_level_get = *Amanda::Logfilec::find_result_t_level_get;
+*swig_level_set = *Amanda::Logfilec::find_result_t_level_set;
+*swig_label_get = *Amanda::Logfilec::find_result_t_label_get;
+*swig_label_set = *Amanda::Logfilec::find_result_t_label_set;
+*swig_filenum_get = *Amanda::Logfilec::find_result_t_filenum_get;
+*swig_filenum_set = *Amanda::Logfilec::find_result_t_filenum_set;
+*swig_status_get = *Amanda::Logfilec::find_result_t_status_get;
+*swig_status_set = *Amanda::Logfilec::find_result_t_status_set;
+*swig_partnum_get = *Amanda::Logfilec::find_result_t_partnum_get;
+*swig_partnum_set = *Amanda::Logfilec::find_result_t_partnum_set;
+sub new {
+    my $pkg = shift;
+    my $self = Amanda::Logfilec::new_find_result_t(@_);
+    bless $self, $pkg if defined($self);
+}
+
+sub DISOWN {
+    my $self = shift;
+    my $ptr = tied(%$self);
+    delete $OWNER{$ptr};
+}
+
+sub ACQUIRE {
+    my $self = shift;
+    my $ptr = tied(%$self);
+    $OWNER{$ptr} = 1;
+}
+
+
+# ------- VARIABLE STUBS --------
+
+package Amanda::Logfile;
+
+*L_BOGUS = *Amanda::Logfilec::L_BOGUS;
+*L_FATAL = *Amanda::Logfilec::L_FATAL;
+*L_ERROR = *Amanda::Logfilec::L_ERROR;
+*L_WARNING = *Amanda::Logfilec::L_WARNING;
+*L_INFO = *Amanda::Logfilec::L_INFO;
+*L_SUMMARY = *Amanda::Logfilec::L_SUMMARY;
+*L_START = *Amanda::Logfilec::L_START;
+*L_FINISH = *Amanda::Logfilec::L_FINISH;
+*L_DISK = *Amanda::Logfilec::L_DISK;
+*L_DONE = *Amanda::Logfilec::L_DONE;
+*L_PART = *Amanda::Logfilec::L_PART;
+*L_PARTPARTIAL = *Amanda::Logfilec::L_PARTPARTIAL;
+*L_SUCCESS = *Amanda::Logfilec::L_SUCCESS;
+*L_PARTIAL = *Amanda::Logfilec::L_PARTIAL;
+*L_FAIL = *Amanda::Logfilec::L_FAIL;
+*L_STRANGE = *Amanda::Logfilec::L_STRANGE;
+*L_CHUNK = *Amanda::Logfilec::L_CHUNK;
+*L_CHUNKSUCCESS = *Amanda::Logfilec::L_CHUNKSUCCESS;
+*L_STATS = *Amanda::Logfilec::L_STATS;
+*L_MARKER = *Amanda::Logfilec::L_MARKER;
+*L_CONT = *Amanda::Logfilec::L_CONT;
+*P_UNKNOWN = *Amanda::Logfilec::P_UNKNOWN;
+*P_PLANNER = *Amanda::Logfilec::P_PLANNER;
+*P_DRIVER = *Amanda::Logfilec::P_DRIVER;
+*P_REPORTER = *Amanda::Logfilec::P_REPORTER;
+*P_DUMPER = *Amanda::Logfilec::P_DUMPER;
+*P_CHUNKER = *Amanda::Logfilec::P_CHUNKER;
+*P_TAPER = *Amanda::Logfilec::P_TAPER;
+*P_AMFLUSH = *Amanda::Logfilec::P_AMFLUSH;
+
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+
+=head1 NAME
+
+Amanda::Logfile - manage Amanda trace logs
+
+=head1 SYNOPSIS
+
+  use Amanda::Logfile qw(:logtype_t); # XXX change
+  use Amanda::Config qw( :getconf config_dir_relative );
+
+  for my $logfile (Amanda::Logfile::find_log()) {
+    $logfile = config_dir_relative(getconf($CNF_LOGDIR)) . "/" . $logfile;
+
+    my $hdl = Amanda::Logfile::open_logfile($logfile);
+    while (my ($type, $prog, $str) = Amanda::Logfile::get_logline($hdl)) {
+      if ($type == $L_INFO) {
+        my $pname = Amanda::Logfile::program_t_to_string($prog);
+        print "Found info line from $pname: $str\n";
+      }
+    }
+    Amanda::Logfile::close_logfile($log);
+
+    my @dumps = Amanda::Logfile::search_logfile("TapeLabel-001", "19780615", $logfile);
+
+    my @matching = Amanda::Logfile::dumps_match([@dumps], "myhost", "/usr", undef, undef, 0);
+    for my $dump (@matching) {
+      print "$dump->{'label'}:$dump->{'filenum'} = $dump->{'hostname'}:$dump->{'disk'}\n";
+    }
+  }
+
+=head1 API STATUS
+
+Stabilizing
+
+=head1 RAW LOGFILE ACCESS
+
+This section corresponds to the C C<logfile> module. 
+
+Raw access to logfiles is accomplished by opening a logfile and
+fetching log lines one by one via the C<get_logline> function.
+
+A log line is represented by a list C<($type, $prog, $string)>
+where C<$type> is one of the C<L_*> constants (available in export
+tag C<logtype_t>), C<$prog> is one of the C<P_*> constants (available
+in export tag C<program_t>), and C<$str> is the remainder of the line.
+
+Both families of constants can be converted to symbolic names with
+C<logtype_t_to_string> and C<program_t_to_string>, respectively.
+
+=head2 FUNCTIONS
+
+=over
+
+=item C<open_logfile($filename)>
+
+Opens a logfile for reading, returning an opaque log file handle.
+
+=item C<close_logfile($handle)>
+
+Closes a log file handle.
+
+=item C<get_logline($handle)>
+
+Return a list as described above representing the next log line in
+C<$handle>, or nothing at the end of the logfile. 
+
+=back
+
+All of these functions can be imported by name if desired.
+
+=head1 Amanda::Find::find_result_t objects
+
+These objects contain information about dumps, as read from logfiles.
+Instance variables are:
+
+=over
+
+=item C<$timestamp>
+
+=item C<$hostname>
+
+=item C<$diskname>
+
+=item C<$level>
+
+=item C<$label>
+
+=item C<$filenum>
+
+=item C<$status>
+
+=item C<$partnum>
+
+=back
+
+=head1 HIGHER-LEVEL FUNCTIONS
+
+Functions in this section extract information from logfiles.
+
+=over
+
+=item C<find_log()>
+
+Return a list of logfiles for active tapes.  The tapelist must be loaded before
+this function is called (see L<Amanda::Tapefile>, and note that this module will be
+renamed to L<Amanda::Tapelist> in Amanda-2.6.1).
+
+=item C<search_logfile($label, $datestamp, $logfile, $add_missing_disks)>
+
+Return all results in C<$logfile> matching C<$label> and C<$datestamp>.
+If C<$add_missing_disks> is true, then any disks in the logfile
+not present in the disklist are added to the disklist; otherwise,
+such dumps are skipped.
+
+=item C<dumps_match([@results], $hostname, $diskname, $datestamp, $level, $ok)>
+
+Return a filtered version of C<@results> containing only results that match the 
+given expressions.  If C<$ok> is true, don't match partial results.  Note that
+C<$level> is given as a string, since it is a match expression.
+
+All of these functions can be imported by name.
+
+=back
+
+=cut
+
+push @EXPORT_OK, qw(open_logfile get_logline close_logfile);
+
+push @EXPORT_OK, qw(logtype_t_to_string);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw(logtype_t_to_string);
+
+my %_logtype_t_VALUES;
+#Convert an enum value to a single string
+sub logtype_t_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_logtype_t_VALUES) {
+       my $v = $_logtype_t_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($L_BOGUS);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_BOGUS);
+
+$_logtype_t_VALUES{"L_BOGUS"} = $L_BOGUS;
+
+push @EXPORT_OK, qw($L_FATAL);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_FATAL);
+
+$_logtype_t_VALUES{"L_FATAL"} = $L_FATAL;
+
+push @EXPORT_OK, qw($L_ERROR);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_ERROR);
+
+$_logtype_t_VALUES{"L_ERROR"} = $L_ERROR;
+
+push @EXPORT_OK, qw($L_WARNING);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_WARNING);
+
+$_logtype_t_VALUES{"L_WARNING"} = $L_WARNING;
+
+push @EXPORT_OK, qw($L_INFO);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_INFO);
+
+$_logtype_t_VALUES{"L_INFO"} = $L_INFO;
+
+push @EXPORT_OK, qw($L_SUMMARY);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_SUMMARY);
+
+$_logtype_t_VALUES{"L_SUMMARY"} = $L_SUMMARY;
+
+push @EXPORT_OK, qw($L_START);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_START);
+
+$_logtype_t_VALUES{"L_START"} = $L_START;
+
+push @EXPORT_OK, qw($L_FINISH);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_FINISH);
+
+$_logtype_t_VALUES{"L_FINISH"} = $L_FINISH;
+
+push @EXPORT_OK, qw($L_DISK);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_DISK);
+
+$_logtype_t_VALUES{"L_DISK"} = $L_DISK;
+
+push @EXPORT_OK, qw($L_DONE);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_DONE);
+
+$_logtype_t_VALUES{"L_DONE"} = $L_DONE;
+
+push @EXPORT_OK, qw($L_PART);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_PART);
+
+$_logtype_t_VALUES{"L_PART"} = $L_PART;
+
+push @EXPORT_OK, qw($L_PARTPARTIAL);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_PARTPARTIAL);
+
+$_logtype_t_VALUES{"L_PARTPARTIAL"} = $L_PARTPARTIAL;
+
+push @EXPORT_OK, qw($L_SUCCESS);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_SUCCESS);
+
+$_logtype_t_VALUES{"L_SUCCESS"} = $L_SUCCESS;
+
+push @EXPORT_OK, qw($L_PARTIAL);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_PARTIAL);
+
+$_logtype_t_VALUES{"L_PARTIAL"} = $L_PARTIAL;
+
+push @EXPORT_OK, qw($L_FAIL);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_FAIL);
+
+$_logtype_t_VALUES{"L_FAIL"} = $L_FAIL;
+
+push @EXPORT_OK, qw($L_STRANGE);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_STRANGE);
+
+$_logtype_t_VALUES{"L_STRANGE"} = $L_STRANGE;
+
+push @EXPORT_OK, qw($L_CHUNK);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_CHUNK);
+
+$_logtype_t_VALUES{"L_CHUNK"} = $L_CHUNK;
+
+push @EXPORT_OK, qw($L_CHUNKSUCCESS);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_CHUNKSUCCESS);
+
+$_logtype_t_VALUES{"L_CHUNKSUCCESS"} = $L_CHUNKSUCCESS;
+
+push @EXPORT_OK, qw($L_STATS);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_STATS);
+
+$_logtype_t_VALUES{"L_STATS"} = $L_STATS;
+
+push @EXPORT_OK, qw($L_MARKER);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_MARKER);
+
+$_logtype_t_VALUES{"L_MARKER"} = $L_MARKER;
+
+push @EXPORT_OK, qw($L_CONT);
+push @{$EXPORT_TAGS{"logtype_t"}}, qw($L_CONT);
+
+$_logtype_t_VALUES{"L_CONT"} = $L_CONT;
+
+push @EXPORT_OK, qw(program_t_to_string);
+push @{$EXPORT_TAGS{"program_t"}}, qw(program_t_to_string);
+
+my %_program_t_VALUES;
+#Convert an enum value to a single string
+sub program_t_to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_program_t_VALUES) {
+       my $v = $_program_t_VALUES{$k};
+
+       #is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+#default, just return the number
+    return $enumval;
+}
+
+push @EXPORT_OK, qw($P_UNKNOWN);
+push @{$EXPORT_TAGS{"program_t"}}, qw($P_UNKNOWN);
+
+$_program_t_VALUES{"P_UNKNOWN"} = $P_UNKNOWN;
+
+push @EXPORT_OK, qw($P_PLANNER);
+push @{$EXPORT_TAGS{"program_t"}}, qw($P_PLANNER);
+
+$_program_t_VALUES{"P_PLANNER"} = $P_PLANNER;
+
+push @EXPORT_OK, qw($P_DRIVER);
+push @{$EXPORT_TAGS{"program_t"}}, qw($P_DRIVER);
+
+$_program_t_VALUES{"P_DRIVER"} = $P_DRIVER;
+
+push @EXPORT_OK, qw($P_REPORTER);
+push @{$EXPORT_TAGS{"program_t"}}, qw($P_REPORTER);
+
+$_program_t_VALUES{"P_REPORTER"} = $P_REPORTER;
+
+push @EXPORT_OK, qw($P_DUMPER);
+push @{$EXPORT_TAGS{"program_t"}}, qw($P_DUMPER);
+
+$_program_t_VALUES{"P_DUMPER"} = $P_DUMPER;
+
+push @EXPORT_OK, qw($P_CHUNKER);
+push @{$EXPORT_TAGS{"program_t"}}, qw($P_CHUNKER);
+
+$_program_t_VALUES{"P_CHUNKER"} = $P_CHUNKER;
+
+push @EXPORT_OK, qw($P_TAPER);
+push @{$EXPORT_TAGS{"program_t"}}, qw($P_TAPER);
+
+$_program_t_VALUES{"P_TAPER"} = $P_TAPER;
+
+push @EXPORT_OK, qw($P_AMFLUSH);
+push @{$EXPORT_TAGS{"program_t"}}, qw($P_AMFLUSH);
+
+$_program_t_VALUES{"P_AMFLUSH"} = $P_AMFLUSH;
+
+push @EXPORT_OK, qw(find_log search_logfile dumps_match);
+1;
diff --git a/perl/Amanda/Logfile.swg b/perl/Amanda/Logfile.swg
new file mode 100644 (file)
index 0000000..cab431a
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%module "Amanda::Logfile"
+%include "amglue/amglue.swg"
+%include "exception.i"
+%include "amglue/dumpspecs.swg"
+%import "Amanda/Cmdline.swg"
+
+%{
+#include <glib.h>
+#include "logfile.h"
+#include "find.h"
+#include "diskfile.h" /* for the gross hack, below */
+%}
+
+%perlcode %{
+=head1 NAME
+
+Amanda::Logfile - manage Amanda trace logs
+
+=head1 SYNOPSIS
+
+  use Amanda::Logfile qw(:logtype_t); # XXX change
+  use Amanda::Config qw( :getconf config_dir_relative );
+
+  for my $logfile (Amanda::Logfile::find_log()) {
+    $logfile = config_dir_relative(getconf($CNF_LOGDIR)) . "/" . $logfile;
+
+    my $hdl = Amanda::Logfile::open_logfile($logfile);
+    while (my ($type, $prog, $str) = Amanda::Logfile::get_logline($hdl)) {
+      if ($type == $L_INFO) {
+        my $pname = Amanda::Logfile::program_t_to_string($prog);
+        print "Found info line from $pname: $str\n";
+      }
+    }
+    Amanda::Logfile::close_logfile($log);
+
+    my @dumps = Amanda::Logfile::search_logfile("TapeLabel-001", "19780615", $logfile);
+
+    my @matching = Amanda::Logfile::dumps_match([@dumps], "myhost", "/usr", undef, undef, 0);
+    for my $dump (@matching) {
+      print "$dump->{'label'}:$dump->{'filenum'} = $dump->{'hostname'}:$dump->{'disk'}\n";
+    }
+  }
+
+=head1 API STATUS
+
+Stabilizing
+
+=head1 RAW LOGFILE ACCESS
+
+This section corresponds to the C C<logfile> module. 
+
+Raw access to logfiles is accomplished by opening a logfile and
+fetching log lines one by one via the C<get_logline> function.
+
+A log line is represented by a list C<($type, $prog, $string)>
+where C<$type> is one of the C<L_*> constants (available in export
+tag C<logtype_t>), C<$prog> is one of the C<P_*> constants (available
+in export tag C<program_t>), and C<$str> is the remainder of the line.
+
+Both families of constants can be converted to symbolic names with
+C<logtype_t_to_string> and C<program_t_to_string>, respectively.
+
+=head2 FUNCTIONS
+
+=over
+
+=item C<open_logfile($filename)>
+
+Opens a logfile for reading, returning an opaque log file handle.
+
+=item C<close_logfile($handle)>
+
+Closes a log file handle.
+
+=item C<get_logline($handle)>
+
+Return a list as described above representing the next log line in
+C<$handle>, or nothing at the end of the logfile. 
+
+=back
+
+All of these functions can be imported by name if desired.
+
+=head1 Amanda::Find::find_result_t objects
+
+These objects contain information about dumps, as read from logfiles.
+Instance variables are:
+
+=over
+
+=item C<$timestamp>
+
+=item C<$hostname>
+
+=item C<$diskname>
+
+=item C<$level>
+
+=item C<$label>
+
+=item C<$filenum>
+
+=item C<$status>
+
+=item C<$partnum>
+
+=back
+
+=head1 HIGHER-LEVEL FUNCTIONS
+
+Functions in this section extract information from logfiles.
+
+=over
+
+=item C<find_log()>
+
+Return a list of logfiles for active tapes.  The tapelist must be loaded before
+this function is called (see L<Amanda::Tapefile>, and note that this module will be
+renamed to L<Amanda::Tapelist> in Amanda-2.6.1).
+
+=item C<search_logfile($label, $datestamp, $logfile, $add_missing_disks)>
+
+Return all results in C<$logfile> matching C<$label> and C<$datestamp>.
+If C<$add_missing_disks> is true, then any disks in the logfile
+not present in the disklist are added to the disklist; otherwise,
+such dumps are skipped.
+
+=item C<dumps_match([@results], $hostname, $diskname, $datestamp, $level, $ok)>
+
+Return a filtered version of C<@results> containing only results that match the 
+given expressions.  If C<$ok> is true, don't match partial results.  Note that
+C<$level> is given as a string, since it is a match expression.
+
+All of these functions can be imported by name.
+
+=back
+
+=cut
+%}
+
+amglue_export_ok(
+    open_logfile get_logline close_logfile
+);
+
+
+amglue_add_enum_tag_fns(logtype_t);
+amglue_add_constant(L_BOGUS, logtype_t);
+amglue_add_constant(L_FATAL, logtype_t);
+amglue_add_constant(L_ERROR, logtype_t);
+amglue_add_constant(L_WARNING, logtype_t);
+amglue_add_constant(L_INFO, logtype_t);
+amglue_add_constant(L_SUMMARY, logtype_t);
+amglue_add_constant(L_START, logtype_t);
+amglue_add_constant(L_FINISH, logtype_t);
+amglue_add_constant(L_DISK, logtype_t);
+amglue_add_constant(L_DONE, logtype_t);
+amglue_add_constant(L_PART, logtype_t);
+amglue_add_constant(L_PARTPARTIAL, logtype_t);
+amglue_add_constant(L_SUCCESS, logtype_t);
+amglue_add_constant(L_PARTIAL, logtype_t);
+amglue_add_constant(L_FAIL, logtype_t);
+amglue_add_constant(L_STRANGE, logtype_t);
+amglue_add_constant(L_CHUNK, logtype_t);
+amglue_add_constant(L_CHUNKSUCCESS, logtype_t);
+amglue_add_constant(L_STATS, logtype_t);
+amglue_add_constant(L_MARKER, logtype_t);
+amglue_add_constant(L_CONT, logtype_t);
+
+amglue_add_enum_tag_fns(program_t);
+amglue_add_constant(P_UNKNOWN, program_t);
+amglue_add_constant(P_PLANNER, program_t);
+amglue_add_constant(P_DRIVER, program_t);
+amglue_add_constant(P_REPORTER, program_t);
+amglue_add_constant(P_DUMPER, program_t);
+amglue_add_constant(P_CHUNKER, program_t);
+amglue_add_constant(P_TAPER, program_t);
+amglue_add_constant(P_AMFLUSH, program_t);
+
+/* TODO: support for writing logfiles is omitted for the moment. */
+
+%inline %{
+/* open_ and close_logfile are both simple wrappers around fopen/fclose. */
+typedef FILE loghandle;
+
+loghandle *open_logfile(char *filename) {
+    return fopen(filename, "r");
+}
+%}
+
+%inline %{
+void close_logfile(loghandle *logfile) {
+    if (logfile) fclose(logfile);
+}
+%}
+
+/* We fake the return type of get_logline, and use a typemap to
+ * slurp curstr, curprog, and curlog into a return value.  */
+%{
+typedef int LOGLINE_RETURN;
+%}
+%typemap(out) LOGLINE_RETURN {
+    if ($1 != 0) {
+       EXTEND(SP, 3);
+       $result = sv_2mortal(newSViv(curlog));
+       argvi++;
+       $result = sv_2mortal(newSViv(curprog));
+       argvi++;
+       $result = sv_2mortal(newSVpv(curstr, 0));
+       argvi++;
+    }
+    /* otherwise (end of logfile) return an empty list */
+}
+LOGLINE_RETURN get_logline(FILE *logfile);
+
+typedef struct {
+    %extend {
+       /* destructor */
+       ~find_result_t() {
+           find_result_t *selfp = self;
+           free_find_result(&selfp);
+       }
+    }
+
+    %immutable;
+    char *timestamp;
+    char *hostname;
+    char *diskname;
+    int level;
+    char *label;
+    off_t filenum;
+    char *status;
+    char *partnum;
+    %mutable;
+} find_result_t;
+
+/* This typemap is used in a few functions.  It converts a linked list of find_result_t's
+ * into an array of same, de-linking the list in the process.  This gives ownership of the
+ * objects to perl, which is consistent with the C interface to this module.
+ */
+%typemap(out) find_result_t * {
+    find_result_t *iter;
+    int len;
+
+    /* measure the list and make room on the perl stack */
+    for (len=0, iter=$1; iter; iter=iter->next) len++;
+    EXTEND(SP, len);
+
+    iter = $1;
+    while (iter) {
+       find_result_t *next;
+       /* Let SWIG take ownership of the object */
+       $result = SWIG_NewPointerObj(iter, $descriptor(find_result_t *), SWIG_OWNER | SWIG_SHADOW);
+       argvi++;
+
+       /* null out the 'next' field */
+       next = iter->next;
+       iter->next = NULL;
+       iter = next;
+    }
+}
+
+/* Similarly, on input we link an array full of find_result_t's.  The list is then
+ * unlinked on return.  Note that the array is supplied as an arrayref (since it's 
+ * usually the first argument).
+ */
+%typemap(in) find_result_t * {
+    AV *av;
+    I32 len, i;
+    find_result_t *head = NULL, *tail = NULL;
+
+    if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
+       SWIG_exception(SWIG_TypeError, "expected an arrayref of find_result_t's");
+    }
+
+    av = (AV *)SvRV($input);
+    len = av_len(av) + 1;
+
+    for (i = 0; i < len; i++) {
+       SV **val = av_fetch(av, i, 0);
+       find_result_t *r;
+
+       if (!val || SWIG_ConvertPtr(*val, (void **)&r, $descriptor(find_result_t *), 0) == -1) {
+           SWIG_exception(SWIG_TypeError, "array member is not a find_result_t");
+       }
+
+       if (!head) {
+           head = tail = r;
+       } else {
+           tail->next = r;
+           tail = r;
+       }
+
+       tail->next = NULL;
+    }
+
+    /* point to the head of that list */
+    $1 = head;
+}
+
+%typemap(freearg) find_result_t * {
+    find_result_t *iter = $1, *next;
+
+    /* undo all the links we added earlier */
+    while (iter) {
+       next = iter->next;
+       iter->next = NULL;
+       iter = next;
+    }
+}
+
+%typemap(out) char ** {
+    char **iter;
+    int len, i;
+    
+    /* measure the length of the array and make sure perl has enough room */
+    for (len=0, iter=$1; *iter; iter++) len++;
+    EXTEND(SP, len);
+
+    /* now copy it to the perl stack */
+    for (i=0, iter=$1; *iter; iter++, i++) {
+       $result = sv_2mortal(newSVpv(*iter, 0));
+       argvi++;
+    }
+}
+
+amglue_export_ok(
+    find_log search_logfile dumps_match
+);
+
+char **find_log(void);
+
+%rename(search_logfile) search_logfile_wrap;
+%inline %{
+find_result_t *search_logfile_wrap(char *label, char *datestamp, 
+                                  char *logfile, int add_missing_disks) {
+    find_result_t *rv = NULL;
+
+    /* We use a static variable to collect any unrecognized disks */
+    static disklist_t unrecognized_disks = { NULL, NULL };
+
+    search_logfile(&rv, label, datestamp, logfile, 
+       add_missing_disks? &unrecognized_disks : NULL);
+
+    return rv;
+}
+%}
+
+find_result_t *dumps_match(find_result_t *output_find, char *hostname,
+                          char *diskname, char *datestamp, char *level, int ok);
+
+find_result_t *dumps_match_dumpspecs(find_result_t *output_find,
+    amglue_dumpspec_list *dumpspecs,
+    gboolean ok);
diff --git a/perl/Amanda/Paths.pm.in b/perl/Amanda/Paths.pm.in
new file mode 100644 (file)
index 0000000..501bffa
--- /dev/null
@@ -0,0 +1,81 @@
+# vim:ft=perl
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+package Amanda::Paths;
+
+=head1 NAME
+
+Amanda::Paths - perl access to build-time configuration values
+
+=head1 SYNOPSIS
+
+  use Amanda::Paths;
+
+  my $filename = "$amlibexecdir/foo/bar";
+
+This package is a means of getting all of the necessary variables provided
+by configure into Perl scripts, without a bunch of boilerplate, and without
+requiring config.status substitution for every .pm file.
+
+All of the variables in @EXPORT will be automatically imported into
+your module's namespace.  See the source, rather than the perldoc,
+to find out what variables are available.
+
+=cut
+
+use Exporter;
+@ISA = qw( Exporter );
+
+@EXPORT = qw(
+    $prefix
+    $exec_prefix
+    $bindir
+    $sbindir
+    $libexecdir
+    $amlibexecdir
+    $mandir
+    $datarootdir
+
+    $AMANDA_TMPDIR
+    $CONFIG_DIR
+    $AMANDA_DBGDIR
+);
+
+# the 'warnings' pragma doesn't recognized exported variables as "used", and generates warnings
+# for variables only used once.  We turn it off for this module.
+no warnings;
+
+## basic filesystem layout
+
+# these need to go in order, due to the way autoconf sets these dirs up
+$prefix = "@prefix@";
+$exec_prefix = "@exec_prefix@";
+$bindir = "@bindir@";
+$sbindir = "@sbindir@";
+$libexecdir = "@libexecdir@";
+$amlibexecdir = "@amlibexecdir@";
+$mandir = "@mandir@";
+# (config.status worries if it doesn't see this:)
+$datarootdir = "@datarootdir@";
+
+## amanda configuration directories
+
+$AMANDA_TMPDIR = "@AMANDA_TMPDIR@";
+$CONFIG_DIR = "@CONFIG_DIR@";
+$AMANDA_DBGDIR = "@AMANDA_DBGDIR@";
diff --git a/perl/Amanda/Tapefile.c b/perl/Amanda/Tapefile.c
new file mode 100644 (file)
index 0000000..9f5c2fb
--- /dev/null
@@ -0,0 +1,1922 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.33
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPERL
+#define SWIG_CASTRANK_MODE
+/* -----------------------------------------------------------------------------
+ *  This section contains generic SWIG labels for method/variable
+ *  declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+#  define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+#   define SWIGINLINE inline
+# else
+#   define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define SWIGUNUSED __attribute__ ((__unused__)) 
+#   else
+#     define SWIGUNUSED
+#   endif
+# elif defined(__ICC)
+#   define SWIGUNUSED __attribute__ ((__unused__)) 
+# else
+#   define SWIGUNUSED 
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+#   define SWIGUNUSEDPARM(p)
+# else
+#   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#  ifndef GCC_HASCLASSVISIBILITY
+#    define GCC_HASCLASSVISIBILITY
+#  endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   if defined(STATIC_LINKED)
+#     define SWIGEXPORT
+#   else
+#     define SWIGEXPORT __declspec(dllexport)
+#   endif
+# else
+#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+#     define SWIGEXPORT __attribute__ ((visibility("default")))
+#   else
+#     define SWIGEXPORT
+#   endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   define SWIGSTDCALL __stdcall
+# else
+#   define SWIGSTDCALL
+# endif 
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+   or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "3"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+  You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+  creating a static or dynamic library from the swig runtime code.
+  In 99.9% of the cases, swig just needs to declare them as 'static'.
+  
+  But only do this if is strictly necessary, ie, if you have problems
+  with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/*  Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN        0x1
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN           0x1
+
+
+/* 
+   Flags/methods for returning states.
+   
+   The swig conversion methods, as ConvertPtr, return and integer 
+   that tells if the conversion was successful or not. And if not,
+   an error code can be returned (see swigerrors.swg for the codes).
+   
+   Use the following macros/flags to set or process the returning
+   states.
+   
+   In old swig versions, you usually write code as:
+
+     if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+       // success code
+     } else {
+       //fail code
+     }
+
+   Now you can be more explicit as:
+
+    int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+    } else {
+      // fail code
+    }
+
+   that seems to be the same, but now you can also do
+
+    Type *ptr;
+    int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+      if (SWIG_IsNewObj(res) {
+        ...
+       delete *ptr;
+      } else {
+        ...
+      }
+    } else {
+      // fail code
+    }
+    
+   I.e., now SWIG_ConvertPtr can return new objects and you can
+   identify the case and take care of the deallocation. Of course that
+   requires also to SWIG_ConvertPtr to return new result values, as
+
+      int SWIG_ConvertPtr(obj, ptr,...) {         
+        if (<obj is ok>) {                            
+          if (<need new object>) {                    
+            *ptr = <ptr to new allocated object>; 
+            return SWIG_NEWOBJ;                       
+          } else {                                    
+            *ptr = <ptr to old object>;               
+            return SWIG_OLDOBJ;                       
+          }                                   
+        } else {                                      
+          return SWIG_BADOBJ;                 
+        }                                             
+      }
+
+   Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+   more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+   swig errors code.
+
+   Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+   allows to return the 'cast rank', for example, if you have this
+
+       int food(double)
+       int fooi(int);
+
+   and you call
+      food(1)   // cast rank '1'  (1 -> 1.0)
+      fooi(1)   // cast rank '0'
+
+   just use the SWIG_AddCast()/SWIG_CheckState()
+
+
+ */
+#define SWIG_OK                    (0) 
+#define SWIG_ERROR                 (-1)
+#define SWIG_IsOK(r)               (r >= 0)
+#define SWIG_ArgError(r)           ((r != SWIG_ERROR) ? r : SWIG_TypeError)  
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT         (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK            (SWIG_CASTRANKLIMIT  << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK            (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ                (SWIG_ERROR)
+#define SWIG_OLDOBJ                (SWIG_OK)
+#define SWIG_NEWOBJ                (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ                (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r)         (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r)           (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r)         (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r)           (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+#  ifndef SWIG_TypeRank
+#    define SWIG_TypeRank             unsigned long
+#  endif
+#  ifndef SWIG_MAXCASTRANK            /* Default cast allowed */
+#    define SWIG_MAXCASTRANK          (2)
+#  endif
+#  define SWIG_CASTRANKMASK          ((SWIG_CASTRANKLIMIT) -1)
+#  define SWIG_CastRank(r)           (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) { 
+  return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) { 
+  return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; 
+}
+#else /* no cast-rank mode */
+#  define SWIG_AddCast
+#  define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store inforomation on one type */
+typedef struct swig_type_info {
+  const char             *name;                        /* mangled name of this type */
+  const char             *str;                 /* human readable name of this type */
+  swig_dycast_func        dcast;               /* dynamic cast function down a hierarchy */
+  struct swig_cast_info  *cast;                        /* linked list of types that can cast into this type */
+  void                   *clientdata;          /* language specific type data */
+  int                    owndata;              /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+  swig_type_info         *type;                        /* pointer to type that is equivalent to this type */
+  swig_converter_func     converter;           /* function to cast the void pointers */
+  struct swig_cast_info  *next;                        /* pointer to next cast in linked list */
+  struct swig_cast_info  *prev;                        /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+  swig_type_info         **types;              /* Array of pointers to swig_type_info structures that are in this module */
+  size_t                 size;                 /* Number of types in this module */
+  struct swig_module_info *next;               /* Pointer to next element in circularly linked list */
+  swig_type_info         **type_initial;       /* Array of initially generated type structures */
+  swig_cast_info         **cast_initial;       /* Array of initially generated casting structures */
+  void                    *clientdata;         /* Language specific module data */
+} swig_module_info;
+
+/* 
+  Compare two type names skipping the space characters, therefore
+  "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+  Return 0 when the two name types are equivalent, as in
+  strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+                 const char *f2, const char *l2) {
+  for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+    while ((*f1 == ' ') && (f1 != l1)) ++f1;
+    while ((*f2 == ' ') && (f2 != l2)) ++f2;
+    if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+  }
+  return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty)         \
+  if (ty) {                                             \
+    swig_cast_info *iter = ty->cast;                    \
+    while (iter) {                                      \
+      if (comparison) {                                 \
+        if (iter == ty->cast) return iter;              \
+        /* Move iter to the top of the linked list */   \
+        iter->prev->next = iter->next;                  \
+        if (iter->next)                                 \
+          iter->next->prev = iter->prev;                \
+        iter->next = ty->cast;                          \
+        iter->prev = 0;                                 \
+        if (ty->cast) ty->cast->prev = iter;            \
+        ty->cast = iter;                                \
+        return iter;                                    \
+      }                                                 \
+      iter = iter->next;                                \
+    }                                                   \
+  }                                                     \
+  return 0
+
+/*
+  Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+  SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+  Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr) {
+  return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/* 
+   Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/*
+  Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/*
+  Return the pretty name associated with this type,
+  that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+  /* The "str" field contains the equivalent pretty names of the
+     type, separated by vertical-bar characters.  We choose
+     to print the last name, as it is often (?) the most
+     specific. */
+  if (!type) return NULL;
+  if (type->str != NULL) {
+    const char *last_name = type->str;
+    const char *s;
+    for (s = type->str; *s; s++)
+      if (*s == '|') last_name = s+1;
+    return last_name;
+  }
+  else
+    return type->name;
+}
+
+/* 
+   Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  swig_cast_info *cast = ti->cast;
+  /* if (ti->clientdata == clientdata) return; */
+  ti->clientdata = clientdata;
+  
+  while (cast) {
+    if (!cast->converter) {
+      swig_type_info *tc = cast->type;
+      if (!tc->clientdata) {
+       SWIG_TypeClientData(tc, clientdata);
+      }
+    }    
+    cast = cast->next;
+  }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+  SWIG_TypeClientData(ti, clientdata);
+  ti->owndata = 1;
+}
+  
+/*
+  Search for a swig_type_info structure only by mangled name
+  Search is a O(log #types)
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start, 
+                            swig_module_info *end, 
+                           const char *name) {
+  swig_module_info *iter = start;
+  do {
+    if (iter->size) {
+      register size_t l = 0;
+      register size_t r = iter->size - 1;
+      do {
+       /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+       register size_t i = (l + r) >> 1; 
+       const char *iname = iter->types[i]->name;
+       if (iname) {
+         register int compare = strcmp(name, iname);
+         if (compare == 0) {       
+           return iter->types[i];
+         } else if (compare < 0) {
+           if (i) {
+             r = i - 1;
+           } else {
+             break;
+           }
+         } else if (compare > 0) {
+           l = i + 1;
+         }
+       } else {
+         break; /* should never happen */
+       }
+      } while (l <= r);
+    }
+    iter = iter->next;
+  } while (iter != end);
+  return 0;
+}
+
+/*
+  Search for a swig_type_info structure for either a mangled name or a human readable name.
+  It first searches the mangled names of the types, which is a O(log #types)
+  If a type is not found it then searches the human readable names, which is O(#types).
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start, 
+                     swig_module_info *end, 
+                    const char *name) {
+  /* STEP 1: Search the name field using binary search */
+  swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+  if (ret) {
+    return ret;
+  } else {
+    /* STEP 2: If the type hasn't been found, do a complete search
+       of the str field (the human readable name) */
+    swig_module_info *iter = start;
+    do {
+      register size_t i = 0;
+      for (; i < iter->size; ++i) {
+       if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+         return iter->types[i];
+      }
+      iter = iter->next;
+    } while (iter != end);
+  }
+  
+  /* neither found a match */
+  return 0;
+}
+
+/* 
+   Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+  static const char hex[17] = "0123456789abcdef";
+  register const unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu =  u + sz;
+  for (; u != eu; ++u) {
+    register unsigned char uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* 
+   Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+  register unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu = u + sz;
+  for (; u != eu; ++u) {
+    register char d = *(c++);
+    register unsigned char uu;
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    else 
+      return (char *) 0;
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    else 
+      return (char *) 0;
+    *u = uu;
+  }
+  return c;
+}
+
+/* 
+   Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+  char *r = buff;
+  if ((2*sizeof(void *) + 2) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,&ptr,sizeof(void *));
+  if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+  strcpy(r,name);
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      *ptr = (void *) 0;
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+  char *r = buff;
+  size_t lname = (name ? strlen(name) : 0);
+  if ((2*sz + 2 + lname) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  if (lname) {
+    strncpy(r,name,lname+1);
+  } else {
+    *r = 0;
+  }
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      memset(ptr,0,sz);
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*  Errors in SWIG */
+#define  SWIG_UnknownError        -1 
+#define  SWIG_IOError             -2 
+#define  SWIG_RuntimeError        -3 
+#define  SWIG_IndexError          -4 
+#define  SWIG_TypeError           -5 
+#define  SWIG_DivisionByZero      -6 
+#define  SWIG_OverflowError       -7 
+#define  SWIG_SyntaxError         -8 
+#define  SWIG_ValueError          -9 
+#define  SWIG_SystemError         -10
+#define  SWIG_AttributeError      -11
+#define  SWIG_MemoryError         -12 
+#define  SWIG_NullReferenceError   -13
+
+
+
+#ifdef __cplusplus
+/* Needed on some windows machines---since MS plays funny games with the header files under C++ */
+#include <math.h>
+#include <stdlib.h>
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* Add in functionality missing in older versions of Perl. Much of this is based on Devel-PPPort on cpan. */
+
+/* Add PERL_REVISION, PERL_VERSION, PERL_SUBVERSION if missing */
+#ifndef PERL_REVISION
+#  if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+#    define PERL_PATCHLEVEL_H_IMPLICIT
+#    include <patchlevel.h>
+#  endif
+#  if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+#    include <could_not_find_Perl_patchlevel.h>
+#  endif
+#  ifndef PERL_REVISION
+#    define PERL_REVISION       (5)
+#    define PERL_VERSION        PATCHLEVEL
+#    define PERL_SUBVERSION     SUBVERSION
+#  endif
+#endif
+
+#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE)
+#define PerlIO_exportFILE(fh,fl) (FILE*)(fh)
+#endif
+
+#ifndef SvIOK_UV
+# define SvIOK_UV(sv)       (SvIOK(sv) && (SvUVX(sv) == SvIVX(sv)))
+#endif
+
+#ifndef SvUOK
+# define SvUOK(sv)           SvIOK_UV(sv)
+#endif
+
+#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5)))
+#  define PL_sv_undef               sv_undef
+#  define PL_na                            na
+#  define PL_errgv                  errgv
+#  define PL_sv_no                  sv_no
+#  define PL_sv_yes                 sv_yes
+#  define PL_markstack_ptr          markstack_ptr
+#endif
+
+#ifndef IVSIZE
+#  ifdef LONGSIZE
+#    define IVSIZE LONGSIZE
+#  else
+#    define IVSIZE 4 /* A bold guess, but the best we can make. */
+#  endif
+#endif
+
+#ifndef INT2PTR
+#  if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#    define PTRV                  UV
+#    define INT2PTR(any,d)        (any)(d)
+#  else
+#    if PTRSIZE == LONGSIZE
+#      define PTRV                unsigned long
+#    else
+#      define PTRV                unsigned
+#    endif
+#    define INT2PTR(any,d)        (any)(PTRV)(d)
+#  endif
+
+#  define NUM2PTR(any,d)  (any)(PTRV)(d)
+#  define PTR2IV(p)       INT2PTR(IV,p)
+#  define PTR2UV(p)       INT2PTR(UV,p)
+#  define PTR2NV(p)       NUM2PTR(NV,p)
+
+#  if PTRSIZE == LONGSIZE
+#    define PTR2ul(p)     (unsigned long)(p)
+#  else
+#    define PTR2ul(p)     INT2PTR(unsigned long,p)
+#  endif
+#endif /* !INT2PTR */
+
+#ifndef SvPV_nolen
+# define SvPV_nolen(x) SvPV(x,PL_na)
+#endif
+
+#ifndef get_sv
+#  define get_sv perl_get_sv
+#endif
+
+#ifndef ERRSV
+#  define ERRSV get_sv("@",FALSE)
+#endif
+
+#ifndef pTHX_
+#define pTHX_
+#endif   
+
+#include <string.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGINTERN const char*
+SWIG_Perl_ErrorType(int code) {
+  const char* type = 0;
+  switch(code) {
+  case SWIG_MemoryError:
+    type = "MemoryError";
+    break;
+  case SWIG_IOError:
+    type = "IOError";
+    break;
+  case SWIG_RuntimeError:
+    type = "RuntimeError";
+    break;
+  case SWIG_IndexError:
+    type = "IndexError";
+    break;
+  case SWIG_TypeError:
+    type = "TypeError";
+    break;
+  case SWIG_DivisionByZero:
+    type = "ZeroDivisionError";
+    break;
+  case SWIG_OverflowError:
+    type = "OverflowError";
+    break;
+  case SWIG_SyntaxError:
+    type = "SyntaxError";
+    break;
+  case SWIG_ValueError:
+    type = "ValueError";
+    break;
+  case SWIG_SystemError:
+    type = "SystemError";
+    break;
+  case SWIG_AttributeError:
+    type = "AttributeError";
+    break;
+  default:
+    type = "RuntimeError";
+  }
+  return type;
+}
+
+
+
+
+/* -----------------------------------------------------------------------------
+ * perlrun.swg
+ *
+ * This file contains the runtime support for Perl modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef PERL_OBJECT
+#define SWIG_PERL_OBJECT_DECL CPerlObj *SWIGUNUSEDPARM(pPerl),
+#define SWIG_PERL_OBJECT_CALL pPerl,
+#else
+#define SWIG_PERL_OBJECT_DECL
+#define SWIG_PERL_OBJECT_CALL
+#endif
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_ConvertPtr(obj, pp, type, flags)           SWIG_Perl_ConvertPtr(SWIG_PERL_OBJECT_CALL obj, pp, type, flags)
+#define SWIG_NewPointerObj(p, type, flags)              SWIG_Perl_NewPointerObj(SWIG_PERL_OBJECT_CALL p, type, flags)
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, p, s, type)             SWIG_Perl_ConvertPacked(SWIG_PERL_OBJECT_CALL obj, p, s, type)
+#define SWIG_NewPackedObj(p, s, type)                  SWIG_Perl_NewPackedObj(SWIG_PERL_OBJECT_CALL p, s, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags)    SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags)           SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type)        SWIG_ConvertPtr(obj, pptr, type, 0)
+#define SWIG_NewFunctionPtrObj(ptr, type)               SWIG_NewPointerObj(ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty)            SWIG_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type)                SWIG_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata)                      SWIG_Perl_GetModule()
+#define SWIG_SetModule(clientdata, pointer)             SWIG_Perl_SetModule(pointer)
+
+
+/* Error manipulation */
+
+#define SWIG_ErrorType(code)                            SWIG_Perl_ErrorType(code)               
+#define SWIG_Error(code, msg)                          sv_setpvf(GvSV(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg)
+#define SWIG_fail                                      goto fail                                                   
+
+/* Perl-specific SWIG API */
+
+#define SWIG_MakePtr(sv, ptr, type, flags)              SWIG_Perl_MakePtr(SWIG_PERL_OBJECT_CALL sv, ptr, type, flags)
+#define SWIG_MakePackedObj(sv, p, s, type)             SWIG_Perl_MakePackedObj(SWIG_PERL_OBJECT_CALL sv, p, s, type)
+#define SWIG_SetError(str)                              SWIG_Error(SWIG_RuntimeError, str)
+
+
+#define SWIG_PERL_DECL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_DECL arg1)
+#define SWIG_PERL_CALL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_CALL arg1)
+#define SWIG_PERL_DECL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_DECL arg1, arg2)
+#define SWIG_PERL_CALL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_CALL arg1, arg2)
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+/* For backward compatibility only */
+#define SWIG_POINTER_EXCEPTION  0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_OWNER   SWIG_POINTER_OWN
+#define SWIG_SHADOW  SWIG_OWNER << 1
+
+#define SWIG_MAYBE_PERL_OBJECT SWIG_PERL_OBJECT_DECL
+
+/* SWIG Perl macros */
+
+/* Macro to declare an XS function */
+#ifndef XSPROTO
+#   define XSPROTO(name) void name(pTHX_ CV* cv)
+#endif
+
+/* Macro to call an XS function */
+#ifdef PERL_OBJECT 
+#  define SWIG_CALLXS(_name) _name(cv,pPerl) 
+#else 
+#  ifndef MULTIPLICITY 
+#    define SWIG_CALLXS(_name) _name(cv) 
+#  else 
+#    define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) 
+#  endif 
+#endif 
+
+#ifdef PERL_OBJECT
+#define MAGIC_PPERL  CPerlObj *pPerl = (CPerlObj *) this;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+#define SWIGCLASS_STATIC
+
+#else /* PERL_OBJECT */
+
+#define MAGIC_PPERL
+#define SWIGCLASS_STATIC static SWIGUNUSED
+
+#ifndef MULTIPLICITY
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MULTIPLICITY */
+
+#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MULTIPLICITY */
+#endif /* PERL_OBJECT */
+
+/* Workaround for bug in perl 5.6.x croak and earlier */
+#if (PERL_VERSION < 8)
+#  ifdef PERL_OBJECT
+#    define SWIG_croak_null() SWIG_Perl_croak_null(pPerl)
+static void SWIG_Perl_croak_null(CPerlObj *pPerl)
+#  else
+static void SWIG_croak_null()
+#  endif
+{
+  SV *err=ERRSV;
+#  if (PERL_VERSION < 6)
+  croak("%_", err);
+#  else
+  if (SvOK(err) && !SvROK(err)) croak("%_", err);
+  croak(Nullch);
+#  endif
+}
+#else
+#  define SWIG_croak_null() croak(Nullch)
+#endif
+
+
+/* 
+   Define how strict is the cast between strings and integers/doubles
+   when overloading between these types occurs.
+   
+   The default is making it as strict as possible by using SWIG_AddCast
+   when needed.
+   
+   You can use -DSWIG_PERL_NO_STRICT_STR2NUM at compilation time to
+   disable the SWIG_AddCast, making the casting between string and
+   numbers less strict.
+
+   In the end, we try to solve the overloading between strings and
+   numerical types in the more natural way, but if you can avoid it,
+   well, avoid it using %rename, for example.
+*/
+#ifndef SWIG_PERL_NO_STRICT_STR2NUM
+# ifndef SWIG_PERL_STRICT_STR2NUM
+#  define SWIG_PERL_STRICT_STR2NUM
+# endif
+#endif
+#ifdef SWIG_PERL_STRICT_STR2NUM
+/* string takes precedence */
+#define SWIG_Str2NumCast(x) SWIG_AddCast(x)  
+#else
+/* number takes precedence */
+#define SWIG_Str2NumCast(x) x
+#endif
+
+
+
+#include <stdlib.h>
+
+SWIGRUNTIME const char *
+SWIG_Perl_TypeProxyName(const swig_type_info *type) {
+  if (!type) return NULL;
+  if (type->clientdata != NULL) {
+    return (const char*) type->clientdata;
+  } 
+  else {
+    return type->name;
+  }
+}
+
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeProxyCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(( (!iter->type->clientdata && (strcmp((char*)iter->type->name, c) == 0)) 
+                           || (iter->type->clientdata && (strcmp((char*)iter->type->clientdata, c) == 0))), ty);
+}
+
+
+/* Function for getting a pointer value */
+
+SWIGRUNTIME int
+SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) {
+  swig_cast_info *tc;
+  void *voidptr = (void *)0;
+  SV *tsv = 0;
+  /* If magical, apply more magic */
+  if (SvGMAGICAL(sv))
+    mg_get(sv);
+
+  /* Check to see if this is an object */
+  if (sv_isobject(sv)) {
+    IV tmp = 0;
+    tsv = (SV*) SvRV(sv);
+    if ((SvTYPE(tsv) == SVt_PVHV)) {
+      MAGIC *mg;
+      if (SvMAGICAL(tsv)) {
+        mg = mg_find(tsv,'P');
+        if (mg) {
+          sv = mg->mg_obj;
+          if (sv_isobject(sv)) {
+           tsv = (SV*)SvRV(sv);
+            tmp = SvIV(tsv);
+          }
+        }
+      } else {
+        return SWIG_ERROR;
+      }
+    } else {
+      tmp = SvIV(tsv);
+    }
+    voidptr = INT2PTR(void *,tmp);
+  } else if (! SvOK(sv)) {            /* Check for undef */
+    *(ptr) = (void *) 0;
+    return SWIG_OK;
+  } else if (SvTYPE(sv) == SVt_RV) {  /* Check for NULL pointer */
+    if (!SvROK(sv)) {
+      *(ptr) = (void *) 0;
+      return SWIG_OK;
+    } else {
+      return SWIG_ERROR;
+    }
+  } else {                            /* Don't know what it is */
+    return SWIG_ERROR;
+  }
+  if (_t) {
+    /* Now see if the types match */
+    char *_c = HvNAME(SvSTASH(SvRV(sv)));
+    tc = SWIG_TypeProxyCheck(_c,_t);
+    if (!tc) {
+      return SWIG_ERROR;
+    }
+    *ptr = SWIG_TypeCast(tc,voidptr);
+  } else {
+    *ptr = voidptr;
+  }
+
+  /* 
+   *  DISOWN implementation: we need a perl guru to check this one.
+   */
+  if (tsv && (flags & SWIG_POINTER_DISOWN)) {
+    /* 
+     *  almost copy paste code from below SWIG_POINTER_OWN setting
+     */
+    SV *obj = sv;
+    HV *stash = SvSTASH(SvRV(obj));
+    GV *gv = *(GV**) hv_fetch(stash, "OWNER", 5, TRUE);
+    if (isGV(gv)) {
+      HV *hv = GvHVn(gv);
+      /*
+       * To set ownership (see below), a newSViv(1) entry is added. 
+       * Hence, to remove ownership, we delete the entry.
+       */
+      if (hv_exists_ent(hv, obj, 0)) {
+       hv_delete_ent(hv, obj, 0, 0);
+      }
+    }
+  }
+  return SWIG_OK;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) {
+  if (ptr && (flags & SWIG_SHADOW)) {
+    SV *self;
+    SV *obj=newSV(0);
+    HV *hash=newHV();
+    HV *stash;
+    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+    stash=SvSTASH(SvRV(obj));
+    if (flags & SWIG_POINTER_OWN) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+      if (!isGV(gv))
+        gv_init(gv, stash, "OWNER", 5, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newSViv(1), 0);
+    }
+    sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0);
+    SvREFCNT_dec(obj);
+    self=newRV_noinc((SV *)hash);
+    sv_setsv(sv, self);
+    SvREFCNT_dec((SV *)self);
+    sv_bless(sv, stash);
+  }
+  else {
+    sv_setref_pv(sv, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+  }
+}
+
+SWIGRUNTIMEINLINE SV *
+SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+  SV *result = sv_newmortal();
+  SWIG_MakePtr(result, ptr, t, flags);
+  return result;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) {
+  char result[1024];
+  char *r = result;
+  if ((2*sz + 1 + strlen(SWIG_Perl_TypeProxyName(type))) > 1000) return;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  strcpy(r,SWIG_Perl_TypeProxyName(type));
+  sv_setpv(sv, result);
+}
+
+SWIGRUNTIME SV *
+SWIG_Perl_NewPackedObj(SWIG_MAYBE_PERL_OBJECT void *ptr, int sz, swig_type_info *type) {
+  SV *result = sv_newmortal();
+  SWIG_Perl_MakePackedObj(result, ptr, sz, type);
+  return result;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME int
+SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty) {
+  swig_cast_info *tc;
+  const char  *c = 0;
+
+  if ((!obj) || (!SvOK(obj))) return SWIG_ERROR;
+  c = SvPV_nolen(obj);
+  /* Pointer values must start with leading underscore */
+  if (*c != '_') return SWIG_ERROR;
+  c++;
+  c = SWIG_UnpackData(c,ptr,sz);
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) return SWIG_ERROR;
+  }
+  return SWIG_OK;
+}
+
+
+/* Macros for low-level exception handling */
+#define SWIG_croak(x)    { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail; }
+
+
+typedef XSPROTO(SwigPerlWrapper);
+typedef SwigPerlWrapper *SwigPerlWrapperPtr;
+
+/* Structure for command table */
+typedef struct {
+  const char         *name;
+  SwigPerlWrapperPtr  wrapper;
+} swig_command_info;
+
+/* Information for constant table */
+
+#define SWIG_INT     1
+#define SWIG_FLOAT   2
+#define SWIG_STRING  3
+#define SWIG_POINTER 4
+#define SWIG_BINARY  5
+
+/* Constant information structure */
+typedef struct swig_constant_info {
+    int              type;
+    const char      *name;
+    long             lvalue;
+    double           dvalue;
+    void            *pvalue;
+    swig_type_info **ptype;
+} swig_constant_info;
+
+
+/* Structure for variable table */
+typedef struct {
+  const char   *name;
+  SwigMagicFunc   set;
+  SwigMagicFunc   get;
+  swig_type_info  **type;
+} swig_variable_info;
+
+/* Magic variable code */
+#ifndef PERL_OBJECT
+#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c)
+  #ifndef MULTIPLICITY
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) 
+  #else
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) 
+  #endif
+#else
+#  define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c)
+SWIGRUNTIME void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) 
+#endif
+{
+  MAGIC *mg;
+  sv_magic(sv,sv,'U',(char *) name,strlen(name));
+  mg = mg_find(sv,'U');
+  mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
+  mg->mg_virtual->svt_get = (SwigMagicFunc) get;
+  mg->mg_virtual->svt_set = (SwigMagicFunc) set;
+  mg->mg_virtual->svt_len = 0;
+  mg->mg_virtual->svt_clear = 0;
+  mg->mg_virtual->svt_free = 0;
+}
+
+
+SWIGRUNTIME swig_module_info *
+SWIG_Perl_GetModule(void) {
+  static void *type_pointer = (void *)0;
+  SV *pointer;
+
+  /* first check if pointer already created */
+  if (!type_pointer) {
+    pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE);
+    if (pointer && SvOK(pointer)) {
+      type_pointer = INT2PTR(swig_type_info **, SvIV(pointer));
+    }
+  }
+
+  return (swig_module_info *) type_pointer;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_SetModule(swig_module_info *module) {
+  SV *pointer;
+
+  /* create a new pointer */
+  pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE);
+  sv_setiv(pointer, PTR2IV(module));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Workaround perl5 global namespace pollution. Note that undefining library
+ * functions like fopen will not solve the problem on all platforms as fopen
+ * might be a macro on Windows but not necessarily on other operating systems. */
+#ifdef do_open
+  #undef do_open
+#endif
+#ifdef do_close
+  #undef do_close
+#endif
+#ifdef scalar
+  #undef scalar
+#endif
+#ifdef list
+  #undef list
+#endif
+#ifdef apply
+  #undef apply
+#endif
+#ifdef convert
+  #undef convert
+#endif
+#ifdef Error
+  #undef Error
+#endif
+#ifdef form
+  #undef form
+#endif
+#ifdef vform
+  #undef vform
+#endif
+#ifdef LABEL
+  #undef LABEL
+#endif
+#ifdef METHOD
+  #undef METHOD
+#endif
+#ifdef Move
+  #undef Move
+#endif
+#ifdef yylex
+  #undef yylex
+#endif
+#ifdef yyparse
+  #undef yyparse
+#endif
+#ifdef yyerror
+  #undef yyerror
+#endif
+#ifdef invert
+  #undef invert
+#endif
+#ifdef ref
+  #undef ref
+#endif
+#ifdef read
+  #undef read
+#endif
+#ifdef write
+  #undef write
+#endif
+#ifdef eof
+  #undef eof
+#endif
+#ifdef bool
+  #undef bool
+#endif
+#ifdef close
+  #undef close
+#endif
+#ifdef rewind
+  #undef rewind
+#endif
+#ifdef free
+  #undef free
+#endif
+#ifdef malloc
+  #undef malloc
+#endif
+#ifdef calloc
+  #undef calloc
+#endif
+#ifdef Stat
+  #undef Stat
+#endif
+#ifdef check
+  #undef check
+#endif
+#ifdef seekdir
+  #undef seekdir
+#endif
+#ifdef open
+  #undef open
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) 
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else 
+
+
+
+  #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) 
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_char swig_types[0]
+#define SWIGTYPE_p_double swig_types[1]
+#define SWIGTYPE_p_float swig_types[2]
+#define SWIGTYPE_p_int swig_types[3]
+#define SWIGTYPE_p_unsigned_char swig_types[4]
+static swig_type_info *swig_types[6];
+static swig_module_info swig_module = {swig_types, 5, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init    boot_Amanda__Tapefile
+
+#define SWIG_name   "Amanda::Tapefilec::boot_Amanda__Tapefile"
+#define SWIG_prefix "Amanda::Tapefilec::"
+
+#define SWIGVERSION 0x010333 
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a)) 
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) 
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifndef PERL_OBJECT
+#ifndef MULTIPLICITY
+SWIGEXPORT void SWIG_init (CV* cv);
+#else
+SWIGEXPORT void SWIG_init (pTHXo_ CV* cv);
+#endif
+#else
+SWIGEXPORT void SWIG_init (CV *cv, CPerlObj *);
+#endif
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include <glib.h>
+#include "tapefile.h"
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+  static int init = 0;
+  static swig_type_info* info = 0;
+  if (!init) {
+    info = SWIG_TypeQuery("_p_char");
+    init = 1;
+  }
+  return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(SV *obj, char** cptr, size_t* psize, int *alloc)
+{
+  if (SvPOK(obj)) {
+    STRLEN len = 0;
+    char *cstr = SvPV(obj, len); 
+    size_t size = len + 1;
+    if (cptr)  {
+      if (alloc) {
+       if (*alloc == SWIG_NEWOBJ) {
+         *cptr = (char *)memcpy((char *)malloc((size)*sizeof(char)), cstr, sizeof(char)*(size));
+       } else {
+         *cptr = cstr;
+         *alloc = SWIG_OLDOBJ;
+       }
+      }
+    }
+    if (psize) *psize = size;
+    return SWIG_OK;
+  } else {
+    swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+    if (pchar_descriptor) {
+      char* vptr = 0; 
+      if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_descriptor, 0) == SWIG_OK) {
+       if (cptr) *cptr = vptr;
+       if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0;
+       if (alloc) *alloc = SWIG_OLDOBJ;
+       return SWIG_OK;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef PERL_OBJECT
+#define MAGIC_CLASS _wrap_Amanda::Tapefile_var::
+class _wrap_Amanda::Tapefile_var : public CPerlObj {
+public:
+#else
+#define MAGIC_CLASS
+#endif
+SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {
+    MAGIC_PPERL
+    croak("Value is read-only.");
+    return 0;
+}
+
+
+#ifdef PERL_OBJECT
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+XS(_wrap_read_tapelist) {
+  {
+    char *arg1 = (char *) 0 ;
+    int result;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: read_tapelist(tapefile);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "read_tapelist" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    result = (int)read_tapelist(arg1);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_char = {"_p_char", "gchar *|char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_double = {"_p_double", "double *|gdouble *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *|gfloat *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "int *|gboolean *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "guchar *|unsigned char *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_char,
+  &_swigt__p_double,
+  &_swigt__p_float,
+  &_swigt__p_int,
+  &_swigt__p_unsigned_char,
+};
+
+static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_char[] = {  {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_char,
+  _swigc__p_double,
+  _swigc__p_float,
+  _swigc__p_int,
+  _swigc__p_unsigned_char,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_constant_info swig_constants[] = {
+{0,0,0,0,0,0}
+};
+#ifdef __cplusplus
+}
+#endif
+static swig_variable_info swig_variables[] = {
+{0,0,0,0}
+};
+static swig_command_info swig_commands[] = {
+{"Amanda::Tapefilec::read_tapelist", _wrap_read_tapelist},
+{0,0}
+};
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic 
+ * memory is used. Also, since swig_type_info structures store pointers to 
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization. 
+ * The idea is that swig generates all the structures that are needed. 
+ * The runtime then collects these partially filled structures. 
+ * The SWIG_InitializeModule function takes these initial arrays out of 
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned staticly to an initial 
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it 
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded. 
+ * There are three cases to handle:
+ *  1) If the cast->type has already been loaded AND the type we are adding
+ *     casting info to has not been loaded (it is in this module), THEN we
+ *     replace the cast->type pointer with the type pointer that has already
+ *     been loaded.
+ *  2) If BOTH types (the one we are adding casting info to, and the 
+ *     cast->type) are loaded, THEN the cast info has already been loaded by
+ *     the previous module so we just ignore it.
+ *  3) Finally, if cast->type has not already been loaded, then we add that
+ *     swig_cast_info to the linked list (because the cast->type) pointer will
+ *     be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+  size_t i;
+  swig_module_info *module_head, *iter;
+  int found;
+  
+  clientdata = clientdata;
+  
+  /* check to see if the circular list has been setup, if not, set it up */
+  if (swig_module.next==0) {
+    /* Initialize the swig_module */
+    swig_module.type_initial = swig_type_initial;
+    swig_module.cast_initial = swig_cast_initial;
+    swig_module.next = &swig_module;
+  }
+  
+  /* Try and load any already created modules */
+  module_head = SWIG_GetModule(clientdata);
+  if (!module_head) {
+    /* This is the first module loaded for this interpreter */
+    /* so set the swig module into the interpreter */
+    SWIG_SetModule(clientdata, &swig_module);
+    module_head = &swig_module;
+  } else {
+    /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+    found=0;
+    iter=module_head;
+    do {
+      if (iter==&swig_module) {
+        found=1;
+        break;
+      }
+      iter=iter->next;
+    } while (iter!= module_head);
+    
+    /* if the is found in the list, then all is done and we may leave */
+    if (found) return;
+    /* otherwise we must add out module into the list */
+    swig_module.next = module_head->next;
+    module_head->next = &swig_module;
+  }
+  
+  /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+  printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+  for (i = 0; i < swig_module.size; ++i) {
+    swig_type_info *type = 0;
+    swig_type_info *ret;
+    swig_cast_info *cast;
+    
+#ifdef SWIGRUNTIME_DEBUG
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+    
+    /* if there is another module already loaded */
+    if (swig_module.next != &swig_module) {
+      type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+    }
+    if (type) {
+      /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+      if (swig_module.type_initial[i]->clientdata) {
+        type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+      }
+    } else {
+      type = swig_module.type_initial[i];
+    }
+    
+    /* Insert casting types */
+    cast = swig_module.cast_initial[i];
+    while (cast->type) {
+      /* Don't need to add information already in the list */
+      ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+      if (swig_module.next != &swig_module) {
+        ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+        if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+      }
+      if (ret) {
+        if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+          printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+          cast->type = ret;
+          ret = 0;
+        } else {
+          /* Check for casting already in the list */
+          swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+          if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+          if (!ocast) ret = 0;
+        }
+      }
+      
+      if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+        if (type->cast) {
+          type->cast->prev = cast;
+          cast->next = type->cast;
+        }
+        type->cast = cast;
+      }
+      cast++;
+    }
+    /* Set entry in modules->types array equal to the type */
+    swig_module.types[i] = type;
+  }
+  swig_module.types[i] = 0;
+  
+#ifdef SWIGRUNTIME_DEBUG
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+  for (i = 0; i < swig_module.size; ++i) {
+    int j = 0;
+    swig_cast_info *cast = swig_module.cast_initial[i];
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+    while (cast->type) {
+      printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+      cast++;
+      ++j;
+    }
+    printf("---- Total casts: %d\n",j);
+  }
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types.  It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+  size_t i;
+  swig_cast_info *equiv;
+  static int init_run = 0;
+  
+  if (init_run) return;
+  init_run = 1;
+  
+  for (i = 0; i < swig_module.size; i++) {
+    if (swig_module.types[i]->clientdata) {
+      equiv = swig_module.types[i]->cast;
+      while (equiv) {
+        if (!equiv->converter) {
+          if (equiv->type && !equiv->type->clientdata)
+          SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+        }
+        equiv = equiv->next;
+      }
+    }
+  }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+  /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(SWIG_init) {
+  dXSARGS;
+  int i;
+  
+  SWIG_InitializeModule(0);
+  
+  /* Install commands */
+  for (i = 0; swig_commands[i].name; i++) {
+    newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__);
+  }
+  
+  /* Install variables */
+  for (i = 0; swig_variables[i].name; i++) {
+    SV *sv;
+    sv = get_sv((char*) swig_variables[i].name, TRUE | 0x2);
+    if (swig_variables[i].type) {
+      SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0);
+    } else {
+      sv_setiv(sv,(IV) 0);
+    }
+    swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); 
+  }
+  
+  /* Install constant */
+  for (i = 0; swig_constants[i].type; i++) {
+    SV *sv;
+    sv = get_sv((char*)swig_constants[i].name, TRUE | 0x2);
+    switch(swig_constants[i].type) {
+    case SWIG_INT:
+      sv_setiv(sv, (IV) swig_constants[i].lvalue);
+      break;
+    case SWIG_FLOAT:
+      sv_setnv(sv, (double) swig_constants[i].dvalue);
+      break;
+    case SWIG_STRING:
+      sv_setpv(sv, (char *) swig_constants[i].pvalue);
+      break;
+    case SWIG_POINTER:
+      SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
+      break;
+    case SWIG_BINARY:
+      SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
+      break;
+    default:
+      break;
+    }
+    SvREADONLY_on(sv);
+  }
+  
+  ST(0) = &PL_sv_yes;
+  XSRETURN(1);
+}
+
diff --git a/perl/Amanda/Tapefile.pm b/perl/Amanda/Tapefile.pm
new file mode 100644 (file)
index 0000000..da8196b
--- /dev/null
@@ -0,0 +1,72 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 1.3.33
+#
+# Don't modify this file, modify the SWIG interface instead.
+
+package Amanda::Tapefile;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+package Amanda::Tapefilec;
+bootstrap Amanda::Tapefile;
+package Amanda::Tapefile;
+@EXPORT = qw( );
+
+# ---------- BASE METHODS -------------
+
+package Amanda::Tapefile;
+
+sub TIEHASH {
+    my ($classname,$obj) = @_;
+    return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+    my ($self,$field) = @_;
+    my $member_func = "swig_${field}_get";
+    $self->$member_func();
+}
+
+sub STORE {
+    my ($self,$field,$newval) = @_;
+    my $member_func = "swig_${field}_set";
+    $self->$member_func($newval);
+}
+
+sub this {
+    my $ptr = shift;
+    return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package Amanda::Tapefile;
+
+*read_tapelist = *Amanda::Tapefilec::read_tapelist;
+
+# ------- VARIABLE STUBS --------
+
+package Amanda::Tapefile;
+
+
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+
+=head1 NAME
+
+Amanda::Tapefile - temporary hack
+
+=head1 HACK?
+
+Yeah, this is just here to make Amanda::Logfile usable.  This module
+wil become Amanda::Tapelist in the next release.
+
+=cut
+1;
diff --git a/perl/Amanda/Tapefile.swg b/perl/Amanda/Tapefile.swg
new file mode 100644 (file)
index 0000000..858e98e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%module "Amanda::Tapefile"
+%include "amglue/amglue.swg"
+%include "exception.i"
+
+%{
+#include <glib.h>
+#include "tapefile.h"
+%}
+
+%perlcode %{
+=head1 NAME
+
+Amanda::Tapefile - temporary hack
+
+=head1 HACK?
+
+Yeah, this is just here to make Amanda::Logfile usable.  This module
+wil become Amanda::Tapelist in the next release.
+
+=cut
+%}
+/* This is just a hack to get Amanda::Logfile working! */
+
+int read_tapelist(char *tapefile);
diff --git a/perl/Amanda/Types.c b/perl/Amanda/Types.c
new file mode 100644 (file)
index 0000000..975e350
--- /dev/null
@@ -0,0 +1,4266 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.33
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPERL
+#define SWIG_CASTRANK_MODE
+/* -----------------------------------------------------------------------------
+ *  This section contains generic SWIG labels for method/variable
+ *  declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+#  define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+#   define SWIGINLINE inline
+# else
+#   define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define SWIGUNUSED __attribute__ ((__unused__)) 
+#   else
+#     define SWIGUNUSED
+#   endif
+# elif defined(__ICC)
+#   define SWIGUNUSED __attribute__ ((__unused__)) 
+# else
+#   define SWIGUNUSED 
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+#   define SWIGUNUSEDPARM(p)
+# else
+#   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#  ifndef GCC_HASCLASSVISIBILITY
+#    define GCC_HASCLASSVISIBILITY
+#  endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   if defined(STATIC_LINKED)
+#     define SWIGEXPORT
+#   else
+#     define SWIGEXPORT __declspec(dllexport)
+#   endif
+# else
+#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+#     define SWIGEXPORT __attribute__ ((visibility("default")))
+#   else
+#     define SWIGEXPORT
+#   endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   define SWIGSTDCALL __stdcall
+# else
+#   define SWIGSTDCALL
+# endif 
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+   or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "3"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+  You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+  creating a static or dynamic library from the swig runtime code.
+  In 99.9% of the cases, swig just needs to declare them as 'static'.
+  
+  But only do this if is strictly necessary, ie, if you have problems
+  with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/*  Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN        0x1
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN           0x1
+
+
+/* 
+   Flags/methods for returning states.
+   
+   The swig conversion methods, as ConvertPtr, return and integer 
+   that tells if the conversion was successful or not. And if not,
+   an error code can be returned (see swigerrors.swg for the codes).
+   
+   Use the following macros/flags to set or process the returning
+   states.
+   
+   In old swig versions, you usually write code as:
+
+     if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+       // success code
+     } else {
+       //fail code
+     }
+
+   Now you can be more explicit as:
+
+    int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+    } else {
+      // fail code
+    }
+
+   that seems to be the same, but now you can also do
+
+    Type *ptr;
+    int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+      if (SWIG_IsNewObj(res) {
+        ...
+       delete *ptr;
+      } else {
+        ...
+      }
+    } else {
+      // fail code
+    }
+    
+   I.e., now SWIG_ConvertPtr can return new objects and you can
+   identify the case and take care of the deallocation. Of course that
+   requires also to SWIG_ConvertPtr to return new result values, as
+
+      int SWIG_ConvertPtr(obj, ptr,...) {         
+        if (<obj is ok>) {                            
+          if (<need new object>) {                    
+            *ptr = <ptr to new allocated object>; 
+            return SWIG_NEWOBJ;                       
+          } else {                                    
+            *ptr = <ptr to old object>;               
+            return SWIG_OLDOBJ;                       
+          }                                   
+        } else {                                      
+          return SWIG_BADOBJ;                 
+        }                                             
+      }
+
+   Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+   more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+   swig errors code.
+
+   Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+   allows to return the 'cast rank', for example, if you have this
+
+       int food(double)
+       int fooi(int);
+
+   and you call
+      food(1)   // cast rank '1'  (1 -> 1.0)
+      fooi(1)   // cast rank '0'
+
+   just use the SWIG_AddCast()/SWIG_CheckState()
+
+
+ */
+#define SWIG_OK                    (0) 
+#define SWIG_ERROR                 (-1)
+#define SWIG_IsOK(r)               (r >= 0)
+#define SWIG_ArgError(r)           ((r != SWIG_ERROR) ? r : SWIG_TypeError)  
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT         (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK            (SWIG_CASTRANKLIMIT  << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK            (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ                (SWIG_ERROR)
+#define SWIG_OLDOBJ                (SWIG_OK)
+#define SWIG_NEWOBJ                (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ                (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r)         (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r)           (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r)         (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r)           (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+#  ifndef SWIG_TypeRank
+#    define SWIG_TypeRank             unsigned long
+#  endif
+#  ifndef SWIG_MAXCASTRANK            /* Default cast allowed */
+#    define SWIG_MAXCASTRANK          (2)
+#  endif
+#  define SWIG_CASTRANKMASK          ((SWIG_CASTRANKLIMIT) -1)
+#  define SWIG_CastRank(r)           (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) { 
+  return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) { 
+  return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; 
+}
+#else /* no cast-rank mode */
+#  define SWIG_AddCast
+#  define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store inforomation on one type */
+typedef struct swig_type_info {
+  const char             *name;                        /* mangled name of this type */
+  const char             *str;                 /* human readable name of this type */
+  swig_dycast_func        dcast;               /* dynamic cast function down a hierarchy */
+  struct swig_cast_info  *cast;                        /* linked list of types that can cast into this type */
+  void                   *clientdata;          /* language specific type data */
+  int                    owndata;              /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+  swig_type_info         *type;                        /* pointer to type that is equivalent to this type */
+  swig_converter_func     converter;           /* function to cast the void pointers */
+  struct swig_cast_info  *next;                        /* pointer to next cast in linked list */
+  struct swig_cast_info  *prev;                        /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+  swig_type_info         **types;              /* Array of pointers to swig_type_info structures that are in this module */
+  size_t                 size;                 /* Number of types in this module */
+  struct swig_module_info *next;               /* Pointer to next element in circularly linked list */
+  swig_type_info         **type_initial;       /* Array of initially generated type structures */
+  swig_cast_info         **cast_initial;       /* Array of initially generated casting structures */
+  void                    *clientdata;         /* Language specific module data */
+} swig_module_info;
+
+/* 
+  Compare two type names skipping the space characters, therefore
+  "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+  Return 0 when the two name types are equivalent, as in
+  strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+                 const char *f2, const char *l2) {
+  for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+    while ((*f1 == ' ') && (f1 != l1)) ++f1;
+    while ((*f2 == ' ') && (f2 != l2)) ++f2;
+    if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+  }
+  return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty)         \
+  if (ty) {                                             \
+    swig_cast_info *iter = ty->cast;                    \
+    while (iter) {                                      \
+      if (comparison) {                                 \
+        if (iter == ty->cast) return iter;              \
+        /* Move iter to the top of the linked list */   \
+        iter->prev->next = iter->next;                  \
+        if (iter->next)                                 \
+          iter->next->prev = iter->prev;                \
+        iter->next = ty->cast;                          \
+        iter->prev = 0;                                 \
+        if (ty->cast) ty->cast->prev = iter;            \
+        ty->cast = iter;                                \
+        return iter;                                    \
+      }                                                 \
+      iter = iter->next;                                \
+    }                                                   \
+  }                                                     \
+  return 0
+
+/*
+  Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+  SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+  Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr) {
+  return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/* 
+   Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/*
+  Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/*
+  Return the pretty name associated with this type,
+  that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+  /* The "str" field contains the equivalent pretty names of the
+     type, separated by vertical-bar characters.  We choose
+     to print the last name, as it is often (?) the most
+     specific. */
+  if (!type) return NULL;
+  if (type->str != NULL) {
+    const char *last_name = type->str;
+    const char *s;
+    for (s = type->str; *s; s++)
+      if (*s == '|') last_name = s+1;
+    return last_name;
+  }
+  else
+    return type->name;
+}
+
+/* 
+   Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  swig_cast_info *cast = ti->cast;
+  /* if (ti->clientdata == clientdata) return; */
+  ti->clientdata = clientdata;
+  
+  while (cast) {
+    if (!cast->converter) {
+      swig_type_info *tc = cast->type;
+      if (!tc->clientdata) {
+       SWIG_TypeClientData(tc, clientdata);
+      }
+    }    
+    cast = cast->next;
+  }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+  SWIG_TypeClientData(ti, clientdata);
+  ti->owndata = 1;
+}
+  
+/*
+  Search for a swig_type_info structure only by mangled name
+  Search is a O(log #types)
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start, 
+                            swig_module_info *end, 
+                           const char *name) {
+  swig_module_info *iter = start;
+  do {
+    if (iter->size) {
+      register size_t l = 0;
+      register size_t r = iter->size - 1;
+      do {
+       /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+       register size_t i = (l + r) >> 1; 
+       const char *iname = iter->types[i]->name;
+       if (iname) {
+         register int compare = strcmp(name, iname);
+         if (compare == 0) {       
+           return iter->types[i];
+         } else if (compare < 0) {
+           if (i) {
+             r = i - 1;
+           } else {
+             break;
+           }
+         } else if (compare > 0) {
+           l = i + 1;
+         }
+       } else {
+         break; /* should never happen */
+       }
+      } while (l <= r);
+    }
+    iter = iter->next;
+  } while (iter != end);
+  return 0;
+}
+
+/*
+  Search for a swig_type_info structure for either a mangled name or a human readable name.
+  It first searches the mangled names of the types, which is a O(log #types)
+  If a type is not found it then searches the human readable names, which is O(#types).
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start, 
+                     swig_module_info *end, 
+                    const char *name) {
+  /* STEP 1: Search the name field using binary search */
+  swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+  if (ret) {
+    return ret;
+  } else {
+    /* STEP 2: If the type hasn't been found, do a complete search
+       of the str field (the human readable name) */
+    swig_module_info *iter = start;
+    do {
+      register size_t i = 0;
+      for (; i < iter->size; ++i) {
+       if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+         return iter->types[i];
+      }
+      iter = iter->next;
+    } while (iter != end);
+  }
+  
+  /* neither found a match */
+  return 0;
+}
+
+/* 
+   Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+  static const char hex[17] = "0123456789abcdef";
+  register const unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu =  u + sz;
+  for (; u != eu; ++u) {
+    register unsigned char uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* 
+   Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+  register unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu = u + sz;
+  for (; u != eu; ++u) {
+    register char d = *(c++);
+    register unsigned char uu;
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    else 
+      return (char *) 0;
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    else 
+      return (char *) 0;
+    *u = uu;
+  }
+  return c;
+}
+
+/* 
+   Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+  char *r = buff;
+  if ((2*sizeof(void *) + 2) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,&ptr,sizeof(void *));
+  if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+  strcpy(r,name);
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      *ptr = (void *) 0;
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+  char *r = buff;
+  size_t lname = (name ? strlen(name) : 0);
+  if ((2*sz + 2 + lname) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  if (lname) {
+    strncpy(r,name,lname+1);
+  } else {
+    *r = 0;
+  }
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      memset(ptr,0,sz);
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*  Errors in SWIG */
+#define  SWIG_UnknownError        -1 
+#define  SWIG_IOError             -2 
+#define  SWIG_RuntimeError        -3 
+#define  SWIG_IndexError          -4 
+#define  SWIG_TypeError           -5 
+#define  SWIG_DivisionByZero      -6 
+#define  SWIG_OverflowError       -7 
+#define  SWIG_SyntaxError         -8 
+#define  SWIG_ValueError          -9 
+#define  SWIG_SystemError         -10
+#define  SWIG_AttributeError      -11
+#define  SWIG_MemoryError         -12 
+#define  SWIG_NullReferenceError   -13
+
+
+
+#ifdef __cplusplus
+/* Needed on some windows machines---since MS plays funny games with the header files under C++ */
+#include <math.h>
+#include <stdlib.h>
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* Add in functionality missing in older versions of Perl. Much of this is based on Devel-PPPort on cpan. */
+
+/* Add PERL_REVISION, PERL_VERSION, PERL_SUBVERSION if missing */
+#ifndef PERL_REVISION
+#  if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+#    define PERL_PATCHLEVEL_H_IMPLICIT
+#    include <patchlevel.h>
+#  endif
+#  if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+#    include <could_not_find_Perl_patchlevel.h>
+#  endif
+#  ifndef PERL_REVISION
+#    define PERL_REVISION       (5)
+#    define PERL_VERSION        PATCHLEVEL
+#    define PERL_SUBVERSION     SUBVERSION
+#  endif
+#endif
+
+#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE)
+#define PerlIO_exportFILE(fh,fl) (FILE*)(fh)
+#endif
+
+#ifndef SvIOK_UV
+# define SvIOK_UV(sv)       (SvIOK(sv) && (SvUVX(sv) == SvIVX(sv)))
+#endif
+
+#ifndef SvUOK
+# define SvUOK(sv)           SvIOK_UV(sv)
+#endif
+
+#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5)))
+#  define PL_sv_undef               sv_undef
+#  define PL_na                            na
+#  define PL_errgv                  errgv
+#  define PL_sv_no                  sv_no
+#  define PL_sv_yes                 sv_yes
+#  define PL_markstack_ptr          markstack_ptr
+#endif
+
+#ifndef IVSIZE
+#  ifdef LONGSIZE
+#    define IVSIZE LONGSIZE
+#  else
+#    define IVSIZE 4 /* A bold guess, but the best we can make. */
+#  endif
+#endif
+
+#ifndef INT2PTR
+#  if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#    define PTRV                  UV
+#    define INT2PTR(any,d)        (any)(d)
+#  else
+#    if PTRSIZE == LONGSIZE
+#      define PTRV                unsigned long
+#    else
+#      define PTRV                unsigned
+#    endif
+#    define INT2PTR(any,d)        (any)(PTRV)(d)
+#  endif
+
+#  define NUM2PTR(any,d)  (any)(PTRV)(d)
+#  define PTR2IV(p)       INT2PTR(IV,p)
+#  define PTR2UV(p)       INT2PTR(UV,p)
+#  define PTR2NV(p)       NUM2PTR(NV,p)
+
+#  if PTRSIZE == LONGSIZE
+#    define PTR2ul(p)     (unsigned long)(p)
+#  else
+#    define PTR2ul(p)     INT2PTR(unsigned long,p)
+#  endif
+#endif /* !INT2PTR */
+
+#ifndef SvPV_nolen
+# define SvPV_nolen(x) SvPV(x,PL_na)
+#endif
+
+#ifndef get_sv
+#  define get_sv perl_get_sv
+#endif
+
+#ifndef ERRSV
+#  define ERRSV get_sv("@",FALSE)
+#endif
+
+#ifndef pTHX_
+#define pTHX_
+#endif   
+
+#include <string.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGINTERN const char*
+SWIG_Perl_ErrorType(int code) {
+  const char* type = 0;
+  switch(code) {
+  case SWIG_MemoryError:
+    type = "MemoryError";
+    break;
+  case SWIG_IOError:
+    type = "IOError";
+    break;
+  case SWIG_RuntimeError:
+    type = "RuntimeError";
+    break;
+  case SWIG_IndexError:
+    type = "IndexError";
+    break;
+  case SWIG_TypeError:
+    type = "TypeError";
+    break;
+  case SWIG_DivisionByZero:
+    type = "ZeroDivisionError";
+    break;
+  case SWIG_OverflowError:
+    type = "OverflowError";
+    break;
+  case SWIG_SyntaxError:
+    type = "SyntaxError";
+    break;
+  case SWIG_ValueError:
+    type = "ValueError";
+    break;
+  case SWIG_SystemError:
+    type = "SystemError";
+    break;
+  case SWIG_AttributeError:
+    type = "AttributeError";
+    break;
+  default:
+    type = "RuntimeError";
+  }
+  return type;
+}
+
+
+
+
+/* -----------------------------------------------------------------------------
+ * perlrun.swg
+ *
+ * This file contains the runtime support for Perl modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef PERL_OBJECT
+#define SWIG_PERL_OBJECT_DECL CPerlObj *SWIGUNUSEDPARM(pPerl),
+#define SWIG_PERL_OBJECT_CALL pPerl,
+#else
+#define SWIG_PERL_OBJECT_DECL
+#define SWIG_PERL_OBJECT_CALL
+#endif
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_ConvertPtr(obj, pp, type, flags)           SWIG_Perl_ConvertPtr(SWIG_PERL_OBJECT_CALL obj, pp, type, flags)
+#define SWIG_NewPointerObj(p, type, flags)              SWIG_Perl_NewPointerObj(SWIG_PERL_OBJECT_CALL p, type, flags)
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, p, s, type)             SWIG_Perl_ConvertPacked(SWIG_PERL_OBJECT_CALL obj, p, s, type)
+#define SWIG_NewPackedObj(p, s, type)                  SWIG_Perl_NewPackedObj(SWIG_PERL_OBJECT_CALL p, s, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags)    SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags)           SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type)        SWIG_ConvertPtr(obj, pptr, type, 0)
+#define SWIG_NewFunctionPtrObj(ptr, type)               SWIG_NewPointerObj(ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty)            SWIG_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type)                SWIG_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata)                      SWIG_Perl_GetModule()
+#define SWIG_SetModule(clientdata, pointer)             SWIG_Perl_SetModule(pointer)
+
+
+/* Error manipulation */
+
+#define SWIG_ErrorType(code)                            SWIG_Perl_ErrorType(code)               
+#define SWIG_Error(code, msg)                          sv_setpvf(GvSV(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg)
+#define SWIG_fail                                      goto fail                                                   
+
+/* Perl-specific SWIG API */
+
+#define SWIG_MakePtr(sv, ptr, type, flags)              SWIG_Perl_MakePtr(SWIG_PERL_OBJECT_CALL sv, ptr, type, flags)
+#define SWIG_MakePackedObj(sv, p, s, type)             SWIG_Perl_MakePackedObj(SWIG_PERL_OBJECT_CALL sv, p, s, type)
+#define SWIG_SetError(str)                              SWIG_Error(SWIG_RuntimeError, str)
+
+
+#define SWIG_PERL_DECL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_DECL arg1)
+#define SWIG_PERL_CALL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_CALL arg1)
+#define SWIG_PERL_DECL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_DECL arg1, arg2)
+#define SWIG_PERL_CALL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_CALL arg1, arg2)
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+/* For backward compatibility only */
+#define SWIG_POINTER_EXCEPTION  0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_OWNER   SWIG_POINTER_OWN
+#define SWIG_SHADOW  SWIG_OWNER << 1
+
+#define SWIG_MAYBE_PERL_OBJECT SWIG_PERL_OBJECT_DECL
+
+/* SWIG Perl macros */
+
+/* Macro to declare an XS function */
+#ifndef XSPROTO
+#   define XSPROTO(name) void name(pTHX_ CV* cv)
+#endif
+
+/* Macro to call an XS function */
+#ifdef PERL_OBJECT 
+#  define SWIG_CALLXS(_name) _name(cv,pPerl) 
+#else 
+#  ifndef MULTIPLICITY 
+#    define SWIG_CALLXS(_name) _name(cv) 
+#  else 
+#    define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) 
+#  endif 
+#endif 
+
+#ifdef PERL_OBJECT
+#define MAGIC_PPERL  CPerlObj *pPerl = (CPerlObj *) this;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+#define SWIGCLASS_STATIC
+
+#else /* PERL_OBJECT */
+
+#define MAGIC_PPERL
+#define SWIGCLASS_STATIC static SWIGUNUSED
+
+#ifndef MULTIPLICITY
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MULTIPLICITY */
+
+#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MULTIPLICITY */
+#endif /* PERL_OBJECT */
+
+/* Workaround for bug in perl 5.6.x croak and earlier */
+#if (PERL_VERSION < 8)
+#  ifdef PERL_OBJECT
+#    define SWIG_croak_null() SWIG_Perl_croak_null(pPerl)
+static void SWIG_Perl_croak_null(CPerlObj *pPerl)
+#  else
+static void SWIG_croak_null()
+#  endif
+{
+  SV *err=ERRSV;
+#  if (PERL_VERSION < 6)
+  croak("%_", err);
+#  else
+  if (SvOK(err) && !SvROK(err)) croak("%_", err);
+  croak(Nullch);
+#  endif
+}
+#else
+#  define SWIG_croak_null() croak(Nullch)
+#endif
+
+
+/* 
+   Define how strict is the cast between strings and integers/doubles
+   when overloading between these types occurs.
+   
+   The default is making it as strict as possible by using SWIG_AddCast
+   when needed.
+   
+   You can use -DSWIG_PERL_NO_STRICT_STR2NUM at compilation time to
+   disable the SWIG_AddCast, making the casting between string and
+   numbers less strict.
+
+   In the end, we try to solve the overloading between strings and
+   numerical types in the more natural way, but if you can avoid it,
+   well, avoid it using %rename, for example.
+*/
+#ifndef SWIG_PERL_NO_STRICT_STR2NUM
+# ifndef SWIG_PERL_STRICT_STR2NUM
+#  define SWIG_PERL_STRICT_STR2NUM
+# endif
+#endif
+#ifdef SWIG_PERL_STRICT_STR2NUM
+/* string takes precedence */
+#define SWIG_Str2NumCast(x) SWIG_AddCast(x)  
+#else
+/* number takes precedence */
+#define SWIG_Str2NumCast(x) x
+#endif
+
+
+
+#include <stdlib.h>
+
+SWIGRUNTIME const char *
+SWIG_Perl_TypeProxyName(const swig_type_info *type) {
+  if (!type) return NULL;
+  if (type->clientdata != NULL) {
+    return (const char*) type->clientdata;
+  } 
+  else {
+    return type->name;
+  }
+}
+
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeProxyCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(( (!iter->type->clientdata && (strcmp((char*)iter->type->name, c) == 0)) 
+                           || (iter->type->clientdata && (strcmp((char*)iter->type->clientdata, c) == 0))), ty);
+}
+
+
+/* Function for getting a pointer value */
+
+SWIGRUNTIME int
+SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) {
+  swig_cast_info *tc;
+  void *voidptr = (void *)0;
+  SV *tsv = 0;
+  /* If magical, apply more magic */
+  if (SvGMAGICAL(sv))
+    mg_get(sv);
+
+  /* Check to see if this is an object */
+  if (sv_isobject(sv)) {
+    IV tmp = 0;
+    tsv = (SV*) SvRV(sv);
+    if ((SvTYPE(tsv) == SVt_PVHV)) {
+      MAGIC *mg;
+      if (SvMAGICAL(tsv)) {
+        mg = mg_find(tsv,'P');
+        if (mg) {
+          sv = mg->mg_obj;
+          if (sv_isobject(sv)) {
+           tsv = (SV*)SvRV(sv);
+            tmp = SvIV(tsv);
+          }
+        }
+      } else {
+        return SWIG_ERROR;
+      }
+    } else {
+      tmp = SvIV(tsv);
+    }
+    voidptr = INT2PTR(void *,tmp);
+  } else if (! SvOK(sv)) {            /* Check for undef */
+    *(ptr) = (void *) 0;
+    return SWIG_OK;
+  } else if (SvTYPE(sv) == SVt_RV) {  /* Check for NULL pointer */
+    if (!SvROK(sv)) {
+      *(ptr) = (void *) 0;
+      return SWIG_OK;
+    } else {
+      return SWIG_ERROR;
+    }
+  } else {                            /* Don't know what it is */
+    return SWIG_ERROR;
+  }
+  if (_t) {
+    /* Now see if the types match */
+    char *_c = HvNAME(SvSTASH(SvRV(sv)));
+    tc = SWIG_TypeProxyCheck(_c,_t);
+    if (!tc) {
+      return SWIG_ERROR;
+    }
+    *ptr = SWIG_TypeCast(tc,voidptr);
+  } else {
+    *ptr = voidptr;
+  }
+
+  /* 
+   *  DISOWN implementation: we need a perl guru to check this one.
+   */
+  if (tsv && (flags & SWIG_POINTER_DISOWN)) {
+    /* 
+     *  almost copy paste code from below SWIG_POINTER_OWN setting
+     */
+    SV *obj = sv;
+    HV *stash = SvSTASH(SvRV(obj));
+    GV *gv = *(GV**) hv_fetch(stash, "OWNER", 5, TRUE);
+    if (isGV(gv)) {
+      HV *hv = GvHVn(gv);
+      /*
+       * To set ownership (see below), a newSViv(1) entry is added. 
+       * Hence, to remove ownership, we delete the entry.
+       */
+      if (hv_exists_ent(hv, obj, 0)) {
+       hv_delete_ent(hv, obj, 0, 0);
+      }
+    }
+  }
+  return SWIG_OK;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) {
+  if (ptr && (flags & SWIG_SHADOW)) {
+    SV *self;
+    SV *obj=newSV(0);
+    HV *hash=newHV();
+    HV *stash;
+    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+    stash=SvSTASH(SvRV(obj));
+    if (flags & SWIG_POINTER_OWN) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+      if (!isGV(gv))
+        gv_init(gv, stash, "OWNER", 5, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newSViv(1), 0);
+    }
+    sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0);
+    SvREFCNT_dec(obj);
+    self=newRV_noinc((SV *)hash);
+    sv_setsv(sv, self);
+    SvREFCNT_dec((SV *)self);
+    sv_bless(sv, stash);
+  }
+  else {
+    sv_setref_pv(sv, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+  }
+}
+
+SWIGRUNTIMEINLINE SV *
+SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+  SV *result = sv_newmortal();
+  SWIG_MakePtr(result, ptr, t, flags);
+  return result;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) {
+  char result[1024];
+  char *r = result;
+  if ((2*sz + 1 + strlen(SWIG_Perl_TypeProxyName(type))) > 1000) return;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  strcpy(r,SWIG_Perl_TypeProxyName(type));
+  sv_setpv(sv, result);
+}
+
+SWIGRUNTIME SV *
+SWIG_Perl_NewPackedObj(SWIG_MAYBE_PERL_OBJECT void *ptr, int sz, swig_type_info *type) {
+  SV *result = sv_newmortal();
+  SWIG_Perl_MakePackedObj(result, ptr, sz, type);
+  return result;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME int
+SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty) {
+  swig_cast_info *tc;
+  const char  *c = 0;
+
+  if ((!obj) || (!SvOK(obj))) return SWIG_ERROR;
+  c = SvPV_nolen(obj);
+  /* Pointer values must start with leading underscore */
+  if (*c != '_') return SWIG_ERROR;
+  c++;
+  c = SWIG_UnpackData(c,ptr,sz);
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) return SWIG_ERROR;
+  }
+  return SWIG_OK;
+}
+
+
+/* Macros for low-level exception handling */
+#define SWIG_croak(x)    { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail; }
+
+
+typedef XSPROTO(SwigPerlWrapper);
+typedef SwigPerlWrapper *SwigPerlWrapperPtr;
+
+/* Structure for command table */
+typedef struct {
+  const char         *name;
+  SwigPerlWrapperPtr  wrapper;
+} swig_command_info;
+
+/* Information for constant table */
+
+#define SWIG_INT     1
+#define SWIG_FLOAT   2
+#define SWIG_STRING  3
+#define SWIG_POINTER 4
+#define SWIG_BINARY  5
+
+/* Constant information structure */
+typedef struct swig_constant_info {
+    int              type;
+    const char      *name;
+    long             lvalue;
+    double           dvalue;
+    void            *pvalue;
+    swig_type_info **ptype;
+} swig_constant_info;
+
+
+/* Structure for variable table */
+typedef struct {
+  const char   *name;
+  SwigMagicFunc   set;
+  SwigMagicFunc   get;
+  swig_type_info  **type;
+} swig_variable_info;
+
+/* Magic variable code */
+#ifndef PERL_OBJECT
+#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c)
+  #ifndef MULTIPLICITY
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) 
+  #else
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) 
+  #endif
+#else
+#  define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c)
+SWIGRUNTIME void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) 
+#endif
+{
+  MAGIC *mg;
+  sv_magic(sv,sv,'U',(char *) name,strlen(name));
+  mg = mg_find(sv,'U');
+  mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
+  mg->mg_virtual->svt_get = (SwigMagicFunc) get;
+  mg->mg_virtual->svt_set = (SwigMagicFunc) set;
+  mg->mg_virtual->svt_len = 0;
+  mg->mg_virtual->svt_clear = 0;
+  mg->mg_virtual->svt_free = 0;
+}
+
+
+SWIGRUNTIME swig_module_info *
+SWIG_Perl_GetModule(void) {
+  static void *type_pointer = (void *)0;
+  SV *pointer;
+
+  /* first check if pointer already created */
+  if (!type_pointer) {
+    pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE);
+    if (pointer && SvOK(pointer)) {
+      type_pointer = INT2PTR(swig_type_info **, SvIV(pointer));
+    }
+  }
+
+  return (swig_module_info *) type_pointer;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_SetModule(swig_module_info *module) {
+  SV *pointer;
+
+  /* create a new pointer */
+  pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE);
+  sv_setiv(pointer, PTR2IV(module));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Workaround perl5 global namespace pollution. Note that undefining library
+ * functions like fopen will not solve the problem on all platforms as fopen
+ * might be a macro on Windows but not necessarily on other operating systems. */
+#ifdef do_open
+  #undef do_open
+#endif
+#ifdef do_close
+  #undef do_close
+#endif
+#ifdef scalar
+  #undef scalar
+#endif
+#ifdef list
+  #undef list
+#endif
+#ifdef apply
+  #undef apply
+#endif
+#ifdef convert
+  #undef convert
+#endif
+#ifdef Error
+  #undef Error
+#endif
+#ifdef form
+  #undef form
+#endif
+#ifdef vform
+  #undef vform
+#endif
+#ifdef LABEL
+  #undef LABEL
+#endif
+#ifdef METHOD
+  #undef METHOD
+#endif
+#ifdef Move
+  #undef Move
+#endif
+#ifdef yylex
+  #undef yylex
+#endif
+#ifdef yyparse
+  #undef yyparse
+#endif
+#ifdef yyerror
+  #undef yyerror
+#endif
+#ifdef invert
+  #undef invert
+#endif
+#ifdef ref
+  #undef ref
+#endif
+#ifdef read
+  #undef read
+#endif
+#ifdef write
+  #undef write
+#endif
+#ifdef eof
+  #undef eof
+#endif
+#ifdef bool
+  #undef bool
+#endif
+#ifdef close
+  #undef close
+#endif
+#ifdef rewind
+  #undef rewind
+#endif
+#ifdef free
+  #undef free
+#endif
+#ifdef malloc
+  #undef malloc
+#endif
+#ifdef calloc
+  #undef calloc
+#endif
+#ifdef Stat
+  #undef Stat
+#endif
+#ifdef check
+  #undef check
+#endif
+#ifdef seekdir
+  #undef seekdir
+#endif
+#ifdef open
+  #undef open
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) 
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else 
+
+
+
+  #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) 
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_a_STRMAX__char swig_types[0]
+#define SWIGTYPE_p_char swig_types[1]
+#define SWIGTYPE_p_double swig_types[2]
+#define SWIGTYPE_p_dumpfile_t swig_types[3]
+#define SWIGTYPE_p_float swig_types[4]
+#define SWIGTYPE_p_int swig_types[5]
+#define SWIGTYPE_p_unsigned_char swig_types[6]
+static swig_type_info *swig_types[8];
+static swig_module_info swig_module = {swig_types, 7, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init    boot_Amanda__Types
+
+#define SWIG_name   "Amanda::Typesc::boot_Amanda__Types"
+#define SWIG_prefix "Amanda::Typesc::"
+
+#define SWIGVERSION 0x010333 
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a)) 
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) 
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifndef PERL_OBJECT
+#ifndef MULTIPLICITY
+SWIGEXPORT void SWIG_init (CV* cv);
+#else
+SWIGEXPORT void SWIG_init (pTHXo_ CV* cv);
+#endif
+#else
+SWIGEXPORT void SWIG_init (CV *cv, CPerlObj *);
+#endif
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "fileheader.h"
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_long  SWIG_PERL_DECL_ARGS_1(long value)
+{    
+  SV *obj = sv_newmortal();
+  sv_setiv(obj, (IV) value);
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_int  SWIG_PERL_DECL_ARGS_1(int value)
+{    
+  return SWIG_From_long  SWIG_PERL_CALL_ARGS_1(value);
+}
+
+
+#include <limits.h>
+#if !defined(SWIG_NO_LLONG_MAX)
+# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__)
+#   define LLONG_MAX __LONG_LONG_MAX__
+#   define LLONG_MIN (-LLONG_MAX - 1LL)
+#   define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+# endif
+#endif
+
+
+SWIGINTERN int
+SWIG_AsVal_double SWIG_PERL_DECL_ARGS_2(SV *obj, double *val)
+{
+  if (SvNIOK(obj)) {
+    if (val) *val = SvNV(obj);
+    return SWIG_OK;
+  } else if (SvIOK(obj)) {
+    if (val) *val = (double) SvIV(obj);
+    return SWIG_AddCast(SWIG_OK);
+  } else {
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      double v = strtod(nptr, &endptr);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+#include <float.h>
+
+
+#include <math.h>
+
+
+SWIGINTERNINLINE int
+SWIG_CanCastAsInteger(double *d, double min, double max) {
+  double x = *d;
+  if ((min <= x && x <= max)) {
+   double fx = floor(x);
+   double cx = ceil(x);
+   double rd =  ((x - fx) < 0.5) ? fx : cx; /* simple rint */
+   if ((errno == EDOM) || (errno == ERANGE)) {
+     errno = 0;
+   } else {
+     double summ, reps, diff;
+     if (rd < x) {
+       diff = x - rd;
+     } else if (rd > x) {
+       diff = rd - x;
+     } else {
+       return 1;
+     }
+     summ = rd + x;
+     reps = diff/summ;
+     if (reps < 8*DBL_EPSILON) {
+       *d = rd;
+       return 1;
+     }
+   }
+  }
+  return 0;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_long SWIG_PERL_DECL_ARGS_2(SV *obj, long* val)
+{
+  if (SvIOK(obj)) {
+    if (val) *val = SvIV(obj);
+    return SWIG_OK;
+  } else {
+    int dispatch = 0;
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      long v;
+      errno = 0;
+      v = strtol(nptr, &endptr,0);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+    if (!dispatch) {
+      double d;
+      int res = SWIG_AddCast(SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj,&d));
+      if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
+       if (val) *val = (long)(d);
+       return res;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_int SWIG_PERL_DECL_ARGS_2(SV * obj, int *val)
+{
+  long v;
+  int res = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v < INT_MIN || v > INT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = (int)(v);
+    }
+  }  
+  return res;
+}
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+  static int init = 0;
+  static swig_type_info* info = 0;
+  if (!init) {
+    info = SWIG_TypeQuery("_p_char");
+    init = 1;
+  }
+  return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(SV *obj, char** cptr, size_t* psize, int *alloc)
+{
+  if (SvPOK(obj)) {
+    STRLEN len = 0;
+    char *cstr = SvPV(obj, len); 
+    size_t size = len + 1;
+    if (cptr)  {
+      if (alloc) {
+       if (*alloc == SWIG_NEWOBJ) {
+         *cptr = (char *)memcpy((char *)malloc((size)*sizeof(char)), cstr, sizeof(char)*(size));
+       } else {
+         *cptr = cstr;
+         *alloc = SWIG_OLDOBJ;
+       }
+      }
+    }
+    if (psize) *psize = size;
+    return SWIG_OK;
+  } else {
+    swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+    if (pchar_descriptor) {
+      char* vptr = 0; 
+      if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_descriptor, 0) == SWIG_OK) {
+       if (cptr) *cptr = vptr;
+       if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0;
+       if (alloc) *alloc = SWIG_OLDOBJ;
+       return SWIG_OK;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharArray(SV * obj, char *val, size_t size)
+{ 
+  char* cptr = 0; size_t csize = 0; int alloc = SWIG_OLDOBJ;
+  int res = SWIG_AsCharPtrAndSize(obj, &cptr, &csize, &alloc);
+  if (SWIG_IsOK(res)) {
+    if ((csize == size + 1) && cptr && !(cptr[csize-1])) --csize;
+    if (csize <= size) {
+      if (val) {
+       if (csize) memcpy(val, cptr, csize*sizeof(char));
+       if (csize < size) memset(val + csize, 0, (size - csize)*sizeof(char));
+      }
+      if (alloc == SWIG_NEWOBJ) {
+       free((char*)cptr);
+       res = SWIG_DelNewMask(res);
+      }      
+      return res;
+    }
+    if (alloc == SWIG_NEWOBJ) free((char*)cptr);
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERNINLINE SV *
+SWIG_FromCharPtrAndSize(const char* carray, size_t size)
+{
+  SV *obj = sv_newmortal();
+  if (carray) {
+    sv_setpvn(obj, carray, size);
+  } else {
+    sv_setsv(obj, &PL_sv_undef);
+  }
+  return obj;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_unsigned_SS_long SWIG_PERL_DECL_ARGS_2(SV *obj, unsigned long *val) 
+{
+  if (SvUOK(obj)) {
+    if (val) *val = SvUV(obj);
+    return SWIG_OK;
+  } else  if (SvIOK(obj)) {
+    long v = SvIV(obj);
+    if (v >= 0) {
+      if (val) *val = v;
+      return SWIG_OK;
+    } else {
+      return SWIG_OverflowError;
+    }
+  } else {
+    int dispatch = 0;
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      unsigned long v;
+      errno = 0;
+      v = strtoul(nptr, &endptr,0);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+    if (!dispatch) {
+      double d;
+      int res = SWIG_AddCast(SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj,&d));
+      if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) {
+       if (val) *val = (unsigned long)(d);
+       return res;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERNINLINE int
+SWIG_AsVal_size_t SWIG_PERL_DECL_ARGS_2(SV * obj, size_t *val)
+{
+  unsigned long v;
+  int res = SWIG_AsVal_unsigned_SS_long SWIG_PERL_CALL_ARGS_2(obj, val ? &v : 0);
+  if (SWIG_IsOK(res) && val) *val = (size_t)(v);
+  return res;
+}
+
+SWIGINTERN dumpfile_t *new_dumpfile_t(){
+           dumpfile_t *df = malloc(sizeof(*df));
+           fh_init(df);
+           return df;
+       }
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef PERL_OBJECT
+#define MAGIC_CLASS _wrap_Amanda::Types_var::
+class _wrap_Amanda::Types_var : public CPerlObj {
+public:
+#else
+#define MAGIC_CLASS
+#endif
+SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {
+    MAGIC_PPERL
+    croak("Value is read-only.");
+    return 0;
+}
+
+
+#ifdef PERL_OBJECT
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+XS(_wrap_dumpfile_t_type_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    filetype_t arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_type_set(self,type);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_type_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    if (arg1) (arg1)->type = arg2;
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_type_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    filetype_t result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_type_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_type_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (filetype_t) ((arg1)->type);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_datestamp_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_datestamp_set(self,datestamp);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_datestamp_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_datestamp_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->datestamp, arg2, STRMAX);
+      if (arg1->datestamp[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_datestamp_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_datestamp_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_datestamp_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->datestamp);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_dumplevel_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_dumplevel_set(self,dumplevel);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_dumplevel_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    if (arg1) (arg1)->dumplevel = arg2;
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_dumplevel_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_dumplevel_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_dumplevel_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (int) ((arg1)->dumplevel);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_compressed_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_compressed_set(self,compressed);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_compressed_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    if (arg1) (arg1)->compressed = arg2;
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_compressed_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_compressed_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_compressed_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (int) ((arg1)->compressed);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_encrypted_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_encrypted_set(self,encrypted);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_encrypted_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    if (arg1) (arg1)->encrypted = arg2;
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_encrypted_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_encrypted_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_encrypted_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (int) ((arg1)->encrypted);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_comp_suffix_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_comp_suffix_set(self,comp_suffix);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_comp_suffix_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_comp_suffix_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->comp_suffix, arg2, STRMAX);
+      if (arg1->comp_suffix[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_comp_suffix_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_comp_suffix_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_comp_suffix_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->comp_suffix);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_encrypt_suffix_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_encrypt_suffix_set(self,encrypt_suffix);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_encrypt_suffix_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_encrypt_suffix_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->encrypt_suffix, arg2, STRMAX);
+      if (arg1->encrypt_suffix[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_encrypt_suffix_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_encrypt_suffix_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_encrypt_suffix_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->encrypt_suffix);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_name_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_name_set(self,name);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_name_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_name_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->name, arg2, STRMAX);
+      if (arg1->name[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_name_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_name_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_name_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->name);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_disk_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_disk_set(self,disk);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_disk_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_disk_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->disk, arg2, STRMAX);
+      if (arg1->disk[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_disk_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_disk_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_disk_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->disk);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_program_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_program_set(self,program);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_program_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_program_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->program, arg2, STRMAX);
+      if (arg1->program[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_program_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_program_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_program_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->program);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_dumper_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_dumper_set(self,dumper);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_dumper_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_dumper_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->dumper, arg2, STRMAX);
+      if (arg1->dumper[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_dumper_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_dumper_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_dumper_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->dumper);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_srvcompprog_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_srvcompprog_set(self,srvcompprog);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_srvcompprog_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_srvcompprog_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->srvcompprog, arg2, STRMAX);
+      if (arg1->srvcompprog[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_srvcompprog_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_srvcompprog_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_srvcompprog_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->srvcompprog);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_clntcompprog_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_clntcompprog_set(self,clntcompprog);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_clntcompprog_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_clntcompprog_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->clntcompprog, arg2, STRMAX);
+      if (arg1->clntcompprog[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_clntcompprog_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_clntcompprog_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_clntcompprog_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->clntcompprog);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_srv_encrypt_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_srv_encrypt_set(self,srv_encrypt);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_srv_encrypt_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_srv_encrypt_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->srv_encrypt, arg2, STRMAX);
+      if (arg1->srv_encrypt[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_srv_encrypt_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_srv_encrypt_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_srv_encrypt_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->srv_encrypt);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_clnt_encrypt_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_clnt_encrypt_set(self,clnt_encrypt);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_clnt_encrypt_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_clnt_encrypt_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->clnt_encrypt, arg2, STRMAX);
+      if (arg1->clnt_encrypt[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_clnt_encrypt_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_clnt_encrypt_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_clnt_encrypt_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->clnt_encrypt);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_recover_cmd_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_recover_cmd_set(self,recover_cmd);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_recover_cmd_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_recover_cmd_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->recover_cmd, arg2, STRMAX);
+      if (arg1->recover_cmd[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_recover_cmd_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_recover_cmd_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_recover_cmd_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->recover_cmd);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_uncompress_cmd_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_uncompress_cmd_set(self,uncompress_cmd);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_uncompress_cmd_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_uncompress_cmd_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->uncompress_cmd, arg2, STRMAX);
+      if (arg1->uncompress_cmd[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_uncompress_cmd_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_uncompress_cmd_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_uncompress_cmd_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->uncompress_cmd);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_encrypt_cmd_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_encrypt_cmd_set(self,encrypt_cmd);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_encrypt_cmd_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_encrypt_cmd_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->encrypt_cmd, arg2, STRMAX);
+      if (arg1->encrypt_cmd[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_encrypt_cmd_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_encrypt_cmd_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_encrypt_cmd_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->encrypt_cmd);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_decrypt_cmd_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_decrypt_cmd_set(self,decrypt_cmd);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_decrypt_cmd_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_decrypt_cmd_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->decrypt_cmd, arg2, STRMAX);
+      if (arg1->decrypt_cmd[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_decrypt_cmd_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_decrypt_cmd_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_decrypt_cmd_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->decrypt_cmd);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_srv_decrypt_opt_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_srv_decrypt_opt_set(self,srv_decrypt_opt);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_srv_decrypt_opt_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_srv_decrypt_opt_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->srv_decrypt_opt, arg2, STRMAX);
+      if (arg1->srv_decrypt_opt[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_srv_decrypt_opt_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_srv_decrypt_opt_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_srv_decrypt_opt_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->srv_decrypt_opt);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_clnt_decrypt_opt_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_clnt_decrypt_opt_set(self,clnt_decrypt_opt);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_clnt_decrypt_opt_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_clnt_decrypt_opt_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->clnt_decrypt_opt, arg2, STRMAX);
+      if (arg1->clnt_decrypt_opt[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_clnt_decrypt_opt_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_clnt_decrypt_opt_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_clnt_decrypt_opt_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->clnt_decrypt_opt);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_cont_filename_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char temp2[STRMAX] ;
+    int res2 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_cont_filename_set(self,cont_filename);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_cont_filename_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    res2 = SWIG_AsCharArray(ST(1), temp2, STRMAX);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dumpfile_t_cont_filename_set" "', argument " "2"" of type '" "char [STRMAX]""'");
+    }
+    arg2 = (char *)(temp2);
+    {
+      strncpy(arg1->cont_filename, arg2, STRMAX);
+      if (arg1->cont_filename[STRMAX-1] != '\0')
+      SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_cont_filename_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    char *result = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_cont_filename_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_cont_filename_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (char *) ((arg1)->cont_filename);
+    {
+      size_t size = STRMAX;
+      
+      while (size && (result[size - 1] == '\0')) --size;
+      
+      ST(argvi) = SWIG_FromCharPtrAndSize(result, size); argvi++ ;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_is_partial_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_is_partial_set(self,is_partial);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_is_partial_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    if (arg1) (arg1)->is_partial = arg2;
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_is_partial_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_is_partial_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_is_partial_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (int) ((arg1)->is_partial);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_partnum_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_partnum_set(self,partnum);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_partnum_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    if (arg1) (arg1)->partnum = arg2;
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_partnum_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_partnum_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_partnum_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (int) ((arg1)->partnum);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_totalparts_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_totalparts_set(self,totalparts);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_totalparts_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    {
+      if (sizeof(signed int) == 1) {
+        arg2 = amglue_SvI8(ST(1));
+      } else if (sizeof(signed int) == 2) {
+        arg2 = amglue_SvI16(ST(1));
+      } else if (sizeof(signed int) == 4) {
+        arg2 = amglue_SvI32(ST(1));
+      } else if (sizeof(signed int) == 8) {
+        arg2 = amglue_SvI64(ST(1));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    if (arg1) (arg1)->totalparts = arg2;
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_totalparts_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    int result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_totalparts_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_totalparts_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result = (int) ((arg1)->totalparts);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVi64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_blocksize_set) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    size_t arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: dumpfile_t_blocksize_set(self,blocksize);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_blocksize_set" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    {
+      if (sizeof(size_t) == 1) {
+        arg2 = amglue_SvU8(ST(1));
+      } else if (sizeof(size_t) == 2) {
+        arg2 = amglue_SvU16(ST(1));
+      } else if (sizeof(size_t) == 4) {
+        arg2 = amglue_SvU32(ST(1));
+      } else if (sizeof(size_t) == 8) {
+        arg2 = amglue_SvU64(ST(1));
+      } else {
+        croak("Unexpected size_t >64 bits?"); /* should be optimized out unless sizeof(size_t) > 8 */
+      }
+    }
+    if (arg1) (arg1)->blocksize = arg2;
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_dumpfile_t_blocksize_get) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    size_t result;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: dumpfile_t_blocksize_get(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dumpfile_t_blocksize_get" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    result =  ((arg1)->blocksize);
+    {
+      ST(argvi) = sv_2mortal(amglue_newSVu64(result));
+      argvi++;
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_new_dumpfile_t) {
+  {
+    dumpfile_t *result = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: new_dumpfile_t();");
+    }
+    result = (dumpfile_t *)new_dumpfile_t();
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_dumpfile_t, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_delete_dumpfile_t__SWIG_1) {
+  {
+    dumpfile_t *arg1 = (dumpfile_t *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: delete_dumpfile_t(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_dumpfile_t, SWIG_POINTER_DISOWN |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_dumpfile_t" "', argument " "1"" of type '" "dumpfile_t *""'"); 
+    }
+    arg1 = (dumpfile_t *)(argp1);
+    free((char *) arg1);
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_delete_dumpfile_t) {
+  dXSARGS;
+  
+  {
+    unsigned long _index = 0;
+    SWIG_TypeRank _rank = 0; 
+    if (items == 1) {
+      SWIG_TypeRank _ranki = 0;
+      SWIG_TypeRank _rankm = 0;
+      SWIG_TypeRank _pi = 1;
+      int _v = 0;
+      {
+        void *vptr = 0;
+        int res = SWIG_ConvertPtr(ST(0), &vptr, SWIGTYPE_p_dumpfile_t, 0);
+        _v = SWIG_CheckState(res);
+      }
+      if (!_v) goto check_1;
+      _ranki += _v*_pi;
+      _rankm += _pi;
+      _pi *= SWIG_MAXCASTRANK;
+      if (!_index || (_ranki < _rank)) {
+        _rank = _ranki; _index = 1;
+        if (_rank == _rankm) goto dispatch;
+      }
+    }
+  check_1:
+    
+  dispatch:
+    switch(_index) {
+    case 1:
+      ++PL_markstack_ptr; SWIG_CALLXS(_wrap_delete_dumpfile_t__SWIG_1); return;
+    }
+  }
+  
+  croak("No matching function for overloaded 'delete_dumpfile_t'");
+  XSRETURN(0);
+}
+
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_a_STRMAX__char = {"_p_a_STRMAX__char", "char (*)[STRMAX]|string_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_char = {"_p_char", "gchar *|char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_double = {"_p_double", "double *|gdouble *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_dumpfile_t = {"_p_dumpfile_t", "dumpfile_t *", 0, 0, (void*)"Amanda::Types::dumpfile_t", 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *|gfloat *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "int *|filetype_t *|gboolean *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "guchar *|unsigned char *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_a_STRMAX__char,
+  &_swigt__p_char,
+  &_swigt__p_double,
+  &_swigt__p_dumpfile_t,
+  &_swigt__p_float,
+  &_swigt__p_int,
+  &_swigt__p_unsigned_char,
+};
+
+static swig_cast_info _swigc__p_a_STRMAX__char[] = {  {&_swigt__p_a_STRMAX__char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_dumpfile_t[] = {  {&_swigt__p_dumpfile_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_char[] = {  {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_a_STRMAX__char,
+  _swigc__p_char,
+  _swigc__p_double,
+  _swigc__p_dumpfile_t,
+  _swigc__p_float,
+  _swigc__p_int,
+  _swigc__p_unsigned_char,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_constant_info swig_constants[] = {
+{0,0,0,0,0,0}
+};
+#ifdef __cplusplus
+}
+#endif
+static swig_variable_info swig_variables[] = {
+{0,0,0,0}
+};
+static swig_command_info swig_commands[] = {
+{"Amanda::Typesc::dumpfile_t_type_set", _wrap_dumpfile_t_type_set},
+{"Amanda::Typesc::dumpfile_t_type_get", _wrap_dumpfile_t_type_get},
+{"Amanda::Typesc::dumpfile_t_datestamp_set", _wrap_dumpfile_t_datestamp_set},
+{"Amanda::Typesc::dumpfile_t_datestamp_get", _wrap_dumpfile_t_datestamp_get},
+{"Amanda::Typesc::dumpfile_t_dumplevel_set", _wrap_dumpfile_t_dumplevel_set},
+{"Amanda::Typesc::dumpfile_t_dumplevel_get", _wrap_dumpfile_t_dumplevel_get},
+{"Amanda::Typesc::dumpfile_t_compressed_set", _wrap_dumpfile_t_compressed_set},
+{"Amanda::Typesc::dumpfile_t_compressed_get", _wrap_dumpfile_t_compressed_get},
+{"Amanda::Typesc::dumpfile_t_encrypted_set", _wrap_dumpfile_t_encrypted_set},
+{"Amanda::Typesc::dumpfile_t_encrypted_get", _wrap_dumpfile_t_encrypted_get},
+{"Amanda::Typesc::dumpfile_t_comp_suffix_set", _wrap_dumpfile_t_comp_suffix_set},
+{"Amanda::Typesc::dumpfile_t_comp_suffix_get", _wrap_dumpfile_t_comp_suffix_get},
+{"Amanda::Typesc::dumpfile_t_encrypt_suffix_set", _wrap_dumpfile_t_encrypt_suffix_set},
+{"Amanda::Typesc::dumpfile_t_encrypt_suffix_get", _wrap_dumpfile_t_encrypt_suffix_get},
+{"Amanda::Typesc::dumpfile_t_name_set", _wrap_dumpfile_t_name_set},
+{"Amanda::Typesc::dumpfile_t_name_get", _wrap_dumpfile_t_name_get},
+{"Amanda::Typesc::dumpfile_t_disk_set", _wrap_dumpfile_t_disk_set},
+{"Amanda::Typesc::dumpfile_t_disk_get", _wrap_dumpfile_t_disk_get},
+{"Amanda::Typesc::dumpfile_t_program_set", _wrap_dumpfile_t_program_set},
+{"Amanda::Typesc::dumpfile_t_program_get", _wrap_dumpfile_t_program_get},
+{"Amanda::Typesc::dumpfile_t_dumper_set", _wrap_dumpfile_t_dumper_set},
+{"Amanda::Typesc::dumpfile_t_dumper_get", _wrap_dumpfile_t_dumper_get},
+{"Amanda::Typesc::dumpfile_t_srvcompprog_set", _wrap_dumpfile_t_srvcompprog_set},
+{"Amanda::Typesc::dumpfile_t_srvcompprog_get", _wrap_dumpfile_t_srvcompprog_get},
+{"Amanda::Typesc::dumpfile_t_clntcompprog_set", _wrap_dumpfile_t_clntcompprog_set},
+{"Amanda::Typesc::dumpfile_t_clntcompprog_get", _wrap_dumpfile_t_clntcompprog_get},
+{"Amanda::Typesc::dumpfile_t_srv_encrypt_set", _wrap_dumpfile_t_srv_encrypt_set},
+{"Amanda::Typesc::dumpfile_t_srv_encrypt_get", _wrap_dumpfile_t_srv_encrypt_get},
+{"Amanda::Typesc::dumpfile_t_clnt_encrypt_set", _wrap_dumpfile_t_clnt_encrypt_set},
+{"Amanda::Typesc::dumpfile_t_clnt_encrypt_get", _wrap_dumpfile_t_clnt_encrypt_get},
+{"Amanda::Typesc::dumpfile_t_recover_cmd_set", _wrap_dumpfile_t_recover_cmd_set},
+{"Amanda::Typesc::dumpfile_t_recover_cmd_get", _wrap_dumpfile_t_recover_cmd_get},
+{"Amanda::Typesc::dumpfile_t_uncompress_cmd_set", _wrap_dumpfile_t_uncompress_cmd_set},
+{"Amanda::Typesc::dumpfile_t_uncompress_cmd_get", _wrap_dumpfile_t_uncompress_cmd_get},
+{"Amanda::Typesc::dumpfile_t_encrypt_cmd_set", _wrap_dumpfile_t_encrypt_cmd_set},
+{"Amanda::Typesc::dumpfile_t_encrypt_cmd_get", _wrap_dumpfile_t_encrypt_cmd_get},
+{"Amanda::Typesc::dumpfile_t_decrypt_cmd_set", _wrap_dumpfile_t_decrypt_cmd_set},
+{"Amanda::Typesc::dumpfile_t_decrypt_cmd_get", _wrap_dumpfile_t_decrypt_cmd_get},
+{"Amanda::Typesc::dumpfile_t_srv_decrypt_opt_set", _wrap_dumpfile_t_srv_decrypt_opt_set},
+{"Amanda::Typesc::dumpfile_t_srv_decrypt_opt_get", _wrap_dumpfile_t_srv_decrypt_opt_get},
+{"Amanda::Typesc::dumpfile_t_clnt_decrypt_opt_set", _wrap_dumpfile_t_clnt_decrypt_opt_set},
+{"Amanda::Typesc::dumpfile_t_clnt_decrypt_opt_get", _wrap_dumpfile_t_clnt_decrypt_opt_get},
+{"Amanda::Typesc::dumpfile_t_cont_filename_set", _wrap_dumpfile_t_cont_filename_set},
+{"Amanda::Typesc::dumpfile_t_cont_filename_get", _wrap_dumpfile_t_cont_filename_get},
+{"Amanda::Typesc::dumpfile_t_is_partial_set", _wrap_dumpfile_t_is_partial_set},
+{"Amanda::Typesc::dumpfile_t_is_partial_get", _wrap_dumpfile_t_is_partial_get},
+{"Amanda::Typesc::dumpfile_t_partnum_set", _wrap_dumpfile_t_partnum_set},
+{"Amanda::Typesc::dumpfile_t_partnum_get", _wrap_dumpfile_t_partnum_get},
+{"Amanda::Typesc::dumpfile_t_totalparts_set", _wrap_dumpfile_t_totalparts_set},
+{"Amanda::Typesc::dumpfile_t_totalparts_get", _wrap_dumpfile_t_totalparts_get},
+{"Amanda::Typesc::dumpfile_t_blocksize_set", _wrap_dumpfile_t_blocksize_set},
+{"Amanda::Typesc::dumpfile_t_blocksize_get", _wrap_dumpfile_t_blocksize_get},
+{"Amanda::Typesc::new_dumpfile_t", _wrap_new_dumpfile_t},
+{"Amanda::Typesc::delete_dumpfile_t", _wrap_delete_dumpfile_t},
+{0,0}
+};
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic 
+ * memory is used. Also, since swig_type_info structures store pointers to 
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization. 
+ * The idea is that swig generates all the structures that are needed. 
+ * The runtime then collects these partially filled structures. 
+ * The SWIG_InitializeModule function takes these initial arrays out of 
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned staticly to an initial 
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it 
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded. 
+ * There are three cases to handle:
+ *  1) If the cast->type has already been loaded AND the type we are adding
+ *     casting info to has not been loaded (it is in this module), THEN we
+ *     replace the cast->type pointer with the type pointer that has already
+ *     been loaded.
+ *  2) If BOTH types (the one we are adding casting info to, and the 
+ *     cast->type) are loaded, THEN the cast info has already been loaded by
+ *     the previous module so we just ignore it.
+ *  3) Finally, if cast->type has not already been loaded, then we add that
+ *     swig_cast_info to the linked list (because the cast->type) pointer will
+ *     be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+  size_t i;
+  swig_module_info *module_head, *iter;
+  int found;
+  
+  clientdata = clientdata;
+  
+  /* check to see if the circular list has been setup, if not, set it up */
+  if (swig_module.next==0) {
+    /* Initialize the swig_module */
+    swig_module.type_initial = swig_type_initial;
+    swig_module.cast_initial = swig_cast_initial;
+    swig_module.next = &swig_module;
+  }
+  
+  /* Try and load any already created modules */
+  module_head = SWIG_GetModule(clientdata);
+  if (!module_head) {
+    /* This is the first module loaded for this interpreter */
+    /* so set the swig module into the interpreter */
+    SWIG_SetModule(clientdata, &swig_module);
+    module_head = &swig_module;
+  } else {
+    /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+    found=0;
+    iter=module_head;
+    do {
+      if (iter==&swig_module) {
+        found=1;
+        break;
+      }
+      iter=iter->next;
+    } while (iter!= module_head);
+    
+    /* if the is found in the list, then all is done and we may leave */
+    if (found) return;
+    /* otherwise we must add out module into the list */
+    swig_module.next = module_head->next;
+    module_head->next = &swig_module;
+  }
+  
+  /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+  printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+  for (i = 0; i < swig_module.size; ++i) {
+    swig_type_info *type = 0;
+    swig_type_info *ret;
+    swig_cast_info *cast;
+    
+#ifdef SWIGRUNTIME_DEBUG
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+    
+    /* if there is another module already loaded */
+    if (swig_module.next != &swig_module) {
+      type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+    }
+    if (type) {
+      /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+      if (swig_module.type_initial[i]->clientdata) {
+        type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+      }
+    } else {
+      type = swig_module.type_initial[i];
+    }
+    
+    /* Insert casting types */
+    cast = swig_module.cast_initial[i];
+    while (cast->type) {
+      /* Don't need to add information already in the list */
+      ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+      if (swig_module.next != &swig_module) {
+        ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+        if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+      }
+      if (ret) {
+        if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+          printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+          cast->type = ret;
+          ret = 0;
+        } else {
+          /* Check for casting already in the list */
+          swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+          if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+          if (!ocast) ret = 0;
+        }
+      }
+      
+      if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+        if (type->cast) {
+          type->cast->prev = cast;
+          cast->next = type->cast;
+        }
+        type->cast = cast;
+      }
+      cast++;
+    }
+    /* Set entry in modules->types array equal to the type */
+    swig_module.types[i] = type;
+  }
+  swig_module.types[i] = 0;
+  
+#ifdef SWIGRUNTIME_DEBUG
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+  for (i = 0; i < swig_module.size; ++i) {
+    int j = 0;
+    swig_cast_info *cast = swig_module.cast_initial[i];
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+    while (cast->type) {
+      printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+      cast++;
+      ++j;
+    }
+    printf("---- Total casts: %d\n",j);
+  }
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types.  It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+  size_t i;
+  swig_cast_info *equiv;
+  static int init_run = 0;
+  
+  if (init_run) return;
+  init_run = 1;
+  
+  for (i = 0; i < swig_module.size; i++) {
+    if (swig_module.types[i]->clientdata) {
+      equiv = swig_module.types[i]->cast;
+      while (equiv) {
+        if (!equiv->converter) {
+          if (equiv->type && !equiv->type->clientdata)
+          SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+        }
+        equiv = equiv->next;
+      }
+    }
+  }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+  /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(SWIG_init) {
+  dXSARGS;
+  int i;
+  
+  SWIG_InitializeModule(0);
+  
+  /* Install commands */
+  for (i = 0; swig_commands[i].name; i++) {
+    newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__);
+  }
+  
+  /* Install variables */
+  for (i = 0; swig_variables[i].name; i++) {
+    SV *sv;
+    sv = get_sv((char*) swig_variables[i].name, TRUE | 0x2);
+    if (swig_variables[i].type) {
+      SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0);
+    } else {
+      sv_setiv(sv,(IV) 0);
+    }
+    swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); 
+  }
+  
+  /* Install constant */
+  for (i = 0; swig_constants[i].type; i++) {
+    SV *sv;
+    sv = get_sv((char*)swig_constants[i].name, TRUE | 0x2);
+    switch(swig_constants[i].type) {
+    case SWIG_INT:
+      sv_setiv(sv, (IV) swig_constants[i].lvalue);
+      break;
+    case SWIG_FLOAT:
+      sv_setnv(sv, (double) swig_constants[i].dvalue);
+      break;
+    case SWIG_STRING:
+      sv_setpv(sv, (char *) swig_constants[i].pvalue);
+      break;
+    case SWIG_POINTER:
+      SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
+      break;
+    case SWIG_BINARY:
+      SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
+      break;
+    default:
+      break;
+    }
+    SvREADONLY_on(sv);
+  }
+  
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_UNKNOWN", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(F_UNKNOWN)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_WEIRD", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(F_WEIRD)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_TAPESTART", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(F_TAPESTART)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_TAPEEND", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(F_TAPEEND)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_DUMPFILE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(F_DUMPFILE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_CONT_DUMPFILE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(F_CONT_DUMPFILE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_SPLIT_DUMPFILE", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(F_SPLIT_DUMPFILE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_EMPTY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(F_EMPTY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  SWIG_TypeClientData(SWIGTYPE_p_dumpfile_t, (void*) "Amanda::Types::dumpfile_t");
+  ST(0) = &PL_sv_yes;
+  XSRETURN(1);
+}
+
diff --git a/perl/Amanda/Types.pm b/perl/Amanda/Types.pm
new file mode 100644 (file)
index 0000000..02ed893
--- /dev/null
@@ -0,0 +1,286 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 1.3.33
+#
+# Don't modify this file, modify the SWIG interface instead.
+
+package Amanda::Types;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+package Amanda::Typesc;
+bootstrap Amanda::Types;
+package Amanda::Types;
+@EXPORT = qw( );
+
+# ---------- BASE METHODS -------------
+
+package Amanda::Types;
+
+sub TIEHASH {
+    my ($classname,$obj) = @_;
+    return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+    my ($self,$field) = @_;
+    my $member_func = "swig_${field}_get";
+    $self->$member_func();
+}
+
+sub STORE {
+    my ($self,$field,$newval) = @_;
+    my $member_func = "swig_${field}_set";
+    $self->$member_func($newval);
+}
+
+sub this {
+    my $ptr = shift;
+    return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package Amanda::Types;
+
+
+############# Class : Amanda::Types::dumpfile_t ##############
+
+package Amanda::Types::dumpfile_t;
+use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
+@ISA = qw( Amanda::Types );
+%OWNER = ();
+%ITERATORS = ();
+*swig_type_get = *Amanda::Typesc::dumpfile_t_type_get;
+*swig_type_set = *Amanda::Typesc::dumpfile_t_type_set;
+*swig_datestamp_get = *Amanda::Typesc::dumpfile_t_datestamp_get;
+*swig_datestamp_set = *Amanda::Typesc::dumpfile_t_datestamp_set;
+*swig_dumplevel_get = *Amanda::Typesc::dumpfile_t_dumplevel_get;
+*swig_dumplevel_set = *Amanda::Typesc::dumpfile_t_dumplevel_set;
+*swig_compressed_get = *Amanda::Typesc::dumpfile_t_compressed_get;
+*swig_compressed_set = *Amanda::Typesc::dumpfile_t_compressed_set;
+*swig_encrypted_get = *Amanda::Typesc::dumpfile_t_encrypted_get;
+*swig_encrypted_set = *Amanda::Typesc::dumpfile_t_encrypted_set;
+*swig_comp_suffix_get = *Amanda::Typesc::dumpfile_t_comp_suffix_get;
+*swig_comp_suffix_set = *Amanda::Typesc::dumpfile_t_comp_suffix_set;
+*swig_encrypt_suffix_get = *Amanda::Typesc::dumpfile_t_encrypt_suffix_get;
+*swig_encrypt_suffix_set = *Amanda::Typesc::dumpfile_t_encrypt_suffix_set;
+*swig_name_get = *Amanda::Typesc::dumpfile_t_name_get;
+*swig_name_set = *Amanda::Typesc::dumpfile_t_name_set;
+*swig_disk_get = *Amanda::Typesc::dumpfile_t_disk_get;
+*swig_disk_set = *Amanda::Typesc::dumpfile_t_disk_set;
+*swig_program_get = *Amanda::Typesc::dumpfile_t_program_get;
+*swig_program_set = *Amanda::Typesc::dumpfile_t_program_set;
+*swig_dumper_get = *Amanda::Typesc::dumpfile_t_dumper_get;
+*swig_dumper_set = *Amanda::Typesc::dumpfile_t_dumper_set;
+*swig_srvcompprog_get = *Amanda::Typesc::dumpfile_t_srvcompprog_get;
+*swig_srvcompprog_set = *Amanda::Typesc::dumpfile_t_srvcompprog_set;
+*swig_clntcompprog_get = *Amanda::Typesc::dumpfile_t_clntcompprog_get;
+*swig_clntcompprog_set = *Amanda::Typesc::dumpfile_t_clntcompprog_set;
+*swig_srv_encrypt_get = *Amanda::Typesc::dumpfile_t_srv_encrypt_get;
+*swig_srv_encrypt_set = *Amanda::Typesc::dumpfile_t_srv_encrypt_set;
+*swig_clnt_encrypt_get = *Amanda::Typesc::dumpfile_t_clnt_encrypt_get;
+*swig_clnt_encrypt_set = *Amanda::Typesc::dumpfile_t_clnt_encrypt_set;
+*swig_recover_cmd_get = *Amanda::Typesc::dumpfile_t_recover_cmd_get;
+*swig_recover_cmd_set = *Amanda::Typesc::dumpfile_t_recover_cmd_set;
+*swig_uncompress_cmd_get = *Amanda::Typesc::dumpfile_t_uncompress_cmd_get;
+*swig_uncompress_cmd_set = *Amanda::Typesc::dumpfile_t_uncompress_cmd_set;
+*swig_encrypt_cmd_get = *Amanda::Typesc::dumpfile_t_encrypt_cmd_get;
+*swig_encrypt_cmd_set = *Amanda::Typesc::dumpfile_t_encrypt_cmd_set;
+*swig_decrypt_cmd_get = *Amanda::Typesc::dumpfile_t_decrypt_cmd_get;
+*swig_decrypt_cmd_set = *Amanda::Typesc::dumpfile_t_decrypt_cmd_set;
+*swig_srv_decrypt_opt_get = *Amanda::Typesc::dumpfile_t_srv_decrypt_opt_get;
+*swig_srv_decrypt_opt_set = *Amanda::Typesc::dumpfile_t_srv_decrypt_opt_set;
+*swig_clnt_decrypt_opt_get = *Amanda::Typesc::dumpfile_t_clnt_decrypt_opt_get;
+*swig_clnt_decrypt_opt_set = *Amanda::Typesc::dumpfile_t_clnt_decrypt_opt_set;
+*swig_cont_filename_get = *Amanda::Typesc::dumpfile_t_cont_filename_get;
+*swig_cont_filename_set = *Amanda::Typesc::dumpfile_t_cont_filename_set;
+*swig_is_partial_get = *Amanda::Typesc::dumpfile_t_is_partial_get;
+*swig_is_partial_set = *Amanda::Typesc::dumpfile_t_is_partial_set;
+*swig_partnum_get = *Amanda::Typesc::dumpfile_t_partnum_get;
+*swig_partnum_set = *Amanda::Typesc::dumpfile_t_partnum_set;
+*swig_totalparts_get = *Amanda::Typesc::dumpfile_t_totalparts_get;
+*swig_totalparts_set = *Amanda::Typesc::dumpfile_t_totalparts_set;
+*swig_blocksize_get = *Amanda::Typesc::dumpfile_t_blocksize_get;
+*swig_blocksize_set = *Amanda::Typesc::dumpfile_t_blocksize_set;
+sub new {
+    my $pkg = shift;
+    my $self = Amanda::Typesc::new_dumpfile_t(@_);
+    bless $self, $pkg if defined($self);
+}
+
+sub DESTROY {
+    return unless $_[0]->isa('HASH');
+    my $self = tied(%{$_[0]});
+    return unless defined $self;
+    delete $ITERATORS{$self};
+    if (exists $OWNER{$self}) {
+        Amanda::Typesc::delete_dumpfile_t($self);
+        delete $OWNER{$self};
+    }
+}
+
+sub DISOWN {
+    my $self = shift;
+    my $ptr = tied(%$self);
+    delete $OWNER{$ptr};
+}
+
+sub ACQUIRE {
+    my $self = shift;
+    my $ptr = tied(%$self);
+    $OWNER{$ptr} = 1;
+}
+
+
+# ------- VARIABLE STUBS --------
+
+package Amanda::Types;
+
+*F_UNKNOWN = *Amanda::Typesc::F_UNKNOWN;
+*F_WEIRD = *Amanda::Typesc::F_WEIRD;
+*F_TAPESTART = *Amanda::Typesc::F_TAPESTART;
+*F_TAPEEND = *Amanda::Typesc::F_TAPEEND;
+*F_DUMPFILE = *Amanda::Typesc::F_DUMPFILE;
+*F_CONT_DUMPFILE = *Amanda::Typesc::F_CONT_DUMPFILE;
+*F_SPLIT_DUMPFILE = *Amanda::Typesc::F_SPLIT_DUMPFILE;
+*F_EMPTY = *Amanda::Typesc::F_EMPTY;
+
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+
+=head1 NAME
+
+Amanda::Types - Amanda data structures that are shared by several modules
+
+=head1 SYNOPSIS
+
+This module includes several types which are not specific to any
+single other module.
+
+=head1 API STATUS
+
+New structures may be added, but existing types are stable.
+
+=head1 dumpfile_t
+
+An in-memory representation of an Amanda header, with keys
+=over
+=item C<type>;
+=item C<datestamp>;
+=item C<dumplevel>;
+=item C<compressed>;
+=item C<encrypted>;
+=item C<comp_suffix>;
+=item C<encrypt_suffix>;
+=item C<name> -- hostname or label;
+=item C<disk>;
+=item C<program>;
+=item C<dumper>;
+=item C<srvcompprog>;
+=item C<clntcompprog>;
+=item C<srv_encrypt>;
+=item C<clnt_encrypt>;
+=item C<recover_cmd>;
+=item C<uncompress_cmd>;
+=item C<encrypt_cmd>;
+=item C<decrypt_cmd>;
+=item C<srv_decrypt_opt>;
+=item C<clnt_decrypt_opt>;
+=item C<cont_filename>;
+=item C<is_partial>;
+=item C<partnum>;
+=item C<totalparts> (-1 == UNKNOWN); and
+=item blocksize.
+=back
+
+where C<type> is one of the following constants, which are availble
+for import in the tag C<:filetype_t>:
+=over
+=item C<F_UNKNOWN>;
+=item C<F_WEIRD>;
+=item C<F_TAPESTART>;
+=item C<F_TAPEEND>;
+=item C<F_DUMPFILE>;
+=item C<F_CONT_DUMPFILE>;
+=item C<F_SPLIT_DUMPFILE>; or
+=item C<F_EMPTY>.
+=back
+
+NOTE: no methods are currently defined on C<dumpfile_t>; interfaces
+can be written as needed.
+
+=cut
+
+push @EXPORT_OK, qw(filetype_t_to_strings);
+push @{$EXPORT_TAGS{"filetype_t"}}, qw(filetype_t_to_strings);
+
+my %_filetype_t_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub filetype_t_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_filetype_t_VALUES) {
+       my $v = $_filetype_t_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($F_UNKNOWN);
+push @{$EXPORT_TAGS{"filetype_t"}}, qw($F_UNKNOWN);
+
+$_filetype_t_VALUES{"F_UNKNOWN"} = $F_UNKNOWN;
+
+push @EXPORT_OK, qw($F_WEIRD);
+push @{$EXPORT_TAGS{"filetype_t"}}, qw($F_WEIRD);
+
+$_filetype_t_VALUES{"F_WEIRD"} = $F_WEIRD;
+
+push @EXPORT_OK, qw($F_TAPESTART);
+push @{$EXPORT_TAGS{"filetype_t"}}, qw($F_TAPESTART);
+
+$_filetype_t_VALUES{"F_TAPESTART"} = $F_TAPESTART;
+
+push @EXPORT_OK, qw($F_TAPEEND);
+push @{$EXPORT_TAGS{"filetype_t"}}, qw($F_TAPEEND);
+
+$_filetype_t_VALUES{"F_TAPEEND"} = $F_TAPEEND;
+
+push @EXPORT_OK, qw($F_DUMPFILE);
+push @{$EXPORT_TAGS{"filetype_t"}}, qw($F_DUMPFILE);
+
+$_filetype_t_VALUES{"F_DUMPFILE"} = $F_DUMPFILE;
+
+push @EXPORT_OK, qw($F_CONT_DUMPFILE);
+push @{$EXPORT_TAGS{"filetype_t"}}, qw($F_CONT_DUMPFILE);
+
+$_filetype_t_VALUES{"F_CONT_DUMPFILE"} = $F_CONT_DUMPFILE;
+
+push @EXPORT_OK, qw($F_SPLIT_DUMPFILE);
+push @{$EXPORT_TAGS{"filetype_t"}}, qw($F_SPLIT_DUMPFILE);
+
+$_filetype_t_VALUES{"F_SPLIT_DUMPFILE"} = $F_SPLIT_DUMPFILE;
+
+push @EXPORT_OK, qw($F_EMPTY);
+push @{$EXPORT_TAGS{"filetype_t"}}, qw($F_EMPTY);
+
+$_filetype_t_VALUES{"F_EMPTY"} = $F_EMPTY;
+1;
diff --git a/perl/Amanda/Types.swg b/perl/Amanda/Types.swg
new file mode 100644 (file)
index 0000000..ff23501
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%module "Amanda::Types"
+%include "amglue/amglue.swg"
+%include "exception.i"
+
+%{
+#include "fileheader.h"
+%}
+
+%perlcode %{
+=head1 NAME
+
+Amanda::Types - Amanda data structures that are shared by several modules
+
+=head1 SYNOPSIS
+
+This module includes several types which are not specific to any
+single other module.
+
+=head1 API STATUS
+
+New structures may be added, but existing types are stable.
+
+=head1 dumpfile_t
+
+An in-memory representation of an Amanda header, with keys
+=over
+=item C<type>;
+=item C<datestamp>;
+=item C<dumplevel>;
+=item C<compressed>;
+=item C<encrypted>;
+=item C<comp_suffix>;
+=item C<encrypt_suffix>;
+=item C<name> -- hostname or label;
+=item C<disk>;
+=item C<program>;
+=item C<dumper>;
+=item C<srvcompprog>;
+=item C<clntcompprog>;
+=item C<srv_encrypt>;
+=item C<clnt_encrypt>;
+=item C<recover_cmd>;
+=item C<uncompress_cmd>;
+=item C<encrypt_cmd>;
+=item C<decrypt_cmd>;
+=item C<srv_decrypt_opt>;
+=item C<clnt_decrypt_opt>;
+=item C<cont_filename>;
+=item C<is_partial>;
+=item C<partnum>;
+=item C<totalparts> (-1 == UNKNOWN); and
+=item blocksize.
+=back
+
+where C<type> is one of the following constants, which are availble
+for import in the tag C<:filetype_t>:
+=over
+=item C<F_UNKNOWN>;
+=item C<F_WEIRD>;
+=item C<F_TAPESTART>;
+=item C<F_TAPEEND>;
+=item C<F_DUMPFILE>;
+=item C<F_CONT_DUMPFILE>;
+=item C<F_SPLIT_DUMPFILE>; or
+=item C<F_EMPTY>.
+=back
+
+NOTE: no methods are currently defined on C<dumpfile_t>; interfaces
+can be written as needed.
+
+=cut
+%}
+
+amglue_add_flag_tag_fns(filetype_t);
+amglue_add_constant(F_UNKNOWN, filetype_t);
+amglue_add_constant(F_WEIRD, filetype_t);
+amglue_add_constant(F_TAPESTART, filetype_t);
+amglue_add_constant(F_TAPEEND, filetype_t);
+amglue_add_constant(F_DUMPFILE, filetype_t);
+amglue_add_constant(F_CONT_DUMPFILE, filetype_t);
+amglue_add_constant(F_SPLIT_DUMPFILE, filetype_t);
+amglue_add_constant(F_EMPTY, filetype_t);
+
+typedef char string_t[STRMAX];
+%typemap(memberin) string_t {
+    strncpy($1, $input, STRMAX);
+    if ($1[STRMAX-1] != '\0')
+       SWIG_exception(SWIG_ValueError, "String too large for dumpfile_t");
+}
+
+typedef struct {
+
+    filetype_t type;
+    string_t datestamp;
+    int dumplevel;
+    int compressed;
+    int encrypted;
+    string_t comp_suffix;
+    string_t encrypt_suffix;
+    string_t name;     /* hostname or label */
+    string_t disk;
+    string_t program;
+    string_t dumper;
+    string_t srvcompprog;
+    string_t clntcompprog;
+    string_t srv_encrypt;
+    string_t clnt_encrypt;
+    string_t recover_cmd;
+    string_t uncompress_cmd;
+    string_t encrypt_cmd;
+    string_t decrypt_cmd;
+    string_t srv_decrypt_opt;
+    string_t clnt_decrypt_opt;
+    string_t cont_filename;
+    int is_partial;
+    int partnum;
+    int totalparts; /* -1 == UNKNOWN */
+    size_t blocksize;
+
+    %extend {
+       /* constructor */
+       dumpfile_t(void) {
+           dumpfile_t *df = malloc(sizeof(*df));
+           fh_init(df);
+           return df;
+       }
+
+       /* destructor */
+       ~dumpfile_t(void) {
+           free(self);
+       }
+    }
+} dumpfile_t;
+
+/* TODO: rename to dump_header */
diff --git a/perl/Amanda/Util.c b/perl/Amanda/Util.c
new file mode 100644 (file)
index 0000000..b4cc13e
--- /dev/null
@@ -0,0 +1,2196 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.33
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPERL
+#define SWIG_CASTRANK_MODE
+/* -----------------------------------------------------------------------------
+ *  This section contains generic SWIG labels for method/variable
+ *  declarations/attributes, and other compiler dependent labels.
+ * ----------------------------------------------------------------------------- */
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# elif defined(__HP_aCC)
+/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
+/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
+#  define SWIGTEMPLATEDISAMBIGUATOR template
+# else
+#  define SWIGTEMPLATEDISAMBIGUATOR
+# endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+#   define SWIGINLINE inline
+# else
+#   define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define SWIGUNUSED __attribute__ ((__unused__)) 
+#   else
+#     define SWIGUNUSED
+#   endif
+# elif defined(__ICC)
+#   define SWIGUNUSED __attribute__ ((__unused__)) 
+# else
+#   define SWIGUNUSED 
+# endif
+#endif
+
+#ifndef SWIGUNUSEDPARM
+# ifdef __cplusplus
+#   define SWIGUNUSEDPARM(p)
+# else
+#   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods */
+#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#  ifndef GCC_HASCLASSVISIBILITY
+#    define GCC_HASCLASSVISIBILITY
+#  endif
+#endif
+
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   if defined(STATIC_LINKED)
+#     define SWIGEXPORT
+#   else
+#     define SWIGEXPORT __declspec(dllexport)
+#   endif
+# else
+#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
+#     define SWIGEXPORT __attribute__ ((visibility("default")))
+#   else
+#     define SWIGEXPORT
+#   endif
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   define SWIGSTDCALL __stdcall
+# else
+#   define SWIGSTDCALL
+# endif 
+#endif
+
+/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
+#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
+#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
+# define _SCL_SECURE_NO_DEPRECATE
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+   or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "3"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+  You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+  creating a static or dynamic library from the swig runtime code.
+  In 99.9% of the cases, swig just needs to declare them as 'static'.
+  
+  But only do this if is strictly necessary, ie, if you have problems
+  with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+/*  Generic buffer size */
+#ifndef SWIG_BUFFER_SIZE
+# define SWIG_BUFFER_SIZE 1024
+#endif
+
+/* Flags for pointer conversions */
+#define SWIG_POINTER_DISOWN        0x1
+
+/* Flags for new pointer objects */
+#define SWIG_POINTER_OWN           0x1
+
+
+/* 
+   Flags/methods for returning states.
+   
+   The swig conversion methods, as ConvertPtr, return and integer 
+   that tells if the conversion was successful or not. And if not,
+   an error code can be returned (see swigerrors.swg for the codes).
+   
+   Use the following macros/flags to set or process the returning
+   states.
+   
+   In old swig versions, you usually write code as:
+
+     if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) {
+       // success code
+     } else {
+       //fail code
+     }
+
+   Now you can be more explicit as:
+
+    int res = SWIG_ConvertPtr(obj,vptr,ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+    } else {
+      // fail code
+    }
+
+   that seems to be the same, but now you can also do
+
+    Type *ptr;
+    int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags);
+    if (SWIG_IsOK(res)) {
+      // success code
+      if (SWIG_IsNewObj(res) {
+        ...
+       delete *ptr;
+      } else {
+        ...
+      }
+    } else {
+      // fail code
+    }
+    
+   I.e., now SWIG_ConvertPtr can return new objects and you can
+   identify the case and take care of the deallocation. Of course that
+   requires also to SWIG_ConvertPtr to return new result values, as
+
+      int SWIG_ConvertPtr(obj, ptr,...) {         
+        if (<obj is ok>) {                            
+          if (<need new object>) {                    
+            *ptr = <ptr to new allocated object>; 
+            return SWIG_NEWOBJ;                       
+          } else {                                    
+            *ptr = <ptr to old object>;               
+            return SWIG_OLDOBJ;                       
+          }                                   
+        } else {                                      
+          return SWIG_BADOBJ;                 
+        }                                             
+      }
+
+   Of course, returning the plain '0(success)/-1(fail)' still works, but you can be
+   more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the
+   swig errors code.
+
+   Finally, if the SWIG_CASTRANK_MODE is enabled, the result code
+   allows to return the 'cast rank', for example, if you have this
+
+       int food(double)
+       int fooi(int);
+
+   and you call
+      food(1)   // cast rank '1'  (1 -> 1.0)
+      fooi(1)   // cast rank '0'
+
+   just use the SWIG_AddCast()/SWIG_CheckState()
+
+
+ */
+#define SWIG_OK                    (0) 
+#define SWIG_ERROR                 (-1)
+#define SWIG_IsOK(r)               (r >= 0)
+#define SWIG_ArgError(r)           ((r != SWIG_ERROR) ? r : SWIG_TypeError)  
+
+/* The CastRankLimit says how many bits are used for the cast rank */
+#define SWIG_CASTRANKLIMIT         (1 << 8)
+/* The NewMask denotes the object was created (using new/malloc) */
+#define SWIG_NEWOBJMASK            (SWIG_CASTRANKLIMIT  << 1)
+/* The TmpMask is for in/out typemaps that use temporal objects */
+#define SWIG_TMPOBJMASK            (SWIG_NEWOBJMASK << 1)
+/* Simple returning values */
+#define SWIG_BADOBJ                (SWIG_ERROR)
+#define SWIG_OLDOBJ                (SWIG_OK)
+#define SWIG_NEWOBJ                (SWIG_OK | SWIG_NEWOBJMASK)
+#define SWIG_TMPOBJ                (SWIG_OK | SWIG_TMPOBJMASK)
+/* Check, add and del mask methods */
+#define SWIG_AddNewMask(r)         (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r)
+#define SWIG_DelNewMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r)
+#define SWIG_IsNewObj(r)           (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK))
+#define SWIG_AddTmpMask(r)         (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r)
+#define SWIG_DelTmpMask(r)         (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r)
+#define SWIG_IsTmpObj(r)           (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK))
+
+
+/* Cast-Rank Mode */
+#if defined(SWIG_CASTRANK_MODE)
+#  ifndef SWIG_TypeRank
+#    define SWIG_TypeRank             unsigned long
+#  endif
+#  ifndef SWIG_MAXCASTRANK            /* Default cast allowed */
+#    define SWIG_MAXCASTRANK          (2)
+#  endif
+#  define SWIG_CASTRANKMASK          ((SWIG_CASTRANKLIMIT) -1)
+#  define SWIG_CastRank(r)           (r & SWIG_CASTRANKMASK)
+SWIGINTERNINLINE int SWIG_AddCast(int r) { 
+  return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r;
+}
+SWIGINTERNINLINE int SWIG_CheckState(int r) { 
+  return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; 
+}
+#else /* no cast-rank mode */
+#  define SWIG_AddCast
+#  define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0)
+#endif
+
+
+
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store inforomation on one type */
+typedef struct swig_type_info {
+  const char             *name;                        /* mangled name of this type */
+  const char             *str;                 /* human readable name of this type */
+  swig_dycast_func        dcast;               /* dynamic cast function down a hierarchy */
+  struct swig_cast_info  *cast;                        /* linked list of types that can cast into this type */
+  void                   *clientdata;          /* language specific type data */
+  int                    owndata;              /* flag if the structure owns the clientdata */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+  swig_type_info         *type;                        /* pointer to type that is equivalent to this type */
+  swig_converter_func     converter;           /* function to cast the void pointers */
+  struct swig_cast_info  *next;                        /* pointer to next cast in linked list */
+  struct swig_cast_info  *prev;                        /* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+  swig_type_info         **types;              /* Array of pointers to swig_type_info structures that are in this module */
+  size_t                 size;                 /* Number of types in this module */
+  struct swig_module_info *next;               /* Pointer to next element in circularly linked list */
+  swig_type_info         **type_initial;       /* Array of initially generated type structures */
+  swig_cast_info         **cast_initial;       /* Array of initially generated casting structures */
+  void                    *clientdata;         /* Language specific module data */
+} swig_module_info;
+
+/* 
+  Compare two type names skipping the space characters, therefore
+  "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+  Return 0 when the two name types are equivalent, as in
+  strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+                 const char *f2, const char *l2) {
+  for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+    while ((*f1 == ' ') && (f1 != l1)) ++f1;
+    while ((*f2 == ' ') && (f2 != l2)) ++f2;
+    if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1;
+  }
+  return (int)((l1 - f1) - (l2 - f2));
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty)         \
+  if (ty) {                                             \
+    swig_cast_info *iter = ty->cast;                    \
+    while (iter) {                                      \
+      if (comparison) {                                 \
+        if (iter == ty->cast) return iter;              \
+        /* Move iter to the top of the linked list */   \
+        iter->prev->next = iter->next;                  \
+        if (iter->next)                                 \
+          iter->next->prev = iter->prev;                \
+        iter->next = ty->cast;                          \
+        iter->prev = 0;                                 \
+        if (ty->cast) ty->cast->prev = iter;            \
+        ty->cast = iter;                                \
+        return iter;                                    \
+      }                                                 \
+      iter = iter->next;                                \
+    }                                                   \
+  }                                                     \
+  return 0
+
+/*
+  Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+  SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+  Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr) {
+  return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/* 
+   Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/*
+  Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/*
+  Return the pretty name associated with this type,
+  that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+  /* The "str" field contains the equivalent pretty names of the
+     type, separated by vertical-bar characters.  We choose
+     to print the last name, as it is often (?) the most
+     specific. */
+  if (!type) return NULL;
+  if (type->str != NULL) {
+    const char *last_name = type->str;
+    const char *s;
+    for (s = type->str; *s; s++)
+      if (*s == '|') last_name = s+1;
+    return last_name;
+  }
+  else
+    return type->name;
+}
+
+/* 
+   Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  swig_cast_info *cast = ti->cast;
+  /* if (ti->clientdata == clientdata) return; */
+  ti->clientdata = clientdata;
+  
+  while (cast) {
+    if (!cast->converter) {
+      swig_type_info *tc = cast->type;
+      if (!tc->clientdata) {
+       SWIG_TypeClientData(tc, clientdata);
+      }
+    }    
+    cast = cast->next;
+  }
+}
+SWIGRUNTIME void
+SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) {
+  SWIG_TypeClientData(ti, clientdata);
+  ti->owndata = 1;
+}
+  
+/*
+  Search for a swig_type_info structure only by mangled name
+  Search is a O(log #types)
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start, 
+                            swig_module_info *end, 
+                           const char *name) {
+  swig_module_info *iter = start;
+  do {
+    if (iter->size) {
+      register size_t l = 0;
+      register size_t r = iter->size - 1;
+      do {
+       /* since l+r >= 0, we can (>> 1) instead (/ 2) */
+       register size_t i = (l + r) >> 1; 
+       const char *iname = iter->types[i]->name;
+       if (iname) {
+         register int compare = strcmp(name, iname);
+         if (compare == 0) {       
+           return iter->types[i];
+         } else if (compare < 0) {
+           if (i) {
+             r = i - 1;
+           } else {
+             break;
+           }
+         } else if (compare > 0) {
+           l = i + 1;
+         }
+       } else {
+         break; /* should never happen */
+       }
+      } while (l <= r);
+    }
+    iter = iter->next;
+  } while (iter != end);
+  return 0;
+}
+
+/*
+  Search for a swig_type_info structure for either a mangled name or a human readable name.
+  It first searches the mangled names of the types, which is a O(log #types)
+  If a type is not found it then searches the human readable names, which is O(#types).
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start, 
+                     swig_module_info *end, 
+                    const char *name) {
+  /* STEP 1: Search the name field using binary search */
+  swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+  if (ret) {
+    return ret;
+  } else {
+    /* STEP 2: If the type hasn't been found, do a complete search
+       of the str field (the human readable name) */
+    swig_module_info *iter = start;
+    do {
+      register size_t i = 0;
+      for (; i < iter->size; ++i) {
+       if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+         return iter->types[i];
+      }
+      iter = iter->next;
+    } while (iter != end);
+  }
+  
+  /* neither found a match */
+  return 0;
+}
+
+/* 
+   Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+  static const char hex[17] = "0123456789abcdef";
+  register const unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu =  u + sz;
+  for (; u != eu; ++u) {
+    register unsigned char uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* 
+   Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+  register unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu = u + sz;
+  for (; u != eu; ++u) {
+    register char d = *(c++);
+    register unsigned char uu;
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    else 
+      return (char *) 0;
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    else 
+      return (char *) 0;
+    *u = uu;
+  }
+  return c;
+}
+
+/* 
+   Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+  char *r = buff;
+  if ((2*sizeof(void *) + 2) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,&ptr,sizeof(void *));
+  if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+  strcpy(r,name);
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      *ptr = (void *) 0;
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+  char *r = buff;
+  size_t lname = (name ? strlen(name) : 0);
+  if ((2*sz + 2 + lname) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  if (lname) {
+    strncpy(r,name,lname+1);
+  } else {
+    *r = 0;
+  }
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      memset(ptr,0,sz);
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*  Errors in SWIG */
+#define  SWIG_UnknownError        -1 
+#define  SWIG_IOError             -2 
+#define  SWIG_RuntimeError        -3 
+#define  SWIG_IndexError          -4 
+#define  SWIG_TypeError           -5 
+#define  SWIG_DivisionByZero      -6 
+#define  SWIG_OverflowError       -7 
+#define  SWIG_SyntaxError         -8 
+#define  SWIG_ValueError          -9 
+#define  SWIG_SystemError         -10
+#define  SWIG_AttributeError      -11
+#define  SWIG_MemoryError         -12 
+#define  SWIG_NullReferenceError   -13
+
+
+
+#ifdef __cplusplus
+/* Needed on some windows machines---since MS plays funny games with the header files under C++ */
+#include <math.h>
+#include <stdlib.h>
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* Add in functionality missing in older versions of Perl. Much of this is based on Devel-PPPort on cpan. */
+
+/* Add PERL_REVISION, PERL_VERSION, PERL_SUBVERSION if missing */
+#ifndef PERL_REVISION
+#  if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+#    define PERL_PATCHLEVEL_H_IMPLICIT
+#    include <patchlevel.h>
+#  endif
+#  if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+#    include <could_not_find_Perl_patchlevel.h>
+#  endif
+#  ifndef PERL_REVISION
+#    define PERL_REVISION       (5)
+#    define PERL_VERSION        PATCHLEVEL
+#    define PERL_SUBVERSION     SUBVERSION
+#  endif
+#endif
+
+#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE)
+#define PerlIO_exportFILE(fh,fl) (FILE*)(fh)
+#endif
+
+#ifndef SvIOK_UV
+# define SvIOK_UV(sv)       (SvIOK(sv) && (SvUVX(sv) == SvIVX(sv)))
+#endif
+
+#ifndef SvUOK
+# define SvUOK(sv)           SvIOK_UV(sv)
+#endif
+
+#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5)))
+#  define PL_sv_undef               sv_undef
+#  define PL_na                            na
+#  define PL_errgv                  errgv
+#  define PL_sv_no                  sv_no
+#  define PL_sv_yes                 sv_yes
+#  define PL_markstack_ptr          markstack_ptr
+#endif
+
+#ifndef IVSIZE
+#  ifdef LONGSIZE
+#    define IVSIZE LONGSIZE
+#  else
+#    define IVSIZE 4 /* A bold guess, but the best we can make. */
+#  endif
+#endif
+
+#ifndef INT2PTR
+#  if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#    define PTRV                  UV
+#    define INT2PTR(any,d)        (any)(d)
+#  else
+#    if PTRSIZE == LONGSIZE
+#      define PTRV                unsigned long
+#    else
+#      define PTRV                unsigned
+#    endif
+#    define INT2PTR(any,d)        (any)(PTRV)(d)
+#  endif
+
+#  define NUM2PTR(any,d)  (any)(PTRV)(d)
+#  define PTR2IV(p)       INT2PTR(IV,p)
+#  define PTR2UV(p)       INT2PTR(UV,p)
+#  define PTR2NV(p)       NUM2PTR(NV,p)
+
+#  if PTRSIZE == LONGSIZE
+#    define PTR2ul(p)     (unsigned long)(p)
+#  else
+#    define PTR2ul(p)     INT2PTR(unsigned long,p)
+#  endif
+#endif /* !INT2PTR */
+
+#ifndef SvPV_nolen
+# define SvPV_nolen(x) SvPV(x,PL_na)
+#endif
+
+#ifndef get_sv
+#  define get_sv perl_get_sv
+#endif
+
+#ifndef ERRSV
+#  define ERRSV get_sv("@",FALSE)
+#endif
+
+#ifndef pTHX_
+#define pTHX_
+#endif   
+
+#include <string.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * error manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGINTERN const char*
+SWIG_Perl_ErrorType(int code) {
+  const char* type = 0;
+  switch(code) {
+  case SWIG_MemoryError:
+    type = "MemoryError";
+    break;
+  case SWIG_IOError:
+    type = "IOError";
+    break;
+  case SWIG_RuntimeError:
+    type = "RuntimeError";
+    break;
+  case SWIG_IndexError:
+    type = "IndexError";
+    break;
+  case SWIG_TypeError:
+    type = "TypeError";
+    break;
+  case SWIG_DivisionByZero:
+    type = "ZeroDivisionError";
+    break;
+  case SWIG_OverflowError:
+    type = "OverflowError";
+    break;
+  case SWIG_SyntaxError:
+    type = "SyntaxError";
+    break;
+  case SWIG_ValueError:
+    type = "ValueError";
+    break;
+  case SWIG_SystemError:
+    type = "SystemError";
+    break;
+  case SWIG_AttributeError:
+    type = "AttributeError";
+    break;
+  default:
+    type = "RuntimeError";
+  }
+  return type;
+}
+
+
+
+
+/* -----------------------------------------------------------------------------
+ * perlrun.swg
+ *
+ * This file contains the runtime support for Perl modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef PERL_OBJECT
+#define SWIG_PERL_OBJECT_DECL CPerlObj *SWIGUNUSEDPARM(pPerl),
+#define SWIG_PERL_OBJECT_CALL pPerl,
+#else
+#define SWIG_PERL_OBJECT_DECL
+#define SWIG_PERL_OBJECT_CALL
+#endif
+
+/* Common SWIG API */
+
+/* for raw pointers */
+#define SWIG_ConvertPtr(obj, pp, type, flags)           SWIG_Perl_ConvertPtr(SWIG_PERL_OBJECT_CALL obj, pp, type, flags)
+#define SWIG_NewPointerObj(p, type, flags)              SWIG_Perl_NewPointerObj(SWIG_PERL_OBJECT_CALL p, type, flags)
+
+/* for raw packed data */
+#define SWIG_ConvertPacked(obj, p, s, type)             SWIG_Perl_ConvertPacked(SWIG_PERL_OBJECT_CALL obj, p, s, type)
+#define SWIG_NewPackedObj(p, s, type)                  SWIG_Perl_NewPackedObj(SWIG_PERL_OBJECT_CALL p, s, type)
+
+/* for class or struct pointers */
+#define SWIG_ConvertInstance(obj, pptr, type, flags)    SWIG_ConvertPtr(obj, pptr, type, flags)
+#define SWIG_NewInstanceObj(ptr, type, flags)           SWIG_NewPointerObj(ptr, type, flags)
+
+/* for C or C++ function pointers */
+#define SWIG_ConvertFunctionPtr(obj, pptr, type)        SWIG_ConvertPtr(obj, pptr, type, 0)
+#define SWIG_NewFunctionPtrObj(ptr, type)               SWIG_NewPointerObj(ptr, type, 0)
+
+/* for C++ member pointers, ie, member methods */
+#define SWIG_ConvertMember(obj, ptr, sz, ty)            SWIG_ConvertPacked(obj, ptr, sz, ty)
+#define SWIG_NewMemberObj(ptr, sz, type)                SWIG_NewPackedObj(ptr, sz, type)
+
+
+/* Runtime API */
+
+#define SWIG_GetModule(clientdata)                      SWIG_Perl_GetModule()
+#define SWIG_SetModule(clientdata, pointer)             SWIG_Perl_SetModule(pointer)
+
+
+/* Error manipulation */
+
+#define SWIG_ErrorType(code)                            SWIG_Perl_ErrorType(code)               
+#define SWIG_Error(code, msg)                          sv_setpvf(GvSV(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg)
+#define SWIG_fail                                      goto fail                                                   
+
+/* Perl-specific SWIG API */
+
+#define SWIG_MakePtr(sv, ptr, type, flags)              SWIG_Perl_MakePtr(SWIG_PERL_OBJECT_CALL sv, ptr, type, flags)
+#define SWIG_MakePackedObj(sv, p, s, type)             SWIG_Perl_MakePackedObj(SWIG_PERL_OBJECT_CALL sv, p, s, type)
+#define SWIG_SetError(str)                              SWIG_Error(SWIG_RuntimeError, str)
+
+
+#define SWIG_PERL_DECL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_DECL arg1)
+#define SWIG_PERL_CALL_ARGS_1(arg1)                     (SWIG_PERL_OBJECT_CALL arg1)
+#define SWIG_PERL_DECL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_DECL arg1, arg2)
+#define SWIG_PERL_CALL_ARGS_2(arg1, arg2)               (SWIG_PERL_OBJECT_CALL arg1, arg2)
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+/* For backward compatibility only */
+#define SWIG_POINTER_EXCEPTION  0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_OWNER   SWIG_POINTER_OWN
+#define SWIG_SHADOW  SWIG_OWNER << 1
+
+#define SWIG_MAYBE_PERL_OBJECT SWIG_PERL_OBJECT_DECL
+
+/* SWIG Perl macros */
+
+/* Macro to declare an XS function */
+#ifndef XSPROTO
+#   define XSPROTO(name) void name(pTHX_ CV* cv)
+#endif
+
+/* Macro to call an XS function */
+#ifdef PERL_OBJECT 
+#  define SWIG_CALLXS(_name) _name(cv,pPerl) 
+#else 
+#  ifndef MULTIPLICITY 
+#    define SWIG_CALLXS(_name) _name(cv) 
+#  else 
+#    define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) 
+#  endif 
+#endif 
+
+#ifdef PERL_OBJECT
+#define MAGIC_PPERL  CPerlObj *pPerl = (CPerlObj *) this;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+#define SWIGCLASS_STATIC
+
+#else /* PERL_OBJECT */
+
+#define MAGIC_PPERL
+#define SWIGCLASS_STATIC static SWIGUNUSED
+
+#ifndef MULTIPLICITY
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MULTIPLICITY */
+
+#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MULTIPLICITY */
+#endif /* PERL_OBJECT */
+
+/* Workaround for bug in perl 5.6.x croak and earlier */
+#if (PERL_VERSION < 8)
+#  ifdef PERL_OBJECT
+#    define SWIG_croak_null() SWIG_Perl_croak_null(pPerl)
+static void SWIG_Perl_croak_null(CPerlObj *pPerl)
+#  else
+static void SWIG_croak_null()
+#  endif
+{
+  SV *err=ERRSV;
+#  if (PERL_VERSION < 6)
+  croak("%_", err);
+#  else
+  if (SvOK(err) && !SvROK(err)) croak("%_", err);
+  croak(Nullch);
+#  endif
+}
+#else
+#  define SWIG_croak_null() croak(Nullch)
+#endif
+
+
+/* 
+   Define how strict is the cast between strings and integers/doubles
+   when overloading between these types occurs.
+   
+   The default is making it as strict as possible by using SWIG_AddCast
+   when needed.
+   
+   You can use -DSWIG_PERL_NO_STRICT_STR2NUM at compilation time to
+   disable the SWIG_AddCast, making the casting between string and
+   numbers less strict.
+
+   In the end, we try to solve the overloading between strings and
+   numerical types in the more natural way, but if you can avoid it,
+   well, avoid it using %rename, for example.
+*/
+#ifndef SWIG_PERL_NO_STRICT_STR2NUM
+# ifndef SWIG_PERL_STRICT_STR2NUM
+#  define SWIG_PERL_STRICT_STR2NUM
+# endif
+#endif
+#ifdef SWIG_PERL_STRICT_STR2NUM
+/* string takes precedence */
+#define SWIG_Str2NumCast(x) SWIG_AddCast(x)  
+#else
+/* number takes precedence */
+#define SWIG_Str2NumCast(x) x
+#endif
+
+
+
+#include <stdlib.h>
+
+SWIGRUNTIME const char *
+SWIG_Perl_TypeProxyName(const swig_type_info *type) {
+  if (!type) return NULL;
+  if (type->clientdata != NULL) {
+    return (const char*) type->clientdata;
+  } 
+  else {
+    return type->name;
+  }
+}
+
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeProxyCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(( (!iter->type->clientdata && (strcmp((char*)iter->type->name, c) == 0)) 
+                           || (iter->type->clientdata && (strcmp((char*)iter->type->clientdata, c) == 0))), ty);
+}
+
+
+/* Function for getting a pointer value */
+
+SWIGRUNTIME int
+SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) {
+  swig_cast_info *tc;
+  void *voidptr = (void *)0;
+  SV *tsv = 0;
+  /* If magical, apply more magic */
+  if (SvGMAGICAL(sv))
+    mg_get(sv);
+
+  /* Check to see if this is an object */
+  if (sv_isobject(sv)) {
+    IV tmp = 0;
+    tsv = (SV*) SvRV(sv);
+    if ((SvTYPE(tsv) == SVt_PVHV)) {
+      MAGIC *mg;
+      if (SvMAGICAL(tsv)) {
+        mg = mg_find(tsv,'P');
+        if (mg) {
+          sv = mg->mg_obj;
+          if (sv_isobject(sv)) {
+           tsv = (SV*)SvRV(sv);
+            tmp = SvIV(tsv);
+          }
+        }
+      } else {
+        return SWIG_ERROR;
+      }
+    } else {
+      tmp = SvIV(tsv);
+    }
+    voidptr = INT2PTR(void *,tmp);
+  } else if (! SvOK(sv)) {            /* Check for undef */
+    *(ptr) = (void *) 0;
+    return SWIG_OK;
+  } else if (SvTYPE(sv) == SVt_RV) {  /* Check for NULL pointer */
+    if (!SvROK(sv)) {
+      *(ptr) = (void *) 0;
+      return SWIG_OK;
+    } else {
+      return SWIG_ERROR;
+    }
+  } else {                            /* Don't know what it is */
+    return SWIG_ERROR;
+  }
+  if (_t) {
+    /* Now see if the types match */
+    char *_c = HvNAME(SvSTASH(SvRV(sv)));
+    tc = SWIG_TypeProxyCheck(_c,_t);
+    if (!tc) {
+      return SWIG_ERROR;
+    }
+    *ptr = SWIG_TypeCast(tc,voidptr);
+  } else {
+    *ptr = voidptr;
+  }
+
+  /* 
+   *  DISOWN implementation: we need a perl guru to check this one.
+   */
+  if (tsv && (flags & SWIG_POINTER_DISOWN)) {
+    /* 
+     *  almost copy paste code from below SWIG_POINTER_OWN setting
+     */
+    SV *obj = sv;
+    HV *stash = SvSTASH(SvRV(obj));
+    GV *gv = *(GV**) hv_fetch(stash, "OWNER", 5, TRUE);
+    if (isGV(gv)) {
+      HV *hv = GvHVn(gv);
+      /*
+       * To set ownership (see below), a newSViv(1) entry is added. 
+       * Hence, to remove ownership, we delete the entry.
+       */
+      if (hv_exists_ent(hv, obj, 0)) {
+       hv_delete_ent(hv, obj, 0, 0);
+      }
+    }
+  }
+  return SWIG_OK;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) {
+  if (ptr && (flags & SWIG_SHADOW)) {
+    SV *self;
+    SV *obj=newSV(0);
+    HV *hash=newHV();
+    HV *stash;
+    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+    stash=SvSTASH(SvRV(obj));
+    if (flags & SWIG_POINTER_OWN) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+      if (!isGV(gv))
+        gv_init(gv, stash, "OWNER", 5, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newSViv(1), 0);
+    }
+    sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0);
+    SvREFCNT_dec(obj);
+    self=newRV_noinc((SV *)hash);
+    sv_setsv(sv, self);
+    SvREFCNT_dec((SV *)self);
+    sv_bless(sv, stash);
+  }
+  else {
+    sv_setref_pv(sv, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+  }
+}
+
+SWIGRUNTIMEINLINE SV *
+SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+  SV *result = sv_newmortal();
+  SWIG_MakePtr(result, ptr, t, flags);
+  return result;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) {
+  char result[1024];
+  char *r = result;
+  if ((2*sz + 1 + strlen(SWIG_Perl_TypeProxyName(type))) > 1000) return;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  strcpy(r,SWIG_Perl_TypeProxyName(type));
+  sv_setpv(sv, result);
+}
+
+SWIGRUNTIME SV *
+SWIG_Perl_NewPackedObj(SWIG_MAYBE_PERL_OBJECT void *ptr, int sz, swig_type_info *type) {
+  SV *result = sv_newmortal();
+  SWIG_Perl_MakePackedObj(result, ptr, sz, type);
+  return result;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME int
+SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty) {
+  swig_cast_info *tc;
+  const char  *c = 0;
+
+  if ((!obj) || (!SvOK(obj))) return SWIG_ERROR;
+  c = SvPV_nolen(obj);
+  /* Pointer values must start with leading underscore */
+  if (*c != '_') return SWIG_ERROR;
+  c++;
+  c = SWIG_UnpackData(c,ptr,sz);
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) return SWIG_ERROR;
+  }
+  return SWIG_OK;
+}
+
+
+/* Macros for low-level exception handling */
+#define SWIG_croak(x)    { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail; }
+
+
+typedef XSPROTO(SwigPerlWrapper);
+typedef SwigPerlWrapper *SwigPerlWrapperPtr;
+
+/* Structure for command table */
+typedef struct {
+  const char         *name;
+  SwigPerlWrapperPtr  wrapper;
+} swig_command_info;
+
+/* Information for constant table */
+
+#define SWIG_INT     1
+#define SWIG_FLOAT   2
+#define SWIG_STRING  3
+#define SWIG_POINTER 4
+#define SWIG_BINARY  5
+
+/* Constant information structure */
+typedef struct swig_constant_info {
+    int              type;
+    const char      *name;
+    long             lvalue;
+    double           dvalue;
+    void            *pvalue;
+    swig_type_info **ptype;
+} swig_constant_info;
+
+
+/* Structure for variable table */
+typedef struct {
+  const char   *name;
+  SwigMagicFunc   set;
+  SwigMagicFunc   get;
+  swig_type_info  **type;
+} swig_variable_info;
+
+/* Magic variable code */
+#ifndef PERL_OBJECT
+#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c)
+  #ifndef MULTIPLICITY
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) 
+  #else
+     SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) 
+  #endif
+#else
+#  define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c)
+SWIGRUNTIME void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) 
+#endif
+{
+  MAGIC *mg;
+  sv_magic(sv,sv,'U',(char *) name,strlen(name));
+  mg = mg_find(sv,'U');
+  mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
+  mg->mg_virtual->svt_get = (SwigMagicFunc) get;
+  mg->mg_virtual->svt_set = (SwigMagicFunc) set;
+  mg->mg_virtual->svt_len = 0;
+  mg->mg_virtual->svt_clear = 0;
+  mg->mg_virtual->svt_free = 0;
+}
+
+
+SWIGRUNTIME swig_module_info *
+SWIG_Perl_GetModule(void) {
+  static void *type_pointer = (void *)0;
+  SV *pointer;
+
+  /* first check if pointer already created */
+  if (!type_pointer) {
+    pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE);
+    if (pointer && SvOK(pointer)) {
+      type_pointer = INT2PTR(swig_type_info **, SvIV(pointer));
+    }
+  }
+
+  return (swig_module_info *) type_pointer;
+}
+
+SWIGRUNTIME void
+SWIG_Perl_SetModule(swig_module_info *module) {
+  SV *pointer;
+
+  /* create a new pointer */
+  pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE);
+  sv_setiv(pointer, PTR2IV(module));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Workaround perl5 global namespace pollution. Note that undefining library
+ * functions like fopen will not solve the problem on all platforms as fopen
+ * might be a macro on Windows but not necessarily on other operating systems. */
+#ifdef do_open
+  #undef do_open
+#endif
+#ifdef do_close
+  #undef do_close
+#endif
+#ifdef scalar
+  #undef scalar
+#endif
+#ifdef list
+  #undef list
+#endif
+#ifdef apply
+  #undef apply
+#endif
+#ifdef convert
+  #undef convert
+#endif
+#ifdef Error
+  #undef Error
+#endif
+#ifdef form
+  #undef form
+#endif
+#ifdef vform
+  #undef vform
+#endif
+#ifdef LABEL
+  #undef LABEL
+#endif
+#ifdef METHOD
+  #undef METHOD
+#endif
+#ifdef Move
+  #undef Move
+#endif
+#ifdef yylex
+  #undef yylex
+#endif
+#ifdef yyparse
+  #undef yyparse
+#endif
+#ifdef yyerror
+  #undef yyerror
+#endif
+#ifdef invert
+  #undef invert
+#endif
+#ifdef ref
+  #undef ref
+#endif
+#ifdef read
+  #undef read
+#endif
+#ifdef write
+  #undef write
+#endif
+#ifdef eof
+  #undef eof
+#endif
+#ifdef bool
+  #undef bool
+#endif
+#ifdef close
+  #undef close
+#endif
+#ifdef rewind
+  #undef rewind
+#endif
+#ifdef free
+  #undef free
+#endif
+#ifdef malloc
+  #undef malloc
+#endif
+#ifdef calloc
+  #undef calloc
+#endif
+#ifdef Stat
+  #undef Stat
+#endif
+#ifdef check
+  #undef check
+#endif
+#ifdef seekdir
+  #undef seekdir
+#endif
+#ifdef open
+  #undef open
+#endif
+
+
+
+#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) 
+
+#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else 
+
+
+
+  #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) 
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_char swig_types[0]
+#define SWIGTYPE_p_double swig_types[1]
+#define SWIGTYPE_p_float swig_types[2]
+#define SWIGTYPE_p_int swig_types[3]
+#define SWIGTYPE_p_unsigned_char swig_types[4]
+static swig_type_info *swig_types[6];
+static swig_module_info swig_module = {swig_types, 5, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init    boot_Amanda__Util
+
+#define SWIG_name   "Amanda::Utilc::boot_Amanda__Util"
+#define SWIG_prefix "Amanda::Utilc::"
+
+#define SWIGVERSION 0x010333 
+#define SWIG_VERSION SWIGVERSION
+
+
+#define SWIG_as_voidptr(a) (void *)((const void *)(a)) 
+#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) 
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifndef PERL_OBJECT
+#ifndef MULTIPLICITY
+SWIGEXPORT void SWIG_init (CV* cv);
+#else
+SWIGEXPORT void SWIG_init (pTHXo_ CV* cv);
+#endif
+#else
+SWIGEXPORT void SWIG_init (CV *cv, CPerlObj *);
+#endif
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "amglue.h"
+
+
+#include "debug.h"
+/* use a relative path here to avoid conflicting with Perl's util.h. */
+#include "../common-src/util.h"
+#include "file.h"
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_long  SWIG_PERL_DECL_ARGS_1(long value)
+{    
+  SV *obj = sv_newmortal();
+  sv_setiv(obj, (IV) value);
+  return obj;
+}
+
+
+SWIGINTERNINLINE SV *
+SWIG_From_int  SWIG_PERL_DECL_ARGS_1(int value)
+{    
+  return SWIG_From_long  SWIG_PERL_CALL_ARGS_1(value);
+}
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+  static int init = 0;
+  static swig_type_info* info = 0;
+  if (!init) {
+    info = SWIG_TypeQuery("_p_char");
+    init = 1;
+  }
+  return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(SV *obj, char** cptr, size_t* psize, int *alloc)
+{
+  if (SvPOK(obj)) {
+    STRLEN len = 0;
+    char *cstr = SvPV(obj, len); 
+    size_t size = len + 1;
+    if (cptr)  {
+      if (alloc) {
+       if (*alloc == SWIG_NEWOBJ) {
+         *cptr = (char *)memcpy((char *)malloc((size)*sizeof(char)), cstr, sizeof(char)*(size));
+       } else {
+         *cptr = cstr;
+         *alloc = SWIG_OLDOBJ;
+       }
+      }
+    }
+    if (psize) *psize = size;
+    return SWIG_OK;
+  } else {
+    swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+    if (pchar_descriptor) {
+      char* vptr = 0; 
+      if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_descriptor, 0) == SWIG_OK) {
+       if (cptr) *cptr = vptr;
+       if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0;
+       if (alloc) *alloc = SWIG_OLDOBJ;
+       return SWIG_OK;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+
+
+
+#include <limits.h>
+#if !defined(SWIG_NO_LLONG_MAX)
+# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__)
+#   define LLONG_MAX __LONG_LONG_MAX__
+#   define LLONG_MIN (-LLONG_MAX - 1LL)
+#   define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+# endif
+#endif
+
+
+SWIGINTERN int
+SWIG_AsVal_double SWIG_PERL_DECL_ARGS_2(SV *obj, double *val)
+{
+  if (SvNIOK(obj)) {
+    if (val) *val = SvNV(obj);
+    return SWIG_OK;
+  } else if (SvIOK(obj)) {
+    if (val) *val = (double) SvIV(obj);
+    return SWIG_AddCast(SWIG_OK);
+  } else {
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      double v = strtod(nptr, &endptr);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+#include <float.h>
+
+
+#include <math.h>
+
+
+SWIGINTERNINLINE int
+SWIG_CanCastAsInteger(double *d, double min, double max) {
+  double x = *d;
+  if ((min <= x && x <= max)) {
+   double fx = floor(x);
+   double cx = ceil(x);
+   double rd =  ((x - fx) < 0.5) ? fx : cx; /* simple rint */
+   if ((errno == EDOM) || (errno == ERANGE)) {
+     errno = 0;
+   } else {
+     double summ, reps, diff;
+     if (rd < x) {
+       diff = x - rd;
+     } else if (rd > x) {
+       diff = rd - x;
+     } else {
+       return 1;
+     }
+     summ = rd + x;
+     reps = diff/summ;
+     if (reps < 8*DBL_EPSILON) {
+       *d = rd;
+       return 1;
+     }
+   }
+  }
+  return 0;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_long SWIG_PERL_DECL_ARGS_2(SV *obj, long* val)
+{
+  if (SvIOK(obj)) {
+    if (val) *val = SvIV(obj);
+    return SWIG_OK;
+  } else {
+    int dispatch = 0;
+    const char *nptr = SvPV_nolen(obj);
+    if (nptr) {
+      char *endptr;
+      long v;
+      errno = 0;
+      v = strtol(nptr, &endptr,0);
+      if (errno == ERANGE) {
+       errno = 0;
+       return SWIG_OverflowError;
+      } else {
+       if (*endptr == '\0') {
+         if (val) *val = v;
+         return SWIG_Str2NumCast(SWIG_OK);
+       }
+      }
+    }
+    if (!dispatch) {
+      double d;
+      int res = SWIG_AddCast(SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj,&d));
+      if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) {
+       if (val) *val = (long)(d);
+       return res;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_int SWIG_PERL_DECL_ARGS_2(SV * obj, int *val)
+{
+  long v;
+  int res = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v < INT_MIN || v > INT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = (int)(v);
+    }
+  }  
+  return res;
+}
+
+
+void
+set_erroutput_type(char *type, char *context)
+{
+    if (strcmp(context, "cmdline") == 0) {
+       erroutput_type = ERR_INTERACTIVE;
+    } else if (strcmp(context, "daemon") == 0) {
+       if (strcmp(type, "server") == 0) {
+           erroutput_type = ERR_INTERACTIVE|ERR_AMANDALOG;
+       } else if (strcmp(type, "client") == 0) {
+           erroutput_type = ERR_INTERACTIVE|ERR_SYSLOG;
+       }
+    }
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef PERL_OBJECT
+#define MAGIC_CLASS _wrap_Amanda::Util_var::
+class _wrap_Amanda::Util_var : public CPerlObj {
+public:
+#else
+#define MAGIC_CLASS
+#endif
+SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {
+    MAGIC_PPERL
+    croak("Value is read-only.");
+    return 0;
+}
+
+
+#ifdef PERL_OBJECT
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+XS(_wrap_set_pname) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: set_pname(name);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "set_pname" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    set_pname(arg1);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_safe_cd) {
+  {
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: safe_cd();");
+    }
+    safe_cd();
+    
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_check_running_as) {
+  {
+    running_as_flags arg1 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: check_running_as(who);");
+    }
+    {
+      if (sizeof(signed int) == 1) {
+        arg1 = amglue_SvI8(ST(0));
+      } else if (sizeof(signed int) == 2) {
+        arg1 = amglue_SvI16(ST(0));
+      } else if (sizeof(signed int) == 4) {
+        arg1 = amglue_SvI32(ST(0));
+      } else if (sizeof(signed int) == 8) {
+        arg1 = amglue_SvI64(ST(0));
+      } else {
+        g_critical("Unexpected signed int >64 bits?"); /* should be optimized out unless sizeof(signed int) > 8 */
+      }
+    }
+    check_running_as(arg1);
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_set_erroutput_type) {
+  {
+    char *arg1 = (char *) 0 ;
+    char *arg2 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: set_erroutput_type(type,context);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "set_erroutput_type" "', argument " "1"" of type '" "char *""'");
+    }
+    arg1 = (char *)(buf1);
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "set_erroutput_type" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = (char *)(buf2);
+    set_erroutput_type(arg1,arg2);
+    
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
+    if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
+    SWIG_croak_null();
+  }
+}
+
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_char = {"_p_char", "gchar *|char *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_double = {"_p_double", "double *|gdouble *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *|gfloat *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "int *|gboolean *|running_as_flags *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "guchar *|unsigned char *", 0, 0, (void*)0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_char,
+  &_swigt__p_double,
+  &_swigt__p_float,
+  &_swigt__p_int,
+  &_swigt__p_unsigned_char,
+};
+
+static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_char[] = {  {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_char,
+  _swigc__p_double,
+  _swigc__p_float,
+  _swigc__p_int,
+  _swigc__p_unsigned_char,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_constant_info swig_constants[] = {
+{0,0,0,0,0,0}
+};
+#ifdef __cplusplus
+}
+#endif
+static swig_variable_info swig_variables[] = {
+{0,0,0,0}
+};
+static swig_command_info swig_commands[] = {
+{"Amanda::Utilc::set_pname", _wrap_set_pname},
+{"Amanda::Utilc::safe_cd", _wrap_safe_cd},
+{"Amanda::Utilc::check_running_as", _wrap_check_running_as},
+{"Amanda::Utilc::set_erroutput_type", _wrap_set_erroutput_type},
+{0,0}
+};
+/* -----------------------------------------------------------------------------
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic 
+ * memory is used. Also, since swig_type_info structures store pointers to 
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization. 
+ * The idea is that swig generates all the structures that are needed. 
+ * The runtime then collects these partially filled structures. 
+ * The SWIG_InitializeModule function takes these initial arrays out of 
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+ *
+ * The generated swig_type_info structures are assigned staticly to an initial 
+ * array. We just loop through that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it 
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+ *
+ * First off, we lookup the cast->type name to see if it is already loaded. 
+ * There are three cases to handle:
+ *  1) If the cast->type has already been loaded AND the type we are adding
+ *     casting info to has not been loaded (it is in this module), THEN we
+ *     replace the cast->type pointer with the type pointer that has already
+ *     been loaded.
+ *  2) If BOTH types (the one we are adding casting info to, and the 
+ *     cast->type) are loaded, THEN the cast info has already been loaded by
+ *     the previous module so we just ignore it.
+ *  3) Finally, if cast->type has not already been loaded, then we add that
+ *     swig_cast_info to the linked list (because the cast->type) pointer will
+ *     be correct.
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* c-mode */
+#endif
+#endif
+
+#if 0
+#define SWIGRUNTIME_DEBUG
+#endif
+
+
+SWIGRUNTIME void
+SWIG_InitializeModule(void *clientdata) {
+  size_t i;
+  swig_module_info *module_head, *iter;
+  int found;
+  
+  clientdata = clientdata;
+  
+  /* check to see if the circular list has been setup, if not, set it up */
+  if (swig_module.next==0) {
+    /* Initialize the swig_module */
+    swig_module.type_initial = swig_type_initial;
+    swig_module.cast_initial = swig_cast_initial;
+    swig_module.next = &swig_module;
+  }
+  
+  /* Try and load any already created modules */
+  module_head = SWIG_GetModule(clientdata);
+  if (!module_head) {
+    /* This is the first module loaded for this interpreter */
+    /* so set the swig module into the interpreter */
+    SWIG_SetModule(clientdata, &swig_module);
+    module_head = &swig_module;
+  } else {
+    /* the interpreter has loaded a SWIG module, but has it loaded this one? */
+    found=0;
+    iter=module_head;
+    do {
+      if (iter==&swig_module) {
+        found=1;
+        break;
+      }
+      iter=iter->next;
+    } while (iter!= module_head);
+    
+    /* if the is found in the list, then all is done and we may leave */
+    if (found) return;
+    /* otherwise we must add out module into the list */
+    swig_module.next = module_head->next;
+    module_head->next = &swig_module;
+  }
+  
+  /* Now work on filling in swig_module.types */
+#ifdef SWIGRUNTIME_DEBUG
+  printf("SWIG_InitializeModule: size %d\n", swig_module.size);
+#endif
+  for (i = 0; i < swig_module.size; ++i) {
+    swig_type_info *type = 0;
+    swig_type_info *ret;
+    swig_cast_info *cast;
+    
+#ifdef SWIGRUNTIME_DEBUG
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+#endif
+    
+    /* if there is another module already loaded */
+    if (swig_module.next != &swig_module) {
+      type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+    }
+    if (type) {
+      /* Overwrite clientdata field */
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: found type %s\n", type->name);
+#endif
+      if (swig_module.type_initial[i]->clientdata) {
+        type->clientdata = swig_module.type_initial[i]->clientdata;
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name);
+#endif
+      }
+    } else {
+      type = swig_module.type_initial[i];
+    }
+    
+    /* Insert casting types */
+    cast = swig_module.cast_initial[i];
+    while (cast->type) {
+      /* Don't need to add information already in the list */
+      ret = 0;
+#ifdef SWIGRUNTIME_DEBUG
+      printf("SWIG_InitializeModule: look cast %s\n", cast->type->name);
+#endif
+      if (swig_module.next != &swig_module) {
+        ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+#ifdef SWIGRUNTIME_DEBUG
+        if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name);
+#endif
+      }
+      if (ret) {
+        if (type == swig_module.type_initial[i]) {
+#ifdef SWIGRUNTIME_DEBUG
+          printf("SWIG_InitializeModule: skip old type %s\n", ret->name);
+#endif
+          cast->type = ret;
+          ret = 0;
+        } else {
+          /* Check for casting already in the list */
+          swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type);
+#ifdef SWIGRUNTIME_DEBUG
+          if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name);
+#endif
+          if (!ocast) ret = 0;
+        }
+      }
+      
+      if (!ret) {
+#ifdef SWIGRUNTIME_DEBUG
+        printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name);
+#endif
+        if (type->cast) {
+          type->cast->prev = cast;
+          cast->next = type->cast;
+        }
+        type->cast = cast;
+      }
+      cast++;
+    }
+    /* Set entry in modules->types array equal to the type */
+    swig_module.types[i] = type;
+  }
+  swig_module.types[i] = 0;
+  
+#ifdef SWIGRUNTIME_DEBUG
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+  for (i = 0; i < swig_module.size; ++i) {
+    int j = 0;
+    swig_cast_info *cast = swig_module.cast_initial[i];
+    printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name);
+    while (cast->type) {
+      printf("SWIG_InitializeModule: cast type %s\n", cast->type->name);
+      cast++;
+      ++j;
+    }
+    printf("---- Total casts: %d\n",j);
+  }
+  printf("**** SWIG_InitializeModule: Cast List ******\n");
+#endif
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types.  It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientData(void) {
+  size_t i;
+  swig_cast_info *equiv;
+  static int init_run = 0;
+  
+  if (init_run) return;
+  init_run = 1;
+  
+  for (i = 0; i < swig_module.size; i++) {
+    if (swig_module.types[i]->clientdata) {
+      equiv = swig_module.types[i]->cast;
+      while (equiv) {
+        if (!equiv->converter) {
+          if (equiv->type && !equiv->type->clientdata)
+          SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+        }
+        equiv = equiv->next;
+      }
+    }
+  }
+}
+
+#ifdef __cplusplus
+#if 0
+{
+  /* c-mode */
+#endif
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(SWIG_init) {
+  dXSARGS;
+  int i;
+  
+  SWIG_InitializeModule(0);
+  
+  /* Install commands */
+  for (i = 0; swig_commands[i].name; i++) {
+    newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__);
+  }
+  
+  /* Install variables */
+  for (i = 0; swig_variables[i].name; i++) {
+    SV *sv;
+    sv = get_sv((char*) swig_variables[i].name, TRUE | 0x2);
+    if (swig_variables[i].type) {
+      SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0);
+    } else {
+      sv_setiv(sv,(IV) 0);
+    }
+    swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); 
+  }
+  
+  /* Install constant */
+  for (i = 0; swig_constants[i].type; i++) {
+    SV *sv;
+    sv = get_sv((char*)swig_constants[i].name, TRUE | 0x2);
+    switch(swig_constants[i].type) {
+    case SWIG_INT:
+      sv_setiv(sv, (IV) swig_constants[i].lvalue);
+      break;
+    case SWIG_FLOAT:
+      sv_setnv(sv, (double) swig_constants[i].dvalue);
+      break;
+    case SWIG_STRING:
+      sv_setpv(sv, (char *) swig_constants[i].pvalue);
+      break;
+    case SWIG_POINTER:
+      SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
+      break;
+    case SWIG_BINARY:
+      SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
+      break;
+    default:
+      break;
+    }
+    SvREADONLY_on(sv);
+  }
+  
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "RUNNING_AS_ROOT", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(RUNNING_AS_ROOT)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "RUNNING_AS_DUMPUSER", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(RUNNING_AS_DUMPUSER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "RUNNING_AS_DUMPUSER_PREFERRED", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(RUNNING_AS_DUMPUSER_PREFERRED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "RUNNING_AS_CLIENT_LOGIN", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(RUNNING_AS_CLIENT_LOGIN)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig/1.3.33/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "RUNNING_AS_UID_ONLY", TRUE | 0x2);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(RUNNING_AS_UID_ONLY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  ST(0) = &PL_sv_yes;
+  XSRETURN(1);
+}
+
diff --git a/perl/Amanda/Util.pm b/perl/Amanda/Util.pm
new file mode 100644 (file)
index 0000000..a40c05b
--- /dev/null
@@ -0,0 +1,289 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 1.3.33
+#
+# Don't modify this file, modify the SWIG interface instead.
+
+package Amanda::Util;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+package Amanda::Utilc;
+bootstrap Amanda::Util;
+package Amanda::Util;
+@EXPORT = qw( );
+
+# ---------- BASE METHODS -------------
+
+package Amanda::Util;
+
+sub TIEHASH {
+    my ($classname,$obj) = @_;
+    return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+    my ($self,$field) = @_;
+    my $member_func = "swig_${field}_get";
+    $self->$member_func();
+}
+
+sub STORE {
+    my ($self,$field,$newval) = @_;
+    my $member_func = "swig_${field}_set";
+    $self->$member_func($newval);
+}
+
+sub this {
+    my $ptr = shift;
+    return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package Amanda::Util;
+
+*set_pname = *Amanda::Utilc::set_pname;
+*safe_cd = *Amanda::Utilc::safe_cd;
+*check_running_as = *Amanda::Utilc::check_running_as;
+*set_erroutput_type = *Amanda::Utilc::set_erroutput_type;
+
+# ------- VARIABLE STUBS --------
+
+package Amanda::Util;
+
+*RUNNING_AS_ROOT = *Amanda::Utilc::RUNNING_AS_ROOT;
+*RUNNING_AS_DUMPUSER = *Amanda::Utilc::RUNNING_AS_DUMPUSER;
+*RUNNING_AS_DUMPUSER_PREFERRED = *Amanda::Utilc::RUNNING_AS_DUMPUSER_PREFERRED;
+*RUNNING_AS_CLIENT_LOGIN = *Amanda::Utilc::RUNNING_AS_CLIENT_LOGIN;
+*RUNNING_AS_UID_ONLY = *Amanda::Utilc::RUNNING_AS_UID_ONLY;
+
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+
+use Amanda::Debug qw(:init);
+use Carp;
+use POSIX qw(:fcntl_h);
+
+=head1 NAME
+
+Amanda::Util - Runtime support for Amanda applications
+
+=head1 Application Initialization
+
+Application initialization generally looks like this:
+
+  use Amanda::Config qw( :init );
+  use Amanda::Util qw( :check_running_as_flags );
+  use Amanda::Debug;
+
+  Amanda::Util::setup_application("myapp", "server", "cmdline");
+  # .. command-line processing ..
+  Amanda::Config::config_init(...);
+  Amanda::Util::finish_setup($RUNNING_AS_DUMPUSER);
+
+=over
+
+=item C<setup_application($name, $type, $context)>
+
+Set up the operating environment for an application, without requiring any
+configuration.
+
+C<$name> is the name of the application, used in log messages, etc.  C<$type>
+is usualy one of "server" or "client".  It specifies the subdirectory in which
+debug logfiles will be created.  C<$context> indicates the usual manner in
+which this application is invoked; one of C<"cmdline"> for a user-invoked
+command-line utility (e.g., C<amadmin>) which should send human-readable error
+messages to stderr; C<"daemon"> for a program started by C<amandad>, e.g.,
+C<sendbackup>; or C<"scriptutil"> for a small program used from shell scripts,
+e.g., C<amgetconf>
+
+Based on C<$type> and C<$context>, this function does the following:
+
+=over
+
+=item *
+
+sets up debug logging;
+
+=item *
+
+configures internationalization
+
+=item *
+
+sets the umask;
+
+=item *
+
+sets the current working directory to the debug or temporary directory;
+
+=item *
+
+closes any unnecessary file descriptors as a security meaasure;
+
+=item *
+
+ignores C<SIGPIPE>; and
+
+=item *
+
+sets the appropriate target for error messages.
+
+=back
+
+=cut
+
+# private package variables
+my $_pname;
+my $_ptype;
+my $_pcontext;
+
+sub setup_application {
+    my ($name, $type, $context) = @_;
+
+    # sanity check
+    croak("no name given") unless ($name);
+    croak("no type given") unless ($type);
+    croak("no context given") unless ($context);
+
+    # store these as perl values
+    $_pname = $name;
+    $_ptype = $type;
+    $_pcontext = $context;
+
+    # and let the C side know about the pname
+    set_pname($name);
+
+    safe_cd(); # (also sets umask)
+    check_std_fds();
+
+    # set up debugging for this application type
+    dbopen($type);
+
+    # ignore SIGPIPE
+    $SIG{'PIPE'} = 'IGNORE';
+
+    set_erroutput_type($type, $context);
+}
+
+=item C<finish_setup($running_as_flags)>
+
+Perform final initialization tasks that require a loaded configuration.
+Specifically, move the debug log into a configuration-specific
+subdirectory, and check that the current userid is appropriate for
+this applciation.
+
+The user is specified by one of the following flags, which are
+available in export tag C<:check_running_as_flags>:
+
+  $RUNNING_AS_ROOT                # root
+  $RUNNING_AS_DUMPUSER            # dumpuser, from configuration
+  $RUNNING_AS_DUMPUSER_PREFERRED  # dumpuser, but client_login is OK too
+  $RUNNING_AS_CLIENT_LOGIN        # client_login (--with-user at build time)
+
+If the flag C<$RUNNING_AS_UID_ONLY> is bit-or'd into C<$running_as_flags>, then
+the euid is ignored; this is used for programs that expect to be setuid-root.
+
+=cut
+
+sub finish_setup {
+    my ($running_as) = @_;
+
+    my $config_name = Amanda::Config::get_config_name();
+
+    if ($config_name) {
+       dbrename($config_name, $_ptype);
+    }
+
+    check_running_as($running_as);
+}
+
+=item C<safe_env()>
+
+Return a "safe" environment hash.  For non-setuid programs, this means filtering out any
+localization variables.
+
+=cut
+
+sub safe_env {
+    my %rv = %ENV;
+
+    delete @rv{qw(IFS CDPATH ENV BASH_ENV LANG)};
+
+    # delete all LC_* variables
+    for my $var (grep /^LC_/, keys %rv) {
+        delete $rv{$var};
+    }
+
+    return %rv;
+}
+
+
+push @EXPORT_OK, qw(running_as_flags_to_strings);
+push @{$EXPORT_TAGS{"running_as_flags"}}, qw(running_as_flags_to_strings);
+
+my %_running_as_flags_VALUES;
+#Convert a flag value to a list of names for flags that are set.
+sub running_as_flags_to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_running_as_flags_VALUES) {
+       my $v = $_running_as_flags_VALUES{$k};
+
+       #is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+#by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+
+push @EXPORT_OK, qw($RUNNING_AS_ROOT);
+push @{$EXPORT_TAGS{"running_as_flags"}}, qw($RUNNING_AS_ROOT);
+
+$_running_as_flags_VALUES{"RUNNING_AS_ROOT"} = $RUNNING_AS_ROOT;
+
+push @EXPORT_OK, qw($RUNNING_AS_DUMPUSER);
+push @{$EXPORT_TAGS{"running_as_flags"}}, qw($RUNNING_AS_DUMPUSER);
+
+$_running_as_flags_VALUES{"RUNNING_AS_DUMPUSER"} = $RUNNING_AS_DUMPUSER;
+
+push @EXPORT_OK, qw($RUNNING_AS_DUMPUSER_PREFERRED);
+push @{$EXPORT_TAGS{"running_as_flags"}}, qw($RUNNING_AS_DUMPUSER_PREFERRED);
+
+$_running_as_flags_VALUES{"RUNNING_AS_DUMPUSER_PREFERRED"} = $RUNNING_AS_DUMPUSER_PREFERRED;
+
+push @EXPORT_OK, qw($RUNNING_AS_CLIENT_LOGIN);
+push @{$EXPORT_TAGS{"running_as_flags"}}, qw($RUNNING_AS_CLIENT_LOGIN);
+
+$_running_as_flags_VALUES{"RUNNING_AS_CLIENT_LOGIN"} = $RUNNING_AS_CLIENT_LOGIN;
+
+push @EXPORT_OK, qw($RUNNING_AS_UID_ONLY);
+push @{$EXPORT_TAGS{"running_as_flags"}}, qw($RUNNING_AS_UID_ONLY);
+
+$_running_as_flags_VALUES{"RUNNING_AS_UID_ONLY"} = $RUNNING_AS_UID_ONLY;
+
+sub check_std_fds {
+    fcntl(STDIN, F_GETFD, 0) or critical("Standard input is not open");
+    fcntl(STDOUT, F_GETFD, 0) or critical("Standard output is not open");
+    fcntl(STDERR, F_GETFD, 0) or critical("Standard error is not open");
+}
+
+=back
+
+=cut
+1;
diff --git a/perl/Amanda/Util.swg b/perl/Amanda/Util.swg
new file mode 100644 (file)
index 0000000..e38a2e5
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%module "Amanda::Util"
+%include "amglue/amglue.swg"
+%include "exception.i"
+
+%{
+#include "debug.h"
+/* use a relative path here to avoid conflicting with Perl's util.h. */
+#include "../common-src/util.h"
+#include "file.h"
+%}
+
+%perlcode %{
+use Amanda::Debug qw(:init);
+use Carp;
+use POSIX qw(:fcntl_h);
+
+=head1 NAME
+
+Amanda::Util - Runtime support for Amanda applications
+
+=head1 Application Initialization
+
+Application initialization generally looks like this:
+
+  use Amanda::Config qw( :init );
+  use Amanda::Util qw( :check_running_as_flags );
+  use Amanda::Debug;
+
+  Amanda::Util::setup_application("myapp", "server", "cmdline");
+  # .. command-line processing ..
+  Amanda::Config::config_init(...);
+  Amanda::Util::finish_setup($RUNNING_AS_DUMPUSER);
+
+=over
+
+=item C<setup_application($name, $type, $context)>
+
+Set up the operating environment for an application, without requiring any
+configuration.
+
+C<$name> is the name of the application, used in log messages, etc.  C<$type>
+is usualy one of "server" or "client".  It specifies the subdirectory in which
+debug logfiles will be created.  C<$context> indicates the usual manner in
+which this application is invoked; one of C<"cmdline"> for a user-invoked
+command-line utility (e.g., C<amadmin>) which should send human-readable error
+messages to stderr; C<"daemon"> for a program started by C<amandad>, e.g.,
+C<sendbackup>; or C<"scriptutil"> for a small program used from shell scripts,
+e.g., C<amgetconf>
+
+Based on C<$type> and C<$context>, this function does the following:
+
+=over
+
+=item *
+
+sets up debug logging;
+
+=item *
+
+configures internationalization
+
+=item *
+
+sets the umask;
+
+=item *
+
+sets the current working directory to the debug or temporary directory;
+
+=item *
+
+closes any unnecessary file descriptors as a security meaasure;
+
+=item *
+
+ignores C<SIGPIPE>; and
+
+=item *
+
+sets the appropriate target for error messages.
+
+=back
+
+=cut
+
+# private package variables
+my $_pname;
+my $_ptype;
+my $_pcontext;
+
+sub setup_application {
+    my ($name, $type, $context) = @_;
+
+    # sanity check
+    croak("no name given") unless ($name);
+    croak("no type given") unless ($type);
+    croak("no context given") unless ($context);
+
+    # store these as perl values
+    $_pname = $name;
+    $_ptype = $type;
+    $_pcontext = $context;
+
+    # and let the C side know about the pname
+    set_pname($name);
+
+    safe_cd(); # (also sets umask)
+    check_std_fds();
+
+    # set up debugging for this application type
+    dbopen($type);
+
+    # ignore SIGPIPE
+    $SIG{'PIPE'} = 'IGNORE';
+
+    set_erroutput_type($type, $context);
+}
+
+=item C<finish_setup($running_as_flags)>
+
+Perform final initialization tasks that require a loaded configuration.
+Specifically, move the debug log into a configuration-specific
+subdirectory, and check that the current userid is appropriate for
+this applciation.
+
+The user is specified by one of the following flags, which are
+available in export tag C<:check_running_as_flags>:
+
+  $RUNNING_AS_ROOT                # root
+  $RUNNING_AS_DUMPUSER            # dumpuser, from configuration
+  $RUNNING_AS_DUMPUSER_PREFERRED  # dumpuser, but client_login is OK too
+  $RUNNING_AS_CLIENT_LOGIN        # client_login (--with-user at build time)
+
+If the flag C<$RUNNING_AS_UID_ONLY> is bit-or'd into C<$running_as_flags>, then
+the euid is ignored; this is used for programs that expect to be setuid-root.
+
+=cut
+
+sub finish_setup {
+    my ($running_as) = @_;
+
+    my $config_name = Amanda::Config::get_config_name();
+
+    if ($config_name) {
+       dbrename($config_name, $_ptype);
+    }
+
+    check_running_as($running_as);
+}
+
+=item C<safe_env()>
+
+Return a "safe" environment hash.  For non-setuid programs, this means filtering out any
+localization variables.
+
+=cut
+
+sub safe_env {
+    my %rv = %ENV;
+
+    delete @rv{qw(IFS CDPATH ENV BASH_ENV LANG)};
+
+    # delete all LC_* variables
+    for my $var (grep /^LC_/, keys %rv) {
+        delete $rv{$var};
+    }
+
+    return %rv;
+}
+
+%}
+
+amglue_add_flag_tag_fns(running_as_flags);
+amglue_add_constant(RUNNING_AS_ROOT, running_as_flags);
+amglue_add_constant(RUNNING_AS_DUMPUSER, running_as_flags);
+amglue_add_constant(RUNNING_AS_DUMPUSER_PREFERRED, running_as_flags);
+amglue_add_constant(RUNNING_AS_CLIENT_LOGIN, running_as_flags);
+amglue_add_constant(RUNNING_AS_UID_ONLY, running_as_flags);
+
+/* -------------------------------------------------------------------------
+ * Functions below this line are only meant to be called within this module;
+ * do not call them externally. */
+
+void set_pname(char *name);
+void safe_cd(void);
+
+void check_running_as(running_as_flags who);
+
+/* Set erroutput_type as appropriate for this process type and context.
+ *
+ * @param type: process type
+ * @param context: process context
+ */
+%inline %{
+void
+set_erroutput_type(char *type, char *context)
+{
+    if (strcmp(context, "cmdline") == 0) {
+       erroutput_type = ERR_INTERACTIVE;
+    } else if (strcmp(context, "daemon") == 0) {
+       if (strcmp(type, "server") == 0) {
+           erroutput_type = ERR_INTERACTIVE|ERR_AMANDALOG;
+       } else if (strcmp(type, "client") == 0) {
+           erroutput_type = ERR_INTERACTIVE|ERR_SYSLOG;
+       }
+    }
+}
+%}
+
+/* Check that fd's 0, 1, and 2 are open, calling critical() if not.
+ */
+%perlcode %{
+sub check_std_fds {
+    fcntl(STDIN, F_GETFD, 0) or critical("Standard input is not open");
+    fcntl(STDOUT, F_GETFD, 0) or critical("Standard output is not open");
+    fcntl(STDERR, F_GETFD, 0) or critical("Standard error is not open");
+}
+
+=back
+
+=cut
+%}
diff --git a/perl/Makefile.am b/perl/Makefile.am
new file mode 100644 (file)
index 0000000..026f067
--- /dev/null
@@ -0,0 +1,231 @@
+##
+## Prepare for SWIGging
+## 
+
+include $(top_srcdir)/config/automake/vars.am
+include $(top_srcdir)/config/automake/scripts.am
+
+# add the SWIG symbol to avoid conflicts with perl definitions.
+# $AMANDA_WARNING_CFLAGS is omitted because SWIG-generated files tend
+# to trigger warnings
+AM_CFLAGS = -DSWIG
+
+# Appropriate INCLUDES depends on which components (server or client) are 
+# being built
+INCLUDES =  \
+            -I$(top_builddir)/common-src \
+            -I$(top_srcdir)/common-src \
+            -I$(top_srcdir)/perl/amglue \
+            -I$(top_srcdir)/gnulib \
+            $(PERL_INC)
+
+if WANT_SERVER
+INCLUDES += -I$(top_srcdir)/device-src \
+           -I$(top_srcdir)/server-src
+endif
+
+if WANT_CLIENT
+INCLUDES += -I$(top_srcdir)/client-src
+endif
+
+if WANT_RESTORE
+INCLUDES += -I$(top_srcdir)/restore-src
+endif
+
+if WANT_RECOVER
+INCLUDES += -I$(top_srcdir)/recover-src
+endif
+
+# (amplot has a conditional, but doesn't have any header files)
+
+##
+## libamglue -- helper functions for gluing amanda to perl
+##
+
+amlib_LTLIBRARIES = libamglue.la
+libamglue_la_SOURCES = \
+       amglue/ghashtable.c \
+       amglue/bigint.c \
+       amglue/amglue.h
+libamglue_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+EXTRA_DIST += $(libamglue_la_SOURCES)
+
+##
+## HTML Generation
+##
+
+# This isn't a very robust implementation, as it's only meant to make the HTML
+# available online as part of the automated compilation process.  It assumes
+# that all perl modules were built (not just server or client), and that the
+# build directory does not contain any "junk".
+
+# HTML_SOURCE_FILES should contain the .pm files from which the HTML should
+# be geneated.  This is just the concatenation of foo_DATA for all $(foodir)
+# into which perl modules are installed.
+HTML_SOURCE_FILES=
+html: make_html amperl.css $(HTML_SOURCE_FILES)
+       rm -rf html-tmp/ && mkdir html-tmp/
+       cp amperl.css html-tmp/
+       $(PERL) make_html html-tmp/ $(HTML_SOURCE_FILES)
+       cd html-tmp/ && tar -zcf $(abs_builddir)/html.tar.gz .
+       rm -rf html-tmp/
+##
+## SWIG-generated packages
+##
+
+# Tell libtool to not bother versioning the libs we build, since perl won't
+# pay attention to such things, anyway.
+PERL_EXT_LDFLAGS = -avoid-version
+
+# And add any flags the user has requested; on FreeBSD, this pulls in the 
+# threading library
+PERL_EXT_LDFLAGS += $(PERLEXTLIBS)
+
+# list our SWIG libraries. 
+AMGLUE_SWG = amglue/amglue.swg \
+       amglue/amglue.swg \
+       amglue/constants.swg \
+       amglue/dumpspecs.swg \
+       amglue/exports.swg \
+       amglue/glib.swg \
+       amglue/integers.swg
+EXTRA_DIST += $(AMGLUE_SWG)
+
+# SWIG OPTIONS:
+# -perl5 -proxy: generate perl code, with proxy (shadow) classes
+# -DSWIG_TYPE_TABLE: the name for the global type table; customized
+#  to minimize type collisions with other SWIG-generated modules
+# -I$(srcdir) use include files relative to this directory
+SWIG_OPTIONS=-perl5 -proxy -DSWIG_TYPE_TABLE=SWIG_TYPES_Amanda -I$(srcdir)
+
+# Suffix rules.  These are parallel-build compatible, but may cause
+# strange behavior if there are other .c files in this directory.  The
+# 'rm -f $@' is needed because SWIG sometimes fails to remove its output
+# file in the event of a syntax error.  .i files are pre-processor output;
+# they are only used during development.
+%.c : %.swg $(AMGLUE_SWG)
+       $(mkdir_p) `dirname $@`
+       $(SWIG) $(SWIG_OPTIONS) -o $@ $(top_srcdir)/perl/$< || { rm -f $@; false; }
+%.pm : %.c
+       @echo "$@ was produced as a side-effect of creating $<"
+%.i : %.swg $(AMGLUE_SWG)
+       $(SWIG) $(SWIG_OPTIONS) -E $(top_srcdir)/perl/$< >$@
+
+Amandadir=$(amperldir)/Amanda
+Amanda_DATA =
+HTML_SOURCE_FILES += $(Amanda_DATA)
+
+if WANT_SERVER
+# PACKAGE: Amanda::Device
+libDevicedir = $(amperldir)/auto/Amanda/Device
+libDevice_LTLIBRARIES = libDevice.la
+libDevice_la_SOURCES = Amanda/Device.c $(AMGLUE_SWG)
+libDevice_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libDevice_la_LIBADD = libamglue.la \
+       $(top_builddir)/device-src/libamdevice.la \
+       $(top_builddir)/common-src/libamanda.la
+Amanda_DATA += Amanda/Device.pm
+EXTRA_DIST += Amanda/Device.swg Amanda/Device.pm
+MAINTAINERCLEANFILES += Amanda/Device.c Amanda/Device.pm
+
+# PACKAGE: Amanda::Logfile
+libLogfiledir = $(amperldir)/auto/Amanda/Logfile
+libLogfile_LTLIBRARIES = libLogfile.la
+libLogfile_la_SOURCES = Amanda/Logfile.c $(AMGLUE_SWG)
+libLogfile_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libLogfile_la_LIBADD = libamglue.la \
+       $(top_builddir)/server-src/libamserver.la \
+       $(top_builddir)/common-src/libamanda.la
+Amanda_DATA += Amanda/Logfile.pm
+EXTRA_DIST += Amanda/Logfile.swg Amanda/Logfile.pm
+MAINTAINERCLEANFILES += Amanda/Logfile.c Amanda/Logfile.pm
+
+# PACKAGE: Amanda::Cmdline
+libCmdlinedir = $(amperldir)/auto/Amanda/Cmdline
+libCmdline_LTLIBRARIES = libCmdline.la
+libCmdline_la_SOURCES = Amanda/Cmdline.c $(AMGLUE_SWG)
+libCmdline_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libCmdline_la_LIBADD = libamglue.la \
+       $(top_builddir)/server-src/libamserver.la \
+       $(top_builddir)/common-src/libamanda.la
+Amanda_DATA += Amanda/Cmdline.pm
+EXTRA_DIST += Amanda/Cmdline.swg Amanda/Cmdline.pm
+MAINTAINERCLEANFILES += Amanda/Cmdline.c Amanda/Cmdline.pm
+
+# PACKAGE: Amanda::Tapefile
+libTapefiledir = $(amperldir)/auto/Amanda/Tapefile
+libTapefile_LTLIBRARIES = libTapefile.la
+libTapefile_la_SOURCES = Amanda/Tapefile.c $(AMGLUE_SWG)
+libTapefile_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libTapefile_la_LIBADD = libamglue.la \
+       $(top_builddir)/server-src/libamserver.la \
+       $(top_builddir)/common-src/libamanda.la
+Amanda_DATA += Amanda/Tapefile.pm
+EXTRA_DIST += Amanda/Tapefile.swg Amanda/Tapefile.pm
+MAINTAINERCLEANFILES += Amanda/Tapefile.c Amanda/Tapefile.pm
+
+# PACKAGE: Amanda::Changer
+Amanda_DATA += Amanda/Changer.pm
+EXTRA_DIST += Amanda/Changer.pm
+
+endif
+
+# PACKAGE: Amanda::Debug
+libDebugdir = $(amperldir)/auto/Amanda/Debug
+libDebug_LTLIBRARIES = libDebug.la
+libDebug_la_SOURCES = Amanda/Debug.c $(AMGLUE_SWG)
+libDebug_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libDebug_la_LIBADD = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+Amanda_DATA += Amanda/Debug.pm
+EXTRA_DIST += Amanda/Debug.swg Amanda/Debug.pm
+MAINTAINERCLEANFILES += Amanda/Debug.c Amanda/Debug.pm
+
+# PACKAGE: Amanda::Config
+libConfigdir = $(amperldir)/auto/Amanda/Config
+libConfig_LTLIBRARIES = libConfig.la
+libConfig_la_SOURCES = Amanda/Config.c $(AMGLUE_SWG)
+libConfig_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libConfig_la_LIBADD = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+Amanda_DATA += Amanda/Config.pm
+EXTRA_DIST += Amanda/Config.swg Amanda/Config.pm
+MAINTAINERCLEANFILES += Amanda/Config.c Amanda/Config.pm
+
+# PACKAGE: Amanda::Util
+libUtildir = $(amperldir)/auto/Amanda/Util
+libUtil_LTLIBRARIES = libUtil.la
+libUtil_la_SOURCES = Amanda/Util.c $(AMGLUE_SWG)
+libUtil_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libUtil_la_LIBADD = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+Amanda_DATA += Amanda/Util.pm
+EXTRA_DIST += Amanda/Util.swg Amanda/Util.pm
+MAINTAINERCLEANFILES += Amanda/Util.c Amanda/Util.pm
+
+# PACKAGE: Amanda::Types
+libTypesdir = $(amperldir)/auto/Amanda/Types
+libTypes_LTLIBRARIES = libTypes.la
+libTypes_la_SOURCES = Amanda/Types.c $(AMGLUE_SWG)
+libTypes_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libTypes_la_LIBADD = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+Amanda_DATA += Amanda/Types.pm
+EXTRA_DIST += Amanda/Types.swg Amanda/Types.pm
+MAINTAINERCLEANFILES += Amanda/Types.c Amanda/Types.pm
+
+# PACKAGE: Amanda::Paths
+Amanda_DATA += Amanda/Paths.pm
+EXTRA_DIST += Amanda/Paths.pm.in
+DISTCLEANFILES += Amanda/Paths.pm
+
+# perl doesn't use the cyg prefix and it doesn't search in the bin
+# directory, dll must be copied to their modules directories.
+if WANT_CYGWIN_COPY_PERL_DLL
+amperldirauto="$(DESTDIR)$(amperldir)/auto/Amanda"
+install-data-hook:
+       @for cygdll in $(amperldirauto)/bin/cyg*.dll; do \
+           destfname=`echo $$cygdll|sed 's!/bin/cyg\([^.]*\).dll!/\1/\1.dll!'`; \
+           cp "$$cygdll" "$$destfname"; \
+       done
+endif
diff --git a/perl/Makefile.in b/perl/Makefile.in
new file mode 100644 (file)
index 0000000..a4fbb16
--- /dev/null
@@ -0,0 +1,1700 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# vim:ft=automake
+# Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+# 
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License version 2.1 as 
+# published by the Free Software Foundation.
+# 
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+# 
+# Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+# simple include file to pre-define variables which are then +='d by other
+# scripts in this directory.
+
+# vim:ft=automake
+# Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+# 
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License version 2.1 as 
+# published by the Free Software Foundation.
+# 
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+# 
+# Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+
+# SYNOPSIS:
+#
+# Automake magic to handle the various tasks of building scripts.  Scripts can
+# be built down to extensionless executables (e.g., foo.pl -> foo), or to 
+# files with the usual extension (foo-lib.sh.in -> foo.sh).
+#
+# Files which support it are syntax-checked when the user invokes 'make check'.
+#
+# All *target* filenames must be listed in SCRIPTS_SHELL, SCRIPTS_PERL, and 
+# SCRIPTS_AWK to support 'make check', 'make dist', and 'make distclean'.
+#
+# USAGE:
+#
+#   include $(top_srcdir)/config/automake/vars.am
+#   include $(top_srcdir)/config/automake/scripts.am
+#   ...
+#   SCRIPTS_PERL = fooscript barscript perl-lib.pl perlmod.pm
+#   SCRIPTS_SHELL = shell1 shell2 sh-lib.sh
+#   SCRIPTS_AWK = talk balk chalk awk-lib.awk
+#
+# with the corresponding files in the repository:
+#
+#   fooscript.pl barscript.pl perl-lib.pl.in perlmod.pm.in
+#   shell1.sh shell2.sh sh-lib.sh.in
+#   talk.awk balk.awk chalk.awk awk-lib.awk.in
+#
+# by default, all shell and perl scripts are syntax checked.  If this is
+# a problem (for example, perl scripts depending on Amanda extension 
+# modules), then assign to CHECK_{PERL,SHELL} the list of files you wish
+# to be checked (which can be empty).
+#
+# To add extra flags to the perl checks (e.g., to add new -I flags), set
+# CHECK_PERL_FLAGS.
+
+# Implementation note:
+#
+# This file uses config.status to substitute @foo@ in those scripts while
+# converting them. It also adds the executable bits (a+x) to extensionless
+# files.  The substitution works even though the files are not listed in 
+# configure.in
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(top_srcdir)/config/automake/scripts.am \
+       $(top_srcdir)/config/automake/vars.am
+@WANT_SERVER_TRUE@am__append_1 = -I$(top_srcdir)/device-src \
+@WANT_SERVER_TRUE@         -I$(top_srcdir)/server-src
+
+@WANT_CLIENT_TRUE@am__append_2 = -I$(top_srcdir)/client-src
+@WANT_RESTORE_TRUE@am__append_3 = -I$(top_srcdir)/restore-src
+@WANT_RECOVER_TRUE@am__append_4 = -I$(top_srcdir)/recover-src
+
+# PACKAGE: Amanda::Changer
+@WANT_SERVER_TRUE@am__append_5 = Amanda/Device.pm Amanda/Logfile.pm \
+@WANT_SERVER_TRUE@     Amanda/Cmdline.pm Amanda/Tapefile.pm \
+@WANT_SERVER_TRUE@     Amanda/Changer.pm
+@WANT_SERVER_TRUE@am__append_6 = Amanda/Device.swg Amanda/Device.pm \
+@WANT_SERVER_TRUE@     Amanda/Logfile.swg Amanda/Logfile.pm \
+@WANT_SERVER_TRUE@     Amanda/Cmdline.swg Amanda/Cmdline.pm \
+@WANT_SERVER_TRUE@     Amanda/Tapefile.swg Amanda/Tapefile.pm \
+@WANT_SERVER_TRUE@     Amanda/Changer.pm
+@WANT_SERVER_TRUE@am__append_7 = Amanda/Device.c Amanda/Device.pm \
+@WANT_SERVER_TRUE@     Amanda/Logfile.c Amanda/Logfile.pm \
+@WANT_SERVER_TRUE@     Amanda/Cmdline.c Amanda/Cmdline.pm \
+@WANT_SERVER_TRUE@     Amanda/Tapefile.c Amanda/Tapefile.pm
+subdir = perl
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps =  \
+       $(top_srcdir)/config/macro-archive/ac_define_dir.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_perl_version.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_swig.m4 \
+       $(top_srcdir)/config/macro-archive/ax_compare_version.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-dtd.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt-min.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt.m4 \
+       $(top_srcdir)/config/macro-archive/xsltproc.m4 \
+       $(top_srcdir)/config/amanda/amplot.m4 \
+       $(top_srcdir)/config/amanda/bsd-security.m4 \
+       $(top_srcdir)/config/amanda/bsdtcp-security.m4 \
+       $(top_srcdir)/config/amanda/bsdudp-security.m4 \
+       $(top_srcdir)/config/amanda/changer.m4 \
+       $(top_srcdir)/config/amanda/components.m4 \
+       $(top_srcdir)/config/amanda/compress.m4 \
+       $(top_srcdir)/config/amanda/config.m4 \
+       $(top_srcdir)/config/amanda/debugging.m4 \
+       $(top_srcdir)/config/amanda/defaults.m4 \
+       $(top_srcdir)/config/amanda/devprefix.m4 \
+       $(top_srcdir)/config/amanda/dirs.m4 \
+       $(top_srcdir)/config/amanda/documentation.m4 \
+       $(top_srcdir)/config/amanda/dumpers.m4 \
+       $(top_srcdir)/config/amanda/flags.m4 \
+       $(top_srcdir)/config/amanda/flock.m4 \
+       $(top_srcdir)/config/amanda/funcs.m4 \
+       $(top_srcdir)/config/amanda/getfsent.m4 \
+       $(top_srcdir)/config/amanda/i18n.m4 \
+       $(top_srcdir)/config/amanda/ipv6.m4 \
+       $(top_srcdir)/config/amanda/krb4-security.m4 \
+       $(top_srcdir)/config/amanda/krb5-security.m4 \
+       $(top_srcdir)/config/amanda/lfs.m4 \
+       $(top_srcdir)/config/amanda/libs.m4 \
+       $(top_srcdir)/config/amanda/net.m4 \
+       $(top_srcdir)/config/amanda/progs.m4 \
+       $(top_srcdir)/config/amanda/readdir.m4 \
+       $(top_srcdir)/config/amanda/readline.m4 \
+       $(top_srcdir)/config/amanda/rsh-security.m4 \
+       $(top_srcdir)/config/amanda/s3-device.m4 \
+       $(top_srcdir)/config/amanda/shmem.m4 \
+       $(top_srcdir)/config/amanda/socklen_t_equiv.m4 \
+       $(top_srcdir)/config/amanda/ssh-security.m4 \
+       $(top_srcdir)/config/amanda/summary.m4 \
+       $(top_srcdir)/config/amanda/swig.m4 \
+       $(top_srcdir)/config/amanda/syshacks.m4 \
+       $(top_srcdir)/config/amanda/tape.m4 \
+       $(top_srcdir)/config/amanda/types.m4 \
+       $(top_srcdir)/config/amanda/userid.m4 \
+       $(top_srcdir)/config/amanda/version.m4 \
+       $(top_srcdir)/config/gnulib/alloca.m4 \
+       $(top_srcdir)/config/gnulib/arpa_inet_h.m4 \
+       $(top_srcdir)/config/gnulib/base64.m4 \
+       $(top_srcdir)/config/gnulib/eoverflow.m4 \
+       $(top_srcdir)/config/gnulib/extensions.m4 \
+       $(top_srcdir)/config/gnulib/float_h.m4 \
+       $(top_srcdir)/config/gnulib/fsusage.m4 \
+       $(top_srcdir)/config/gnulib/getaddrinfo.m4 \
+       $(top_srcdir)/config/gnulib/gettimeofday.m4 \
+       $(top_srcdir)/config/gnulib/gnulib-comp.m4 \
+       $(top_srcdir)/config/gnulib/include_next.m4 \
+       $(top_srcdir)/config/gnulib/inet_ntop.m4 \
+       $(top_srcdir)/config/gnulib/intmax_t.m4 \
+       $(top_srcdir)/config/gnulib/lock.m4 \
+       $(top_srcdir)/config/gnulib/longlong.m4 \
+       $(top_srcdir)/config/gnulib/malloc.m4 \
+       $(top_srcdir)/config/gnulib/mkdtemp.m4 \
+       $(top_srcdir)/config/gnulib/netinet_in_h.m4 \
+       $(top_srcdir)/config/gnulib/onceonly_2_57.m4 \
+       $(top_srcdir)/config/gnulib/physmem.m4 \
+       $(top_srcdir)/config/gnulib/safe-read.m4 \
+       $(top_srcdir)/config/gnulib/safe-write.m4 \
+       $(top_srcdir)/config/gnulib/snprintf.m4 \
+       $(top_srcdir)/config/gnulib/socklen.m4 \
+       $(top_srcdir)/config/gnulib/sockpfaf.m4 \
+       $(top_srcdir)/config/gnulib/ssize_t.m4 \
+       $(top_srcdir)/config/gnulib/stdbool.m4 \
+       $(top_srcdir)/config/gnulib/stdint.m4 \
+       $(top_srcdir)/config/gnulib/stdio_h.m4 \
+       $(top_srcdir)/config/gnulib/stdlib_h.m4 \
+       $(top_srcdir)/config/gnulib/strdup.m4 \
+       $(top_srcdir)/config/gnulib/string_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_socket_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_stat_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_time_h.m4 \
+       $(top_srcdir)/config/gnulib/tempname.m4 \
+       $(top_srcdir)/config/gnulib/ulonglong.m4 \
+       $(top_srcdir)/config/gnulib/unistd_h.m4 \
+       $(top_srcdir)/config/gnulib/vasnprintf.m4 \
+       $(top_srcdir)/config/gnulib/visibility.m4 \
+       $(top_srcdir)/config/gnulib/wchar.m4 \
+       $(top_srcdir)/config/gettext-macros/gettext.m4 \
+       $(top_srcdir)/config/gettext-macros/iconv.m4 \
+       $(top_srcdir)/config/gettext-macros/inttypes_h.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-ld.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-link.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-prefix.m4 \
+       $(top_srcdir)/config/gettext-macros/longlong.m4 \
+       $(top_srcdir)/config/gettext-macros/nls.m4 \
+       $(top_srcdir)/config/gettext-macros/po.m4 \
+       $(top_srcdir)/config/gettext-macros/progtest.m4 \
+       $(top_srcdir)/config/gettext-macros/size_max.m4 \
+       $(top_srcdir)/config/gettext-macros/stdint_h.m4 \
+       $(top_srcdir)/config/gettext-macros/wchar_t.m4 \
+       $(top_srcdir)/config/gettext-macros/wint_t.m4 \
+       $(top_srcdir)/config/gettext-macros/xsize.m4 \
+       $(top_srcdir)/config/libtool.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(amlibdir)" "$(DESTDIR)$(libCmdlinedir)" \
+       "$(DESTDIR)$(libConfigdir)" "$(DESTDIR)$(libDebugdir)" \
+       "$(DESTDIR)$(libDevicedir)" "$(DESTDIR)$(libLogfiledir)" \
+       "$(DESTDIR)$(libTapefiledir)" "$(DESTDIR)$(libTypesdir)" \
+       "$(DESTDIR)$(libUtildir)" "$(DESTDIR)$(Amandadir)"
+amlibLTLIBRARIES_INSTALL = $(INSTALL)
+libCmdlineLTLIBRARIES_INSTALL = $(INSTALL)
+libConfigLTLIBRARIES_INSTALL = $(INSTALL)
+libDebugLTLIBRARIES_INSTALL = $(INSTALL)
+libDeviceLTLIBRARIES_INSTALL = $(INSTALL)
+libLogfileLTLIBRARIES_INSTALL = $(INSTALL)
+libTapefileLTLIBRARIES_INSTALL = $(INSTALL)
+libTypesLTLIBRARIES_INSTALL = $(INSTALL)
+libUtilLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(amlib_LTLIBRARIES) $(libCmdline_LTLIBRARIES) \
+       $(libConfig_LTLIBRARIES) $(libDebug_LTLIBRARIES) \
+       $(libDevice_LTLIBRARIES) $(libLogfile_LTLIBRARIES) \
+       $(libTapefile_LTLIBRARIES) $(libTypes_LTLIBRARIES) \
+       $(libUtil_LTLIBRARIES)
+@WANT_SERVER_TRUE@libCmdline_la_DEPENDENCIES = libamglue.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/server-src/libamserver.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/common-src/libamanda.la
+am__libCmdline_la_SOURCES_DIST = Amanda/Cmdline.c amglue/amglue.swg \
+       amglue/constants.swg amglue/dumpspecs.swg amglue/exports.swg \
+       amglue/glib.swg amglue/integers.swg
+am__objects_1 =
+@WANT_SERVER_TRUE@am_libCmdline_la_OBJECTS = Cmdline.lo \
+@WANT_SERVER_TRUE@     $(am__objects_1)
+libCmdline_la_OBJECTS = $(am_libCmdline_la_OBJECTS)
+libCmdline_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libCmdline_la_LDFLAGS) $(LDFLAGS) -o $@
+@WANT_SERVER_TRUE@am_libCmdline_la_rpath = -rpath $(libCmdlinedir)
+libConfig_la_DEPENDENCIES = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+am_libConfig_la_OBJECTS = Config.lo $(am__objects_1)
+libConfig_la_OBJECTS = $(am_libConfig_la_OBJECTS)
+libConfig_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libConfig_la_LDFLAGS) $(LDFLAGS) -o $@
+libDebug_la_DEPENDENCIES = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+am_libDebug_la_OBJECTS = Debug.lo $(am__objects_1)
+libDebug_la_OBJECTS = $(am_libDebug_la_OBJECTS)
+libDebug_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libDebug_la_LDFLAGS) $(LDFLAGS) -o $@
+@WANT_SERVER_TRUE@libDevice_la_DEPENDENCIES = libamglue.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/device-src/libamdevice.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/common-src/libamanda.la
+am__libDevice_la_SOURCES_DIST = Amanda/Device.c amglue/amglue.swg \
+       amglue/constants.swg amglue/dumpspecs.swg amglue/exports.swg \
+       amglue/glib.swg amglue/integers.swg
+@WANT_SERVER_TRUE@am_libDevice_la_OBJECTS = Device.lo $(am__objects_1)
+libDevice_la_OBJECTS = $(am_libDevice_la_OBJECTS)
+libDevice_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libDevice_la_LDFLAGS) $(LDFLAGS) -o $@
+@WANT_SERVER_TRUE@am_libDevice_la_rpath = -rpath $(libDevicedir)
+@WANT_SERVER_TRUE@libLogfile_la_DEPENDENCIES = libamglue.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/server-src/libamserver.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/common-src/libamanda.la
+am__libLogfile_la_SOURCES_DIST = Amanda/Logfile.c amglue/amglue.swg \
+       amglue/constants.swg amglue/dumpspecs.swg amglue/exports.swg \
+       amglue/glib.swg amglue/integers.swg
+@WANT_SERVER_TRUE@am_libLogfile_la_OBJECTS = Logfile.lo \
+@WANT_SERVER_TRUE@     $(am__objects_1)
+libLogfile_la_OBJECTS = $(am_libLogfile_la_OBJECTS)
+libLogfile_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libLogfile_la_LDFLAGS) $(LDFLAGS) -o $@
+@WANT_SERVER_TRUE@am_libLogfile_la_rpath = -rpath $(libLogfiledir)
+@WANT_SERVER_TRUE@libTapefile_la_DEPENDENCIES = libamglue.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/server-src/libamserver.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/common-src/libamanda.la
+am__libTapefile_la_SOURCES_DIST = Amanda/Tapefile.c amglue/amglue.swg \
+       amglue/constants.swg amglue/dumpspecs.swg amglue/exports.swg \
+       amglue/glib.swg amglue/integers.swg
+@WANT_SERVER_TRUE@am_libTapefile_la_OBJECTS = Tapefile.lo \
+@WANT_SERVER_TRUE@     $(am__objects_1)
+libTapefile_la_OBJECTS = $(am_libTapefile_la_OBJECTS)
+libTapefile_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libTapefile_la_LDFLAGS) $(LDFLAGS) -o $@
+@WANT_SERVER_TRUE@am_libTapefile_la_rpath = -rpath $(libTapefiledir)
+libTypes_la_DEPENDENCIES = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+am_libTypes_la_OBJECTS = Types.lo $(am__objects_1)
+libTypes_la_OBJECTS = $(am_libTypes_la_OBJECTS)
+libTypes_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libTypes_la_LDFLAGS) $(LDFLAGS) -o $@
+libUtil_la_DEPENDENCIES = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+am_libUtil_la_OBJECTS = Util.lo $(am__objects_1)
+libUtil_la_OBJECTS = $(am_libUtil_la_OBJECTS)
+libUtil_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libUtil_la_LDFLAGS) $(LDFLAGS) -o $@
+libamglue_la_LIBADD =
+am_libamglue_la_OBJECTS = ghashtable.lo bigint.lo
+libamglue_la_OBJECTS = $(am_libamglue_la_OBJECTS)
+libamglue_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libamglue_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I. -I$(top_builddir)/config@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
+SOURCES = $(libCmdline_la_SOURCES) $(libConfig_la_SOURCES) \
+       $(libDebug_la_SOURCES) $(libDevice_la_SOURCES) \
+       $(libLogfile_la_SOURCES) $(libTapefile_la_SOURCES) \
+       $(libTypes_la_SOURCES) $(libUtil_la_SOURCES) \
+       $(libamglue_la_SOURCES)
+DIST_SOURCES = $(am__libCmdline_la_SOURCES_DIST) \
+       $(libConfig_la_SOURCES) $(libDebug_la_SOURCES) \
+       $(am__libDevice_la_SOURCES_DIST) \
+       $(am__libLogfile_la_SOURCES_DIST) \
+       $(am__libTapefile_la_SOURCES_DIST) $(libTypes_la_SOURCES) \
+       $(libUtil_la_SOURCES) $(libamglue_la_SOURCES)
+AmandaDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(Amanda_DATA)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMANDA_DBGDIR = @AMANDA_DBGDIR@
+AMANDA_DEBUG_DAYS = @AMANDA_DEBUG_DAYS@
+AMANDA_STATIC_LDFLAGS = @AMANDA_STATIC_LDFLAGS@
+AMANDA_TMPDIR = @AMANDA_TMPDIR@
+AMANDA_WARNING_CFLAGS = @AMANDA_WARNING_CFLAGS@
+AMLINT = @AMLINT@
+AMLINTFLAGS = @AMLINTFLAGS@
+AMPLOT_CAT_COMPRESS = @AMPLOT_CAT_COMPRESS@
+AMPLOT_CAT_GZIP = @AMPLOT_CAT_GZIP@
+AMPLOT_CAT_PACK = @AMPLOT_CAT_PACK@
+AMPLOT_COMPRESS = @AMPLOT_COMPRESS@
+AMTAR = @AMTAR@
+AR = @AR@
+ARPA_INET_H = @ARPA_INET_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASH = @BASH@
+BINARY_OWNER = @BINARY_OWNER@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+CAT = @CAT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CHIO = @CHIO@
+CHS = @CHS@
+CLIENT_LOGIN = @CLIENT_LOGIN@
+CLIENT_SCRIPTS_OPT = @CLIENT_SCRIPTS_OPT@
+COMPRESS = @COMPRESS@
+CONFIG_DIR = @CONFIG_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURL_CONFIG = @CURL_CONFIG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DD = @DD@
+DEFAULT_AMANDATES_FILE = @DEFAULT_AMANDATES_FILE@
+DEFAULT_CHANGER_DEVICE = @DEFAULT_CHANGER_DEVICE@
+DEFAULT_CONFIG = @DEFAULT_CONFIG@
+DEFAULT_SERVER = @DEFAULT_SERVER@
+DEFAULT_TAPE_DEVICE = @DEFAULT_TAPE_DEVICE@
+DEFAULT_TAPE_SERVER = @DEFAULT_TAPE_SERVER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOC_BUILD_DATE = @DOC_BUILD_DATE@
+DUMP = @DUMP@
+DUMPER_DIR = @DUMPER_DIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXAMPLE_TAPEDEV = @EXAMPLE_TAPEDEV@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FLOAT_H = @FLOAT_H@
+GETCONF = @GETCONF@
+GETTEXT = @GETTEXT@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@
+GNULIB_CHOWN = @GNULIB_CHOWN@
+GNULIB_DUP2 = @GNULIB_DUP2@
+GNULIB_FCHDIR = @GNULIB_FCHDIR@
+GNULIB_FFLUSH = @GNULIB_FFLUSH@
+GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@
+GNULIB_FSEEK = @GNULIB_FSEEK@
+GNULIB_FSEEKO = @GNULIB_FSEEKO@
+GNULIB_FTELL = @GNULIB_FTELL@
+GNULIB_FTELLO = @GNULIB_FTELLO@
+GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@
+GNULIB_GETCWD = @GNULIB_GETCWD@
+GNULIB_GETDELIM = @GNULIB_GETDELIM@
+GNULIB_GETLINE = @GNULIB_GETLINE@
+GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@
+GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@
+GNULIB_LCHOWN = @GNULIB_LCHOWN@
+GNULIB_LSEEK = @GNULIB_LSEEK@
+GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@
+GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@
+GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@
+GNULIB_MBSCHR = @GNULIB_MBSCHR@
+GNULIB_MBSCSPN = @GNULIB_MBSCSPN@
+GNULIB_MBSLEN = @GNULIB_MBSLEN@
+GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@
+GNULIB_MBSNLEN = @GNULIB_MBSNLEN@
+GNULIB_MBSPBRK = @GNULIB_MBSPBRK@
+GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@
+GNULIB_MBSRCHR = @GNULIB_MBSRCHR@
+GNULIB_MBSSEP = @GNULIB_MBSSEP@
+GNULIB_MBSSPN = @GNULIB_MBSSPN@
+GNULIB_MBSSTR = @GNULIB_MBSSTR@
+GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@
+GNULIB_MEMMEM = @GNULIB_MEMMEM@
+GNULIB_MEMPCPY = @GNULIB_MEMPCPY@
+GNULIB_MEMRCHR = @GNULIB_MEMRCHR@
+GNULIB_MKDTEMP = @GNULIB_MKDTEMP@
+GNULIB_MKSTEMP = @GNULIB_MKSTEMP@
+GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@
+GNULIB_READLINK = @GNULIB_READLINK@
+GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@
+GNULIB_SLEEP = @GNULIB_SLEEP@
+GNULIB_SNPRINTF = @GNULIB_SNPRINTF@
+GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@
+GNULIB_STPCPY = @GNULIB_STPCPY@
+GNULIB_STPNCPY = @GNULIB_STPNCPY@
+GNULIB_STRCASESTR = @GNULIB_STRCASESTR@
+GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@
+GNULIB_STRDUP = @GNULIB_STRDUP@
+GNULIB_STRNDUP = @GNULIB_STRNDUP@
+GNULIB_STRNLEN = @GNULIB_STRNLEN@
+GNULIB_STRPBRK = @GNULIB_STRPBRK@
+GNULIB_STRSEP = @GNULIB_STRSEP@
+GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
+GNULIB_VASPRINTF = @GNULIB_VASPRINTF@
+GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@
+GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@
+GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@
+GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@
+GNULIB_WCWIDTH = @GNULIB_WCWIDTH@
+GNUPLOT = @GNUPLOT@
+GNUTAR = @GNUTAR@
+GNUTAR_LISTED_INCREMENTAL_DIR = @GNUTAR_LISTED_INCREMENTAL_DIR@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GZIP = @GZIP@
+HAVE_CALLOC_POSIX = @HAVE_CALLOC_POSIX@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_MKDIR = @HAVE_DECL_MKDIR@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DUP2 = @HAVE_DUP2@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_IO_H = @HAVE_IO_H@
+HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MALLOC_POSIX = @HAVE_MALLOC_POSIX@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_REALLOC_POSIX = @HAVE_REALLOC_POSIX@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRNDUP = @HAVE_STRNDUP@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE__BOOL = @HAVE__BOOL@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPTH = @LIBPTH@
+LIBS = @LIBS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBPTH = @LTLIBPTH@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAILER = @MAILER@
+MAKEINFO = @MAKEINFO@
+MAXTAPEBLOCKSIZE = @MAXTAPEBLOCKSIZE@
+MCUTIL = @MCUTIL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+MT = @MT@
+MTX = @MTX@
+MT_FILE_FLAG = @MT_FILE_FLAG@
+NETINET_IN_H = @NETINET_IN_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCAT = @PCAT@
+PERL = @PERL@
+PERLEXTLIBS = @PERLEXTLIBS@
+PERL_INC = @PERL_INC@
+PKG_CONFIG = @PKG_CONFIG@
+POSUB = @POSUB@
+PRINT = @PRINT@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_FCHDIR = @REPLACE_FCHDIR@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+RESTORE = @RESTORE@
+SAMBA_CLIENT = @SAMBA_CLIENT@
+SERVICE_SUFFIX = @SERVICE_SUFFIX@
+SETUID_GROUP = @SETUID_GROUP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+SNAPSHOT_STAMP = @SNAPSHOT_STAMP@
+SORT = @SORT@
+SSH = @SSH@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SVN = @SVN@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYS_SOCKET_H = @SYS_SOCKET_H@
+SYS_STAT_H = @SYS_STAT_H@
+SYS_TIME_H = @SYS_TIME_H@
+USE_NLS = @USE_NLS@
+USE_VERSION_SUFFIXES = @USE_VERSION_SUFFIXES@
+VDUMP = @VDUMP@
+VERSION = @VERSION@
+VERSION_COMMENT = @VERSION_COMMENT@
+VERSION_MAJOR = @VERSION_MAJOR@
+VERSION_MINOR = @VERSION_MINOR@
+VERSION_PATCH = @VERSION_PATCH@
+VERSION_SUFFIX = @VERSION_SUFFIX@
+VRESTORE = @VRESTORE@
+VXDUMP = @VXDUMP@
+VXRESTORE = @VXRESTORE@
+WCHAR_H = @WCHAR_H@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+XFSDUMP = @XFSDUMP@
+XFSRESTORE = @XFSRESTORE@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XSLREL = @XSLREL@
+XSLTPROC = @XSLTPROC@
+XSLTPROC_FLAGS = @XSLTPROC_FLAGS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+amincludedir = @amincludedir@
+amlibdir = @amlibdir@
+amlibexecdir = @amlibexecdir@
+amperldir = @amperldir@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUFFIXES = 
+EXTRA_DIST = $(libamglue_la_SOURCES) $(AMGLUE_SWG) $(am__append_6) \
+       Amanda/Debug.swg Amanda/Debug.pm Amanda/Config.swg \
+       Amanda/Config.pm Amanda/Util.swg Amanda/Util.pm \
+       Amanda/Types.swg Amanda/Types.pm Amanda/Paths.pm.in
+BUILT_SOURCES = 
+MOSTLYCLEANFILES = 
+
+# config.status leaves config.log files around
+CLEANFILES = config.log
+
+# and we'll need to clean up our generated files for distclean
+DISTCLEANFILES = $(SCRIPTS_SHELL) $(SCRIPTS_PERL) $(SCRIPTS_AWK) \
+       Amanda/Paths.pm
+MAINTAINERCLEANFILES = $(am__append_7) Amanda/Debug.c Amanda/Debug.pm \
+       Amanda/Config.c Amanda/Config.pm Amanda/Util.c Amanda/Util.pm \
+       Amanda/Types.c Amanda/Types.pm
+
+# syntax-check shell scripts on 'make check'
+CHECK_SHELL = $(SCRIPTS_SHELL)
+
+# add the SWIG symbol to avoid conflicts with perl definitions.
+# $AMANDA_WARNING_CFLAGS is omitted because SWIG-generated files tend
+# to trigger warnings
+AM_CFLAGS = -DSWIG
+
+# Appropriate INCLUDES depends on which components (server or client) are 
+# being built
+INCLUDES = -I$(top_builddir)/common-src -I$(top_srcdir)/common-src \
+       -I$(top_srcdir)/perl/amglue -I$(top_srcdir)/gnulib $(PERL_INC) \
+       $(am__append_1) $(am__append_2) $(am__append_3) \
+       $(am__append_4)
+
+# (amplot has a conditional, but doesn't have any header files)
+amlib_LTLIBRARIES = libamglue.la
+libamglue_la_SOURCES = \
+       amglue/ghashtable.c \
+       amglue/bigint.c \
+       amglue/amglue.h
+
+libamglue_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+
+# This isn't a very robust implementation, as it's only meant to make the HTML
+# available online as part of the automated compilation process.  It assumes
+# that all perl modules were built (not just server or client), and that the
+# build directory does not contain any "junk".
+
+# HTML_SOURCE_FILES should contain the .pm files from which the HTML should
+# be geneated.  This is just the concatenation of foo_DATA for all $(foodir)
+# into which perl modules are installed.
+HTML_SOURCE_FILES = $(Amanda_DATA)
+
+# Tell libtool to not bother versioning the libs we build, since perl won't
+# pay attention to such things, anyway.
+
+# And add any flags the user has requested; on FreeBSD, this pulls in the 
+# threading library
+PERL_EXT_LDFLAGS = -avoid-version $(PERLEXTLIBS)
+
+# list our SWIG libraries. 
+AMGLUE_SWG = amglue/amglue.swg \
+       amglue/amglue.swg \
+       amglue/constants.swg \
+       amglue/dumpspecs.swg \
+       amglue/exports.swg \
+       amglue/glib.swg \
+       amglue/integers.swg
+
+
+# SWIG OPTIONS:
+# -perl5 -proxy: generate perl code, with proxy (shadow) classes
+# -DSWIG_TYPE_TABLE: the name for the global type table; customized
+#  to minimize type collisions with other SWIG-generated modules
+# -I$(srcdir) use include files relative to this directory
+SWIG_OPTIONS = -perl5 -proxy -DSWIG_TYPE_TABLE=SWIG_TYPES_Amanda -I$(srcdir)
+Amandadir = $(amperldir)/Amanda
+
+# PACKAGE: Amanda::Paths
+Amanda_DATA = $(am__append_5) Amanda/Debug.pm Amanda/Config.pm \
+       Amanda/Util.pm Amanda/Types.pm Amanda/Paths.pm
+
+# PACKAGE: Amanda::Device
+@WANT_SERVER_TRUE@libDevicedir = $(amperldir)/auto/Amanda/Device
+@WANT_SERVER_TRUE@libDevice_LTLIBRARIES = libDevice.la
+@WANT_SERVER_TRUE@libDevice_la_SOURCES = Amanda/Device.c $(AMGLUE_SWG)
+@WANT_SERVER_TRUE@libDevice_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+@WANT_SERVER_TRUE@libDevice_la_LIBADD = libamglue.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/device-src/libamdevice.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/common-src/libamanda.la
+
+
+# PACKAGE: Amanda::Logfile
+@WANT_SERVER_TRUE@libLogfiledir = $(amperldir)/auto/Amanda/Logfile
+@WANT_SERVER_TRUE@libLogfile_LTLIBRARIES = libLogfile.la
+@WANT_SERVER_TRUE@libLogfile_la_SOURCES = Amanda/Logfile.c $(AMGLUE_SWG)
+@WANT_SERVER_TRUE@libLogfile_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+@WANT_SERVER_TRUE@libLogfile_la_LIBADD = libamglue.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/server-src/libamserver.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/common-src/libamanda.la
+
+
+# PACKAGE: Amanda::Cmdline
+@WANT_SERVER_TRUE@libCmdlinedir = $(amperldir)/auto/Amanda/Cmdline
+@WANT_SERVER_TRUE@libCmdline_LTLIBRARIES = libCmdline.la
+@WANT_SERVER_TRUE@libCmdline_la_SOURCES = Amanda/Cmdline.c $(AMGLUE_SWG)
+@WANT_SERVER_TRUE@libCmdline_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+@WANT_SERVER_TRUE@libCmdline_la_LIBADD = libamglue.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/server-src/libamserver.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/common-src/libamanda.la
+
+
+# PACKAGE: Amanda::Tapefile
+@WANT_SERVER_TRUE@libTapefiledir = $(amperldir)/auto/Amanda/Tapefile
+@WANT_SERVER_TRUE@libTapefile_LTLIBRARIES = libTapefile.la
+@WANT_SERVER_TRUE@libTapefile_la_SOURCES = Amanda/Tapefile.c $(AMGLUE_SWG)
+@WANT_SERVER_TRUE@libTapefile_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+@WANT_SERVER_TRUE@libTapefile_la_LIBADD = libamglue.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/server-src/libamserver.la \
+@WANT_SERVER_TRUE@     $(top_builddir)/common-src/libamanda.la
+
+
+# PACKAGE: Amanda::Debug
+libDebugdir = $(amperldir)/auto/Amanda/Debug
+libDebug_LTLIBRARIES = libDebug.la
+libDebug_la_SOURCES = Amanda/Debug.c $(AMGLUE_SWG)
+libDebug_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libDebug_la_LIBADD = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+
+
+# PACKAGE: Amanda::Config
+libConfigdir = $(amperldir)/auto/Amanda/Config
+libConfig_LTLIBRARIES = libConfig.la
+libConfig_la_SOURCES = Amanda/Config.c $(AMGLUE_SWG)
+libConfig_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libConfig_la_LIBADD = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+
+
+# PACKAGE: Amanda::Util
+libUtildir = $(amperldir)/auto/Amanda/Util
+libUtil_LTLIBRARIES = libUtil.la
+libUtil_la_SOURCES = Amanda/Util.c $(AMGLUE_SWG)
+libUtil_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libUtil_la_LIBADD = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+
+
+# PACKAGE: Amanda::Types
+libTypesdir = $(amperldir)/auto/Amanda/Types
+libTypes_LTLIBRARIES = libTypes.la
+libTypes_la_SOURCES = Amanda/Types.c $(AMGLUE_SWG)
+libTypes_la_LDFLAGS = $(PERL_EXT_LDFLAGS)
+libTypes_la_LIBADD = libamglue.la \
+       $(top_builddir)/common-src/libamanda.la
+
+
+# perl doesn't use the cyg prefix and it doesn't search in the bin
+# directory, dll must be copied to their modules directories.
+@WANT_CYGWIN_COPY_PERL_DLL_TRUE@amperldirauto = "$(DESTDIR)$(amperldir)/auto/Amanda"
+all: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/config/automake/vars.am $(top_srcdir)/config/automake/scripts.am $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  perl/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --gnu  perl/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-amlibLTLIBRARIES: $(amlib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(amlibdir)" || $(MKDIR_P) "$(DESTDIR)$(amlibdir)"
+       @list='$(amlib_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(amlibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(amlibdir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(amlibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(amlibdir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-amlibLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(amlib_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(amlibdir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(amlibdir)/$$p"; \
+       done
+
+clean-amlibLTLIBRARIES:
+       -test -z "$(amlib_LTLIBRARIES)" || rm -f $(amlib_LTLIBRARIES)
+       @list='$(amlib_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-libCmdlineLTLIBRARIES: $(libCmdline_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libCmdlinedir)" || $(MKDIR_P) "$(DESTDIR)$(libCmdlinedir)"
+       @list='$(libCmdline_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(libCmdlineLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libCmdlinedir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(libCmdlineLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libCmdlinedir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-libCmdlineLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libCmdline_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libCmdlinedir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libCmdlinedir)/$$p"; \
+       done
+
+clean-libCmdlineLTLIBRARIES:
+       -test -z "$(libCmdline_LTLIBRARIES)" || rm -f $(libCmdline_LTLIBRARIES)
+       @list='$(libCmdline_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-libConfigLTLIBRARIES: $(libConfig_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libConfigdir)" || $(MKDIR_P) "$(DESTDIR)$(libConfigdir)"
+       @list='$(libConfig_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(libConfigLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libConfigdir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(libConfigLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libConfigdir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-libConfigLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libConfig_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libConfigdir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libConfigdir)/$$p"; \
+       done
+
+clean-libConfigLTLIBRARIES:
+       -test -z "$(libConfig_LTLIBRARIES)" || rm -f $(libConfig_LTLIBRARIES)
+       @list='$(libConfig_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-libDebugLTLIBRARIES: $(libDebug_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libDebugdir)" || $(MKDIR_P) "$(DESTDIR)$(libDebugdir)"
+       @list='$(libDebug_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(libDebugLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libDebugdir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(libDebugLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libDebugdir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-libDebugLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libDebug_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libDebugdir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libDebugdir)/$$p"; \
+       done
+
+clean-libDebugLTLIBRARIES:
+       -test -z "$(libDebug_LTLIBRARIES)" || rm -f $(libDebug_LTLIBRARIES)
+       @list='$(libDebug_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-libDeviceLTLIBRARIES: $(libDevice_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libDevicedir)" || $(MKDIR_P) "$(DESTDIR)$(libDevicedir)"
+       @list='$(libDevice_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(libDeviceLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libDevicedir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(libDeviceLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libDevicedir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-libDeviceLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libDevice_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libDevicedir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libDevicedir)/$$p"; \
+       done
+
+clean-libDeviceLTLIBRARIES:
+       -test -z "$(libDevice_LTLIBRARIES)" || rm -f $(libDevice_LTLIBRARIES)
+       @list='$(libDevice_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-libLogfileLTLIBRARIES: $(libLogfile_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libLogfiledir)" || $(MKDIR_P) "$(DESTDIR)$(libLogfiledir)"
+       @list='$(libLogfile_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(libLogfileLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libLogfiledir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(libLogfileLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libLogfiledir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-libLogfileLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libLogfile_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libLogfiledir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libLogfiledir)/$$p"; \
+       done
+
+clean-libLogfileLTLIBRARIES:
+       -test -z "$(libLogfile_LTLIBRARIES)" || rm -f $(libLogfile_LTLIBRARIES)
+       @list='$(libLogfile_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-libTapefileLTLIBRARIES: $(libTapefile_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libTapefiledir)" || $(MKDIR_P) "$(DESTDIR)$(libTapefiledir)"
+       @list='$(libTapefile_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(libTapefileLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libTapefiledir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(libTapefileLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libTapefiledir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-libTapefileLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libTapefile_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libTapefiledir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libTapefiledir)/$$p"; \
+       done
+
+clean-libTapefileLTLIBRARIES:
+       -test -z "$(libTapefile_LTLIBRARIES)" || rm -f $(libTapefile_LTLIBRARIES)
+       @list='$(libTapefile_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-libTypesLTLIBRARIES: $(libTypes_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libTypesdir)" || $(MKDIR_P) "$(DESTDIR)$(libTypesdir)"
+       @list='$(libTypes_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(libTypesLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libTypesdir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(libTypesLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libTypesdir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-libTypesLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libTypes_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libTypesdir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libTypesdir)/$$p"; \
+       done
+
+clean-libTypesLTLIBRARIES:
+       -test -z "$(libTypes_LTLIBRARIES)" || rm -f $(libTypes_LTLIBRARIES)
+       @list='$(libTypes_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-libUtilLTLIBRARIES: $(libUtil_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       test -z "$(libUtildir)" || $(MKDIR_P) "$(DESTDIR)$(libUtildir)"
+       @list='$(libUtil_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           f=$(am__strip_dir) \
+           echo " $(LIBTOOL) --mode=install $(libUtilLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libUtildir)/$$f'"; \
+           $(LIBTOOL) --mode=install $(libUtilLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libUtildir)/$$f"; \
+         else :; fi; \
+       done
+
+uninstall-libUtilLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(libUtil_LTLIBRARIES)'; for p in $$list; do \
+         p=$(am__strip_dir) \
+         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libUtildir)/$$p'"; \
+         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libUtildir)/$$p"; \
+       done
+
+clean-libUtilLTLIBRARIES:
+       -test -z "$(libUtil_LTLIBRARIES)" || rm -f $(libUtil_LTLIBRARIES)
+       @list='$(libUtil_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+libCmdline.la: $(libCmdline_la_OBJECTS) $(libCmdline_la_DEPENDENCIES) 
+       $(libCmdline_la_LINK) $(am_libCmdline_la_rpath) $(libCmdline_la_OBJECTS) $(libCmdline_la_LIBADD) $(LIBS)
+libConfig.la: $(libConfig_la_OBJECTS) $(libConfig_la_DEPENDENCIES) 
+       $(libConfig_la_LINK) -rpath $(libConfigdir) $(libConfig_la_OBJECTS) $(libConfig_la_LIBADD) $(LIBS)
+libDebug.la: $(libDebug_la_OBJECTS) $(libDebug_la_DEPENDENCIES) 
+       $(libDebug_la_LINK) -rpath $(libDebugdir) $(libDebug_la_OBJECTS) $(libDebug_la_LIBADD) $(LIBS)
+libDevice.la: $(libDevice_la_OBJECTS) $(libDevice_la_DEPENDENCIES) 
+       $(libDevice_la_LINK) $(am_libDevice_la_rpath) $(libDevice_la_OBJECTS) $(libDevice_la_LIBADD) $(LIBS)
+libLogfile.la: $(libLogfile_la_OBJECTS) $(libLogfile_la_DEPENDENCIES) 
+       $(libLogfile_la_LINK) $(am_libLogfile_la_rpath) $(libLogfile_la_OBJECTS) $(libLogfile_la_LIBADD) $(LIBS)
+libTapefile.la: $(libTapefile_la_OBJECTS) $(libTapefile_la_DEPENDENCIES) 
+       $(libTapefile_la_LINK) $(am_libTapefile_la_rpath) $(libTapefile_la_OBJECTS) $(libTapefile_la_LIBADD) $(LIBS)
+libTypes.la: $(libTypes_la_OBJECTS) $(libTypes_la_DEPENDENCIES) 
+       $(libTypes_la_LINK) -rpath $(libTypesdir) $(libTypes_la_OBJECTS) $(libTypes_la_LIBADD) $(LIBS)
+libUtil.la: $(libUtil_la_OBJECTS) $(libUtil_la_DEPENDENCIES) 
+       $(libUtil_la_LINK) -rpath $(libUtildir) $(libUtil_la_OBJECTS) $(libUtil_la_LIBADD) $(LIBS)
+libamglue.la: $(libamglue_la_OBJECTS) $(libamglue_la_DEPENDENCIES) 
+       $(libamglue_la_LINK) -rpath $(amlibdir) $(libamglue_la_OBJECTS) $(libamglue_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Cmdline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Config.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Debug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Device.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Logfile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Tapefile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Types.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bigint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ghashtable.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LTCOMPILE) -c -o $@ $<
+
+Cmdline.lo: Amanda/Cmdline.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT Cmdline.lo -MD -MP -MF $(DEPDIR)/Cmdline.Tpo -c -o Cmdline.lo `test -f 'Amanda/Cmdline.c' || echo '$(srcdir)/'`Amanda/Cmdline.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/Cmdline.Tpo $(DEPDIR)/Cmdline.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='Amanda/Cmdline.c' object='Cmdline.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o Cmdline.lo `test -f 'Amanda/Cmdline.c' || echo '$(srcdir)/'`Amanda/Cmdline.c
+
+Config.lo: Amanda/Config.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT Config.lo -MD -MP -MF $(DEPDIR)/Config.Tpo -c -o Config.lo `test -f 'Amanda/Config.c' || echo '$(srcdir)/'`Amanda/Config.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/Config.Tpo $(DEPDIR)/Config.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='Amanda/Config.c' object='Config.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o Config.lo `test -f 'Amanda/Config.c' || echo '$(srcdir)/'`Amanda/Config.c
+
+Debug.lo: Amanda/Debug.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT Debug.lo -MD -MP -MF $(DEPDIR)/Debug.Tpo -c -o Debug.lo `test -f 'Amanda/Debug.c' || echo '$(srcdir)/'`Amanda/Debug.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/Debug.Tpo $(DEPDIR)/Debug.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='Amanda/Debug.c' object='Debug.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o Debug.lo `test -f 'Amanda/Debug.c' || echo '$(srcdir)/'`Amanda/Debug.c
+
+Device.lo: Amanda/Device.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT Device.lo -MD -MP -MF $(DEPDIR)/Device.Tpo -c -o Device.lo `test -f 'Amanda/Device.c' || echo '$(srcdir)/'`Amanda/Device.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/Device.Tpo $(DEPDIR)/Device.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='Amanda/Device.c' object='Device.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o Device.lo `test -f 'Amanda/Device.c' || echo '$(srcdir)/'`Amanda/Device.c
+
+Logfile.lo: Amanda/Logfile.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT Logfile.lo -MD -MP -MF $(DEPDIR)/Logfile.Tpo -c -o Logfile.lo `test -f 'Amanda/Logfile.c' || echo '$(srcdir)/'`Amanda/Logfile.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/Logfile.Tpo $(DEPDIR)/Logfile.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='Amanda/Logfile.c' object='Logfile.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o Logfile.lo `test -f 'Amanda/Logfile.c' || echo '$(srcdir)/'`Amanda/Logfile.c
+
+Tapefile.lo: Amanda/Tapefile.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT Tapefile.lo -MD -MP -MF $(DEPDIR)/Tapefile.Tpo -c -o Tapefile.lo `test -f 'Amanda/Tapefile.c' || echo '$(srcdir)/'`Amanda/Tapefile.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/Tapefile.Tpo $(DEPDIR)/Tapefile.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='Amanda/Tapefile.c' object='Tapefile.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o Tapefile.lo `test -f 'Amanda/Tapefile.c' || echo '$(srcdir)/'`Amanda/Tapefile.c
+
+Types.lo: Amanda/Types.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT Types.lo -MD -MP -MF $(DEPDIR)/Types.Tpo -c -o Types.lo `test -f 'Amanda/Types.c' || echo '$(srcdir)/'`Amanda/Types.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/Types.Tpo $(DEPDIR)/Types.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='Amanda/Types.c' object='Types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o Types.lo `test -f 'Amanda/Types.c' || echo '$(srcdir)/'`Amanda/Types.c
+
+Util.lo: Amanda/Util.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT Util.lo -MD -MP -MF $(DEPDIR)/Util.Tpo -c -o Util.lo `test -f 'Amanda/Util.c' || echo '$(srcdir)/'`Amanda/Util.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/Util.Tpo $(DEPDIR)/Util.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='Amanda/Util.c' object='Util.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o Util.lo `test -f 'Amanda/Util.c' || echo '$(srcdir)/'`Amanda/Util.c
+
+ghashtable.lo: amglue/ghashtable.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ghashtable.lo -MD -MP -MF $(DEPDIR)/ghashtable.Tpo -c -o ghashtable.lo `test -f 'amglue/ghashtable.c' || echo '$(srcdir)/'`amglue/ghashtable.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/ghashtable.Tpo $(DEPDIR)/ghashtable.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='amglue/ghashtable.c' object='ghashtable.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ghashtable.lo `test -f 'amglue/ghashtable.c' || echo '$(srcdir)/'`amglue/ghashtable.c
+
+bigint.lo: amglue/bigint.c
+@am__fastdepCC_TRUE@   $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bigint.lo -MD -MP -MF $(DEPDIR)/bigint.Tpo -c -o bigint.lo `test -f 'amglue/bigint.c' || echo '$(srcdir)/'`amglue/bigint.c
+@am__fastdepCC_TRUE@   mv -f $(DEPDIR)/bigint.Tpo $(DEPDIR)/bigint.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='amglue/bigint.c' object='bigint.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bigint.lo `test -f 'amglue/bigint.c' || echo '$(srcdir)/'`amglue/bigint.c
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+install-AmandaDATA: $(Amanda_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(Amandadir)" || $(MKDIR_P) "$(DESTDIR)$(Amandadir)"
+       @list='$(Amanda_DATA)'; for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         f=$(am__strip_dir) \
+         echo " $(AmandaDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(Amandadir)/$$f'"; \
+         $(AmandaDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(Amandadir)/$$f"; \
+       done
+
+uninstall-AmandaDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(Amanda_DATA)'; for p in $$list; do \
+         f=$(am__strip_dir) \
+         echo " rm -f '$(DESTDIR)$(Amandadir)/$$f'"; \
+         rm -f "$(DESTDIR)$(Amandadir)/$$f"; \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+           $$tags $$unique; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(CTAGS_ARGS)$$tags$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$tags $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && cd $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+       $(MAKE) $(AM_MAKEFLAGS) \
+         top_distdir="$(top_distdir)" distdir="$(distdir)" \
+         dist-hook
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) check-local
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+       for dir in "$(DESTDIR)$(amlibdir)" "$(DESTDIR)$(libCmdlinedir)" "$(DESTDIR)$(libConfigdir)" "$(DESTDIR)$(libDebugdir)" "$(DESTDIR)$(libDevicedir)" "$(DESTDIR)$(libLogfiledir)" "$(DESTDIR)$(libTapefiledir)" "$(DESTDIR)$(libTypesdir)" "$(DESTDIR)$(libUtildir)" "$(DESTDIR)$(Amandadir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+@WANT_CYGWIN_COPY_PERL_DLL_FALSE@install-data-hook:
+clean: clean-am
+
+clean-am: clean-amlibLTLIBRARIES clean-generic \
+       clean-libCmdlineLTLIBRARIES clean-libConfigLTLIBRARIES \
+       clean-libDebugLTLIBRARIES clean-libDeviceLTLIBRARIES \
+       clean-libLogfileLTLIBRARIES clean-libTapefileLTLIBRARIES \
+       clean-libTypesLTLIBRARIES clean-libUtilLTLIBRARIES \
+       clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-AmandaDATA install-amlibLTLIBRARIES \
+       install-libCmdlineLTLIBRARIES install-libConfigLTLIBRARIES \
+       install-libDebugLTLIBRARIES install-libDeviceLTLIBRARIES \
+       install-libLogfileLTLIBRARIES install-libTapefileLTLIBRARIES \
+       install-libTypesLTLIBRARIES install-libUtilLTLIBRARIES
+       @$(NORMAL_INSTALL)
+       $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-AmandaDATA uninstall-amlibLTLIBRARIES \
+       uninstall-libCmdlineLTLIBRARIES uninstall-libConfigLTLIBRARIES \
+       uninstall-libDebugLTLIBRARIES uninstall-libDeviceLTLIBRARIES \
+       uninstall-libLogfileLTLIBRARIES \
+       uninstall-libTapefileLTLIBRARIES uninstall-libTypesLTLIBRARIES \
+       uninstall-libUtilLTLIBRARIES
+
+.MAKE: install-am install-data-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am check-local clean \
+       clean-amlibLTLIBRARIES clean-generic \
+       clean-libCmdlineLTLIBRARIES clean-libConfigLTLIBRARIES \
+       clean-libDebugLTLIBRARIES clean-libDeviceLTLIBRARIES \
+       clean-libLogfileLTLIBRARIES clean-libTapefileLTLIBRARIES \
+       clean-libTypesLTLIBRARIES clean-libUtilLTLIBRARIES \
+       clean-libtool ctags dist-hook distclean distclean-compile \
+       distclean-generic distclean-libtool distclean-tags distdir dvi \
+       dvi-am html html-am info info-am install install-AmandaDATA \
+       install-am install-amlibLTLIBRARIES install-data \
+       install-data-am install-data-hook install-dvi install-dvi-am \
+       install-exec install-exec-am install-html install-html-am \
+       install-info install-info-am install-libCmdlineLTLIBRARIES \
+       install-libConfigLTLIBRARIES install-libDebugLTLIBRARIES \
+       install-libDeviceLTLIBRARIES install-libLogfileLTLIBRARIES \
+       install-libTapefileLTLIBRARIES install-libTypesLTLIBRARIES \
+       install-libUtilLTLIBRARIES install-man install-pdf \
+       install-pdf-am install-ps install-ps-am install-strip \
+       installcheck installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags uninstall uninstall-AmandaDATA uninstall-am \
+       uninstall-amlibLTLIBRARIES uninstall-libCmdlineLTLIBRARIES \
+       uninstall-libConfigLTLIBRARIES uninstall-libDebugLTLIBRARIES \
+       uninstall-libDeviceLTLIBRARIES uninstall-libLogfileLTLIBRARIES \
+       uninstall-libTapefileLTLIBRARIES uninstall-libTypesLTLIBRARIES \
+       uninstall-libUtilLTLIBRARIES
+
+
+# Perl
+%: %.pl $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+       chmod a+x $@
+
+%.pl: %.pl.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+%.pm: %.pm.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+# Shell
+%: %.sh $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+       chmod a+x $@
+
+%.sh: %.sh.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+# Awk
+%: %.awk $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+       chmod a+x $@
+
+%.awk: %.awk.in $(top_builddir)/config.status
+       $(top_builddir)/config.status --file=$@:$<
+
+# syntax-check perl scripts on 'make check'
+check-perl: $(CHECK_PERL)
+       @CHECK_PERL="$(CHECK_PERL)"; \
+       if test -n "$(PERL)"; then \
+               for perlobj in $$CHECK_PERL; do \
+                       $(PERL) $(CHECK_PERL_FLAGS) -c -w -T $$perlobj || exit 1; \
+               done; \
+       fi
+check-local: check-perl
+check-shell: $(CHECK_SHELL)
+       @CHECK_SHELL="$(CHECK_SHELL)"; \
+       if test -n "$$CHECK_SHELL"; then \
+               if test -n "$(BASH)"; then \
+                       for shobj in $$CHECK_SHELL; do \
+                               if $(BASH) -n $$shobj; then \
+                                       echo "$$shobj syntax OK"; \
+                               else \
+                                       echo "$$shobj syntax error"; \
+                                       exit 1; \
+                               fi; \
+                       done; \
+               else \
+                       echo "No 'bash' available -- cannot syntax-check shell scripts"; \
+               fi; \
+       fi
+check-local: check-shell
+
+# make sure that the sources for all shell and perl scripts get included
+# in the distribution
+dist-scripts:
+       SCRIPTS_PERL="$(SCRIPTS_PERL)"; SCRIPTS_SHELL="$(SCRIPTS_SHELL)"; SCRIPTS_AWK="$(SCRIPTS_AWK)"; \
+       for script in $$SCRIPTS_PERL; do \
+               test -f $(srcdir)/$${script}.pl && { cp -p $(srcdir)/$${script}.pl $(distdir)/ || exit 1; } \
+       done; \
+       for script in $$SCRIPTS_SHELL; do \
+               test -f $(srcdir)/$${script}.sh && { cp -p $(srcdir)/$${script}.sh $(distdir)/ || exit 1; } \
+       done; \
+       for script in $$SCRIPTS_AWK; do \
+               test -f $(srcdir)/$${script}.awk && { cp -p $(srcdir)/$${script}.awk $(distdir)/ || exit 1; } \
+       done; \
+       for script in $$SCRIPTS_SHELL $$SCRIPTS_PERL $$SCRIPTS_AWK; do \
+               test -f $(srcdir)/$${script}.in && { cp -p $(srcdir)/$${script}.in $(distdir)/ || exit 1; } \
+       done; \
+       true
+dist-hook: dist-scripts
+html: make_html amperl.css $(HTML_SOURCE_FILES)
+       rm -rf html-tmp/ && mkdir html-tmp/
+       cp amperl.css html-tmp/
+       $(PERL) make_html html-tmp/ $(HTML_SOURCE_FILES)
+       cd html-tmp/ && tar -zcf $(abs_builddir)/html.tar.gz .
+       rm -rf html-tmp/
+
+# Suffix rules.  These are parallel-build compatible, but may cause
+# strange behavior if there are other .c files in this directory.  The
+# 'rm -f $@' is needed because SWIG sometimes fails to remove its output
+# file in the event of a syntax error.  .i files are pre-processor output;
+# they are only used during development.
+%.c : %.swg $(AMGLUE_SWG)
+       $(mkdir_p) `dirname $@`
+       $(SWIG) $(SWIG_OPTIONS) -o $@ $(top_srcdir)/perl/$< || { rm -f $@; false; }
+%.pm : %.c
+       @echo "$@ was produced as a side-effect of creating $<"
+%.i : %.swg $(AMGLUE_SWG)
+       $(SWIG) $(SWIG_OPTIONS) -E $(top_srcdir)/perl/$< >$@
+@WANT_CYGWIN_COPY_PERL_DLL_TRUE@install-data-hook:
+@WANT_CYGWIN_COPY_PERL_DLL_TRUE@       @for cygdll in $(amperldirauto)/bin/cyg*.dll; do \
+@WANT_CYGWIN_COPY_PERL_DLL_TRUE@           destfname=`echo $$cygdll|sed 's!/bin/cyg\([^.]*\).dll!/\1/\1.dll!'`; \
+@WANT_CYGWIN_COPY_PERL_DLL_TRUE@           cp "$$cygdll" "$$destfname"; \
+@WANT_CYGWIN_COPY_PERL_DLL_TRUE@       done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/perl/amglue/amglue.h b/perl/amglue/amglue.h
new file mode 100644 (file)
index 0000000..b9434cd
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#ifndef AMANDA_AMGLUE_H
+#define AMANDA_AMGLUE_H
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include <glib.h>
+#include <glib-object.h>
+
+/* These defines are missing from older glibs, so we add them here */
+#ifndef G_MAXINT8
+#define G_MAXINT8 (127)
+#endif
+
+#ifndef G_MININT8
+#define G_MININT8 (-127-1)
+#endif
+
+#ifndef G_MAXUINT8
+#define G_MAXUINT8 (255)
+#endif
+
+#ifndef G_MAXINT16
+#define G_MAXINT16 (32767)
+#endif
+
+#ifndef G_MININT16
+#define G_MININT16 (-32767-1)
+#endif
+
+#ifndef G_MAXUINT16
+#define G_MAXUINT16 (65535)
+#endif
+
+#ifndef G_MAXINT32
+#define G_MAXINT32 (2147483647)
+#endif
+
+#ifndef G_MININT32
+#define G_MININT32 (-2147483647-1)
+#endif
+
+#ifndef G_MAXUINT32
+#define G_MAXUINT32 (4294967295U)
+#endif
+
+/*
+ * prototypes for ghashtable.c
+ */
+
+/* Turn a GLib hash table (mapping strings to strings) into a reference
+ * to a Perl hash table.
+ *
+ * @param hash: GLib hash table
+ * @returns: Perl hashref
+ */
+SV *g_hash_table_to_hashref(GHashTable *hash);
+
+/*
+ * prototypes for bigint.c
+ */
+
+/*
+ * These functions handle conversion of integers to and from Perl-compatible
+ * values.  Most perls do not natively support 64-bit integers, so these functions
+ * interface with the Math::BigInt module to support those integers.  The functions
+ * also handle conversions from floating-point to integer values, with silent fraction
+ * truncation, as perl automatically promotes integers to doubles on overflow.
+ */
+
+/* Convert an (unsigned) integer to a Perl SV.  These will always produce a 
+ * Math::BigInt object.  Any failure is fatal.  *All* C-to-Perl integer conversions
+ * must use these functions.
+ *
+ * @param v: value to convert
+ * @returns: pointer to a new SV (refcount=1)
+ */
+SV *amglue_newSVi64(gint64 v);
+SV *amglue_newSVu64(guint64 v);
+
+/* Convert a Perl SV to an integer of the specified size.  These functions should
+ * be used for *all* Perl-to-C integer conversions, since the Perl value may be a
+ * Math::BigInt object.  All of these functions will call croak() on an overflow
+ * condition, rather than silently truncate.
+ *
+ * @param sv: perl value to convert
+ * @returns: value of the given type
+ */
+gint64 amglue_SvI64(SV *sv);
+guint64 amglue_SvU64(SV *sv);
+gint32 amglue_SvI32(SV *sv);
+guint32 amglue_SvU32(SV *sv);
+gint16 amglue_SvI16(SV *sv);
+guint16 amglue_SvU16(SV *sv);
+gint8 amglue_SvI8(SV *sv);
+guint8 amglue_SvU8(SV *sv);
+
+#endif /* AMANDA_AMGLUE_H */
diff --git a/perl/amglue/amglue.swg b/perl/amglue/amglue.swg
new file mode 100644 (file)
index 0000000..9ff37f4
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%{
+#include "amglue.h"
+%}
+
+%include "amglue/constants.swg"
+%include "amglue/exports.swg"
+%include "amglue/glib.swg"
+%include "amglue/integers.swg"
diff --git a/perl/amglue/bigint.c b/perl/amglue/bigint.c
new file mode 100644 (file)
index 0000000..73128e6
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include "amglue.h"
+#include "stdint.h"
+
+/*
+ * C -> Perl
+ */
+
+/* these functions are only needed if Perl has 32-bit IV's */
+/* Make sure Math::BigInt is loaded
+ */
+static void
+load_Math_BigInt(void)
+{
+    static int loaded = 0;
+
+    if (loaded) return;
+
+    eval_pv("use Math::BigInt;", 1);
+    loaded = 1;
+}
+
+/* Given a string, create a Math::BigInt representing its value.
+ *
+ * @param num: string representation of a number
+ * @returns: BigInt representation of the same number
+ */
+static SV *
+str2bigint(char *num)
+{
+    int count;
+    SV *rv;
+    dSP;
+
+    load_Math_BigInt();
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP);
+    XPUSHs(sv_2mortal(newSVpv("Math::BigInt", 0)));
+    XPUSHs(sv_2mortal(newSVpv(num, 0)));
+    PUTBACK;
+
+    count = call_method("Math::BigInt::new", G_SCALAR);
+
+    SPAGAIN;
+
+    if (count != 1)
+       croak("Expected a result from Math::Bigint->new");
+
+    rv = POPs;
+    SvREFCNT_inc(rv);
+
+    PUTBACK;
+    FREETMPS;
+    LEAVE;
+
+    return rv;
+}
+
+SV *
+amglue_newSVi64(gint64 v)
+{
+    char numstr[25];
+    g_snprintf(numstr, sizeof(numstr), "%jd", (intmax_t)v);
+    numstr[sizeof(numstr)-1] = '\0';
+    return str2bigint(numstr);
+}
+
+SV *
+amglue_newSVu64(guint64 v)
+{
+    char numstr[25];
+    g_snprintf(numstr, sizeof(numstr), "%ju", (uintmax_t)v);
+    numstr[sizeof(numstr)-1] = '\0';
+    return str2bigint(numstr);
+}
+
+/*
+ * Perl -> C
+ */
+
+/* Conversion from Perl values handles BigInts regardless of whether
+ * Perl's IVs are 32- or 64-bit, for completeness' sake.
+ */
+
+/* Convert a bigint to a signed integer, or croak trying.
+ *
+ * @param bigint: the perl object to convert
+ * @returns: signed integer
+ */
+static gint64
+bigint2int64(SV *bigint)
+{
+    SV *sv;
+    char *str;
+    guint64 absval;
+    gboolean negative = FALSE;
+    int count;
+    dSP;
+
+    /* first, see if it's a BigInt */
+    if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))
+       croak("Expected an integer or a Math::BigInt; cannot convert");
+
+    ENTER;
+    SAVETMPS;
+
+    /* get the value:
+     * strtoull($bigint->bstr()) */
+
+    PUSHMARK(SP);
+    XPUSHs(bigint);
+    PUTBACK;
+
+    count = call_method("Math::BigInt::bstr", G_SCALAR);
+
+    SPAGAIN;
+
+    if (count != 1)
+       croak("Expected a result from Math::BigInt::bstr");
+
+    sv = POPs;
+    str = SvPV_nolen(sv);
+    if (!str)
+       croak("Math::BigInt::bstr did not return a string");
+
+    if (str[0] == '-') {
+       negative = TRUE;
+       str++;
+    }
+
+    errno = 0;
+    absval = g_ascii_strtoull(str, NULL, 0);
+    /* (the last branch of this || depends on G_MININT64 = -G_MAXINT64-1) */
+    if ((absval == G_MAXUINT64 && errno == ERANGE)
+        || (!negative && absval > (guint64)(G_MAXINT64))
+       || (negative && absval > (guint64)(G_MAXINT64)+1))
+       croak("Expected a signed 64-bit value or smaller; value '%s' out of range", str);
+    if (errno)
+       croak("Math::BigInt->bstr returned invalid number '%s'", str);
+
+    PUTBACK;
+    FREETMPS;
+    LEAVE;
+
+    if (negative) return -absval;
+    return absval;
+}
+
+/* Convert bigint to an unsigned integer, or croak trying.
+ *
+ * @param bigint: the perl object to convert
+ * @returns: unsigned integer
+ */
+static guint64
+bigint2uint64(SV *bigint)
+{
+    SV *sv;
+    char *str;
+    guint64 rv;
+    int count;
+    dSP;
+
+    /* first, see if it's a BigInt */
+    if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))
+       croak("Expected an integer or a Math::BigInt; cannot convert");
+
+    ENTER;
+    SAVETMPS;
+
+    /* make sure the bigint is positive:
+     * croak(..) unless $bigint->sign() eq "+"; */
+
+    PUSHMARK(SP);
+    XPUSHs(bigint);
+    PUTBACK;
+
+    count = call_method("Math::BigInt::sign", G_SCALAR);
+
+    SPAGAIN;
+
+    if (count != 1)
+       croak("Expected a result from Math::BigInt::sign");
+
+    sv = POPs;
+    str = SvPV_nolen(sv);
+    if (!str)
+       croak("Math::BigInt::sign did not return a string");
+
+    if (strcmp(str, "+") != 0)
+       croak("Expected a positive number; value out of range");
+
+    /* get the value:
+     * strtoull($bigint->bstr()) */
+
+    PUSHMARK(SP);
+    XPUSHs(bigint);
+    PUTBACK;
+
+    count = call_method("Math::BigInt::bstr", G_SCALAR);
+
+    SPAGAIN;
+
+    if (count != 1)
+       croak("Expected a result from Math::BigInt::bstr");
+
+    sv = POPs;
+    str = SvPV_nolen(sv);
+    if (!str)
+       croak("Math::BigInt::bstr did not return a string");
+
+    errno = 0;
+    rv = g_ascii_strtoull(str, NULL, 0);
+    if (rv == G_MAXUINT64 && errno == ERANGE)
+       croak("Expected an unsigned 64-bit value or smaller; value '%s' out of range", str);
+    if (errno)
+       croak("Math::BigInt->bstr returned invalid number '%s'", str);
+
+    PUTBACK;
+    FREETMPS;
+    LEAVE;
+
+    return rv;
+}
+
+gint64 amglue_SvI64(SV *sv)
+{
+    if (SvIOK(sv)) {
+       if (SvIsUV(sv)) {
+           return SvUV(sv);
+       } else {
+           return SvIV(sv);
+       }
+    } else if (SvNOK(sv)) {
+       double dv = SvNV(sv);
+
+       /* preprocessor constants seem to have trouble here, so we convert to gint64 and
+        * back, and if the result differs, then we have lost something.  Note that this will
+        * also error out on integer truncation .. which is probably OK */
+       gint64 iv = (gint64)dv;
+       if (dv != (double)iv) {
+           croak("Expected a signed 64-bit value or smaller; value '%.0f' out of range", (float)dv);
+           return 0;
+       } else {
+           return iv;
+       }
+    } else {
+       return bigint2int64(sv);
+    }
+}
+
+guint64 amglue_SvU64(SV *sv)
+{
+    if (SvIOK(sv)) {
+       if (SvIsUV(sv)) {
+           return SvUV(sv);
+       } else if (SvIV(sv) < 0) {
+           croak("Expected an unsigned value, got a negative integer");
+           return 0;
+       } else {
+           return (guint64)SvIV(sv);
+       }
+    } else if (SvNOK(sv)) {
+       double dv = SvNV(sv);
+       if (dv < 0.0) {
+           croak("Expected an unsigned value, got a negative integer");
+           return 0;
+       } else if (dv > (double)G_MAXUINT64) {
+           croak("Expected an unsigned 64-bit value or smaller; value out of range");
+           return 0;
+       } else {
+           return (guint64)dv;
+       }
+    } else {
+       return bigint2uint64(sv);
+    }
+}
+
+gint32 amglue_SvI32(SV *sv)
+{
+    gint64 v64 = amglue_SvI64(sv);
+    if (v64 < G_MININT32 || v64 > G_MAXINT32) {
+       croak("Expected a 32-bit integer; value out of range");
+       return 0;
+    } else {
+       return (gint32)v64;
+    }
+}
+
+guint32 amglue_SvU32(SV *sv)
+{
+    guint64 v64 = amglue_SvU64(sv);
+    if (v64 > G_MAXUINT32) {
+       croak("Expected a 32-bit unsigned integer; value out of range");
+       return 0;
+    } else {
+       return (guint32)v64;
+    }
+}
+
+gint16 amglue_SvI16(SV *sv)
+{
+    gint64 v64 = amglue_SvI64(sv);
+    if (v64 < G_MININT16 || v64 > G_MAXINT16) {
+       croak("Expected a 16-bit integer; value out of range");
+       return 0;
+    } else {
+       return (gint16)v64;
+    }
+}
+
+guint16 amglue_SvU16(SV *sv)
+{
+    guint64 v64 = amglue_SvU64(sv);
+    if (v64 > G_MAXUINT16) {
+       croak("Expected a 16-bit unsigned integer; value out of range");
+       return 0;
+    } else {
+       return (guint16)v64;
+    }
+}
+
+gint8 amglue_SvI8(SV *sv)
+{
+    gint64 v64 = amglue_SvI64(sv);
+    if (v64 < G_MININT8 || v64 > G_MAXINT8) {
+       croak("Expected a 8-bit integer; value out of range");
+       return 0;
+    } else {
+       return (gint8)v64;
+    }
+}
+
+guint8 amglue_SvU8(SV *sv)
+{
+    guint64 v64 = amglue_SvU64(sv);
+    if (v64 > G_MAXUINT8) {
+       croak("Expected a 8-bit unsigned integer; value out of range");
+       return 0;
+    } else {
+       return (guint8)v64;
+    }
+}
+
diff --git a/perl/amglue/constants.swg b/perl/amglue/constants.swg
new file mode 100644 (file)
index 0000000..0fa1985
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/*
+ * This file contains SWIG macros to handle C constants, enums, and flags
+ */
+
+%include "amglue/exports.swg"
+
+/* Rather than try to use glib's flag/enum architecture, which is only used
+ * for a few constants (mostly in property.h), .swg files define constants using
+ * these macros.  A typical definition would look like:
+ *   amglue_add_flag_tag_fns(Permissions);
+ *   amglue_add_constant(PERM_READ, Permissions);
+ *   amglue_add_constant(PERM_WRITE, Permissions);
+ * note that the values of the constants do not appear here, although the header
+ * file in which they are defined must be included in the %{ .. %} block.
+ *
+ * The above would result in:
+ *  - typedef int Permissions;
+ *  - $PERM_READ and $PERM_WRITE in @EXPORT_OK
+ *  - $PERM_READ and $PERM_WRITE in %EXPORT_TAGS{'Permissions'}
+ *  - Permissions_to_strings($flags) -> ( name, name, .. )
+ *
+ * Similarly, amglue_add_enum_tag_fns(FileType) would add the same
+ * EXPORTs, but a function
+ *  - FileType_to_string($enum) -> name
+ */
+
+%define amglue_add_flag_tag_fns(TAG)
+typedef int TAG;
+amglue_export_tag(TAG, TAG ## _to_strings);
+%perlcode %{
+my %_ ## TAG ## _VALUES;
+# Convert a flag value to a list of names for flags that are set.
+sub TAG ## _to_strings {
+    my ($flags) = @_;
+    my @result = ();
+
+    for my $k (keys %_ ## TAG ## _VALUES) {
+       my $v = $_ ## TAG ## _VALUES{$k};
+
+       # is this a matching flag?
+       if (($v == 0 && $flags == 0) || ($v != 0 && ($flags & $v) == $v)) {
+           push @result, $k;
+       }
+    }
+
+    # by default, just return the number as a 1-element list
+    if (!@result) {
+       return ($flags);
+    }
+
+    return @result;
+}
+%}
+%enddef
+
+%define amglue_add_enum_tag_fns(TAG)
+typedef int TAG;
+amglue_export_tag(TAG, TAG ## _to_string);
+%perlcode %{
+my %_ ## TAG ## _VALUES;
+# Convert an enum value to a single string
+sub TAG ## _to_string {
+    my ($enumval) = @_;
+
+    for my $k (keys %_ ## TAG ## _VALUES) {
+       my $v = $_ ## TAG ## _VALUES{$k};
+
+       # is this a matching flag?
+       if ($enumval == $v) {
+           return $k;
+       }
+    }
+
+    # default, just return the number
+    return $enumval;
+}
+%}
+%enddef
+
+/* Add the given constant, assuming the constant name is the 
+ * short name
+ *
+ * @param CONSTNAME: the name of the constant, as used in C code
+ * @param TAG: the tag for this constant (enum name, etc.)
+ */
+%define amglue_add_constant(CONSTNAME, TAG)
+enum { CONSTNAME }; /* pass the constant to SWIG */
+amglue_export_tag(TAG, $CONSTNAME);
+%perlcode %{
+$_ ## TAG ## _VALUES{`CONSTNAME`} = $CONSTNAME;
+%}
+%enddef
+
+/* Add the given constant with a short name
+ *
+ * @param CONSTNAME: the name of the constant, as used in C code
+ * @param SHORTNAME: the name to be shown by TAG_to_string(s) (a string)
+ * @param TAG: the tag for this constant (enum name, etc.)
+ */
+%define amglue_add_constant_short(CONSTNAME, SHORTNAME, TAG)
+enum { CONSTNAME }; /* pass the constant to SWIG */
+amglue_export_tag(TAG, $CONSTNAME);
+%perlcode %{
+$_ ## TAG ## _VALUES{`SHORTNAME`} = $CONSTNAME;
+%}
+%enddef
+
+/* Add the given constant.  No shortname is supplied, so the constant
+ * will not be used for conversion to strings.  Use this function for
+ * bit combinations and other metadata, e.g., FOO_MASK or FOO_MAX
+ *
+ * @param CONSTNAME: the name of the constant, as used in C code
+ * @param TAG: the tag for this constant (enum name, etc.)
+ */
+%define amglue_add_constant_noshort(CONSTNAME, TAG)
+enum { CONSTNAME }; /* pass the constant to SWIG */
+amglue_export_tag(TAG, $CONSTNAME);
+%enddef
diff --git a/perl/amglue/dumpspecs.swg b/perl/amglue/dumpspecs.swg
new file mode 100644 (file)
index 0000000..772a43a
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
+ * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
+ */
+
+%{
+#include "cmdline.h"
+%}
+
+/*
+ * Typemaps for lists of dumpspecs
+ *
+ * To use:
+ *   %include "amglue/dumpspecs.swg"
+ *   %import "Amanda/Logfile.swg"
+ * and declare functions as either taking or returning "amglue_dumpspec_list *".
+ */
+
+%inline %{
+typedef GSList amglue_dumpspec_list;
+%}
+
+/* Typemap to convert a GSList of dumpspec_t's into an array of same. This uses
+ * some SWIG trickery to manage to convert the GSList itself to an array, while
+ * leaving the dumpspecs as C objects.
+ */
+%types(dumpspec_t *);
+%typemap(out) amglue_dumpspec_list * {
+    if ($1) {
+       GSList *iter;
+       EXTEND(SP, g_slist_length($1)); /* make room for return values */
+
+       iter = $1;
+       while (iter) {
+           /* Let SWIG take ownership of the object; we'll free the GSList momentarily */
+           $result = SWIG_NewPointerObj(iter->data, $descriptor(dumpspec_t*), SWIG_OWNER | SWIG_SHADOW);
+           argvi++;
+           iter = iter->next;
+       }
+
+       /* Now free the GSList, but *not* its contents (which are now "owned" by SWIG) */
+       g_slist_free($1);
+    }
+}
+
+/* Typemap to convert an arrayref of dumpspecs into a GSList of same.  This assumes
+ * that the dumpspecs are all C objects.  This borrows references to the underlying
+ * dumpspec objects, which remain owned by SWIG.
+ */
+%typemap(in) amglue_dumpspec_list * {
+    AV *av;
+    int len;
+    int i;
+
+    if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
+       SWIG_exception_fail(SWIG_TypeError, "Expected an arrayref of dumpspecs");
+    }
+    av = (AV *)SvRV($input);
+
+    len = av_len(av)+1;
+    $1 = NULL;
+    for (i = 0; i < len; i++) {
+       dumpspec_t *ds = NULL;
+       SV **elt = av_fetch(av, i, 0);
+       if (elt)
+           SWIG_ConvertPtr(*elt, (void **)&ds, $descriptor(dumpspec_t *), 0);
+       if (!ds)
+           SWIG_exception_fail(SWIG_TypeError, "Expected an arrayref of dumpspecs");
+       $1 = g_slist_append($1, ds);
+    }
+}
+
+%typemap(freearg) amglue_dumpspec_list * {
+    /* Free the GSList, but not its contents (which are still owned by SWIG) */
+    g_slist_free($1);
+}
diff --git a/perl/amglue/exports.swg b/perl/amglue/exports.swg
new file mode 100644 (file)
index 0000000..ea4f5cb
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/*
+ * This file contains SWIG macros to handle exports from perl modules using
+ * the Exporter paackage;
+ */
+
+/* Initialization: SWIG sets up @EXPORT, but to be 'use strict'-compatible,
+ * we declare @EXPORT_OK and %EXPORT_TAGS.
+ */
+%perlcode %{
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+%}
+
+/* Mark SYMBOLS as exported by default (in @EXPORT)
+ *
+ * @param SYMBOLS: whitespace-separated list of symbols (used in qw())
+ */
+%define amglue_export(SYMBOLS)
+%perlcode %{
+push @EXPORT, qw(SYMBOLS);
+%}
+%enddef
+
+/* Mark SYMBOLS as exported on request (in @EXPORT_OK)
+ *
+ * @param SYMBOLS: whitespace-separated list of symbols (used in qw())
+ */
+%define amglue_export_ok(SYMBOLS)
+%perlcode %{
+push @EXPORT_OK, qw(SYMBOLS);
+%}
+%enddef
+
+/* Mark SYMBOLS as exported for tag TAG (in $EXPORT_TAGS{TAG}); also
+ * adds SYMBOLS to EXPORT_OK.
+ *
+ * @param TAG: tag under which to export
+ * @param SYMBOLS: whitespace-separated list of symbols (used in qw())
+ */
+%define amglue_export_tag(TAG, SYMBOLS)
+%perlcode %{
+push @EXPORT_OK, qw(SYMBOLS);
+push @{$EXPORT_TAGS{`TAG`}}, qw(SYMBOLS);
+%}
+%enddef
+
+/* Copy symbols in tag SRCTAG to tag DESTTAG; this is usually used to
+ * include enums or flags into a categorical tag.
+ *
+ * @param SRCTAG: tag to copy from
+ * @param DESTTAG: tag to copy to
+ */
+%define amglue_copy_to_tag(SRCTAG, DESTTAG)
+%perlcode %{
+# copy symbols in SRCTAG to DESTTAG
+push @{$EXPORT_TAGS{`DESTTAG`}},  @{$EXPORT_TAGS{`SRCTAG`}};
+%}
+%enddef
diff --git a/perl/amglue/ghashtable.c b/perl/amglue/ghashtable.c
new file mode 100644 (file)
index 0000000..61a0289
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+#include "amglue.h"
+
+static void 
+foreach_fn(gpointer key_p, gpointer value_p, gpointer user_data_p)
+{
+    char *key = key_p;
+    char *value = value_p;
+    HV *hv = user_data_p;
+    hv_store(hv, key, strlen(key), newSVpv(value, 0), 0);
+}
+
+SV *
+g_hash_table_to_hashref(GHashTable *hash)
+{
+    HV *hv = (HV *)sv_2mortal((SV *)newHV());
+
+    g_hash_table_foreach(hash, foreach_fn, hv);
+
+    return newRV((SV *)hv);
+}
diff --git a/perl/amglue/glib.swg b/perl/amglue/glib.swg
new file mode 100644 (file)
index 0000000..4ed25c1
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+/* Typedefs for a few glib basic types that SWIG doesn't recognize
+ * automatically.  Integers are handled specially; see bigint.{swg,c}
+ */
+
+%{
+#include "amglue.h"
+%}
+
+typedef int gboolean;
+typedef void *gpointer;
+typedef void *gconstpointer;
+
+typedef char gchar;
+typedef unsigned char guchar;
+
+typedef float gfloat;
+typedef double gdouble;
diff --git a/perl/amglue/integers.swg b/perl/amglue/integers.swg
new file mode 100644 (file)
index 0000000..505e7b7
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) Zmanda, Inc.  All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+ *
+ * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
+ * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+ */
+
+%{
+#include "amglue.h"
+%}
+
+/*
+ * perl -> C (input)
+ */
+
+%typemap(in) guint64 {
+    $1 = amglue_SvU64($input);
+}
+
+%typemap(in) gint64 {
+    $1 = amglue_SvI64($input);
+}
+
+%typemap(in) guint32 {
+    $1 = amglue_SvU32($input);
+}
+
+%typemap(in) gint32 {
+    $1 = amglue_SvI32($input);
+}
+
+%typemap(in) guint16 {
+    $1 = amglue_SvU16($input);
+}
+
+%typemap(in) gint16 {
+    $1 = amglue_SvI16($input);
+}
+
+%typemap(in) guint8 {
+    $1 = amglue_SvU8($input);
+}
+
+%typemap(in) gint8 {
+    $1 = amglue_SvI8($input);
+}
+
+/* remaining types depend on the complier to optimize out constant sizeof() 
+ * expressions.  The SWIG preprocessor can't perform calculations based on 
+ * sizeof(). */
+
+%define typemap_in_unsigned(type)
+%typemap(in) type {
+    if (sizeof(type) == 1) {
+       $1 = amglue_SvU8($input);
+    } else if (sizeof(type) == 2) {
+       $1 = amglue_SvU16($input);
+    } else if (sizeof(type) == 4) {
+       $1 = amglue_SvU32($input);
+    } else if (sizeof(type) == 8) {
+       $1 = amglue_SvU64($input);
+    } else {
+       croak("Unexpected type >64 bits?"); /* should be optimized out unless sizeof(type) > 8 */
+    }
+}
+%enddef
+
+typemap_in_unsigned(unsigned int)
+typemap_in_unsigned(guint)
+typemap_in_unsigned(unsigned short)
+typemap_in_unsigned(gushort)
+typemap_in_unsigned(size_t)
+typemap_in_unsigned(gsize)
+typemap_in_unsigned(unsigned long long)
+typemap_in_unsigned(unsigned long)
+typemap_in_unsigned(gulong)
+typemap_in_unsigned(off_t)
+typemap_in_unsigned(ptrdiff_t)
+typemap_in_unsigned(uintmax_t)
+
+%define typemap_in_signed(type)
+%typemap(in) type {
+    if (sizeof(type) == 1) {
+       $1 = amglue_SvI8($input);
+    } else if (sizeof(type) == 2) {
+       $1 = amglue_SvI16($input);
+    } else if (sizeof(type) == 4) {
+       $1 = amglue_SvI32($input);
+    } else if (sizeof(type) == 8) {
+       $1 = amglue_SvI64($input);
+    } else {
+       g_critical("Unexpected type >64 bits?"); /* should be optimized out unless sizeof(type) > 8 */
+    }
+}
+%enddef
+
+typemap_in_signed(int)
+typemap_in_signed(gint)
+typemap_in_signed(signed int)
+typemap_in_signed(short)
+typemap_in_signed(gshort)
+typemap_in_signed(signed short)
+typemap_in_signed(ssize_t)
+typemap_in_signed(gssize)
+typemap_in_signed(long long)
+typemap_in_signed(signed long long)
+typemap_in_signed(long)
+typemap_in_signed(signed long)
+typemap_in_signed(glong)
+typemap_in_signed(intmax_t)
+
+/*
+ * C -> perl (output)
+ */
+
+/* All conversions from C to Perl create Math::BigInt objects, even when the
+ * C datatype is 32 bits or smaller.  This is to ensure that Perl's automatic
+ * promotion to double does not silently corrupt arithmetic on large numbers.
+ */
+
+/* (these all use newSV*64, relying on C to upcast to a 64-bit integer) */
+
+%define typemap_out_unsigned(type)
+%typemap(out) type {
+    $result = sv_2mortal(amglue_newSVu64($1));
+    argvi++;
+}
+%enddef
+
+typemap_out_unsigned(guint64)
+typemap_out_unsigned(guint32)
+typemap_out_unsigned(guint16)
+typemap_out_unsigned(guint8)
+typemap_out_unsigned(unsigned int)
+typemap_out_unsigned(guint)
+typemap_out_unsigned(unsigned short)
+typemap_out_unsigned(gushort)
+typemap_out_unsigned(size_t)
+typemap_out_unsigned(gsize)
+typemap_out_unsigned(unsigned long long)
+typemap_out_unsigned(unsigned long)
+typemap_out_unsigned(gulong)
+typemap_out_unsigned(off_t)
+typemap_out_unsigned(ptrdiff_t)
+typemap_out_unsigned(uintmax_t)
+
+%define typemap_out_signed(type)
+%typemap(out) type {
+    $result = sv_2mortal(amglue_newSVi64($1));
+    argvi++;
+}
+%enddef
+
+typemap_out_signed(gint64)
+typemap_out_signed(gint32)
+typemap_out_signed(gint16)
+typemap_out_signed(gint8)
+typemap_out_signed(int)
+typemap_out_signed(gint)
+typemap_out_signed(signed int)
+typemap_out_signed(short)
+typemap_out_signed(gshort)
+typemap_out_signed(signed short)
+typemap_out_signed(ssize_t)
+typemap_out_signed(gssize)
+typemap_out_signed(long long)
+typemap_out_signed(signed long long)
+typemap_out_signed(long)
+typemap_out_signed(signed long)
+typemap_out_signed(glong)
+typemap_out_signed(intmax_t)
diff --git a/po/Makefile.am b/po/Makefile.am
new file mode 100755 (executable)
index 0000000..d2f4fa8
--- /dev/null
@@ -0,0 +1,152 @@
+# Makefile for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+PACKAGE = amanda
+MAINTAINER_EMAIL = support@zmanda.com
+
+POFILES = $(wildcard *.po)
+#MOFILES = $(patsubst %.po,%.mo,$(POFILES)) 
+MOFILES = 
+
+CFILES = $(wildcard $(top_srcdir)/*/*.[ch])
+PLFILES = $(wildcard $(top_srcdir)/*/*.pl.in)
+SHFILES = $(wildcard $(top_srcdir)/*/*.sh.in)
+ALLFILES = $(CFILES) $(PLFILES) $(SHFILES)
+
+# This variable depends on the location of this directory.
+top_builddir = ..
+localedir=$(datadir)/locale
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=_T
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used.  It is usually empty.
+EXTRA_LOCALE_CATEGORIES =
+
+
+GMSGFMT = gmsgfmt
+MSGFMT = msgfmt
+MSGINIT = msginit
+MSGMERGE = msgmerge
+MSGMERGE_UPDATE = msgmerge --update
+XGETTEXT = xgettext
+
+DISTFILES =                    \
+       ${POFILES}              \
+       ${MOFILES}              \
+       boldquot.sed            \
+       en@boldquot.header      \
+       en@quot.header          \
+       insert-header.sin       \
+       Makefile.am             \
+       Makefile.in             \
+       Makevars                \
+       quot.sed                \
+       remove-potcdate.sin     \
+       Rules-quot              \
+       stamp-po
+
+SUFFIXES = .po .mo .sed .sin
+
+.sin.sed:
+       sed -e '/^#/d' $< > t-$@
+       mv t-$@ $@
+
+all: $(MOFILES)
+
+# This target rebuilds amanda.pot; it is an expensive operation.
+# Note that amanda.pot is not touched if it doesn't need to be changed.
+amanda.pot: $(ALLFILES)
+       @echo $(XGETTEXT) --language=C --output=amanda.pot ... 
+       @$(XGETTEXT) --output=amanda.pot --default-domain=amanda           \
+         --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) --language=C     \
+         $(CFILES)
+       @echo $(XGETTEXT) --language=Perl --join-existing --output=amanda.pot ... 
+       @$(XGETTEXT) --output=amanda.pot --default-domain=amanda           \
+         --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) --language=Perl  \
+         --join-existing $(PLFILES)
+       @echo $(XGETTEXT) --language=Shell --join-existing --output=amanda.pot ... 
+       @$(XGETTEXT) --output=amanda.pot --default-domain=amanda           \
+         --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) --language=Shell \
+         --join-existing $(SHFILES)
+       @test ! -f amanda.po || {                                          \
+         if test -f $(srcdir)/amanda.pot; then                            \
+           sed -f remove-potcdate.sed < $(srcdir)/amanda.pot > amanda.1po && \
+           sed -f remove-potcdate.sed < amanda.po > amanda.2po &&         \
+           if cmp amanda.1po amanda.2po >/dev/null 2>&1; then             \
+             rm -f amanda.1po amanda.2po amanda.po;                       \
+           else                                                           \
+             rm -f amanda.1po amanda.2po $(srcdir)/amanda.pot &&          \
+             mv amanda.po $(srcdir)/amanda.pot;                           \
+           fi;                                                            \
+         else                                                             \
+           mv amanda.po $(srcdir)/amanda.pot;                             \
+         fi;                                                              \
+       }
+
+
+# This target rebuilds a PO file if amanda.pot has changed.
+# Note that a PO file is not touched if it doesn't need to be changed.
+%.po: amanda.pot
+       @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
+       if test "$$lang" = "en_ZM"; then  \
+         echo msgen -o en.po amanda.pot; \
+         msgen -o en.po amanda.pot; \
+       elif test -f "$(srcdir)/$${lang}.po"; then \
+         echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po amanda.pot"; \
+         cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po amanda.pot; \
+       else \
+         echo $(MSGINIT) --locale=$${lang} --input=amanda.pot --output-file=$${lang}.po; \
+         $(MSGINIT) --no-translator --locale=$${lang} --input=amanda.pot --output-file=$${lang}.po; \
+       fi
+
+#en_ZM.po: en.po zlocale.pl ztranslation
+#      @chmod +x ./zlocale.pl
+#      ./zlocale.pl                    
+
+%.mo: %.po
+       @echo "$(MSGFMT) -o $@ $<"; \
+       $(MSGFMT) -o t-$@ $< && mv t-$@ $@
+
+install-data-hook: $(MOFILES)
+       @for cat in "" $(MOFILES); do \
+         if test -z "$$cat" -o "$$cat" = "en.mo"; then \
+           continue; \
+         fi; \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed -e 's/\.mo$$//'`; \
+         dir=$(localedir)/$$lang/LC_MESSAGES; \
+         $(mkdir_p) $(DESTDIR)$$dir; \
+         if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \
+         $(INSTALL) $$realcat $(DESTDIR)$$dir/amanda.mo; \
+         echo "installing $$realcat as $(DESTDIR)$$dir/amanda.mo"; \
+         for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
+           if test -n "$$lc"; then \
+             if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
+               link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
+               mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+               mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
+                for file in *; do \
+                  if test -f $$file; then \
+                    ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
+                  fi; \
+                done); \
+               rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+             else \
+               if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
+                 :; \
+               else \
+                 rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
+                 mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               fi; \
+             fi; \
+             rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo; \
+             ln -s ../LC_MESSAGES/amanda.mo $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo 2>/dev/null || \
+             ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/amanda.mo $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo 2>/dev/null || \
+             cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/amanda.mo $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo; \
+             echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo"; \
+           fi; \
+         done; \
+        done
diff --git a/po/Makefile.in b/po/Makefile.in
new file mode 100644 (file)
index 0000000..8409cec
--- /dev/null
@@ -0,0 +1,864 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for PO directory in any package using GNU gettext.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = po
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps =  \
+       $(top_srcdir)/config/macro-archive/ac_define_dir.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_perl_version.m4 \
+       $(top_srcdir)/config/macro-archive/ac_prog_swig.m4 \
+       $(top_srcdir)/config/macro-archive/ax_compare_version.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-dtd.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt-min.m4 \
+       $(top_srcdir)/config/macro-archive/docbook-xslt.m4 \
+       $(top_srcdir)/config/macro-archive/xsltproc.m4 \
+       $(top_srcdir)/config/amanda/amplot.m4 \
+       $(top_srcdir)/config/amanda/bsd-security.m4 \
+       $(top_srcdir)/config/amanda/bsdtcp-security.m4 \
+       $(top_srcdir)/config/amanda/bsdudp-security.m4 \
+       $(top_srcdir)/config/amanda/changer.m4 \
+       $(top_srcdir)/config/amanda/components.m4 \
+       $(top_srcdir)/config/amanda/compress.m4 \
+       $(top_srcdir)/config/amanda/config.m4 \
+       $(top_srcdir)/config/amanda/debugging.m4 \
+       $(top_srcdir)/config/amanda/defaults.m4 \
+       $(top_srcdir)/config/amanda/devprefix.m4 \
+       $(top_srcdir)/config/amanda/dirs.m4 \
+       $(top_srcdir)/config/amanda/documentation.m4 \
+       $(top_srcdir)/config/amanda/dumpers.m4 \
+       $(top_srcdir)/config/amanda/flags.m4 \
+       $(top_srcdir)/config/amanda/flock.m4 \
+       $(top_srcdir)/config/amanda/funcs.m4 \
+       $(top_srcdir)/config/amanda/getfsent.m4 \
+       $(top_srcdir)/config/amanda/i18n.m4 \
+       $(top_srcdir)/config/amanda/ipv6.m4 \
+       $(top_srcdir)/config/amanda/krb4-security.m4 \
+       $(top_srcdir)/config/amanda/krb5-security.m4 \
+       $(top_srcdir)/config/amanda/lfs.m4 \
+       $(top_srcdir)/config/amanda/libs.m4 \
+       $(top_srcdir)/config/amanda/net.m4 \
+       $(top_srcdir)/config/amanda/progs.m4 \
+       $(top_srcdir)/config/amanda/readdir.m4 \
+       $(top_srcdir)/config/amanda/readline.m4 \
+       $(top_srcdir)/config/amanda/rsh-security.m4 \
+       $(top_srcdir)/config/amanda/s3-device.m4 \
+       $(top_srcdir)/config/amanda/shmem.m4 \
+       $(top_srcdir)/config/amanda/socklen_t_equiv.m4 \
+       $(top_srcdir)/config/amanda/ssh-security.m4 \
+       $(top_srcdir)/config/amanda/summary.m4 \
+       $(top_srcdir)/config/amanda/swig.m4 \
+       $(top_srcdir)/config/amanda/syshacks.m4 \
+       $(top_srcdir)/config/amanda/tape.m4 \
+       $(top_srcdir)/config/amanda/types.m4 \
+       $(top_srcdir)/config/amanda/userid.m4 \
+       $(top_srcdir)/config/amanda/version.m4 \
+       $(top_srcdir)/config/gnulib/alloca.m4 \
+       $(top_srcdir)/config/gnulib/arpa_inet_h.m4 \
+       $(top_srcdir)/config/gnulib/base64.m4 \
+       $(top_srcdir)/config/gnulib/eoverflow.m4 \
+       $(top_srcdir)/config/gnulib/extensions.m4 \
+       $(top_srcdir)/config/gnulib/float_h.m4 \
+       $(top_srcdir)/config/gnulib/fsusage.m4 \
+       $(top_srcdir)/config/gnulib/getaddrinfo.m4 \
+       $(top_srcdir)/config/gnulib/gettimeofday.m4 \
+       $(top_srcdir)/config/gnulib/gnulib-comp.m4 \
+       $(top_srcdir)/config/gnulib/include_next.m4 \
+       $(top_srcdir)/config/gnulib/inet_ntop.m4 \
+       $(top_srcdir)/config/gnulib/intmax_t.m4 \
+       $(top_srcdir)/config/gnulib/lock.m4 \
+       $(top_srcdir)/config/gnulib/longlong.m4 \
+       $(top_srcdir)/config/gnulib/malloc.m4 \
+       $(top_srcdir)/config/gnulib/mkdtemp.m4 \
+       $(top_srcdir)/config/gnulib/netinet_in_h.m4 \
+       $(top_srcdir)/config/gnulib/onceonly_2_57.m4 \
+       $(top_srcdir)/config/gnulib/physmem.m4 \
+       $(top_srcdir)/config/gnulib/safe-read.m4 \
+       $(top_srcdir)/config/gnulib/safe-write.m4 \
+       $(top_srcdir)/config/gnulib/snprintf.m4 \
+       $(top_srcdir)/config/gnulib/socklen.m4 \
+       $(top_srcdir)/config/gnulib/sockpfaf.m4 \
+       $(top_srcdir)/config/gnulib/ssize_t.m4 \
+       $(top_srcdir)/config/gnulib/stdbool.m4 \
+       $(top_srcdir)/config/gnulib/stdint.m4 \
+       $(top_srcdir)/config/gnulib/stdio_h.m4 \
+       $(top_srcdir)/config/gnulib/stdlib_h.m4 \
+       $(top_srcdir)/config/gnulib/strdup.m4 \
+       $(top_srcdir)/config/gnulib/string_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_socket_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_stat_h.m4 \
+       $(top_srcdir)/config/gnulib/sys_time_h.m4 \
+       $(top_srcdir)/config/gnulib/tempname.m4 \
+       $(top_srcdir)/config/gnulib/ulonglong.m4 \
+       $(top_srcdir)/config/gnulib/unistd_h.m4 \
+       $(top_srcdir)/config/gnulib/vasnprintf.m4 \
+       $(top_srcdir)/config/gnulib/visibility.m4 \
+       $(top_srcdir)/config/gnulib/wchar.m4 \
+       $(top_srcdir)/config/gettext-macros/gettext.m4 \
+       $(top_srcdir)/config/gettext-macros/iconv.m4 \
+       $(top_srcdir)/config/gettext-macros/inttypes_h.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-ld.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-link.m4 \
+       $(top_srcdir)/config/gettext-macros/lib-prefix.m4 \
+       $(top_srcdir)/config/gettext-macros/longlong.m4 \
+       $(top_srcdir)/config/gettext-macros/nls.m4 \
+       $(top_srcdir)/config/gettext-macros/po.m4 \
+       $(top_srcdir)/config/gettext-macros/progtest.m4 \
+       $(top_srcdir)/config/gettext-macros/size_max.m4 \
+       $(top_srcdir)/config/gettext-macros/stdint_h.m4 \
+       $(top_srcdir)/config/gettext-macros/wchar_t.m4 \
+       $(top_srcdir)/config/gettext-macros/wint_t.m4 \
+       $(top_srcdir)/config/gettext-macros/xsize.m4 \
+       $(top_srcdir)/config/libtool.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMANDA_DBGDIR = @AMANDA_DBGDIR@
+AMANDA_DEBUG_DAYS = @AMANDA_DEBUG_DAYS@
+AMANDA_STATIC_LDFLAGS = @AMANDA_STATIC_LDFLAGS@
+AMANDA_TMPDIR = @AMANDA_TMPDIR@
+AMANDA_WARNING_CFLAGS = @AMANDA_WARNING_CFLAGS@
+AMLINT = @AMLINT@
+AMLINTFLAGS = @AMLINTFLAGS@
+AMPLOT_CAT_COMPRESS = @AMPLOT_CAT_COMPRESS@
+AMPLOT_CAT_GZIP = @AMPLOT_CAT_GZIP@
+AMPLOT_CAT_PACK = @AMPLOT_CAT_PACK@
+AMPLOT_COMPRESS = @AMPLOT_COMPRESS@
+AMTAR = @AMTAR@
+AR = @AR@
+ARPA_INET_H = @ARPA_INET_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASH = @BASH@
+BINARY_OWNER = @BINARY_OWNER@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+CAT = @CAT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CHIO = @CHIO@
+CHS = @CHS@
+CLIENT_LOGIN = @CLIENT_LOGIN@
+CLIENT_SCRIPTS_OPT = @CLIENT_SCRIPTS_OPT@
+COMPRESS = @COMPRESS@
+CONFIG_DIR = @CONFIG_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURL_CONFIG = @CURL_CONFIG@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DD = @DD@
+DEFAULT_AMANDATES_FILE = @DEFAULT_AMANDATES_FILE@
+DEFAULT_CHANGER_DEVICE = @DEFAULT_CHANGER_DEVICE@
+DEFAULT_CONFIG = @DEFAULT_CONFIG@
+DEFAULT_SERVER = @DEFAULT_SERVER@
+DEFAULT_TAPE_DEVICE = @DEFAULT_TAPE_DEVICE@
+DEFAULT_TAPE_SERVER = @DEFAULT_TAPE_SERVER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOC_BUILD_DATE = @DOC_BUILD_DATE@
+DUMP = @DUMP@
+DUMPER_DIR = @DUMPER_DIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EOVERFLOW = @EOVERFLOW@
+EXAMPLE_TAPEDEV = @EXAMPLE_TAPEDEV@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FLOAT_H = @FLOAT_H@
+GETCONF = @GETCONF@
+GETTEXT = @GETTEXT@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = gmsgfmt
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@
+GNULIB_CHOWN = @GNULIB_CHOWN@
+GNULIB_DUP2 = @GNULIB_DUP2@
+GNULIB_FCHDIR = @GNULIB_FCHDIR@
+GNULIB_FFLUSH = @GNULIB_FFLUSH@
+GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@
+GNULIB_FSEEK = @GNULIB_FSEEK@
+GNULIB_FSEEKO = @GNULIB_FSEEKO@
+GNULIB_FTELL = @GNULIB_FTELL@
+GNULIB_FTELLO = @GNULIB_FTELLO@
+GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@
+GNULIB_GETCWD = @GNULIB_GETCWD@
+GNULIB_GETDELIM = @GNULIB_GETDELIM@
+GNULIB_GETLINE = @GNULIB_GETLINE@
+GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@
+GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@
+GNULIB_LCHOWN = @GNULIB_LCHOWN@
+GNULIB_LSEEK = @GNULIB_LSEEK@
+GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@
+GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@
+GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@
+GNULIB_MBSCHR = @GNULIB_MBSCHR@
+GNULIB_MBSCSPN = @GNULIB_MBSCSPN@
+GNULIB_MBSLEN = @GNULIB_MBSLEN@
+GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@
+GNULIB_MBSNLEN = @GNULIB_MBSNLEN@
+GNULIB_MBSPBRK = @GNULIB_MBSPBRK@
+GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@
+GNULIB_MBSRCHR = @GNULIB_MBSRCHR@
+GNULIB_MBSSEP = @GNULIB_MBSSEP@
+GNULIB_MBSSPN = @GNULIB_MBSSPN@
+GNULIB_MBSSTR = @GNULIB_MBSSTR@
+GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@
+GNULIB_MEMMEM = @GNULIB_MEMMEM@
+GNULIB_MEMPCPY = @GNULIB_MEMPCPY@
+GNULIB_MEMRCHR = @GNULIB_MEMRCHR@
+GNULIB_MKDTEMP = @GNULIB_MKDTEMP@
+GNULIB_MKSTEMP = @GNULIB_MKSTEMP@
+GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@
+GNULIB_READLINK = @GNULIB_READLINK@
+GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@
+GNULIB_SLEEP = @GNULIB_SLEEP@
+GNULIB_SNPRINTF = @GNULIB_SNPRINTF@
+GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@
+GNULIB_STPCPY = @GNULIB_STPCPY@
+GNULIB_STPNCPY = @GNULIB_STPNCPY@
+GNULIB_STRCASESTR = @GNULIB_STRCASESTR@
+GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@
+GNULIB_STRDUP = @GNULIB_STRDUP@
+GNULIB_STRNDUP = @GNULIB_STRNDUP@
+GNULIB_STRNLEN = @GNULIB_STRNLEN@
+GNULIB_STRPBRK = @GNULIB_STRPBRK@
+GNULIB_STRSEP = @GNULIB_STRSEP@
+GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
+GNULIB_VASPRINTF = @GNULIB_VASPRINTF@
+GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@
+GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@
+GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@
+GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@
+GNULIB_WCWIDTH = @GNULIB_WCWIDTH@
+GNUPLOT = @GNUPLOT@
+GNUTAR = @GNUTAR@
+GNUTAR_LISTED_INCREMENTAL_DIR = @GNUTAR_LISTED_INCREMENTAL_DIR@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GZIP = @GZIP@
+HAVE_CALLOC_POSIX = @HAVE_CALLOC_POSIX@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_MKDIR = @HAVE_DECL_MKDIR@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DUP2 = @HAVE_DUP2@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_IO_H = @HAVE_IO_H@
+HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MALLOC_POSIX = @HAVE_MALLOC_POSIX@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_REALLOC_POSIX = @HAVE_REALLOC_POSIX@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRNDUP = @HAVE_STRNDUP@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE__BOOL = @HAVE__BOOL@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPTH = @LIBPTH@
+LIBS = @LIBS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBPTH = @LTLIBPTH@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAILER = @MAILER@
+MAKEINFO = @MAKEINFO@
+MAXTAPEBLOCKSIZE = @MAXTAPEBLOCKSIZE@
+MCUTIL = @MCUTIL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = msgfmt
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = msgmerge
+MT = @MT@
+MTX = @MTX@
+MT_FILE_FLAG = @MT_FILE_FLAG@
+NETINET_IN_H = @NETINET_IN_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+OBJEXT = @OBJEXT@
+
+# Usually the message domain is the same as the package name.
+PACKAGE = amanda
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCAT = @PCAT@
+PERL = @PERL@
+PERLEXTLIBS = @PERLEXTLIBS@
+PERL_INC = @PERL_INC@
+PKG_CONFIG = @PKG_CONFIG@
+POSUB = @POSUB@
+PRINT = @PRINT@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_FCHDIR = @REPLACE_FCHDIR@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+RESTORE = @RESTORE@
+SAMBA_CLIENT = @SAMBA_CLIENT@
+SERVICE_SUFFIX = @SERVICE_SUFFIX@
+SETUID_GROUP = @SETUID_GROUP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+SNAPSHOT_STAMP = @SNAPSHOT_STAMP@
+SORT = @SORT@
+SSH = @SSH@
+STDBOOL_H = @STDBOOL_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SVN = @SVN@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYS_SOCKET_H = @SYS_SOCKET_H@
+SYS_STAT_H = @SYS_STAT_H@
+SYS_TIME_H = @SYS_TIME_H@
+USE_NLS = @USE_NLS@
+USE_VERSION_SUFFIXES = @USE_VERSION_SUFFIXES@
+VDUMP = @VDUMP@
+VERSION = @VERSION@
+VERSION_COMMENT = @VERSION_COMMENT@
+VERSION_MAJOR = @VERSION_MAJOR@
+VERSION_MINOR = @VERSION_MINOR@
+VERSION_PATCH = @VERSION_PATCH@
+VERSION_SUFFIX = @VERSION_SUFFIX@
+VRESTORE = @VRESTORE@
+VXDUMP = @VXDUMP@
+VXRESTORE = @VXRESTORE@
+WCHAR_H = @WCHAR_H@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+XFSDUMP = @XFSDUMP@
+XFSRESTORE = @XFSRESTORE@
+XGETTEXT = xgettext
+XGETTEXT_015 = @XGETTEXT_015@
+XSLREL = @XSLREL@
+XSLTPROC = @XSLTPROC@
+XSLTPROC_FLAGS = @XSLTPROC_FLAGS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+amincludedir = @amincludedir@
+amlibdir = @amlibdir@
+amlibexecdir = @amlibexecdir@
+amperldir = @amperldir@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = $(datadir)/locale
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+
+# This variable depends on the location of this directory.
+top_builddir = ..
+top_srcdir = @top_srcdir@
+MAINTAINER_EMAIL = support@zmanda.com
+POFILES = $(wildcard *.po)
+#MOFILES = $(patsubst %.po,%.mo,$(POFILES)) 
+MOFILES = 
+CFILES = $(wildcard $(top_srcdir)/*/*.[ch])
+PLFILES = $(wildcard $(top_srcdir)/*/*.pl.in)
+SHFILES = $(wildcard $(top_srcdir)/*/*.sh.in)
+ALLFILES = $(CFILES) $(PLFILES) $(SHFILES)
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=_T
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used.  It is usually empty.
+EXTRA_LOCALE_CATEGORIES = 
+MSGINIT = msginit
+MSGMERGE_UPDATE = msgmerge --update
+DISTFILES = \
+       ${POFILES}              \
+       ${MOFILES}              \
+       boldquot.sed            \
+       en@boldquot.header      \
+       en@quot.header          \
+       insert-header.sin       \
+       Makefile.am             \
+       Makefile.in             \
+       Makevars                \
+       quot.sed                \
+       remove-potcdate.sin     \
+       Rules-quot              \
+       stamp-po
+
+SUFFIXES = .po .mo .sed .sin
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .po .mo .sed .sin
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  po/Makefile'; \
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --gnu  po/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+           fi; \
+           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+       @$(NORMAL_INSTALL)
+       $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-data-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+       distclean distclean-generic distclean-libtool distdir dvi \
+       dvi-am html html-am info info-am install install-am \
+       install-data install-data-am install-data-hook install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       uninstall uninstall-am
+
+
+.sin.sed:
+       sed -e '/^#/d' $< > t-$@
+       mv t-$@ $@
+
+all: $(MOFILES)
+
+# This target rebuilds amanda.pot; it is an expensive operation.
+# Note that amanda.pot is not touched if it doesn't need to be changed.
+amanda.pot: $(ALLFILES)
+       @echo $(XGETTEXT) --language=C --output=amanda.pot ... 
+       @$(XGETTEXT) --output=amanda.pot --default-domain=amanda           \
+         --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) --language=C     \
+         $(CFILES)
+       @echo $(XGETTEXT) --language=Perl --join-existing --output=amanda.pot ... 
+       @$(XGETTEXT) --output=amanda.pot --default-domain=amanda           \
+         --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) --language=Perl  \
+         --join-existing $(PLFILES)
+       @echo $(XGETTEXT) --language=Shell --join-existing --output=amanda.pot ... 
+       @$(XGETTEXT) --output=amanda.pot --default-domain=amanda           \
+         --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) --language=Shell \
+         --join-existing $(SHFILES)
+       @test ! -f amanda.po || {                                          \
+         if test -f $(srcdir)/amanda.pot; then                            \
+           sed -f remove-potcdate.sed < $(srcdir)/amanda.pot > amanda.1po && \
+           sed -f remove-potcdate.sed < amanda.po > amanda.2po &&         \
+           if cmp amanda.1po amanda.2po >/dev/null 2>&1; then             \
+             rm -f amanda.1po amanda.2po amanda.po;                       \
+           else                                                           \
+             rm -f amanda.1po amanda.2po $(srcdir)/amanda.pot &&          \
+             mv amanda.po $(srcdir)/amanda.pot;                           \
+           fi;                                                            \
+         else                                                             \
+           mv amanda.po $(srcdir)/amanda.pot;                             \
+         fi;                                                              \
+       }
+
+# This target rebuilds a PO file if amanda.pot has changed.
+# Note that a PO file is not touched if it doesn't need to be changed.
+%.po: amanda.pot
+       @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
+       if test "$$lang" = "en_ZM"; then  \
+         echo msgen -o en.po amanda.pot; \
+         msgen -o en.po amanda.pot; \
+       elif test -f "$(srcdir)/$${lang}.po"; then \
+         echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po amanda.pot"; \
+         cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po amanda.pot; \
+       else \
+         echo $(MSGINIT) --locale=$${lang} --input=amanda.pot --output-file=$${lang}.po; \
+         $(MSGINIT) --no-translator --locale=$${lang} --input=amanda.pot --output-file=$${lang}.po; \
+       fi
+
+#en_ZM.po: en.po zlocale.pl ztranslation
+#      @chmod +x ./zlocale.pl
+#      ./zlocale.pl                    
+
+%.mo: %.po
+       @echo "$(MSGFMT) -o $@ $<"; \
+       $(MSGFMT) -o t-$@ $< && mv t-$@ $@
+
+install-data-hook: $(MOFILES)
+       @for cat in "" $(MOFILES); do \
+         if test -z "$$cat" -o "$$cat" = "en.mo"; then \
+           continue; \
+         fi; \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed -e 's/\.mo$$//'`; \
+         dir=$(localedir)/$$lang/LC_MESSAGES; \
+         $(mkdir_p) $(DESTDIR)$$dir; \
+         if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \
+         $(INSTALL) $$realcat $(DESTDIR)$$dir/amanda.mo; \
+         echo "installing $$realcat as $(DESTDIR)$$dir/amanda.mo"; \
+         for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
+           if test -n "$$lc"; then \
+             if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
+               link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
+               mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+               mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
+                for file in *; do \
+                  if test -f $$file; then \
+                    ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
+                  fi; \
+                done); \
+               rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
+             else \
+               if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
+                 :; \
+               else \
+                 rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
+                 mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
+               fi; \
+             fi; \
+             rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo; \
+             ln -s ../LC_MESSAGES/amanda.mo $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo 2>/dev/null || \
+             ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/amanda.mo $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo 2>/dev/null || \
+             cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/amanda.mo $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo; \
+             echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/amanda.mo"; \
+           fi; \
+         done; \
+        done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/po/Makevars b/po/Makevars
new file mode 100755 (executable)
index 0000000..79ec38d
--- /dev/null
@@ -0,0 +1,41 @@
+# Makefile variables for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+DOMAIN = amanda
+
+# These two variables depend on the location of this directory.
+subdir = po
+top_builddir = ..
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
+
+# This is the copyright holder that gets inserted into the header of the
+# $(DOMAIN).pot file.  Set this to the copyright holder of the surrounding
+# package.  (Note that the msgstr strings, extracted from the package's
+# sources, belong to the copyright holder of the package.)  Translators are
+# expected to transfer the copyright for their translations to this person
+# or entity, or to disclaim their copyright.  The empty string stands for
+# the public domain; in this case the translators are expected to disclaim
+# their copyright.
+COPYRIGHT_HOLDER = Zmanda Inc.
+
+# This is the email address or URL to which the translators shall report
+# bugs in the untranslated strings:
+# - Strings which are not entire sentences, see the maintainer guidelines
+#   in the GNU gettext documentation, section 'Preparing Strings'.
+# - Strings which use unclear terms or require additional context to be
+#   understood.
+# - Strings which make invalid assumptions about notation of date, time or
+#   money.
+# - Pluralisation problems.
+# - Incorrect English spelling.
+# - Incorrect formatting.
+# It can be your email address, or a mailing list address where translators
+# can write to without being subscribed, or the URL of a web page through
+# which the translators can contact you.
+MSGID_BUGS_ADDRESS = support@zmanda.com
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used.  It is usually empty.
+EXTRA_LOCALE_CATEGORIES =
diff --git a/po/Rules-quot b/po/Rules-quot
new file mode 100755 (executable)
index 0000000..9c2a995
--- /dev/null
@@ -0,0 +1,47 @@
+# Special Makefile rules for English message catalogs with quotation marks.
+
+DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot
+
+.SUFFIXES: .insert-header .po-update-en
+
+en@quot.po-create:
+       $(MAKE) en@quot.po-update
+en@boldquot.po-create:
+       $(MAKE) en@boldquot.po-update
+
+en@quot.po-update: en@quot.po-update-en
+en@boldquot.po-update: en@boldquot.po-update-en
+
+.insert-header.po-update-en:
+       @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \
+       if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \
+       tmpdir=`pwd`; \
+       echo "$$lang:"; \
+       ll=`echo $$lang | sed -e 's/@.*//'`; \
+       LC_ALL=C; export LC_ALL; \
+       cd $(srcdir); \
+       if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \
+         if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
+           rm -f $$tmpdir/$$lang.new.po; \
+         else \
+           if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
+             :; \
+           else \
+             echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
+             exit 1; \
+           fi; \
+         fi; \
+       else \
+         echo "creation of $$lang.po failed!" 1>&2; \
+         rm -f $$tmpdir/$$lang.new.po; \
+       fi
+
+en@quot.insert-header: insert-header.sin
+       sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header
+
+en@boldquot.insert-header: insert-header.sin
+       sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header
+
+mostlyclean: mostlyclean-quot
+mostlyclean-quot:
+       rm -f *.insert-header
diff --git a/po/boldquot.sed b/po/boldquot.sed
new file mode 100755 (executable)
index 0000000..4b937aa
--- /dev/null
@@ -0,0 +1,10 @@
+s/"\([^"]*\)"/“\1”/g
+s/`\([^`']*\)'/‘\1’/g
+s/ '\([^`']*\)' / ‘\1’ /g
+s/ '\([^`']*\)'$/ ‘\1’/g
+s/^'\([^`']*\)' /‘\1’ /g
+s/“”/""/g
+s/“/“\e[1m/g
+s/”/\e[0m”/g
+s/‘/‘\e[1m/g
+s/’/\e[0m’/g
diff --git a/po/en@boldquot.header b/po/en@boldquot.header
new file mode 100755 (executable)
index 0000000..fedb6a0
--- /dev/null
@@ -0,0 +1,25 @@
+# All this catalog "translates" are quotation characters.
+# The msgids must be ASCII and therefore cannot contain real quotation
+# characters, only substitutes like grave accent (0x60), apostrophe (0x27)
+# and double quote (0x22). These substitutes look strange; see
+# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html
+#
+# This catalog translates grave accent (0x60) and apostrophe (0x27) to
+# left single quotation mark (U+2018) and right single quotation mark (U+2019).
+# It also translates pairs of apostrophe (0x27) to
+# left single quotation mark (U+2018) and right single quotation mark (U+2019)
+# and pairs of quotation mark (0x22) to
+# left double quotation mark (U+201C) and right double quotation mark (U+201D).
+#
+# When output to an UTF-8 terminal, the quotation characters appear perfectly.
+# When output to an ISO-8859-1 terminal, the single quotation marks are
+# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to
+# grave/acute accent (by libiconv), and the double quotation marks are
+# transliterated to 0x22.
+# When output to an ASCII terminal, the single quotation marks are
+# transliterated to apostrophes, and the double quotation marks are
+# transliterated to 0x22.
+#
+# This catalog furthermore displays the text between the quotation marks in
+# bold face, assuming the VT100/XTerm escape sequences.
+#
diff --git a/po/en@quot.header b/po/en@quot.header
new file mode 100755 (executable)
index 0000000..a9647fc
--- /dev/null
@@ -0,0 +1,22 @@
+# All this catalog "translates" are quotation characters.
+# The msgids must be ASCII and therefore cannot contain real quotation
+# characters, only substitutes like grave accent (0x60), apostrophe (0x27)
+# and double quote (0x22). These substitutes look strange; see
+# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html
+#
+# This catalog translates grave accent (0x60) and apostrophe (0x27) to
+# left single quotation mark (U+2018) and right single quotation mark (U+2019).
+# It also translates pairs of apostrophe (0x27) to
+# left single quotation mark (U+2018) and right single quotation mark (U+2019)
+# and pairs of quotation mark (0x22) to
+# left double quotation mark (U+201C) and right double quotation mark (U+201D).
+#
+# When output to an UTF-8 terminal, the quotation characters appear perfectly.
+# When output to an ISO-8859-1 terminal, the single quotation marks are
+# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to
+# grave/acute accent (by libiconv), and the double quotation marks are
+# transliterated to 0x22.
+# When output to an ASCII terminal, the single quotation marks are
+# transliterated to apostrophes, and the double quotation marks are
+# transliterated to 0x22.
+#
diff --git a/po/insert-header.sin b/po/insert-header.sin
new file mode 100755 (executable)
index 0000000..b26de01
--- /dev/null
@@ -0,0 +1,23 @@
+# Sed script that inserts the file called HEADER before the header entry.
+#
+# At each occurrence of a line starting with "msgid ", we execute the following
+# commands. At the first occurrence, insert the file. At the following
+# occurrences, do nothing. The distinction between the first and the following
+# occurrences is achieved by looking at the hold space.
+/^msgid /{
+x
+# Test if the hold space is empty.
+s/m/m/
+ta
+# Yes it was empty. First occurrence. Read the file.
+r HEADER
+# Output the file's contents by reading the next line. But don't lose the
+# current line while doing this.
+g
+N
+bb
+:a
+# The hold space was nonempty. Following occurrences. Do nothing.
+x
+:b
+}
diff --git a/po/quot.sed b/po/quot.sed
new file mode 100755 (executable)
index 0000000..0122c46
--- /dev/null
@@ -0,0 +1,6 @@
+s/"\([^"]*\)"/“\1”/g
+s/`\([^`']*\)'/‘\1’/g
+s/ '\([^`']*\)' / ‘\1’ /g
+s/ '\([^`']*\)'$/ ‘\1’/g
+s/^'\([^`']*\)' /‘\1’ /g
+s/“”/""/g
diff --git a/po/remove-potcdate.sin b/po/remove-potcdate.sin
new file mode 100755 (executable)
index 0000000..2436c49
--- /dev/null
@@ -0,0 +1,19 @@
+# Sed script that remove the POT-Creation-Date line in the header entry
+# from a POT file.
+#
+# The distinction between the first and the following occurrences of the
+# pattern is achieved by looking at the hold space.
+/^"POT-Creation-Date: .*"$/{
+x
+# Test if the hold space is empty.
+s/P/P/
+ta
+# Yes it was empty. First occurrence. Remove the line.
+g
+d
+bb
+:a
+# The hold space was nonempty. Following occurrences. Do nothing.
+x
+:b
+}
diff --git a/po/stamp-po b/po/stamp-po
new file mode 100644 (file)
index 0000000..9788f70
--- /dev/null
@@ -0,0 +1 @@
+timestamp
diff --git a/server-src/amaddclient.pl b/server-src/amaddclient.pl
new file mode 100755 (executable)
index 0000000..510b0e6
--- /dev/null
@@ -0,0 +1,497 @@
+#!@PERL@
+#
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+#
+
+
+use Getopt::Long;
+use Time::Local;
+use File::Copy;
+use Socket;   # for gethostbyname
+
+my $confdir="@CONFIG_DIR@";
+my $tmpdir="@AMANDA_DBGDIR@";
+
+my $prefix="@prefix@";
+my $localstatedir="@localstatedir@";
+my $amandahomedir="$localstatedir/lib/amanda";
+
+my $amanda_user="@CLIENT_LOGIN@";
+my $amanda_group="disk";
+my $def_root_user="root";
+my $def_dumptype="user-tar";
+
+my $sp_diskfile=0;
+
+# Get the version suffix.
+my $USE_VERSION_SUFFIXES = '@USE_VERSION_SUFFIXES@';
+my $suf = '';
+if ( $USE_VERSION_SUFFIXES =~ /^yes$/i ) {
+        $suf='-@VERSION@';
+}
+
+
+sub usage {
+        print "$0 $suf\n";      
+        print "\t\t--config <config>         Required. Ex: DailySet1\n";       
+       print "\t\t--client <FQDN-name>      Required. Ex: server.zmanda.com\n";
+        print "\t\t--diskdev <directory>     Required. Ex: /home\n";
+       print "\t\t--m                       Modify exisiting entry\n";
+       print "\t\t[--dumptype <dumptype>    Default: user-tar]\n";
+        print "\t\t[--includefile <string>   glob expression of file(s) to include]\n";
+       print "\t\t[--includelist <file>     file contains glob expressions to include]\n";
+       print "\t\t[ specify either --includefile or --includelist ]\n";
+       print "\t\t[--excludefile <string>   glob expression of file(s) to exclude]\n";
+       print "\t\t[--excludelist <file>     file contains glob expressions to exclude]\n";
+       print "\t\t[ specify either --excludefile or --excludelist ]\n";
+       print "\t\t[--user <username>          name of user running amrecover on the client]\n";
+       print "\t\t[--auth <string>            authentication used when running amrecover]\n";
+       print "\t\t[--gnutar_list_dir <string> directory where gnutar keep its state file on the client]\n";
+       print "\t\t[--amandates <string>       file where amanda keep the date of dumplevel on the client]\n";
+       print "\t\t[--batch                    batch mode used when copying file to client]\n";
+       print "\t\t[--no-client-update         do not update files on the client";
+        print "\t\t[--help]\n";
+}
+
+sub mprint {
+    for $fh ( STDOUT, LOG ) {
+       print $fh @_;
+    }
+}
+
+sub log_and_die {
+    print LOG @_;
+    die @_;
+}
+
+sub is_user_right {
+    my $user = `whoami`;
+    chomp($user);
+    ( $user eq $amanda_user ) ||
+       die ("ERROR: $0 must be run by $amanda_user\n");
+}
+
+
+# alphabetics, numerics, and underscores, 
+# hyphen, at sign, dot and "/" are ok
+sub is_tainted { 
+ local($arg) = @_;
+ if ( $arg  =~ /^([-\@\/\w.]+)$/ ) {
+        return 0; # ok
+    } else {
+        return 1; # bad, tainted input
+    }
+}
+
+
+# modify existing entry. 
+# only got here if -m is used and entry is found.
+sub dle_mod {
+    my $open_seen=0;     # '{' is seen
+    my $include_done=0;  # original include line is parsed
+    my $exclude_done=0;  # original exclude line is parsed
+    my $ok=0;            # 1 if target entry is found
+
+    @ARGV = ("$confdir/$config/disklist");
+    $^I = ".tmp"; # allow inplace editing
+    while (<>) {
+       my ($one, $two, $three ) = split(/\s+/, $_);
+
+       # if include or exclude is not previously there, 
+       # take care of them here
+       if ( $one eq "}" ) {
+           $open_seen=0;
+               if ( $include_done==0 && $ok ) {
+                  print "include list \"$includelist\"\n" if ( $includelist );
+                  print "include file \"$includefile\"\n" if ( $includefile );
+                   }
+               if ( $exclude_done==0 && $ok ) {
+                  print "exclude list \"$excludelist\"\n" if ( $excludelist );
+                  print "exclude file \"$excludefile\"\n" if ( $excludefile );
+                   }
+           $ok=0; # reset, done with one entry
+       }   
+       
+       # take care of entry that has '{'
+       if ( $open_seen==1 ) {
+           if ( !$two  && !$three ) {   # inside {, dumptype line has 1 field only
+               s/$one/$dumptype/ if ( $dumptype );
+           } elsif ( $two && $three ) { # inside {, include/exclude line
+               if ( $one eq "include" ) {
+                   if ( $includelist ) {
+                       s/$two.*$/list "$includelist"/;
+                   } elsif ( $includefile ) {
+                       s/$two.*$/file "$includefile"/;
+                   }
+                   $include_done=1;
+               }
+               if ( $one eq "exclude" ) {
+                   if ( $excludelist ) {
+                       s/$two.*$/list "$excludelist"/;
+                   } elsif ( $excludefile ) {
+                       s/$two.*$/file "$excludefile"/;
+                   }
+                   $exclude_done=1;
+               }
+
+           }
+       }  # inside '{'
+       
+       # entry which previously doesn't have include/exclude
+       if (( $one eq $client ) && ($two eq $diskdev) ) {
+           $ok=1;
+           if ( $three && ($three ne "{") ) {
+               if ( $sp_diskfile==1 ) {  #previously don't have include/exclude
+                   $three = $dumptype if ( $dumptype );
+                   $includeline="include list \"$includelist\""   if ( $includelist );
+                   $includeline="include file \"$includefile\""   if ( $includefile );
+                   $excludeline="exclude list \"$excludelist\"\n" if ( $excludelist );
+                   $excludeline="exclude file \"$excludefile\"\n" if ( $excludefile );
+                   s/$three/{\n$three\n$includeline\n$excludeline}/;
+               } else {
+                   s/$three/$dumptype/ if ( $dumptype ); #easy one, just replace dumptype.
+                   $ok=0; #done with one entry
+               }
+           } else {
+               $open_seen=1;
+           }
+       }
+       print;
+    }  # while loop
+    unlink("$confdir/$config/disklist.tmp");
+    exit 0;
+}
+    
+
+
+#main
+my $ret=0;
+          
+$ret= GetOptions (      "config=s"=>\$config,
+                        "client=s"=>\$client,
+                        "diskdev=s"=>\$diskdev,
+                        "dumptype=s"=>\$dumptype,
+                        "includefile=s"=>\$includefile,
+                        "includelist=s"=>\$includelist,
+                        "excludefile=s"=>\$excludefile,
+                        "excludelist=s"=>\$excludelist,
+                       "user=s"=>\$root_user,
+                       "auth=s"=>\$auth,
+                       "gnutar_list_dir=s"=>\$tarlist,
+                       "amandates=s"=>\$amandates,
+                       "batch!"=>\$batch,
+                       "m!"=>\$mod,
+                       "no-client-update!"=>\$no_client_update,
+                        "help!"=>\$help
+                       );
+
+
+unless ( $ret ) {
+    &usage;
+    exit 1;
+}
+
+
+if($help) {
+    &usage;
+    exit 0;
+}
+
+unless (defined $config && defined $client && defined $diskdev ) {
+    print STDERR "--config, --client and --diskdev are required.\n";
+    &usage;
+    exit 1;
+}
+else {
+    die ("ERROR: Invalid data in config.\n")  if is_tainted($config);
+    die ("ERROR: Invalid data in client.\n")  if is_tainted($client);
+}
+
+
+if ( defined $includefile && defined $includelist ) {
+    print STDERR "Specify either --includefile or --includelist, not both.\n";
+    &usage;
+    exit 1;
+}
+   
+if ( defined $excludefile && defined $excludelist ) {
+    print STDERR "Specify either --excludefile or --excludelist, not both.\n";
+    &usage;
+    exit 1;
+}   
+
+$oldPATH = $ENV{'PATH'};
+$ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin:/usr/ucb"; # force known path
+$date=`date +%Y%m%d%H%M%S`;
+chomp($date);
+my $logfile="$tmpdir/amaddclient.$date.debug";
+
+&is_user_right;
+open (LOG, ">$logfile") || die "ERROR: Cannot create logfile : $!\n";
+print STDOUT "Logging to $logfile\n";
+
+my $lhost=`hostname`;
+chomp($lhost);
+# get our own canonical name, if possible (we don't sweat the IPv6 stuff here)
+my $host=(gethostbyname($lhost))[0];
+
+unless ( $host ) {
+    $host = $lhost;  #gethostbyname() failed, go with hostname output
+}
+
+
+my $found=0;
+my $fhs;
+
+# make sure dumptype is defined in dumptypes or amanda.conf file
+
+if ( defined $dumptype ) { 
+for $fhs ( "$confdir/template.d/dumptypes", "$confdir/$config/amanda.conf" ) {
+    open (DTYPE, $fhs) ||
+       &log_and_die ("ERROR: Cannot open $fhs file : $!\n");
+    while (<DTYPE>) {
+       if (/^\s*define\s*dumptype\s*$dumptype\s*{/) {
+           $found=1;
+           last;
+       }
+       }
+       close (DTYPE);
+    }
+
+    unless ( $found ) {
+        &log_and_die ("ERROR: $dumptype not defined in $confdir/template.d/dumptypes or $confdir/$config/amanda.conf\n");
+    }
+}
+
+# create disklist file
+    unless ( -e "$confdir/$config"  ) {
+       &log_and_die ("ERROR: $confdir/$config not found\n");
+    }
+    $found=0;
+    if (defined $includefile || defined $includelist 
+                   || defined $excludefile || defined $excludelist) {
+       $sp_diskfile=1;
+       }
+
+    unless ( -e "$confdir/$config/disklist" ) {         # create it if necessary
+        open (DLE, ">$confdir/$config/disklist") || 
+           &log_and_die ("ERROR: Cannot create $confdir/$config/disklist file : $!\n");
+       print DLE "#This file is generated by amaddclient.\n";
+       print DLE "#Don't edit it manually, otherwise, 'amaddclient -m ...' might not work\n";
+    }
+
+    open (DLE, "+<$confdir/$config/disklist")    # open for read/write
+       || &log_and_die ("ERROR: Cannot open $confdir/$config/disklist file : $!\n");
+    while (<DLE>) {
+       my ($lclient, $ldiskdev, $dontcare ) = split(/\s+/, $_);
+       if (( $lclient eq $client ) && ($ldiskdev eq $diskdev) ) {
+           $found=1;
+           last;
+       }
+    }
+
+# if found and -m, do modification and exit 
+    if ( defined $mod ) {
+       if ( $found ) {
+       &dle_mod;
+    } else {
+       &log_and_die ("ERROR: $client $diskdev not found, cannot modify\n");
+    }
+    }
+
+unless ( defined $dumptype ) {
+    $dumptype=$def_dumptype;
+} 
+    if ( $found==1 ) {
+       &mprint("$confdir/$config/disklist has '$client $diskdev ...' entry, file not updated\n"); }
+    else {
+       print DLE "$client  $diskdev ";
+       print DLE "{\n$dumptype\n" if ($sp_diskfile);
+       if ( defined $includefile ) {
+           print DLE "include file \"$includefile\"\n";
+       }
+       elsif ( defined $includelist ) {
+           print DLE "include list \"$includelist\"\n";
+       }
+       if ( defined $excludefile ) {
+           print DLE "exclude file \"$excludefile\"\n";
+       }
+       elsif ( defined $excludelist ) {
+           print DLE "exclude list \"$excludelist\"\n";
+       }
+        print DLE "}\n" if ($sp_diskfile);
+
+        print DLE "  $dumptype\n" if ($sp_diskfile==0);
+       &mprint ("$confdir/$config/disklist updated\n");
+       close (DLE);
+    }
+
+
+# update .amandahosts on server and client
+    my $scp="scp";
+    my $scp_opt1="-p";   # p: preserve mode
+    my $scp_opt2="-o ConnectTimeout=15";   #timeout after 15 seconds
+    my $ssh="ssh";
+    my $ssh_opt="-x"; # -x as a placeholder, otherwise ssh complains
+    my $mkdir="mkdir";
+    my $client_conf_dir="$confdir/$config";
+    my $amanda_client_conf="$client_conf_dir/amanda-client.conf";
+    my $file="$amandahomedir/.amandahosts";
+    my $client_file="$amandahomedir/amanda-client.conf-$client";
+   
+   if ( defined $batch ) {
+    $scp_opt1="-Bp";
+    $ssh_opt="-o BatchMode=yes";
+  }
+    
+    &mprint ("updating $file on $host\n");
+    unless ( defined $root_user ) {
+    $root_user=$def_root_user;
+  }
+    $found=0;
+    open (HFILE, "+<$file") 
+       || &log_and_die ("ERROR: Cannot open $file : $!\n");
+       
+       while (<HFILE>) {
+           if (/^\s*$client\s*$root_user\s*amindexd\s*amidxtaped\s/) {
+               $found=1;
+               last;
+           }
+       }
+    if ( $found==1 ) {
+       &mprint ("$file contains $client $root_user, file not updated\n") ; }
+    else {
+       print HFILE "$client  $root_user amindexd amidxtaped\n";
+       close (HFILE);
+    }
+
+# update client .amandahosts
+unless ( $no_client_update ) {
+     
+    &mprint ("Attempting to update $file on $client\n");
+
+    chdir ("$amandahomedir");
+    system "$scp", "$scp_opt1", "$scp_opt2", "$amanda_user\@$client:$file", "$file.tmp";
+    $exit_value  = $? >> 8;
+    if ( $exit_value !=0 ) {
+       &mprint ("WARNING: $scp from $client not successful.\n");
+       &mprint ("Check $client:$file file.\n");
+       &mprint ("If entry '$host $amanda_user' is not present,\n");
+       &mprint ("append the entry to the file manually.\n");
+    }
+    else { 
+    $found=0;
+    unless ( -e "$file.tmp" ) {
+       &mprint ("WARNING: $file.tmp not found\n"); }
+    else {
+       open (CFILE, "+<$file.tmp") 
+           || &log_and_die ("ERROR: Cannot open $file.tmp file : $!\n");
+       while (<CFILE>) {
+           if (/^\s*$host\s*$amanda_user\s*amdump\s/) {
+               $found=1;
+               last;
+           }
+       }
+       if ( $found==1 ) {
+           &mprint ("$file contains $host $amanda_user, file not updated\n") ; }
+       else {
+           print CFILE "$host  $amanda_user amdump\n";
+           close (CFILE);
+           
+           #make sure permission mode is correct
+           chmod (0600, "$file.tmp");
+           system "$scp", "$scp_opt1", "$scp_opt2", "$file.tmp", "$client:$file";
+           $exit_value  = $? >> 8;
+           if ( $exit_value !=0 ) {
+               &mprint ("WARNING: $scp to $client not successful.\n");
+               &mprint ("Check $client:$file file.\n");
+               &mprint ("If entry '$host $amanda_user amdump' is not present,\n");
+               &mprint ("append the entry to the file manually.\n");
+           }
+    
+       } 
+    }
+    unlink ("$file.tmp") || &mprint("unlink $file.tmp failed: $!\n");
+    &mprint ("$client:$file updated successfully\n");
+  }
+  }
+
+# done updating client .amandahosts
+
+#create amanda-client.conf and scp over to client
+
+unless ( $no_client_update ) {
+&mprint ("Creating amanda-client.conf for $client\n");
+
+$auth="bsdtcp" unless ( defined $auth ); 
+
+open (ACFILE, ">$client_file") || &log_and_die ("ERROR: Cannot open $client_file file : $!\n");
+ print ACFILE "#amanda-client.conf - Amanda client configuration file.\n";
+ print ACFILE "conf            \"$config\"\n";
+ print ACFILE "index_server    \"$host\"\n";
+ print ACFILE "tape_server     \"$host\"\n";
+ print ACFILE "#  auth  - authentication scheme to use between server and client.\n";
+ print ACFILE "#          Valid values are 'bsdtcp' or 'ssh'\n";
+ print ACFILE "auth            \"$auth\"\n";
+ print ACFILE "# ssh keys file if ssh auth is used\n";
+ print ACFILE "ssh_keys        \"$amandahomedir/.ssh/id_rsa_amrecover\"\n";
+ print ACFILE "gnutar_list_dir \"$tarlist\"\n" if ( defined $tarlist );
+ print ACFILE "amandates       \"$amandates\"\n" if ( defined $amandates ); 
+
+close (ACFILE);
+&mprint ("Creating  $client_conf_dir on $client\n");
+system "$ssh", "$ssh_opt", "$amanda_user\@$client", "$mkdir", "$client_conf_dir";
+$exit_value  = $? >> 8;
+if ( $exit_value !=0 ) {
+  &mprint ("WARNING: Cannot create $client_conf_dir on $client\n");
+  &mprint ("Please copy $client_file to $client manually\n");
+} else { 
+  chmod (0600, "$client_file");
+  system "$scp", "$scp_opt1", "$scp_opt2", "$client_file", "$amanda_user\@$client:$amanda_client_conf";
+  $exit_value  = $? >> 8;
+  if ( $exit_value !=0 ) {
+    &mprint ("WARNING: Cannot copy $client_file to $client\n");
+    &mprint ("Please copy $client_file to $client:$client_conf_dir manually\n");
+  } else {
+    &mprint ("Copy $client_file to $client successfully\n");
+    unlink($client_file);
+  }      
+}
+}
+
+#create gnutar_list_dir
+if ( defined $tarlist && !defined $no_update_client ) {
+ system "$ssh", "$ssh_opt", "$amanda_user\@$client", "$mkdir", "$gnutar_list_dir";
+ $exit_value  = $? >> 8;
+if ( $exit_value !=0 ) {
+  &mprint ("WARNING: Cannot create $gnutar_list_dir on $client\n"); 
+  &mprint ("Please create $gnutar_list_dir on $client manually\n");
+} else { 
+  &mprint ("$client_file created on $client successfully\n");
+}
+}
+
+&mprint ("File /var/lib/amanda/example/xinetd.amandaclient contains the latest Amanda client daemon configuration.\n");
+&mprint ("Please merge it to /etc/xinetd.d/amandaclient.\n");
+$ENV{'PATH'} = $oldPATH;
+close (LOG);
+
+#THE END                                      
+    
diff --git a/server-src/amcheckdb.sh b/server-src/amcheckdb.sh
new file mode 100644 (file)
index 0000000..ec527b7
--- /dev/null
@@ -0,0 +1,92 @@
+#! @SHELL@
+#
+# check tapelist against database and vice versa
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+ConfigDir=@CONFIG_DIR@
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+       SUF="-@VERSION@"
+else
+       SUF=
+fi
+
+Program=`basename $0`
+
+log () {
+       echo 1>&2 "$@"
+       return 0
+}
+
+Config=$1
+if [ "$Config" = "" ]; then
+       log "usage: ${Program} <config>"
+       exit 1
+fi
+shift;
+
+#
+# Check if the configuration directory exists.  Make sure that the
+# necessary files can be found, such as amanda.conf and tapelist.
+#
+if [ ! -d ${ConfigDir}/${Config} ]; then
+       log "${Program}: configuration directory ${ConfigDir}/${Config} does not exist."
+       exit 1
+fi
+(cd ${ConfigDir}/${Config} >/dev/null 2>&1) || exit $?
+cd ${ConfigDir}/${Config}
+if [ ! -r amanda.conf ]; then
+       log "${Program}: amanda.conf not found or is not readable in ${ConfigDir}."
+       exit 1
+fi
+
+# Get the location and name of the tapelist filename.  If tapelist is not
+# specified in the amanda.conf file, then use tapelist in the config
+# directory.
+TapeList=`amgetconf${SUF} $Config tapelist "@$"`
+if [ ! "$TapeList" ]; then
+       TapeList="$ConfigDir/$Config/tapelist"
+fi
+if [ ! -r $TapeList ]; then
+       log "${Program}: $TapeList not found or is not readable."
+       exit 1
+fi
+
+Amadmin=$sbindir/amadmin$SUF
+
+[ ! -f $Amadmin ] \
+       && echo `_ '%s was not found' $Amadmin` >&2 \
+       && exit 1
+[ ! -x $Amadmin ] \
+       && echo `_ '%s is not executable' $Amadmin` >&2 \
+       && exit 1
+
+$Amadmin $Config export "$@"\
+       | grep "^stats: " \
+       | while read LINE; do
+               [ "$LINE" = "" ] && continue
+               set $LINE
+               echo $8
+       done \
+       | sort -u \
+       | while read TAPE; do
+               [ "$TAPE" = "" ] && continue
+               grep " $TAPE " $TapeList 2>/dev/null >/dev/null
+               [ $? != 0 ] \
+                       && echo `_ 'Tape %s missing in %s' "$TAPE" "$TapeList"`
+       done
+
+echo `_ 'Ready.'`
+
+exit 0
diff --git a/server-src/amcheckdump.pl b/server-src/amcheckdump.pl
new file mode 100644 (file)
index 0000000..a7352de
--- /dev/null
@@ -0,0 +1,428 @@
+#! @PERL@
+use lib '@amperldir@';
+use strict;
+
+use File::Basename;
+use Getopt::Long;
+
+use Amanda::Device qw( :constants );
+use Amanda::Debug qw( :logging );
+use Amanda::Config qw( :init :getconf config_dir_relative );
+use Amanda::Logfile;
+use Amanda::Util qw( :running_as_flags );
+use Amanda::Tapefile;
+use Amanda::Changer;
+
+# Have all images been verified successfully so far?
+my $all_success = 1;
+
+sub usage {
+    print <<EOF;
+USAGE: amcheckdump config [ --timestamp|-t timestamp ] [-o configoption]*
+    amcheckdump validates Amanda dump images by reading them from storage
+volume(s), and verifying archive integrity if the proper tool is locally
+available. amcheckdump does not actually compare the data located in the image
+to anything; it just validates that the archive stream is valid.
+    Arguments:
+       config       - The Amanda configuration name to use.
+       -t timestamp - The run of amdump or amflush to check. By default, check
+                       the most recent dump; if this parameter is specified,
+                       check the most recent dump matching the given
+                       date- or timestamp.
+       -o configoption - see the CONFIGURATION OVERRIDE section of amanda(8)
+EOF
+    exit(1);
+}
+
+# Find the most recent logfile name matching the given timestamp
+sub find_logfile_name($) {
+    my $timestamp = shift @_;
+    my $rval;
+    my $config_dir = config_dir_relative(getconf($CNF_LOGDIR));
+    # First try log.$datestamp.$seq
+    for (my $seq = 0;; $seq ++) {
+        my $logfile = sprintf("%s/log.%s.%u", $config_dir, $timestamp, $seq);
+        if (-f $logfile) {
+            $rval = $logfile;
+        } else {
+            last;
+        }
+    }
+    return $rval if defined $rval;
+
+    # Next try log.$datestamp.amflush
+    $rval = sprintf("%s/log.%s.amflush", $config_dir, $timestamp);
+
+    return $rval if -f $rval;
+
+    # Finally try log.datestamp.
+    $rval = sprintf("%s/log.%s.amflush", $config_dir, $timestamp);
+    
+    return $rval if -f $rval;
+
+    # No dice.
+    return undef;
+}
+
+## Device management
+
+my $changer_init_done = 0;
+my $current_device;
+my $current_device_label;
+
+sub find_next_device {
+    my $label = shift;
+    if (getconf_seen($CNF_TPCHANGER)) {
+       # We're using a changer script.
+       if (!$changer_init_done) {
+           my $error = (Amanda::Changer::reset())[0];
+           critical($error) if $error;
+           $changer_init_done = 1;
+       }
+       my ($error, $slot, $tapedev) = Amanda::Changer::find($label);
+       if ($error) {
+           critical("Error operating changer: $error.");
+       } elsif ($slot eq "<none>") {
+           critical("Could not find tape label $label in changer.");
+       } else {
+           return $tapedev;
+       }
+    } else {
+       # The user is changing tapes for us.
+       my $device_name = getconf($CNF_TAPEDEV);
+       printf("Insert volume with label %s in device %s and press ENTER: ",
+              $label, $device_name);
+       <>;
+       return $device_name;
+    }
+}
+
+# Try to open a device containing a volume with the given label.  Returns undef
+# if there is a problem.
+sub try_open_device {
+    my ($label) = @_;
+
+    # can we use the same device as last time?
+    if ($current_device_label eq $label) {
+       return $current_device;
+    }
+
+    # nope -- get rid of that device
+    close_device();
+
+    my $device_name = find_next_device($label);
+    if ( !$device_name ) {
+       print "Could not find a device for label '$label'.\n";
+        return undef;
+    }
+
+    my $device = Amanda::Device->new($device_name);
+    if ( !$device ) {
+       print "Could not open '$device_name'.\n";
+        return undef;
+    }
+
+    $device->set_startup_properties_from_config();
+
+    my $label_status = $device->read_label();
+    if ($label_status != $READ_LABEL_STATUS_SUCCESS) {
+       print "Could not read device $device_name: one of ",
+            join(", ", ReadLabelStatusFlags_to_strings($label_status)),
+            "\n";
+       return undef;
+    }
+
+    if ($device->{volume_label} ne $label) {
+       printf("Labels do not match: Expected '%s', but the device contains '%s'.\n",
+                    $label, $device->{volume_label});
+       return undef;
+    }
+
+    if (!$device->start($ACCESS_READ, undef, undef)) {
+       printf("Error reading device %s.\n", $device_name);
+       return undef;
+    }
+
+    $current_device = $device;
+    $current_device_label = $device->{volume_label};
+
+    return $device;
+}
+
+sub close_device {
+    $current_device = undef;
+    $current_device_label = undef;
+}
+
+## Validation application
+
+my ($current_validation_pid, $current_validation_pipeline, $current_validation_image);
+
+# Return a filehandle for the validation application that will handle this
+# image.  This function takes care of split dumps.  At the moment, we have
+# a single "current" validation application, and as such assume that split dumps
+# are stored contiguously and in order on the volume.
+sub open_validation_app {
+    my ($image, $header) = @_;
+
+    # first, see if this is the same image we were looking at previously
+    if (defined($current_validation_image)
+       and $current_validation_image->{timestamp} eq $image->{timestamp}
+       and $current_validation_image->{hostname} eq $image->{hostname}
+       and $current_validation_image->{diskname} eq $image->{diskname}
+       and $current_validation_image->{level} == $image->{level}) {
+       # TODO: also check that the part number is correct
+        print "Continuing with previously started validation process.\n";
+       return $current_validation_pipeline;
+    }
+
+    # nope, new image.  close the previous pipeline
+    close_validation_app();
+       
+    my $validation_command = find_validation_command($header);
+    print "  using '$validation_command'.\n";
+    $current_validation_pid = open($current_validation_pipeline, "|-", $validation_command);
+        
+    if (!$current_validation_pid) {
+       print "Can't execute validation command: $!\n";
+       undef $current_validation_pid;
+       undef $current_validation_pipeline;
+       return undef;
+    }
+
+    $current_validation_image = $image;
+    return $current_validation_pipeline;
+}
+
+# Close any running validation app, checking its exit status for errors.  Sets
+# $all_success to false if there is an error.
+sub close_validation_app {
+    if (!defined($current_validation_pipeline)) {
+       return;
+    }
+
+    # first close the applications standard input to signal it to stop
+    if (!close($current_validation_pipeline)) {
+       my $exit_value = $? >> 8;
+       print "Validation process returned $exit_value (full status $?)\n";
+       $all_success = 0; # flag this as a failure
+    }
+
+    $current_validation_pid = undef;
+    $current_validation_pipeline = undef;
+    $current_validation_image = undef;
+}
+
+# Given a dumpfile_t, figure out the command line to validate.
+sub find_validation_command {
+    my ($header) = @_;
+
+    # We base the actual archiver on our own table, but just trust
+    # whatever is listed as the decrypt/uncompress commands.
+    my $program = uc(basename($header->{program}));
+    
+    my $validation_program;
+    my %validation_programs = (
+        "DUMP" => "@RESTORE@ tbf 2 -",
+        "VDUMP" => "@VRESTORE@ tf -",
+        "VXDUMP" => "@VXRESTORE@ tbf 2 -",
+        "XFSDUMP" => "@XFSRESTORE@ -t -v silent -",
+        "TAR" => "@GNUTAR@ tf -",
+        "GTAR" => "@GNUTAR@ tf -",
+        "GNUTAR" => "@GNUTAR@ tf -",
+        "SMBCLIENT" => "@SAMBA_CLIENT@ tf -",
+    );
+
+    $validation_program = $validation_programs{$program};
+    if (!defined $validation_program) {
+        warning("Could not determine validation for dumper $program; ".
+             "Will send dumps to /dev/null instead.");
+        $validation_program = "cat > /dev/null";
+    } else {
+        # This is to clean up any extra output the program doesn't read.
+        $validation_program .= " > /dev/null && cat > /dev/null";
+    }
+    
+    my $cmdline = "";
+    if (defined $header->{decrypt_cmd} && 
+        length($header->{decrypt_cmd}) > 0) {
+        $cmdline .= $header->{decrypt_cmd};
+    }
+    if (defined $header->{uncompress_cmd} && 
+        length($header->{uncompress_cmd}) > 0) {
+        $cmdline .= $header->{uncompress_cmd};
+    }
+    $cmdline .= $validation_program;
+
+    return $cmdline;
+}
+
+## Application initialization
+
+Amanda::Util::setup_application("amcheckdump", "server", "cmdline");
+
+my $timestamp = undef;
+my $config_overwrites = new_config_overwrites($#ARGV+1);
+
+Getopt::Long::Configure(qw(bundling));
+GetOptions(
+    'timestamp|t=s' => \$timestamp,
+    'help|usage|?' => \&usage,
+    'o=s' => sub { add_config_overwrite_opt($config_overwrites, $_[1]); },
+) or usage();
+
+usage() if (@ARGV < 1);
+
+my $config_name = shift @ARGV;
+if (!config_init($CONFIG_INIT_EXPLICIT_NAME |
+                 $CONFIG_INIT_FATAL, $config_name)) {
+    critical('errors processing config file "' . 
+               Amanda::Config::get_config_filename() . '"');
+}
+apply_config_overwrites($config_overwrites);
+
+Amanda::Util::finish_setup($RUNNING_AS_DUMPUSER);
+
+# Read the tape list.
+my $tl = Amanda::Tapefile::read_tapelist(config_dir_relative(getconf($CNF_TAPELIST)));
+
+# If we weren't given a timestamp, find the newer of
+# amdump.1 or amflush.1 and extract the datestamp from it.
+if (!defined $timestamp) {
+    my $amdump_log = config_dir_relative(getconf($CNF_LOGDIR)) . "/amdump.1";
+    my $amflush_log = config_dir_relative(getconf($CNF_LOGDIR)) . "/amflush.1";
+    my $logfile;
+    if (-f $amflush_log && -f $amdump_log &&
+         -M $amflush_log  < -M $amdump_log) {
+         $logfile=$amflush_log;
+    } elsif (-f $amdump_log) {
+         $logfile=$amdump_log;
+    } elsif (-f $amflush_log) {
+         $logfile=$amflush_log;
+    } else {
+       print "Could not find any dump log file.\n";
+       exit;
+    }
+
+    # extract the datestamp from the dump log
+    open (AMDUMP, "<$logfile") || critical();
+    while(<AMDUMP>) {
+       if (/^amdump: starttime (\d*)$/) {
+           $timestamp = $1;
+       }
+       elsif (/^amflush: starttime (\d*)$/) {
+           $timestamp = $1;
+       }
+       elsif (/^planner: timestamp (\d*)$/) {
+           $timestamp = $1;
+       }
+    }
+    close AMDUMP;
+}
+
+# Find all logfiles matching our timestamp
+my @logfiles =
+    grep { $_ =~ /^log\.$timestamp(?:\.[0-9]+|\.amflush)?$/ }
+    Amanda::Logfile::find_log();
+
+if (!@logfiles) {
+    critical("Can't find any logfiles with timestamp $timestamp.");
+}
+
+# compile a list of *all* dumps in those logfiles
+my $logfile_dir = config_dir_relative(getconf($CNF_LOGDIR));
+my @images;
+for my $logfile (@logfiles) {
+    push @images, Amanda::Logfile::search_logfile(undef, $timestamp,
+                                                  "$logfile_dir/$logfile", 1);
+}
+
+# filter only "ok" dumps, removing partial and failed dumps
+@images = Amanda::Logfile::dumps_match([@images],
+       undef, undef, undef, undef, 1);
+
+if (!@images) {
+    critical("Could not find any matching dumps");
+}
+
+# Find unique tapelist, using a hash to filter duplicate tapes
+my %tapes = map { ($_->{label}, undef) } @images;
+my @tapes = sort { $a cmp $b } keys %tapes;
+
+if (!@tapes) {
+    critical("Could not find any matching dumps");
+}
+
+printf("You will need the following tape%s: %s\n", (@tapes > 1) ? "s" : "",
+       join(", ", @tapes));
+
+# Now loop over the images, verifying each one.  
+
+IMAGE:
+for my $image (@images) {
+    # Currently, L_PART results will be n/x, n >= 1, x >= -1
+    # In the past (before split dumps), L_PART could be --
+    # Headers can give partnum >= 0, where 0 means not split.
+    my $logfile_part = 1; # assume this is not a split dump
+    if ($image->{partnum} =~ m$(\d+)/(-?\d+)$) {
+        $logfile_part = $1;
+    }
+
+    printf("Validating image %s:%s datestamp %s level %s part %s on tape %s file #%d\n",
+           $image->{hostname}, $image->{diskname}, $image->{timestamp},
+           $image->{level}, $logfile_part, $image->{label}, $image->{filenum});
+
+    # note that if there is a device failure, we may try the same device
+    # again for the next image.  That's OK -- it may give a user with an
+    # intermittent drive some indication of such.
+    my $device = try_open_device($image->{label});
+    if (!defined $device) {
+       # error message already printed
+       $all_success = 0;
+       next IMAGE;
+    }
+
+    # Now get the header from the device
+    my $header = $device->seek_file($image->{filenum});
+    if (!defined $header) {
+        printf("Could not seek to file %d of volume %s.\n",
+                     $image->{filenum}, $image->{label});
+       $all_success = 0;
+        next IMAGE;
+    }
+
+    # Make sure that the on-device header matches what the logfile
+    # told us we'd find.
+
+    my $volume_part = $header->{partnum};
+    if ($volume_part == 0) {
+        $volume_part = 1;
+    }
+
+    if ($image->{timestamp} ne $header->{datestamp} ||
+        $image->{hostname} ne $header->{name} ||
+        $image->{diskname} ne $header->{disk} ||
+        $image->{level} != $header->{dumplevel} ||
+        $logfile_part != $volume_part) {
+        printf("Details of dump at file %d of volume %s do not match logfile.\n",
+                     $image->{filenum}, $image->{label});
+       $all_success = 0;
+        next IMAGE;
+    }
+    
+    # get the validation application pipeline that will process this dump.
+    my $pipeline = open_validation_app($image, $header);
+
+    # send the datastream from the device straight to the application
+    if (!$device->read_to_fd(fileno($pipeline))) {
+        print "Error reading device or writing data to validation command.\n";
+       $all_success = 0;
+       next IMAGE;
+    }
+}
+
+# clean up
+close_validation_app();
+close_device();
+
+exit($all_success? 0 : 1);
diff --git a/server-src/amcleanup.sh b/server-src/amcleanup.sh
new file mode 100644 (file)
index 0000000..166dace
--- /dev/null
@@ -0,0 +1,289 @@
+#!@SHELL@
+#
+# Amanda, The Advanced Maryland Automatic Network Disk Archiver
+# Copyright (c) 1991-1998 University of Maryland at College Park
+# All Rights Reserved.
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of U.M. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  U.M. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Author: James da Silva, Systems Design and Analysis Group
+#                         Computer Science Department
+#                         University of Maryland at College Park
+#
+
+#
+# amcleanup.sh - clean up and generate a report after a crash.
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+confdir=@CONFIG_DIR@
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = yes; then
+        SUF=-@VERSION@
+else
+        SUF=
+fi
+
+#
+#Function to :
+#   parse process tree and get the children of a given process ID
+#
+
+
+find_children() {
+
+#sample ps -ef output
+#500      20810  4938  0 10:21 pts/2    00:00:00 /bin/sh /usr/sbin/amdump tapebackup
+
+       for pid in $(ps -ef | awk "{if ( \$3 == $1 ) { print \$2 }}")
+       do
+               process_name=`ps -e|grep -w ${pid}|awk '{print $4}'`
+               echo `_ '%s: Process %s found running at pid #%s.' "amcleanup" "${process_name}" "${pid}"`
+               pidname[$i]=$pid
+               i=`expr $i + 1`
+               find_children $pid
+       done
+}
+
+#
+#Function to :
+#   send SIGTERM signal to kill given process ID and check if process still alive 
+#   after receiving SIGTERM,  if yes send SIGKILL  
+#
+
+function killpid() {
+
+killPID=$1
+SIGTERM=15
+
+       echo `_ '%s: Sending process %s the %s signal.' "$0" "${killPID}" "SIGTERM"`
+       `kill -${SIGTERM} ${killPID} 2>/dev/null`
+       for second in 0 1 2 3 4 ; do
+               pid_status=`ps -e|grep -w ${killPID}|grep -v grep |wc -l`
+               if [ ${pid_status} -ne 0 ] ; then
+                       # process is still alive
+                       sleep 1
+               else
+                       return 0
+               fi
+       done
+       SIGKILL=9
+       echo `_ '%s: Sending process %s the %s signal.' "$0" "${killPID}" "SIGKILL"`
+       `kill -${SIGKILL} ${killPID} 2>/dev/null`
+       sleep 2
+       pid_status=`ps -e|grep -w ${killPID}|grep -v grep |wc -l`
+       if [ ${pid_status} -ne 0 ] ; then
+               return 1
+       else
+               return 0
+       fi
+}
+
+
+# process arguments
+KILL_ENABLE=0
+VERBOSE=0
+while test $# -ge 2; do
+    case "$1" in
+       -k) KILL_ENABLE=1;;
+       -v) VERBOSE=1;;
+       *)
+           echo `_ 'Usage: amcleanup [-k] [-v] conf'`
+           exit 1 ;;
+    esac
+    shift
+done
+conf="$1"
+shift
+
+if test ! -d $confdir/$conf ; then
+       echo `_ '%s: could not cd into %s' "amcleanup" "$confdir/$conf"`
+       exit 1
+fi
+
+#check if amdump/amflush is running for given config  
+if test ${KILL_ENABLE} -eq 0 ; then
+       for am_process in amdump amflush ; do
+               am_pid=`ps -ef|grep -w ${am_process}|grep -w ${conf}|awk '{print $2}'`
+               if test ! -z "${am_pid}" ; then
+                       echo `_ '%s: %s Process is running at PID %s for %s configuration.' "$0" "${am_process}" ${am_pid} ${conf}`
+                       echo `_ '%s: Use -k option to stop all the process...' "$0"`
+                       echo `_ 'Usage: amcleanup [-k] conf'`
+                       exit 0
+               fi
+       done
+fi
+
+cd $confdir/$conf
+
+logdir=`amgetconf$SUF $conf logdir "$@"`
+rc=$?
+if test $rc -ne 0 ; then
+       echo `_ '%s: "%s" exited with status: %s' "amcleanup" "amgetconf$SUF logdir" "$rc"` 1>&2
+       exit 1
+fi
+logfile=$logdir/log
+errfile=$logdir/amdump
+erramflush=$logdir/amflush
+tapecycle=`amgetconf$SUF $conf tapecycle "$@"`
+rc=$?
+if test $rc -ne 0 ; then
+       echo `_ '%s: "%s" exited with status: %s' "amcleanup" "amgetconf$SUF tapecycle" "$rc"` 1>&2
+       exit 1
+fi
+dumpuser=`amgetconf$SUF $conf dumpuser "$@"`
+rc=$?
+if test $rc -ne 0 ; then
+       echo `_ '%s: "%s" exited with status: %s' "amcleanup" "amgetconf$SUF $conf dumpuser" "$rc"` 1>&2
+       exit 1
+fi
+if test ${KILL_ENABLE} -eq 1 ; then
+
+       #check if any one of the dumps are runing, if yes get the process tree and kill them
+        for am_process in amdump amflush ; do
+                unset pidname
+                am_pid=`ps -ef|grep -w ${am_process}|grep -w ${conf}|awk '{print $2}'`
+                #echo "checking children for ${am_pid}"
+                if test ! -z "${am_pid}" ; then
+                        find_children ${am_pid}
+                fi
+
+                KILL_FAILURES=0
+               i=0
+
+                while test ${#pidname[@]} -gt $i ; do
+
+                        mypid=`ps -e|grep -w ${pidname[$i]}|grep -v grep|wc -l`
+                        if [ ${mypid} -ne 0 ] ; then
+                                killpid ${pidname[$i]}
+                                rc=$?
+                                if test $rc -ne 0 ; then
+                                        KILL_FAILURES=`expr ${KILL_FAILURES} + 1`
+                                fi
+                        else
+                                echo `_ '%s: Process %s no longer running.  Skipping...' "$0" "${pidname[$i]}"`
+                        fi
+                       i=`expr $i + 1`
+                done
+
+        if test ${#pidname[@]} -gt 0 ; then
+                echo `_ '%s: %s Amanda processes were found running.' "$0" "${#pidname[@]}"`
+                echo `_ '%s: %s processes failed to terminate.' "$0" "${KILL_FAILURES}"`
+        fi
+
+        done
+fi
+
+retstatus=0
+if test -f $logfile ; then
+       echo `_ '%s: processing outstanding log file.' "$0"`
+       exec </dev/null >/dev/null 2>&1
+       amreport$SUF $conf "$@"
+       rc=$?
+       if test $rc -ne 0 ; then
+               echo `_ '%s: "%s" exited with status: %s' "$0" "amreport" "$rc"` 1>&2
+               retstatus=`expr $retstatus + 1`
+       fi
+
+       # Roll the log file to its datestamped name.
+       amlogroll$SUF $conf "$@"
+       rc=$?
+       if test $rc -ne 0 ; then
+               echo `_ '%s: "%s" exited with status: %s' "$0" "amlogroll" "$rc"` 1>&2
+               retstatus=`expr $retstatus + 2`
+       fi
+
+       # Trim the index file to those for dumps that still exist.
+       amtrmidx$SUF $conf "$@"
+       rc=$?
+       if test $rc -ne 0 ; then
+               echo `_ '%s: "%s" exited with status: %s' "$0" "amtrmidx" "$rc"` 1>&2
+               retstatus=`expr $retstatus + 4`
+       fi
+
+else
+       echo `_ '%s: no unprocessed logfile to clean up.' "$0"`
+fi
+
+if test -f $errfile ; then
+    # if log was found, this will have been directed to /dev/null,
+    # which is fine.
+    echo `_ '%s: %s exists, renaming it.' "$0" "$errfile"`
+
+    # Keep debug log through the tapecycle plus a couple days
+    maxdays=`expr $tapecycle + 2`
+
+    days=1
+    # First, find out the last existing errfile,
+    # to avoid ``infinite'' loops if tapecycle is infinite
+    while test $days -lt $maxdays  && test -f $errfile.$days ; do
+       days=`expr $days + 1`
+    done
+    # Now, renumber the existing log files
+    while test $days -ge 2 ; do
+       ndays=`expr $days - 1`
+       mv $errfile.$ndays $errfile.$days
+       days=$ndays
+    done
+    mv $errfile $errfile.1
+fi
+
+if test -f $erramflush ; then
+    # if log was found, this will have been directed to /dev/null,
+    # which is fine.
+    echo `_ '%s: %s exists, renaming it.' "$0" "$erramflush"`
+
+    # Keep debug log through the tapecycle plus a couple days
+    maxdays=`expr $tapecycle + 2`
+
+    days=1
+    # First, find out the last existing erramflush,
+    # to avoid ``infinite'' loops if tapecycle is infinite
+    while test $days -lt $maxdays  && test -f $erramflush.$days ; do
+       days=`expr $days + 1`
+    done
+    # Now, renumber the existing log files
+    while test $days -ge 2 ; do
+       ndays=`expr $days - 1`
+       mv $erramflush.$ndays $erramflush.$days
+       days=$ndays
+    done
+    mv $erramflush $erramflush.1
+fi
+
+v=''
+if test $VERBOSE -eq 1; then
+    v='-v'
+fi
+$amlibexecdir/amcleanupdisk $v $conf "$@"
+rc=$?
+if test $rc -ne 0 ; then
+       echo `_ '%s: "%s" exited with status: %s' "$0" "amcleanupdisk" "$rc"` 1>&2
+       retstatus=`expr $retstatus + 8`
+fi
+
+exit $retstatus
diff --git a/server-src/amdevcheck.pl b/server-src/amdevcheck.pl
new file mode 100644 (file)
index 0000000..1e6d8b4
--- /dev/null
@@ -0,0 +1,65 @@
+#! @PERL@
+use lib '@amperldir@';
+use strict;
+use Amanda::Device qw( :constants );
+use Amanda::Config qw( :getconf :init );
+use Amanda::Debug qw( :logging );
+use Amanda::Util qw( :running_as_flags );
+
+# try to open the device and read its label, returning the device_read_label
+# result (one or more of ReadLabelStatusFlags)
+sub try_read_label {
+    my ($device_name) = @_;
+
+    if ( !$device_name ) {
+        return $READ_LABEL_STATUS_DEVICE_MISSING;
+    }
+
+    my $device = Amanda::Device->new($device_name);
+    if ( !$device ) {
+        return $READ_LABEL_STATUS_DEVICE_MISSING
+             | $READ_LABEL_STATUS_DEVICE_ERROR;
+    }
+
+    $device->set_startup_properties_from_config();
+
+    return $device->read_label();
+}
+
+# print the results, one flag per line
+sub print_result {
+    my ($flags) = @_;
+
+    print join( "\n", ReadLabelStatusFlags_to_strings($flags) ), "\n";
+}
+
+sub usage {
+    print <<EOF;
+Usage: amdevcheck <config> [ <device name> ]
+EOF
+    exit(1);
+}
+
+## Application initialization
+
+Amanda::Util::setup_application("amdevcheck", "server", "cmdline");
+
+usage() if ( @ARGV < 1 || @ARGV > 2 );
+my $config_name = $ARGV[0];
+if (!config_init($CONFIG_INIT_EXPLICIT_NAME, $config_name)) {
+    critical('errors processing config file "' .
+              Amanda::Config::get_config_filename() . '"');
+}
+
+Amanda::Util::finish_setup($RUNNING_AS_DUMPUSER);
+
+## Check the device
+
+my $device_name;
+if ( $#ARGV == 1 ) {
+    $device_name = $ARGV[1];
+} else {
+    $device_name = getconf($CNF_TAPEDEV);
+}
+
+print_result( try_read_label($device_name) );
diff --git a/server-src/amdump.sh~HEAD b/server-src/amdump.sh~HEAD
new file mode 100644 (file)
index 0000000..70a0a7f
--- /dev/null
@@ -0,0 +1,225 @@
+#!@SHELL@
+#
+# Amanda, The Advanced Maryland Automatic Network Disk Archiver
+# Copyright (c) 1991-1998 University of Maryland at College Park
+# All Rights Reserved.
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of U.M. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  U.M. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Author: James da Silva, Systems Design and Analysis Group
+#                         Computer Science Department
+#                         University of Maryland at College Park
+#
+
+#
+# amdump: Manage running one night's Amanda dump run.
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+confdir=@CONFIG_DIR@
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+       SUF="-@VERSION@"
+else
+       SUF=
+fi
+
+if [ $# -lt 1 ]
+then
+<<<<<<< HEAD:server-src/amdump.sh.in
+        echo "Usage: amdump config [host [disk...]...]" 1>&2
+=======
+        echo `_ 'Usage: %s config [host [disk...]...]' "$0"`  1>&2
+>>>>>>> upstream:server-src/amdump.sh
+        exit 1
+fi
+
+exit_status=0;
+
+conf=$1
+if [ ! -d $confdir/$conf ]; then
+<<<<<<< HEAD:server-src/amdump.sh.in
+    echo "amdump$SUF: could not find directory $confdir/$conf" 1>&2
+=======
+    echo `_ '%s: could not find directory %s' "amdump$SUF" "$confdir/$conf"` 1>&2
+>>>>>>> upstream:server-src/amdump.sh
+    exit 1
+fi
+shift
+
+cd $confdir/$conf || exit 1
+
+logdir=`amgetconf$SUF $conf logdir "$@"`
+[ $? -ne 0 ]  && exit 1
+errfile=$logdir/amdump
+tapecycle=`amgetconf$SUF $conf tapecycle "$@"`
+[ $? -ne 0 ]  && exit 1
+dumpuser=`amgetconf$SUF $conf dumpuser "$@"`
+[ $? -ne 0 ]  && exit 1
+
+runuser=`{ whoami ; } 2>/dev/null`
+if [ $? -ne 0 ]; then
+       idinfo=`{ id ; } 2>/dev/null`
+       if [ $? -ne 0 ]; then
+               runuser=${LOGNAME:-"??unknown??"}
+       else
+               runuser=`echo $idinfo | sed -e 's/).*//' -e 's/^.*(//'`
+       fi
+fi
+
+<<<<<<< HEAD:server-src/amdump.sh.in
+#if [ $runuser != $dumpuser ]; then
+#      echo "amdump: must be run as user $dumpuser, not $runuser" 1>&2
+#      exit 1
+#fi
+
+if test -f hold; then
+       echo "amdump: waiting for hold file to be removed" 1>&2
+=======
+if [ $runuser != $dumpuser ]; then
+       echo `_ '%s: must be run as user %s, not %s' "$0" "$dumpuser" "$runuser"` 1>&2
+       exit 1
+fi
+
+if test -f hold; then
+       echo `_ '%s: waiting for hold file to be removed' "$0"` 1>&2
+>>>>>>> upstream:server-src/amdump.sh
+       while test -f hold; do
+               sleep 60
+       done
+fi
+
+if test -f $errfile || test -f $logdir/log; then
+<<<<<<< HEAD:server-src/amdump.sh.in
+       echo "amdump: amdump or amflush is already running, or you must run amcleanup" 1>&2
+=======
+       echo `_ '%s: amdump or amflush is already running, or you must run amcleanup' "$0"` 1>&2
+>>>>>>> upstream:server-src/amdump.sh
+       exit 1
+fi
+
+umask 077
+
+exit_code=0
+# Plan and drive the dumps.
+#exec </dev/null >$errfile 2>&1
+touch $errfile
+exit_code=$?
+[ $exit_code -ne 0 ] && exit_status=$exit_code
+exec </dev/null 2>>$errfile 1>&2
+exit_code=$?
+[ $exit_code -ne 0 ] && exit_status=$exit_code
+<<<<<<< HEAD:server-src/amdump.sh.in
+echo "amdump: start at `date`"
+echo "amdump: datestamp `date +%Y%m%d`"
+echo "amdump: starttime `date +%Y%m%d%H%M%S`"
+$libexecdir/planner$SUF $conf "$@" | $libexecdir/driver$SUF $conf "$@"
+exit_code=$?
+[ $exit_code -ne 0 ] && exit_status=$exit_code
+echo "amdump: end at `date`"
+=======
+
+gdate=`date +'%a %b %e %H:%M:%S %Z %YAAAAA%Y%m%dBBBBB%Y%m%d%H%M%SCCCCC%Y-%m-%d %H:%M:%S %Z'`
+
+#date=%a %b %e %H:%M:%S %Z %Y
+date=`echo $gdate |sed -e "s/AAAAA.*$//"`
+
+#date_datestamp="%Y%m%d"
+date_datestamp=`echo $gdate |sed -e "s/^.*AAAAA//;s/BBBBB.*$//"`
+
+#date_starttime="%Y%m%d%H%M%S"
+date_starttime=`echo $gdate |sed -e "s/^.*BBBBB//;s/CCCCC.*$//"`
+
+#date_locale_independent=%Y-%m-%d %H:%M:%S %Z
+date_locale_independent=`echo $gdate |sed -e "s/^.*CCCCC//"`
+
+printf '%s: start at %s\n' "amdump" "$date"
+printf '%s: datestamp %s\n' "amdump" "$date_datestamp"
+printf '%s: starttime %s\n' "amdump" "$date_starttime"
+printf '%s: starttime-locale-independent %s\n' "amdump" "$date_locale_independent"
+
+$amlibexecdir/planner$SUF $conf --starttime $date_starttime "$@" | $amlibexecdir/driver$SUF $conf "$@"
+exit_code=$?
+[ $exit_code -ne 0 ] && exit_status=$exit_code
+printf '%s: end at %s\n' "amdump" "`date`"
+>>>>>>> upstream:server-src/amdump.sh
+
+# Send out a report on the dumps.
+$sbindir/amreport$SUF $conf "$@"
+exit_code=$?
+[ $exit_code -ne 0 ] && exit_status=$exit_code
+
+# Roll the log file to its datestamped name.
+<<<<<<< HEAD:server-src/amdump.sh.in
+$libexecdir/amlogroll$SUF $conf "$@"
+=======
+$amlibexecdir/amlogroll$SUF $conf "$@"
+>>>>>>> upstream:server-src/amdump.sh
+exit_code=$?
+[ $exit_code -ne 0 ] && exit_status=$exit_code
+
+# Trim the log file to those for dumps that still exist.
+<<<<<<< HEAD:server-src/amdump.sh.in
+$libexecdir/amtrmlog$SUF $conf "$@"
+=======
+$amlibexecdir/amtrmlog$SUF $conf "$@"
+>>>>>>> upstream:server-src/amdump.sh
+exit_code=$?
+[ $exit_code -ne 0 ] && exit_status=$exit_code
+
+# Trim the index file to those for dumps that still exist.
+<<<<<<< HEAD:server-src/amdump.sh.in
+$libexecdir/amtrmidx$SUF $conf "$@"
+=======
+$amlibexecdir/amtrmidx$SUF $conf "$@"
+>>>>>>> upstream:server-src/amdump.sh
+exit_code=$?
+[ $exit_code -ne 0 ] && exit_status=$exit_code
+
+# Keep a debug log through the tapecycle plus a couple of days.
+maxdays=`expr $tapecycle + 2`
+days=1
+# First, find out the last existing errfile,
+# to avoid ``infinite'' loops if tapecycle is infinite
+while [ $days -lt $maxdays ] && [ -f $errfile.$days ]; do
+       days=`expr $days + 1`
+done
+# Now, renumber the existing log files
+while [ $days -ge 2 ]; do
+       ndays=`expr $days - 1`
+       mv $errfile.$ndays $errfile.$days
+       exit_code=$?
+       echo $exit_code
+       [ $exit_code -ne 0 ] && exit_status=$exit_code
+       days=$ndays
+done
+mv $errfile $errfile.1
+exit_code=$?
+[ $exit_code -ne 0 ] && exit_status=$exit_code
+
+exit $exit_status
diff --git a/server-src/amoverview.pl b/server-src/amoverview.pl
new file mode 100644 (file)
index 0000000..35594e4
--- /dev/null
@@ -0,0 +1,265 @@
+#!@PERL@
+
+# Catch for sh/csh on systems without #! ability.
+eval '(exit $?0)' && eval 'exec @PERL@ -S $0 ${1+"$@"}'
+       & eval 'exec @PERL@ -S $0 $argv:q'
+               if 0;
+
+require 5.001;
+
+use FileHandle;
+use Getopt::Long;
+use Text::ParseWords;
+use Carp;
+use POSIX;
+
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
+$ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin";
+
+sub Usage {
+    print STDERR <<END;
+Usage: $0 [[-config] CONFIG] [-hostwidth width] [-diskwidth width] [-skipmissed] [-last] [-num0] [-togo0] [-verbose]
+
+This script generates to standard output an overview of the filesystems
+dumped over time and the type of dump done on a particular day, such as
+a full dump, or an incremental, or if the dump failed.
+
+You may override the default configuration `@DEFAULT_CONFIG@' by using
+the -config command line option.  On larger installations, this script
+will take a while to run.  In this case, run it with --verbose to see
+how far along it is.
+END
+    exit 1;
+}
+
+# Default paths for this installation of Amanda.
+my $prefix='@prefix@';
+$prefix=$prefix;               # avoid warnings about possible typo
+my $exec_prefix="@exec_prefix@";
+$exec_prefix=$exec_prefix;     # ditto
+my $amlibexecdir="@amlibexecdir@";
+my $sbindir="@sbindir@";
+# The directory where configurations can be found.
+my $confdir="@CONFIG_DIR@";
+
+# The default configuration.
+my $config="@DEFAULT_CONFIG@";
+
+# Get the version suffix.
+my $USE_VERSION_SUFFIXES = '@USE_VERSION_SUFFIXES@';
+my $suf = '';
+if ( $USE_VERSION_SUFFIXES =~ /^yes$/i ) {
+       $suf='-@VERSION@';
+}
+
+my $amadmin    = "$sbindir/amadmin$suf";
+
+# overrideable defaults
+my $opt_config         = "$config";
+my $opt_hostwidth      = 8;
+my $opt_diskwidth      = 20;
+my $opt_skipmissed     = 0;
+my $opt_last           = 0;
+my $opt_num0           = 0;
+my $opt_togo0          = 0;
+my $opt_verbose                = 0;
+
+GetOptions('config=s'          => \$opt_config,
+          'hostwidth=i'        => \$opt_hostwidth,
+          'diskwidth=i'        => \$opt_diskwidth,
+          'skipmissed'         => \$opt_skipmissed,
+          'last'               => \$opt_last,
+          'num0'               => \$opt_num0,
+          'togo0'              => \$opt_togo0,
+          'verbose'            => \$opt_verbose)
+or Usage();
+
+if($#ARGV == 0) {
+  $opt_config = $ARGV[0];
+}
+elsif($#ARGV > 0) {
+  Usage();
+}
+
+#untaint user input $ARGV[0]
+
+if ($opt_config =~ /^([\w.-]+)$/) {          # $1 is untainted
+   $opt_config = $1;
+} else {
+    die "filename '$opt_config' has invalid characters.\n";
+}
+
+
+-d "$confdir/$opt_config" or
+       die "$0: directory `$confdir/$opt_config' does not exist.\n";
+
+# read disklist
+my %disks = ();
+$::host = '';
+$::disk = '';
+$opt_verbose and
+    print STDERR "Running $amadmin $opt_config disklist\n";
+my $dlfh = new FileHandle "$amadmin $opt_config disklist|" or
+    die "$0: error in opening `$amadmin $opt_config disklist' pipe: $!\n";
+$/ = "";
+while (<$dlfh>) {
+    ($host, $disk) = m/    host (.*?):.*    disk (.*?):.*strategy (STANDARD|NOFULL|NOINC|HANOI|INCRONLY).*ignore NO/s;
+    next unless $host;
+    $disks{$host}{$disk}++;
+}
+
+$/ = "\n";
+$dlfh->close or
+    die "$0: error in closing `$amadmin $opt_config disklist|' pipe: $!\n";
+
+# Get backup dates
+%::dates = ();
+%::level = ();
+$::level = '';
+my ($date, $tape, $file, $status);
+$opt_verbose and
+    print STDERR "Running $amadmin $opt_config find\n";
+my $fh = new FileHandle "$amadmin $opt_config find|" or
+    die "$0: error in opening `$amadmin $opt_config find' pipe: $!\n";
+<$fh>;
+while (<$fh>) {
+    chomp;
+    next if /found Amanda directory/;
+    next if /skipping cruft directory/;
+    next if /skip-incr/;
+
+    ($date, $time, $host, $disk, $level, $tape, $file, $part, $status) = shellwords($_);
+
+    next if $date eq 'date';
+    next if $date eq 'Warning:';
+    next if $date eq 'Scanning';
+    next if $date eq "";
+
+    if($time !~/^\d\d:\d\d:\d\d$/) {
+       $status = $part;
+       $part = $file;
+       $file = $tape;
+       $tape = $level;
+       $level = $disk;
+       $disk = $host;
+       $host = $time;
+    }
+
+    if ($date =~ /^\d\d\d\d-\d\d-\d\d$/) {
+       if(defined $disks{$host}{$disk}) {
+           defined($level{$host}{$disk}{$date}) or
+               $level{$host}{$disk}{$date} = '';
+           $level{$host}{$disk}{$date} .= ($status eq 'OK') ? $level : 'E';
+           $dates{$date}++;
+       }
+    }
+    else {
+       print "bad date $date in $_\n";
+    }
+}
+$fh->close or
+    die "$0: error in closing `$amadmin $opt_config find|' pipe: $!\n";
+
+# Process the status to arrive at a "last" status
+if ($opt_last) {
+    for $host (sort keys %disks) {
+        for $disk (sort keys %{$disks{$host}}) {
+           $level{$host}{$disk}{"0000-LA-ST"} = '';
+           for $date (sort keys %dates) {
+               if ($level{$host}{$disk}{$date} eq "E"
+                    && $level{$host}{$disk}{"0000-LA-ST"} =~ /^\d/ ) {
+                   $level{$host}{$disk}{"0000-LA-ST"} .= $level{$host}{$disk}{$date};
+               } elsif ($level{$host}{$disk}{$date} eq "") {
+                   $level{$host}{$disk}{"0000-LA-ST"} =~ s/E//;
+               } else {
+                   $level{$host}{$disk}{"0000-LA-ST"} = $level{$host}{$disk}{$date};
+               }
+           }
+        }
+    }
+}
+
+# Number of level 0 backups
+if ($opt_num0) {
+    for $host (sort keys %disks) {
+        for $disk (sort keys %{$disks{$host}}) {
+            $level{$host}{$disk}{'0000-NM-L0'} = 0;
+            for $date (sort keys %dates) {
+                if ($level{$host}{$disk}{$date} =~ /0/) {
+                    $level{$host}{$disk}{'0000-NM-L0'} += 1;
+                }
+            }
+        }
+    }
+}
+
+# Runs to the last level 0
+if ($opt_togo0) {
+    for $host (sort keys %disks) {
+        for $disk (sort keys %{$disks{$host}}) {
+            $level{$host}{$disk}{'0000-TO-GO'} = 0;
+            my $togo=0;
+            for $date (sort keys %dates) {
+                if ($level{$host}{$disk}{$date} =~ /0/) {
+                    $level{$host}{$disk}{'0000-TO-GO'} = $togo;
+                }
+                $togo++;
+            }
+        }
+    }
+}
+
+unless ($opt_skipmissed)
+# touch all the dates just in case whole days were missed.
+{
+    my ($start, $finish) = 
+       map {
+           my($y,$m,$d) = split /-/, $_;
+           POSIX::mktime(0,0,0,$d,$m-1,$y-1900);
+       } (sort keys %dates)[0,-1];
+
+    while ($start < $finish) {
+       my @l = localtime $start;
+       $dates{sprintf("%d-%02d-%02d", 1900+$l[5], $l[4]+1, $l[3])}++;
+       $start += 86400;
+    }
+}
+
+#Add the "last" entry    
+$dates{"0000-LA-ST"}=1 if ($opt_last);
+
+#Add the "Number of Level 0s" entry
+$dates{"0000-NM-L0"}=1 if ($opt_num0);
+
+#Add the "Runs to go" entry
+$dates{"0000-TO-GO"}=1 if ($opt_togo0);
+
+# make formats
+
+my $top_format = "format TOP =\n\n" .
+    sprintf("%-0${opt_hostwidth}s %-0${opt_diskwidth}s ", '', 'date') .
+    join(' ', map((split(/-/, $_))[1], sort keys %dates)) . "\n" .
+    sprintf("%-0${opt_hostwidth}s %-0${opt_diskwidth}s ", 'host', 'disk') .
+    join(' ', map((split(/-/, $_))[2], sort keys %dates)) . "\n" .
+    "\n.\n";
+
+my $out_format = "format STDOUT =\n" .
+    "@" . "<" x ($opt_hostwidth - 1) . ' ' .
+    "@" . "<" x ($opt_diskwidth - 1) . ' ' .
+    '@> ' x scalar(keys %dates) . "\n" .
+    join(', ', '$host', '$disk', 
+        map("substr(\$level{\$host}{\$disk}{'$_'},-2)", sort keys %dates)) . "\n" .
+    ".\n";
+
+eval $top_format;
+die $@ if $@;
+$^ = 'TOP';
+eval $out_format;
+die $@ if $@;
+
+for $host (sort keys %disks) {
+    for $disk (sort keys %{$disks{$host}}) {
+       write;
+    }
+}
diff --git a/server-src/amrmtape.sh b/server-src/amrmtape.sh
new file mode 100644 (file)
index 0000000..3e5a88e
--- /dev/null
@@ -0,0 +1,271 @@
+#!@SHELL@
+#
+# amrmtape.sh
+# Time-stamp: <96/10/23 12:07:21 adrian>
+# Copyright 1996, Adrian Filipi-Martin
+#
+# amrmtape
+#
+# Summary:  This script allow you to invalidate the contents of an
+# existing backup tape within the Amanda current tape database.  This
+# is meant as a recovery mecanism for when a good backup is damaged
+# either by faulty hardware or user error, i.e. the tape is eaten by
+# the tape drive, or the tape has been overwritten.
+#
+# To remove a tape you must specify the Amanda configuration to
+# operate upon as well as the name of the tape. e.g.
+#
+# amrmtape nvl NVL-006
+#
+# N.B.  amrmtape must be run as a user that can read the tape database
+# files and rewrite them.
+#
+# Usage: amrmtape [-n] [-v] [-q] [-d] <configuration> <label>
+#          -n Do nothing to original files, leave new ones in --with-tmpdir
+#            directory.
+#          -v Verbose mode.  Enabled by default.
+#          -q Quiet (opposite of -v).
+#          -d Enable debug tracing.
+#
+# Credits: The what-to-do algorithm was provided by Cedric Scott,
+#          cedric.scott@sse.ie. 
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+ConfigDir=@CONFIG_DIR@
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if test "$USE_VERSION_SUFFIXES" = "yes"; then
+       SUF="-@VERSION@"
+else
+       SUF=
+fi
+
+Program=`basename $0`
+
+CleanTapelist () {
+  [ "xyes" = "x${DebugMode}" ] && set -x
+
+  #
+  # Check if the configuration directory exists.  Make sure that the
+  # necessary files can be found, such as amanda.conf and tapelist.
+  #
+  if [ ! -d ${ConfigDir}/${Config} ]; then
+    log `_ '%s: configuration directory %s does not exist.' "$0" "${ConfigDir}/${Config}"`
+    return 1
+  fi
+  (cd ${ConfigDir}/${Config} >/dev/null 2>&1) || return $?
+  cd ${ConfigDir}/${Config}
+  if [ ! -r amanda.conf ]; then
+    log `_ '%s: amanda.conf not found or is not readable in %s.' "$0" "${ConfigDir}"`
+    return 1
+  fi
+
+  dumpuser=`amgetconf$SUF dumpuser`
+  runuser=`whoami`
+  if [ $runuser != $dumpuser ]; then
+    log `_ '%s: must be run as user %s' "$0" "$dumpuser"`
+    return 1
+  fi
+
+  # Get the location and name of the tapelist filename.  If tapelist is not
+  # specified in the amanda.conf file, then use tapelist in the config
+  # directory.
+  TapeList=`amgetconf${SUF} tapelist`
+  if [ ! "$TapeList" ]; then
+    TapeList="$ConfigDir/$Config/tapelist"
+  fi
+  if [ ! -r $TapeList ]; then
+    log `_ '%s: %s not found or is not readable.' "$0" "$TapeList"`
+    return 1
+  fi
+
+  # Get the location and name of the database filename.
+  InfoFile=`amgetconf${SUF} infofile`
+  if [ ! "$InfoFile" ]; then
+    log `_ '%s: unable to find name of infofile from %s.' "$0" "${ConfigDir}/${Config}/amanda.conf"`
+    return 1
+  fi
+  VarDir=`echo "$InfoFile" | sed -e 's%^[^/]*$%.%' -e 's%/[^/]*$%%'`
+
+  # Check that the database directory and files really exist.
+  if [ ! -d "${VarDir}" ]; then
+    log `_ '%s: %s does not exist or is not a directory.' "$0" "${VarDir}"`
+    return 1
+  fi
+  if [ ! -r "${InfoFile}" ] && [ ! -d "${InfoFile}" ]; then
+    log `_ '%s: %s does not exist or is not readable.' "${Program}" "${InfoFile}"`
+    return 1
+  fi
+
+  if [ ! -d @AMANDA_TMPDIR@ ]; then
+    log `_ '%s: directory %s does not exist.' "$0" "@AMANDA_TMPDIR@"`
+    exit 1
+  fi
+
+  NewTapelist=@AMANDA_TMPDIR@/tapelist
+  rm -f ${NewTapelist}
+  awk "\$2 == \"${Tape}\" { next; } { print; }" \
+      > ${NewTapelist} < $TapeList ||
+  return $?
+  if [ "xno" = "x${DoNothing}" ]; then
+    lines=`wc -l < $TapeList`
+    linesafter=`wc -l < $NewTapelist`
+    if [ "$lines" -gt "$linesafter" ]; then
+      cp -p $TapeList ${TapeList}~ && (
+        if test "$lines" -gt 1; then
+          [ -s ${NewTapelist} ] &&
+            cp ${NewTapelist} $TapeList &&
+            rm -f ${NewTapelist}
+        else
+          [ -f ${NewTapelist} ] &&
+            cp ${NewTapelist} $TapeList &&
+            rm -f ${NewTapelist}
+        fi
+      )
+      log `_ '%s: remove label %s.' "$0" "${Tape}"`
+    else
+      log `_ '%s: no such tape: %s.' "$0" "${Tape}"`
+      return 1
+    fi
+  fi
+  
+  return $?
+}
+
+
+CleanCurinfo () {
+  [ "xyes" = "x${DebugMode}" ] && set -x
+  (cd ${VarDir} >/dev/null 2>&1) || return $?
+  cd ${VarDir}
+  InfoFileBase=`echo $InfoFile | sed -e 's%.*/%%g'`
+
+  TmpSrc=$InfoFileBase.orig.$$
+  TmpDest=$InfoFileBase.new.$$
+  rm -f ${TmpSrc} ${TmpDest}
+  amadmin${SUF} ${Config} export > ${TmpSrc} || return $?
+  log `_ '%s: preserving original database in %s (exported).' "$0" "${TmpSrc}"`
+  exec < ${TmpSrc} > ${TmpDest} || return $?
+  DeadLevel=10
+  while read Line; do
+    case ${Line} in
+      CURINFO*|"#"*|command*|last_level*|consecutive_runs*|full*|incr*)
+       echo "${Line}"
+        ;;
+      host*)
+       set ${Line}
+        Host=$2
+       echo "${Line}"
+        ;;
+      disk*)
+       set ${Line}
+        Disk=$2
+       echo "${Line}"
+        ;;
+      stats*)
+       set ${Line}
+       if [ $# -lt 6 ] || [ $# -gt 8 ]; then
+         log `_ '%s: unexpected number of fields in "stats" entry for %s.' "${Program}" "${Host}:${Disk}"`
+         log "${Line}"
+         return 1
+       fi
+       Level=$2
+       CurrentTape=$8
+       if [ "${CurrentTape}" = "${Tape}" ]; then
+         DeadLevel=${Level}
+         ${Verbose} "Discarding Host: ${Host}, Disk: ${Disk}, Level: ${Level}"
+       elif [ $Level -gt $DeadLevel ]; then
+         ${Verbose} "Discarding Host: ${Host}, Disk: ${Disk}, Level: ${Level}"
+       else
+         echo "${Line}"
+       fi
+       ;;
+      history*)
+       set ${Line}
+       echo "${Line}"
+       ;;
+      //)
+       echo "${Line}"
+       DeadLevel=10
+       ;;
+      *)
+       log `_ 'Error: unrecognized line of input: "%s"' "${Line}"`
+       return 1
+    esac
+  done
+  exec < /dev/tty > /dev/tty
+
+  if [ "xno" = "x${DoNothing}" ]; then
+    [ -s ${TmpDest} ] && 
+    amadmin${SUF} ${Config} import < ${TmpDest} &&
+    rm -f ${TmpDest}
+  fi
+
+  return $?
+}
+
+
+log () {
+  echo 1>&2 "$@"
+  return 0
+}
+
+
+usage () {
+  echo `_ '%s [-n] [-v] [-q] [-d] <configuration> <label>' "${Program}"`
+  echo `_ '  -n Do nothing to original files, leave new ones in database directory.'`
+  echo `_ '  -v Verbose, list backups of hosts and disks that are being discarded.'`
+  echo `_ '  -q Quiet, opposite of -v.'`
+  echo `_ '  -d Enable debug tracing.'`
+  echo `_ 'This program allows you to invalidate the contents of an existing
+backup tape within the Amanda current tape database.  This is meant
+as a recovery mecanism for when a good backup is damaged either by
+faulty hardware or user error, i.e. the tape is eaten by the tape drive,
+or the tape has been overwritten.'`
+  return 0
+}
+
+
+Verbose="log "
+DoNothing="no"
+DebugMode="no"
+
+set dummy ${1+"$@"}
+while shift 2>/dev/null; do
+  case "$1" in
+    -q)
+      Verbose=": "
+      ;;
+    -v)
+      Verbose="log "
+      ;;
+    -n)
+      DoNothing="yes"
+      ;;
+    -d)
+      DebugMode="yes"
+      ;;
+    *)
+      if [ $# = 2 ]; then
+        Config=$1
+        Tape=$2
+       break
+      else
+        usage 1>&2
+       exit 1
+      fi
+
+  esac
+done
+
+( CleanTapelist && CleanCurinfo )
+exit $?
diff --git a/server-src/amserverconfig.pl b/server-src/amserverconfig.pl
new file mode 100755 (executable)
index 0000000..09557cb
--- /dev/null
@@ -0,0 +1,655 @@
+#!@PERL@
+#
+# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
+#
+
+use Getopt::Long;
+use Time::Local;
+use File::Copy;
+use Socket;   # for gethostbyname
+
+my $confdir="@CONFIG_DIR@";
+my $prefix="@prefix@";
+my $tmpdir="@AMANDA_DBGDIR@";
+$prefix=$prefix;                # avoid warnings about possible typo
+my $exec_prefix="@exec_prefix@";
+$exec_prefix=$exec_prefix;      # ditto
+my $sbindir="@sbindir@";
+my $localstatedir="@localstatedir@";
+my $amandahomedir="$localstatedir/lib/amanda";
+my $datadir="$amandahomedir/template.d"; #rpm install template files here
+my $def_tapedev="file:/$amandahomedir/vtapes";
+
+my $amanda_user="@CLIENT_LOGIN@";
+my $def_config="@DEFAULT_CONFIG@";
+my $def_dtimeout="1800";
+my $def_ctimeout="30";
+my $def_etimeout="300";
+my $def_perm=0750;
+my $amanda_conf_perm=0600;
+my $def_tapecycle=10;
+my $config;
+my $vtape_err=0;
+my $holding_err=0;
+my $template_only=0;
+my $parentdir;
+my $host;
+# Get the version suffix.
+my $USE_VERSION_SUFFIXES = '@USE_VERSION_SUFFIXES@';
+my $suf = '';
+if ( $USE_VERSION_SUFFIXES =~ /^yes$/i ) {
+        $suf='-@VERSION@';
+}
+
+
+#usage
+sub usage {
+        print "$0 $suf\n";
+        print "\t\t <config> [--template <template>]\n";
+       print "\t\t[--no-vtape] (do not create virtual tapes)\n";
+        print "\t\t[--tapetype <tapetype>] [--tpchanger <tpchanger>]\n";
+        print "\t\t[--tapedev <tapedev>] [--changerfile <changerfile>]\n";
+        print "\t\t[--changerdev <changerdev>] [--labelstr <labelstr>] \n";
+       print "\t\t[--mailto <mailto>] [--dumpcycle <dumpcycle> (ex: 5days, 1week or 2weeks)]\n";
+       print "\t\t[--runspercycle <runspercycle>] [--runtapes <runtapes>]\n";
+       print "\t\t[--tapecycle <tapecycle>]\n";
+       print "\t\t[--help]\n";
+}
+
+#print and log
+sub mprint {
+    for $fh ( STDOUT, LOG ) {
+       print $fh @_;
+    }
+}
+
+sub log_and_die { 
+    my ($err, $cleanup) = @_;
+    print LOG $err;
+    # clean up $config directory if cleanup=1
+    # if error in creating vtape or holding disk, 
+    # advise user to create manually, no need to cleanup
+    if ( $cleanup && defined $config  && -e "$confdir/$config" ) {
+       print LOG "cleaning up $confdir/$config\n";
+       if ( -e "$confdir/$config/amanda.conf" ) {
+           unlink "$confdir/$config/amanda.conf" || 
+           print LOG "unlink $confdir/$config/amanda.conf failed: $!\n";
+       }
+       if ( -e "$confdir/$config/advanced.conf" ) {
+           unlink "$confdir/$config/advanced.conf" || 
+           print LOG "unlink $confdir/$config/advanced.conf failed: $!\n";
+       }
+       if ( -e "$confdir/$config/tapelist" ) {
+           unlink "$confdir/$config/tapelist" || 
+           print LOG "unlink $confdir/$config/tapelist failed: $!\n";
+       }
+       if ( -e "$confdir/$config/curinfo" ) {
+           rmdir "$confdir/$config/curinfo" || 
+           print LOG "rmdir $confdir/$config failed: $!\n";
+       }
+       if ( -e "$confdir/$config/index" ) {
+           rmdir "$confdir/$config/index" || 
+           print LOG "rmdir $confdir/$config/index failed: $!\n";
+       }
+       rmdir "$confdir/$config" || 
+           print LOG "rmdir $confdir/$config failed: $!\n";
+    }
+    die $err;
+}
+
+
+sub is_user_right {
+    my $user = `whoami`;
+    chomp($user);
+    ( $user eq $amanda_user ) ||
+       die ("ERROR: $0 must be run by $amanda_user\n", 0);
+}
+
+
+# rpm installation should have taken care of these. Create one if it's not there
+sub check_gnutarlist_dir {
+    if ( -e "$amandahomedir/gnutar-lists" ) {
+       &mprint ("$amandahomedir/gnutar-lists directory exists\n");
+    }
+    else {
+       mkdir ("$amandahomedir/gnutar-lists", $def_perm) ||
+           &log_and_die ("ERROR: mkdir:$amandahomedir/gnutar-lists failed: $!\n", 0);
+    }
+}
+
+sub create_conf_dir {
+  unless ( -e $confdir ) {
+    &log_and_die ("ERROR: $confdir does not exist\n", 0);
+  }
+  unless ( -e "$confdir/$config" ) {
+    mkdir ("$confdir/$config", $def_perm) ||
+      &log_and_die ("ERROR: mkdir: $confdir/$config failed: $!\n", 0); # $! = system error
+  } else {
+    &log_and_die ("ERROR: Configuration $config exists\n", 0);
+  }
+  unless ( -e "$confdir/template.d" ) {
+    mkdir ("$confdir/template.d", $def_perm)  ||
+      &log_and_die ("ERROR: mkdir: $confdir/template.d failed: $!\n", 0);
+    &mprint ("$confdir/template.d directory created\n");
+  }
+}
+
+sub copy_template_file {
+    my $tplate = $_[0];
+    unless ($tplate) {
+       &log_and_die ("ERROR: template is missing\n", 1);
+    }
+    # create and update amanda.conf
+    open(CONF, "$datadir/amanda-$tplate.conf")
+       || &log_and_die ("ERROR: Cannot open $datadir/amanda-$tplate.conf: $!\n", 1);
+    open(NEWCONF, ">$confdir/$config/amanda.conf") ||
+       &log_and_die ("ERROR: Cannot create $confdir/$config/amanda.conf: $!\n", 1);
+    chmod ($amanda_conf_perm, "$confdir/$config/amanda.conf") ||
+       &log_and_die ("ERROR: Cannot set amanda.conf file access permission: $!\n", 1);
+    while (<CONF>) {
+       $_ =~ s/$def_config/$config/;
+       print NEWCONF $_;
+    }
+    close(CONF);
+    close(NEWCONF);
+    &mprint ("$confdir/$config/amanda.conf created and updated\n");
+}
+
+
+sub create_curinfo_index_dir {
+    mkdir("$confdir/$config/curinfo", $def_perm) ||
+       &log_and_die ("ERROR: mkdir: $confdir/$config/curinfo failed: $!\n", 1);
+    mkdir("$confdir/$config/index", $def_perm) || 
+       &log_and_die ("ERROR: mkdir: $confdir/$config/index failed: $!\n", 1);
+    &mprint ("curinfo and index directory created\n");
+}
+
+sub touch_list_files {
+    open (TLIST, ">$confdir/$config/tapelist")
+       || &log_and_die ("ERROR: Cannot create tapelist file: $!\n", 1);
+    close (TLIST);
+    &mprint ("tapelist file created\n");
+
+    open (DLIST, ">$confdir/$config/disklist")
+       || &log_and_die ("ERROR: Cannot create disklist file: $!\n", 1);
+    close (DLIST);
+    &mprint ("disklist file created\n");
+}
+
+# create holding disk directory, check disk space first
+sub create_holding { 
+  if ( -d "$amandahomedir/holdings/$config" ) {
+    my $uid = (stat("$amandahomedir/holdings/$config"))[4];
+    my $owner = (getpwuid($uid))[0];
+    unless ( $owner eq $amanda_user ) {
+      &mprint ("WARNING: holding disk directory exists and is not owned by $amanda_user\n");
+      $holding_err++;
+    }
+    return;
+  }
+    my $div=1;
+    my $out = `df -k $amandahomedir`;
+    my @dfout = split(" " , $out);
+    unless ( $#dfout == 12 ) { # df should output 12 elem
+       &mprint ("WARNING: df failed, holding disk directory not created\n");
+       $holding_err++;
+       return;
+    }
+    unless (( $dfout[1] eq "1K-blocks" ) || ( $dfout[1] eq "kbytes")) {
+         $div=2;       # 512-blocks displayed by df
+     }
+    
+    if (( $dfout[10] / $div )  > 1024000 ) { # holding disk is defined 1000 MB
+       &mprint ("creating holding disk directory\n");
+       unless ( -d "$amandahomedir/holdings" ) { 
+       mkdir ( "$amandahomedir/holdings", $def_perm) ||
+           (&mprint ("WARNING: mkdir $amandahomedir/holdings failed: $!\n"), $holding_err++, return );
+    }
+       mkdir ( "$amandahomedir/holdings/$config", $def_perm) ||
+           (&mprint ("WARNING: mkdir $amandahomedir/holdings/$config failed: $!\n"), $holding_err++, return) ;
+    }
+}
+
+#create default tape dir
+sub create_deftapedir{
+    unless ( -e "$amandahomedir/vtapes" ) { 
+       mkdir ( "$amandahomedir/vtapes", $def_perm) ||
+           ( &mprint ("WARNING: mkdir $amandahomedir/$config/vtapes failed: $!\n"), return );
+    }
+    unless ( -e "$amandahomedir/vtapes/$config" ) { 
+       mkdir ( "$amandahomedir/vtapes/$config", $def_perm) ||
+           ( &mprint ("WARNING: mkdir $amandahomedir/vtapes/$config failed: $!\n"), return );
+    }
+       $parentdir="$amandahomedir/vtapes/$config";
+}
+
+# create and label vtape
+sub create_vtape {
+       &mprint ("creating vtape directory\n");
+       if ($template_only==0){ #  check $template mode
+               $mylabelprefix=$labelstr;   #set labelstr
+               if ($tapedev eq "$def_tapedev/$config"){
+               &create_deftapedir;
+               }
+               else {
+               $tapedev=~/^(file:\/)/;
+               $parentdir=$';
+               }
+       }
+       else {
+               $mylabelprefix=$config;
+               &create_deftapedir;     
+       }
+       unless ( -e $parentdir){
+               &mprint ("WARNING: tapedev $parentdir does not exists, vtapes creation failed!\n");
+               &mprint ("Please create $parentdir and $confdir/$config and rerun the same command or else create vtapes manually.\n");
+               $vtape_err++;
+               return;
+       }
+
+       chdir ("$parentdir") ||
+               ( &mprint("WARNING: chdir $parentdir failed: $!\n"), $vtape_err++, return );
+    my $i;
+    &mprint ("amlabel vtapes\n");
+       if (defined $tapecycle) {
+               $tapecycle=~/^\d+/; 
+               $tp_cyclelimit=$&;
+                       # check space
+               my $dfout =`df $parentdir`;
+               my $mul=1024;
+               @dfdata=split(" ",$dfout);
+               unless ( $dfdata[1] eq "1K-blocks" ) {
+                       $mul=512;       # 512-blocks displayed by df
+               }
+               if (($dfdata[10]*$mul) < (($tp_cyclelimit*73728)+10240)){
+                       &mprint ("WARNING: Not enough space for vtapes. Creation of vtapes failed\n");
+                       $vtape_err++;
+                       return;
+               }
+       }
+       else {
+               $tp_cyclelimit=$def_tapecycle;
+       }
+
+       for $i (1..$tp_cyclelimit) {
+               unless ( -e "slot$i"){
+               mkdir ("slot$i", $def_perm) ||
+               ( &mprint ("WARNING: mkdir $parentdir/slot$i failed: $!\n"), $vtape_err++, return);
+               }
+               ( @amlabel_out = `$sbindir/amlabel -f $config $mylabelprefix-$i slot $i`) ||
+           ( &mprint ("WARNING: amlabel vtapes failed at slot $i: $!\n"), $vtape_err++, return);
+    }
+       foreach (@amlabel_out) {
+         print LOG;
+        }
+       # reset tape to the first slot
+       `$sbindir/amtape $config reset`;
+}
+
+sub create_customconf{
+          # now create a custom amanda.conf from user input
+       unless ( $mailto ) 
+       { $mailto="$amanda_user"; }
+       else {  # untaint mailto which can be evil
+                # reject mailto with the following * ( ) < > [ ] , ; : ! $ \ / "
+           if ( $mailto =~ /^([^\*\(\)<>\[\]\,\;\:\!\$\\\/\"]+)$/ ) {
+               $mailto = $1;                      #  now untainted
+           } else {
+               &log_and_die ("ERROR: Invalid data in mailto.\n");  # log this somewhere
+           }
+       }
+       unless ( $dumpcycle ) { $dumpcycle="1 week"; }
+       unless ( $runspercycle ) { $runspercycle="5"; }
+       unless ( $tapecycle ) { $tapecycle="10 tapes"; }
+       unless ( $runtapes ) { $runtapes="1"; }
+       unless ( $labelstr ) {
+         if ($template eq "harddisk") {
+           $labelstr="$config";
+         } else {
+           $labelstr="^$config-[0-9][0-9]*\$";
+         }
+       }
+       if ((!(defined($template)))||($template eq "harddisk")) 
+         {
+               if (defined $tapedev){
+               $tapedev="file:/".$tapedev;
+               }
+               unless ( $tpchanger ) { $tpchanger="chg-disk"; }
+               unless ( $tapedev ) { $tapedev="$def_tapedev/$config"; }
+               unless ( $changerfile ) { $changerfile="$confdir/$config/changer.conf"; }
+               unless ( $changerdev ) { $changerdev="/dev/null";}
+               unless ( $tapetype ) { $tapetype="HARDDISK"; }  
+         }
+       elsif ($template eq "single-tape")
+         {
+               unless ($tpchanger) {$tpchanger="chg-manual";}
+               unless ($tapedev)     {$tapedev="/dev/nst0";}
+               unless ($changerfile) {$changerfile="$confdir/$config/chg-manual.conf";}
+               unless ($changerdev) {$changerdev="/dev/null";}
+               unless ($tapetype) {$tapetype="HP-DAT";}
+         }
+       elsif ($template eq "tape-changer") 
+          {
+               unless ($tpchanger){$tpchanger="chg-zd-mtx";}
+               unless ($tapedev){ $tapedev="/dev/nst0";}
+               unless ($changerfile){$changerfile="$confdir/$config/changer.conf";}
+               unless ($changerdev) {$changerdev="/dev/sg1";}
+               unless ($tapetype)  {$tapetype="HP-DAT";}
+          }
+        else # S3 case
+         {
+           unless ($tpchanger){$tpchanger="chg-multi";}
+           unless ($changerfile){$changerfile="$confdir/$config/changer.conf";}
+           unless ($tapetype)  {$tapetype="HP-DAT";}
+         }
+
+
+       open (CONF, ">$confdir/$config/amanda.conf") ||
+           &log_and_die ("ERROR: Cannot create amanda.conf file: $!\n", 1);
+       chmod ($amanda_conf_perm, "$confdir/$config/amanda.conf") ||
+           &log_and_die ("ERROR: Cannot set amanda.conf file access permission: $!\n", 1);
+
+       print CONF "org \"$config\"\t\t# your organization name for reports\n";
+       print CONF "mailto \"$mailto\"\t# space separated list of operators at your site\n";
+       print CONF "dumpcycle $dumpcycle\t\t# the number of days in the normal dump cycle\n";
+        print CONF "runspercycle $runspercycle\t\t# the number of amdump runs in dumpcycle days\n";
+       print CONF "tapecycle $tapecycle\t# the number of tapes in rotation\n"; 
+       print CONF "runtapes $runtapes\t\t# number of tapes to be used in a single run of amdump\n";
+       print CONF "tpchanger \"$tpchanger\"\t# the tape-changer glue script\n";
+       print CONF "tapedev \"$tapedev\"\t# the no-rewind tape device\n";
+       print CONF "changerfile \"$changerfile\"\t# tape changer configuration parameter file\n";
+       print CONF "changerdev \"$changerdev\"\t# tape changer configuration parameter device\n";
+       print CONF "tapetype $tapetype\t# what kind of tape it is\n";
+       print CONF "labelstr \"$labelstr\"\t# label constraint regex: all tapes must match\n";
+       print CONF "dtimeout $def_dtimeout\t# number of idle seconds before a dump is aborted\n";
+       print CONF "ctimeout $def_ctimeout\t# max number of secconds amcheck waits for each client\n";
+       print CONF "etimeout $def_etimeout\t# number of seconds per filesystem for estimates\n";
+       print CONF "define dumptype global {\n";
+       print CONF "       comment \"Global definitions\"\n";
+       print CONF "       auth \"bsdtcp\"\n}\n";
+       print CONF "define dumptype gui-base {\n";
+       print CONF "       global\n";
+       print CONF "       program \"GNUTAR\"\n";
+       print CONF "       comment \"gui base dumptype dumped with tar\"\n";
+       print CONF "       compress none\n";
+       print CONF "       index yes\n}\n";
+       if ($tapetype eq "HARDDISK") {
+         print CONF "define tapetype HARDDISK {\n";
+         print CONF "       comment \"Virtual Tapes\"\n";
+         print CONF "       length 5000 mbytes\n}\n";
+       }
+       print CONF "includefile \"advanced.conf\"\n";
+       print CONF "includefile \"$confdir/template.d/dumptypes\"\n";
+       print CONF "includefile \"$confdir/template.d/tapetypes\"\n";
+       close (CONF);
+       mprint ("custom amanda.conf created\n");
+  }
+
+
+sub check_xinetd{
+    &mprint ("/var/lib/amanda/example/xinetd.amandaserver contains the latest Amanda server daemon configuration.\n");
+    &mprint ("Please merge it to /etc/xinetd.d/amandaserver.\n");
+}
+
+
+sub build_amanda_ssh_key{
+  if ( -e "$amandahomedir/.ssh/id_rsa_amdump.pub" ) {
+    if ( -e "$amandahomedir/.ssh/client_authorized_key" ) {
+      &mprint ("$amandahomedir/.ssh/client_authorized_keys exists.\n");
+    }
+    else {
+      open(NEWAUTH, ">$amandahomedir/.ssh/client_authorized_keys") ||
+       (&mprint("WARNING: open $amandahomedir/.ssh/client_authorized_key failed: $!\n"), return);
+      open(PUB, "$amandahomedir/.ssh/id_rsa_amdump.pub") ||
+       (&mprint("WARNING: open $amandahomedir/.ssh/id_rsa_amdump.pub failed: $!\n"), return);
+      print NEWAUTH "from=\"$host\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command=\"/usr/lib/amanda/amandad -auth=ssh amdump\" ";
+      while (<PUB>) {
+      print NEWAUTH;
+    }
+      close NEWAUTH;
+      close PUB;
+      &mprint("$amandahomedir/.ssh/client_authorized_keys created. Please append to /var/lib/amanda/.ssh/authorized_keys file on Amanda clients\n");
+      }
+  }
+}
+
+sub copy_chg_manual_conf {
+  if ( $template eq "single-tape" && !defined $changerfile && !defined $tpchanger)
+    {
+      my $my_changerfile="$confdir/$config/chg-manual.conf";
+      copy("$datadir/chg-manual.conf", $my_changerfile) ||
+       &mprint ("copy $datadir/chg-manual.conf to $my_changerfile failed: $!\n");
+    }
+}
+
+#main
+my $ret=0;
+
+$ret = GetOptions ("template=s"=>\$template,
+                  "no-vtape!"=>\$novtape,
+             "tapetype=s"=>\$tapetype,
+             "tpchanger=s"=>\$tpchanger,
+             "tapedev=s"=>\$tapedev,
+             "changerfile=s"=>\$changerfile,
+             "changerdev=s"=>\$changerdev,
+             "labelstr=s"=>\$labelstr,
+             "mailto=s"=>\$mailto,
+             "dumpcycle=s"=>\$dumpcycle,
+             "runspercycle=i"=>\$runspercycle,
+             "runtapes=i"=>\$runtapes,
+             "tapecycle=i"=>\$tapecycle,
+             "help!"=>\$help
+             );
+
+unless ( $ret ) {
+    &usage;
+    exit 1;
+}
+
+if($help) {
+    &usage;
+    exit 0;
+}
+
+unless ( $#ARGV == 0 ) {
+    print STDERR "ERROR: config name is required.\n";
+    &usage;
+    exit 1;
+}
+else {
+    if ( "$ARGV[0]" =~ /^([-\@\w.]+)$/ ) {
+       $config = $1;                   #  now untainted
+    } else {
+       die ("ERROR: Invalid data in config name.\n");  # log this somewhere
+    }
+}
+
+
+$oldPATH = $ENV{'PATH'};
+
+$ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin:/usr/ucb"; # force known path
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+$date=`date +%Y%m%d%H%M%S`;
+chomp($date);
+my $logfile="$tmpdir/amserverconfig.$date.debug";
+
+&is_user_right;
+unless ( -e "$tmpdir" ) {
+    mkdir ("$tmpdir", $def_perm) ||
+       die ("ERROR: mkdir: $tmpdir failed: $!\n");
+}
+
+open (LOG, ">$logfile") || die ("ERROR: Cannot create logfile: $!\n");
+print STDOUT "Logging to $logfile\n";
+
+my $lhost=`hostname`;
+chomp($lhost);
+# get our own canonical name, if possible (we don't sweat the IPv6 stuff here)
+$host=(gethostbyname($lhost))[0];
+
+unless ( $host ) {
+    $host = $lhost;  #gethostbyname() failed, go with hostname output
+}
+
+
+&create_conf_dir;
+
+if ( defined $template ) {
+# validate user input to template
+    chomp($template);
+    my $found = 0;
+    @valid_templates = ( "harddisk", "single-tape", "tape-changer", "s3");
+    foreach $elt (@valid_templates) {
+       if ($elt eq lc($template)) {
+           $found = 1;
+           last;
+       }
+    }
+    unless ( $found ) {
+       print STDERR "valid inputs to --templates are harddisk, single-tape, tape-changer or S3\n";
+       &usage;
+       exit 1;
+}
+# if tape-changer is chosen, check if mtx is installed
+    if ($template eq "tape-changer") {
+      my $ok = 0;
+      for $dir ("/usr/sbin", "/usr/local/sbin", "/usr/local/bin", "/usr/bin", "/bin","/opt/csw/sbin",split(":",$oldPATH)) {
+       if ( -e "$dir/mtx" ) {
+         $ok = 1;
+         last;
+       }
+      }
+      unless ($ok) {
+       &mprint      ("ERROR: mtx binary not found, tape-changer template will not work and is not installed.\n");
+       &log_and_die ("ERROR: Please install mtx and rerun the same command.\n", 0);
+      }
+      unless ($changerfile) {$changerfile="$confdir/$config/changer.conf";}
+      open (CCONF, ">$changerfile")
+       || &log_and_die ("ERROR: Cannot create $changerfile: $!\n", 1);
+      close (CCONF);
+  } elsif ($template eq "S3" ) {
+
+      unless ($changerfile) {$changerfile="$confdir/$config/changer.conf";}
+      open (CCONF, ">$changerfile")
+    || &log_and_die ("ERROR: Cannot create $changerfile: $!\n", 1);
+      close (CCONF);
+
+  }
+
+}
+
+&check_gnutarlist_dir;
+
+# copy dumptypes and tapetypes files if none exists.
+my $dtype="$confdir/template.d/dumptypes";
+my $ttype="$confdir/template.d/tapetypes";
+
+unless ( -e $dtype ) {
+    copy("$datadir/dumptypes", $dtype ) ||
+    &log_and_die ("ERROR: copy dumptypes failed: $!\n", 1);
+}
+
+
+unless ( -e $ttype ) {
+    copy("$datadir/tapetypes", $ttype ) ||
+    &log_and_die ("ERROR: copy tapetypes file to $ttype failed: $!\n", 1);
+}
+
+
+
+# update $def_config value to the specified config value in advanced.conf
+    open(ADV, "$datadir/advanced.conf") || &log_and_die ("ERROR: Cannot open advanced.conf file: $!\n", 1);
+    open(NEWADV, ">$confdir/$config/advanced.conf") || 
+       &log_and_die ("ERROR: Cannot create advanced.conf file: $!\n", 1);
+    while (<ADV>) {
+       $_ =~ s/$def_config/$config/;
+       print NEWADV $_;
+    }
+    close(ADV);
+    close(NEWADV);
+    &mprint ("$confdir/$config/advanced.conf created and updated\n");
+
+
+&create_curinfo_index_dir;
+&touch_list_files;
+
+
+if ( defined $template ) {
+# if any other parameters are provided, create a workable custom config
+       if ( defined $tapetype || defined $tpchanger || defined $tapedev
+        || defined $changerdev || defined $labelstr || defined $mailto || defined $dumpcycle
+        || defined $runspercycle || defined $runtapes || defined $tapecycle ) {
+               &mprint("Creating custom configuration using templates\n");
+               create_customconf();
+               if ( $template ne "harddisk" ) {
+                 &create_holding;
+               } else {
+                 if (defined $labelstr) {
+                   if ($labelstr=~/^([-\w.]+)$/) {
+                     &create_vtape unless ( defined $novtape );
+                   } else {
+                     &mprint ("WARNING: Only alphanumeric string is supported in labelstr when using template to create vtapes. ");
+                     &mprint ("If you want to use regex in labelstr, please create vtapes manually.\n");
+                   }
+                 }
+               }
+             } else {
+               $template_only=1;
+               $tapedev="$def_tapedev/$config";
+               &copy_template_file($template);
+               if ($template ne "harddisk") {
+                 unless ( -e "$amandahomedir/holdings/$config" ) {
+                   &create_holding;
+                 }
+               } else {  # harddisk and template only
+                 unless ( -e "$amandahomedir/vtapes/$config" || defined $novtape ) {
+                   &create_vtape;
+                 }
+               }
+             }
+       &copy_chg_manual_conf;
+      } else {
+&create_customconf;
+}
+
+&check_xinetd;
+&build_amanda_ssh_key;
+
+if ( $vtape_err ) {
+  &mprint("Error in creating virtual tape, please check log and create virtual tape manually.\n");
+  exit 1;
+}
+
+if ( $holding_err ) {
+  &mprint("Error in creating holding disk, please check log and create holding disk manually.\n");
+  exit 1;
+}
+
+
+
+if ( $vtape_err==0 && $holding_err==0) {
+  &mprint("DONE.\n");
+  exit 0;
+}
+
+
+$ENV{'PATH'} = $oldPATH;
+
+
+# THE END
diff --git a/server-src/amstatus.pl b/server-src/amstatus.pl
new file mode 100644 (file)
index 0000000..2c32d1b
--- /dev/null
@@ -0,0 +1,1439 @@
+#!@PERL@ -Tw
+#
+
+# Run perl.
+eval '(exit $?0)' && eval 'exec @PERL@ -S $0 ${1+"$@"}'
+        & eval 'exec @PERL@ -S $0 $argv:q'
+               if 0;
+
+require "newgetopt.pl";
+use Time::Local;
+use Text::ParseWords;
+
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
+$ENV{'PATH'} = "/bin:/usr/bin:/usr/sbin:/sbin";       # force known path
+
+$confdir="@CONFIG_DIR@";
+$prefix='@prefix@';
+$prefix=$prefix;               # avoid warnings about possible typo
+$exec_prefix="@exec_prefix@";
+$exec_prefix=$exec_prefix;     # ditto
+$sbindir="@sbindir@";
+
+#$STATUS_STRANGE =  2;
+$STATUS_FAILED  =  4;
+$STATUS_MISSING =  8;
+$STATUS_TAPE    = 16;
+$exit_status    =  0;
+
+$USE_VERSION_SUFFIXES='@USE_VERSION_SUFFIXES@';
+$suf = '';
+if ( $USE_VERSION_SUFFIXES =~ /^yes$/i ) {
+        $suf='-@VERSION@';
+}
+
+$result = &NGetOpt (   "summary",
+                       "stats|statistics",
+                       "dumping|d",
+                       "waitdumping|wdumping",
+                       "waittaper|wtaper",
+                       "dumpingtape|dtape",
+                       "writingtape|wtape",
+                       "finished",
+                       "failed|error",
+                       "estimate",
+                       "gestimate|gettingestimate",
+                       "date",
+                       "config|c:s",
+                       "file:s",
+                       "locale-independent-date-format",
+                       );
+if($result !=1 ) {
+       &usage();
+}
+
+if( defined $opt_config ) {
+       $conf = $opt_config;
+}
+else {
+       if($#ARGV == 0 ) {
+               $conf=$ARGV[0];
+       }
+       else {
+               &usage();
+       }
+}
+
+#untaint user input $ARGV[0]
+
+if ($conf =~ /^([\w.-]+)$/) {          # $1 is untainted
+   $conf = $1;
+} else {
+    die "filename '$conf' has invalid characters.\n";
+}
+
+if ( ! -e "$confdir/$conf" ) {
+    print "Configuration directory '" . $confdir/$conf . "' doesn't exist\n";
+    exit 1;
+}
+if ( ! -d "$confdir/$conf" ) {
+    print "Configuration directory '" . $confdir/$conf . "' is not a directory\n";
+    exit 1;
+ }
+
+
+$pwd = `pwd`;
+chomp $pwd;
+chdir "$confdir/$conf";
+
+$logdir=`$sbindir/amgetconf$suf logdir`;
+exit 1 if $? != 0;
+chomp $logdir;
+$errfile="$logdir/amdump";
+
+$nb_options = defined( $opt_summary ) +
+                                 defined( $opt_stats ) +
+                                 defined( $opt_dumping ) +
+                                 defined( $opt_waitdumping ) +
+                                 defined( $opt_waittaper ) +
+                                 defined( $opt_dumpingtape ) +
+                                 defined( $opt_writingtape ) +
+                                 defined( $opt_finished ) +
+                                 defined( $opt_estimate ) +
+                                 defined( $opt_gestimate ) +
+                                 defined( $opt_failed );
+
+if($nb_options == 0 ) {
+       $opt_summary     = 1;
+       $opt_stats       = 1; 
+       $opt_dumping     = 1;
+       $opt_waitdumping = 1;
+       $opt_waittaper   = 1;
+       $opt_dumpingtape = 1;
+       $opt_writingtape = 1;
+       $opt_finished    = 1;
+       $opt_failed      = 1;
+       $opt_gestimate   = 1;
+       $opt_estimate    = 1;
+}
+
+$unit=`$sbindir/amgetconf$suf displayunit`;
+chomp($unit);
+$unit =~ tr/A-Z/a-z/;
+$unitdivisor=1;
+if($unit eq 'k') {
+  $unitdivisor = 1;
+}
+elsif($unit eq 'm') {
+  $unitdivisor = 1024;
+}
+elsif($unit eq 'g') {
+  $unitdivisor = 1024*1024;
+}
+elsif($unit eq 't') {
+  $unitdivisor = 1024*1024*1024;
+}
+else {
+  $unit = 'k';
+  $unitdivisor = 1;
+}
+
+
+if( defined $opt_file) {
+       if( $opt_file =~ m,^/, ) {
+               $errfile = $opt_file;
+       } else {
+               $errfile = "$pwd/$opt_file";
+               $errfile = "$logdir/$opt_file" if ( ! (-f $errfile ));
+       }
+}
+else {
+       $errfile="$logdir/amflush" if(! (-f $errfile));
+       if (! -f $errfile) {
+               if (-f "$logdir/amflush.1" && -f "$logdir/amdump.1" &&
+                   -M "$logdir/amflush.1"  < -M "$logdir/amdump.1") {
+                       $errfile="$logdir/amflush.1";
+               } else {
+                       $errfile="$logdir/amdump.1";
+               }
+       }
+}
+
+open(AMDUMP,"<$errfile") || die("$errfile: $!");
+print "Using $errfile\n";
+
+$start_degraded_mode = 0;
+
+$label = "";                                   # -w fodder
+$origsize = 0;                                 # -w fodder
+$idle_dumpers = 0;
+$status_driver = "";
+$status_taper = 0;
+$estimate_done = 0;
+$holding_space = 0;
+$start_time = 0;
+@dumpers_active = ();
+$nb_tape = 0;
+$ntpartition{$nb_tape} = 0;
+$ntsize{$nb_tape} = 0;
+$ntesize{$nb_tape} = 0;
+$tape_size = 0;
+$driver_finished = 0;
+$generating_schedule = 0;
+
+while($lineX = <AMDUMP>) {
+       chomp $lineX;
+       $lineX =~ s/[:\s]+$//g; #remove separator at end of line
+       next if $lineX eq "";
+       @line = &quotewords('[:\s]+', 0, $lineX);
+       next if !defined $line[0];
+
+       if($line[0] eq "amdump" || $line[0] eq "amflush") {
+               if ($line[1] eq "start" && $line[2] eq "at") {
+                       $datestr = $lineX;
+                       $datestr =~ s/.*start at //g;
+                       if (!defined $opt_locale_independent_date_format) {
+                               print "From " . $datestr . "\n";
+                       }
+               } elsif($line[1] eq "datestamp") {
+                       $gdatestamp = $line[2];
+                       if(!defined $datestamp{$gdatestamp}) {
+                               $datestamp{$gdatestamp} = 1;
+                               push @datestamp, $gdatestamp;
+                       }
+               } elsif($line[1] eq "starttime") {
+                       $starttime=&set_starttime($line[2]);
+               } elsif($line[1] eq "starttime-locale-independent") {
+                       if (defined $opt_locale_independent_date_format) {
+                               printf "From " . $line[2] . " " . $line[3] . ":" . $line[4] . ":" . $line[5] . " " . $line[6] . "\n";
+                       }
+               }
+               if($line[0] eq "amflush") {
+                       $estimate_done=1;
+               }
+       } elsif($line[0] eq "planner") {
+               if($line[1] eq "timestamp") {
+                       $gdatestamp = $line[2];
+                       if(!defined $datestamp{$gdatestamp}) {
+                               $datestamp{$gdatestamp} = 1;
+                               push @datestamp, $gdatestamp;
+                       }
+               }
+               elsif($line[1] eq "FAILED") {
+                       #2:host 3:disk 4:datestamp 5:level 6:errmsg
+                       $host=$line[2];
+                       $partition=$line[3];
+                       $datestamp=$line[4];
+                       $hostpart=&make_hostpart($host,$partition,$datestamp);
+                       $dump_started{$hostpart}=-1;
+                       $level{$hostpart}=$line[5];
+                       $error{$hostpart}="planner: " . $line[6];
+       } elsif($line[1] eq "time") {
+               if($line[3] eq "got") {
+                               if($line[4] eq "result") {
+                                       $host = $line[7];
+                                       $partition = $line[9];
+                                       $hostpart=&make_hostpart($host,$partition,$gdatestamp);
+                                       $estimate{$hostpart}=1;
+                                       $level{$hostpart}=$line[10];
+                                       $line[12] =~ /(\d+)K/;
+                                       $esize{$hostpart}=$1 / $unitdivisor;
+                                       $partialestimate{$hostpart}=0;
+                                       $getest{$hostpart} = "";
+                               } elsif($line[4] eq "partial") {
+                                       $host = $line[8];
+                                       $partition = $line[10];
+                                       $hostpart=&make_hostpart($host,$partition,$gdatestamp);
+                                       $level1 = $line[11];
+                                       $line[13] =~ /(-?\d+)K/;
+                                       $size1 = $1;
+                                       $level2 = $line[14];
+                                       $line[16] =~ /(-?\d+)K/;
+                                       $size2 = $1;
+                                       $level3 = $line[17];
+                                       $line[19] =~ /(-?\d+)K/;
+                                       $size3 = $1;
+                                       if($size1 > 0 || $size2 > 0 || $size3 > 0) {
+                                               $estimate{$hostpart}=1;
+                                               $level{$hostpart}=$line[11];
+                                               $esize{$hostpart}=$size1 / $unitdivisor;
+                                               $partialestimate{$hostpart}=1;
+                                               if($size1 > 0) { $getest{$hostpart} =~ s/:$level1://; }
+                                               if($size2 > 0) { $getest{$hostpart} =~ s/:$level2://; }
+                                               if($size3 > 0) { $getest{$hostpart} =~ s/:$level3://; }
+                                               if($getest{$hostpart} eq "") {$partialestimate{$hostpart}=0;}
+                                       }
+                               }
+                       } elsif($line[3] eq "getting" &&
+                                         $line[4] eq "estimates" &&
+                                         $line[5] eq "took") {
+                               $estimate_done=1;
+                       }
+               }
+       } elsif($line[0] eq "setup_estimate") {
+               $host = $line[1];
+               $partition = $line[2];
+               $hostpart=&make_hostpart($host,$partition,$gdatestamp);
+               $estimate{$hostpart}=0;
+               $level{$hostpart}=0;
+               $degr_level{$hostpart}=-1;
+               $esize{$hostpart}=0;
+               $dump_started{$hostpart}=0;
+               $dump_finished{$hostpart}=0;
+               $taper_started{$hostpart}=0;
+               $taper_finished{$hostpart}=0;
+               $partialestimate{$hostpart}=0;
+               $error{$hostpart}="";
+               if($line[7] eq "last_level") {
+                       $getest{$hostpart}="";
+                       $level1 = $line[15];
+                       $level2 = $line[17];
+                       $level3 = $line[19];
+                       if($level1 != -1) { $getest{$hostpart} .= ":$level1:" };
+                       if($level2 != -1) { $getest{$hostpart} .= ":$level2:" };
+                       if($level3 != -1) { $getest{$hostpart} .= ":$level3:" };
+               }
+       } elsif($line[0] eq "GENERATING" &&
+                               $line[1] eq "SCHEDULE") {
+               $generating_schedule=1;
+       } elsif($line[0] eq "--------") {
+               if ($generating_schedule == 1) {
+                       $generating_schedule = 2;
+               } elsif ($generating_schedule == 2) {
+                       $generating_schedule = 3;
+               }
+       } elsif($line[0] eq "DUMP") {
+               if($generating_schedule == 2 ) {
+                       $host = $line[1];
+                       $partition = $line[3];
+                       $datestamp = $line[4];
+                       $hostpart=&make_hostpart($host,$partition,$datestamp);
+                       $level{$hostpart}=$line[6];
+                       $esize=$line[14];       #compressed size
+                       $esize=32 if $esize<32;
+                       $esize{$hostpart}=$esize / $unitdivisor;
+                       if(!defined($line[22])) {
+                               $degr_level{$hostpart}=-1;
+                       } else {
+                               $degr_level{$hostpart}=$line[18];
+                               $esize=$line[25];       #compressed size
+                               $esize=32 if $esize<32;
+                               $degr_size{$hostpart}=$esize / $unitdivisor;
+                       }
+               }
+       } elsif($line[0] eq "FLUSH") {
+               $host = $line[1];
+               $partition = $line[2];
+               $datestamp = $line[3];
+               $level = $line[4];
+               $holding_file = $line[5];
+               $hostpart=&make_hostpart($host,$partition,$datestamp);
+               $flush{$hostpart}=0;
+               $holding_file{$hostpart}=$holding_file;
+               $level{$hostpart}=$level;
+       } elsif($line[0] eq "driver") {
+               if($line[1] eq "start" && $line[2] eq "time") {
+                       $start_time=$line[3];
+                       $current_time=$line[3];
+                       $dumpers_active[0]=0;
+                       $dumpers_held[0]={};
+                       $dumpers_active=0;
+               }
+               elsif($line[1] eq "tape" && $line[2] eq "size") {
+                       $lineX =~ /^driver: start time (\S+)/;
+                       $tape_size = $line[3] / $unitdivisor;
+               }
+               elsif($line[1] eq "adding" &&
+                          $line[2] eq "holding" &&
+                               $line[3] eq "disk") {
+                       $holding_space += $line[8];
+               }
+               elsif($line[1] eq "send-cmd" && $line[2] eq "time") {
+                       #print "send-cmd: " , $line[5] . " " . $line[6] . " " . $line[7] . "\n" if defined $line[5] && defined $line[6] && defined $line[7];
+                       $current_time = $line[3];
+                       if($line[5] =~ /dumper\d*/) {
+                               $dumper = $line[5];
+                               if($line[6] eq "PORT-DUMP") {
+                                       #7:handle 8:port 9:host 10:amfeatures 11:disk 12:device 13:level ...
+                                       $host = $line[9];
+                                       $partition = $line[11];
+                                       $hostpart=&make_hostpart($host,$partition,$gdatestamp);
+                                       $serial=$line[7];
+                                       $dump_started{$hostpart}=1;
+                                       $dump_time{$hostpart}=$current_time;
+                                       $dump_finished{$hostpart}=0;
+                                       if(     $level{$hostpart} != $line[13] &&
+                                          $degr_level{$hostpart} == $line[13]) {
+                                               $level{$hostpart}=$degr_level{$hostpart};
+                                               $esize{$hostpart}=$degr_size{$hostpart};
+                                       }
+                                       if(! defined($busy_time{$dumper})) {
+                                               $busy_time{$dumper}=0;
+                                       }
+                                       $running_dumper{$dumper} = $hostpart;
+                                       $error{$hostpart}="";
+                                       $size{$hostpart} = 0;
+                                       $dumpers_active++;
+                                       if(! defined($dumpers_active[$dumpers_active])) {
+                                               $dumpers_active[$dumpers_active]=0;
+                                       }
+                                       if(! defined($dumpers_held[$dumpers_active])) {
+                                               $dumpers_held[$dumpers_active]={};
+                                       }
+                               }
+                       }
+                       elsif($line[5] =~ /chunker\d*/) {
+                               if($line[6] eq "PORT-WRITE") {
+                                       $host=$line[9];
+                                       $partition=$line[11];
+                                       $hostpart=&make_hostpart($host,$partition,$gdatestamp);
+                                       $serial=$line[7];
+                                       $serial{$serial}=$hostpart;
+                                       $holding_file{$hostpart}=$line[8];
+                                       #$chunk_started{$hostpart}=1;
+                                       $chunk_time{$hostpart}=$current_time;
+                                       #$chunk_finished{$hostpart}=0;
+                               }
+                               elsif($line[6] eq "CONTINUE") {
+                                       #7:handle 8:filename 9:chunksize 10:use
+                                       $serial=$line[7];
+                                       $hostpart=$serial{$serial};
+                                       if($hostpart ne "") {
+                                               $dump_roomq{$hostpart}=undef;
+                                               $error{$hostpart}="";
+                                       }
+                               }
+                       }
+                       elsif($line[5] =~ /taper/) {
+                               if($line[6] eq "START-TAPER") {
+                                       #7:timestamp
+                                       $gdatestamp=$line[7];
+                                       if(!defined $datestamp{$gdatestamp}) {
+                                               $datestamp{$gdatestamp} = 1;
+                                               push @datestamp, $gdatestamp;
+                                       }
+                               }
+                               elsif($line[6] eq "FILE-WRITE") {
+                                       #7:handle 8:filename 9:host 10:disk 11:level 12:datestamp 13:splitsize
+                                       $serial=$line[7];
+                                       $host=$line[9];
+                                       $partition=$line[10];
+                                       $level=$line[11];
+                                       $ldatestamp=$line[12];
+                                       if(!defined $datestamp{$ldatestamp}) {
+                                               $datestamp{$ldatestamp} = 1;
+                                               push @datestamp, $ldatestamp;
+                                       }
+                                       $hostpart=&make_hostpart($host,$partition,$ldatestamp);
+                                       $serial{$serial}=$hostpart;
+                                       if(!defined $level{$hostpart}) {
+                                               $level{$hostpart} = $level;
+                                       }
+                                       $taper_started{$hostpart}=1;
+                                       $taper_finished{$hostpart}=0;
+                                       $taper_time{$hostpart}=$current_time;
+                                       $ntchunk_size = 0;
+                               }
+                               elsif($line[6] eq "PORT-WRITE") {
+                                       #7:handle 8:host 9:disk 10:level 11:datestamp 12:splitsize 13:diskbuffer 14:fallback_splitsize
+                                       $serial=$line[7];
+                                       $host=$line[8];
+                                       $partition=$line[9];
+                                       $level=$line[10];
+                                       $ldatestamp=$line[11];
+                                       $hostpart=&make_hostpart($host,$partition,$ldatestamp);
+                                       $serial{$serial}=$hostpart;
+                                       $taper_started{$hostpart}=1;
+                                       $taper_finished{$hostpart}=0;
+                                       $taper_time{$hostpart}=$current_time;
+                                       $ntchunk_size = 0;
+                               }
+                       }
+               }
+               elsif($line[1] eq "result" && $line[2] eq "time") {
+                       #print "result: " , $line[5] . " " . $line[6] . " " . $line[7] . "\n" if defined $line[5] && defined $line[6] && defined $line[7];
+                       $current_time = $line[3];
+                       if($line[5] =~ /dumper\d+/) {
+                               if($line[6] eq "FAILED" || $line[6] eq "TRY-AGAIN") {
+                                       #7:handle 8:message
+                                       $serial = $line[7];
+                                       $error = $line[8];
+                                       $hostpart=$serial{$serial};
+                             $dump_finished{$hostpart}=-1;
+                                       $busy_time{$line[5]}+=($current_time-$dump_time{$hostpart});
+                             $running_dumper{$line[5]} = "0";
+                             $dump_time{$hostpart}=$current_time;
+                             $error{$hostpart}="dumper: $error";
+                             $dumpers_active--;
+
+                               }
+                               elsif($line[6] eq "DONE") {
+                                       #7:handle 8:origsize 9:size ...
+                                       $serial=$line[7];
+                                       $origsize=$line[8] / $unitdivisor;
+                                       $outputsize=$line[9] / $unitdivisor;
+                                       $hostpart=$serial{$serial};
+                                       $size{$hostpart}=$outputsize;
+                                       $dump_finished{$hostpart}=1;
+                                       $busy_time{$line[5]}+=($current_time-$dump_time{$hostpart});
+                                       $running_dumper{$line[5]} = "0";
+                                       $dump_time{$hostpart}=$current_time;
+                                       $error{$hostpart}="";
+                                       $dumpers_active--;
+                               }
+                               elsif($line[6] eq "ABORT-FINISHED") {
+                                       #7:handle
+                                       $serial=$line[7];
+                                       $hostpart=$serial{$serial};
+                                       $dump_started{$hostpart}=0;
+                                       $dump_finished{$hostpart}=0;
+                                       $busy_time{$line[5]}+=($current_time-$dump_time{$hostpart});
+                                       $running_dumper{$line[5]} = "0";
+                                       $dump_time{$hostpart}=$current_time;
+                                       $error{$hostpart}="dumper: (aborted)";
+                                       $dumpers_active--;
+                               }
+                       }
+                       elsif($line[5] =~ /chunker\d+/) {
+                               if($line[6] eq "DONE" || $line[6] eq "PARTIAL") {
+                                       #7:handle 8:size
+                                       $serial=$line[7];
+                                       $outputsize=$line[8] / $unitdivisor;
+                                       $hostpart=$serial{$serial};
+                                       $size{$hostpart}=$outputsize;
+                                       $dump_finished{$hostpart}=1;
+                                       $busy_time{$line[5]}+=($current_time-$chunk_time{$hostpart});
+                                       $running_dumper{$line[5]} = "0";
+                                       $chunk_time{$hostpart}=$current_time;
+                                       $error{$hostpart}="";
+                                       if ($line[6] eq "PARTIAL") {
+                                               $partial{$hostpart} = 1;
+                                       }
+                                       else {
+                                               $partial{$hostpart} = 0;
+                                       }
+                               }
+                               elsif($line[6] eq "FAILED") {
+                                       $serial=$line[7];
+                                       $hostpart=$serial{$serial};
+                                       $dump_finished{$hostpart}=-1;
+                                       $busy_time{$line[5]}+=($current_time-$chunk_time{$hostpart});
+                                       $running_dumper{$line[5]} = "0";
+                                       $chunk_time{$hostpart}=$current_time;
+                                       $error{$hostpart}="chunker: " .$line[8] if $error{$hostpart} eq "";
+                               }
+                               elsif($line[6] eq "RQ-MORE-DISK") {
+                                       #7:handle
+                                       $serial=$line[7];
+                                       $hostpart=$serial{$serial};
+                                       $dump_roomq{$hostpart}=1;
+                                       $error{$hostpart}="(waiting for holding disk space)";
+                               }
+                       }
+                       elsif($line[5] eq "taper") {
+                               if($line[6] eq "DONE" || $line[6] eq "PARTIAL") {
+                                       #7:handle 8:label 9:filenum 10:errstr
+                                       $serial=$line[7];
+                                       $label=$line[8];
+                                       $hostpart=$serial{$serial};
+                                       $line[10] =~ /sec (\S+) kb (\d+) kps/;
+                                       $size=$2 / $unitdivisor;
+                                       $taper_finished{$hostpart}=1;
+                                       $busy_time{"taper"}+=($current_time-$taper_time{$hostpart});
+                                       $taper_time{$hostpart}=$current_time;
+                                       if(!defined $size{$hostpart}) {
+                                               $size{$hostpart}=$size;
+                                       }
+                                       $ntpartition{$nb_tape}++;
+                                       $ntsize{$nb_tape} += $size{$hostpart} - $ntchunk_size;
+                                       if(defined $esize{$hostpart} && $esize{$hostpart} > 1) {
+                                               $ntesize{$nb_tape} += $esize{$hostpart} - $ntchunk_size;
+                                       }
+                                       else {
+                                               $ntesize{$nb_tape} += $size{$hostpart} - $ntchunk_size;
+                                       }
+                                       if ($line[6] eq "PARTIAL") {
+                                               $partial{$hostpart} = 1;
+                                       }
+                                       else {
+                                               $partial{$hostpart} = 0;
+                                       }
+                                       if ($ntchunk_size > 0) {
+                                               $ntchunk{$nb_tape}++;
+                                       }
+                               }
+                               elsif($line[6] eq "PARTDONE") {
+                                       #7:handle 8:label 9:filenum 10:ksize 11:errstr
+                                       $serial=$line[7];
+                                       $hostpart=$serial{$serial};
+                                       #$line[11] =~ /.*kb (\d*) kps/;
+                                       #$size=$1 / $unitdivisor;
+                                       $size=$line[10] / $unitdivisor;
+                                       $tapedsize{$hostpart} += $size;
+                                       $ntchunk{$nb_tape}++;
+                                       $ntsize{$nb_tape} += $size;
+                                       $ntesize{$nb_tape} += $size;
+                                       $ntchunk_size += $size;
+                               }
+                               elsif($line[6] eq "REQUEST-NEW-TAPE") {
+                                       #7:serial
+                                       $serial=$line[7];
+                                       $hostpart=$serial{$serial};
+                                       if (defined $hostpart) {
+                                               $error{$hostpart} = "waiting for a new tape";
+                                       }
+                               }
+                               elsif($line[6] eq "NEW-TAPE") {
+                                       #7:serial #8:label
+                                       $serial=$line[7];
+                                       $hostpart=$serial{$serial};
+                                       if (defined $hostpart) {
+                                               $error{$hostpart} = "";
+                                       }
+                               }
+                               elsif($line[6] eq "TRY-AGAIN" || $line[6] eq "TAPE-ERROR") {
+                                       #7:handle 8:errstr
+                                       $serial=$line[7];
+                                       $error=$line[8];
+                                       $hostpart=$serial{$serial};
+                                       if(defined $hostpart) {
+                                               $taper_finished{$hostpart}= $line[6] eq 'TAPE-ERROR' ? -2 : -1;
+                                               $busy_time{"taper"}+=($current_time-$taper_time{$hostpart});
+                                               $taper_time{$hostpart}=$current_time;
+                                               $error{$hostpart}="taper: $error";
+                                       }
+                               }
+                               elsif($line[6] eq "FAILED") {
+                                       #7:handle 8:INPUT- 9:TAPE- 10:input_message 11:tape_message
+                                  $serial=$line[7];
+                                       $hostpart=$serial{$serial};
+                                       if(defined $hostpart) {
+                                               if($line[9] eq "TAPE-ERROR") {
+                                                       $error=$line[11];
+                                                       $taper_finished{$hostpart} = -2;
+                                               }
+                                               else {
+                                                       $error=$line[10];
+                                                       $taper_finished{$hostpart} = -1;
+                                               }
+                                               $busy_time{"taper"}+=($current_time-$taper_time{$hostpart});
+                                               $taper_time{$hostpart}=$current_time;
+                                               $error{$hostpart}="$error";
+                                       }
+                               }
+                       }
+               }
+               elsif($line[1] eq "finished-cmd" && $line[2] eq "time") {
+                       $current_time=$line[3];
+                       if($line[4] =~ /dumper\d+/) {
+                       }
+               }
+               elsif($line[1] eq "dump" && $line[2] eq "failed") {
+                       #3:handle 4: 5: 6:"too many dumper retry"
+                       $serial=$line[3];
+                       $hostpart=$serial{$serial};
+                       $dump_started{$hostpart}=-1;
+                       $dump_finished{$hostpart}=-2;
+                       $error{$hostpart} .= "(" . $line[6] . ")";
+               }
+               elsif($line[1] eq "tape" && $line[2] eq "failed") {
+                       #3:handle 4: 5: 6:"too many dumper retry"
+                       $serial=$line[3];
+                       $hostpart=$serial{$serial};
+                       $taper_started{$hostpart}=-1;
+                       $taper_finished{$hostpart}=-2;
+                       $error{$hostpart} .= "(" . $line[6] . ")";
+               }
+               elsif($line[1] eq "state" && $line[2] eq "time") {
+                       #3:time 4:"free" 5:"kps" 6:free 7:"space" 8:space 9:"taper" 10:taper 11:"idle-dumpers" 12:idle-dumpers 13:"qlen" 14:"tapeq" 15:tapeq 16:"runq" 17:runq 18:"roomq" 19:roomq 20:"wakeup" 21:wakeup 22:"driver-idle" 23:driver-idle
+                       $current_time=$line[3];
+                       $status_taper=$line[10];
+                       $idle_dumpers=$line[12];
+
+                       $free{"kps"} = $line[6];
+                       $free{"space"} = $line[8];
+                       $qlen{"tapeq"} = $line[15];
+                       $qlen{"runq"} = $line[17];
+                       $qlen{"roomq"} = $line[19];
+
+                       if(defined($dumpers_active)) {
+                               if($status_driver ne "") {
+                                       $dumpers_active[$dumpers_active_prev]
+                                               +=$current_time-$state_time_prev;
+                                       $dumpers_held[$dumpers_active_prev]{$status_driver}
+                                               +=$current_time-$state_time_prev;
+                               }
+                               $state_time_prev=$current_time;
+                               $dumpers_active_prev=$dumpers_active;
+                               $status_driver=$line[16];
+                               if(! defined($dumpers_held[$dumpers_active]{$status_driver})) {
+                                       $dumpers_held[$dumpers_active]{$status_driver}=0;
+                               }
+                       }
+               }
+          elsif($line[1] eq "FINISHED") {
+                       $driver_finished = 1;
+               }
+       }
+       elsif($line[0] eq "dump") {
+               if($line[1] eq "of" &&
+                       $line[2] eq "driver" &&
+                       $line[3] eq "schedule" &&
+                       $line[4] eq "after" &&
+                       $line[5] eq "start" &&
+                       $line[6] eq "degraded" &&
+                       $line[7] eq "mode") {
+                       $start_degraded_mode=1;
+               }
+       }
+       elsif($line[0] eq "taper") {
+               if($line[1] eq "slot") {
+                       #2:slot 3:"wrote" 4:"label" 5:corrupted...
+                       $nb_tape++;
+                       $lineX =~ /wrote label `(\S*)'/;
+                       $label = $1;
+                       $ntlabel{$nb_tape} = $label;
+                       $ntpartition{$nb_tape} = 0;
+                       $ntsize{$nb_tape} = 0;
+                       $ntesize{$nb_tape} = 0;
+               }
+               elsif($line[1] eq "wrote") {
+                       #1:"wrote" 2:"label" 3:corrupted
+                       $nb_tape++;
+                       $lineX =~ /wrote label `(\S*)'/;
+                       $label = $1;
+                       $ntlabel{$nb_tape} = $label;
+                       $ntpartition{$nb_tape} = 0;
+                       $ntsize{$nb_tape} = 0;
+                       $ntesize{$nb_tape} = 0;
+               }
+       }
+   elsif($line[0] eq "splitting" &&
+                        $line[1] eq "chunk" &&
+                        $line[2] eq "that" &&
+                        $line[3] eq "started" &&
+                        $line[4] eq "at" &&
+                        $line[6] eq "after") {
+               $line[7] =~ /(\d*)kb/;
+               $size = $1;
+               $ntchunk{$nb_tape}++;
+          $ntsize{$nb_tape} += $size / $unitdivisor;
+               $ntesize{$nb_tape} += $size / $unitdivisor;
+               $ntchunk_size += $size / $unitdivisor;
+       }
+       else {
+               #print "Ignoring: $lineX\n";
+       }
+}
+
+close(AMDUMP);
+
+if(defined $current_time) {
+       for ($d = 0; $d < $#dumpers_active; $d++) {
+               $the_dumper = "dumper$d";
+               if(defined($running_dumper{$the_dumper}) &&
+                  $running_dumper{$the_dumper} ne "0") {
+                       $busy_time{$the_dumper}+=($current_time-$dump_time{$running_dumper{$the_dumper}});
+               }
+       }
+}
+
+print "\n";
+
+$nb_partition = 0;
+
+$epartition = 0;
+$estsize = 0;
+$fpartition = 0;
+$fsize = 0;
+$wpartition = 0;
+$wsize = 0;
+
+$flpartition = 0;
+$flsize = 0;
+$wfpartition = 0;
+$wfsize = 0;
+
+$dtpartition = 0;
+$dtesize = 0;
+$dupartition = 0;
+$dusize = 0;
+$duesize = 0;
+$dpartition = 0;
+$dsize = 0;
+$desize = 0;
+
+$twpartition = 0;
+$twsize = 0;
+$twesize = 0;
+$tapartition = 0;
+$tasize = 0;
+$taesize = 0;
+$tfpartition = 0;
+$tfsize = 0;
+$tfesize = 0;
+$tpartition = 0;
+$tsize = 0;
+$tesize = 0;
+
+$maxnamelength = 10;
+foreach $host (sort @hosts) {
+       foreach $partition (sort @$host) {
+               foreach $datestamp (sort @datestamp) {
+                       $hostpart=&make_hostpart($host,$partition,$datestamp);
+                       next if(!defined $estimate{$hostpart} && !defined $flush{$hostpart});
+                       if(length("$host:$partition") > $maxnamelength) {
+                               $maxnamelength = length("$host:$partition");
+                       }
+               }
+       }
+}
+
+foreach $host (sort @hosts) {
+       foreach $partition (sort @$host) {
+          foreach $datestamp (sort @datestamp) {
+                       $hostpart=&make_hostpart($host,$partition,$datestamp);
+                       next if(!defined $estimate{$hostpart} && !defined $flush{$hostpart});
+                       $nb_partition++;
+                       if( (!defined $size{$hostpart} || $size{$hostpart} == 0) &&
+                                defined $holding_file{$hostpart}) {
+                               $size{$hostpart} = &dump_size($holding_file{$hostpart}) / (1024 * $unitdivisor);
+                       }
+                       $in_flush=0;
+                       if($estimate_done != 1 && !defined $flush{$hostpart}) {
+                               if(defined $estimate{$hostpart}) {
+                                       if($estimate{$hostpart} != 1) {
+                                               if( defined $opt_gestimate) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s", "$host:$partition";
+                                                       print "              getting estimate\n";
+                                               }
+                                       }
+                                       else {
+                                               if(defined $opt_estimate ||
+                                                       (defined $opt_gestimate && $partialestimate{$hostpart} == 1)) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s", "$host:$partition";
+                                                       printf "%2d ",  $level{$hostpart};
+                                                       printf "%9d$unit", $esize{$hostpart};
+                                                       if($partialestimate{$hostpart} == 1) {
+                                                               print " partial";
+                                                       }
+                                                       print " estimate done\n";
+                                               }
+                                               $epartition++;
+                                               $estsize += $esize{$hostpart};
+                                       }
+                               }
+                       }
+                       else {
+                               if(defined $estimate{$hostpart}) {
+                                       if($estimate{$hostpart} == 1) {
+                                               $epartition++;
+                                               $estsize += $esize{$hostpart};
+                                       }
+                                       elsif (!defined $dump_started{$hostpart} || $dump_started{$hostpart} == 0) {
+                                               if( defined $opt_failed) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       printf "           no estimate\n";
+                                               }
+                                               $exit_status |= $STATUS_FAILED;
+                                               $fpartition++;
+                                               $fsize+=$esize{$hostpart};
+                                       }
+                               }
+                               else {
+                                       $flpartition++;
+                                       $flsize += $size{$hostpart};
+                                       $in_flush=1;
+                               }
+                               if(defined $taper_started{$hostpart} &&
+                                               $taper_started{$hostpart}==1) {
+                                       if(defined $dump_started{$hostpart}) {
+                                               $dpartition++;
+                                               if(defined($size{$hostpart})) {
+                                                       $dsize += $size{$hostpart};
+                                               }
+                                               else {
+                                                       $dsize += $esize{$hostpart};
+                                               }
+                                               $desize += $esize{$hostpart};
+                                       }
+                                       if(defined $dump_started{$hostpart} &&
+                                               $dump_started{$hostpart} == 1 &&
+                                                       $dump_finished{$hostpart} == -1) {
+                                               if(defined $opt_failed) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       printf "%9d$unit", $esize{$hostpart};
+                                                       print " dump to tape failed: " . $error{$hostpart};
+                                                       print "\n";
+                                               }
+                                               $exit_status |= $STATUS_FAILED;
+                                               $fpartition++;
+                                               $fsize+=$esize{$hostpart};
+                                       } elsif(defined $dump_started{$hostpart} &&
+                                               $dump_started{$hostpart} == 1 &&
+                                                       $dump_finished{$hostpart} == 0 &&
+                                                       $taper_started{$hostpart} == 1) {
+                                               if( defined $opt_dumpingtape ) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       printf "%9d$unit", $esize{$hostpart};
+                                                       print " dumping to tape";
+                                                       if( defined $starttime ) {
+                                                               print " (", &showtime($taper_time{$hostpart}), ")";
+                                                       }
+                                                       print "\n";
+                                               }
+                                               $dtpartition++;
+                                               $dtesize += $esize{$hostpart};
+                                       }
+                                       elsif($taper_finished{$hostpart} == 0) {
+                                               if( defined $opt_writingtape ) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       printf "%9d$unit", $size{$hostpart};
+                                                       if($in_flush == 0) {
+                                                               print " writing to tape";
+                                                       }
+                                                       else {
+                                                               print " flushing to tape";
+                                                       }
+                                                       if(defined($tapedsize{$hostpart})) {
+                                                               printf " (%d$unit done)", $tapedsize{$hostpart};
+                                                       }
+                                                       if( defined $starttime ) {
+                                                               print " (", &showtime($taper_time{$hostpart}), ")";
+                                                       }
+                                                       print ", ", $error{$hostpart} if defined($error{$hostpart} &&
+                                                                                                                                          $error{$hostpart} ne "");
+                                                       print "\n";
+                                               }
+                                               $tapartition++;
+                                               $tasize += $size{$hostpart};
+                                               if(defined $esize{$hostpart}) {
+                                                       $taesize += $esize{$hostpart};
+                                               }
+                                               else {
+                                                       $taesize += $size{$hostpart};
+                                               }
+                                       }
+                                       elsif($taper_finished{$hostpart} < 0) {
+
+                                               if(defined $size{$hostpart}) {
+                                                       $xsize = $size{$hostpart};
+                                               }
+                                               elsif(defined $esize{$hostpart}) {
+                                                       $xsize = $esize{$hostpart};
+                                               }
+                                               else {
+                                                       $xsize = 0;
+                                               }
+
+                                               if(defined $esize{$hostpart}) {
+                                                       $exsize += $esize{$hostpart};
+                                               }
+                                               else {
+                                                       $exsize += $xsize;
+                                               }
+
+                                               if( defined $opt_failed  ||
+                                                        (defined $opt_waittaper && ($taper_finished{$hostpart} == -1))) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       printf "%9d$unit", $xsize;
+                                                       if($in_flush == 0) {
+                                                               print " failed to tape";
+                                                       }
+                                                       else {
+                                                               print " failed to flush";
+                                                       }
+                                                       print ": ",$error{$hostpart} if defined $error{$hostpart};
+                                               
+                                                       print " (will retry)" unless $taper_finished{$hostpart} < -1;
+                                                       if( defined $starttime ) {
+                                                               print " (", &showtime($taper_time{$hostpart}), ")";
+                                                       }
+                                                       print "\n";
+                                               }
+                                               $exit_status |= $STATUS_TAPE;
+
+                                               $tfpartition++;
+                                               $tfsize += $xsize;
+                                               $tfesize += $exsize;
+
+                                               if($in_flush == 0) {
+                                                       $twpartition++;
+                                                       $twsize += $xsize;
+                                                       $twesize += $exsize;
+                                               }
+                                               else {
+                                                       $wfpartition++;
+                                                       $wfsize += $xsize;
+                                               }
+                                       }
+                                       elsif($taper_finished{$hostpart} == 1) {
+                                               if( defined $opt_finished ) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       printf "%9d$unit", $size{$hostpart};
+                                                       if($in_flush == 0) {
+                                                               print " finished";
+                                                       }
+                                                       else {
+                                                               print " flushed";
+                                                       }
+                                                       if( defined $starttime ) {
+                                                               print " (", &showtime($taper_time{$hostpart}), ")";
+                                                       }
+                                                       if(defined $partial{$hostpart} && $partial{$hostpart} == 1) {
+                                                               print ", PARTIAL";
+                                                               $exit_status |= $STATUS_FAILED;
+                                                       }
+                                                       print "\n";
+                                               }
+                                               $tpartition++;
+                                               $tsize += $size{$hostpart};
+                                               if(defined $esize{$hostpart} && $esize{$hostpart} > 1) {
+                                                       $tesize += $esize{$hostpart};
+                                               }
+                                               else {
+                                                       $tesize += $size{$hostpart};
+                                               }
+                                       }
+                                       else {
+                                               printf "%8s ", $datestamp if defined $opt_date;
+                                               printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                               print " unknown state TAPER\n";
+                                       }
+                               }
+                               elsif(defined $dump_started{$hostpart}) {
+                                       if($dump_started{$hostpart} == -1) {
+                                               if( defined $opt_failed ) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       printf " " . $error{$hostpart} . "\n";
+                                               }
+                                               $exit_status |= $STATUS_FAILED;
+
+                                               $fpartition++;
+                                               $fsize+=$esize{$hostpart};
+                                       }
+                                       elsif($dump_started{$hostpart} == 0) {
+                                               if($estimate{$hostpart} == 1) {
+                                                       if( defined $opt_waitdumping ) {
+                                                               printf "%8s ", $datestamp if defined $opt_date;
+                                                               printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                               printf "%9d$unit", $esize{$hostpart};
+                                                               print " wait for dumping $error{$hostpart}\n";
+                                                       }
+                                                       if($driver_finished == 1) {
+                                                               $exit_status |= $STATUS_MISSING;
+                                                       }
+                                                       $wpartition++;
+                                                       $wsize += $esize{$hostpart};
+                                               }
+                                       }
+                                       elsif($dump_started{$hostpart} == 1 &&
+                                                       $dump_finished{$hostpart} == -1) {
+                                               if( defined $opt_failed ) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       print " ", $error{$hostpart};
+                                                       if( defined $starttime ) {
+                                                               print " (", &showtime($dump_time{$hostpart}), ")";
+                                                       }
+                                                       print "\n";
+                                               }
+                                               $exit_status |= $STATUS_FAILED;
+                                               $fpartition++;
+                                               $fsize+=$esize{$hostpart};
+                                       }
+                                       elsif($dump_started{$hostpart} == 1 &&
+                                                       $dump_finished{$hostpart} != 1) {
+                                               if( defined $opt_dumping ) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       printf "%9d$unit", $esize{$hostpart};
+                                                       printf " dumping %8d$unit", $size{$hostpart};
+                                                       if($size{$hostpart} != 0) {
+                                                               printf " (%6.2f%%)", (100.0*$size{$hostpart})/$esize{$hostpart};
+                                                       }
+                                                       if( defined $starttime ) {
+                                                               print " (", &showtime($dump_time{$hostpart}), ")";
+                                                       }
+                                                       if(defined $dump_roomq{$hostpart}) {
+                                                               print " " . $error{$hostpart};
+                                                       }
+                                                       print "\n";
+                                               }
+                                               $dupartition++;
+                                               $dusize += $size{$hostpart};
+                                               $duesize += $esize{$hostpart};
+                                       }
+                                       elsif($dump_finished{$hostpart} == 1 &&
+                                                       $taper_started{$hostpart} != 1) {
+                                               if( defined $opt_waittaper ) {
+                                                       printf "%8s ", $datestamp if defined $opt_date;
+                                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                                       printf "%9d$unit", $size{$hostpart};
+                                                       print " dump done";
+                                                       if( defined $starttime ) {
+                                                               print " (", &showtime($dump_time{$hostpart}), ")";
+                                                       }
+                                                       print ", wait for writing to tape";
+                                                       if(defined $partial{$hostpart} && $partial{$hostpart} == 1) {
+                                                               print ", PARTIAL";
+                                                               $exit_status |= $STATUS_FAILED;
+                                                       }
+                                                       print "\n";
+                                               }
+                                               $dpartition++;
+                                               $dsize += $size{$hostpart};
+                                               $desize += $esize{$hostpart};
+                                               $twpartition++;
+                                               $twsize += $size{$hostpart};
+                                               $twesize += $esize{$hostpart};
+                                       }
+                                       else {
+                                               printf "%8s ", $datestamp if defined $opt_date;
+                                               printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                               print " unknown state DUMPER\n";
+                                       }
+                               }
+                               elsif(defined $flush{$hostpart}) {
+                                       if( defined $opt_waittaper ) {
+                                               printf "%8s ", $datestamp if defined $opt_date;
+                                               printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                               printf "%9d$unit", $size{$hostpart};
+                                               print " waiting to flush";
+                                               if(defined $partial{$hostpart} && $partial{$hostpart} == 1) {
+                                                       print ", PARTIAL";
+                                                       $exit_status |= $STATUS_FAILED;
+                                               }
+                                               print "\n";
+                                       }
+                                       $wfpartition++;
+                                       $wfsize += $size{$hostpart};
+                               }
+                               elsif(defined $level{$hostpart}) {
+                                       printf "%8s ", $datestamp if defined $opt_date;
+                                       printf "%-${maxnamelength}s%2d ", "$host:$partition", $level{$hostpart};
+                                       print " unknown state\n";
+                               }
+                       }
+               }
+       }
+}
+
+if (defined $opt_summary) {
+       print "\n";
+       print  "SUMMARY          part      real  estimated\n";
+       print  "                           size       size\n";
+       printf "partition       : %3d\n", $nb_partition;
+       printf "estimated       : %3d %20d$unit\n", $epartition , $estsize;
+       printf "flush           : %3d %9d$unit\n", $flpartition, $flsize;
+       printf "failed          : %3d %20d$unit           (%6.2f%%)\n",
+               $fpartition , $fsize,
+               $estsize ? ($fsize * 1.0 / $estsize) * 100 : 0.0;
+       printf "wait for dumping: %3d %20d$unit           (%6.2f%%)\n",
+               $wpartition , $wsize,
+               $estsize ? ($wsize * 1.0 / $estsize) * 100 : 0.0;
+       printf "dumping to tape : %3d %20d$unit           (%6.2f%%)\n",
+               $dtpartition, $dtesize,
+               $estsize ? ($dtesize * 1.0 / $estsize) * 100 : 0.0;
+       printf "dumping         : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
+               $dupartition, $dusize, $duesize,
+               $duesize ? ($dusize * 1.0 / $duesize) * 100 : 0.0,
+               $estsize ? ($dusize * 1.0 / $estsize) * 100 : 0.0;
+       printf "dumped          : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
+               $dpartition , $dsize , $desize,
+               $desize ? ($dsize * 1.0 / $desize) * 100 : 0.0,
+               $estsize ? ($dsize * 1.0 / $estsize) * 100 : 0.0;
+       printf "wait for writing: %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
+               $twpartition, $twsize, $twesize,
+               $twesize ? ($twsize * 1.0 / $twesize) * 100 : 0.0,
+               $estsize ? ($twsize * 1.0 / $estsize) * 100 : 0.0;
+       printf "wait to flush   : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
+               $wfpartition, $wfsize, $wfsize, 100, 0;
+       printf "writing to tape : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
+               $tapartition, $tasize, $taesize,
+               $taesize ? ($tasize * 1.0 / $taesize) * 100 : 0.0,
+               $estsize ? ($tasize * 1.0 / $estsize) * 100 : 0.0;
+       printf "failed to tape  : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
+               $tfpartition, $tfsize, $tfesize,
+               $tfesize ? ($tfsize * 1.0 / $tfesize) * 100 : 0.0,
+               $estsize ? ($tfsize * 1.0 / $estsize) * 100 : 0.0;
+       printf "taped           : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
+               $tpartition , $tsize , $tesize,
+               $tesize ? ($tsize * 1.0 / $tesize) * 100 : 0.0,
+               ($estsize+$flsize) ? ($tsize * 1.0 / ($estsize + $flsize)) * 100 : 0.0;
+       if($nb_tape > 1 || $tape_size != 0) {
+               for($i=1; $i <= $nb_tape; $i++) {
+                       if($tape_size != 0) {
+                               printf "  tape %-3d      : %3d %9d$unit %9d$unit (%6.2f%%) %s",
+                                       $i, $ntpartition{$i}, $ntsize{$i}, $ntesize{$i}, 100*$ntsize{$i}/$tape_size, $ntlabel{$i};
+                       }
+                       else {
+                               printf "  tape %-3d      : %3d %9d$unit %9d$unit %s",
+                                       $i, $ntpartition{$i}, $ntsize{$i}, $ntesize{$i}, $ntlabel{$i};
+                       }
+                       if(defined($ntchunk{$i}) && $ntchunk{$i} > 0) {
+                               printf " (%d chunks)", $ntchunk{$i};
+                       }
+                       print "\n";
+               }
+       }
+       if($idle_dumpers == 0) {
+               printf "all dumpers active\n";
+       }
+       else {
+               $c1 = ($idle_dumpers == 1) ? "" : "s";
+               $c2 = ($idle_dumpers < 10) ? " " : "";
+               $c3 = ($idle_dumpers == 1) ? " " : "";
+               printf "%d dumper%s idle%s %s: %s\n", $idle_dumpers, $c1, $c2, $c3, $status_driver;
+       }
+       if($status_taper eq "writing" && defined($qlen{"tapeq:"})) {
+               printf "taper writing, tapeq: %d\n", $qlen{"tapeq:"};
+       }
+       else {
+               printf "taper idle\n";
+       }
+       if (defined ($free{"kps:"})) {
+               printf "network free kps: %9d\n", $free{"kps:"};
+       }
+       if (defined ($free{"space:"})) {
+               if ($holding_space) {
+                       $hs = ($free{"space:"} * 1.0 / $holding_space) * 100;
+               } else {
+                       $hs = 0.0;
+               }
+               printf "holding space   : %9d$unit (%6.2f%%)\n", ($free{"space:"}/$unitdivisor), $hs;
+       }
+}
+
+if(defined $opt_stats) {
+       if(defined($current_time) && $current_time != $start_time) {
+               $total_time=$current_time-$start_time;
+               foreach $key (sort byprocess keys %busy_time) {
+                       printf "%8s busy   : %8s  (%6.2f%%)\n",
+                               $key, &busytime($busy_time{$key}),
+                               ($busy_time{$key} * 1.0 / $total_time) * 100;
+               }
+               for ($d = 0; $d <= $#dumpers_active; $d++) {
+                       $l = sprintf "%2d dumper%s busy%s : %8s  (%6.2f%%)",
+                               $d, ($d == 1) ? "" : "s", ($d == 1) ? " " : "",
+                               &busytime($dumpers_active[$d]),
+                               ($dumpers_active[$d] * 1.0 / $total_time) * 100;
+                       print $l;
+                       $s1 = "";
+                       $s2 = " " x length($l);
+                       $r = $dumpers_held[$d];
+                       foreach $key (sort valuesort keys %$r) {
+                               next
+                                 unless $dumpers_held[$d]{$key} >= 1;
+                               printf "%s%20s: %8s  (%6.2f%%)\n",
+                                       $s1,
+                                       $key,
+                                       &busytime($dumpers_held[$d]{$key}),
+                                       ($dumpers_held[$d]{$key} * 1.0 / $dumpers_active[$d]) * 100;
+                               $s1 = $s2;
+                       }
+                       if ($s1 eq "") {
+                               print "\n";
+                       }
+               }
+       }
+}
+
+exit $exit_status;
+
+sub make_hostpart() {
+       local($host,$partition,$datestamp) = @_;
+
+       if(! defined($hosts{$host})) {
+               push @hosts, $host;
+               $hosts{$host}=1;
+       }
+       my($new_part) = 1;
+       foreach $pp (sort @$host) {
+               $new_part = 0 if ($pp eq $partition);
+       }
+       push @$host, $partition if $new_part==1;
+
+       my($hostpart) = "$host$partition$datestamp";
+       if(!defined $datestamp{$datestamp}) {
+               $datestamp{$datestamp} = 1;
+               push @datestamp, $datestamp;
+       }
+
+       return $hostpart;
+}
+
+sub byprocess() {
+       my(@tmp_a) = split(/(\d*)$/, $a, 2);
+       my(@tmp_b) = split(/(\d*)$/, $b, 2);
+       return ($tmp_a[0] cmp $tmp_b[0]) || ($tmp_a[1] <=> $tmp_b[1]);
+}                               
+sub valuesort() {
+       $r->{$b} <=> $r->{$a};
+}
+
+sub dump_size() {
+       local($filename) = @_;
+       local($size);
+       local($dsize) = 0;
+       local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+                  $atime,$mtime,$ctime,$blksize,$blocks);
+       while ($filename ne "") {
+               $filename = "$filename.tmp" if (!(-e "$filename"));
+               $filename = "/dev/null" if (!(-e "$filename"));
+               ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+                               $atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
+               $size=$size-32768 if $size > 32768;
+               $dsize += $size;
+               open(DUMP,$filename);
+               $filename = "";
+               while(<DUMP>) {
+                       if(/^CONT_FILENAME=(.*)$/) { $filename = $1; last }
+                       last if /^To restore, position tape at start of file and run/;
+               }
+               close(DUMP);
+       }
+       return $dsize;
+}
+
+sub unctime() {
+       my (@MoY);
+       my (@tl);
+       my ($a);
+       my ($m);
+       my ($month);
+       my ($time);
+
+       @MoY = ('Jan','Feb','Mar','Apr','May','Jun',
+               'Jul','Aug','Sep','Oct','Nov','Dec');
+
+       # Preset an array of values in case some parts are not passed as
+       # arguments.  This lets the date, etc, be omitted and default to
+       # today.
+
+       @tl = localtime;
+
+       foreach $a (@_) {
+               next
+                 if ($a eq '');
+
+               # See if this argument looks like a month name.
+
+               $month = 0;
+               foreach $m (@MoY) {
+                       last
+                         if ($m eq $a);
+                       $month = $month + 1;
+               }
+               if ($month < 12) {
+                       $tl[4] = $month;
+                       next;
+               }
+
+               # See if this is a day of the month.
+
+               if ($a =~ /^\d+$/ && $a >= 1 && $a <= 32) {
+                       $tl[3] = $a;
+                       next;
+               }
+
+               # See if the next argument looks like a time.
+
+               if ($a =~ /^(\d+):(\d+)/) {
+                       $tl[2] = $1;
+                       $tl[1] = $2;
+                       if ($a =~ /^(\d+):(\d+):(\d+)/) {
+                               $tl[0] = $3;
+                       }
+                       next;
+               }
+
+               # See if this is a year.
+
+               if ($a =~ /^\d\d\d\d$/ && $a >= 1900) {
+                       $tl[5] = $a;
+                       next;
+               }
+       }
+
+       $time = &timelocal (@tl);
+
+       return $time;
+}
+
+sub set_starttime() {
+       my (@tl);
+       my ($time);
+       my ($date);
+
+       # Preset an array of values in case some parts are not passed as
+       # arguments.  This lets the date, etc, be omitted and default to
+       # today.
+
+       ($date)=@_;
+       @tl = localtime;
+
+       $tl[5] = substr($date,  0, 4)   if(length($date) >= 4);
+       $tl[4] = substr($date,  4, 2)-1 if(length($date) >= 6);
+       $tl[3] = substr($date,  6, 2)   if(length($date) >= 8);
+       $tl[2] = substr($date,  8, 2)   if(length($date) >= 10);
+       $tl[1] = substr($date, 10, 2)   if(length($date) >= 12);
+       $tl[0] = substr($date, 12, 2)   if(length($date) >= 14);
+
+       $time = &timelocal (@tl);
+
+       return $time;
+}
+
+
+sub showtime() {
+       my($delta)=shift;
+       my($oneday)=24*60*60;
+
+       @now=localtime($starttime+$delta);
+       if($delta > $oneday) {
+               $result=sprintf("%d+",$delta/$oneday);
+       } else {
+               $result="";
+       }
+       $result.=sprintf("%d:%02d:%02d",$now[2],$now[1],$now[0]);
+       return $result;
+}
+
+sub busytime() {
+       my($busy)=shift;
+       my($oneday)=24*60*60;
+
+       if($busy > $oneday) {
+               $days=int($busy/$oneday);
+               $result=sprintf("%d+",$busy/$oneday);
+               $busy-=$days*$oneday;
+       } else {
+               $result="";
+       }
+       $hours=int($busy/60/60);
+       $busy-=$hours*60*60;
+       $minutes=int($busy/60);
+       $busy-=$minutes*60;
+       $seconds=$busy;
+       $result.=sprintf("%d:%02d:%02d",$hours,$minutes,$seconds);
+       return $result;
+}
+
+sub usage() {
+       print "amstatus [--config] config [--file amdump_file]\n";
+       print "         [--summary] [--dumping] [--waitdumping] [--waittaper]\n";
+       print "         [--dumpingtape] [--writingtape] [--finished] [--failed]\n";
+       print "         [--estimate] [--gestimate] [--stats] [--date] [--locale-independent-date-format]\n";
+       exit 0;
+}
diff --git a/server-src/amtoc.pl b/server-src/amtoc.pl
new file mode 100644 (file)
index 0000000..79d0757
--- /dev/null
@@ -0,0 +1,257 @@
+#!@PERL@ -w
+
+# create a TOC (Table Of Content) file for an amanda dump
+
+# Author: Nicolas.Mayencourt@cui.unige.ch
+
+# release 3.1.4
+
+# HISTORY
+# 1.0 19??-??-?? nicolas@cui.unige.ch
+#      don't remember :-)
+# 2.0 1996-??-?? nicolas@cui.unige.ch
+#      amanda 2.2.6 support
+# 3.0 1999-02-17 Nicolas.Mayencourt@cui.unige.ch
+#      major rewrite, incompatible with release 2.0, amanda 2.4 support
+# 3.0.1 1999-02-17 oliva@dcc.unicamp.br
+#      minor fixes for multi-tape runs
+# 3.0.2 1999-02-28 martineau@IRO.UMontreal.CA
+#      output the datestamp of each dump
+# 3.0.3 1999-09-01 jrj@purdue.edu
+#      allow multiple -s entries
+# 3.0.4 1999-09-15 jrj@purdue.edu
+#      handle an image failing on one tape...
+# 3.1.0 1999-10-06 Nicolas.Mayencourt@cui.unige.ch
+#      add new options (-i -t)
+# 3.1.1 1999-10-08 Nicolas.Mayencourt@cui.unige.ch
+#      print original size, instead of size-on-tape
+# 3.1.2 1999-10-11 Nicolas.Mayencourt@cui.unige.ch
+#      really print original size, instead of size-on-tape
+# 3.1.3 Nicolas.Mayencourt@cui.unige.ch
+#      correct a bug for total report
+# 3.1.4 2000-01-14 dhw@whistle.com
+#      Add a flag (-w) for vertical whitespace
+
+
+#--------------------------------------------------------
+sub pr($$$$$$$) { 
+# you can update these proc if you want another formating
+# format: filenumber  host:part  date  level  size
+# If you use tabular option, modifie the format at the end of the code
+  if (defined($tabular)) {
+       $fnbr=$_[0];
+       $hstprt=$_[1] . ":" . $_[2];
+       $dt=$_[3];
+       $lvl=$_[4];
+       $sz=$_[5];
+       $ch=$_[6];
+    write($OF);
+  } else {
+    print $OF "$_[0]  $_[1]:$_[2]  $_[3]  $_[4]  $_[5]  $_[6]\n";
+  }
+}
+#--------------------------------------------------------
+
+
+
+#--------------------------------------------------------
+sub tfn($) {
+  # calculate tocfilename
+  $_ = $_[0];
+  foreach $s (@subs) {
+    eval $s;
+  }
+  return $dir . $_ ;
+}
+#--------------------------------------------------------
+
+
+#--------------------------------------------------------
+sub usage($) {
+  print STDERR "@_\n\n";
+  print STDERR "usage: amtoc [-a] [-i] [-t] [-f file] [-s subs] [-w] [--] logfile\n";
+  print STDERR "         -a      : file output to `label`.toc\n";
+  print STDERR "         -i      : Start TOC with a small help message\n";
+  print STDERR "         -t      : tabular output\n";
+  print STDERR "         -f file : output to file\n";
+  print STDERR "         -s subs : output file name evaluated to `eval \$subs`\n";
+  print STDERR "         -w      : add vertical whitespace after each tape\n";
+  print STDERR "         --      : last option\n";
+  print STDERR "         logfile : input file ('-' for stdin)\n";
+  exit;
+}
+#--------------------------------------------------------
+
+#--------------------------------------------------------
+sub init() {
+  &usage("amtoc required at least 'logfile' parameter.") if ($#ARGV==-1) ;
+
+  @subs = ();
+  for ($i=0;$i<=$#ARGV;$i++) {
+    if ($ARGV[$i] eq '-a') {
+        push (@subs, "s/\$/.toc/");
+      }
+    elsif ($ARGV[$i] eq '-i') {
+        $info=1;
+      }
+    elsif ($ARGV[$i] eq '-t') {
+        $tabular=1;
+      }
+    elsif ($ARGV[$i] eq '-f') {
+        $i++;
+        &usage("'-f' option require 'file' parameter.")  if ($i > $#ARGV);
+        $tocfilename=$ARGV[$i];
+      }
+    elsif ($ARGV[$i] eq '-s') {
+        $i++;
+        &usage("'-s' option require 'subs' parameter.")  if ($i > $#ARGV);
+        push (@subs, $ARGV[$i]);
+      }
+    elsif ($ARGV[$i] eq '-w') {
+        $vwspace=1;
+      }
+    elsif ($ARGV[$i] eq '--') {
+      # no more options: next arg == logfile
+        $i++;
+        &usage("amtoc required at least 'logfile' parameter.") if ($i > $#ARGV);
+        $logfile=$ARGV[$i];
+        &usage("too many parameters.") unless ($i == $#ARGV);
+      }
+    else {
+        $logfile=$ARGV[$i];
+        &usage("too many parameters.") unless ($i == $#ARGV);
+      }
+  }
+  &usage("amtoc required at least 'logfile' parameter.") unless ($logfile);
+}
+
+#--------------------------------------------------------
+
+&init;
+
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
+$ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin";
+
+$dir=$logfile;
+$dir =~ s/[^\/]*$//;
+
+
+if ($logfile eq '-') {$IF=STDIN} else 
+  {die ("Cannot open logfile $logfile") unless open (IF,"$logfile");$IF=IF;}
+
+$filenumber=0;
+$tot_or_size=0;
+
+while ( <$IF> ) {
+  $line = $_;
+  if ( /^FAIL dumper (\S+) (\S+)/ ) {
+    next;
+  }
+  if ( /^SUCCESS dumper (\S+) (\S+)/ ) {
+    $host = $1;
+    $disk = $2;
+    $line =~ /orig-kb (\d+)/;
+    $osize{$host}{$disk} = $1;
+    $tot_or_size += $osize{$host}{$disk};
+    $fail{$host}{$disk} = 0;
+    next;
+  }
+  if ( /^START amflush/ ) {
+    $flash_mode = 1;
+    next;
+  }
+  if ( ! /^([A-Z]+) taper (\S+) (\S+) (\S+) (\S+) (\S+)/) { next;}
+  # $_ = $1;
+  $host = $2;
+  $disk = $3;
+  $date = $4;
+  $chunk = $5;
+  $level = $6;
+  switch: {
+    /START taper/ && do {
+      $tocfilename=&tfn($chunk) if ($#subs >= 0);
+      if (!$tocfilename || ($tocfilename eq '-')) {$OF=STDOUT;}
+      else {
+          die ("Cannot open tocfile $tocfilename") unless open(OF,">$tocfilename");
+          $OF=OF;
+        }
+
+       print $OF "\f" if ($vwspace && $filenumber);
+       if (defined($info)) {
+         print $OF "AMANDA: To restore:\n";
+         print $OF "    position tape at start of file and run:\n";
+         print $OF "        dd if=<tape> bs=32k skip=1 [ | zcat ] | restore -...f\n";
+         print $OF "    or run: amrestore -p <tape> [host [partition]] | restore -...f\n";
+         print $OF "\n";
+       }
+
+
+
+      $filenumber=0;
+      &pr("#","Server","/partition","date", "level","size[Kb]","part");
+      &pr("$filenumber","$chunk","","$disk","-","-","-");
+      last switch; };
+    /^(?:SUCCESS|CHUNK) taper/ && do {
+      if(/SUCCESS/){
+       $level = $chunk;
+       $chunk = "-";
+      }
+      $mysize = 0;
+      if(/ kb (\d+) /){
+       $mysize = $1;
+      }
+      if ( $fail{$host}{$disk} ) {
+        &pr("$filenumber","${host}","${disk}","${date}","${level}","FAIL","${chunk}");
+      } else {
+       if (defined($flash_mode)) {
+          &pr("$filenumber","${host}","${disk}","${date}","${level}","$mysize","${chunk}");
+       } else {
+         if (defined($osize{$host}{$disk}) && !/^CHUNK/) {
+            &pr("$filenumber","${host}","${disk}","${date}","${level}","$osize{$host}{$disk}","${chunk}");
+         } else {
+           $note = "";
+           if(!/^CHUNK/){
+               # this case should never happend: 
+           $strange=1;
+             $note = "*";
+           }
+            &pr("$filenumber","${host}","${disk}","${date}","${level}","$note$mysize","${chunk}");
+         }
+       }
+      }
+      last switch;};
+    /INFO taper retrying/ && do {
+      --$filenumber;
+      last switch; };
+    /INFO taper tape .* \[OK\]/ && do {
+      $line =~ / kb (\d+) /;
+      $size = $1;
+      $line =~ / fm (\d+) /;
+      print "\n\n" if ($vwspace);
+      &pr("$1","total","on_tape","-","-","$size","-");
+      if (defined($flash_mode)) {
+       &pr("$1","total","origin","-","not","available","-");
+      } else {
+       &pr("$1","total","origin","-","-","$tot_or_size","-");
+      }
+      if (defined($strange)) {
+       &pr("*","size","on_tape","-","-","-","-");
+      }
+      last switch; };
+    /FAIL taper/ && do { next; };
+  }
+  $filenumber += 1;
+}
+close $IF;
+close OF;
+
+
+format OF =
+@>>  @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<< @>> @>>>>>>>>
+$fnbr,$hstprt,$dt,$lvl,$sz
+.
+
+format STDOUT =
+@>>  @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<< @>> @>>>>>>>> @>>>
+$fnbr,$hstprt,$dt,$lvl,$sz,$ch
+.
diff --git a/server-src/amverify.sh~HEAD b/server-src/amverify.sh~HEAD
new file mode 100644 (file)
index 0000000..e34cd4e
--- /dev/null
@@ -0,0 +1,565 @@
+#! @SHELL@
+#
+#      $Id: amverify.sh.in,v 1.38 2006/07/25 19:00:56 martinea Exp $
+#
+# (C) 1996 by ICEM Systems GmbH
+# Author: Axel Zinser (fifi@icem.de)
+#
+# amverify: check amanda tapes and report errors
+#
+
+echo "amverify is deprecated -- use amcheckdump" >& 2
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if [ "$USE_VERSION_SUFFIXES" = "yes" ]; then
+       SUF="-@VERSION@"
+else
+       SUF=
+fi
+
+# If the shell/system echo support \r and \c, use them to write some
+# status messages over the top of each other as things progress, otherwise
+# use a normal echo and let them go on new lines.  Define $Echoe to be
+# an echo that goes to stderr.  In the code, $Echoe is used and it may
+# be either echoe or echone, the latter being code that knows about echon.
+
+t=`echo "abc\r\c" | wc -c`
+if [ $t -eq 4 ]; then
+       Echon=echon
+else
+       Echon=echo
+fi
+Echoe=echoe
+elen=0
+echoe() {
+       echo "$@" >&2
+       Echoe=echoe
+}
+echon() {
+        newelen=`expr "$1" : '.*'`
+       blanks=
+        while [ $newelen -lt $elen ]; do
+               blanks="$blanks "
+                elen=`expr $elen - 1`
+        done
+        echo "$1""$blanks\r\c"
+        elen=$newelen
+       Echoe=echone
+}
+echone() {
+       echon
+       echoe "$@"
+       Echoe=echoe
+}
+
+report() {
+       $Echoe "$@"
+       echo "$@" >> $REPORT
+}
+
+getparm() {
+       $AMGETCONF $CONFIG $1 2>/dev/null
+}
+
+sendreport() {
+       if [ -f $REPORT -a X"$REPORTTO" != X"" ]; then
+               (
+               echo `_ 'Tapes: %s' "$TAPELIST"`
+               if [ -s $DEFECTS ]; then
+                       echo `_ 'Errors found:'`
+                       cat $DEFECTS
+               else
+                       echo `_ 'No errors found!'`
+               fi
+               echo
+
+               [ -s $REPORT ] \
+                       && cat $REPORT
+               ) | (
+                   if test -n "$MAIL"; then
+                       $MAIL -s "$ORG AMANDA VERIFY REPORT FOR$TAPELIST" $REPORTTO
+                   else
+                       cat >&2
+                   fi
+               )
+       fi
+}
+
+###
+# This function is called to process one dump image.  Standard input is
+# the dump image.  We parse the header and decide if it is a GNU tar
+# dump or a system dump.  Then we do a catalog operation to /dev/null
+# and finally a "cat" to /dev/null to soak up whatever data is still in
+# the pipeline.
+#
+# In the case of a system restore catalogue, this does not fully check
+# the integrity of the dump image because system restore programs stop
+# as soon as they are done with the directories, which are all at the
+# beginning.  But the trailing cat will at least make sure the whole
+# image is readable.
+###
+
+doonefile() {
+
+       ###
+       # The goal here is to collect the first 32 KBytes and save the
+       # first line.  But the pipe size coming in to us from amrestore
+       # is highly system dependent and "dd" does not do reblocking.
+       # So we pick a block size that is likely to always be available in
+       # the pipe and a count to take it up to 32 KBytes.  Worst case,
+       # this could be changed to "bs=1 count=32k".  We also have to
+       # soak up the rest of the output after the "head" so an EPIPE
+       # does not go back and terminate the "dd" early.
+       ###
+
+        HEADER=`$DD bs=512 count=64 2>/dev/null | ( sed 1q ; cat > /dev/null )`
+       CMD=
+       result=1
+       if [ X"$HEADER" = X"" ]; then
+               echo `_ '** No header'` > $TEMP/errors
+       else
+               set X $HEADER
+               # XXX meh, while[] is dangerous, what about a bad header?
+               while [ X"$1" != X"program" ]; do shift; done
+               if [ X"$1" = X"program" -a X"$2" != X"" ]; then
+                       if [ X"$TAR" != X"" \
+                            -a \( X"`basename $2`" = X"`basename $TAR`" \
+                                  -o X"`basename $2`" = X"gtar" \
+                                  -o X"`basename $2`" = X"gnutar" \
+                                  -o X"`basename $2`" = X"tar" \) ]; then
+                               CMD=$TAR
+                               ARGS="tf -"
+                       elif [ X"$TAR" != X"" \
+                              -a X"$SAMBA_CLIENT" != X"" \
+                              -a X"$2" = X"$SAMBA_CLIENT" ]; then
+                               CMD=$TAR
+                               ARGS="tf -"
+                       elif [ X"$DUMP" != X"" -a X"$2" = X"$DUMP" ]; then
+                               CMD=$RESTORE
+                               if [ $IS_AIX -eq 1 ]; then
+                                       ARGS=-tB
+                               else
+                                       ARGS="tbf 2 -"
+                               fi
+                       elif [ X"$VDUMP" != X"" -a X"$2" = X"$VDUMP" ]; then
+                               CMD=$VRESTORE
+                               ARGS="tf -"
+                       elif [ X"$VXDUMP" != X"" -a X"$2" = X"$VXDUMP" ]; then
+                               CMD=$VXRESTORE
+                               ARGS="tbf 2 -"
+                       elif [ X"$XFSDUMP" != X"" -a X"$2" = X"$XFSDUMP" ]; then
+                               CMD=$XFSRESTORE
+                               ARGS="-t -v silent -"
+                       else
+                               echo `_ '** Cannot do %s dumps' "$2"` > $TEMP/errors
+                               result=999      # flag as not really an error
+                       fi
+               else
+                       echo `_ '** Cannot find dump type'` > $TEMP/errors
+               fi
+       fi
+       echo $CMD > $TEMP/onefile.cmd
+       if [ X"`echo $HEADER | grep '^AMANDA: SPLIT_FILE'`" != X"" ]; then
+           result=500
+           set X $HEADER
+           shift 7
+           echo $1 | cut -f7 -d' ' > $TEMP/onefile.partnum
+       elif [ X"$CMD" != X"" ]; then
+               if [ -x $CMD ]; then
+                       $CMD $ARGS > /dev/null 2> $TEMP/errors
+                       result=$?
+               else
+                       echo `_ '** Cannot execute %s' "$CMD"` > $TEMP/errors
+               fi
+       fi
+       cat >/dev/null                          # soak up the rest of the image
+       echo $result
+}
+
+#
+# some paths
+#
+#      CONFIG_DIR      directory in which the config file resides
+#      AMRESTORE       full path name of amrestore
+#      AMGETCONF       full path name of amgetconf
+#      AMTAPE          full path name of amtape
+#      TAR             ditto for GNU-tar
+#      SAMBA_CLIENT    ditto for smbclient
+#      DUMP            ditto for the system dump program
+#      RESTORE         ditto for the system restore program
+#      VDUMP           ditto for the system dump program
+#      VRESTORE        ditto for the system restore program
+#      VXDUMP          ditto for the system dump program
+#      VXRESTORE       ditto for the system restore program
+#      XFSDUMP         ditto for the system dump program
+#      XFSRESTORE      ditto for the system restore program
+#      DD              ditto for dd
+#      MT              ditto for mt
+#      MTF             flag given to MT to specify tape device: -f or -t
+#      MAIL            mail program
+#      IS_AIX          true if this is an AIX system
+
+CONFIG_DIR=@CONFIG_DIR@
+amlibexecdir=$amlibexecdir
+sbindir=$sbindir
+AMRESTORE=$sbindir/amrestore$SUF
+AMGETCONF=$sbindir/amgetconf$SUF
+AMTAPE=$sbindir/amtape$SUF
+TAR=@GNUTAR@
+SAMBA_CLIENT=@SAMBA_CLIENT@
+DUMP=@DUMP@
+RESTORE=@RESTORE@
+VDUMP=@VDUMP@
+VRESTORE=@VRESTORE@
+VXDUMP=@VXDUMP@
+VXRESTORE=@VXRESTORE@
+XFSDUMP=@XFSDUMP@
+XFSRESTORE=@XFSRESTORE@
+MAIL=@MAILER@
+DD=@DD@
+
+. ${amlibexecdir}/chg-lib.sh
+
+#
+# config file
+#
+SLOT=0
+CONFIG=$1
+[ X"$CONFIG" = X"" ] \
+       && $Echoe "usage: amverify$SUF <config> [slot [ runtapes ] ]" \
+       && exit 1
+
+AMCONFIG=$CONFIG_DIR/$CONFIG/amanda.conf
+[ ! -f $AMCONFIG ] \
+       && $Echoe "Cannot find config file $AMCONFIG" \
+       && exit 1
+
+TPCHANGER=`getparm tpchanger`
+if [ X"$TPCHANGER" = X"" ]; then
+       $Echoe "No tape changer..."
+       DEVICE=`getparm tapedev`
+       [ X"$DEVICE" = X"" ] \
+               && $Echoe "No tape device..." \
+               && exit 1
+       $Echoe "Tape device is $DEVICE..."
+       SLOTS=1
+else
+       CHANGER_SLOT=${2:-current}
+       $Echoe "Tape changer is $TPCHANGER..."
+       SLOTS=${3:-`getparm runtapes`}
+       [ X"$SLOTS" = X"" ] && SLOTS=1
+       if [ $SLOTS -eq 1 ]; then
+               p=""
+       else
+               p=s
+       fi
+       $Echoe "$SLOTS slot${p}..."
+       MAXRETRIES=2
+fi
+
+#
+# check the accessability
+#
+[ X"$TAR" != X"" -a ! -x "$TAR" ] \
+       && $Echoe "GNU tar not found: $TAR"
+[ X"$DUMP" != X"" -a \( X"$RESTORE" = X"" -o ! -x "$RESTORE" \) ] \
+       && $Echoe "System restore program not found: $RESTORE"
+[ X"$VDUMP" != X"" -a \( X"$VRESTORE" = X"" -o ! -x "$VRESTORE" \) ] \
+       && $Echoe "System restore program not found: $VRESTORE"
+[ X"$VXDUMP" != X"" -a \( X"$VXRESTORE" = X"" -o ! -x "$VXRESTORE" \) ] \
+       && $Echoe "System restore program not found: $VXRESTORE"
+[ X"$XFSDUMP" != X"" -a \( X"$XFSRESTORE" = X"" -o ! -x "$XFSRESTORE" \) ] \
+       && $Echoe "System restore program not found: $XFSRESTORE"
+[ ! -x $AMRESTORE ] \
+       && $Echoe "amrestore not found: $AMRESTORE" \
+       && exit 1
+
+REPORTTO=`getparm mailto`
+if [ X"$REPORTTO" = X"" ]; then
+       $Echoe "No notification by mail!"
+else
+       $Echoe "Verify summary to $REPORTTO"
+fi
+
+ORG=`getparm org`
+if [ X"$ORG" = X"" ]; then
+       $Echoe "No org in amanda.conf -- using $CONFIG"
+       ORG=$CONFIG
+fi
+
+#
+# ok, let's do it
+#
+#      TEMP            directory for temporary tar archives and stderr
+#      DEFECTS         defect list
+#      REPORT          report for mail
+
+if [ ! -d @AMANDA_TMPDIR@ ]; then
+  $Echoe "amverify: directory @AMANDA_TMPDIR@ does not exist."
+  exit 1
+fi
+
+cd @AMANDA_TMPDIR@ || exit 1
+
+TEMP=@AMANDA_TMPDIR@/amverify.$$
+trap 'rm -fr $TEMP' EXIT
+if ( umask 077 ; mkdir $TEMP ) ; then
+       :
+else
+       $Echoe "Cannot create $TEMP"
+       exit 1
+fi
+DEFECTS=$TEMP/defects; rm -f $DEFECTS
+REPORT=$TEMP/report; rm -f $REPORT
+TAPELIST=
+EXITSTAT=$TEMP/amrecover.exit; rm -rf $EXITSTAT
+
+<<<<<<< HEAD:server-src/amverify.sh.in
+trap 'report "aborted!"; echo "aborted!" >> $DEFECTS; sendreport; rm -fr $TEMP; exit 1' EXIT
+=======
+trap 'report "aborted!"; echo `_ 'aborted!'` >> $DEFECTS; sendreport; rm -fr $TEMP; exit 1' 1 2 3 4 5 6 7 8 10 12 13 14 15
+>>>>>>> upstream:server-src/amverify.sh
+
+$Echoe "Defects file is $DEFECTS"
+report "amverify $CONFIG"
+report "`date`"
+report ""
+
+# ----------------------------------------------------------------------------
+
+SPLIT_DUMPS= # this will keep track of split dumps that we'll tally later
+while [ $SLOT -lt $SLOTS ]; do
+       SLOT=`expr $SLOT + 1`
+       #
+       # Tape Changer: dial slot
+       #
+       if [ X"$TPCHANGER" != X"" ]; then
+               report "Loading ${CHANGER_SLOT} slot..."
+               $AMTAPE $CONFIG slot $CHANGER_SLOT > $TEMP/amtape.out 2>&1
+               THIS_SLOT=$CHANGER_SLOT
+               CHANGER_SLOT=next
+               RESULT=`grep "changed to slot" $TEMP/amtape.out`
+               [ X"$RESULT" = X"" ] \
+                       && report "** Error loading slot $THIS_SLOT" \
+                       && report "`cat $TEMP/amtape.out`" \
+                       && cat $TEMP/amtape.out >> $DEFECTS \
+                       && continue
+               DEVICE=`$AMTAPE $CONFIG device`
+       fi
+       report "Using device $DEVICE"
+       $Echon "Waiting for device to go ready..."
+       count=1800
+<<<<<<< HEAD:server-src/amverify.sh.in
+       until eval $DEVICE_READY > $TEMP/ammt.out 2>&1; do
+               [ count -lt 0 ] \
+                       && report "Device not ready" \
+                       && report "`cat $TEMP/ammt.out`" \
+                       && report cat $TEMP/ammt.out >> $DEFECTS \
+                       && break;
+               sleep 3
+               count=`expr $count - 3`
+       done
+       $Echon "Rewinding..."
+       ERRORS=0
+       until $MT $MTF $DEVICE rewind > $TEMP/ammt.out 2>&1; do
+               RESULT=`grep "No medium found" $TEMP/ammt.out`
+               [ X"$RESULT" != X"" ] \
+                       && report "** Error rewinding tape" \
+                       && report "`cat $TEMP/ammt.out`" \
+                       && cat $TEMP/ammt.out >> $DEFECTS \
+                       && break
+               ERRORS=`expr $ERRORS + 1`
+               [ $ERRORS -gt 100 ] \
+                       && report "** Error rewinding tape" \
+                       && report "`cat $TEMP/ammt.out`" \
+                       && cat $TEMP/ammt.out >> $DEFECTS \
+                       && break
+               sleep 3
+=======
+        while true; do
+            amdevcheck_output="`amdevcheck $CONFIG $DEVICE`"
+            amdevcheck_status=$?
+            if [ $amdevcheck_status -eq 0 ]; then
+                break;
+            else
+                if echo $amdevcheck_output | grep UNLABELED > /dev/null; then
+                   if [ count -lt 0 ]; then
+                       report "Device not ready"
+                        break;
+                   fi
+                    sleep 3
+                   count=`expr $count - 3`
+                else
+                    report "Volume in $DEVICE unlabeled."
+                    break;
+                fi
+            fi
+>>>>>>> upstream:server-src/amverify.sh
+       done
+       $Echon "Processing label..."
+        amtape_output="`amtape $CONFIG current 2>&1`";
+        if echo "$amtape_output" | \
+            egrep "^slot +[0-9]+: time [^ ]+ +label [^ ]+" > /dev/null; then
+           : # everything is fine
+       else
+            report "Error reading tape label using amtape."
+            continue
+        fi
+        
+        set X $amtape_output
+        until [ "$1" = "time" ]; do
+            shift
+        done
+        
+       VOLUME=$4
+       DWRITTEN=$2
+       report "Volume $VOLUME, Date $DWRITTEN"
+       [ X"$DWRITTEN" = X"0" -o X"$DWRITTEN" = X"X" ] \
+               && report "Fresh tape. Skipping..." \
+               && continue
+       TAPELIST="$TAPELIST $VOLUME"
+
+        FILENO=0
+       ERG=0
+       ERRORS=0
+       while [ $ERG = 0 ]; do
+<<<<<<< HEAD:server-src/amverify.sh.in
+               if [ $Echon = echon ]; then
+                       $Echon "Waiting for device to go ready..."
+               fi
+               count=1800
+               until eval $DEVICE_READY > $TEMP/ammt.out 2>&1; do
+                       [ count -lt 0 ] \
+                               && report "Device not ready" \
+                               && report "`cat $TEMP/ammt.out`" \
+                               && report cat $TEMP/ammt.out >> $DEFECTS \
+                               && break;
+                       sleep 3
+                       count=`expr $count - 3`
+               done
+               if [ $Echon = echon ]; then
+                       $Echon "Reading..."
+               fi
+               RESULT=`$AMRESTORE -h -p $DEVICE 2> $TEMP/amrestore.out \
+                       | doonefile 2> $TEMP/onefile.errors`
+               FILE=`grep restoring $TEMP/amrestore.out \
+                       | sed 's/^.*restoring //'`
+               EOF=`grep "reached end of tape" $TEMP/amrestore.out`
+               EOI=`grep "reached end of information" $TEMP/amrestore.out`
+               # amrestore:   0: restoring sundae._mnt_sol1_usr.19961127.1
+=======
+               FILENO=`expr $FILENO + 1`
+#            { cat <<EOF; dd if=/dev/zero bs=32k count=1; } | doonefile
+#AMANDA: FILE 20070925205916 localhost /boot  lev 0 comp N program /bin/tar
+#To restore, position tape at start of file and run:
+#        dd if=<tape> bs=32k skip=1 |      /bin/tar -xpGf - ...
+#EOF
+               RESULT=`$AMRESTORE -h -p -f $FILENO $DEVICE \
+                            2> $TEMP/amrestore.out \
+                       | doonefile 2> $TEMP/onefile.errors`
+               FILE=`grep restoring $TEMP/amrestore.out \
+                       | sed 's/^.*restoring //'`
+>>>>>>> upstream:server-src/amverify.sh
+               if [ X"$FILE" != X"" -a X"$RESULT" = X"0" ]; then
+                       report "Checked $FILE"
+               elif [ X"$FILE" != X"" -a X"$RESULT" = X"500" ]; then
+                       report "Skipped `cat $TEMP/onefile.cmd` check on partial dump $FILE"
+                       dump="`echo $FILE | cut -d'.' -f'1,2,3,4'`"
+                       cat $TEMP/onefile.partnum >> $TEMP/$dump.parts
+                       if [ X"`echo $SPLIT_DUMPS | grep $dump`" = X"" ]; then
+                           SPLIT_DUMPS="$dump $SPLIT_DUMPS"
+                       fi
+               elif [ X"$FILE" != X"" -a X"$RESULT" = X"999" ]; then
+                       report "Skipped $FILE (`cat $TEMP/errors`)"
+               elif [ -z "$FILE" ]; then
+                        # Unless we went over, there is no extra output.
+                       report "End-of-Tape detected."
+                       break
+               elif [ -n "$EOI" ]; then
+                        report "End-of-Information detected."
+                        break
+               else
+                       report "** Error detected ($FILE)"
+                       echo "$VOLUME ($FILE):" >>$DEFECTS
+                       [ -s $TEMP/amrestore.out ] \
+                               && report "`cat $TEMP/amrestore.out`" \
+                               && cat $TEMP/amrestore.out >>$DEFECTS
+                       [ -s $TEMP/errors ] \
+                               && report "`cat $TEMP/errors`" \
+                               && cat $TEMP/errors >>$DEFECTS
+                       [ -s $TEMP/onefile.errors ] \
+                               && report "`cat $TEMP/onefile.errors`" \
+                               && cat $TEMP/onefile.errors >>$DEFECTS
+                       ERRORS=`expr $ERRORS + 1`
+                       [ $ERRORS -gt 5 ] \
+                               && report "Too many errors." \
+                               && break
+               fi
+       done
+       rm -f $TEMP/header \
+             $TEMP/amtape.out \
+             $TEMP/amrestore.out \
+             $TEMP/errors \
+             $TEMP/onefile.cmd \
+             $TEMP/onefile.partnum \
+             $TEMP/onefile.errors
+done
+
+[ -s $DEFECTS ] \
+       && $Echoe "Errors found: " \
+       && cat $DEFECTS
+
+# Work out whether any split dumps we saw had all their parts
+for dump in $SPLIT_DUMPS;do
+    report ""
+    numparts=0
+    max=0
+    max_known=0
+    missing=0
+    # figure out 
+    for part in `cat $TEMP/$dump.parts`;do
+       cur="`echo $part | cut -d/ -f1`"
+       max="`echo $part | cut -d/ -f2`"
+       if [ $max != "UNKNOWN" ]; then
+           numparts=$max
+           max_known=1
+           break;
+       fi
+       if [ $cur -gt $numparts ]; then
+           numparts=$cur
+       fi
+    done
+    report "Split dump $dump should have $numparts total pieces"
+    if [ $max_known != 1 ]; then
+       report "NOTE: Header field for total pieces was UNKNOWN, $numparts is best guess"
+    fi
+    part=1
+    while [ $part -lt $numparts ];do
+       part=`expr $part + 1`
+       if [ X"`grep \"^$part/\" $TEMP/$dump.parts`" = X"" ];then
+           report "Spanning chunk part $part is missing!"
+           missing=`expr $missing + 1`
+       fi
+    done
+    if [ $missing = 0 ];then
+       report "All parts found"        
+    fi
+    rm -f $TEMP/$dump.parts
+done
+
+sendreport
+
+rm -fr $TEMP
+trap - EXIT
+
+exit 0
diff --git a/server-src/amverifyrun.sh b/server-src/amverifyrun.sh
new file mode 100644 (file)
index 0000000..d35826e
--- /dev/null
@@ -0,0 +1,76 @@
+#!@SHELL@
+#
+
+echo "amverifyrun is deprecated -- use amcheckdump" >& 2
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+amlibexecdir="@amlibexecdir@"
+. "${amlibexecdir}/amanda-sh-lib.sh"
+
+# add sbin and ucb dirs
+PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
+export PATH
+
+USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
+if [ "$USE_VERSION_SUFFIXES" = "yes" ]; then
+        SUF="-@VERSION@"
+else
+        SUF=
+fi
+
+getparm() {
+        $AMGETCONF $CONFIG $1 2>/dev/null
+}
+
+CONFIG=$1
+amlibexecdir=$amlibexecdir  
+sbindir=$sbindir
+AMGETCONF=$sbindir/amgetconf$SUF
+AMVERIFY=$sbindir/amverify$SUF
+LOGDIR=`getparm logdir`
+AMDUMPLOG=${LOGDIR}/amdump.1
+AMFLUSHLOG=${LOGDIR}/amflush.1
+if [ -f $AMDUMPLOG ]; then
+  if [ -f $AMFLUSHLOG ]; then
+    if [ $AMDUMPLOG -nt $AMFLUSHLOG ]; then
+      AMLOG=$AMDUMPLOG
+    else
+      AMLOG=$AMFLUSHLOG
+    fi
+  else
+    AMLOG=$AMDUMPLOG
+  fi
+else
+  if [ -f $AMFLUSHLOG ]; then
+    AMLOG=$AMFLUSHLOG
+  else
+    echo `_ 'Nothing to verify'`
+    exit 1;
+  fi
+fi
+
+
+FIRST_SLOT=`grep "taper: slot" $AMLOG | fgrep 'exact label match
+new tape
+first labelstr match' | sed 1q | sed 's/://g' | awk '{print $3}'`
+if [ X"$FIRST_SLOT" = X"" ]; then
+  FIRST_SLOT=`grep "taper: slot: .* wrote label" $AMLOG | sed 1q | sed 's/://g' | awk '{print $3}'`
+  if [ X"$FIRST_SLOT" = X"" ]; then
+    FIRST_SLOT='-1'
+  fi
+fi
+
+NBTAPES=`grep -c "taper: .*wrote label " $AMLOG`
+
+if [ X"$NBTAPES" != X"0" ]; then
+  if ln -s $AMLOG $LOGDIR/log ; then
+    $AMVERIFY $CONFIG $FIRST_SLOT $NBTAPES
+    if [ -L $LOGDIR/log ] ; then rm $LOGDIR/log ; fi
+  else
+    echo "amdump or amflush is already running, or you must run amcleanup"
+  fi
+else
+  echo `_ 'Nothing to verify'`
+fi
diff --git a/server-src/taper-disk-port-source.c b/server-src/taper-disk-port-source.c
new file mode 100644 (file)
index 0000000..58f13d3
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#define selfp (self->_priv)
+
+#include "taper-disk-port-source.h"
+#include "taper-mem-port-source.h"
+
+struct _TaperDiskPortSourcePrivate {
+    gboolean retry_mode;
+    int buffer_fd;
+    TaperSource * fallback;
+    gboolean disk_problem;
+    guint64 disk_buffered_bytes;
+    
+    /* This is for extra data we picked up by accident. */
+    char * excess_buffer;
+    size_t excess_buffer_size;
+
+    guint64 retry_data_written;
+};
+
+/* here are local prototypes */
+static void taper_disk_port_source_init (TaperDiskPortSource * o);
+static void taper_disk_port_source_class_init (TaperDiskPortSourceClass * c);
+static ssize_t taper_disk_port_source_read (TaperSource * pself, void * buf,
+                                            size_t count);
+static gboolean taper_disk_port_source_seek_to_part_start
+    (TaperSource * pself);
+static void taper_disk_port_source_start_new_part (TaperSource * pself);
+static gboolean taper_disk_port_source_get_end_of_data(TaperSource * pself);
+static gboolean taper_disk_port_source_get_end_of_part(TaperSource * pself);
+static int taper_disk_port_source_predict_parts(TaperSource * pself);
+
+/* pointer to the class of our parent */
+static TaperSourceClass * source_parent_class = NULL;
+static TaperPortSourceClass *parent_class = NULL;
+
+GType taper_disk_port_source_get_type (void) {
+    static GType type = 0;
+    
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (TaperDiskPortSourceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) taper_disk_port_source_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (TaperDiskPortSource),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) taper_disk_port_source_init,
+            NULL
+        };
+        
+        type = g_type_register_static (TAPER_TYPE_PORT_SOURCE,
+                                       "TaperDiskPortSource", &info,
+                                       (GTypeFlags)0);
+    }
+    
+    return type;
+}
+
+static void taper_disk_port_source_dispose(GObject * obj_self) {
+    TaperDiskPortSource *self = TAPER_DISK_PORT_SOURCE (obj_self);
+    if (G_OBJECT_CLASS (parent_class)->dispose)
+        (* G_OBJECT_CLASS (parent_class)->dispose) (obj_self);
+    
+    if(self->_priv->fallback) {
+        g_object_unref (self->_priv->fallback);
+    }
+}
+
+static void
+taper_disk_port_source_finalize(GObject *obj_self)
+{
+    TaperDiskPortSource *self = TAPER_DISK_PORT_SOURCE (obj_self);
+    if(G_OBJECT_CLASS(parent_class)->finalize)
+        (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+
+    amfree(self->buffer_dir_name);
+    amfree(self->_priv->excess_buffer);
+    amfree(self->_priv);
+}
+
+static void 
+taper_disk_port_source_init (TaperDiskPortSource * o G_GNUC_UNUSED)
+{
+        o->_priv = malloc(sizeof(TaperDiskPortSourcePrivate));
+       o->_priv->retry_mode = FALSE;
+        o->_priv->buffer_fd = -1;
+       o->_priv->fallback = NULL;
+        o->_priv->disk_problem = FALSE;
+        o->_priv->disk_buffered_bytes = 0;
+        o->_priv->excess_buffer = NULL;
+        o->_priv->excess_buffer_size = 0;
+}
+
+static void 
+taper_disk_port_source_class_init (TaperDiskPortSourceClass * c G_GNUC_UNUSED)
+{
+    GObjectClass *g_object_class = (GObjectClass*) c;
+    TaperSourceClass *taper_source_class = (TaperSourceClass *)c;
+    
+    parent_class = g_type_class_ref (TAPER_TYPE_PORT_SOURCE);
+    source_parent_class = (TaperSourceClass*)parent_class;
+    
+    taper_source_class->read = taper_disk_port_source_read;
+    taper_source_class->seek_to_part_start =
+        taper_disk_port_source_seek_to_part_start;
+    taper_source_class->start_new_part = taper_disk_port_source_start_new_part;
+    taper_source_class->get_end_of_data =
+        taper_disk_port_source_get_end_of_data;
+    taper_source_class->get_end_of_part =
+        taper_disk_port_source_get_end_of_part;
+    taper_source_class->predict_parts = taper_disk_port_source_predict_parts;
+
+    g_object_class->dispose = taper_disk_port_source_dispose;
+    g_object_class->finalize = taper_disk_port_source_finalize;
+}
+
+
+static gboolean taper_disk_port_source_get_end_of_data(TaperSource * pself) {
+    TaperDiskPortSource * self = TAPER_DISK_PORT_SOURCE(pself);
+    g_return_val_if_fail(self != NULL, TRUE);
+
+    if (self->_priv->fallback != NULL) {
+        return taper_source_get_end_of_data(self->_priv->fallback);
+    } else {
+        return (source_parent_class->get_end_of_data)(pself);
+    }
+}
+static gboolean taper_disk_port_source_get_end_of_part(TaperSource * pself) {
+    TaperDiskPortSource * self = TAPER_DISK_PORT_SOURCE(pself);
+    g_return_val_if_fail(self != NULL, TRUE);
+
+    if (self->_priv->fallback != NULL) {
+        return taper_source_get_end_of_part(self->_priv->fallback);
+    } else {
+        return (source_parent_class->get_end_of_part)(pself);
+    }
+}
+  
+static int taper_disk_port_source_predict_parts(TaperSource * pself) {
+    TaperDiskPortSource * self = TAPER_DISK_PORT_SOURCE(pself);
+    g_return_val_if_fail(self != NULL, -1);
+
+    return -1;
+}
+
+static TaperSource * make_fallback_source(TaperDiskPortSource * self) {
+    TaperSource * rval;
+    TaperPortSource * port_rval;
+    rval = (TaperSource*)
+        g_object_new(TAPER_TYPE_MEM_PORT_SOURCE, NULL);
+    port_rval = (TaperPortSource*)rval;
+    
+    if (rval == NULL)
+        return NULL;
+
+    port_rval->socket_fd = ((TaperPortSource*)self)->socket_fd;
+    rval->max_part_size = self->fallback_buffer_size;
+
+    return rval;
+}
+
+/* Open the buffer file. We create the file and then immediately
+   unlink it, to improve security and ease cleanup. */
+static gboolean open_buffer_file(TaperDiskPortSource * self) {
+    int fd;
+    char * filename;
+    mode_t old_umask;
+
+    g_return_val_if_fail(self != NULL, FALSE);
+    g_return_val_if_fail(self->buffer_dir_name != NULL, FALSE);
+
+    filename = g_strdup_printf("%s/amanda-split-buffer-XXXXXX",
+                               self->buffer_dir_name);
+    /* This is not thread-safe. :-( */
+    old_umask = umask(0);
+    fd = g_mkstemp(filename);
+    umask(old_umask);
+    if (fd < 0) {
+        g_fprintf(stderr, "Couldn't open temporary file with template %s: %s\n",
+                filename, strerror(errno));
+        return FALSE;
+    }
+
+    /* If it fails, that's annoying, but no great loss. */
+    if (unlink(filename) != 0) {
+        g_fprintf(stderr, "Unlinking %s failed: %s\n", filename,
+                strerror(errno));
+    }
+
+    free(filename);
+    selfp->buffer_fd = fd;
+    return TRUE;
+}
+
+/* An error has occured with the disk buffer; store the extra data in
+   memory until we can recover. */
+static void store_excess(TaperDiskPortSource * self, char * buf,
+                         size_t attempted_size, size_t disk_size) {
+    TaperSource * pself = (TaperSource*)self;
+    g_return_if_fail(attempted_size > 0);
+    g_return_if_fail(disk_size < attempted_size);
+    g_return_if_fail(buf != NULL);
+    g_return_if_fail(selfp->excess_buffer == NULL);
+
+    selfp->excess_buffer_size = attempted_size - disk_size;
+    selfp->excess_buffer = malloc(selfp->excess_buffer_size);
+    memcpy(selfp->excess_buffer, buf + disk_size, attempted_size - disk_size);
+
+    selfp->disk_buffered_bytes += disk_size;
+    pself->max_part_size = MIN(pself->max_part_size,
+                               selfp->disk_buffered_bytes);
+}
+
+/* Handle the output of the small amount of saved in-memory data. */
+static size_t handle_excess_buffer_read(TaperDiskPortSource * self,
+                                        void * buf, size_t count) {
+    TaperSource * pself = (TaperSource*)self;
+    guint64 offset;
+
+    /* First, do we have anything left? */
+    if (selfp->retry_data_written >=
+        (selfp->disk_buffered_bytes + selfp->excess_buffer_size)) {
+        pself->end_of_part = TRUE;
+        return 0;
+    }
+    
+    count = MIN(count,
+                (selfp->disk_buffered_bytes + selfp->excess_buffer_size)
+                - selfp->retry_data_written);
+
+    offset = selfp->disk_buffered_bytes + selfp->excess_buffer_size
+        - selfp->retry_data_written;
+    g_assert(offset + count <= selfp->excess_buffer_size);
+    memcpy(buf, selfp->excess_buffer + offset, count);
+
+    selfp->retry_data_written += count;
+
+    return count;
+}
+    
+/* Write data out to the disk buffer, and handle any problems that
+   crop up along the way. */
+static ssize_t write_disk_buffer(TaperDiskPortSource * self, char * buf,
+                                 size_t read_size) {
+    size_t bytes_written = 0;
+    while (bytes_written < read_size) {
+        int write_result = write(selfp->buffer_fd, buf + bytes_written,
+                                 read_size - bytes_written);
+        if (write_result > 0) {
+            bytes_written += write_result;
+            continue;
+        } else if (write_result == 0) {
+            g_fprintf(stderr, "Writing disk buffer: Wrote 0 bytes.\n");
+            continue;
+        } else {
+            if (0
+#ifdef EAGAIN
+                || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                || errno == EINTR
+#endif
+                ) {
+                /* Try again. */
+                continue;
+            } else if (0
+#ifdef EFBIG
+                       || errno == EFBIG
+#endif
+#ifdef ENOSPC
+                       || errno == ENOSPC
+#endif
+                       ) {
+                /* Out of space */
+                store_excess(self, buf, read_size, bytes_written);
+                return read_size;
+            } else {
+                /* I/O error. */
+                store_excess(self, buf, read_size, bytes_written);
+                selfp->disk_problem = TRUE;
+                TAPER_SOURCE(self)->end_of_part = TRUE;
+                return read_size;
+            }
+        }
+        g_assert_not_reached();
+    }
+
+    selfp->disk_buffered_bytes += bytes_written;
+    return read_size;
+}
+
+static ssize_t 
+taper_disk_port_source_read (TaperSource * pself, void * buf, size_t count) {
+    TaperDiskPortSource * self = (TaperDiskPortSource*)pself;
+
+    g_return_val_if_fail (self != NULL, -1);
+    g_return_val_if_fail (TAPER_IS_DISK_PORT_SOURCE (self), -1);
+    g_return_val_if_fail (buf != NULL, -1);
+    g_return_val_if_fail (count > 0, -1);
+    g_assert(selfp->disk_buffered_bytes <= pself->max_part_size);
+       
+    if (selfp->fallback != NULL) {
+        return taper_source_read(selfp->fallback, buf, count);
+    } else if (selfp->buffer_fd < 0) {
+        if (!open_buffer_file(self)) {
+            /* Buffer file failed; go immediately to failover mode. */
+            selfp->fallback = make_fallback_source(self);
+            if (selfp->fallback != NULL) {
+                return taper_source_read(selfp->fallback, buf, count);
+            } else {
+                /* Even the fallback source failed! */
+                return -1;
+            }
+        }
+    }
+
+    if (selfp->retry_mode) {
+        /* Read from disk buffer. */
+
+        if (selfp->retry_data_written < selfp->disk_buffered_bytes) {
+            /* Read from disk. */
+            int result;
+            count = MIN(count, selfp->disk_buffered_bytes -
+                               selfp->retry_data_written);
+            result = read(selfp->buffer_fd, buf, count);
+            if (result <= 0) {
+                /* This should not happen. */
+                return -1;
+            } else {
+                selfp->retry_data_written += result;
+                return result;
+            }
+        } else if (selfp->excess_buffer != NULL) {
+            /* We are writing out the last bit of buffer. Handle that. */
+            return handle_excess_buffer_read(self, buf, count);
+        } else {
+            /* No more data. */
+            pself->end_of_part = TRUE;
+            return 0;
+        }
+        
+        g_assert_not_reached();
+    } else {
+        /* Read from port. */
+        int read_result;
+        count = MIN(count, pself->max_part_size - selfp->disk_buffered_bytes);
+        if (count == 0) /* It was nonzero before. */ {
+            pself->end_of_part = TRUE;
+            return 0;
+        }
+        
+        read_result = source_parent_class->read(pself, buf, count);
+        /* Parent handles EOF and other goodness. */
+        if (read_result <= 0) {
+            return read_result;
+        }
+        /* Now write to disk buffer. */
+        return write_disk_buffer(self, buf, read_result);
+    }
+}
+
+/* Try seeking back to byte 0. If that fails, then we mark ourselves
+   as having a disk problem. Returns FALSE in that case. */
+static gboolean try_rewind(TaperDiskPortSource * self) {
+    gint64 result;
+    result = lseek(selfp->buffer_fd, 0, SEEK_SET);
+    if (result != 0) {
+        g_fprintf(stderr, "Couldn't seek split buffer: %s\n", strerror(errno));
+        selfp->disk_problem = TRUE;
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+
+static gboolean 
+taper_disk_port_source_seek_to_part_start (TaperSource * pself) {
+    TaperDiskPortSource * self = (TaperDiskPortSource*)pself;
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (TAPER_IS_DISK_PORT_SOURCE (pself), FALSE);
+    g_return_val_if_fail (selfp->disk_buffered_bytes
+                          + selfp->excess_buffer_size > 0, FALSE);
+    
+    if (self->_priv->fallback != NULL) {
+        return taper_source_seek_to_part_start(selfp->fallback);
+    }
+
+    if (selfp->disk_problem && selfp->disk_buffered_bytes) {
+        /* The disk buffer is screwed; nothing to do. */
+        return FALSE;
+    }
+
+    if (!selfp->disk_problem) {
+        if (!try_rewind(self)) {
+            return FALSE;
+        }
+    }
+
+    selfp->retry_mode = TRUE;
+    selfp->retry_data_written = 0;
+
+    if (source_parent_class->seek_to_part_start) {
+        return source_parent_class->seek_to_part_start(pself);
+    } else {
+        return TRUE;
+    }
+}
+
+static void 
+taper_disk_port_source_start_new_part (TaperSource * pself) {
+    TaperDiskPortSource * self = (TaperDiskPortSource*)pself;
+    g_return_if_fail (self != NULL);
+    g_return_if_fail (TAPER_IS_DISK_PORT_SOURCE (pself));
+       
+    if (self->_priv->fallback != NULL) {
+        taper_source_start_new_part(self->_priv->fallback);
+        return;
+    }
+
+    selfp->retry_mode = FALSE;
+    if (!selfp->disk_problem) {
+        try_rewind(self); /* If this fails it will set disk_problem to
+                             TRUE. */
+    }
+
+    if (selfp->disk_problem && selfp->fallback == NULL) {
+        selfp->fallback = make_fallback_source(self);
+    }
+    selfp->disk_buffered_bytes = 0;
+    amfree(selfp->excess_buffer);
+    selfp->excess_buffer_size = selfp->retry_data_written = 0;
+
+    if (source_parent_class->start_new_part) {
+        source_parent_class->start_new_part(pself);
+    }
+}
diff --git a/server-src/taper-disk-port-source.h b/server-src/taper-disk-port-source.h
new file mode 100644 (file)
index 0000000..ba83385
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* The taper disk port source is a taper source (see taper-source.h)
+   used for the case where we are reading directly from a client
+   (PORT-WRITE) and are using a disk buffer to hold split dump parts. */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "taper-port-source.h"
+
+#ifndef __TAPER_DISK_PORT_SOURCE_H__
+#define __TAPER_DISK_PORT_SOURCE_H__
+
+
+/*
+ * Type checking and casting macros
+ */
+#define TAPER_TYPE_DISK_PORT_SOURCE    (taper_disk_port_source_get_type())
+#define TAPER_DISK_PORT_SOURCE(obj)    G_TYPE_CHECK_INSTANCE_CAST((obj), taper_disk_port_source_get_type(), TaperDiskPortSource)
+#define TAPER_DISK_PORT_SOURCE_CONST(obj)      G_TYPE_CHECK_INSTANCE_CAST((obj), taper_disk_port_source_get_type(), TaperDiskPortSource const)
+#define TAPER_DISK_PORT_SOURCE_CLASS(klass)    G_TYPE_CHECK_CLASS_CAST((klass), taper_disk_port_source_get_type(), TaperDiskPortSourceClass)
+#define TAPER_IS_DISK_PORT_SOURCE(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), taper_disk_port_source_get_type ())
+
+#define TAPER_DISK_PORT_SOURCE_GET_CLASS(obj)  G_TYPE_INSTANCE_GET_CLASS((obj), taper_disk_port_source_get_type(), TaperDiskPortSourceClass)
+
+/* Private structure type */
+typedef struct _TaperDiskPortSourcePrivate TaperDiskPortSourcePrivate;
+
+/*
+ * Main object structure
+ */
+#ifndef __TYPEDEF_TAPER_DISK_PORT_SOURCE__
+#define __TYPEDEF_TAPER_DISK_PORT_SOURCE__
+typedef struct _TaperDiskPortSource TaperDiskPortSource;
+#endif
+struct _TaperDiskPortSource {
+    TaperPortSource __parent__;
+    /*< private >*/
+    guint64 fallback_buffer_size;
+    char * buffer_dir_name;
+    TaperDiskPortSourcePrivate *_priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _TaperDiskPortSourceClass TaperDiskPortSourceClass;
+struct _TaperDiskPortSourceClass {
+       TaperPortSourceClass __parent__;
+};
+
+/*
+ * Public methods
+ */
+GType  taper_disk_port_source_get_type (void);
+
+#endif
diff --git a/server-src/taper-file-source.c b/server-src/taper-file-source.c
new file mode 100644 (file)
index 0000000..65a75a9
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#define selfp (self->_priv)
+
+#include "taper-file-source.h"
+
+#include "fileheader.h"
+#include "holding.h"
+
+#define HOLDING_DISK_OPEN_FLAGS (O_NOCTTY | O_RDONLY)
+
+struct _TaperFileSourcePrivate {
+    /* How many bytes have we written from the current part? */
+    guint64 current_part_pos;
+    /* Information about the files at the start of this part. */
+    dumpfile_t part_start_chunk_header;
+    int part_start_chunk_fd;
+    /* Where is the start of this part with respect to the first chunk
+       of the part? */
+    guint64 part_start_chunk_offset;
+    /* These may be the same as their part_start_chunk_ counterparts. */
+    dumpfile_t current_chunk_header;
+    int current_chunk_fd;
+    /* Current position of current_chunk_fd. */
+    guint64 current_chunk_position;
+    /* Expected number of split parts. */
+    int predicted_splits;
+};
+/* here are local prototypes */
+static void taper_file_source_init (TaperFileSource * o);
+static void taper_file_source_class_init (TaperFileSourceClass * c);
+static ssize_t taper_file_source_read (TaperSource * pself, void * buf,
+                                            size_t count);
+static gboolean taper_file_source_seek_to_part_start (TaperSource * pself);
+static void taper_file_source_start_new_part (TaperSource * pself);
+static int taper_file_source_predict_parts(TaperSource * pself);
+static dumpfile_t * taper_file_source_get_first_header(TaperSource * pself);
+static gboolean first_time_setup(TaperFileSource * self);
+
+/* pointer to the class of our parent */
+static TaperSourceClass *parent_class = NULL;
+
+GType taper_file_source_get_type (void) {
+    static GType type = 0;
+    
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (TaperFileSourceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) taper_file_source_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (TaperFileSource),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) taper_file_source_init,
+            NULL
+        };
+        
+        type = g_type_register_static (TAPER_TYPE_SOURCE, "TaperFileSource",
+                                       &info, (GTypeFlags)0);
+    }
+    
+    return type;
+}
+
+static void
+taper_file_source_finalize(GObject *obj_self)
+{
+    TaperFileSource *self = TAPER_FILE_SOURCE (obj_self);
+    gpointer priv G_GNUC_UNUSED = self->_priv;
+    if(G_OBJECT_CLASS(parent_class)->finalize)
+        (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+    if(self->_priv->part_start_chunk_fd >= 0) {
+        close (self->_priv->part_start_chunk_fd);
+    }
+    if(self->_priv->current_chunk_fd >= 0) {
+        close (self->_priv->current_chunk_fd);
+    }
+}
+
+static void 
+taper_file_source_init (TaperFileSource * o G_GNUC_UNUSED)
+{
+    o->_priv = malloc(sizeof(TaperFileSourcePrivate));
+    o->_priv->part_start_chunk_fd = -1;
+    o->_priv->current_chunk_fd = -1;
+    o->_priv->predicted_splits = -1;
+    o->holding_disk_file = NULL;
+}
+
+static void  taper_file_source_class_init (TaperFileSourceClass * c) {
+    GObjectClass *g_object_class = (GObjectClass*) c;
+    TaperSourceClass *taper_source_class = (TaperSourceClass *)c;
+
+    parent_class = g_type_class_ref (TAPER_TYPE_SOURCE);
+
+    taper_source_class->read = taper_file_source_read;
+    taper_source_class->seek_to_part_start =
+        taper_file_source_seek_to_part_start;
+    taper_source_class->start_new_part = taper_file_source_start_new_part;
+    taper_source_class->get_first_header = taper_file_source_get_first_header;
+    taper_source_class->predict_parts = taper_file_source_predict_parts;
+
+    g_object_class->finalize = taper_file_source_finalize;
+}
+
+static void compute_splits(TaperFileSource * self) {
+    guint64 total_kb;
+    int predicted_splits;
+    TaperSource * pself = (TaperSource*)self;
+
+    if (selfp->predicted_splits > 0) {
+        return;
+    }
+
+    if (pself->max_part_size <= 0) {
+        selfp->predicted_splits = 1;
+        return;
+    }
+
+    total_kb = holding_file_size(self->holding_disk_file, TRUE);
+    if (total_kb <= 0) {
+        g_fprintf(stderr, "taper: %lld KB holding file makes no sense, not precalculating splits\n",
+               (long long)total_kb);
+        fflush(stderr);
+        selfp->predicted_splits = -1;
+        return;
+    }
+    
+    g_fprintf(stderr, "taper: Total dump size should be %jukb, part size is %jukb\n",
+            (uintmax_t)total_kb, (uintmax_t)pself->max_part_size);
+
+    predicted_splits = (total_kb * 1024) / pself->max_part_size;
+    if (predicted_splits == 0 ||
+        (0 != ((total_kb * 1024) % pself->max_part_size))) {
+        predicted_splits ++;
+    }
+    selfp->predicted_splits = predicted_splits;
+}
+
+static int taper_file_source_predict_parts(TaperSource * pself) {
+    TaperFileSource * self = TAPER_FILE_SOURCE(pself);
+    g_return_val_if_fail(self != NULL, -1);
+
+    compute_splits(self);
+
+    return selfp->predicted_splits;
+}
+
+static dumpfile_t * taper_file_source_get_first_header(TaperSource * pself) {
+    TaperFileSource * self = TAPER_FILE_SOURCE(pself);
+    g_return_val_if_fail(self != NULL, NULL);
+
+    first_time_setup(self);
+
+    if (parent_class->get_first_header) {
+        return (parent_class->get_first_header)(pself);
+    } else {
+        return NULL;
+    }
+}
+
+/* Open a holding disk and parse the header. Returns TRUE if
+   everything went OK. Writes the fd into fd_pointer and the header
+   into header_pointer. Both must be non-NULL. */
+static gboolean open_holding_file(char * filename, int * fd_pointer,
+                                  dumpfile_t * header_pointer) {
+    int fd;
+    int read_result;
+    char * header_buffer;
+
+    g_return_val_if_fail(filename != NULL, FALSE);
+    g_return_val_if_fail(fd_pointer != NULL, FALSE);
+    g_return_val_if_fail(header_pointer != NULL, FALSE);
+
+    fd = robust_open(filename, O_NOCTTY | O_RDONLY, 0);
+    if (fd < 0) {
+        g_fprintf(stderr, "Could not open holding disk file %s: %s\n",
+                filename, strerror(errno));
+        return FALSE;
+    }
+
+    header_buffer = malloc(DISK_BLOCK_BYTES);
+    read_result = fullread(fd, header_buffer, DISK_BLOCK_BYTES);
+    if (read_result < DISK_BLOCK_BYTES) {
+        g_fprintf(stderr,
+                "Could not read header from holding disk file %s: %s\n",
+                filename, strerror(errno));
+        aclose(fd);
+        return FALSE;
+    }
+    
+    parse_file_header(header_buffer, header_pointer, DISK_BLOCK_BYTES);
+    amfree(header_buffer);
+    
+    if (!(header_pointer->type == F_DUMPFILE ||
+          header_pointer->type == F_CONT_DUMPFILE)) {
+        g_fprintf(stderr, "Got strange header from file %s.\n",
+                filename);
+        aclose(fd);
+        return FALSE;
+    }
+    
+    *fd_pointer = fd;
+    return TRUE;
+}
+
+/* Copy fd and header information from first chunk fields to current
+   chunk. Returns FALSE if an error occurs (unlikely). */
+static gboolean copy_chunk_data(int * from_fd, int* to_fd,
+                                dumpfile_t * from_header,
+                                dumpfile_t * to_header) {
+    g_return_val_if_fail(from_fd != NULL, FALSE);
+    g_return_val_if_fail(to_fd != NULL, FALSE);
+    g_return_val_if_fail(from_header != NULL, FALSE);
+    g_return_val_if_fail(to_header != NULL, FALSE);
+    g_return_val_if_fail(*to_fd < 0, FALSE);
+    
+    *to_fd = dup(*from_fd);
+    if (*to_fd < 0) {
+        g_fprintf(stderr, "dup(%d) failed!\n", *from_fd);
+        return FALSE;
+    }
+
+    memcpy(to_header, from_header, sizeof(*to_header));
+
+    return TRUE;
+}
+
+
+static gboolean first_time_setup(TaperFileSource * self) {
+    TaperSource * pself = (TaperSource*)self;
+
+    if (selfp->part_start_chunk_fd >= 0) {
+        return TRUE;
+    }
+
+    g_return_val_if_fail(self->holding_disk_file != NULL, FALSE);
+
+    if (!open_holding_file(self->holding_disk_file, 
+                           &(selfp->part_start_chunk_fd),
+                           &(selfp->part_start_chunk_header))) {
+        return FALSE;
+    }
+
+    /* We are all set; just copy the "start chunk" datums into the
+       "current chunk" fields. */
+    if (!copy_chunk_data(&(selfp->part_start_chunk_fd),
+                         &(selfp->current_chunk_fd),
+                         &(selfp->part_start_chunk_header),
+                         &(selfp->current_chunk_header))) {
+        aclose(selfp->part_start_chunk_fd);
+        return FALSE;
+    }
+
+    pself->first_header = g_memdup(&(selfp->part_start_chunk_header),
+                                   sizeof(dumpfile_t));
+
+    /* Should not be necessary. You never know! */
+    selfp->current_part_pos = selfp->part_start_chunk_offset =
+        selfp->current_chunk_position = 0;
+
+    return TRUE;
+}
+
+static int retry_read(int fd, void * buf, size_t count) {
+    for (;;) {
+        int read_result = read(fd, buf, count);
+        if (read_result < 0 && (0
+#ifdef EAGAIN
+                                || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                                || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                                || errno == EINTR
+#endif
+                  )) {
+            /* Try again. */
+            continue;
+        } else {
+            if (read_result < 0) {
+                g_fprintf(stderr, "Error reading holding disk: %s\n",
+                        strerror(errno));
+            }
+            return read_result;
+        }
+    }
+}
+
+/* If another chunk is available, load it. Returns TRUE if there are
+   no more chunks or the next chunk is loaded, or FALSE if an error
+   occurs. */
+static gboolean get_next_chunk(TaperFileSource * self) {
+    char * cont_filename = NULL;
+
+    if (selfp->current_chunk_header.cont_filename[0] != '\0') {
+        cont_filename =
+            g_strdup(selfp->current_chunk_header.cont_filename);
+    } else {
+        /* No more data. */
+        aclose(selfp->current_chunk_fd);
+        bzero(&(selfp->current_chunk_header),
+              sizeof(selfp->current_chunk_header));
+        return TRUE;
+    }
+
+    /* More data. */
+
+    aclose(selfp->current_chunk_fd);
+
+    if (!open_holding_file(cont_filename,
+                           &(selfp->current_chunk_fd),
+                           &(selfp->current_chunk_header))) {
+        amfree(cont_filename);
+        bzero(&(selfp->current_chunk_header),
+              sizeof(selfp->current_chunk_header));
+        aclose(selfp->current_chunk_fd);
+        return FALSE;
+    }
+
+    amfree(cont_filename);
+    selfp->current_chunk_position = 0;
+
+    return TRUE;
+}
+
+static ssize_t 
+taper_file_source_read (TaperSource * pself, void * buf, size_t count) {
+    TaperFileSource * self = (TaperFileSource*) pself;
+    int read_result;
+
+    g_return_val_if_fail (self != NULL, -1);
+    g_return_val_if_fail (TAPER_IS_FILE_SOURCE (self), -1);
+    g_return_val_if_fail (buf != NULL, -1);
+    g_return_val_if_fail (count > 0, -1);
+    
+    if (!first_time_setup(self))
+        return -1;
+
+    if (pself->max_part_size > 0) {
+        count = MIN(count, pself->max_part_size - selfp->current_part_pos);
+    }
+    if (count <= 0) {
+        /* Was positive before. Thus we are at EOP. */
+        pself->end_of_part = TRUE;
+        return 0;
+    }
+
+    /* We don't use fullread, because we would rather return a partial
+     * read ASAP. */
+    read_result = retry_read(selfp->current_chunk_fd, buf, count);
+    if (read_result < 0) {
+        /* Nothing we can do. */
+        return read_result;
+    } else if (read_result == 0) {
+        if (!get_next_chunk(self)) {
+            return -1; 
+        }
+
+        if (selfp->current_chunk_fd >= 0) {
+            /* Try again with the next chunk. */
+            return taper_file_source_read(pself, buf, count);
+        } else {
+            pself->end_of_data = TRUE;
+            return 0;
+        }
+    } else {
+        /* Success. */
+        selfp->current_part_pos += read_result;
+        selfp->current_chunk_position += read_result;
+        return read_result;
+    }
+}
+
+static gboolean taper_file_source_seek_to_part_start (TaperSource * pself) {
+    TaperFileSource * self = (TaperFileSource*)pself;
+    off_t lseek_result;
+
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (TAPER_IS_FILE_SOURCE (self), FALSE);
+
+    aclose(selfp->current_chunk_fd);
+    if (!copy_chunk_data(&(selfp->part_start_chunk_fd),
+                         &(selfp->current_chunk_fd),
+                         &(selfp->part_start_chunk_header),
+                         &(selfp->current_chunk_header))) {
+        return FALSE;
+    }
+
+    selfp->current_chunk_position = selfp->part_start_chunk_offset;
+
+    lseek_result = lseek(selfp->current_chunk_fd,
+                         DISK_BLOCK_BYTES + selfp->current_chunk_position,
+                         SEEK_SET);
+    if (lseek_result < 0) {
+        g_fprintf(stderr, "Could not seek holding disk file: %s\n",
+                strerror(errno));
+        return FALSE;
+    }
+
+    selfp->current_part_pos = 0;
+
+    if (parent_class->seek_to_part_start)
+        return parent_class->seek_to_part_start(pself);
+    else
+        return TRUE;
+}
+
+static void taper_file_source_start_new_part (TaperSource * pself) {
+    TaperFileSource * self = (TaperFileSource*)pself;
+    g_return_if_fail (self != NULL);
+    g_return_if_fail (TAPER_IS_FILE_SOURCE (self));
+
+    aclose(selfp->part_start_chunk_fd);
+    if (!copy_chunk_data(&(selfp->current_chunk_fd),
+                         &(selfp->part_start_chunk_fd),
+                         &(selfp->current_chunk_header),
+                         &(selfp->part_start_chunk_header))) {
+        /* We can't return FALSE. :-( Instead, we set things up so
+           they will fail on the next read(). */
+        aclose(selfp->current_chunk_fd);
+        aclose(selfp->part_start_chunk_fd);
+        return;
+    }
+
+    selfp->part_start_chunk_offset = selfp->current_chunk_position;
+    selfp->current_part_pos = 0;
+
+    if (parent_class->start_new_part)
+        parent_class->start_new_part(pself);
+}
+    
diff --git a/server-src/taper-file-source.h b/server-src/taper-file-source.h
new file mode 100644 (file)
index 0000000..8d2830b
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* The taper file source is a taper source (see taper-source.h)
+   used for the case where we are reading from the holding disk
+   (FILE-WRITE mode). */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "taper-source.h" 
+
+#ifndef __TAPER_FILE_SOURCE_H__
+#define __TAPER_FILE_SOURCE_H__
+
+/*
+ * Type checking and casting macros
+ */
+#define TAPER_TYPE_FILE_SOURCE (taper_file_source_get_type())
+#define TAPER_FILE_SOURCE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), taper_file_source_get_type(), TaperFileSource)
+#define TAPER_FILE_SOURCE_CONST(obj)   G_TYPE_CHECK_INSTANCE_CAST((obj), taper_file_source_get_type(), TaperFileSource const)
+#define TAPER_FILE_SOURCE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), taper_file_source_get_type(), TaperFileSourceClass)
+#define TAPER_IS_FILE_SOURCE(obj)      G_TYPE_CHECK_INSTANCE_TYPE((obj), taper_file_source_get_type ())
+
+#define TAPER_FILE_SOURCE_GET_CLASS(obj)       G_TYPE_INSTANCE_GET_CLASS((obj), taper_file_source_get_type(), TaperFileSourceClass)
+
+/* Private structure type */
+typedef struct _TaperFileSourcePrivate TaperFileSourcePrivate;
+
+/*
+ * Main object structure
+ */
+#ifndef __TYPEDEF_TAPER_FILE_SOURCE__
+#define __TYPEDEF_TAPER_FILE_SOURCE__
+typedef struct _TaperFileSource TaperFileSource;
+#endif
+struct _TaperFileSource {
+    TaperSource __parent__;
+    /*< private >*/
+    char * holding_disk_file;
+    TaperFileSourcePrivate *_priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _TaperFileSourceClass TaperFileSourceClass;
+struct _TaperFileSourceClass {
+    TaperSourceClass __parent__;
+};
+
+
+/*
+ * Public methods
+ */
+GType  taper_file_source_get_type      (void);
+
+#endif
diff --git a/server-src/taper-mem-port-source.c b/server-src/taper-mem-port-source.c
new file mode 100644 (file)
index 0000000..0540845
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#define selfp (self->_priv)
+
+#include "taper-mem-port-source.h"
+
+#include "physmem.h"
+
+struct _TaperMemPortSourcePrivate {
+    /* Actual size of this buffer is given by max_part_size in TaperSource. */
+    char * retry_buffer;
+    guint64 buffer_offset; /* Bytes read from buffer. */
+    guint64 buffer_len;    /* Bytes written to buffer. */
+    gboolean retry_mode;
+};
+/* here are local prototypes */
+static void taper_mem_port_source_init (TaperMemPortSource * o);
+static void taper_mem_port_source_class_init (TaperMemPortSourceClass * c);
+static ssize_t taper_mem_port_source_read (TaperSource * pself, void * buf,
+                                           size_t count);
+static gboolean taper_mem_port_source_seek_to_part_start (TaperSource * pself);
+static void taper_mem_port_source_start_new_part (TaperSource * pself);
+static int taper_mem_port_source_predict_parts(TaperSource * pself);
+
+/* pointer to the class of our parent */
+static TaperSourceClass * source_parent_class = NULL;
+static TaperPortSourceClass *parent_class = NULL;
+
+GType
+taper_mem_port_source_get_type (void)
+{
+    static GType type = 0;
+    
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (TaperMemPortSourceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) taper_mem_port_source_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (TaperMemPortSource),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) taper_mem_port_source_init,
+            NULL
+        };
+        
+        type = g_type_register_static (TAPER_TYPE_PORT_SOURCE,
+                                       "TaperMemPortSource", &info,
+                                       (GTypeFlags)0);
+    }
+    
+    return type;
+}
+
+static void
+taper_mem_port_source_finalize(GObject *obj_self) {
+    TaperMemPortSource *self = TAPER_MEM_PORT_SOURCE (obj_self);
+    if(G_OBJECT_CLASS(parent_class)->finalize)
+        (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+    amfree (self->_priv->retry_buffer);
+    amfree (self->_priv);
+}
+
+static void 
+taper_mem_port_source_init (TaperMemPortSource * o) {
+    o->_priv = malloc(sizeof(TaperMemPortSourcePrivate));
+    o->_priv->retry_buffer = NULL;
+    o->_priv->retry_mode = FALSE;
+    o->_priv->buffer_offset = o->_priv->buffer_len = 0;
+}
+
+static void 
+taper_mem_port_source_class_init (TaperMemPortSourceClass * c) {
+    GObjectClass *g_object_class = (GObjectClass*) c;
+    TaperSourceClass *taper_source_class = (TaperSourceClass *)c;
+    
+    parent_class = g_type_class_ref (TAPER_TYPE_PORT_SOURCE);
+    source_parent_class = (TaperSourceClass*)parent_class;
+    
+    taper_source_class->read = taper_mem_port_source_read;
+    taper_source_class->seek_to_part_start =
+        taper_mem_port_source_seek_to_part_start;
+    taper_source_class->start_new_part = taper_mem_port_source_start_new_part;
+    taper_source_class->predict_parts = taper_mem_port_source_predict_parts;
+
+    g_object_class->finalize = taper_mem_port_source_finalize;
+}
+
+static int taper_mem_port_source_predict_parts(TaperSource * pself) {
+    TaperMemPortSource * self = TAPER_MEM_PORT_SOURCE(pself);
+    g_return_val_if_fail(self != NULL, -1);
+
+    return -1;
+}
+
+/* Allocate buffer space, if it hasn't been done yet. */
+static void setup_retry_buffer(TaperMemPortSource * self) {
+    guint64 alloc_size;
+    guint64 max_usage;
+    if (selfp->retry_buffer != NULL)
+        return;
+
+    alloc_size = TAPER_SOURCE(self)->max_part_size;
+    if (alloc_size > SIZE_MAX) {
+        g_fprintf(stderr, "Fallback split size of %lld is greater that system maximum of %lld.\n",
+                (long long)alloc_size, (long long)SIZE_MAX);
+        alloc_size = SIZE_MAX;
+    }
+    
+    max_usage = physmem_available() * .95;
+    if (alloc_size > max_usage) {
+        g_fprintf(stderr, "Fallback split size of %lld is greater than 95%% of available memory (%lld bytes).\n", (long long)alloc_size, (long long)max_usage);
+        alloc_size = max_usage;
+    }
+    
+    if (alloc_size < DISK_BLOCK_BYTES * 10) {
+        g_fprintf(stderr, "Fallback split size of %ju is smaller than 10 blocks (%u bytes).\n",
+                 (uintmax_t)alloc_size, DISK_BLOCK_BYTES * 10);
+        alloc_size = DISK_BLOCK_BYTES * 10;
+    }
+    
+    TAPER_SOURCE(self)->max_part_size = alloc_size;
+    selfp->retry_buffer = malloc(alloc_size);
+}
+
+static ssize_t 
+taper_mem_port_source_read (TaperSource * pself, void * buf, size_t count) {
+    TaperMemPortSource * self = (TaperMemPortSource*)pself;
+    g_return_val_if_fail (self != NULL, -1);
+    g_return_val_if_fail (TAPER_IS_MEM_PORT_SOURCE (self), -1);
+    g_return_val_if_fail (buf != NULL, -1);
+    g_return_val_if_fail (count > 0, -1);
+    
+    if (selfp->retry_mode) {
+        g_assert(selfp->retry_buffer != NULL && selfp->buffer_len > 0);
+        count = MIN(count, selfp->buffer_len - selfp->buffer_offset);
+
+        if (count == 0) {
+            /* It was not before. */
+            pself->end_of_part = TRUE;
+            return 0;
+        }
+
+        memcpy(buf, selfp->retry_buffer + selfp->buffer_offset, count);
+        selfp->buffer_offset += count;
+        return count;
+    } else {
+        int read_result;
+        if (selfp->retry_buffer == NULL) {
+            setup_retry_buffer(self);
+        }
+
+        count = MIN(count, pself->max_part_size - selfp->buffer_len);
+        if (count == 0) /* it was nonzero before */ {
+            pself->end_of_part = TRUE;
+            return 0;
+        }
+        
+        read_result = source_parent_class->read(pself, buf, count);
+        /* TaperPortSource handles EOF and other goodness. */
+        if (read_result <= 0) {
+            return read_result;
+        }
+
+        /* All's well in the world. */
+        memcpy(selfp->retry_buffer + selfp->buffer_len,
+               buf, read_result);
+        selfp->buffer_len += read_result;
+
+        return read_result;
+    }
+
+    g_assert_not_reached();
+}
+
+static gboolean 
+taper_mem_port_source_seek_to_part_start (TaperSource * pself) {
+    TaperMemPortSource * self = (TaperMemPortSource*)pself;
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (TAPER_IS_MEM_PORT_SOURCE (self), FALSE);
+    g_return_val_if_fail (selfp->buffer_len > 0, FALSE);
+
+    selfp->retry_mode = TRUE;
+    selfp->buffer_offset = 0;
+
+    if (source_parent_class->seek_to_part_start)
+        return source_parent_class->seek_to_part_start(pself);
+    else
+        return TRUE;
+}
+
+static void 
+taper_mem_port_source_start_new_part (TaperSource * pself) {
+    TaperMemPortSource * self = (TaperMemPortSource*)pself;
+    g_return_if_fail (self != NULL);
+    g_return_if_fail (TAPER_IS_MEM_PORT_SOURCE (self));
+
+    selfp->buffer_offset = selfp->buffer_len = 0;
+    selfp->retry_mode = FALSE;
+
+    if (source_parent_class->start_new_part)
+        source_parent_class->start_new_part(pself);
+}
diff --git a/server-src/taper-mem-port-source.h b/server-src/taper-mem-port-source.h
new file mode 100644 (file)
index 0000000..5aa02f5
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* The taper memory port source is a taper source (see taper-source.h)
+   used for the case where we are reading directly from a client
+   (PORT-WRITE) and are using an in-memory buffer to hold split dump parts. */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "taper-port-source.h"
+
+#ifndef __TAPER_MEM_PORT_SOURCE_H__
+#define __TAPER_MEM_PORT_SOURCE_H__
+
+
+/*
+ * Type checking and casting macros
+ */
+#define TAPER_TYPE_MEM_PORT_SOURCE     (taper_mem_port_source_get_type())
+#define TAPER_MEM_PORT_SOURCE(obj)     G_TYPE_CHECK_INSTANCE_CAST((obj), taper_mem_port_source_get_type(), TaperMemPortSource)
+#define TAPER_MEM_PORT_SOURCE_CONST(obj)       G_TYPE_CHECK_INSTANCE_CAST((obj), taper_mem_port_source_get_type(), TaperMemPortSource const)
+#define TAPER_MEM_PORT_SOURCE_CLASS(klass)     G_TYPE_CHECK_CLASS_CAST((klass), taper_mem_port_source_get_type(), TaperMemPortSourceClass)
+#define TAPER_IS_MEM_PORT_SOURCE(obj)  G_TYPE_CHECK_INSTANCE_TYPE((obj), taper_mem_port_source_get_type ())
+
+#define TAPER_MEM_PORT_SOURCE_GET_CLASS(obj)   G_TYPE_INSTANCE_GET_CLASS((obj), taper_mem_port_source_get_type(), TaperMemPortSourceClass)
+
+/* Private structure type */
+typedef struct _TaperMemPortSourcePrivate TaperMemPortSourcePrivate;
+
+/*
+ * Main object structure
+ */
+#ifndef __TYPEDEF_TAPER_MEM_PORT_SOURCE__
+#define __TYPEDEF_TAPER_MEM_PORT_SOURCE__
+typedef struct _TaperMemPortSource TaperMemPortSource;
+#endif
+struct _TaperMemPortSource {
+    TaperPortSource __parent__;
+    /*< private >*/
+    TaperMemPortSourcePrivate *_priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _TaperMemPortSourceClass TaperMemPortSourceClass;
+struct _TaperMemPortSourceClass {
+       TaperPortSourceClass __parent__;
+};
+
+
+/*
+ * Public methods
+ */
+GType  taper_mem_port_source_get_type  (void);
+
+#endif
diff --git a/server-src/taper-port-source.c b/server-src/taper-port-source.c
new file mode 100644 (file)
index 0000000..e4666d4
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#define selfp (self->_priv)
+
+#include "taper-port-source.h"
+
+/* here are local prototypes */
+static void taper_port_source_class_init (TaperPortSourceClass * c);
+static ssize_t taper_port_source_read (TaperSource * pself, void * buf,
+                                       size_t count);
+static void taper_port_source_init (TaperPortSource * self);
+static gboolean taper_port_source_is_partial(TaperSource * self);
+static int taper_port_source_predict_parts(TaperSource * pself);
+static dumpfile_t * taper_port_source_get_first_header(TaperSource * pself);
+
+
+/* pointer to the class of our parent */
+static TaperSourceClass *parent_class = NULL;
+
+GType
+taper_port_source_get_type (void)
+{
+    static GType type = 0;
+    
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (TaperPortSourceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) taper_port_source_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (TaperPortSource),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) taper_port_source_init,
+            NULL
+        };
+        
+        type = g_type_register_static (TAPER_TYPE_SOURCE, "TaperPortSource",
+                                       &info, (GTypeFlags)0);
+    }
+    
+    return type;
+}
+
+static void taper_port_source_finalize(GObject * obj_self) {
+    TaperPortSource *self = TAPER_PORT_SOURCE(obj_self);
+    if (self->socket_fd >= 0) {
+        aclose(self->socket_fd);
+    }
+    
+    G_OBJECT_CLASS (parent_class)->finalize (obj_self);
+}
+
+static void taper_port_source_class_init (TaperPortSourceClass * c) {
+    TaperSourceClass *taper_source_class = (TaperSourceClass *)c;
+    GObjectClass *g_object_class = (GObjectClass*)c;
+    
+    parent_class = g_type_class_ref (TAPER_TYPE_SOURCE);
+
+    taper_source_class->read = taper_port_source_read;
+    taper_source_class->is_partial = taper_port_source_is_partial;
+    taper_source_class->get_first_header = taper_port_source_get_first_header;
+    taper_source_class->predict_parts = taper_port_source_predict_parts;
+
+    g_object_class->finalize = taper_port_source_finalize;
+}
+
+/* Check if the header has been read; if not, read and parse it. */
+static void check_first_header(TaperPortSource * self) {
+    TaperSource * pself = (TaperSource*)self;
+    char buf[DISK_BLOCK_BYTES];
+    int result;
+    dumpfile_t * rval;
+    
+    if (G_LIKELY(pself->first_header != NULL)) {
+        return;
+    }
+    
+    result = fullread(self->socket_fd, buf, DISK_BLOCK_BYTES);
+    if (result != DISK_BLOCK_BYTES) {
+        return;
+    }
+    rval = malloc(sizeof(dumpfile_t));
+    parse_file_header(buf, rval, DISK_BLOCK_BYTES);
+    pself->first_header = rval;
+}
+
+static int taper_port_source_predict_parts(TaperSource * pself) {
+    TaperPortSource * self = TAPER_PORT_SOURCE(pself);
+    g_return_val_if_fail(self != NULL, -1);
+
+    return 1;
+}
+
+static dumpfile_t * taper_port_source_get_first_header(TaperSource * pself) {
+    TaperPortSource * self = TAPER_PORT_SOURCE(pself);
+    g_return_val_if_fail(self != NULL, NULL);
+
+    check_first_header(self);
+    
+    if (parent_class->get_first_header) {
+        return (parent_class->get_first_header)(pself);
+    } else {
+        return NULL;
+    }
+}
+
+static void taper_port_source_init (TaperPortSource * self) {
+    /* Subclasses may do as they please, but if we are the final word,
+       then there will be no rewinding. */
+    if (G_TYPE_FROM_INSTANCE(self) == TAPER_TYPE_PORT_SOURCE) {
+        TAPER_SOURCE(self)->max_part_size = 0;
+    }
+    self->socket_fd = -1;
+}
+
+static ssize_t taper_port_source_read (TaperSource * pself, void * buf,
+                                       size_t count) {
+    TaperPortSource * self = (TaperPortSource*)pself;
+    int read_result;
+    g_return_val_if_fail (self != NULL, -1);
+    g_return_val_if_fail (TAPER_IS_PORT_SOURCE (pself), -1);
+    g_return_val_if_fail (buf != NULL, -1);
+    g_return_val_if_fail (count > 0, -1);
+    
+    check_first_header(self);
+
+    for (;;) {
+        read_result = read(self->socket_fd, buf, count);
+        if (read_result > 0) {
+            return read_result;
+        } else if (read_result == 0) {
+            pself->end_of_data = TRUE;
+            aclose(self->socket_fd);
+            return 0;
+        } else if (0
+#ifdef EAGAIN
+                   || errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+                   || errno == EWOULDBLOCK
+#endif
+#ifdef EINTR
+                   || errno == EINTR
+#endif
+                   ) {
+            /* Try again. */
+            continue;
+        } else {
+            /* Error occured. */
+            return read_result;
+        }
+    }
+    
+    g_assert_not_reached();
+}
+
+static gboolean
+taper_port_source_is_partial(TaperSource * pself) {
+    cmd_t cmd;
+    struct cmdargs cmdargs;
+    TaperPortSource * self = (TaperPortSource*)pself;
+
+    g_return_val_if_fail(self->socket_fd < 0, FALSE);
+
+    /* Query DRIVER about partial dump. */
+    putresult(DUMPER_STATUS, "%s\n", pself->driver_handle);
+    cmd = getcmd(&cmdargs);
+    if (cmd == FAILED) {
+        return TRUE;
+    } else if (cmd == DONE) {
+        return FALSE;
+    } else {
+        error("Driver gave invalid response "
+              "to query DUMPER-STATUS.\n");
+        g_assert_not_reached();
+    }
+}
diff --git a/server-src/taper-port-source.h b/server-src/taper-port-source.h
new file mode 100644 (file)
index 0000000..155fbf1
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* The taper port source is a taper source (see taper-source.h)
+   used for the case where we are reading directly from a client
+   (PORT-WRITE). */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "taper-source.h"
+
+#ifndef __TAPER_PORT_SOURCE_H__
+#define __TAPER_PORT_SOURCE_H__
+
+/*
+ * Type checking and casting macros
+ */
+#define TAPER_TYPE_PORT_SOURCE (taper_port_source_get_type())
+#define TAPER_PORT_SOURCE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), taper_port_source_get_type(), TaperPortSource)
+#define TAPER_PORT_SOURCE_CONST(obj)   G_TYPE_CHECK_INSTANCE_CAST((obj), taper_port_source_get_type(), TaperPortSource const)
+#define TAPER_PORT_SOURCE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), taper_port_source_get_type(), TaperPortSourceClass)
+#define TAPER_IS_PORT_SOURCE(obj)      G_TYPE_CHECK_INSTANCE_TYPE((obj), taper_port_source_get_type ())
+
+#define TAPER_PORT_SOURCE_GET_CLASS(obj)       G_TYPE_INSTANCE_GET_CLASS((obj), taper_port_source_get_type(), TaperPortSourceClass)
+
+/*
+ * Main object structure
+ */
+#ifndef __TYPEDEF_TAPER_PORT_SOURCE__
+#define __TYPEDEF_TAPER_PORT_SOURCE__
+typedef struct _TaperPortSource TaperPortSource;
+#endif
+struct _TaperPortSource {
+    TaperSource __parent__;
+    /*< private >*/
+    int socket_fd; /* protected. */
+};
+
+/*
+ * Class definition
+ */
+typedef struct _TaperPortSourceClass TaperPortSourceClass;
+struct _TaperPortSourceClass {
+       TaperSourceClass __parent__;
+};
+
+
+/*
+ * Public methods
+ */
+GType  taper_port_source_get_type      (void);
+
+#endif
diff --git a/server-src/taper-source-test.c b/server-src/taper-source-test.c
new file mode 100644 (file)
index 0000000..ff731a6
--- /dev/null
@@ -0,0 +1,99 @@
+#include "taper-source.h"
+
+typedef struct {
+    guint64 tape_size;
+    guint64 tape_used;
+    ConsumerFunctor consumer;
+    gpointer consumer_data;
+} tape_info_t;
+
+/* A ConsumerFunctor. */
+static int size_limited_consumer(gpointer user_data, queue_buffer_t * buffer) {
+    tape_info_t * info = user_data;
+    int result;
+    
+    result = info->consumer(info->consumer_data, buffer);
+
+    info->tape_used += result;
+    if (info->tape_size < info->tape_used)
+        return -1;
+    else
+        return result;
+}
+
+int main(int argc, char ** argv) {
+    TaperSource * source;
+    tape_info_t info;
+    
+    g_type_init();
+
+    switch (argc) {
+    default:
+        g_fprintf(stderr, "USAGE: %16s volume-size ( holding-disk-file splitsize | \n"
+               "                                          "
+               "split-disk-buffer splitsize\n"
+               "                                          "
+               "fallback-splitsize )\n",
+               basename(argv[0]));
+        return EXIT_FAILURE;
+    case 4: {
+        /* FILE-WRITE */
+        guint64 splitsize = strtod(argv[3], NULL);
+        
+        source = taper_source_new("", FILE_WRITE, argv[2], -1, NULL, 
+                                  splitsize, 0);
+    }
+        break;
+    case 5: {
+        guint64 splitsize, fallback_splitsize;
+        splitsize = strtod(argv[3], NULL);
+        fallback_splitsize = strtod(argv[4], NULL);
+        
+        source = taper_source_new("", PORT_WRITE, NULL, STDIN_FILENO,
+                                  argv[2][0] == '\0' ? NULL : argv[2],
+                                  splitsize, fallback_splitsize);
+    }
+        break;
+    }
+
+    if (source == NULL)
+        return EXIT_FAILURE;
+
+    info.tape_used = 0;
+    info.tape_size = strtod(argv[1], NULL);
+    info.consumer = fd_write_consumer;
+    info.consumer_data = GINT_TO_POINTER(STDOUT_FILENO);
+
+    for (;;) {
+        gboolean success = do_consumer_producer_queue(taper_source_producer,
+                                                      source,
+                                                      size_limited_consumer,
+                                                      &info);
+
+        if (success) {
+            if (taper_source_get_end_of_data(source)) {
+                g_fprintf(stderr, "Got end of data.\n");
+                return EXIT_SUCCESS;
+            } else if (taper_source_get_end_of_part(source)) {
+                taper_source_start_new_part(source);
+                g_fprintf(stderr, "Finished part. Starting new one.\n");
+                continue;
+            } else {
+                g_fprintf(stderr, "Read error.\n");
+                return EXIT_FAILURE;
+            }
+        } else {
+            /* Write or read error. (we can't tell) */
+            info.tape_used = 0;
+            if (taper_source_seek_to_part_start(source)) {
+                g_fprintf(stderr, "Retrying a part.\n");
+                continue;
+            } else {
+                g_fprintf(stderr, "Couldn't seek. Dying.\n");
+                return EXIT_FAILURE;
+            }
+        }
+    }
+
+    g_assert_not_reached();
+}
diff --git a/server-src/taper-source.c b/server-src/taper-source.c
new file mode 100644 (file)
index 0000000..f0d3205
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#define selfp (self->_priv)
+
+#include "taper-source.h"
+#include "taper-file-source.h"
+#include "taper-port-source.h"
+#include "taper-disk-port-source.h"
+#include "taper-mem-port-source.h"
+
+/* here are local prototypes */
+static void taper_source_init (TaperSource * o);
+static void taper_source_class_init (TaperSourceClass * c);
+static void default_taper_source_start_new_part(TaperSource * self);
+static gboolean default_taper_source_is_partial(TaperSource * self);
+static gboolean default_taper_source_seek_to_part_start(TaperSource * self);
+static gboolean default_taper_source_get_end_of_data(TaperSource * self);
+static gboolean default_taper_source_get_end_of_part(TaperSource * self);
+static dumpfile_t * default_taper_source_get_first_header(TaperSource * self);
+
+/* pointer to the class of our parent */
+static GObjectClass *parent_class = NULL;
+
+GType
+taper_source_get_type (void)
+{
+    static GType type = 0;
+    
+    if G_UNLIKELY(type == 0) {
+        static const GTypeInfo info = {
+            sizeof (TaperSourceClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) taper_source_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL /* class_data */,
+            sizeof (TaperSource),
+            0 /* n_preallocs */,
+            (GInstanceInitFunc) taper_source_init,
+            NULL
+        };
+        
+        type = g_type_register_static (G_TYPE_OBJECT, "TaperSource", &info,
+                                       (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
+    }
+    
+    return type;
+}
+
+static void taper_source_finalize(GObject * obj_self) {
+    TaperSource * self = TAPER_SOURCE(obj_self);
+    
+    if (G_OBJECT_CLASS(parent_class)->finalize)
+        G_OBJECT_CLASS(parent_class)->finalize(obj_self);
+
+    if (self->first_header)
+        amfree(self->first_header);
+
+    if (self->driver_handle)
+        amfree(self->driver_handle);
+}
+
+static void 
+taper_source_init (TaperSource * o) {
+    o->end_of_data = FALSE;
+    o->end_of_part = FALSE;
+    o->max_part_size = G_MAXUINT64;
+    o->first_header = NULL;
+}
+
+static void 
+taper_source_class_init (TaperSourceClass * c) {
+    GObjectClass *g_object_class = (GObjectClass*) c;
+
+    parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+    c->read = NULL;
+    c->seek_to_part_start = default_taper_source_seek_to_part_start;
+    c->start_new_part = default_taper_source_start_new_part;
+    c->is_partial = default_taper_source_is_partial;
+    c->get_end_of_data = default_taper_source_get_end_of_data;
+    c->get_end_of_part = default_taper_source_get_end_of_part;
+    c->get_first_header = default_taper_source_get_first_header;
+    c->predict_parts = NULL;
+
+    g_object_class->finalize = taper_source_finalize;
+}
+
+TaperSource * taper_source_new(char * handle,
+                               cmd_t mode, char * holding_disk_file,
+                               int socket_fd,
+                               char * split_disk_buffer,
+                               guint64 splitsize,
+                               guint64 fallback_splitsize) {
+    TaperSource * source_rval;
+    g_return_val_if_fail(mode == FILE_WRITE || mode == PORT_WRITE, NULL);
+    if (mode == FILE_WRITE) {
+        TaperFileSource * file_rval;
+        g_return_val_if_fail(holding_disk_file != NULL, NULL);
+        g_return_val_if_fail(holding_disk_file[0] != '\0', NULL);
+
+        /* Return a TaperFileSource. */
+        
+        source_rval = (TaperSource*)
+            g_object_new(TAPER_TYPE_FILE_SOURCE, NULL);
+        file_rval = (TaperFileSource*) source_rval;
+
+        if (file_rval == NULL)
+            return NULL;
+
+        file_rval->holding_disk_file = g_strdup(holding_disk_file);
+        source_rval->max_part_size = splitsize;
+    } else {
+        TaperPortSource * port_rval;
+        g_return_val_if_fail(socket_fd >= 0, NULL);
+
+        if (split_disk_buffer != NULL) {
+            TaperDiskPortSource * disk_rval;
+            g_return_val_if_fail(split_disk_buffer[0] != '\0', NULL);
+            g_return_val_if_fail(splitsize > 0, NULL);
+            
+            /* Return a TaperDiskPortSource. */
+            source_rval = (TaperSource*)
+                g_object_new(TAPER_TYPE_DISK_PORT_SOURCE, NULL);
+            disk_rval = (TaperDiskPortSource*) source_rval;
+            port_rval = (TaperPortSource*) source_rval;
+
+            if (disk_rval == NULL)
+                return NULL;
+
+            disk_rval->buffer_dir_name = g_strdup(split_disk_buffer);
+            disk_rval->fallback_buffer_size = fallback_splitsize;
+            source_rval->max_part_size = splitsize;
+        } else {
+            if (splitsize != 0) {
+                TaperMemPortSource * mem_rval;
+                /* Return a TaperMemPortSource. */
+                if (fallback_splitsize == 0)
+                    fallback_splitsize = splitsize;
+                source_rval = (TaperSource*)
+                    g_object_new(TAPER_TYPE_MEM_PORT_SOURCE, NULL);
+                mem_rval = (TaperMemPortSource*) source_rval;
+                port_rval = (TaperPortSource*) source_rval;
+
+                if (mem_rval == NULL)
+                    return NULL;
+                
+                source_rval->max_part_size = fallback_splitsize;
+            } else {
+                /* Return a TaperPortSource. */
+                source_rval = (TaperSource*)
+                    g_object_new(TAPER_TYPE_PORT_SOURCE, NULL);
+                port_rval = (TaperPortSource*) source_rval;
+
+                if (source_rval == NULL)
+                    return NULL;
+            } 
+        }
+        
+        port_rval->socket_fd = socket_fd;
+    }
+
+    /* If we got here, we have a return value. */
+    source_rval->driver_handle = strdup(handle);
+    return source_rval;
+}
+
+/* Default implementations of virtual functions. */
+static void
+default_taper_source_start_new_part(TaperSource * self) {
+    self->end_of_part = FALSE;
+}
+
+static gboolean
+default_taper_source_seek_to_part_start(TaperSource * self) {
+    self->end_of_data = self->end_of_part = FALSE;
+
+    return TRUE;
+}
+
+static gboolean
+default_taper_source_is_partial(TaperSource * self) {
+    return self->first_header->is_partial;
+}
+
+static gboolean default_taper_source_get_end_of_data(TaperSource * self) {
+    return self->end_of_data;
+}
+static gboolean default_taper_source_get_end_of_part(TaperSource * self) {
+    return self->end_of_part;
+}
+static dumpfile_t* default_taper_source_get_first_header(TaperSource * self) {
+    if (self->first_header == NULL)
+       return NULL;
+    return dumpfile_copy(self->first_header);
+}
+
+/* The rest of these functions are vtable dispatch stubs. */
+
+ssize_t 
+taper_source_read (TaperSource * self, void * buf, size_t count)
+{
+    TaperSourceClass *klass;
+    g_return_val_if_fail (self != NULL, (ssize_t )-1);
+    g_return_val_if_fail (TAPER_IS_SOURCE (self), (ssize_t )-1);
+    g_return_val_if_fail (buf != NULL, (ssize_t )-1);
+    g_return_val_if_fail (count > 0, (ssize_t )-1);
+
+    if (self->end_of_data || self->end_of_part) {
+        return 0;
+    }
+
+    klass = TAPER_SOURCE_GET_CLASS(self);
+    
+    if(klass->read)
+        return (*klass->read)(self,buf,count);
+    else
+        return (ssize_t )(-1);
+}
+
+gboolean 
+taper_source_get_end_of_data (TaperSource * self)
+{
+    TaperSourceClass *klass;
+    g_return_val_if_fail (self != NULL, TRUE);
+    g_return_val_if_fail (TAPER_IS_SOURCE (self), TRUE);
+
+    klass = TAPER_SOURCE_GET_CLASS(self);
+    
+    g_return_val_if_fail(klass->get_end_of_data != NULL, TRUE);
+
+    return (*klass->get_end_of_data)(self);
+}
+
+gboolean 
+taper_source_get_end_of_part (TaperSource * self)
+{
+    TaperSourceClass *klass;
+    g_return_val_if_fail (self != NULL, TRUE);
+    g_return_val_if_fail (TAPER_IS_SOURCE (self), TRUE);
+
+    klass = TAPER_SOURCE_GET_CLASS(self);
+    
+    g_return_val_if_fail(klass->get_end_of_part != NULL, TRUE);
+
+    return (*klass->get_end_of_part)(self);
+}
+
+dumpfile_t *
+taper_source_get_first_header (TaperSource * self)
+{
+    TaperSourceClass *klass;
+    g_return_val_if_fail (self != NULL, NULL);
+    g_return_val_if_fail (TAPER_IS_SOURCE (self), NULL);
+
+    klass = TAPER_SOURCE_GET_CLASS(self);
+    
+    g_return_val_if_fail(klass->get_first_header != NULL, NULL);
+
+    return (*klass->get_first_header)(self);
+}
+
+int taper_source_predict_parts(TaperSource * self) {
+    TaperSourceClass *klass;
+    g_return_val_if_fail (self != NULL, -1);
+    g_return_val_if_fail (TAPER_IS_SOURCE (self), -1);
+
+    klass = TAPER_SOURCE_GET_CLASS(self);
+    
+    if (klass->predict_parts != NULL) {
+        return (*klass->predict_parts)(self);
+    } else {
+        return -1;
+    }
+}
+
+gboolean 
+taper_source_seek_to_part_start (TaperSource * self)
+{
+    TaperSourceClass *klass;
+    g_return_val_if_fail (self != NULL, (gboolean )0);
+    g_return_val_if_fail (TAPER_IS_SOURCE (self), (gboolean )0);
+    klass = TAPER_SOURCE_GET_CLASS(self);
+    
+    if(klass->seek_to_part_start)
+        return (*klass->seek_to_part_start)(self);
+    else
+        return (gboolean )(0);
+}
+
+void 
+taper_source_start_new_part (TaperSource * self)
+{
+    TaperSourceClass *klass;
+    g_return_if_fail (self != NULL);
+    g_return_if_fail (TAPER_IS_SOURCE (self));
+    klass = TAPER_SOURCE_GET_CLASS(self);
+    
+    if(klass->start_new_part)
+        (*klass->start_new_part)(self);
+}
+
+gboolean
+taper_source_is_partial (TaperSource * self)
+{
+    TaperSourceClass *klass;
+    g_return_val_if_fail (self != NULL, FALSE);
+    g_return_val_if_fail (TAPER_IS_SOURCE (self), FALSE);
+    g_return_val_if_fail (taper_source_get_end_of_data(self), FALSE);
+    klass = TAPER_SOURCE_GET_CLASS(self);
+    
+    if(klass->is_partial)
+        return (*klass->is_partial)(self);
+    else
+        return FALSE;
+}
+
+producer_result_t taper_source_producer(gpointer data,
+                                        queue_buffer_t * buffer,
+                                        int hint_size) {
+    TaperSource * source;
+    int result;
+
+    source = data;
+    g_assert(TAPER_IS_SOURCE(source));
+
+    buffer->offset = 0;
+    if (buffer->data == NULL) {
+        buffer->data = malloc(hint_size);
+        /* This allocation is more likely than most to fail. */
+        g_return_val_if_fail(buffer->data != NULL, PRODUCER_ERROR);
+        buffer->alloc_size = hint_size;
+    }
+
+    result = taper_source_read(source, buffer->data, buffer->alloc_size);
+    if (result > 0) {
+        buffer->data_size = result;
+        return PRODUCER_MORE;
+    } else if (result == 0) {
+        /* EOF or EOC? We are done here either way. */
+        return PRODUCER_FINISHED;
+    } else {
+        return PRODUCER_ERROR;
+    }
+
+    g_assert_not_reached();
+}
+
diff --git a/server-src/taper-source.h b/server-src/taper-source.h
new file mode 100644 (file)
index 0000000..37d0f7a
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 2006 Zmanda Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* The taper source object abstracts the different ways that taper can
+ * retrieve and buffer data on its way to the device. It handles all
+ * splitting up and re-reading of split-tape parts, as well as all
+ * holding-disk related actions. */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <amanda.h>
+#include "server_util.h"
+#include "fileheader.h"
+#include "queueing.h"
+
+#ifndef __TAPER_SOURCE_H__
+#define __TAPER_SOURCE_H__
+
+
+/*
+ * Type checking and casting macros
+ */
+#define TAPER_TYPE_SOURCE      (taper_source_get_type())
+#define TAPER_SOURCE(obj)      G_TYPE_CHECK_INSTANCE_CAST((obj), taper_source_get_type(), TaperSource)
+#define TAPER_SOURCE_CONST(obj)        G_TYPE_CHECK_INSTANCE_CAST((obj), taper_source_get_type(), TaperSource const)
+#define TAPER_SOURCE_CLASS(klass)      G_TYPE_CHECK_CLASS_CAST((klass), taper_source_get_type(), TaperSourceClass)
+#define TAPER_IS_SOURCE(obj)   G_TYPE_CHECK_INSTANCE_TYPE((obj), taper_source_get_type ())
+
+#define TAPER_SOURCE_GET_CLASS(obj)    G_TYPE_INSTANCE_GET_CLASS((obj), taper_source_get_type(), TaperSourceClass)
+
+/*
+ * Main object structure
+ */
+#ifndef __TYPEDEF_TAPER_SOURCE__
+#define __TYPEDEF_TAPER_SOURCE__
+typedef struct _TaperSource TaperSource;
+#endif
+struct _TaperSource {
+    GObject __parent__;
+    /*< private >*/
+    gboolean end_of_data; /* protected */
+    gboolean end_of_part; /* protected */
+    guint64 max_part_size; /* protected */
+    dumpfile_t * first_header;
+    char * driver_handle;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _TaperSourceClass TaperSourceClass;
+struct _TaperSourceClass {
+    GObjectClass __parent__;
+    ssize_t (* read) (TaperSource * self, void * buf, size_t count);
+    gboolean (* seek_to_part_start) (TaperSource * self);
+    void (* start_new_part) (TaperSource * self);
+    gboolean (* is_partial) (TaperSource * self);
+    gboolean (* get_end_of_data)(TaperSource * self);
+    gboolean (* get_end_of_part)(TaperSource * self);
+    dumpfile_t * (* get_first_header)(TaperSource * self);
+    int (* predict_parts)(TaperSource * self);
+};
+
+
+/*
+ * Public methods
+ */
+GType  taper_source_get_type   (void);
+ssize_t        taper_source_read       (TaperSource * self,
+                                       void * buf,
+                                       size_t count);
+gboolean       taper_source_get_end_of_data    (TaperSource * self);
+gboolean       taper_source_get_end_of_part    (TaperSource * self);
+dumpfile_t *    taper_source_get_first_header   (TaperSource * self);
+/* Returns -1 for an unknown number of splits, or a positive integer if the
+ * number of splits is exactly known. Should never return zero. */
+int             taper_source_predict_parts      (TaperSource * self);
+
+/* You can only call this function (and expect to get an accurate
+   result) if taper_source_get_end_of_data() has already returned
+   TRUE. */
+gboolean        taper_source_is_partial         (TaperSource * self);
+
+gboolean       taper_source_seek_to_part_start (TaperSource * self);
+void   taper_source_start_new_part     (TaperSource * self);
+
+/* This function is how you get a taper source. Call it with the
+   relevant parameters, and the return value is yours to
+   keep. Arguments must be consistant (e.g., if you specify FILE_WRITE
+   mode, then you must provide a holding disk file). Input strings are
+   copied internally. */
+TaperSource * taper_source_new(char * handle,
+                               cmd_t mode, char * holding_disk_file,
+                               int socket_fd,
+                               char * split_disk_buffer,
+                               guint64 splitsize,
+                               guint64 fallback_splitsize);
+
+/* This function is a ProducerFunctor, as that type is defined in
+   device-src/queueing.h. */
+producer_result_t taper_source_producer(gpointer taper_source,
+                                        queue_buffer_t * buffer,
+                                        int hint_size);
+
+#endif