]> git.sur5r.net Git - bacula/bacula/commitdiff
Initial revision
authorKern Sibbald <kern@sibbald.com>
Tue, 23 Apr 2002 19:48:51 +0000 (19:48 +0000)
committerKern Sibbald <kern@sibbald.com>
Tue, 23 Apr 2002 19:48:51 +0000 (19:48 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2 91ce42f0-d328-0410-95d8-f526ca767f89

300 files changed:
bacula/ABOUT-NLS [new file with mode: 0644]
bacula/COPYING [new file with mode: 0644]
bacula/ChangeLog [new file with mode: 0644]
bacula/INSTALL [new file with mode: 0644]
bacula/Makefile.in [new file with mode: 0755]
bacula/README [new file with mode: 0644]
bacula/autoconf/Make.common.in [new file with mode: 0644]
bacula/autoconf/acconfig.h [new file with mode: 0644]
bacula/autoconf/aclocal.m4 [new file with mode: 0644]
bacula/autoconf/confdefs.h [new file with mode: 0644]
bacula/autoconf/config.guess [new file with mode: 0755]
bacula/autoconf/config.h.in [new file with mode: 0644]
bacula/autoconf/config.log [new file with mode: 0644]
bacula/autoconf/config.sub [new file with mode: 0755]
bacula/autoconf/configure.in [new file with mode: 0644]
bacula/autoconf/gnome-macros/Makefile [new file with mode: 0644]
bacula/autoconf/gnome-macros/Makefile.am [new file with mode: 0644]
bacula/autoconf/gnome-macros/Makefile.in [new file with mode: 0644]
bacula/autoconf/gnome-macros/aclocal-include.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/autogen.sh [new file with mode: 0644]
bacula/autoconf/gnome-macros/compiler-flags.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/curses.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-bonobo-check.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-common.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-fileutils.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-ghttp-check.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-gnorba-check.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-guile-checks.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-libgtop-check.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-objc-checks.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-orbit-check.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-print-check.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-pthread-check.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-support.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-undelfs.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-vfs.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-x-checks.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome-xml-check.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gnome.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/gperf-check.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/linger.m4 [new file with mode: 0644]
bacula/autoconf/gnome-macros/need-declaration.m4 [new file with mode: 0644]
bacula/autoconf/install-sh [new file with mode: 0755]
bacula/autoconf/install.sh [new file with mode: 0755]
bacula/autoconf/mkinstalldirs [new file with mode: 0755]
bacula/configure [new file with mode: 0755]
bacula/intl/ChangeLog [new file with mode: 0644]
bacula/intl/Makefile.in [new file with mode: 0644]
bacula/intl/VERSION [new file with mode: 0644]
bacula/intl/bindtextdom.c [new file with mode: 0644]
bacula/intl/cat-compat.c [new file with mode: 0644]
bacula/intl/dcgettext.c [new file with mode: 0644]
bacula/intl/dgettext.c [new file with mode: 0644]
bacula/intl/explodename.c [new file with mode: 0644]
bacula/intl/finddomain.c [new file with mode: 0644]
bacula/intl/gettext.c [new file with mode: 0644]
bacula/intl/gettext.h [new file with mode: 0644]
bacula/intl/gettextP.h [new file with mode: 0644]
bacula/intl/hash-string.h [new file with mode: 0644]
bacula/intl/intl-compat.c [new file with mode: 0644]
bacula/intl/l10nflist.c [new file with mode: 0644]
bacula/intl/libgettext.h [new file with mode: 0644]
bacula/intl/linux-msg.sed [new file with mode: 0644]
bacula/intl/loadinfo.h [new file with mode: 0644]
bacula/intl/loadmsgcat.c [new file with mode: 0644]
bacula/intl/localealias.c [new file with mode: 0644]
bacula/intl/po2tbl.sed [new file with mode: 0644]
bacula/intl/po2tbl.sed.in [new file with mode: 0644]
bacula/intl/textdomain.c [new file with mode: 0644]
bacula/intl/xopen-msg.sed [new file with mode: 0644]
bacula/platforms/Makefile.in [new file with mode: 0644]
bacula/platforms/README [new file with mode: 0644]
bacula/platforms/freebsd/Makefile.in [new file with mode: 0644]
bacula/platforms/freebsd/bacula-dir.in [new file with mode: 0755]
bacula/platforms/freebsd/bacula-fd.in [new file with mode: 0755]
bacula/platforms/freebsd/bacula-sd.in [new file with mode: 0755]
bacula/platforms/install-symlinks [new file with mode: 0755]
bacula/platforms/redhat/Makefile.in [new file with mode: 0644]
bacula/platforms/redhat/bacula-dir.in [new file with mode: 0755]
bacula/platforms/redhat/bacula-fd.in [new file with mode: 0755]
bacula/platforms/redhat/bacula-sd.in [new file with mode: 0755]
bacula/platforms/solaris/Makefile.in [new file with mode: 0644]
bacula/platforms/solaris/bacula-dir.in [new file with mode: 0755]
bacula/platforms/solaris/bacula-fd.in [new file with mode: 0755]
bacula/platforms/solaris/bacula-sd.in [new file with mode: 0755]
bacula/platforms/unknown/Makefile.in [new file with mode: 0644]
bacula/po/ChangeLog [new file with mode: 0644]
bacula/po/Makefile.in [new file with mode: 0644]
bacula/po/Makefile.in.in [new file with mode: 0644]
bacula/po/POTFILES.in [new file with mode: 0644]
bacula/po/bacula.pot [new file with mode: 0644]
bacula/po/cat-id-tbl.c [new file with mode: 0644]
bacula/po/stamp-cat-id [new file with mode: 0644]
bacula/src/.indent.pro [new file with mode: 0644]
bacula/src/Makefile.in [new file with mode: 0644]
bacula/src/baconfig.h [new file with mode: 0644]
bacula/src/bacula.h [new file with mode: 0644]
bacula/src/bc_types.h [new file with mode: 0644]
bacula/src/c [new file with mode: 0644]
bacula/src/c.scr [new file with mode: 0644]
bacula/src/cats/Makefile.in [new file with mode: 0644]
bacula/src/cats/bdb.c [new file with mode: 0644]
bacula/src/cats/bdb.h [new file with mode: 0644]
bacula/src/cats/bdb_create.c [new file with mode: 0644]
bacula/src/cats/bdb_delete.c [new file with mode: 0644]
bacula/src/cats/bdb_find.c [new file with mode: 0644]
bacula/src/cats/bdb_get.c [new file with mode: 0644]
bacula/src/cats/bdb_list.c [new file with mode: 0644]
bacula/src/cats/bdb_update.c [new file with mode: 0755]
bacula/src/cats/cats.h [new file with mode: 0644]
bacula/src/cats/create_mysql_database.in [new file with mode: 0644]
bacula/src/cats/create_test_database [new file with mode: 0644]
bacula/src/cats/drop_mysql_tables.in [new file with mode: 0644]
bacula/src/cats/drop_test_tables [new file with mode: 0755]
bacula/src/cats/grant_mysql_privileges.in [new file with mode: 0644]
bacula/src/cats/grant_privileges [new file with mode: 0644]
bacula/src/cats/make_mysql_tables.in [new file with mode: 0644]
bacula/src/cats/make_sqlite_tables.in [new file with mode: 0644]
bacula/src/cats/make_test_tables [new file with mode: 0755]
bacula/src/cats/mysql.c [new file with mode: 0644]
bacula/src/cats/protos.h [new file with mode: 0644]
bacula/src/cats/sql.c [new file with mode: 0644]
bacula/src/cats/sql_create.c [new file with mode: 0644]
bacula/src/cats/sql_delete.c [new file with mode: 0644]
bacula/src/cats/sql_find.c [new file with mode: 0644]
bacula/src/cats/sql_get.c [new file with mode: 0644]
bacula/src/cats/sql_list.c [new file with mode: 0644]
bacula/src/cats/sql_update.c [new file with mode: 0644]
bacula/src/cats/sqlite.c [new file with mode: 0644]
bacula/src/cats/sqlite.in [new file with mode: 0644]
bacula/src/console.glade [new file with mode: 0644]
bacula/src/console/Makefile.in [new file with mode: 0644]
bacula/src/console/authenticate.c [new file with mode: 0644]
bacula/src/console/console.c [new file with mode: 0644]
bacula/src/console/console_conf.c [new file with mode: 0644]
bacula/src/console/console_conf.h [new file with mode: 0644]
bacula/src/count-doc [new file with mode: 0755]
bacula/src/count-lines [new file with mode: 0755]
bacula/src/dird/Makefile.in [new file with mode: 0644]
bacula/src/dird/README-config [new file with mode: 0644]
bacula/src/dird/authenticate.c [new file with mode: 0644]
bacula/src/dird/backup.c [new file with mode: 0644]
bacula/src/dird/bacula-dir.conf.in [new file with mode: 0644]
bacula/src/dird/catreq.c [new file with mode: 0644]
bacula/src/dird/dird.c [new file with mode: 0644]
bacula/src/dird/dird.h [new file with mode: 0644]
bacula/src/dird/dird_conf.c [new file with mode: 0644]
bacula/src/dird/dird_conf.h [new file with mode: 0644]
bacula/src/dird/fd_cmds.c [new file with mode: 0644]
bacula/src/dird/getmsg.c [new file with mode: 0644]
bacula/src/dird/job.c [new file with mode: 0644]
bacula/src/dird/mountreq.c [new file with mode: 0644]
bacula/src/dird/msgchan.c [new file with mode: 0644]
bacula/src/dird/newvol.c [new file with mode: 0644]
bacula/src/dird/protos.h [new file with mode: 0644]
bacula/src/dird/query.sql [new file with mode: 0644]
bacula/src/dird/restore.c [new file with mode: 0644]
bacula/src/dird/run_conf.c [new file with mode: 0644]
bacula/src/dird/scheduler.c [new file with mode: 0644]
bacula/src/dird/ua.h [new file with mode: 0644]
bacula/src/dird/ua_cmds.c [new file with mode: 0644]
bacula/src/dird/ua_dotcmds.c [new file with mode: 0644]
bacula/src/dird/ua_input.c [new file with mode: 0644]
bacula/src/dird/ua_output.c [new file with mode: 0644]
bacula/src/dird/ua_run.c [new file with mode: 0644]
bacula/src/dird/ua_select.c [new file with mode: 0644]
bacula/src/dird/ua_server.c [new file with mode: 0644]
bacula/src/dird/ua_status.c [new file with mode: 0644]
bacula/src/dird/verify.c [new file with mode: 0644]
bacula/src/filed/Makefile.in [new file with mode: 0755]
bacula/src/filed/authenticate.c [new file with mode: 0644]
bacula/src/filed/backup.c [new file with mode: 0644]
bacula/src/filed/bacula-fd.conf.in [new file with mode: 0644]
bacula/src/filed/estimate.c [new file with mode: 0644]
bacula/src/filed/filed.c [new file with mode: 0644]
bacula/src/filed/filed.h [new file with mode: 0644]
bacula/src/filed/filed_conf.c [new file with mode: 0644]
bacula/src/filed/filed_conf.h [new file with mode: 0644]
bacula/src/filed/job.c [new file with mode: 0644]
bacula/src/filed/protos.h [new file with mode: 0644]
bacula/src/filed/restore.c [new file with mode: 0644]
bacula/src/filed/status.c [new file with mode: 0755]
bacula/src/filed/verify.c [new file with mode: 0644]
bacula/src/filed/win32/Makefile.in [new file with mode: 0755]
bacula/src/filed/win32/bacula.bmp [new file with mode: 0644]
bacula/src/filed/win32/bacula.ico [new file with mode: 0644]
bacula/src/filed/win32/bacula.rc [new file with mode: 0644]
bacula/src/filed/win32/bin/Install.bat [new file with mode: 0755]
bacula/src/filed/win32/bin/Start.bat [new file with mode: 0755]
bacula/src/filed/win32/bin/Stop.bat [new file with mode: 0755]
bacula/src/filed/win32/bin/Uninstall.bat [new file with mode: 0755]
bacula/src/filed/win32/bin/btraceback [new file with mode: 0755]
bacula/src/filed/win32/bin/btraceback.gdb [new file with mode: 0755]
bacula/src/filed/win32/bin/cygwin1.dll [new file with mode: 0755]
bacula/src/filed/win32/bin/setup.bat [new file with mode: 0755]
bacula/src/filed/win32/error.ico [new file with mode: 0644]
bacula/src/filed/win32/idle.ico [new file with mode: 0644]
bacula/src/filed/win32/mymapi32.def [new file with mode: 0644]
bacula/src/filed/win32/popup.c [new file with mode: 0644]
bacula/src/filed/win32/running.ico [new file with mode: 0644]
bacula/src/filed/win32/saving.ico [new file with mode: 0644]
bacula/src/filed/win32/winabout.cpp [new file with mode: 0755]
bacula/src/filed/win32/winabout.h [new file with mode: 0755]
bacula/src/filed/win32/winbacula.h [new file with mode: 0755]
bacula/src/filed/win32/winevents.cpp [new file with mode: 0755]
bacula/src/filed/win32/winevents.h [new file with mode: 0755]
bacula/src/filed/win32/winmain.cpp [new file with mode: 0755]
bacula/src/filed/win32/winres.h [new file with mode: 0755]
bacula/src/filed/win32/winres.rc [new file with mode: 0644]
bacula/src/filed/win32/winservice.cpp [new file with mode: 0755]
bacula/src/filed/win32/winservice.h [new file with mode: 0755]
bacula/src/filed/win32/winstat.cpp [new file with mode: 0755]
bacula/src/filed/win32/winstat.h [new file with mode: 0755]
bacula/src/filed/win32/wintray.cpp [new file with mode: 0755]
bacula/src/filed/win32/wintray.h [new file with mode: 0755]
bacula/src/findlib/Makefile.in [new file with mode: 0644]
bacula/src/findlib/find.c [new file with mode: 0644]
bacula/src/findlib/find.h [new file with mode: 0755]
bacula/src/findlib/find_one.c [new file with mode: 0755]
bacula/src/findlib/match.c [new file with mode: 0644]
bacula/src/findlib/testresults.txt [new file with mode: 0644]
bacula/src/gcc-Wall [new file with mode: 0755]
bacula/src/jcr.h [new file with mode: 0644]
bacula/src/lib/Makefile.in [new file with mode: 0644]
bacula/src/lib/alloc.c [new file with mode: 0644]
bacula/src/lib/base64.c [new file with mode: 0644]
bacula/src/lib/bits.h [new file with mode: 0644]
bacula/src/lib/bnet.c [new file with mode: 0644]
bacula/src/lib/bnet_server.c [new file with mode: 0644]
bacula/src/lib/bshm.c [new file with mode: 0644]
bacula/src/lib/bshm.h [new file with mode: 0644]
bacula/src/lib/bsock.h [new file with mode: 0644]
bacula/src/lib/btime.c [new file with mode: 0644]
bacula/src/lib/btime.h [new file with mode: 0644]
bacula/src/lib/cram-md5.c [new file with mode: 0644]
bacula/src/lib/crc32.c [new file with mode: 0644]
bacula/src/lib/daemon.c [new file with mode: 0644]
bacula/src/lib/events.c [new file with mode: 0644]
bacula/src/lib/fnmatch.c [new file with mode: 0644]
bacula/src/lib/fnmatch.h [new file with mode: 0644]
bacula/src/lib/gconsole [new file with mode: 0755]
bacula/src/lib/getopt.h [new file with mode: 0644]
bacula/src/lib/hmac.c [new file with mode: 0644]
bacula/src/lib/idcache.c [new file with mode: 0644]
bacula/src/lib/jcr.c [new file with mode: 0755]
bacula/src/lib/lex.c [new file with mode: 0644]
bacula/src/lib/lex.h [new file with mode: 0644]
bacula/src/lib/lib.h [new file with mode: 0644]
bacula/src/lib/md5.c [new file with mode: 0644]
bacula/src/lib/md5.h [new file with mode: 0644]
bacula/src/lib/mem_pool.c [new file with mode: 0644]
bacula/src/lib/mem_pool.h [new file with mode: 0644]
bacula/src/lib/message.c [new file with mode: 0755]
bacula/src/lib/message.h [new file with mode: 0644]
bacula/src/lib/parse_conf.c [new file with mode: 0755]
bacula/src/lib/parse_conf.h [new file with mode: 0644]
bacula/src/lib/protos.h [new file with mode: 0644]
bacula/src/lib/queue.c [new file with mode: 0644]
bacula/src/lib/queue.h [new file with mode: 0644]
bacula/src/lib/rwlock.c [new file with mode: 0644]
bacula/src/lib/rwlock.h [new file with mode: 0644]
bacula/src/lib/serial.c [new file with mode: 0644]
bacula/src/lib/serial.h [new file with mode: 0644]
bacula/src/lib/signal.c [new file with mode: 0644]
bacula/src/lib/smartall.c [new file with mode: 0644]
bacula/src/lib/smartall.h [new file with mode: 0644]
bacula/src/lib/tcpd.h [new file with mode: 0644]
bacula/src/lib/util.c [new file with mode: 0644]
bacula/src/lib/waitq.h [new file with mode: 0644]
bacula/src/lib/watchdog.c [new file with mode: 0755]
bacula/src/lib/workq.c [new file with mode: 0755]
bacula/src/lib/workq.h [new file with mode: 0644]
bacula/src/stored/Makefile.in [new file with mode: 0644]
bacula/src/stored/append.c [new file with mode: 0644]
bacula/src/stored/askdir.c [new file with mode: 0644]
bacula/src/stored/authenticate.c [new file with mode: 0644]
bacula/src/stored/bacula-sd.conf.in [new file with mode: 0644]
bacula/src/stored/bextract.c [new file with mode: 0644]
bacula/src/stored/block.c [new file with mode: 0644]
bacula/src/stored/block.h [new file with mode: 0644]
bacula/src/stored/bls.c [new file with mode: 0644]
bacula/src/stored/bscan.c [new file with mode: 0644]
bacula/src/stored/btape.c [new file with mode: 0644]
bacula/src/stored/dev.c [new file with mode: 0644]
bacula/src/stored/dev.h [new file with mode: 0644]
bacula/src/stored/device.c [new file with mode: 0644]
bacula/src/stored/dircmd.c [new file with mode: 0644]
bacula/src/stored/fd_cmds.c [new file with mode: 0644]
bacula/src/stored/job.c [new file with mode: 0644]
bacula/src/stored/label.c [new file with mode: 0644]
bacula/src/stored/protos.h [new file with mode: 0644]
bacula/src/stored/read.c [new file with mode: 0644]
bacula/src/stored/record.c [new file with mode: 0644]
bacula/src/stored/record.h [new file with mode: 0644]
bacula/src/stored/stored.c [new file with mode: 0644]
bacula/src/stored/stored.conf.in [new file with mode: 0644]
bacula/src/stored/stored.h [new file with mode: 0644]
bacula/src/stored/stored_conf.c [new file with mode: 0644]
bacula/src/stored/stored_conf.h [new file with mode: 0644]
bacula/src/version.h [new file with mode: 0644]

diff --git a/bacula/ABOUT-NLS b/bacula/ABOUT-NLS
new file mode 100644 (file)
index 0000000..28d38c7
--- /dev/null
@@ -0,0 +1,226 @@
+Notes on the Free Translation Project
+*************************************
+
+   Free software is going international!  The Free Translation Project
+is a way to get maintainers of free software, translators, and users all
+together, so that will gradually become able to speak many languages.
+A few packages already provide translations for their messages.
+
+   If you found this `ABOUT-NLS' file inside a distribution, you may
+assume that the distributed package does use GNU `gettext' internally,
+itself available at your nearest GNU archive site.  But you do *not*
+need to install GNU `gettext' prior to configuring, installing or using
+this package with messages translated.
+
+   Installers will find here some useful hints.  These notes also
+explain how users should proceed for getting the programs to use the
+available translations.  They tell how people wanting to contribute and
+work at translations should contact the appropriate team.
+
+   When reporting bugs in the `intl/' directory or bugs which may be
+related to internationalization, you should tell about the version of
+`gettext' which is used.  The information can be found in the
+`intl/VERSION' file, in internationalized packages.
+
+One advise in advance
+=====================
+
+   If you want to exploit the full power of internationalization, you
+should configure it using
+
+     ./configure --with-included-gettext
+
+to force usage of internationalizing routines provided within this
+package, despite the existence of internationalizing capabilities in the
+operating system where this package is being installed.  So far, only
+the `gettext' implementation in the GNU C library version 2 provides as
+many features (such as locale alias or message inheritance) as the
+implementation here.  It is also not possible to offer this additional
+functionality on top of a `catgets' implementation.  Future versions of
+GNU `gettext' will very likely convey even more functionality.  So it
+might be a good idea to change to GNU `gettext' as soon as possible.
+
+   So you need not provide this option if you are using GNU libc 2 or
+you have installed a recent copy of the GNU gettext package with the
+included `libintl'.
+
+INSTALL Matters
+===============
+
+   Some packages are "localizable" when properly installed; the
+programs they contain can be made to speak your own native language.
+Most such packages use GNU `gettext'.  Other packages have their own
+ways to internationalization, predating GNU `gettext'.
+
+   By default, this package will be installed to allow translation of
+messages.  It will automatically detect whether the system provides
+usable `catgets' (if using this is selected by the installer) or
+`gettext' functions.  If neither is available, the GNU `gettext' own
+library will be used.  This library is wholly contained within this
+package, usually in the `intl/' subdirectory, so prior installation of
+the GNU `gettext' package is *not* required.  Installers may use
+special options at configuration time for changing the default
+behaviour.  The commands:
+
+     ./configure --with-included-gettext
+     ./configure --with-catgets
+     ./configure --disable-nls
+
+will respectively bypass any pre-existing `catgets' or `gettext' to use
+the internationalizing routines provided within this package, enable
+the use of the `catgets' functions (if found on the locale system), or
+else, *totally* disable translation of messages.
+
+   When you already have GNU `gettext' installed on your system and run
+configure without an option for your new package, `configure' will
+probably detect the previously built and installed `libintl.a' file and
+will decide to use this.  This might be not what is desirable.  You
+should use the more recent version of the GNU `gettext' library.  I.e.
+if the file `intl/VERSION' shows that the library which comes with this
+package is more recent, you should use
+
+     ./configure --with-included-gettext
+
+to prevent auto-detection.
+
+   By default the configuration process will not test for the `catgets'
+function and therefore they will not be used.  The reasons are already
+given above: the emulation on top of `catgets' cannot provide all the
+extensions provided by the GNU `gettext' library.  If you nevertheless
+want to use the `catgets' functions use
+
+     ./configure --with-catgets
+
+to enable the test for `catgets' (this causes no harm if `catgets' is
+not available on your system).  If you really select this option we
+would like to hear about the reasons because we cannot think of any
+good one ourself.
+
+   Internationalized packages have usually many `po/LL.po' files, where
+LL gives an ISO 639 two-letter code identifying the language.  Unless
+translations have been forbidden at `configure' time by using the
+`--disable-nls' switch, all available translations are installed
+together with the package.  However, the environment variable `LINGUAS'
+may be set, prior to configuration, to limit the installed set.
+`LINGUAS' should then contain a space separated list of two-letter
+codes, stating which languages are allowed.
+
+Using This Package
+==================
+
+   As a user, if your language has been installed for this package, you
+only have to set the `LANG' environment variable to the appropriate
+ISO 639 `LL' two-letter code prior to using the programs in the
+package.  For example, let's suppose that you speak German.  At the
+shell prompt, merely execute `setenv LANG de' (in `csh'),
+`export LANG; LANG=de' (in `sh') or `export LANG=de' (in `bash').  This
+can be done from your `.login' or `.profile' file, once and for all.
+
+   An operating system might already offer message localization for
+many of its programs, while other programs have been installed locally
+with the full capabilities of GNU `gettext'.  Just using `gettext'
+extended syntax for `LANG' would break proper localization of already
+available operating system programs.  In this case, users should set
+both `LANGUAGE' and `LANG' variables in their environment, as programs
+using GNU `gettext' give preference to `LANGUAGE'.  For example, some
+Swedish users would rather read translations in German than English for
+when Swedish is not available.  This is easily accomplished by setting
+`LANGUAGE' to `sv:de' while leaving `LANG' to `sv'.
+
+Translating Teams
+=================
+
+   For the Free Translation Project to be a success, we need interested
+people who like their own language and write it well, and who are also
+able to synergize with other translators speaking the same language.
+Each translation team has its own mailing list, courtesy of Linux
+International.  You may reach your translation team at the address
+`LL@li.org', replacing LL by the two-letter ISO 639 code for your
+language.  Language codes are *not* the same as the country codes given
+in ISO 3166.  The following translation teams exist, as of December
+1997:
+
+     Chinese `zh', Czech `cs', Danish `da', Dutch `nl', English `en',
+     Esperanto `eo', Finnish `fi', French `fr', German `de', Hungarian
+     `hu', Irish `ga', Italian `it', Indonesian `id', Japanese `ja',
+     Korean `ko', Latin `la', Norwegian `no', Persian `fa', Polish
+     `pl', Portuguese `pt', Russian `ru', Slovenian `sl', Spanish `es',
+     Swedish `sv', and Turkish `tr'.
+
+For example, you may reach the Chinese translation team by writing to
+`zh@li.org'.
+
+   If you'd like to volunteer to *work* at translating messages, you
+should become a member of the translating team for your own language.
+The subscribing address is *not* the same as the list itself, it has
+`-request' appended.  For example, speakers of Swedish can send a
+message to `sv-request@li.org', having this message body:
+
+     subscribe
+
+   Keep in mind that team members are expected to participate
+*actively* in translations, or at solving translational difficulties,
+rather than merely lurking around.  If your team does not exist yet and
+you want to start one, or if you are unsure about what to do or how to
+get started, please write to `translation@iro.umontreal.ca' to reach the
+coordinator for all translator teams.
+
+   The English team is special.  It works at improving and uniformizing
+the terminology in use.  Proven linguistic skill are praised more than
+programming skill, here.
+
+Available Packages
+==================
+
+   Languages are not equally supported in all packages.  The following
+matrix shows the current state of internationalization, as of December
+1997.  The matrix shows, in regard of each package, for which languages
+PO files have been submitted to translation coordination.
+
+     Ready PO files    cs da de en es fi fr it ja ko nl no pl pt ru sl sv
+                     .----------------------------------------------------.
+     bash            |       []          []          []                   |  3
+     bison           |       []          []          []                   |  3
+     clisp           |       [] [] []    []                               |  4
+     cpio            |       []    []    []       [] []    []             |  6
+     diffutils       |       []    []    []                []          [] |  5
+     enscript        |       []    [] [] []          []             []    |  6
+     fileutils       | []    []    []    []       [] []    [] []    [] [] | 10
+     findutils       |       []    []    [] []    [] []    []    []    [] |  9
+     flex            |             []    []       []                   [] |  4
+     gcal            |       []          []          []    []          [] |  5
+     gettext         |    [] []    []    []       [] [] [] [] []    [] [] | 12
+     grep            |       []    []    []       [] [] [] []    [] [] [] | 10
+     hello           |    [] []    []    []       [] [] [] [] []    [] [] | 11
+     id-utils        |       []          []                []             |  3
+     indent          |    [] []                   []       []    []       |  5
+     libc            |       []    []    []       [] []    []          [] |  7
+     m4              |       []          []    []    []          []    [] |  6
+     make            |       []    []    []       [] []    []             |  6
+     music           |                   []                []             |  2
+     ptx             |       []    []    []          [] [] [] []       [] |  8
+     recode          |    [] []    []    []          []    [] []    [] [] |  9
+     sh-utils        |       []    []    []          [] [] [] []       [] |  8
+     sharutils       | []    []    []    []          []                [] |  6
+     tar             | []    []          [] []    [] [] [] [] []    [] [] | 11
+     texinfo         | []    []          []                               |  3
+     textutils       | []    []    []    []       [] [] [] []          [] |  9
+     wdiff           | []    []    []    []          [] [] []          [] |  8
+                     `----------------------------------------------------'
+       17 languages    cs da de en es fi fr it ja ko nl no pl pt ru sl sv
+       27 packages      6  4 25  1 18  1 26  2  1 12 20  9 19  7  4  7 17  179
+
+   Some counters in the preceding matrix are higher than the number of
+visible blocks let us expect.  This is because a few extra PO files are
+used for implementing regional variants of languages, or language
+dialects.
+
+   For a PO file in the matrix above to be effective, the package to
+which it applies should also have been internationalized and
+distributed as such by its maintainer.  There might be an observable
+lag between the mere existence a PO file and its wide availability in a
+distribution.
+
+   If December 1997 seems to be old, you may fetch a more recent copy
+of this `ABOUT-NLS' file on most GNU archive sites.
+
diff --git a/bacula/COPYING b/bacula/COPYING
new file mode 100644 (file)
index 0000000..5087530
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+ */
diff --git a/bacula/ChangeLog b/bacula/ChangeLog
new file mode 100644 (file)
index 0000000..09d0172
--- /dev/null
@@ -0,0 +1,164 @@
+
+2002-04-22 Release 1.18
+- Applied Phil's configure.in fix for --prefix, ...
+- Fixed bug found by Phil (patch supplied) in updating
+  MD5 signatures (revert to 32 bit FileId, move "static"
+  variables into JCR) (catreq.c fd-cmds.c).
+- Reverted to using INTEGER for FileId in make_sql_tables
+  due to a bug in MySQL.
+- Change editing code to %d for FileId.
+- Remove sqlite in make distclean in cats directory.
+- Remove console.conf in console during make distclean
+- Remove gnome-console.conf during make distclean
+- Remove bacula-dir.conf during make distclean
+- Set default level when using Console if none specified.
+  Bug reported by Phil.
+- A simple . command from Console is ignored.   
+- Change program named from filed to bacual-fd in winmain.cpp
+- Change default config file for Win32 in winmain.cpp
+- Free namebuf on early return from find_one.c. Bug reported by
+  Phil.
+- Modify testfind.c to dump orphaned buffers.
+- Removed terabytes from parse_conf.c because of problems with
+  older gcc compilers.
+- Turn off gnome options in gnome-console by constructing empty
+  argv.
+
+2002-04-18 Release 1.17 Kern Sibbald
+- Ensure that platforms Makefiles are called for clean  
+  and distclean.
+- Hide a lot of Makefile messages with @
+- Applied Phil's configure.in patch. Thanks.
+- Doc updates, many to clarify points brought up by Phil.
+- Applied Phil's make_mysql_tables.in patch. Thanks.
+- Made authenticate.c in dird test bnet_send status.
+- Make label a bit more friendly with extra info message.
+- Add level 200 to debug info in run command.
+- Remove old code from findlib/testfind.c so that it compiles.
+- Add two minute max wait to cram-md5 authentication. Hopefully,
+  this will catch non-responding WinNT daemons.
+- Allow time and size modifiers to be upper or lower case.
+- Turn off old CYGWIN patch for pthread_cond_timedwait() bug that
+  now causes File daemon hangs on WinNT.
+- Fix mount messages for restore. Previous updates to save
+  broke the restore code.
+- By default write fixed block sizes rather than variable block
+  sizes.  My Sony DAT simply does not work (reread failures) with
+  variable block sizes.
+- Data split across tapes was not being correctly restored
+  (at least on DAT tapes). 
+- Implement MaximumBlockSize and MinumBlockSize statements in
+  Storage daemon so user can specify variable block sizes if
+  desired.
+- Return error if block checksum error on read (previously 
+  ignored).
+- Fixed some error messages in bls, and in some cases exit(1)
+  rather than ABORT. There remain ABORTs to be examined.
+- Made a local copy of tcpd.h and corrected the function 
+  prototype problem for C++.
+
+2002-04-14 First public release 1.16 Kern Sibbald
+ - Many intervening changes/updates.
+
+2001-09-29 Release 1.0 Kern Sibbald
+ - Fixes to problems found at John's
+   installation.
+ - See techlogs/kes25Sep01 for details
+
+2001-09-25 Release 1.0 Kern Sibbald
+ - Helped John install at his site.
+   He is backing up one Linux machine and
+   one Win2000 machine.
+
+2001-mm-dd Many releases
+ - Released internally.
+  
+2000-04-09 Release 0.4 Kern Sibbald
+ - Added a lot of Director configuration code. In      
+   part (a small part), the Director now uses the
+   bacula.conf file to know what to do. There still
+   remains a lot to do.
+ - The file search code is now integrated into the
+   MySQL database routines, and Bacula is now hooked
+   into the MySQL database (if so configured). Thus
+   all the database records are being created, though
+   there still remains some work in getting all the
+   details into the records (such as the Storage 
+   coordinates).
+ - I've defined how Volume pools work (see manual).
+ - I've defined error message handling though no code
+   is yet written.
+ - The following resources and records are implemented
+   in the Director configuration file (bacula.conf):
+    
+   Director
+     Name (passed to Storage daemon)
+   Client
+     Name, Address, Port
+     Password (not yet used)
+   Storage    
+     Name, Address, Port, Password, MediaType
+   Job
+     Name    
+     Type (not yet used)
+     Backup (only one permitted) 
+       Client, FileSet
+     Storage
+     Schedule, Messages, Pool (not used)
+   FileSet
+     Name  
+     Include (options ignored)
+     Exclude (no options)
+   Schedule (not used)
+     Name
+   Messages (not used)
+     Name       
+     Debug, syslog, mail, append (not used)
+   Catalog
+     Name
+     Address, Port, Password (not used)
+   Pool (not used)
+     Name
+     PoolType, MediaType (not used)
+
+ - Added Storage configuration routines.
+   Director
+     Name, password (verified against those sent by Director)
+   Storage
+     Name, Address, Port (address, port must correspond to Director's values)
+     Password, MediaType
+   Device
+     Name, MediaType (must correspond to those sent by Director)
+     Archive Device (defines device name)
+
+
+
+2000-03-10 Release 0.3 Kern Sibbald
+ - Implemented new base64 encoding for attributes.
+   This eliminates some of the error messages in the
+   sprintfs on the Solaris due to different stat() sizes.
+ - Implemented  the first cut of the file search routines for
+   the File daemon.  The exclusion lists work including wild
+   cards.   There is a lot of work to be done, but the basic
+   structure is now in place (wild cards do not yet work for
+   the include).
+ - Completed writing the memory pool code.  Now I must
+   implement it in the daemons.
+ - Modified the bacula start/stop script so that it has a
+   better chance of working on SGI and Solaris.
+ - The catalog code has not been converted to the new file
+   search code.
+
+2000-03-06 Release 0.2 Kern Sibbald
+ - Integrated John's fixes.
+ - Made Makefiles self configuring when Makefile.in is changed.
+ - Added a runit script in the top level that runs bacula
+ - Added a "bacula" script in the top level directory that
+   starts and stops the File daemon and the Storage daemon.
+
+2000-03-03 Release 0.1 Kern Sibbald
+ - Basic Director, File, and Storage daemons.
+   Standalone Catalog services using MySQL
+
+2000-01-22 Kern Sibbald
+   * Setup basic file structure with ./configure
diff --git a/bacula/INSTALL b/bacula/INSTALL
new file mode 100644 (file)
index 0000000..2998b61
--- /dev/null
@@ -0,0 +1,35 @@
+--------------------------------------------------------------------------
+Using GNU autoconfig
+--------------------------------------------------------------------------
+  1.    Read the Compiling and Installing section of the HTML manual
+        in the "doc" directory.
+
+  2.    Run   ./configure   to generate config.h and the various Makefiles.
+        ./configure --help   gives a list of possible options with slightly
+        longer descriptions in README.configure
+
+        You might look at the "defaultconfig" file in the top directory.
+        It is an example of what is probably reasonable for defaults.
+
+        Some systems require unusual options for compilation or linking that
+        the `configure' script does not know about.  You can give `configure'
+        initial values for variables by setting them in the environment.  Using
+        a Bourne-compatible shell, you can do that on the command line like
+        this:
+                CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+        Or on systems that have the `env' program, you can do it like this:
+                env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+        Or if you're using a non Bourne-compatible shell, you can do:
+                sh -c 'CFLAGS="-O2 -g" ./configure
+
+        A typical Bacula development configuration for Linux is:
+
+        CFLAGS="-g -Wall" ./configure --enable-smartalloc --enable-mysql
+          
+
+  3.    set any other main preferences (normally, you don't do this):
+            Edit "config.h"   if you didn't use ./configure options
+            If you're cross-compiling, edit the following in "config.h"
+
+  4.    Build it (repeat step 2 as desired):
+            make
diff --git a/bacula/Makefile.in b/bacula/Makefile.in
new file mode 100755 (executable)
index 0000000..2796af3
--- /dev/null
@@ -0,0 +1,172 @@
+# 
+# 
+@MCOMMON@
+
+working_dir=@working_dir@
+
+srcdir =       @srcdir@
+VPATH =        @srcdir@
+.PATH:         @srcdir@
+topdir = .
+thisdir = .
+
+
+first_rule: all
+dummy:
+
+subdirs = src doc src/lib src/findlib src/cats \
+         @READLINE_SRC@ src/console src/dird src/filed \
+         src/stored @GNOME_DIR@
+
+FDsubdirs = src/lib src/findlib src/filed
+
+DIST = INSTALL README.configure configure Makefile Makefile.in ChangeLog
+
+DIST_CFG = autoconf/aclocal.m4 autoconf/configure.in \
+       autoconf/config.h.in  autoconf/acconfig.h  autoconf/Make.common.in \
+       autoconf/install-sh autoconf/mkinstalldirs
+
+MKDIR = $(srcdir)/autoconf/mkinstalldirs
+
+#-------------------------------------------------------------------------
+
+all: Makefile
+       @for I in ${subdirs}; \
+         do (cd $$I; echo "==>Entering directory `pwd`"; $(MAKE) $@ || exit 1); done
+
+depend:
+       @for I in ${subdirs}; \
+         do (cd $$I; echo "==>Entering directory `pwd`"; $(MAKE) $@ || exit 1); done
+       
+bacula-fd: Makefile       
+       @for I in ${FDsubdirs}; \
+         do (cd $$I; echo "==>Entering directory `pwd`"; $(MAKE) all || exit 1); done
+
+#-------------------------------------------------------------------------
+configure: autoconf/configure.in autoconf/aclocal.m4 autoconf/acconfig.h autoconf/config.h.in
+       cd $(srcdir);
+       autoconf --localdir=$(srcdir)/autoconf \
+       autoconf/configure.in > configure
+       chmod 755 configure
+
+config.status:
+       if test -x config.status; then config.status --recheck; \
+       else $(SHELL) configure; fi
+
+autoconf/config.h.in: autoconf/configure.in autoconf/acconfig.h
+       cd $(srcdir);
+       autoheader --localdir=$(srcdir)/autoconf \
+       autoconf/configure.in > autoconf/config.h.in
+       chmod 644 autoconf/config.h.in
+
+installdirs:
+       $(MKDIR) $(DESTDIR)$(sbindir)
+       $(MKDIR) $(DESTDIR)$(sysconfdir)
+       $(MKDIR) $(DESTDIR)$(working_dir)
+#      $(MKDIR) $(DESTDIR)$(mandir)
+
+install: installdirs
+       $(INSTALL_SCRIPT) startmysql $(DESTDIR)$(sysconfdir)/startmysql
+       $(INSTALL_SCRIPT) stopmysql $(DESTDIR)$(sysconfdir)/stopmysql
+       $(INSTALL_SCRIPT) console $(DESTDIR)$(sysconfdir)/console
+       $(INSTALL_SCRIPT) bacula $(DESTDIR)$(sysconfdir)/bacula
+       $(INSTALL_SCRIPT) fd $(DESTDIR)$(sysconfdir)/fd
+       $(INSTALL_SCRIPT) btraceback $(DESTDIR)$(sysconfdir)/btraceback
+       $(INSTALL_DATA)   btraceback.gdb $(DESTDIR)$(sysconfdir)/btraceback.gdb
+       @for I in $(subdirs); do (cd $$I; $(MAKE) DESTDIR=$(DESTDIR) $@ || exit 1); done
+
+uninstall:
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) startmysql)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) stopmysql)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) console)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) bacula)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) fd)
+       @for I in $(subdirs); do (cd $$I; $(MAKE) DESTDIR=$(DESTDIR) $@ || exit 1); done
+
+install-autostart: install-autostart-dir install-autostart-fd install-autostart-sd
+
+install-autostart-dir:
+       (cd platforms; $(MAKE) $@ || exit 1) 
+
+install-autostart-fd:
+       (cd platforms; $(MAKE) $@ || exit 1) 
+
+install-autostart-sd:
+       (cd platforms; $(MAKE) $@ || exit 1) 
+
+uninstall-autostart: uninstall-autostart-dir uninstall-autostart-fd uninstall-autrun-sd
+
+uninstall-autostart-dir:
+       (cd platforms; $(MAKE) $@ || exit 1)
+
+uninstall-autostart-fd:
+       (cd platforms; $(MAKE) $@ || exit 1)
+
+uninstall-autostart-sd:
+       (cd platforms; $(MAKE) $@ || exit 1)
+
+Makefile: Makefile.in
+       cd $(topdir) \
+           && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+Makefiles:
+       $(SHELL) config.status
+       chmod 755 startmysql stopmysql bacula fd startit stopit btraceback
+       chmod 755 src/console/btraceback src/lib/btraceback            
+       chmod 755 src/dird/btraceback src/filed/btraceback
+       chmod 755 src/stored/btraceback
+       chmod 755 src/cats/make_mysql_tables src/cats/drop_mysql_tables
+       chmod 755 src/cats/make_test_tables src/cats/drop_test_tables
+       chmod 755 src/cats/create_mysql_database
+       chmod 755 src/cats/grant_mysql_privileges
+       chmod 755 src/cats/make_sqlite_tables
+
+clean:
+       @for I in ${subdirs}; \
+         do (cd $$I; echo "==>Entering directory `pwd`"; ${MAKE} $@ || exit 1); done
+       @(cd platforms; echo "==>Entering directory `pwd`"; ${MAKE} $@ || exit 1)
+       @$(RMF) *~ 1 2 3 core core.*
+
+# distclean goal is for making a clean source tree, but if you have run
+# configure from a different directory, then doesn't destroy all your
+# hardly compiled and linked stuff. That's why there is always $(srcdir)/
+# In that case most of those commands do nothing, except cleaning *~
+# and cleaning source links.
+distclean:
+       @for I in $(subdirs); do (cd $$I; $(MAKE) $@ || exit 1); done
+       @for I in $(subdirs); do (cd $$I; $(RMF) startit stopit btraceback btraceback.gdb); done
+       @(cd $(srcdir); $(RMF) *~ config.cache config.h config.log config.status)
+       @(cd $(srcdir); $(RMF) Makefile autoconf/Make.common)
+       @(cd platforms; echo "==>Entering directory `pwd`"; ${MAKE} $@ || exit 1)
+       @$(RMF) bacula fd Makefile startmysql stopmysql startit stopit btraceback
+       @$(RMF) *~ 1 2 3 core core.*
+       @$(RMF) working/*
+
+distdirs:
+       mkdir ../$(VERNAME);
+       mkdir ../$(VERNAME)/autoconf;
+       @for I in $(subdirs); do (cd $$I; $(MAKE) $@ || (echo "Failed to make distclean in $$I"; exit 0) ); done
+
+distcopy:
+       $(CP) -p $(DIST) ../$(VERNAME);
+       $(CP) -p $(DIST_CFG) ../$(VERNAME)/autoconf;
+       @for I in $(subdirs); do (cd $$I; $(MAKE) $@ || exit 1); done
+
+distrib: configure autoconf/config.h.in distdirs distcopy
+
+tar.gz:  ../$(VERNAME).tar.gz
+../$(VERNAME).tar.gz:
+       (cd ..; tar cvf - $(VERNAME) | gzip -f9 > $(VERNAME).tar.gz)
+
+tar.Z: ../$(VERNAME).tar.Z
+../$(VERNAME).tar.Z:
+       (cd ..; tar cvf - $(VERNAME) | compress > $(VERNAME).tar.Z)
+
+tar.bz2: ../$(VERNAME).tar.bz2
+../$(VERNAME).tar.bz2:
+       (cd ..; tar cvf - $(VERNAME) | bzip2 -f9 > $(VERNAME).tar.bz2)
+
+uuencode: tar.gz
+       uuencode ../$(VERNAME).tar.gz $(VERNAME).tar.gz > ../$(VERNAME).tgz.uu
+
+# ------------------------------------------------------------------------
diff --git a/bacula/README b/bacula/README
new file mode 100644 (file)
index 0000000..db6f596
--- /dev/null
@@ -0,0 +1,44 @@
+
+This is the first release of Bacula, and as such it
+is perhaps a bit rough around the edges. As you will
+note, I don't follow the standard GNU release numbering
+conventions, but rather one that I started in 1970.
+My internal releases were 0.nn, the first release to
+another user was 1.0, each modified source code release
+then gets a new minor release (1.1, ...) as well as
+a date. Each major change in the software -- e.g. new
+tape format will have the major release number incremented.
+
+Your best bet for getting Bacula up and running
+is to read the manual, which can be found in
+<bacula-main-directory>/doc/html-manual, or in
+<bacula-main-directory>/doc/bacula.pdf.
+
+Barring reading the manual, you might try the
+following:
+
+CFLAGS="-g -Wall" \
+  ./configure \
+    --sbindir=$HOME/bacula/bin \
+    --sysconfdir=$HOME/bacula/bin \
+    --with-pid-dir=$HOME/bacula/bin \
+    --with-subsys-dir=$HOME/bacula/bin \
+    --enable-gnome \
+    --with-mysql=$HOME/mysql \
+    --with-working-dir=$HOME/bacula/bin/working \
+    --with-dump-email=YOUR_EMAIL_ADDRESS \
+    --with-job-email=YOUR_EMAIL_ADDRESS \
+    --with-smtp-host=YOUR_SMTP_SERVER_ADDRESS \
+    --with-baseport=9101
+
+
+Build Bacula
+
+   make
+
+   There should be no errors.  The most likely source of
+   errors will probably come in the src/stored directory
+   in time.c or dev.c.  There may also be problems in
+   lib/signal.c as I currently pull in all Linux signals,
+   some of which may not be available on your system.
+
diff --git a/bacula/autoconf/Make.common.in b/bacula/autoconf/Make.common.in
new file mode 100644 (file)
index 0000000..e2d86db
--- /dev/null
@@ -0,0 +1,72 @@
+# autoconf/Make.common.in        -*- Makefile -*-
+# release date (man), LSM date, version number/name, current maintainer
+DATE="@DATE@"
+LSMDATE=@LSMDATE@
+VERSION=@VERSION@
+VERNAME=bacula-$(VERSION)#
+MAINT=Kern Sibbald#
+MAINTEMAIL=<kern@sibbald.com>#
+WEBMAINT=#
+WEBMAINTEMAIL=#
+WEBPAGE=#
+FTPSITENAME=#
+FTPSITEDIR=#
+#-------------------------------------------------------------------------
+
+SHELL = /bin/sh
+
+# This variable makes it possible to move the installation root to another
+# directory. This is useful when you're creating a binary distribution
+# If empty, normal root will be used.
+# You can run eg. 'make install DESTDIR=/packages/rxvt-xx' to accomplish
+# that.
+# DESTDIR = /usr/local/X11/$(VERNAME)
+
+# Installation target directories & other installation stuff
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+binprefix =
+manprefix =
+sbindir = @sbindir@
+sysconfdir = @sysconfdir@
+mandir = @mandir@/man1
+manext = 1
+
+# Tools & program stuff
+CC = @CC@
+CPP = @CPP@
+CXX = @CXX@
+MV = @MV@
+RM = @RM@
+RMF = @RM@ -f
+CP = @CP@
+SED = @SED@
+AWK = @AWK@
+ECHO = @ECHO@
+CMP = @CMP@
+TBL = @TBL@
+AR = @AR@
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+# add the -s to the following in PRODUCTION mode
+INSTALL_PROGRAM = @INSTALL@ -m 755
+INSTALL_DATA = @INSTALL@ -m 644
+INSTALL_SCRIPT = @INSTALL@ -m 755
+
+# Flags & libs
+CFLAGS = @CFLAGS@ 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+#DEFS = @DEFS@
+LIBS = @LIBS@
+DINCLUDE = @DINCLUDE@
+DLIB = @DLIB@
+
+# X Include directory
+#XINC = @X_CFLAGS@ @XPM_CFLAGS@
+
+# extra libraries needed by X on some systems, X library location
+#XLIB = @X_LIBS@ @XPM_LIBS@ -lX11 @X_EXTRA_LIBS@
+
+# End of common section of the Makefile
+#-------------------------------------------------------------------------
diff --git a/bacula/autoconf/acconfig.h b/bacula/autoconf/acconfig.h
new file mode 100644 (file)
index 0000000..f442ee2
--- /dev/null
@@ -0,0 +1,190 @@
+/* ------------------------------------------------------------------------- */
+/* --                     CONFIGURE SPECIFIED FEATURES                    -- */
+/* ------------------------------------------------------------------------- */
+   
+/* Define if you want to use MySQL as Catalog database */
+#undef USE_MYSQL_DB
+
+/* Define if you want SmartAlloc debug code enabled */
+#undef SMARTALLOC
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef daddr_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef major_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef minor_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef ssize_t
+
+/* Define if you want to use MySQL */
+#undef HAVE_MYSQL
+
+/* Define if you want to use SQLite */
+#undef HAVE_SQLITE
+
+/* Define if you want to use Berkeley DB */
+#undef HAVE_BERKELEY_DB
+
+
+/* Define if you want to use PostgreSQL */
+#undef HAVE_PGSQL
+
+/* Define if you want to use mSQL */
+#undef HAVE_MSQL
+
+/* Define if you want to use iODBC */
+#undef HAVE_IODBC
+
+/* Define if you want to use unixODBC */
+#undef HAVE_UNIXODBC
+
+/* Define if you want to use Solid SQL Server */
+#undef HAVE_SOLID
+
+/* Define if you want to use OpenLink ODBC (Virtuoso) */
+#undef HAVE_VIRT
+
+/* Define if you want to use EasySoft ODBC */
+#undef HAVE_EASYSOFT
+
+/* Define if you want to use Interbase SQL Server */
+#undef HAVE_IBASE
+
+/* Define if you want to use Oracle 8 SQL Server */
+#undef HAVE_ORACLE8
+
+/* Define if you want to use Oracle 7 SQL Server */
+#undef HAVE_ORACLE7
+
+
+/* ------------------------------------------------------------------------- */
+/* --                     CONFIGURE DETECTED FEATURES                     -- */
+/* ------------------------------------------------------------------------- */
+@TOP@
+
+/* Define if you need function prototypes */
+#undef PROTOTYPES
+
+/* Define if you have XPointer typedef */
+#undef HAVE_XPOINTER
+
+/* Define if you have _GNU_SOURCE getpt() */
+#undef HAVE_GETPT
+
+/* Define if you have GCC */
+#undef HAVE_GCC
+
+/* Define if you have the Andrew File System.  */
+#undef AFS
+
+/* Define If you want find -nouser and -nogroup to make tables of
+   used UIDs and GIDs at startup instead of using getpwuid or
+   getgrgid when needed.  Speeds up -nouser and -nogroup unless you
+   are running NIS or Hesiod, which make password and group calls
+   very expensive.  */
+#undef CACHE_IDS
+
+/* Define to use SVR4 statvfs to get filesystem type.  */
+#undef FSTYPE_STATVFS
+
+/* Define to use SVR3.2 statfs to get filesystem type.  */
+#undef FSTYPE_USG_STATFS
+
+/* Define to use AIX3 statfs to get filesystem type.  */
+#undef FSTYPE_AIX_STATFS
+
+/* Define to use 4.3BSD getmntent to get filesystem type.  */
+#undef FSTYPE_MNTENT
+
+/* Define to use 4.4BSD and OSF1 statfs to get filesystem type.  */
+#undef FSTYPE_STATFS
+
+/* Define to use Ultrix getmnt to get filesystem type.  */
+#undef FSTYPE_GETMNT
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define.  */
+#undef dev_t
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define.  */
+#undef ino_t
+
+/* Define to 1 if utime.h exists and declares struct utimbuf.  */
+#undef HAVE_UTIME_H
+
+#if (HAVE_MYSQL||HAVE_PGSQL||HAVE_MSQL||HAVE_IODBC||HAVE_UNIXODBC||HAVE_SOLID||HAVE_VIRT||HAVE_IBASE||HAVE_ORACLE8||HAVE_ORACLE7||HAVE_EASYSOFT)
+#define HAVE_SQL
+#endif
+
+/* Data types */
+#undef HAVE_U_INT
+#undef HAVE_INTXX_T
+#undef HAVE_U_INTXX_T
+#undef HAVE_UINTXX_T
+#undef HAVE_INT64_T
+#undef HAVE_U_INT64_T
+#undef HAVE_INTMAX_T
+#undef HAVE_U_INTMAX_T
+/* Define if you want TCP Wrappers support */
+#undef HAVE_LIBWRAP
+
+/* Define if you have sys/bitypes.h */
+#undef HAVE_SYS_BITYPES_H
+/* Directory for PID files */
+#undef _PATH_BACULA_PIDDIR
+
+/* Define if you have zlib */
+#undef HAVE_LIBZ
+
+/* General libs */
+#undef LIBS
+
+/* File daemon specif libraries */
+#undef FDLIBS
+
+/* Path to Sendmail program */
+#undef SENDMAIL_PATH
+
+/* What kind of signals we have */
+#undef HAVE_POSIX_SIGNALS
+#undef HAVE_BSD_SIGNALS
+#undef HAVE_USG_SIGHOLD
+
+/* Operating systems */
+/* OSes */
+#undef HAVE_LINUX_OS
+#undef HAVE_FREEBSD_OS
+#undef HAVE_NETBSD_OS
+#undef HAVE_OPENBSD_OS
+#undef HAVE_BSDI_OS
+#undef HAVE_HPUX_OS
+#undef HAVE_SUN_OS
+#undef HAVE_AIX_OS
+#undef HAVE_SGI_OS
+#undef HAVE_CYGWIN
+#undef HAVE_OSF1_OS
+
+/* Set to correct scanf value for long long int */
+#undef lld
+#undef llu
+
+#undef HAVE_READLINE 
+
+#undef HAVE_GMP
+
+#undef HAVE_CWEB
+
+#undef HAVE_FCHDIR
+
+#undef HAVE_LOCALTIME_R
+
+#undef HAVE_READDIR_R
+
+#undef HAVE_GETOPT_LONG
+
+#undef HAVE_LIBSM
diff --git a/bacula/autoconf/aclocal.m4 b/bacula/autoconf/aclocal.m4
new file mode 100644 (file)
index 0000000..017f853
--- /dev/null
@@ -0,0 +1,1176 @@
+dnl
+dnl If available, use support for large files unless the user specified
+dnl one of the CPPFLAGS, LDFLAGS, or LIBS variables (<eggert@twinsun.com>
+dnl via GNU patch 2.5)
+dnl
+AC_DEFUN(LARGE_FILE_SUPPORT,
+[AC_MSG_CHECKING(whether large file support needs explicit enabling)
+ac_getconfs=''
+ac_result=yes
+ac_set=''
+ac_shellvars='CPPFLAGS LDFLAGS LIBS'
+for ac_shellvar in $ac_shellvars; do
+  case $ac_shellvar in
+  CPPFLAGS) ac_lfsvar=LFS_CFLAGS ac_lfs64var=LFS64_CFLAGS ;;
+  *) ac_lfsvar=LFS_$ac_shellvar ac_lfs64var=LFS64_$ac_shellvar ;;
+  esac
+  eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar
+  (getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; }
+  ac_getconf=`getconf $ac_lfsvar`
+  ac_getconf64=`getconf $ac_lfs64var`
+  ac_getconfs=$ac_getconfs$ac_getconf\ $ac_getconf64
+  eval ac_test_$ac_shellvar="\$ac_getconf\ \$ac_getconf64"
+done
+case "$ac_result$ac_getconfs" in
+yes) ac_result=no ;;
+esac
+case "$ac_result$ac_set" in
+yes?*) ac_result="yes, but $ac_set is already set, so use its settings"
+esac
+AC_MSG_RESULT($ac_result)
+case $ac_result in
+yes)
+  for ac_shellvar in $ac_shellvars; do
+    eval $ac_shellvar=\$ac_test_$ac_shellvar
+  done ;;
+esac
+])
+
+dnl Check type of signal routines (posix, 4.2bsd, 4.1bsd or v7)
+AC_DEFUN(SIGNAL_CHECK,
+[AC_REQUIRE([AC_TYPE_SIGNAL])
+AC_MSG_CHECKING(for type of signal functions)
+AC_CACHE_VAL(bash_cv_signal_vintage,
+[
+  AC_TRY_LINK([#include <signal.h>],[
+    sigset_t ss;
+    struct sigaction sa;
+    sigemptyset(&ss); sigsuspend(&ss);
+    sigaction(SIGINT, &sa, (struct sigaction *) 0);
+    sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0);
+  ], bash_cv_signal_vintage=posix,
+  [
+    AC_TRY_LINK([#include <signal.h>], [
+        int mask = sigmask(SIGINT);
+        sigsetmask(mask); sigblock(mask); sigpause(mask);
+    ], bash_cv_signal_vintage=4.2bsd,
+    [
+      AC_TRY_LINK([
+        #include <signal.h>
+        RETSIGTYPE foo() { }], [
+                int mask = sigmask(SIGINT);
+                sigset(SIGINT, foo); sigrelse(SIGINT);
+                sighold(SIGINT); sigpause(SIGINT);
+        ], bash_cv_signal_vintage=svr3, bash_cv_signal_vintage=v7
+    )]
+  )]
+)
+])
+AC_MSG_RESULT($bash_cv_signal_vintage)
+if test "$bash_cv_signal_vintage" = posix; then
+AC_DEFINE(HAVE_POSIX_SIGNALS)
+elif test "$bash_cv_signal_vintage" = "4.2bsd"; then
+AC_DEFINE(HAVE_BSD_SIGNALS)
+elif test "$bash_cv_signal_vintage" = svr3; then
+AC_DEFINE(HAVE_USG_SIGHOLD)
+fi
+])
+
+AC_DEFUN(BA_CONDITIONAL,
+[AC_SUBST($1_TRUE)
+AC_SUBST($1_FALSE)
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi])
+
+
+AC_DEFUN(BA_CHECK_OPSYS,
+[AC_MSG_CHECKING(for Operating System)
+AC_CYGWIN
+if test $HAVE_UNAME=yes -a x`uname -s` = xSunOS
+then
+        BA_CONDITIONAL(HAVE_SUN_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_SUN_OS)
+else
+        BA_CONDITIONAL(HAVE_SUN_OS, $FALSEPRG)
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xOSF1
+then
+        BA_CONDITIONAL(HAVE_OSF1_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_OSF1_OS)
+else
+        BA_CONDITIONAL(HAVE_OSF1_OS, $FALSEPRG)
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xAIX
+then
+        BA_CONDITIONAL(HAVE_AIX_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_AIX_OS)
+else
+        BA_CONDITIONAL(HAVE_AIX_OS, $FALSEPRG)
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xHP-UX
+then
+        BA_CONDITIONAL(HAVE_HPUX_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_HPUX_OS)
+else
+        BA_CONDITIONAL(HAVE_HPUX_OS, $FALSEPRG)
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xLinux
+then
+        BA_CONDITIONAL(HAVE_LINUX_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_LINUX_OS)
+else
+        BA_CONDITIONAL(HAVE_LINUX_OS, $FALSEPRG)
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xFreeBSD
+then
+        BA_CONDITIONAL(HAVE_FREEBSD_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_FREEBSD_OS)
+else
+        BA_CONDITIONAL(HAVE_FREEBSD_OS, $FALSEPRG)
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xNetBSD
+then
+        BA_CONDITIONAL(HAVE_NETBSD_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_NETBSD_OS)
+else
+        BA_CONDITIONAL(HAVE_NETBSD_OS, $FALSEPRG)
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xOpenBSD
+then
+        BA_CONDITIONAL(HAVE_OPENBSD_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_OPENBSD_OS)
+else
+        BA_CONDITIONAL(HAVE_OPENBSD_OS, $FALSEPRG)
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xBSD/OS
+then
+        BA_CONDITIONAL(HAVE_BSDI_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_BSDI_OS)
+else
+        BA_CONDITIONAL(HAVE_BSDI_OS, $FALSEPRG)
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xSGI
+then
+        BA_CONDITIONAL(HAVE_SGI_OS, $TRUEPRG)
+        AC_DEFINE(HAVE_SGI_OS)
+else
+        BA_CONDITIONAL(HAVE_SGI_OS, $FALSEPRG)
+fi
+AC_MSG_RESULT(" ")
+])
+
+AC_DEFUN(BA_CHECK_OPSYS_DISTNAME,
+[AC_MSG_CHECKING(for Operating System Distribution)
+if test "x$DISTNAME" != "x"
+then
+        echo "distname set to $DISTNAME"
+elif test $HAVE_UNAME=yes -a x`uname -s` = xOSF1
+then
+        DISTNAME=alpha
+elif test $HAVE_UNAME=yes -a x`uname -s` = xHP-UX
+then
+        DISTNAME=hpux
+elif test $HAVE_UNAME=yes -a x`uname -s` = xSunOS
+then
+        DISTNAME=solaris
+elif test $HAVE_UNAME=yes -a x`uname -s` = xFreeBSD
+then
+        DISTNAME=freebsd
+elif test $HAVE_UNAME=yes -a x`uname -s` = xNetBSD
+then
+        DISTNAME=netbsd
+elif test $HAVE_UNAME=yes -a x`uname -s` = xOpenBSD
+then
+        DISTNAME=openbsd
+elif test $HAVE_UNAME=yes -a x`uname -s` = xBSD/OS
+then
+        DISTNAME=bsdi
+elif test -f /etc/SuSE-release
+then
+        DISTNAME=suse
+elif test -d /etc/SuSEconfig
+then
+        DISTNAME=suse5
+elif test -d /usr/src/OpenLinux
+then
+        DISTNAME=caldera
+elif test -f /etc/redhat-release
+then
+        DISTNAME=redhat
+elif test -f /etc/debian_version
+then
+        DISTNAME=debian
+elif test -f /etc/slackware-version
+then
+        DISTNAME=slackware
+elif test "$ac_cv_cygwin" = yes
+then
+        DISTNAME=cygwin
+        AC_DEFINE(HAVE_CYGWIN)
+else
+        DISTNAME=unknown
+fi
+AC_MSG_RESULT(" ")
+])
+
+AC_DEFUN(BA_CHECK_MYSQL_DB,
+[
+have_db=no
+db_name=none
+AC_MSG_CHECKING(for MySQL support)
+AC_ARG_WITH(mysql,
+[
+Which one DBMS do you want to use (please select only one):
+  --with-mysql[=DIR]      Include MySQL support.  DIR is the MySQL base
+                          install directory, default is to search through
+                          a number of common places for the MySQL files.],
+[
+  if test "$withval" != "no"; then
+        if test "$withval" = "yes"; then
+                if test -f /usr/local/mysql/include/mysql/mysql.h; then
+                        MYSQL_INCDIR=/usr/local/mysql/include/mysql
+                        MYSQL_LIBDIR=/usr/local/mysql/lib/mysql
+                        MYSQL_BINDIR=/usr/local/mysql/bin
+                elif test -f /usr/include/mysql/mysql.h; then
+                        MYSQL_INCDIR=/usr/include/mysql
+                        MYSQL_LIBDIR=/usr/lib/mysql
+                        MYSQL_BINDIR=/usr/bin      
+                elif test -f /usr/include/mysql.h; then
+                        MYSQL_INCDIR=/usr/include
+                        MYSQL_LIBDIR=/usr/lib
+                        MYSQL_BINDIR=/usr/bin
+                elif test -f /usr/local/include/mysql/mysql.h; then
+                        MYSQL_INCDIR=/usr/local/include/mysql
+                        MYSQL_LIBDIR=/usr/local/lib/mysql
+                        MYSQL_BINDIR=/usr/local/bin
+                elif test -f /usr/local/include/mysql.h; then
+                        MYSQL_INCDIR=/usr/local/include
+                        MYSQL_LIBDIR=/usr/local/lib
+                        MYSQL_BINDIR=/usr/local/bin
+                else
+                   AC_MSG_RESULT(no)
+                   AC_MSG_ERROR(Unable to find mysql.h in standard locations)
+                fi
+        else
+                if test -f $withval/include/mysql/mysql.h; then
+                        MYSQL_INCDIR=$withval/include/mysql
+                        MYSQL_LIBDIR=$withval/lib/mysql
+                        MYSQL_BINDIR=$withval/bin
+                elif test -f $withval/include/mysql.h; then
+                        MYSQL_INCDIR=$withval/include
+                        MYSQL_LIBDIR=$withval/lib
+                        MYSQL_BINDIR=$withval/bin
+                else
+                   AC_MSG_RESULT(no)
+                   AC_MSG_ERROR(Invalid MySQL directory $withval - unable to find mysql.h under $withval)
+                fi
+        fi
+    SQL_INCLUDE=-I$MYSQL_INCDIR
+    SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient"
+    SQL_BINDIR=$MYSQL_BINDIR
+
+    AC_DEFINE(HAVE_MYSQL)
+    AC_MSG_RESULT(yes)
+    have_db=yes
+    support_mysql=yes
+    db_name=MySQL
+
+  else
+        AC_MSG_RESULT(no)
+  fi
+],[
+  AC_MSG_RESULT(no)
+])
+AC_SUBST(SQL_LFLAGS)
+AC_SUBST(SQL_INCLUDE)
+AC_SUBST(SQL_BINDIR)
+  
+])
+
+
+AC_DEFUN(BA_CHECK_SQLITE_DB,
+[
+have_db=no
+db_name=none
+AC_MSG_CHECKING(for SQLite support)
+AC_ARG_WITH(sqlite,
+[
+Which one DBMS do you want to use (please select only one):
+  --with-sqlite[=DIR]     Include SQLite support.  DIR is the SQLite base
+                          install directory, default is to search through
+                          a number of common places for the SQLite files.],
+[
+  if test "$withval" != "no"; then
+        if test "$withval" = "yes"; then
+                if test -f /usr/local/include/sqlite.h; then
+                        SQLITE_INCDIR=/usr/local/include
+                        SQLITE_LIBDIR=/usr/local/lib
+                        SQLITE_BINDIR=/usr/local/bin
+                elif test -f /usr/include/sqlite.h; then
+                        SQLITE_INCDIR=/usr/include
+                        SQLITE_LIBDIR=/usr/lib
+                        SQLITE_BINDIR=/usr/bin      
+                else
+                   AC_MSG_RESULT(no)
+                   AC_MSG_ERROR(Unable to find sqlite.h in standard locations)
+                fi
+        else
+                if test -f $withval/sqlite.h; then
+                        SQLITE_INCDIR=$withval
+                        SQLITE_LIBDIR=$withval
+                        SQLITE_BINDIR=$withval
+                else
+                   AC_MSG_RESULT(no)
+                   AC_MSG_ERROR(Invalid SQLite directory $withval - unable to find sqlite.h under $withval)
+                fi
+        fi
+    SQL_INCLUDE=-I$SQLITE_INCDIR
+    SQL_LFLAGS="-L$SQLITE_LIBDIR -lsqlite"
+    SQL_BINDIR=$SQLITE_BINDIR
+
+    AC_DEFINE(HAVE_SQLITE)
+    AC_MSG_RESULT(yes)
+    have_db=yes
+    support_sqlite=yes
+    db_name=SQLite
+
+  else
+        AC_MSG_RESULT(no)
+  fi
+],[
+  AC_MSG_RESULT(no)
+])
+AC_SUBST(SQL_LFLAGS)
+AC_SUBST(SQL_INCLUDE)
+AC_SUBST(SQL_BINDIR)
+  
+])
+
+
+
+AC_DEFUN(BA_CHECK_SQL_DB, 
+[AC_MSG_CHECKING(Checking for various databases)
+dnl# --------------------------------------------------------------------------
+dnl# CHECKING FOR VARIOUS DATABASES (thanks to UdmSearch team)
+dnl# --------------------------------------------------------------------------
+dnl Check for some DBMS backend
+dnl NOTE: we can use only one backend at a time
+AC_MSG_RESULT(" ")
+
+have_db=no
+db_name=none
+
+
+
+if test x$support_mysql = xyes; then
+   cats=cats
+fi
+
+
+AC_MSG_CHECKING(for Berkeley DB support)
+AC_ARG_WITH(berkeleydb,
+[
+Which one DBMS do you want to use (please select only one):
+  --with-berkeleydb[=DIR] Include Berkeley DB support.  DIR is the Berkeley DB base
+                          install directory, default is to search through
+                          a number of common places for the DB files.],
+[
+  if test "$withval" != "no"; then
+        if test "$withval" = "yes"; then
+                if test -f /usr/include/db.h; then
+                        BERKELEYDB_INCDIR=/usr/include
+                        BERKELEYDB_LIBDIR=/usr/lib
+                else
+                AC_MSG_RESULT(no)
+                AC_MSG_ERROR(Invalid Berkeley DB directory - unable to find db.h)
+                fi
+        else
+                if test -f $withval/include/db.h; then
+                        BERKELEYDB_INCDIR=$withval/include
+                        BERKELEYDBL_LIBDIR=$withval/lib
+                else
+                AC_MSG_RESULT(no)
+                AC_MSG_ERROR(Invalid Berkeley DB directory - unable to find db.h under $withval)
+                fi
+        fi
+    SQL_INCLUDE=-I$BERKELEYDB_INCDIR
+    SQL_LFLAGS="-L$BERKELEYDB_LIBDIR -ldb"
+
+    AC_DEFINE(HAVE_BERKELEY_DB)
+    AC_MSG_RESULT(yes)
+    have_db=yes
+    support_mysql=yes
+    db_name=BerkelyDB
+
+  else
+        AC_MSG_RESULT(no)
+  fi
+],[
+  AC_MSG_RESULT(no)
+])
+AC_SUBST(SQL_LFLAGS)
+AC_SUBST(SQL_INCLUDE)
+
+if test x$support_berkleydb = xyes; then
+   cats=cats
+fi
+
+
+AC_MSG_CHECKING(for PostgreSQL support)
+AC_ARG_WITH(pgsql,
+[  --with-pgsql[=DIR]      Include PostgreSQL support.  DIR is the PostgreSQL
+                          base install directory, defaults to /usr/local/pgsql.],
+[
+  if test "$withval" != "no"; then
+      if test "$have_db" = "yes"; then
+          AC_MSG_RESULT(error)
+          AC_MSG_ERROR("You can configure for only one database.");
+      fi
+        if test "$withval" = "yes"; then
+                if test -f /usr/include/pgsql/libpq-fe.h; then
+                        PGSQL_INCDIR=/usr/include/pgsql
+                else
+                        PGSQL_INCDIR=/usr/local/pgsql/include
+                fi
+                if test -f /usr/lib/libpq.a; then
+                        PGSQL_LIBDIR=/usr/lib
+                else
+                        PGSQL_LIBDIR=/usr/local/pgsql/lib
+                fi
+        else
+                PGSQL_INCDIR=$withval/include
+                test -d $withval/include/pgsql && PGSQL_INCDIR=$withval/include/pgsql
+                PGSQL_LIBDIR=$withval/lib
+                test -d $withval/lib/pgsql && PGSQL_LIBDIR=$withval/lib/pgsql
+        fi
+    PGSQL_INCLUDE=-I$PGSQL_INCDIR
+    PGSQL_LFLAGS="-L$PGSQL_LIBDIR -lpq"
+    AC_CHECK_FUNC(crypt, , AC_CHECK_LIB(crypt, crypt, [LIBS="-lcrypt $LIBS"]))
+
+    AC_DEFINE(HAVE_PGSQL)
+    AC_MSG_RESULT(yes)
+    have_db=yes
+  else
+    AC_MSG_RESULT(no)
+  fi
+],[
+  AC_MSG_RESULT(no)
+])
+AC_SUBST(PGSQL_LFLAGS)
+AC_SUBST(PGSQL_INCLUDE)
+
+
+AC_MSG_CHECKING(for mSQL support)
+AC_ARG_WITH(msql,
+[  --with-msql[=DIR]       Include mSQL support.  DIR is the mSQL base
+                          install directory, defaults to /usr/local/Hughes.],
+[
+  if test "$withval" != "no"; then
+    if test "$have_db" = "yes"; then
+        AC_MSG_RESULT(error)
+        AC_MSG_ERROR("You can configure for only one database.");
+    fi
+
+    if test "$withval" = "yes"; then
+        MSQL_INCDIR=/usr/local/Hughes/include
+        MSQL_LIBDIR=/usr/local/Hughes/lib
+    else
+        MSQL_INCDIR=$withval/include
+        MSQL_LIBDIR=$withval/lib
+    fi
+    MSQL_INCLUDE=-I$MSQL_INCDIR
+    MSQL_LFLAGS="-L$MSQL_LIBDIR -lmsql"
+
+    AC_DEFINE(HAVE_MSQL)
+    AC_MSG_RESULT(yes)
+    have_db=yes
+  else
+        AC_MSG_RESULT(no)
+  fi
+],[
+  AC_MSG_RESULT(no)
+])
+AC_SUBST(MSQL_LFLAGS)
+AC_SUBST(MSQL_INCLUDE)
+
+
+AC_MSG_CHECKING(for iODBC support)
+AC_ARG_WITH(iodbc,
+[  --with-iodbc[=DIR]      Include iODBC support.  DIR is the iODBC base
+                          install directory, defaults to /usr/local.],
+[
+        if test "$withval" != "no"; then
+            if test "$have_db" = "yes"; then
+                AC_MSG_RESULT(error)
+                AC_MSG_ERROR("You can configure for only one database.");
+            fi
+        fi
+        
+        if test "$withval" = "yes"; then
+                withval=/usr/local
+        fi
+
+        if test "$withval" != "no"; then
+                if test -f $withval/include/isql.h; then
+                        IODBC_INCDIR=$withval/include
+                        IODBC_LIBDIR=$withval/lib
+                else
+                        AC_MSG_RESULT(no)
+                        AC_MSG_ERROR(Invalid iODBC directory - unable to find isql.h)
+                fi
+                IODBC_LFLAGS="-L$IODBC_LIBDIR -liodbc"
+                IODBC_INCLUDE=-I$IODBC_INCDIR
+                AC_DEFINE(HAVE_IODBC)
+                AC_MSG_RESULT(yes)
+                have_db=yes
+        fi
+],[
+        AC_MSG_RESULT(no)
+])
+AC_SUBST(IODBC_LFLAGS)
+AC_SUBST(IODBC_INCLUDE)
+
+
+AC_MSG_CHECKING(for unixODBC support)
+AC_ARG_WITH(unixODBC,
+[  --with-unixODBC[=DIR]   Include unixODBC support.  DIR is the unixODBC base
+                          install directory, defaults to /usr/local.],
+[
+        if test "$withval" != "no"; then
+            if test "$have_db" = "yes"; then
+                AC_MSG_RESULT(error)
+                AC_MSG_ERROR("You can configure for only one database.");
+            fi
+        fi
+        
+        if test "$withval" = "yes"; then
+                withval=/usr/local
+        fi
+
+        if test "$withval" != "no"; then
+                if test -f $withval/include/sql.h; then
+                        UNIXODBC_INCDIR=$withval/include
+                        UNIXODBC_LIBDIR=$withval/lib
+                else
+                        AC_MSG_RESULT(no)
+                        AC_MSG_ERROR(Invalid unixODBC directory - unable to find sql.h)
+                fi
+                UNIXODBC_LFLAGS="-L$UNIXODBC_LIBDIR -lodbc"
+                UNIXODBC_INCLUDE=-I$UNIXODBC_INCDIR
+                AC_DEFINE(HAVE_UNIXODBC)
+                AC_MSG_RESULT(yes)
+                have_db=yes
+        fi
+],[
+        AC_MSG_RESULT(no)
+])
+AC_SUBST(UNIXODBC_LFLAGS)
+AC_SUBST(UNIXODBC_INCLUDE)
+
+
+AC_MSG_CHECKING(for Solid support)
+AC_ARG_WITH(solid,
+[  --with-solid[=DIR]      Include Solid support.  DIR is the Solid base
+                          install directory, defaults to /usr/local.],
+[
+        if test "$withval" != "no"; then
+            if test "$have_db" = "yes"; then
+                AC_MSG_RESULT(error)
+                AC_MSG_ERROR("You can configure for only one database.");
+            fi
+        fi
+
+        if test "$withval" = "yes"; then
+                withval=/usr/local
+        fi
+
+        if test "$withval" != "no"; then
+                if test -f $withval/include/cli0cli.h; then
+                        SOLID_INCDIR=$withval/include
+                        SOLID_LIBDIR=$withval/lib
+                else
+                        AC_MSG_RESULT(no)
+                        AC_MSG_ERROR(Invalid Solid directory - unable to find cli0cli.h)
+                fi
+                SOLID_LFLAGS="-L$SOLID_LIBDIR -lsolcli"
+                SOLID_INCLUDE="-I$SOLID_INCDIR"
+                AC_DEFINE(HAVE_SOLID)
+                AC_MSG_RESULT(yes)
+                have_db=yes
+        fi
+],[
+        AC_MSG_RESULT(no)
+])
+AC_SUBST(SOLID_LFLAGS)
+AC_SUBST(SOLID_INCLUDE)
+
+AC_MSG_CHECKING(for OpenLink ODBC support)
+AC_ARG_WITH(openlink,
+[  --with-openlink[=DIR]   Include OpenLink ODBC support. 
+                          DIR is the base OpenLink ODBC install directory],
+[
+  if test "$withval" != "no"; then
+        if test "$withval" = "yes"; then
+
+                if test "$have_db" = "yes"; then
+                        AC_MSG_RESULT(error)
+                        AC_MSG_ERROR("You can configure for only one database.");
+                fi
+
+                if test -f /usr/local/virtuoso-ent/odbcsdk/include/isql.h; then
+                        VIRT_INCDIR=/usr/local/virtuoso-ent/odbcsdk/include/
+                        VIRT_LIBDIR=/usr/local/virtuoso-ent/odbcsdk/lib/
+                elif test -f /usr/local/virtuoso-lite/odbcsdk/include/isql.h; then
+                        VIRT_INCDIR=/usr/local/virtuoso-lite/odbcsdk/include/
+                        VIRT_LIBDIR=/usr/local/virtuoso-lite/odbcsdk/lib/
+                elif test -f /usr/local/virtuoso/odbcsdk/include/isql.h; then
+                        VIRT_INCDIR=/usr/local/virtuoso/odbcsdk/include/
+                        VIRT_LIBDIR=/usr/local/virtuoso/odbcsdk/lib/
+                else
+                AC_MSG_RESULT(no)
+                AC_MSG_ERROR(Invalid OpenLink ODBC directory - unable to find isql.h)
+                fi
+        else
+                if test -f $withval/odbcsdk/include/isql.h; then
+                        VIRT_INCDIR=$withval/odbcsdk/include/
+                        VIRT_LIBDIR=$withval/odbcsdk/lib/
+                elif test -f $withval/include/isql.h; then
+                        VIRT_INCDIR=$withval/include/
+                        VIRT_LIBDIR=$withval/lib/
+                else
+                AC_MSG_RESULT(no)
+                AC_MSG_ERROR(Invalid OpenLink ODBC directory - unable to find isql.h under $withval)
+                fi
+        fi
+    VIRT_INCLUDE=-I$VIRT_INCDIR
+    VIRT_LFLAGS="-L$VIRT_LIBDIR -liodbc"
+
+    AC_DEFINE(HAVE_VIRT)
+    AC_MSG_RESULT(yes)
+    have_db=yes
+
+  else
+        AC_MSG_RESULT(no)
+  fi
+],[
+  AC_MSG_RESULT(no)
+])
+AC_SUBST(VIRT_LFLAGS)
+AC_SUBST(VIRT_INCLUDE)
+
+
+AC_MSG_CHECKING(for EasySoft ODBC support)
+AC_ARG_WITH(easysoft,
+[  --with-easysoft[=DIR]   Include EasySoft ODBC support. 
+                          DIR is the base EasySoft ODBC install directory],
+[
+  if test "$withval" != "no"; then
+        if test "$withval" = "yes"; then
+
+                if test "$have_db" = "yes"; then
+                        AC_MSG_RESULT(error)
+                        AC_MSG_ERROR("You can configure for only one database.");
+                fi
+
+                if test -f /usr/local/easysoft/oob/client/include/sql.h; then
+                        EASYSOFT_INCDIR=/usr/local/easysoft/oob/client/include/
+                        EASYSOFT_LFLAGS="-L/usr/local/easysoft/oob/client/lib/ -L/usr/local/easysoft/lib"
+                else
+                AC_MSG_RESULT(no)
+                AC_MSG_ERROR(Invalid EasySoft ODBC directory - unable to find sql.h)
+                fi
+        else
+                if test -f $withval/easysoft/oob/client/include/sql.h; then
+                        EASYSOFT_INCDIR=$withval/easysoft/oob/client/include/
+                        EASYSOFT_LFLAGS="-L$withval/easysoft/oob/client/lib/ -L$withval/easysoft/lib"
+                else
+                AC_MSG_RESULT(no)
+                AC_MSG_ERROR(Invalid EasySoft ODBC directory - unable to find sql.h under $withval)
+                fi
+        fi
+    EASYSOFT_INCLUDE=-I$EASYSOFT_INCDIR
+    EASYSOFT_LFLAGS="$EASYSOFT_LFLAGS -lesoobclient -lesrpc -lsupport -lextra"
+
+    AC_DEFINE(HAVE_EASYSOFT)
+    AC_MSG_RESULT(yes)
+    have_db=yes
+
+  else
+        AC_MSG_RESULT(no)
+  fi
+],[
+  AC_MSG_RESULT(no)
+])
+AC_SUBST(EASYSOFT_LFLAGS)
+AC_SUBST(EASYSOFT_INCLUDE)
+
+
+
+AC_MSG_CHECKING(for InterBase support)
+AC_ARG_WITH(ibase,
+[  --with-ibase[=DIR]      Include InterBase support.  DIR is the InterBase
+                          install directory, defaults to /usr/interbase.],
+[
+        if test "$withval" != "no"; then
+            if test "$have_db" = "yes"; then
+                AC_MSG_RESULT(error)
+                AC_MSG_ERROR("You can configure for only one database.");
+            fi
+        fi
+        
+        if test "$withval" = "yes"; then
+                withval=/usr/interbase
+        fi
+
+        if test "$withval" != "no"; then
+                if test -f $withval/include/ibase.h; then
+                        IBASE_INCDIR=$withval/include
+                        IBASE_LIBDIR=$withval/lib
+                else
+                        AC_MSG_RESULT(no)
+                        AC_MSG_ERROR(Invalid InterBase directory - unable to find ibase.h)
+                fi
+                IBASE_LFLAGS="-L$IBASE_LIBDIR -lgds"
+                IBASE_INCLUDE=-I$IBASE_INCDIR
+                AC_DEFINE(HAVE_IBASE)
+                AC_MSG_RESULT(yes)
+                have_db=yes
+        fi
+],[
+        AC_MSG_RESULT(no)
+])
+AC_SUBST(IBASE_LFLAGS)
+AC_SUBST(IBASE_INCLUDE)
+
+AC_MSG_CHECKING(for Oracle8 support)
+AC_ARG_WITH(oracle8,
+[  --with-oracle8[=DIR]    Include Oracle8 support.  DIR is the Oracle
+                          home directory, defaults to $ORACLE_HOME or
+                          /oracle8/app/oracle/product/8.0.5.],
+[
+        if test "$withval" != "no"; then
+            if test "$have_db" = "yes"; then
+                AC_MSG_RESULT(error)
+                AC_MSG_ERROR("You can configure for only one database.");
+            fi
+        fi
+
+        if test "$withval" = "yes"; then
+                withval="$ORACLE_HOME"
+                if test "$withval" = ""; then
+                        withval=/oracle8/app/oracle/product/8.0.5
+                fi
+        fi
+
+        if test "$withval" != "no"; then
+                if test -f $withval/rdbms/demo/oci.h; then
+                        ORACLE8_INCDIR1=$withval/rdbms/demo/
+                        ORACLE8_INCDIR2=$withval/rdbms/public/:
+                        ORACLE8_INCDIR3=$withval/network/public/
+                        ORACLE8_INCDIR4=$withval/plsql/public/
+                        ORACLE8_LIBDIR1=$withval/lib
+                        ORACLE8_LIBDIR2=$withval/rdbms/lib
+                else
+                        AC_MSG_RESULT(no)
+                        AC_MSG_ERROR(Invalid ORACLE directory - unable to find oci.h)
+                fi
+                ORACLE8_LFLAGS="-L$ORACLE8_LIBDIR1 -L$ORACLE8_LIBDIR2 $withval/lib/libclntsh.so -lmm -lepc -lclient -lvsn -lcommon -lgeneric -lcore4 -lnlsrtl3 -lnsl -lm -ldl -lnetv2 -lnttcp -lnetwork -lncr -lsql"
+                ORACLE8_INCLUDE="-I$ORACLE8_INCDIR1 -I$ORACLE8_INCDIR2 -I$ORACLE8_INCDIR3 -I$ORACLE8_INCDIR4"
+                AC_DEFINE(HAVE_ORACLE8)
+                AC_MSG_RESULT(yes)
+                have_db=yes
+        fi
+],[
+        AC_MSG_RESULT(no)
+])
+AC_SUBST(ORACLE8_LFLAGS)
+AC_SUBST(ORACLE8_INCLUDE)
+
+
+AC_MSG_CHECKING(for Oracle7 support)
+AC_ARG_WITH(oracle7,
+[  --with-oracle7[=DIR]    Include Oracle 7.3 support.  DIR is the Oracle
+                          home directory, defaults to 
+                          ORACLE_HOME [$ORACLE_HOME]],
+[
+        if test "$withval" != "no"; then
+            if test "$have_db" = "yes"; then
+                AC_MSG_RESULT(error)
+                AC_MSG_ERROR("You can configure for only one database.");
+            fi
+        fi
+
+        if test "$withval" = "yes"; then
+                withval="$ORACLE_HOME"
+        fi
+
+        if test "$withval" != "no"; then
+                if test -f $withval/rdbms/demo/ocidfn.h; then
+                        ORACLE7_INCDIR=$withval/rdbms/demo/
+                        ORACLE7_LIBDIR1=$withval/lib
+                        ORACLE7_LIBDIR2=$withval/rdbms/lib
+                else
+                        AC_MSG_RESULT(no)
+                        AC_MSG_ERROR(Invalid ORACLE directory - unable to find ocidfn.h)
+                fi
+
+        ORACLEINST_TOP=$withval
+        if test -f "$ORACLEINST_TOP/rdbms/lib/sysliblist"
+        then
+          ORA_SYSLIB="`cat $ORACLEINST_TOP/rdbms/lib/sysliblist`"
+        elif test -f "$ORACLEINST_TOP/lib/sysliblist"
+            then
+          ORA_SYSLIB="`cat $ORACLEINST_TOP/lib/sysliblist`"
+        else
+          ORA_SYSLIB="-lm"
+        fi
+          
+                ORACLE7_LFLAGS="-L$ORACLE7_LIBDIR1 -L$ORACLE7_LIBDIR2 \
+            -lclient -lsqlnet -lncr -lsqlnet -lclient -lcommon \
+            -lgeneric -lsqlnet -lncr -lsqlnet -lclient -lcommon -lgeneric \
+            -lepc -lnlsrtl3 -lc3v6 -lcore3 -lnlsrtl3 -lcore3 -lnlsrtl3 \
+            $ORA_SYSLIB -lcore3 $ORA_SYSLIB"
+                ORACLE7_INCLUDE="-I$ORACLE7_INCDIR "
+                AC_DEFINE(HAVE_ORACLE7)
+                AC_MSG_RESULT(yes)
+                have_db=yes
+        fi
+],[
+        AC_MSG_RESULT(no)
+])
+AC_SUBST(ORACLE7_LFLAGS)
+AC_SUBST(ORACLE7_INCLUDE)
+])
+  
+dnl AM_ACLOCAL_INCLUDE(macrodir)
+AC_DEFUN([AM_ACLOCAL_INCLUDE],
+[
+        AM_CONDITIONAL(INSIDE_GNOME_COMMON, false)
+
+        test -n "$ACLOCAL_FLAGS" && ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS"
+
+        for k in $1 ; do ACLOCAL="$ACLOCAL -I $k" ; done
+])
+
+dnl
+dnl GNOME_INIT_HOOK (script-if-gnome-enabled, [failflag], [additional-inits])
+dnl
+dnl if failflag is "fail" then GNOME_INIT_HOOK will abort if gnomeConf.sh
+dnl is not found. 
+dnl
+
+AC_DEFUN([GNOME_INIT_HOOK],[
+        AC_SUBST(GNOME_LIBS)
+        AC_SUBST(GNOMEUI_LIBS)
+        AC_SUBST(GNOMEGNORBA_LIBS)
+        AC_SUBST(GTKXMHTML_LIBS)
+        AC_SUBST(ZVT_LIBS)
+        AC_SUBST(GNOME_LIBDIR)
+        AC_SUBST(GNOME_INCLUDEDIR)
+
+        AC_ARG_WITH(gnome-includes,
+        [  --with-gnome-includes   Specify location of GNOME headers],[
+        CFLAGS="$CFLAGS -I$withval"
+        ])
+        
+        AC_ARG_WITH(gnome-libs,
+        [  --with-gnome-libs       Specify location of GNOME libs],[
+        LDFLAGS="$LDFLAGS -L$withval"
+        gnome_prefix=$withval
+        ])
+
+        AC_ARG_WITH(gnome,
+        [  --with-gnome            Specify prefix for GNOME files],
+                if test x$withval = xyes; then
+                        want_gnome=yes
+                        dnl Note that an empty true branch is not
+                        dnl valid sh syntax.
+                        ifelse([$1], [], :, [$1])
+                else
+                        if test "x$withval" = xno; then
+                                want_gnome=no
+                        else
+                                want_gnome=yes
+                                LDFLAGS="$LDFLAGS -L$withval/lib"
+                                CFLAGS="$CFLAGS -I$withval/include"
+                                gnome_prefix=$withval/lib
+                        fi
+                fi,
+                want_gnome=yes)
+
+        if test "x$want_gnome" = xyes; then
+
+            AC_PATH_PROG(GNOME_CONFIG,gnome-config,no)
+            if test "$GNOME_CONFIG" = "no"; then
+              no_gnome_config="yes"
+            else
+              AC_MSG_CHECKING(if $GNOME_CONFIG works)
+              if $GNOME_CONFIG --libs-only-l gnome >/dev/null 2>&1; then
+                AC_MSG_RESULT(yes)
+                GNOME_GNORBA_HOOK([],$2)
+                GNOME_LIBS="`$GNOME_CONFIG --libs-only-l gnome`"
+                GNOMEUI_LIBS="`$GNOME_CONFIG --libs-only-l gnomeui`"
+                GNOMEGNORBA_LIBS="`$GNOME_CONFIG --libs-only-l gnorba gnomeui`"
+                GTKXMHTML_LIBS="`$GNOME_CONFIG --libs-only-l gtkxmhtml`"
+                ZVT_LIBS="`$GNOME_CONFIG --libs-only-l zvt`"
+                GNOME_LIBDIR="`$GNOME_CONFIG --libs-only-L gnorba gnomeui`"
+                GNOME_INCLUDEDIR="`$GNOME_CONFIG --cflags gnorba gnomeui`"
+                $1
+              else
+                AC_MSG_RESULT(no)
+                no_gnome_config="yes"
+              fi
+            fi
+
+            if test x$exec_prefix = xNONE; then
+                if test x$prefix = xNONE; then
+                    gnome_prefix=$ac_default_prefix/lib
+                else
+                    gnome_prefix=$prefix/lib
+                fi
+            else
+                gnome_prefix=`eval echo \`echo $libdir\``
+            fi
+        
+            if test "$no_gnome_config" = "yes"; then
+              AC_MSG_CHECKING(for gnomeConf.sh file in $gnome_prefix)
+              if test -f $gnome_prefix/gnomeConf.sh; then
+                AC_MSG_RESULT(found)
+                echo "loading gnome configuration from" \
+                     "$gnome_prefix/gnomeConf.sh"
+                . $gnome_prefix/gnomeConf.sh
+                $1
+              else
+                AC_MSG_RESULT(not found)
+                if test x$2 = xfail; then
+                  AC_MSG_ERROR(Could not find the gnomeConf.sh file that is generated by gnome-libs install)
+                fi
+              fi
+            fi
+        fi
+
+        if test -n "$3"; then
+          n="$3"
+          for i in $n; do
+            AC_MSG_CHECKING(extra library \"$i\")
+            case $i in 
+              applets)
+                AC_SUBST(GNOME_APPLETS_LIBS)
+                GNOME_APPLETS_LIBS=`$GNOME_CONFIG --libs-only-l applets`
+                AC_MSG_RESULT($GNOME_APPLETS_LIBS);;
+              docklets)
+                AC_SUBST(GNOME_DOCKLETS_LIBS)
+                GNOME_DOCKLETS_LIBS=`$GNOME_CONFIG --libs-only-l docklets`
+                AC_MSG_RESULT($GNOME_DOCKLETS_LIBS);;
+              capplet)
+                AC_SUBST(GNOME_CAPPLET_LIBS)
+                GNOME_CAPPLET_LIBS=`$GNOME_CONFIG --libs-only-l capplet`
+                AC_MSG_RESULT($GNOME_CAPPLET_LIBS);;
+              *)
+                AC_MSG_RESULT(unknown library)
+            esac
+            EXTRA_INCLUDEDIR=`$GNOME_CONFIG --cflags $i`
+            GNOME_INCLUDEDIR="$GNOME_INCLUDEDIR $EXTRA_INCLUDEDIR"
+          done
+        fi
+])
+
+dnl
+dnl GNOME_INIT ([additional-inits])
+dnl
+
+AC_DEFUN([GNOME_INIT],[
+        GNOME_INIT_HOOK([],fail,$1)
+])
+
+dnl GNOME_X_CHECKS
+dnl
+dnl Basic X11 related checks for X11.  At the end, the following will be
+dnl defined/changed:
+dnl   GTK_{CFLAGS,LIBS}      From AM_PATH_GTK
+dnl   CPPFLAGS               Will include $X_CFLAGS
+dnl   GNOME_HAVE_SM          `true' or `false' depending on whether session
+dnl                          management is available.  It is available if
+dnl                          both -lSM and X11/SM/SMlib.h exist.  (Some
+dnl                          Solaris boxes have the library but not the header)
+dnl   XPM_LIBS               -lXpm if Xpm library is present, otherwise ""
+dnl
+dnl The following configure cache variables are defined (but not used):
+dnl   gnome_cv_passdown_{x_libs,X_LIBS,X_CFLAGS}
+dnl
+AC_DEFUN([GNOME_X_CHECKS],
+[
+        AM_PATH_GTK(1.2.0,,AC_MSG_ERROR(GTK not installed, or gtk-config not in path))
+        dnl Hope that GTK_CFLAGS have only -I and -D.  Otherwise, we could
+        dnl   test -z "$x_includes" || CPPFLAGS="$CPPFLAGS -I$x_includes"
+        dnl
+        dnl Use CPPFLAGS instead of CFLAGS because AC_CHECK_HEADERS uses
+        dnl CPPFLAGS, not CFLAGS
+        CPPFLAGS="$CPPFLAGS $GTK_CFLAGS"
+
+        saved_ldflags="$LDFLAGS"
+        LDFLAGS="$LDFLAGS $GTK_LIBS"
+
+        gnome_cv_passdown_x_libs="$GTK_LIBS"
+        gnome_cv_passdown_X_LIBS="$GTK_LIBS"
+        gnome_cv_passdown_X_CFLAGS="$GTK_CFLAGS"
+        gnome_cv_passdown_GTK_LIBS="$GTK_LIBS"
+
+        LDFLAGS="$saved_ldflags $GTK_LIBS"
+
+dnl We are requiring GTK >= 1.1.1, which means this will be fine anyhow.
+        USE_DEVGTK=true
+
+dnl     AC_MSG_CHECKING([whether to use features from (unstable) GTK+ 1.1.x])
+dnl     AC_EGREP_CPP(answer_affirmatively,
+dnl     [#include <gtk/gtkfeatures.h>
+dnl     #ifdef GTK_HAVE_FEATURES_1_1_0
+dnl        answer_affirmatively
+dnl     #endif
+dnl     ], dev_gtk=yes, dev_gtk=no)
+dnl     if test "$dev_gtk" = "yes"; then
+dnl        USE_DEVGTK=true
+dnl     fi
+dnl     AC_MSG_RESULT("$dev_gtk")
+
+        GNOME_HAVE_SM=true
+        case "$GTK_LIBS" in
+         *-lSM*)
+            dnl Already found it.
+            ;;
+         *)
+            dnl Assume that if we have -lSM then we also have -lICE.
+            AC_CHECK_LIB(SM, SmcSaveYourselfDone,
+                [GTK_LIBS="-lSM -lICE $GTK_LIBS"],GNOME_HAVE_SM=false,
+                $x_libs -lICE)
+            ;;
+        esac
+
+        if test "$GNOME_HAVE_SM" = true; then
+           AC_CHECK_HEADERS(X11/SM/SMlib.h,,GNOME_HAVE_SM=false)
+        fi
+
+        if test "$GNOME_HAVE_SM" = true; then
+           AC_DEFINE(HAVE_LIBSM)
+        fi
+
+        XPM_LIBS=""
+        AC_CHECK_LIB(Xpm, XpmFreeXpmImage, [XPM_LIBS="-lXpm"], , $x_libs)
+        AC_SUBST(XPM_LIBS)
+
+        AC_REQUIRE([GNOME_PTHREAD_CHECK])
+        LDFLAGS="$saved_ldflags"
+
+        AC_PROVIDE([GNOME_X_CHECKS])
+])
+
+AC_DEFUN([GNOME_PTHREAD_CHECK],[
+        PTHREAD_LIB=""
+        AC_CHECK_LIB(pthread, pthread_create, PTHREAD_LIB="-lpthread",
+                [AC_CHECK_LIB(pthreads, pthread_create, PTHREAD_LIB="-lpthreads",
+                    [AC_CHECK_LIB(c_r, pthread_create, PTHREAD_LIB="-lc_r",
+                        [AC_CHECK_LIB(pthread, __pthread_attr_init_system, PTHREAD_LIB="-lpthread",
+                                [AC_CHECK_FUNC(pthread_create)]
+                        )]
+                    )]
+                )]
+        )
+        AC_SUBST(PTHREAD_LIB)
+        AC_PROVIDE([GNOME_PTHREAD_CHECK])
+])
+
+AC_DEFUN(AM_CONDITIONAL,
+[AC_SUBST($1_TRUE)
+AC_SUBST($1_FALSE)
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi])
+
+dnl
+dnl GNOME_GNORBA_HOOK (script-if-gnorba-found, failflag)
+dnl
+dnl if failflag is "failure" it aborts if gnorba is not found.
+dnl
+
+AC_DEFUN([GNOME_GNORBA_HOOK],[
+        GNOME_ORBIT_HOOK([],$2)
+        AC_CACHE_CHECK([for gnorba libraries],gnome_cv_gnorba_found,[
+                gnome_cv_gnorba_found=no
+                if test x$gnome_cv_orbit_found = xyes; then
+                        GNORBA_CFLAGS="`gnome-config --cflags gnorba gnomeui`"
+                        GNORBA_LIBS="`gnome-config --libs gnorba gnomeui`"
+                        if test -n "$GNORBA_LIBS"; then
+                                gnome_cv_gnorba_found=yes
+                        fi
+                fi
+        ])
+        AM_CONDITIONAL(HAVE_GNORBA, test x$gnome_cv_gnorba_found = xyes)
+        if test x$gnome_cv_orbit_found = xyes; then
+                $1
+                GNORBA_CFLAGS="`gnome-config --cflags gnorba gnomeui`"
+                GNORBA_LIBS="`gnome-config --libs gnorba gnomeui`"
+                AC_SUBST(GNORBA_CFLAGS)
+                AC_SUBST(GNORBA_LIBS)
+        else
+                if test x$2 = xfailure; then
+                        AC_MSG_ERROR(gnorba library not installed or installation problem)
+                fi
+        fi
+])
+
+AC_DEFUN([GNOME_GNORBA_CHECK], [
+        GNOME_GNORBA_HOOK([],failure)
+])
+
+dnl
+dnl GNOME_ORBIT_HOOK (script-if-orbit-found, failflag)
+dnl
+dnl if failflag is "failure" it aborts if orbit is not found.
+dnl
+
+AC_DEFUN([GNOME_ORBIT_HOOK],[
+        AC_PATH_PROG(ORBIT_CONFIG,orbit-config,no)
+        AC_PATH_PROG(ORBIT_IDL,orbit-idl,no)
+        AC_CACHE_CHECK([for working ORBit environment],gnome_cv_orbit_found,[
+                if test x$ORBIT_CONFIG = xno -o x$ORBIT_IDL = xno; then
+                        gnome_cv_orbit_found=no
+                else
+                        gnome_cv_orbit_found=yes
+                fi
+        ])
+        AM_CONDITIONAL(HAVE_ORBIT, test x$gnome_cv_orbit_found = xyes)
+        if test x$gnome_cv_orbit_found = xyes; then
+                $1
+                ORBIT_CFLAGS=`orbit-config --cflags client server`
+                ORBIT_LIBS=`orbit-config --use-service=name --libs client server`
+                AC_SUBST(ORBIT_CFLAGS)
+                AC_SUBST(ORBIT_LIBS)
+        else
+                if test x$2 = xfailure; then
+                        AC_MSG_ERROR(ORBit not installed or installation problem)
+                fi
+        fi
+])
+
+AC_DEFUN([GNOME_ORBIT_CHECK], [
+        GNOME_ORBIT_HOOK([],failure)
+])
+
diff --git a/bacula/autoconf/confdefs.h b/bacula/autoconf/confdefs.h
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/bacula/autoconf/config.guess b/bacula/autoconf/config.guess
new file mode 100755 (executable)
index 0000000..0ce538b
--- /dev/null
@@ -0,0 +1,1183 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+#   Free Software Foundation, Inc.
+#
+# This file 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 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.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# Use $HOST_CC if defined. $CC may point to a cross-compiler
+if test x"$CC_FOR_BUILD" = x; then
+  if test x"$HOST_CC" != x; then
+    CC_FOR_BUILD="$HOST_CC"
+  else
+    if test x"$CC" != x; then
+      CC_FOR_BUILD="$CC"
+    else
+      CC_FOR_BUILD=cc
+    fi
+  fi
+fi
+
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # Netbsd (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       # Determine the machine/vendor (is the vendor relevant).
+       case "${UNAME_MACHINE}" in
+           amiga) machine=m68k-cbm ;;
+           arm32) machine=arm-unknown ;;
+           atari*) machine=m68k-atari ;;
+           sun3*) machine=m68k-sun ;;
+           mac68k) machine=m68k-apple ;;
+           macppc) machine=powerpc-apple ;;
+           hp3[0-9][05]) machine=m68k-hp ;;
+           ibmrt|romp-ibm) machine=romp-ibm ;;
+           *) machine=${UNAME_MACHINE}-unknown ;;
+       esac
+       # The Operating System including object format.
+       if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+               | grep __ELF__ >/dev/null
+       then
+           # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+           # Return netbsd for either.  FIX?
+           os=netbsd
+       else
+           os=netbsdelf
+       fi
+       # The OS release
+       release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit 0 ;;
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       cat <<EOF >$dummy.s
+       .data
+\$Lformat:
+       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+
+       .text
+       .globl main
+       .align 4
+       .ent main
+main:
+       .frame \$30,16,\$26,0
+       ldgp \$29,0(\$27)
+       .prologue 1
+       .long 0x47e03d80 # implver \$0
+       lda \$2,-1
+       .long 0x47e20c21 # amask \$2,\$1
+       lda \$16,\$Lformat
+       mov \$0,\$17
+       not \$1,\$18
+       jsr \$26,printf
+       ldgp \$29,0(\$26)
+       mov 0,\$16
+       jsr \$26,exit
+       .end main
+EOF
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               case `./$dummy` in
+                       0-0)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       1-0)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       1-1)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       1-101)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       2-303)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       2-307)
+                               UNAME_MACHINE="alphaev67"
+                               ;;
+               esac
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-cbm-sysv4
+       exit 0;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    arc64:OpenBSD:*:*)
+       echo mips64el-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hkmips:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    SR2?01:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    sun3*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy \
+         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && rm $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i?86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+               rm -f $dummy.c $dummy
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:4)
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=4.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+              sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+       (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+       rm -f $dummy.c $dummy
+       esac
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    *9??*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i?86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    hppa*:OpenBSD:*:*)
+       echo hppa-unknown-openbsd
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+       echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY-2:*:*:*)
+       echo cray2-cray-unicos
+        exit 0 ;;
+    F300:UNIX_System_V:*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    F301:UNIX_System_V:*:*)
+       echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+       exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i386-pc-interix
+       exit 0 ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    *:Linux:*:*)
+
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       ld_help_string=`cd /; ld --help 2>&1`
+       ld_supported_emulations=`echo $ld_help_string \
+                        | sed -ne '/supported emulations:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported emulations: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_emulations" in
+         *ia64)
+               echo "${UNAME_MACHINE}-unknown-linux"
+               exit 0
+               ;;
+         i?86linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0
+               ;;
+         elf_i?86)
+               echo "${UNAME_MACHINE}-pc-linux"
+               exit 0
+               ;;
+         i?86coff)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit 0
+               ;;
+         sparclinux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+               exit 0
+               ;;
+         armlinux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+               exit 0
+               ;;
+         elf32arm*)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuoldld"
+               exit 0
+               ;;
+         armelf_linux*)
+               echo "${UNAME_MACHINE}-unknown-linux-gnu"
+               exit 0
+               ;;
+         m68klinux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+               exit 0
+               ;;
+         elf32ppc | elf32ppclinux)
+               # Determine Lib Version
+               cat >$dummy.c <<EOF
+#include <features.h>
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+#if defined(__GLIBC__)
+  printf("%s %s\n", __libc_version, __libc_release);
+#else
+  printf("unkown\n");
+#endif
+  return 0;
+}
+EOF
+               LIBC=""
+               $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
+               if test "$?" = 0 ; then
+                       ./$dummy | grep 1\.99 > /dev/null
+                       if test "$?" = 0 ; then
+                               LIBC="libc1"
+                       fi
+               fi
+               rm -f $dummy.c $dummy
+               echo powerpc-unknown-linux-gnu${LIBC}
+               exit 0
+               ;;
+       esac
+
+       if test "${UNAME_MACHINE}" = "alpha" ; then
+               cat <<EOF >$dummy.s
+                       .data
+               \$Lformat:
+                       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+
+                       .text
+                       .globl main
+                       .align 4
+                       .ent main
+               main:
+                       .frame \$30,16,\$26,0
+                       ldgp \$29,0(\$27)
+                       .prologue 1
+                       .long 0x47e03d80 # implver \$0
+                       lda \$2,-1
+                       .long 0x47e20c21 # amask \$2,\$1
+                       lda \$16,\$Lformat
+                       mov \$0,\$17
+                       not \$1,\$18
+                       jsr \$26,printf
+                       ldgp \$29,0(\$26)
+                       mov 0,\$16
+                       jsr \$26,exit
+                       .end main
+EOF
+               LIBC=""
+               $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+               if test "$?" = 0 ; then
+                       case `./$dummy` in
+                       0-0)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       1-0)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       1-1)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       1-101)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       2-303)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       2-307)
+                               UNAME_MACHINE="alphaev67"
+                               ;;
+                       esac
+
+                       objdump --private-headers $dummy | \
+                         grep ld.so.1 > /dev/null
+                       if test "$?" = 0 ; then
+                               LIBC="libc1"
+                       fi
+               fi
+               rm -f $dummy.s $dummy
+               echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+       elif test "${UNAME_MACHINE}" = "mips" ; then
+         cat >$dummy.c <<EOF
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+  printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+  printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+         $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         rm -f $dummy.c $dummy
+       elif test "${UNAME_MACHINE}" = "s390"; then
+         echo s390-ibm-linux && exit 0
+       else
+         # Either a pre-BFD a.out linker (linux-gnuoldld)
+         # or one that does not give us useful --help.
+         # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+         # If ld does not provide *any* "supported emulations:"
+         # that means it is gnuoldld.
+         echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
+         test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+         case "${UNAME_MACHINE}" in
+         i?86)
+           VENDOR=pc;
+           ;;
+         *)
+           VENDOR=unknown;
+           ;;
+         esac
+         # Determine whether the default compiler is a.out or elf
+         cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+#  if __GLIBC__ >= 2
+    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+#  else
+    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+#  endif
+# else
+   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+         $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         rm -f $dummy.c $dummy
+       fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i?86:DYNIX/ptx:4*:*)
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i?86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit 0 ;;
+    i?86:*:5:7*)
+        # Fixed at (any) Pentium or better
+        UNAME_MACHINE=i586
+        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
+           echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
+       else
+           echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    i?86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    i?86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit 0 ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:*:6*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Darwin:*:*)
+       echo `uname -p`-apple-darwin${UNAME_RELEASE}
+       exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       if test "${UNAME_MACHINE}" = "x86pc"; then
+               UNAME_MACHINE=pc
+       fi
+       echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+       exit 0 ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit 0 ;;
+    NSR-W:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit 0 ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/bacula/autoconf/config.h.in b/bacula/autoconf/config.h.in
new file mode 100644 (file)
index 0000000..cc1892a
--- /dev/null
@@ -0,0 +1,460 @@
+/* autoconf/config.h.in.  Generated automatically from autoconf/configure.in by autoheader.  */
+/* ------------------------------------------------------------------------- */
+/* --                     CONFIGURE SPECIFIED FEATURES                    -- */
+/* ------------------------------------------------------------------------- */
+   
+/* Define if you want to use MySQL as Catalog database */
+#undef USE_MYSQL_DB
+
+/* Define if you want SmartAlloc debug code enabled */
+#undef SMARTALLOC
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef daddr_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef major_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef minor_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef ssize_t
+
+/* Define if you want to use MySQL */
+#undef HAVE_MYSQL
+
+/* Define if you want to use SQLite */
+#undef HAVE_SQLITE
+
+/* Define if you want to use Berkeley DB */
+#undef HAVE_BERKELEY_DB
+
+
+/* Define if you want to use PostgreSQL */
+#undef HAVE_PGSQL
+
+/* Define if you want to use mSQL */
+#undef HAVE_MSQL
+
+/* Define if you want to use iODBC */
+#undef HAVE_IODBC
+
+/* Define if you want to use unixODBC */
+#undef HAVE_UNIXODBC
+
+/* Define if you want to use Solid SQL Server */
+#undef HAVE_SOLID
+
+/* Define if you want to use OpenLink ODBC (Virtuoso) */
+#undef HAVE_VIRT
+
+/* Define if you want to use EasySoft ODBC */
+#undef HAVE_EASYSOFT
+
+/* Define if you want to use Interbase SQL Server */
+#undef HAVE_IBASE
+
+/* Define if you want to use Oracle 8 SQL Server */
+#undef HAVE_ORACLE8
+
+/* Define if you want to use Oracle 7 SQL Server */
+#undef HAVE_ORACLE7
+
+
+/* ------------------------------------------------------------------------- */
+/* --                     CONFIGURE DETECTED FEATURES                     -- */
+/* ------------------------------------------------------------------------- */
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define if the closedir function returns void instead of int.  */
+#undef CLOSEDIR_VOID
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef gid_t
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if your system has a working fnmatch function.  */
+#undef HAVE_FNMATCH
+
+/* Define if you have the getmntent function.  */
+#undef HAVE_GETMNTENT
+
+/* Define if your struct stat has st_blksize.  */
+#undef HAVE_ST_BLKSIZE
+
+/* Define if your struct stat has st_blocks.  */
+#undef HAVE_ST_BLOCKS
+
+/* Define if you have the strcoll function and it is properly defined.  */
+#undef HAVE_STRCOLL
+
+/* Define if your struct stat has st_rdev.  */
+#undef HAVE_ST_RDEV
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible.  */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if your struct tm has tm_zone.  */
+#undef HAVE_TM_ZONE
+
+/* Define if you don't have tm_zone but do have the external array
+   tzname.  */
+#undef HAVE_TZNAME
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define if major, minor, and makedev are declared in <mkdev.h>.  */
+#undef MAJOR_IN_MKDEV
+
+/* Define if major, minor, and makedev are declared in <sysmacros.h>.  */
+#undef MAJOR_IN_SYSMACROS
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef mode_t
+
+/* Define if your C compiler doesn't accept -c and -o together.  */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define if the `setpgrp' function takes no argument.  */
+#undef SETPGRP_VOID
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly.  */
+#undef STAT_MACROS_BROKEN
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef uid_t
+
+/* Define if the X Window System is missing or not being used.  */
+#undef X_DISPLAY_MISSING
+
+/* Define if you need function prototypes */
+#undef PROTOTYPES
+
+/* Define if you have GCC */
+#undef HAVE_GCC
+
+/* Define to use SVR4 statvfs to get filesystem type.  */
+#undef FSTYPE_STATVFS
+
+/* Define to use SVR3.2 statfs to get filesystem type.  */
+#undef FSTYPE_USG_STATFS
+
+/* Define to use AIX3 statfs to get filesystem type.  */
+#undef FSTYPE_AIX_STATFS
+
+/* Define to use 4.3BSD getmntent to get filesystem type.  */
+#undef FSTYPE_MNTENT
+
+/* Define to use 4.4BSD and OSF1 statfs to get filesystem type.  */
+#undef FSTYPE_STATFS
+
+/* Define to use Ultrix getmnt to get filesystem type.  */
+#undef FSTYPE_GETMNT
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define.  */
+#undef dev_t
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define.  */
+#undef ino_t
+
+/* Define to 1 if utime.h exists and declares struct utimbuf.  */
+#undef HAVE_UTIME_H
+
+/* Data types */
+#undef HAVE_U_INT
+#undef HAVE_INTXX_T
+#undef HAVE_U_INTXX_T
+#undef HAVE_UINTXX_T
+#undef HAVE_INT64_T
+#undef HAVE_U_INT64_T
+#undef HAVE_INTMAX_T
+#undef HAVE_U_INTMAX_T
+
+/* Define if you want TCP Wrappers support */
+#undef HAVE_LIBWRAP
+
+/* Define if you have sys/bitypes.h */
+#undef HAVE_SYS_BITYPES_H
+
+/* Directory for PID files */
+#undef _PATH_BACULA_PIDDIR
+
+/* File daemon specif libraries */
+#undef FDLIBS
+
+/* What kind of signals we have */
+#undef HAVE_POSIX_SIGNALS
+#undef HAVE_BSD_SIGNALS
+#undef HAVE_USG_SIGHOLD
+
+/* Operating systems */
+/* OSes */
+#undef HAVE_LINUX_OS
+#undef HAVE_FREEBSD_OS
+#undef HAVE_NETBSD_OS
+#undef HAVE_OPENBSD_OS
+#undef HAVE_BSDI_OS
+#undef HAVE_HPUX_OS
+#undef HAVE_SUN_OS
+#undef HAVE_AIX_OS
+#undef HAVE_SGI_OS
+#undef HAVE_CYGWIN
+#undef HAVE_OSF1_OS
+
+/* Set to correct scanf value for long long int */
+#undef lld
+#undef llu
+
+#undef HAVE_READLINE 
+
+#undef HAVE_GMP
+
+#undef HAVE_CWEB
+
+#undef HAVE_FCHDIR
+
+#undef HAVE_LOCALTIME_R
+
+#undef HAVE_READDIR_R
+
+#undef HAVE_GETOPT_LONG
+
+/* The number of bytes in a char.  */
+#undef SIZEOF_CHAR
+
+/* The number of bytes in a int.  */
+#undef SIZEOF_INT
+
+/* The number of bytes in a int *.  */
+#undef SIZEOF_INT_P
+
+/* The number of bytes in a long int.  */
+#undef SIZEOF_LONG_INT
+
+/* The number of bytes in a long long int.  */
+#undef SIZEOF_LONG_LONG_INT
+
+/* The number of bytes in a short int.  */
+#undef SIZEOF_SHORT_INT
+
+/* Define if you have the fchdir function.  */
+#undef HAVE_FCHDIR
+
+/* Define if you have the fork function.  */
+#undef HAVE_FORK
+
+/* Define if you have the getcwd function.  */
+#undef HAVE_GETCWD
+
+/* Define if you have the gethostname function.  */
+#undef HAVE_GETHOSTNAME
+
+/* Define if you have the getpid function.  */
+#undef HAVE_GETPID
+
+/* Define if you have the lchown function.  */
+#undef HAVE_LCHOWN
+
+/* Define if you have the localtime_r function.  */
+#undef HAVE_LOCALTIME_R
+
+/* Define if you have the lstat function.  */
+#undef HAVE_LSTAT
+
+/* Define if you have the putenv function.  */
+#undef HAVE_PUTENV
+
+/* Define if you have the readdir_r function.  */
+#undef HAVE_READDIR_R
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the setenv function.  */
+#undef HAVE_SETENV
+
+/* Define if you have the setlocale function.  */
+#undef HAVE_SETLOCALE
+
+/* Define if you have the setpgid function.  */
+#undef HAVE_SETPGID
+
+/* Define if you have the setpgrp function.  */
+#undef HAVE_SETPGRP
+
+/* Define if you have the setsid function.  */
+#undef HAVE_SETSID
+
+/* Define if you have the signal function.  */
+#undef HAVE_SIGNAL
+
+/* Define if you have the snprintf function.  */
+#undef HAVE_SNPRINTF
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strncmp function.  */
+#undef HAVE_STRNCMP
+
+/* Define if you have the strncpy function.  */
+#undef HAVE_STRNCPY
+
+/* Define if you have the tcgetattr function.  */
+#undef HAVE_TCGETATTR
+
+/* Define if you have the vfprintf function.  */
+#undef HAVE_VFPRINTF
+
+/* Define if you have the vsnprintf function.  */
+#undef HAVE_VSNPRINTF
+
+/* Define if you have the <assert.h> header file.  */
+#undef HAVE_ASSERT_H
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <grp.h> header file.  */
+#undef HAVE_GRP_H
+
+/* Define if you have the <libc.h> header file.  */
+#undef HAVE_LIBC_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <stdarg.h> header file.  */
+#undef HAVE_STDARG_H
+
+/* Define if you have the <stdlib.h> header file.  */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/byteorder.h> header file.  */
+#undef HAVE_SYS_BYTEORDER_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ioctl.h> header file.  */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/pte.h> header file.  */
+#undef HAVE_SYS_PTE_H
+
+/* Define if you have the <sys/ptem.h> header file.  */
+#undef HAVE_SYS_PTEM_H
+
+/* Define if you have the <sys/select.h> header file.  */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <sys/sockio.h> header file.  */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define if you have the <sys/stream.h> header file.  */
+#undef HAVE_SYS_STREAM_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <termcap.h> header file.  */
+#undef HAVE_TERMCAP_H
+
+/* Define if you have the <termio.h> header file.  */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the <termios.h> header file.  */
+#undef HAVE_TERMIOS_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the <varargs.h> header file.  */
+#undef HAVE_VARARGS_H
+
+/* Define if you have the inet library (-linet).  */
+#undef HAVE_LIBINET
+
+/* Define if you have the nsl library (-lnsl).  */
+#undef HAVE_LIBNSL
+
+/* Define if you have the resolv library (-lresolv).  */
+#undef HAVE_LIBRESOLV
+
+/* Define if you have the socket library (-lsocket).  */
+#undef HAVE_LIBSOCKET
+
+/* Define if you have the sun library (-lsun).  */
+#undef HAVE_LIBSUN
+
+/* Define if you have the xnet library (-lxnet).  */
+#undef HAVE_LIBXNET
diff --git a/bacula/autoconf/config.log b/bacula/autoconf/config.log
new file mode 100644 (file)
index 0000000..fb9038e
--- /dev/null
@@ -0,0 +1,3 @@
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
diff --git a/bacula/autoconf/config.sub b/bacula/autoconf/config.sub
new file mode 100755 (executable)
index 0000000..c8e7785
--- /dev/null
@@ -0,0 +1,1268 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+#   Free Software Foundation, Inc.
+#
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file 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 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.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+       echo Configuration name missing. 1>&2
+       echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+       echo "or     $0 ALIAS" 1>&2
+       echo where ALIAS is a recognized configuration type. 1>&2
+       exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+       *local*)
+               echo $1
+               exit 0
+               ;;
+       *)
+       ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+               | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+               | 580 | i960 | h8300 \
+               | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \
+               | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+               | hppa64 \
+               | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
+               | alphaev6[78] \
+               | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
+               | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
+               | mips64orion | mips64orionel | mipstx39 | mipstx39el \
+               | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+               | mips64vr5000 | miprs64vr5000el | mcore \
+               | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
+               | thumb | d10v | fr30 | avr)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl)
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i[34567]86)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       # FIXME: clean up the formatting here.
+       vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
+             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+             | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+             | xmp-* | ymp-* \
+             | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \
+             | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
+             | hppa2.0n-* | hppa64-* \
+             | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
+             | alphaev6[78]-* \
+             | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+             | clipper-* | orion-* \
+             | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+             | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
+             | mips64el-* | mips64orion-* | mips64orionel-* \
+             | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+             | mipstx39-* | mipstx39el-* | mcore-* \
+             | f301-* | armv*-* | s390-* | sv1-* | t3e-* \
+             | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+             | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \
+             | bs2000-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-cbm
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-cbm
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-cbm
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       cray2)
+               basic_machine=cray2-cray
+               os=-unicos
+               ;;
+       [ctj]90-cray)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i[34567]86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i[34567]86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i[34567]86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i[34567]86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       i386-go32 | go32)
+               basic_machine=i386-unknown
+               os=-go32
+               ;;
+       i386-mingw32 | mingw32)
+               basic_machine=i386-unknown
+               os=-mingw32
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mipsel*-linux*)
+               basic_machine=mipsel-unknown
+               os=-linux-gnu
+               ;;
+       mips*-linux*)
+               basic_machine=mips-unknown
+               os=-linux-gnu
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       mmix*)
+               basic_machine=mmix-knuth
+               os=-mmixware
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       msdos)
+               basic_machine=i386-unknown
+               os=-msdos
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+        pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | k6 | nexen)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexen-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=rs6000-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sparclite-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=t3e-cray
+               os=-unicos
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xmp)
+               basic_machine=xmp-cray
+               os=-unicos
+               ;;
+        xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       mips)
+               if [ x$os = x-linux-gnu ]; then
+                       basic_machine=mips-unknown
+               else
+                       basic_machine=mips-mips
+               fi
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sparc | sparcv9)
+               basic_machine=sparc-sun
+               ;;
+        cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       c4x*)
+               basic_machine=c4x-none
+               os=-coff
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i[34567]86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto*)
+               os=-nto-qnx
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+        -*mint | -*MiNT)
+               os=-mint
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+        pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+        *-gould)
+               os=-sysv
+               ;;
+        *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+        *-sgi)
+               os=-irix
+               ;;
+        *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f301-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -*MiNT)
+                               vendor=atari
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in
new file mode 100644 (file)
index 0000000..179c880
--- /dev/null
@@ -0,0 +1,1239 @@
+dnl#
+dnl#
+dnl# Process this file with autoconf to produce a configure script.
+dnl#
+AC_INIT(src/version.h)
+BUILD_DIR=`pwd`
+cd ..
+TOP_DIR=`pwd`
+cd ${BUILD_DIR}
+AC_SUBST(BUILD_DIR)
+AC_CONFIG_AUX_DIR(${BUILD_DIR}/autoconf)
+AC_CONFIG_HEADER(src/config.h:autoconf/config.h.in)
+
+dnl require a recent autoconf
+AC_PREREQ(2.12)
+
+
+dnl search for true and false programs.
+AC_PATH_PROGS(TRUEPRG, true, :)
+AC_PATH_PROGS(FALSEPRG, false, :)
+
+AC_CANONICAL_HOST
+
+dnl bacula version
+VERSION=`sed -n -e 's/^.*VERSION.*"\(.*\)"$/\1/p' ${srcdir}/src/version.h`
+DATE=`sed -n -e 's/^.*[ \t]*DATE.*"\(.*\)"$/\1/p' ${srcdir}/src/version.h`
+LSMDATE=`sed -n -e 's/^.*LSMDATE.*"\(.*\)"$/\1/p' ${srcdir}/src/version.h`
+AC_SUBST(VERSION)dnl 
+AC_SUBST(DATE)dnl 
+AC_SUBST(LSMDATE)dnl 
+echo "configuring for bacula $VERSION ($DATE)"
+
+
+dnl -------------------------------------------------------
+dnl# Check for compiler.
+dnl ------------------------------------------------------
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_CC_C_O                 dnl Determine if C compiler support -c -o.
+AC_PROG_GCC_TRADITIONAL        dnl Determine if ioctl() need -traditional.
+
+if test x$CC = xgcc
+then
+   AC_DEFINE(HAVE_GCC)
+fi
+
+dnl -------------------------------------------------------
+dnl# Check for programs.
+dnl ------------------------------------------------------
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_PATH_PROG(MV, mv, mv)
+AC_PATH_PROG(RM, rm, rm)
+AC_PATH_PROG(CP, cp, cp)
+AC_PATH_PROG(SED, sed, sed)
+AC_PATH_PROG(AWK, awk, awk)
+AC_PATH_PROG(ECHO, echo, echo)
+AC_PATH_PROG(CMP, cmp, cmp)
+AC_PATH_PROG(TBL, tbl, tbl)
+AC_PATH_PROG(AR, ar, ar)
+AC_PATH_PROG(RANLIB, ranlib, ranlib)
+AC_PATH_PROG(OPENSSL, openssl, none)
+
+test -n "$ARFLAG" || ARFLAGS="cr"
+AC_SUBST(ARFLAGS)
+
+MAKE_SHELL=/bin/sh
+AC_SUBST(MAKE_SHELL)
+
+AC_SUBST(LOCAL_LIBS)
+AC_SUBST(LOCAL_CFLAGS)
+AC_SUBST(LOCAL_LDFLAGS)
+AC_SUBST(LOCAL_DEFS)
+
+
+
+dnl --------------------------------------------------
+dnl Bacula OP Sys determination (see aclocal.m4)
+dnl --------------------------------------------------
+BA_CHECK_OPSYS
+
+# -----------------------------------------------------------
+dnl Bacula OPSys Distribution determination (see aclocal.m4)
+# ----------------------------------------------------------
+BA_CHECK_OPSYS_DISTNAME
+
+# -----------------------------------------------------------
+dnl Check for gnome stuff for gnome-console
+# ----------------------------------------------------------
+AM_ACLOCAL_INCLUDE(gnome-macros)
+
+# ------------------------------------------------------------------
+#  If the user has not set --prefix, we set our default to nothing.
+#  In this case, if the user has not set --sysconfdir, we set it
+#  to the package default of /etc/bacula.  If either --prefix or
+#  --sysconfdir is set, we leave sysconfdir alone except to eval it.
+# ------------------------------------------------------------------
+if test x${prefix} = xNONE ; then
+    if test `eval echo ${sysconfdir}` = NONE/etc ; then
+       sysconfdir=/etc/bacula
+    fi
+    prefix=
+fi
+sysconfdir=`eval echo ${sysconfdir}`
+
+# -------------------------------------------------------------------------
+#  If the user has not set --exec-prefix, we default to ${prefix}
+# -------------------------------------------------------------------------
+if test x${exec_prefix} = xNONE ; then
+    exec_prefix=${prefix}
+fi
+
+# ------------------------------------------------------------------
+# If the user has not set --sbindir, we set our default as /sbin
+# ------------------------------------------------------------------
+if test x$sbindir = x'${exec_prefix}/sbin' ; then
+    sbindir=${exec_prefix}/sbin
+fi
+sbindir=`eval echo ${sbindir}`
+                     
+# ------------------------------------------------------------------
+# All list of languages for which a translation exist. Each
+#  language is separated by a space.
+# ------------------------------------------------------------------
+ALL_LINGUAS=""
+
+AC_PATH_PROGS(MSGFMT, msgfmt, no)
+if test "$MSGFMT" = "no"
+then
+   echo 'msgfmt program not found, disabling NLS !'
+   USE_NLS=no
+   USE_INCLUDED_LIBINTL=no
+#else
+#   AM_GNU_GETTEXT
+fi
+
+
+support_mysql=no
+support_sqlite=no
+support_smartalloc=yes
+cats=
+
+dnl# --------------------------------------------------------------------------
+dnl# CHECKING COMMAND LINE OPTIONS
+dnl# --------------------------------------------------------------------------
+AC_ARG_ENABLE(everything,
+  [  --enable-everything     enable standard non-multichoice features: marked *],
+  [if test x$enableval = xyes; then
+    support_smartalloc=yes
+  fi])
+
+# -------------------------------------------
+# gnome (default off)
+# -------------------------------------------
+support_gnome=no
+AC_ARG_ENABLE(gnome,
+  [  --enable-gnome    enable build of gnome-console GUI                     *],
+  [if test x$enableval = xyes; then
+    support_gnome=yes
+  fi])
+
+GNOME_DIR=
+if test x$support_gnome = xyes; then
+    GNOME_INIT
+    GNOME_DIR=src/gnome-console
+fi
+AC_SUBST(GNOME_DIR)
+
+
+# -------------------------------------------
+# smartalloc (default off)
+# -------------------------------------------
+AC_ARG_ENABLE(smartalloc,
+  [  --enable-smartalloc     enable smartalloc debugging support                  *],
+  [if test x$enableval = xno; then
+    support_smartalloc=no
+  fi])
+
+if test x$support_smartalloc = xyes; then
+   AC_DEFINE(SMARTALLOC)
+fi
+
+
+
+# ---------------------------------------------------
+# Check for readline support/directory (default on)
+# ---------------------------------------------------
+support_readline=yes
+# this allows you to turn it completely off
+AC_ARG_ENABLE(readline,
+  [  --disable-readline      disable readline support ],
+  [if test x$enableval = xno; then
+    support_readline=no
+  fi])
+
+got_readline="no"
+READLINE_SRC=
+if test x$support_readline = xyes; then
+   AC_ARG_WITH(readline,
+     [ --with-readline[=DIR]   Specify readline library directory],
+     [
+       case "$with_readline" in
+       no) : ;;
+       yes|*)
+         if test "$with_readline" != "yes"; then
+           CONS_INC="-I$with_readline"
+           CONS_LDFLAGS="-L$with_readline"
+         else
+            with_readline="/usr/include/readline" 
+         fi
+         AC_CHECK_HEADER($with_readline/readline.h, 
+            [ AC_MSG_RESULT(yes)
+              AC_DEFINE(HAVE_READLINE) 
+              CONS_LIBS="-lreadline"
+              got_readline="yes"   
+            ],
+            [ AC_MSG_ERROR([*** readline library missing]) 
+            ]
+         )
+         ;;
+       esac
+     ],[
+       # check for standard readline library
+       AC_CHECK_HEADER(/usr/include/readline/readline.h, 
+       [ AC_MSG_RESULT(yes)
+        AC_DEFINE(HAVE_READLINE)
+        got_readline="yes"
+        CONS_INC="-I/usr/include/readline"
+        CONS_LIBS="-lreadline"
+       ], [
+        # Did not find starndard library, so user our own
+        AC_MSG_RESULT(yes)
+        AC_DEFINE(HAVE_READLINE)
+        got_readline="yes"
+        CONS_INC="-I${TOP_DIR}/depkgs"
+        CONS_LIBS="-lreadline -lhistory"
+        CONS_LDFLAGS="-L${TOP_DIR}/depkgs/readline"
+        READLINE_SRC="${TOP_DIR}/depkgs/readline"
+       ])
+     ]  
+   )
+fi
+AC_SUBST(CONS_INC)
+AC_SUBST(CONS_LIBS)
+AC_SUBST(CONS_LDFLAGS)
+AC_SUBST(READLINE_SRC)
+
+# Minimal stuff for readline Makefile configuration
+MAKE_SHELL=/bin/sh
+AC_SUBST(MAKE_SHELL)
+
+AC_HEADER_STAT
+AC_HEADER_DIRENT
+
+AC_CHECK_FUNCS(strcasecmp select setenv putenv tcgetattr setlocale lstat lchown)
+
+#AC_CHECK_FUNC(getopt_long, AC_DEFINE(HAVE_GETOPT_LONG),
+#   [LIBEXTRAOBJ="$LIBEXTRAOBJ getopt.o getopt1.o"
+#    EXTRAOBJ="$EXTRAOBJ lib/getopt.o lib/getopt1.o"])
+
+AC_CHECK_FUNC(getopt_long, AC_DEFINE(HAVE_GETOPT_LONG))
+
+
+AC_FUNC_STRCOLL
+
+AC_CHECK_HEADERS(varargs.h \
+               sys/ptem.h sys/pte.h sys/stream.h \
+               termcap.h termio.h )
+
+TERMCAP_LIB=-ltermcap
+AC_SUBST(TERMCAP_LIB)
+
+
+# End of readline stuff
+# -----------------------------------------------------------------------
+
+
+# ---------------------------------------------------
+# Check for GMP support/directory
+# ---------------------------------------------------
+GMP_SRC=
+local_gmp="no"
+AC_ARG_WITH(gmp,
+  [  --with-gmp[=DIR]  Specify gmp library directory],
+  [
+     case "$with_gmp" in
+     no) : ;;
+     yes|*)
+       if test "$with_gmp" != "yes"; then
+        GMP_INC="-I$with_gmp"
+        GMP_LIBS="-lgmp"
+        GMP_LDFLAGS="-L$with_gmp"
+       else
+         with_gmp="/usr/include" 
+       fi
+       AC_CHECK_HEADER($with_gmp/gmp.h, 
+         [ AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_GMP) 
+           GMP_LIBS="-lgmp"
+           got_gmp="yes"   
+         ],
+         [ AC_MSG_ERROR([*** gmp library missing]) 
+         ]
+       )
+       ;;
+     esac
+  ],[
+    # check for standard gmp library
+    AC_CHECK_HEADER(/usr/include/gmp.h,
+    [ AC_MSG_RESULT(yes)
+      AC_DEFINE(HAVE_GMP)
+      got_gmp="yes"
+      GMP_INC=
+      GMP_LIBS="-lgmp"
+    ], [
+      # Did not find standard library, so use our own
+      AC_MSG_RESULT(yes)
+      AC_DEFINE(HAVE_GMP)
+      got_gmp="yes"
+      local_gmp="yes"
+      GMP_INC="-I${TOP_DIR}/depkgs/gmp"
+      GMP_LIBS="-lgmp"
+      GMP_LDFLAGS="-L${TOP_DIR}/depkgs/gmp"
+      GMP_SRC="${TOP_DIR}/depkgs/gmp"
+    ])
+  ]   
+)
+AC_SUBST(GMP_INC)
+AC_SUBST(GMP_LIBS)
+AC_SUBST(GMP_LDFLAGS)
+AC_SUBST(GMP_SRC)
+
+# End of GMP stuff
+# -----------------------------------------------------------------------
+
+
+# ---------------------------------------------------
+# Check for CWEB support/directory
+# ---------------------------------------------------
+CWEB_SRC=
+local_cweb="no"
+AC_ARG_WITH(cweb,
+  [  --with-cweb[=DIR]  Specify cweb library directory],
+  [
+     case "$with_cweb" in
+     no) : ;;
+     yes|*)
+       if test "$with_cweb" != "yes"; then
+        CWEB_INC="-I$with_cweb"
+        CWEB_LIBS="-lcweb"
+        CWEB_LDFLAGS="-L$with_cweb"
+       else
+         with_cweb="/usr/include" 
+       fi
+       AC_CHECK_HEADER($with_cweb/cweb.h, 
+         [ AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_CWEB) 
+           CWEB_LIBS="-lcweb"
+           got_cweb="yes"   
+         ],
+         [ AC_MSG_ERROR([*** cweb library missing]) 
+         ]
+       )
+       ;;
+     esac
+  ],[
+    # check for standard cweb library
+    AC_CHECK_HEADER(/usr/include/cweb.h,
+    [ AC_MSG_RESULT(yes)
+      AC_DEFINE(HAVE_CWEB)
+      got_cweb="yes"
+      CWEB_INC=
+      CWEB_LIBS="-lcweb"
+    ], [
+      # Did not find starndard library, so use our own
+      AC_MSG_RESULT(yes)
+      AC_DEFINE(HAVE_CWEB)
+      got_cweb="yes"
+      local_cweb="yes"
+      CWEB_INC="-I${TOP_DIR}/depkgs/cweb"
+      CWEB_LIBS="-lcweb"
+      CWEB_LDFLAGS="-L${TOP_DIR}/depkgs/cweb"
+      CWEB_SRC="${TOP_DIR}/depkgs/cweb"
+    ])
+  ]   
+)
+AC_SUBST(CWEB_INC)
+AC_SUBST(CWEB_LIBS)
+AC_SUBST(CWEB_LDFLAGS)
+AC_SUBST(CWEB_SRC)
+
+# End of CWEB stuff
+# -----------------------------------------------------------------------
+
+
+
+# -----------------------------------------------------------
+# Check whether user wants TCP wrappers support (default off)
+# -----------------------------------------------------------
+TCPW_MSG="no" 
+AC_ARG_WITH(tcp-wrappers,
+  [  --with-tcp-wrappers=DIR Enable tcpwrappers support],
+  [
+    if test "x$withval" != "xno" ; then
+       saved_LIBS="$LIBS"
+       LIBS="$LIBS -lwrap -lnsl"
+       AC_MSG_CHECKING(for libwrap)
+       AC_TRY_LINK(
+         [ #include <tcpd.h>
+            int deny_severity = 0;
+            int allow_severity = 0;
+            struct request_info *req; ],
+         [ hosts_access(req); ],
+         [
+           AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_LIBWRAP)
+           TCPW_MSG="yes" 
+         ],
+         [AC_MSG_ERROR([*** libwrap missing]) ]
+       )
+    fi
+  ]
+)
+
+# ------------------------------------------
+# Where to place working dir
+# ------------------------------------------
+working_dir=`eval echo ${sysconfdir}/working`
+AC_ARG_WITH(working-dir,
+   [  --with-working-dir=PATH Specify location of Bacula working files],
+   [
+       if test "x$withval" != "xno" ; then     
+             working_dir=$withval
+       fi
+   ]
+)
+
+AC_SUBST(working_dir)
+
+# ------------------------------------------
+# Where to send dump email
+# ------------------------------------------
+dump_email=root
+AC_ARG_WITH(dump-email,
+   [  --with-dump-email=Dump email address],
+   [
+       if test "x$withval" != "xno" ; then     
+             dump_email=$withval
+       fi
+   ]
+)
+
+AC_SUBST(dump_email)
+
+# ------------------------------------------
+# Where to send job email
+# ------------------------------------------
+job_email=root
+AC_ARG_WITH(job-email,
+   [  --with-job-email=Job output email address],
+   [
+       if test "x$withval" != "xno" ; then     
+             job_email=$withval
+       fi
+   ]
+)
+
+AC_SUBST(job_email)
+
+# ------------------------------------------
+# Where to find smtp host
+# ------------------------------------------
+smtp_host=localhost
+AC_ARG_WITH(smtp_host,
+   [  --with-smtp-host=SMTP mail host address],
+   [
+       if test "x$withval" != "xno" ; then     
+             smtp_host=$withval
+       fi
+   ]
+)
+
+AC_SUBST(smtp_host)
+
+
+# ------------------------------------
+# Where to place pid files
+# ------------------------------------
+piddir=/var/run
+AC_ARG_WITH(pid-dir,
+    [  --with-pid-dir=PATH    Specify location of Bacula pid files],
+    [
+       if test "x$withval" != "xno" ; then     
+           piddir=$withval
+       fi
+    ]
+)
+
+# make sure the pid directory exists
+if test ! -d $piddir ; then    
+    piddir=`eval echo ${sysconfdir}`
+    case $piddir in
+         NONE/*) piddir=`echo $piddir | sed "s~NONE~$ac_default_prefix~"` ;;
+    esac
+fi
+
+AC_DEFINE_UNQUOTED(_PATH_BACULA_PIDDIR, "$piddir")
+AC_SUBST(piddir)
+
+
+# ------------------------------------
+# Where to place subsys "lock file"
+# ------------------------------------
+subsysdir=/var/run/subsys
+AC_ARG_WITH(subsys-dir,
+    [  --with-subsys-dir=PATH   Specify location of Bacula subsys file],
+    [
+       if test "x$withval" != "xno" ; then     
+           subsysdir=$withval
+       fi
+    ]
+)
+
+# make sure the pid directory exists
+if test ! -d $subsysdir ; then    
+    subsysdir=`eval echo ${sysconfdir}`
+    case $subsysdir in
+       NONE/*) subsysdir=`echo $subsysdir | sed "s~NONE~$ac_default_prefix~"` ;;
+    esac
+fi
+
+AC_SUBST(subsysdir)
+
+
+
+# ------------------------------------
+# Where to start assigning ports
+# ------------------------------------
+baseport=9101
+AC_ARG_WITH(baseport,
+    [  --with-baseport=PORT    Specify base port address for daemons],
+    [
+       if test "x$withval" != "xno" ; then     
+            baseport=$withval
+       fi
+    ]
+)
+
+AC_SUBST(baseport)
+dir_port=`expr $baseport`
+fd_port=`expr $baseport + 1`
+sd_port=`expr $fd_port + 1`
+
+AC_SUBST(dir_port)
+AC_SUBST(fd_port)
+AC_SUBST(sd_port)
+
+
+# ------------------------------------------
+# Generate passwords
+# ------------------------------------------
+dir_password=
+AC_ARG_WITH(dir-password,
+   [  --with-dir-password=PASSWORD Specify Director's password],
+   [
+       if test "x$withval" != "xno" ; then     
+          dir_password=$withval
+       fi
+   ]
+)
+
+if test "x$dir_password" = "x" ; then
+   if test "x$OPENSSL" = "xnone" ; then
+      key=`date | uuencode 1 | tr "\"@\\\`\\ \\=\\,\\(\\)\\#\\.\\!\\-$'" abcdefghijklmnopqrst | awk '{getline} {print} {exit}'`
+   else
+      key=`openssl rand -base64 33`
+   fi
+   dir_password=$key
+fi
+
+fd_password=
+AC_ARG_WITH(fd-password,
+   [  --with-fd-password=PASSWORD Specify Client's password],
+   [
+       if test "x$withval" != "xno" ; then     
+          fd_password=$withval
+       fi
+   ]
+)
+
+if test "x$fd_password" = "x" ; then
+   if test "x$OPENSSL" = "xnone" ; then
+      key=`date | uuencode 1 | tr "\"@\\\`\\ \\=\\,\\(\\)\\#\\.\\!\\-$'" tsrqponmlkjihgfedcba | awk '{getline} {print} {exit}'`
+   else
+      key=`openssl rand -base64 33`
+   fi
+   fd_password=$key
+fi
+
+sd_password=
+AC_ARG_WITH(sd-password,
+   [  --with-sd-password=PASSWORD Specify Storage daemon's password],
+   [
+       if test "x$withval" != "xno" ; then     
+          sd_password=$withval
+       fi
+   ]
+)
+
+if test "x$sd_password" = "x" ; then
+   if test "x$OPENSSL" = "xnone" ; then
+      key=`date | uuencode 1 | tr "\"@\\\`\\ \\=\\,\\(\\)\\#\\.\\!\\-$'" 123456789uvwxyzabcdef | awk '{getline} {print} {exit}'`
+   else
+      key=`openssl rand -base64 33`
+   fi
+   sd_password=$key
+fi
+
+
+AC_SUBST(dir_password)
+AC_SUBST(fd_password)
+AC_SUBST(sd_password)
+
+
+
+AC_SUBST(cats)
+
+# ------------------------------------------------
+# Bacula check for various SQL database engines
+# ------------------------------------------------
+BA_CHECK_MYSQL_DB
+
+
+# ------------------------------------------------
+# Bacula check for various SQL database engines
+# ------------------------------------------------
+BA_CHECK_SQLITE_DB
+
+
+AC_DEFINE(PROTOTYPES)
+
+dnl# --------------------------------------------------------------------------
+dnl# Supply default CFLAGS, if not specified by `CFLAGS=flags ./configure'
+dnl#
+if test -z "$CFLAGS"; then
+    if test -z "$CCOPTS"; then
+       CCOPTS='-O'
+dnl>   if test "x$GCC" = xyes; then
+dnl>       if test x$system = xLinux; then
+dnl>           CCOPTS="$CCOPTS "'-O2 -fno-strength-reduce'
+dnl>       fi
+dnl>   fi
+    fi
+    CFLAGS="$CCOPTS"
+fi
+
+
+dnl A few others 
+AC_EXEEXT
+dnl # AC_SYS_LARGEFILE must modify aclocal.m4
+dnl LARGE_FILE_SUPPORT
+  
+
+
+AC_PATH_XTRA
+
+dnl# --------------------------------------------------------------------------
+dnl# CHECKING FOR HEADER FILES
+dnl# --------------------------------------------------------------------------
+AC_CHECK_HEADERS( \
+       assert.h \
+       fcntl.h \
+       grp.h \
+       libc.h \
+       limits.h \
+       stdarg.h \
+       stdlib.h \
+       string.h \
+       termios.h \
+       unistd.h \
+       sys/byteorder.h \
+       sys/ioctl.h \
+       sys/select.h \
+       sys/sockio.h \
+       sys/time.h \
+)
+AC_HEADER_STDC
+AC_HEADER_MAJOR
+AC_HEADER_DIRENT
+AC_HEADER_STAT
+AC_HEADER_SYS_WAIT
+AC_HEADER_TIME
+AC_STRUCT_ST_BLKSIZE
+AC_STRUCT_ST_BLOCKS
+AC_STRUCT_TIMEZONE
+
+# It seems that that many machines where <utime.h> seems to be
+# broken just require something like -D_XXX_SOURCE, where XXX might
+# be POSIX, POSIX_C, ALL, HPUX or whatever, depending on the machine.
+
+AC_CACHE_CHECK(for utime.h, tar_cv_header_utime_h,
+  [AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <utime.h>], [struct utimbuf foo],
+  tar_cv_header_utime_h=yes, tar_cv_header_utime_h=no)])
+test $tar_cv_header_utime_h = yes && AC_DEFINE(HAVE_UTIME_H)
+
+AC_C_CONST
+
+
+dnl# --------------------------------------------------------------------------
+dnl# CHECKING FOR FILESYSTEM TYPE
+dnl# --------------------------------------------------------------------------
+AC_MSG_CHECKING(how to get filesystem type)
+fstype=no
+# The order of these tests is important.
+AC_TRY_CPP([#include <sys/statvfs.h>
+#include <sys/fstyp.h>], AC_DEFINE(FSTYPE_STATVFS) fstype=SVR4)
+if test $fstype = no; then
+AC_TRY_CPP([#include <sys/statfs.h>
+#include <sys/fstyp.h>], AC_DEFINE(FSTYPE_USG_STATFS) fstype=SVR3)
+fi
+if test $fstype = no; then
+AC_TRY_CPP([#include <sys/statfs.h>
+#include <sys/vmount.h>], AC_DEFINE(FSTYPE_AIX_STATFS) fstype=AIX)
+fi
+if test $fstype = no; then  
+AC_TRY_CPP([#include <mntent.h>], AC_DEFINE(FSTYPE_MNTENT) fstype=4.3BSD)
+fi
+if test $fstype = no; then  
+AC_EGREP_HEADER(f_type;, sys/mount.h, AC_DEFINE(FSTYPE_STATFS) fstype=4.4BSD/OSF1)
+fi
+if test $fstype = no; then  
+AC_TRY_CPP([#include <sys/mount.h>
+#include <sys/fs_types.h>], AC_DEFINE(FSTYPE_GETMNT) fstype=Ultrix)
+fi
+AC_MSG_RESULT($fstype)
+
+dnl# --------------------------------------------------------------------------
+dnl# CHECKING FOR TYPEDEFS, STRUCTURES, AND COMPILER CHARACTERISTICS.
+dnl# --------------------------------------------------------------------------
+AC_TYPE_SIGNAL
+SIGNAL_CHECK
+AC_TYPE_MODE_T
+AC_TYPE_UID_T
+AC_TYPE_SIZE_T
+AC_TYPE_PID_T
+AC_TYPE_OFF_T
+AC_CHECK_TYPE(ino_t, unsigned long)
+AC_CHECK_TYPE(dev_t, unsigned long)
+AC_CHECK_TYPE(daddr_t, long)
+AC_CHECK_TYPE(major_t, int)
+AC_CHECK_TYPE(minor_t, int)
+AC_CHECK_TYPE(ssize_t, int)
+AC_STRUCT_ST_BLOCKS
+AC_STRUCT_ST_RDEV
+AC_STRUCT_TM
+AC_C_CONST
+
+
+AC_CHECK_SIZEOF(char, 1)
+AC_CHECK_SIZEOF(short int, 2)
+AC_CHECK_SIZEOF(int, 4)
+AC_CHECK_SIZEOF(long int, 4)
+AC_CHECK_SIZEOF(long long int, 8)
+AC_CHECK_SIZEOF(int *, 4)
+
+# Check for sys/types.h types
+AC_CACHE_CHECK([for u_int type], ac_cv_have_u_int, [
+    AC_TRY_COMPILE(
+       [ #include <sys/types.h> ], 
+       [ u_int a; a = 1;], 
+       [ ac_cv_have_u_int="yes" ],
+       [ ac_cv_have_u_int="no" ]
+    )
+])
+if test "x$ac_cv_have_u_int" = "xyes" ; then
+   AC_DEFINE(HAVE_U_INT)
+   have_u_int=1
+fi
+
+AC_CACHE_CHECK([for intmax_t type], ac_cv_have_intmax_t, [
+   AC_TRY_COMPILE(
+      [ #include <sys/types.h> ], 
+      [ intmax_t a; a = 1;], 
+      [ ac_cv_have_intmax_t="yes" ],
+      [ 
+        AC_TRY_COMPILE(
+           [ #include <stdint.h> ], 
+           [ intmax_t a; a = 1;], 
+           [ ac_cv_have_intmax_t="yes" ],
+           [ ac_cv_have_intmax_t="no" ]
+        )
+      ]
+   )       
+
+])
+if test "x$ac_cv_have_intmax_t" = "xyes" ; then
+   AC_DEFINE(HAVE_INTMAX_T)
+   have_intmax_t=1
+fi
+
+
+AC_CACHE_CHECK([for u_intmax_t type], ac_cv_have_u_intmax_t, [
+   AC_TRY_COMPILE(
+      [ #include <sys/types.h> ], 
+      [ u_intmax_t a; a = 1;], 
+      [ ac_cv_have_u_intmax_t="yes" ],
+      [ 
+        AC_TRY_COMPILE(
+           [ #include <stdint.h> ], 
+           [ u_intmax_t a; a = 1;], 
+           [ ac_cv_have_u_intmax_t="yes" ],
+           [ ac_cv_have_u_intmax_t="no" ]
+        )
+      ]
+   )
+])
+if test "x$ac_cv_have_u_intmax_t" = "xyes" ; then
+   AC_DEFINE(HAVE_U_INTMAX_T)
+   have_u_intmax_t=1
+fi
+
+
+AC_CACHE_CHECK([for intXX_t types], ac_cv_have_intxx_t, [
+   AC_TRY_COMPILE(
+      [ #include <sys/types.h> ], 
+      [ int8_t a; int16_t b; int32_t c; a = b = c = 1;], 
+      [ ac_cv_have_intxx_t="yes" ],
+      [ ac_cv_have_intxx_t="no" ]
+   )
+])
+if test "x$ac_cv_have_intxx_t" = "xyes" ; then
+   AC_DEFINE(HAVE_INTXX_T)
+   have_intxx_t=1
+fi
+       
+AC_CACHE_CHECK([for int64_t type], ac_cv_have_int64_t, [
+   AC_TRY_COMPILE(
+      [ #include <sys/types.h> ], 
+      [ int64_t a; a = 1;], 
+      [ ac_cv_have_int64_t="yes" ],
+      [ ac_cv_have_int64_t="no" ]
+   )
+])
+if test "x$ac_cv_have_int64_t" = "xyes" ; then
+   AC_DEFINE(HAVE_INT64_T)
+   have_int64_t=1
+fi
+       
+AC_CACHE_CHECK([for u_intXX_t types], ac_cv_have_u_intxx_t, [
+   AC_TRY_COMPILE(
+      [ #include <sys/types.h> ], 
+      [ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;], 
+      [ ac_cv_have_u_intxx_t="yes" ],
+      [ ac_cv_have_u_intxx_t="no" ]
+   )
+])
+if test "x$ac_cv_have_u_intxx_t" = "xyes" ; then
+   AC_DEFINE(HAVE_U_INTXX_T)
+   have_u_intxx_t=1
+fi
+
+AC_CACHE_CHECK([for u_int64_t types], ac_cv_have_u_int64_t, [
+   AC_TRY_COMPILE(
+      [ #include <sys/types.h> ], 
+      [ u_int64_t a; a = 1;], 
+      [ ac_cv_have_u_int64_t="yes" ],
+      [ ac_cv_have_u_int64_t="no" ]
+   )
+])
+if test "x$ac_cv_have_u_int64_t" = "xyes" ; then
+   AC_DEFINE(HAVE_U_INT64_T)
+   have_u_int64_t=1
+fi
+
+if (test -z "$have_u_intxx_t" || test -z "$have_intxx_t" && \
+          test "x$ac_cv_header_sys_bitypes_h" = "xyes")
+then
+   AC_MSG_CHECKING([for intXX_t and u_intXX_t types in sys/bitypes.h])
+   AC_TRY_COMPILE(
+      [ #include <sys/bitypes.h>  ], 
+      [ int8_t a; int16_t b; int32_t c;
+       u_int8_t e; u_int16_t f; u_int32_t g;
+       a = b = c = e = f = g = 1;  ], 
+      [ AC_DEFINE(HAVE_U_INTXX_T)
+       AC_DEFINE(HAVE_INTXX_T)
+       AC_DEFINE(HAVE_SYS_BITYPES_H)
+       AC_MSG_RESULT(yes) ],
+      [ AC_MSG_RESULT(no)]
+   ) 
+fi
+
+if test -z "$have_u_intxx_t" ; then
+   AC_CACHE_CHECK([for uintXX_t types], ac_cv_have_uintxx_t, [
+      AC_TRY_COMPILE(
+        [ #include <sys/types.h> ], 
+        [ uint8_t a; uint16_t b; 
+          uint32_t c; a = b = c = 1; ], 
+        [ ac_cv_have_uintxx_t="yes" ],
+        [ ac_cv_have_uintxx_t="no" ]
+      )
+   ])
+   if test "x$ac_cv_have_uintxx_t" = "xyes" ; then
+      AC_DEFINE(HAVE_UINTXX_T)
+   fi
+fi
+
+
+dnl# --------------------------------------------------------------------------
+dnl# CHECKING FOR LIBRARY FUNCTIONS
+dnl# --------------------------------------------------------------------------
+AC_CHECK_FUNCS( \
+       fork \
+       getcwd \
+       gethostname \
+       getpid \
+       setpgid \
+       setpgrp \
+       setsid \
+       signal \
+       strerror \
+       strncmp \
+       strncpy \
+       vfprintf \
+       ,,
+       [echo 'configure: cannot find needed function.'; exit 1]
+)
+
+AC_CHECK_FUNCS(fchdir, [AC_DEFINE(HAVE_FCHDIR)])
+
+AC_CHECK_FUNCS(snprintf vsnprintf)
+
+AC_CHECK_FUNCS(localtime_r, [AC_DEFINE(HAVE_LOCALTIME_R)])
+
+AC_CHECK_FUNCS(readdir_r, [AC_DEFINE(HAVE_READDIR_R)])
+
+# Find where sockets are (especially for Solaris)
+AC_CHECK_FUNC(socket,
+    AC_MSG_RESULT(using libc's socket),
+    AC_CHECK_LIB(xnet,socket)
+    AC_CHECK_LIB(socket,socket)
+    AC_CHECK_LIB(inet,socket))
+
+# If resolver functions are not in libc check for -lnsl or -lresolv.
+AC_CHECK_FUNC(gethostbyname,
+    AC_MSG_RESULT(using libc's resolver),
+    AC_CHECK_LIB(nsl,gethostbyname)
+    AC_CHECK_LIB(resolv,gethostbyname))
+
+
+AC_FUNC_STRFTIME
+AC_FUNC_VPRINTF
+AC_FUNC_ALLOCA
+AC_FUNC_GETMNTENT
+AC_FUNC_CLOSEDIR_VOID
+AC_FUNC_SETPGRP                      dnl check for BSD setpgrp.
+AC_FUNC_FNMATCH
+
+
+dnl# FreeBSD needs to link libxpg4
+AC_CHECK_LIB(xpg4, setlocale, [LIBS="$LIBS -lxpg4"])
+
+
+AC_CHECK_LIB(sun, getpwnam)
+AC_CHECK_LIB(z, deflate, [FDLIBS="-lz"])
+have_zlib=no
+if test x$FDLIBS = x-lz; then
+  have_zlib=yes
+fi
+
+dnl Check for pthread libraries
+PTHREAD_LIB=""
+AC_CHECK_LIB(pthread, pthread_create, PTHREAD_LIB="-lpthread",
+       [AC_CHECK_LIB(pthreads, pthread_create, PTHREAD_LIB="-lpthreads",
+           [AC_CHECK_LIB(c_r, pthread_create, PTHREAD_LIB="-lc_r",
+               [AC_CHECK_FUNC(pthread_create)]
+           )]
+       )]
+)
+
+AC_SUBST(FDLIBS)
+AC_DEFINE(FDLIBS)
+
+
+CFLAGS=${CFLAGS--O}
+LDFLAGS=${LDFLAGS--O}
+LIBS="${LIBS} ${SQL_LFLAGS}"
+
+CPPFLAGS="$CPPFLAGS"
+AC_SUBST(DEBUG)
+AC_SUBST(DINCLUDE)
+AC_SUBST(CFLAGS)
+AC_SUBST(CPPFLAGS)
+AC_SUBST(LDFLAGS)
+AC_SUBST(X_CFLAGS)
+AC_SUBST(LIBS)
+AC_SUBST(DLIB)
+AC_SUBST(X_LIBS)
+AC_SUBST(X_EXTRA_LIBS)
+
+dnl# extra configurable objects
+OBJLIST=
+AC_SUBST(OBJLIST)
+
+lld="lld"
+llu="llu"
+
+#
+# Finally we set appropriate distribution specific
+#  variables and defaults
+#
+# PFILES are platform specific files
+PFILES="platforms/Makefile"
+PSCMD="ps -e"
+WIN32=
+hostname=`hostname`
+case "$DISTNAME" in
+alpha)
+       DISTVER=`uname -r`
+       PTHREAD_LIB="-lpthread -lexc"
+       if test "${CC}" = "gcc" ; then
+          lld="lld"
+          llu="llu"
+       else
+          lld="ld"
+          llu="lu"
+       fi
+       TAPEDRIVE="/dev/nrmt0"
+  ;;
+bsdi)
+       DISTVER=`uname -a |awk '{print $3}'`
+       TAPEDRIVE="/dev/nrst0"
+  ;;
+caldera)
+       DISTVER=`cat /etc/.issue | grep Version | cut -f 2 -d ' '`
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+cygwin)
+       DISTVER=`uname -a |awk '{print $3}'`
+       TAPEDRIVE="/dev/nrst0"
+       WIN32=win32
+       CFLAGS="${CFLAGS} -mwindows"
+       LDFLAGS="${LDFLAGS} -mwindows"
+  ;;
+debian)
+       DISTVER=`cat /etc/debian_version`
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+freebsd)
+       DISTVER=`uname -a |awk '{print $3}'`
+       PTHREAD_LIB="-pthread"
+       CFLAGS="${CFLAGS} -pthread"
+       lld="qd"
+       llu="qu"
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -x -o pid,command"
+       PFILES="${PFILES} \
+           platforms/freebsd/Makefile \
+           platforms/freebsd/bacula-fd \
+           platforms/freebsd/bacula-sd \
+           platforms/freebsd/bacula-dir"
+       hostname=`hostname -s`
+  ;;
+hpux)
+       DISTVER=`uname -r`
+       TAPEDRIVE="/dev/rmt/0hnb"
+  ;;
+netbsd)
+       DISTVER=`uname -a |awk '{print $3}'`
+       lld="qd"
+       llu="qu"
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -a -o pid,command"
+  ;;
+openbsd)
+       DISTVER=`uname -a |awk '{print $3}'`
+       lld="qd"
+       llu="qu"
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -a -o pid,command"
+  ;;
+redhat)
+       DISTVER=`cat /etc/redhat-release | grep release |\
+                               cut -f 5 -d ' '`
+       TAPEDRIVE="/dev/nst0"
+       PSCMD="ps -e -o pid,command"
+       PFILES="${PFILES} \
+           platforms/redhat/Makefile \
+           platforms/redhat/bacula-fd \
+           platforms/redhat/bacula-sd \
+           platforms/redhat/bacula-dir"
+       hostname=`hostname -s`
+  ;;
+slackware)
+       DISTVER=`cat /etc/slackware-version`
+       TAPEDRIVE="/dev/nst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+solaris)
+       DISTVER=Solaris
+       TAPEDRIVE="/dev/rmt/0cbn"
+       PSCMD="ps -e -o pid,comm"
+       PFILES="${PFILES} \
+           platforms/solaris/Makefile \
+           platforms/solaris/bacula-fd \
+           platforms/solaris/bacula-sd \
+           platforms/solaris/bacula-dir"
+  ;;
+suse)
+       DISTVER=`cat /etc/SuSE-release |grep VERSION|\
+                               cut -f 3 -d ' '`
+       TAPEDRIVE="/dev/nst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+suse5)
+       DISTNAME=suse
+       DISTVER=5.x
+       TAPEDRIVE="/dev/nst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+unknown)
+       DISTVER=unknown
+       TAPEDRIVE="/dev/nst0"
+  ;;
+*)
+  echo " === Something went wrong. Unknown DISTNAME $DISTNAME ==="
+  ;;
+esac  
+
+AC_SUBST(hostname)
+
+
+LIBS="$PTHREAD_LIB $LIBS"
+
+AC_DEFINE_UNQUOTED(lld, "$lld")
+AC_DEFINE_UNQUOTED(llu, "$llu")
+AC_SUBST(TAPEDRIVE)
+AC_SUBST(PSCMD)
+AC_SUBST(WIN32)
+AC_SUBST(DISTNAME)
+AC_SUBST(DISTVER)
+
+
+dnl# common parts of the Makefile
+MCOMMON=./autoconf/Make.common
+AC_SUBST_FILE(MCOMMON)
+
+AC_OUTPUT([autoconf/Make.common \
+          Makefile \
+          startmysql \
+          stopmysql \
+          btraceback \
+          startit \
+          stopit \
+          bacula \
+          fd \
+          doc/Makefile \
+          src/Makefile \
+          src/console/Makefile \
+          src/console/console.conf \
+          src/gnome-console/Makefile \
+          src/gnome-console/gnome-console.conf \
+          src/dird/Makefile \
+          src/dird/bacula-dir.conf \
+          src/lib/Makefile \
+          src/stored/Makefile \
+          src/stored/bacula-sd.conf \
+          src/filed/Makefile \
+          src/filed/bacula-fd.conf \
+          src/filed/win32/Makefile \
+          src/cats/Makefile \
+          src/cats/make_mysql_tables \
+          src/cats/drop_mysql_tables \
+          src/cats/create_mysql_database \
+          src/cats/grant_mysql_privileges \
+          src/cats/make_sqlite_tables \
+          src/cats/sqlite \
+          src/findlib/Makefile \
+          $PFILES ],  
+         [(echo "Doing make of dependencies"; make depend;) ]
+)
+
+chmod 755 startmysql stopmysql bacula startit stopit btraceback
+cp -f startit stopit btraceback btraceback.gdb src/console
+cp -f startit stopit btraceback btraceback.gdb src/dird
+cp -f startit stopit btraceback btraceback.gdb src/filed
+cp -f startit stopit btraceback btraceback.gdb src/lib
+cp -f startit stopit btraceback btraceback.gdb src/stored
+chmod 755 src/cats/make_mysql_tables src/cats/drop_mysql_tables
+chmod 755 src/cats/make_test_tables src/cats/drop_test_tables
+chmod 755 src/cats/create_mysql_database
+chmod 755 src/cats/grant_mysql_privileges
+chmod 755 src/cats/make_sqlite_tables 
+chmod 755 src/cats/sqlite
+
+
+echo "
+Configuration:
+
+  Host:                      ${DISTNAME} ${DISTVER}
+  Bacula version:            ${VERSION} (${DATE})
+  Source code location:       ${srcdir}
+  Install binaries:          ${sbindir}
+  Install config files:       ${sysconfdir}
+  C Compiler:                ${CC}
+  C++ Compiler:              ${CXX}
+  Compiler flags:            ${CFLAGS} 
+  Linker flags:              ${LDFLAGS}
+  Libraries:                 ${LIBS}
+  Database found:            ${have_db}
+  Database type:             ${db_name}
+
+  Job Output Email:          ${job_email}
+  Traceback Email:           ${dump_email}
+  SMTP Host Address:         ${smtp_host}
+  Director Port              ${dir_port}
+  File daemon Port           ${fd_port}
+  Storage daemon Port        ${sd_port}
+  Working directory          ${working_dir}
+  SQL binaries Directory      ${SQL_BINDIR}
+
+  readline support:          ${got_readline} ${READLINE_SRC}
+  cweb support:              ${got_cweb} ${CWEB_SRC}
+  TCP Wrappers support:       ${TCPW_MSG}
+  ZLIB support:              ${have_zlib}
+  enable-smartalloc:         ${support_smartalloc} 
+  enable-gnome:              ${support_gnome}
+  gmp support:               ${got_gmp} ${GMP_SRC}
+
+  "
diff --git a/bacula/autoconf/gnome-macros/Makefile b/bacula/autoconf/gnome-macros/Makefile
new file mode 100644 (file)
index 0000000..a8037c3
--- /dev/null
@@ -0,0 +1,254 @@
+# Generated automatically from Makefile.in by configure.
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 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.
+
+
+SHELL = /bin/sh
+
+srcdir = .
+top_srcdir = ..
+prefix = /usr/local
+exec_prefix = ${prefix}
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+libexecdir = ${exec_prefix}/libexec
+datadir = ${prefix}/share
+sysconfdir = ${prefix}/etc
+sharedstatedir = ${prefix}/com
+localstatedir = ${prefix}/var
+libdir = ${exec_prefix}/lib
+infodir = ${prefix}/info
+mandir = ${prefix}/man
+includedir = ${prefix}/include
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/bacula
+pkglibdir = $(libdir)/bacula
+pkgincludedir = $(includedir)/bacula
+
+top_builddir = ..
+
+ACLOCAL = aclocal -I macros
+AUTOCONF = autoconf
+AUTOMAKE = automake
+AUTOHEADER = autoheader
+
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+transform = s,x,x,
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CATALOGS = 
+CATOBJEXT = .gmo
+CC = gcc
+DATADIRNAME = share
+GENCAT = 
+GMOFILES = 
+GMSGFMT = /usr/bin/msgfmt
+GNOMEGNORBA_LIBS = -rdynamic -lgnorba -lORBitCosNaming -lORBit -lIIOP -lORBitutil -lnsl -lgnomeui -lart_lgpl -lgdk_imlib -lSM -lICE -lgtk -lgdk -lgmodule -ldl -lXi -lXext -lX11 -lgnome -lgnomesupport -lesd -laudiofile -lm -ldb1 -lglib
+GNOMEUI_LIBS = -rdynamic -lgnomeui -lart_lgpl -lgdk_imlib -lSM -lICE -lgtk -lgdk -lgmodule -ldl -lXi -lXext -lX11 -lgnome -lgnomesupport -lesd -laudiofile -lm -ldb1 -lglib
+GNOME_APPLETS_LIBS = 
+GNOME_CAPPLET_LIBS = 
+GNOME_CONFIG = /usr/bin/gnome-config
+GNOME_DOCKLETS_LIBS = 
+GNOME_INCLUDEDIR = -I/usr/include/gnome-1.0 -DNEED_GNOMESUPPORT_H -I/usr/lib/gnome-libs/include -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/include/orbit-1.0 -I/usr/include/gtk-1.2 -I/usr/X11R6/include
+GNOME_LIBDIR = -rdynamic -L/usr/lib -L/usr/X11R6/lib
+GNOME_LIBS = -lgnome -lgnomesupport -lesd -laudiofile -lm -ldb1 -lglib
+GNORBA_CFLAGS = -I/usr/include/gnome-1.0 -DNEED_GNOMESUPPORT_H -I/usr/lib/gnome-libs/include -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/include/orbit-1.0 -I/usr/include/gtk-1.2 -I/usr/X11R6/include
+GNORBA_LIBS = -rdynamic -L/usr/lib -L/usr/X11R6/lib -lgnorba -lORBitCosNaming -lORBit -lIIOP -lORBitutil -lnsl -lgnomeui -lart_lgpl -lgdk_imlib -lSM -lICE -lgtk -lgdk -lgmodule -ldl -lXi -lXext -lX11 -lgnome -lgnomesupport -lesd -laudiofile -lm -ldb1 -lglib
+GTKXMHTML_LIBS = -rdynamic -lgtkxmhtml -lXpm -ljpeg -lpng -lz -lSM -lICE -lgtk -lgdk -lgmodule -lglib -ldl -lXi -lXext -lX11 -lm
+GTK_CFLAGS = -I/usr/include/gtk-1.2 -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/X11R6/include
+GTK_CONFIG = /usr/bin/gtk-config
+GTK_LIBS = -lSM -lICE -L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXi -lXext -lX11 -lm
+GT_NO = 
+GT_YES = #YES#
+INCLUDE_LOCALE_H = #include <locale.h>
+INSTOBJEXT = .mo
+INTLDEPS = 
+INTLLIBS = 
+INTLOBJS = 
+MAKEINFO = makeinfo
+MKINSTALLDIRS = ./mkinstalldirs
+MSGFMT = /usr/bin/msgfmt
+ORBIT_CFLAGS = -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/include/orbit-1.0
+ORBIT_CONFIG = /usr/bin/orbit-config
+ORBIT_IDL = /usr/bin/orbit-idl
+ORBIT_LIBS = -L/usr/lib -lORBitCosNaming -lORBit -lIIOP -lORBitutil -lglib -lnsl -lm
+PACKAGE = bacula
+POFILES = 
+POSUB = po
+PTHREAD_LIB = -lpthread
+RANLIB = ranlib
+USE_INCLUDED_LIBINTL = no
+USE_NLS = yes
+VERSION = 0.1
+XPM_LIBS = -lXpm
+ZVT_LIBS = -rdynamic -lzvt -lutil -lSM -lICE -lgdk_imlib -lgtk -lgdk -lgmodule -lglib -ldl -lXi -lXext -lX11 -lm
+cflags_set = yes
+cxxflags_set = @cxxflags_set@
+l = 
+
+MACROS =    aclocal-include.m4                           compiler-flags.m4                               curses.m4                                       gnome-bonobo-check.m4                           gnome-fileutils.m4                              gnome-ghttp-check.m4                            gnome-gnorba-check.m4                           gnome-guile-checks.m4                           gnome-libgtop-check.m4                          gnome-objc-checks.m4                            gnome-orbit-check.m4                            gnome-print-check.m4                            gnome-pthread-check.m4                          gnome-support.m4                                gnome-undelfs.m4                                gnome-vfs.m4                                    gnome-x-checks.m4                               gnome-xml-check.m4                              gnome.m4                                        gperf-check.m4                                  linger.m4                                       need-declaration.m4                           
+
+
+EXTRA_DIST = $(MACROS) gnome-common.m4 gnome-gettext.m4 autogen.sh
+MAINTAINERCLEANFILES = macros.dep
+
+#gnome_aclocaldir = $(datadir)/aclocal/gnome-macros
+
+#gnome_aclocal_DATA = $(MACROS) gnome-macros.dep gnome-common.m4       gnome-gettext.m4 autogen.sh
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+DATA =  $(gnome_aclocal_DATA)
+
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu macros/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-gnome_aclocalDATA: $(gnome_aclocal_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(gnome_aclocaldir)
+       @list='$(gnome_aclocal_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(gnome_aclocaldir)/$$p"; \
+           $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(gnome_aclocaldir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_DATA) $$p $(DESTDIR)$(gnome_aclocaldir)/$$p"; \
+           $(INSTALL_DATA) $$p $(DESTDIR)$(gnome_aclocaldir)/$$p; \
+         fi; fi; \
+       done
+
+uninstall-gnome_aclocalDATA:
+       @$(NORMAL_UNINSTALL)
+       list='$(gnome_aclocal_DATA)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(gnome_aclocaldir)/$$p; \
+       done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = macros
+
+distdir: $(DISTFILES)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(top_distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu macros/Makefile
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         if test -d $$d/$$file; then \
+           cp -pr $$d/$$file $(distdir)/$$file; \
+         else \
+           test -f $(distdir)/$$file \
+           || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+           || cp -p $$d/$$file $(distdir)/$$file || :; \
+         fi; \
+       done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-gnome_aclocalDATA
+install-data: install-data-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-gnome_aclocalDATA
+uninstall: uninstall-am
+all-am: Makefile $(DATA)
+all-redirect: all-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+       $(mkinstalldirs)  $(DESTDIR)$(gnome_aclocaldir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+mostlyclean-am:  mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-generic distclean-am
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-gnome_aclocalDATA install-gnome_aclocalDATA tags \
+distdir info-am info dvi-am dvi check check-am installcheck-am \
+installcheck install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-redirect all-am all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+macros.dep: Makefile.am
+       @echo '$$(top_srcdir)/aclocal.m4: $(MACROS:%=macros/%)' > $@
+
+#gnome-macros.dep: Makefile.am
+#      @echo '$$(top_srcdir)/aclocal.m4: $(MACROS:%=$(gnome_aclocaldir)/%)' > $@
+
+# 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/bacula/autoconf/gnome-macros/Makefile.am b/bacula/autoconf/gnome-macros/Makefile.am
new file mode 100644 (file)
index 0000000..f5cc043
--- /dev/null
@@ -0,0 +1,42 @@
+## Please update this variable if any new macros are created
+
+MACROS=                                                \
+  aclocal-include.m4                           \
+  compiler-flags.m4                            \
+  curses.m4                                    \
+  gnome-bonobo-check.m4                                \
+  gnome-fileutils.m4                           \
+  gnome-ghttp-check.m4                         \
+  gnome-gnorba-check.m4                                \
+  gnome-guile-checks.m4                                \
+  gnome-libgtop-check.m4                       \
+  gnome-objc-checks.m4                         \
+  gnome-orbit-check.m4                         \
+  gnome-print-check.m4                         \
+  gnome-pthread-check.m4                       \
+  gnome-support.m4                             \
+  gnome-undelfs.m4                             \
+  gnome-vfs.m4                                 \
+  gnome-x-checks.m4                            \
+  gnome-xml-check.m4                           \
+  gnome.m4                                     \
+  gperf-check.m4                               \
+  linger.m4                                    \
+  need-declaration.m4                          
+
+EXTRA_DIST=$(MACROS) gnome-common.m4 gnome-gettext.m4 autogen.sh
+MAINTAINERCLEANFILES=macros.dep
+
+@MAINT@macros.dep: Makefile.am
+@MAINT@        @echo '$$(top_srcdir)/aclocal.m4: $(MACROS:%=macros/%)' > $@
+
+if INSIDE_GNOME_COMMON
+gnome_aclocaldir = $(datadir)/aclocal/gnome-macros
+
+gnome-macros.dep: Makefile.am
+       @echo '$$(top_srcdir)/aclocal.m4: $(MACROS:%=$(gnome_aclocaldir)/%)' > $@
+
+gnome_aclocal_DATA = $(MACROS) gnome-macros.dep gnome-common.m4 \
+       gnome-gettext.m4 autogen.sh
+
+endif
diff --git a/bacula/autoconf/gnome-macros/Makefile.in b/bacula/autoconf/gnome-macros/Makefile.in
new file mode 100644 (file)
index 0000000..111a372
--- /dev/null
@@ -0,0 +1,254 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 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.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GNOMEGNORBA_LIBS = @GNOMEGNORBA_LIBS@
+GNOMEUI_LIBS = @GNOMEUI_LIBS@
+GNOME_APPLETS_LIBS = @GNOME_APPLETS_LIBS@
+GNOME_CAPPLET_LIBS = @GNOME_CAPPLET_LIBS@
+GNOME_CONFIG = @GNOME_CONFIG@
+GNOME_DOCKLETS_LIBS = @GNOME_DOCKLETS_LIBS@
+GNOME_INCLUDEDIR = @GNOME_INCLUDEDIR@
+GNOME_LIBDIR = @GNOME_LIBDIR@
+GNOME_LIBS = @GNOME_LIBS@
+GNORBA_CFLAGS = @GNORBA_CFLAGS@
+GNORBA_LIBS = @GNORBA_LIBS@
+GTKXMHTML_LIBS = @GTKXMHTML_LIBS@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_CONFIG = @GTK_CONFIG@
+GTK_LIBS = @GTK_LIBS@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+ORBIT_CFLAGS = @ORBIT_CFLAGS@
+ORBIT_CONFIG = @ORBIT_CONFIG@
+ORBIT_IDL = @ORBIT_IDL@
+ORBIT_LIBS = @ORBIT_LIBS@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PTHREAD_LIB = @PTHREAD_LIB@
+RANLIB = @RANLIB@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XPM_LIBS = @XPM_LIBS@
+ZVT_LIBS = @ZVT_LIBS@
+cflags_set = @cflags_set@
+cxxflags_set = @cxxflags_set@
+l = @l@
+
+MACROS =    aclocal-include.m4                           compiler-flags.m4                               curses.m4                                       gnome-bonobo-check.m4                           gnome-fileutils.m4                              gnome-ghttp-check.m4                            gnome-gnorba-check.m4                           gnome-guile-checks.m4                           gnome-libgtop-check.m4                          gnome-objc-checks.m4                            gnome-orbit-check.m4                            gnome-print-check.m4                            gnome-pthread-check.m4                          gnome-support.m4                                gnome-undelfs.m4                                gnome-vfs.m4                                    gnome-x-checks.m4                               gnome-xml-check.m4                              gnome.m4                                        gperf-check.m4                                  linger.m4                                       need-declaration.m4                           
+
+
+EXTRA_DIST = $(MACROS) gnome-common.m4 gnome-gettext.m4 autogen.sh
+MAINTAINERCLEANFILES = macros.dep
+
+@INSIDE_GNOME_COMMON_TRUE@gnome_aclocaldir = $(datadir)/aclocal/gnome-macros
+
+@INSIDE_GNOME_COMMON_TRUE@gnome_aclocal_DATA = $(MACROS) gnome-macros.dep gnome-common.m4      gnome-gettext.m4 autogen.sh
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+DATA =  $(gnome_aclocal_DATA)
+
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu macros/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-gnome_aclocalDATA: $(gnome_aclocal_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(gnome_aclocaldir)
+       @list='$(gnome_aclocal_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(gnome_aclocaldir)/$$p"; \
+           $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(gnome_aclocaldir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_DATA) $$p $(DESTDIR)$(gnome_aclocaldir)/$$p"; \
+           $(INSTALL_DATA) $$p $(DESTDIR)$(gnome_aclocaldir)/$$p; \
+         fi; fi; \
+       done
+
+uninstall-gnome_aclocalDATA:
+       @$(NORMAL_UNINSTALL)
+       list='$(gnome_aclocal_DATA)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(gnome_aclocaldir)/$$p; \
+       done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = macros
+
+distdir: $(DISTFILES)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(top_distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu macros/Makefile
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         if test -d $$d/$$file; then \
+           cp -pr $$d/$$file $(distdir)/$$file; \
+         else \
+           test -f $(distdir)/$$file \
+           || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+           || cp -p $$d/$$file $(distdir)/$$file || :; \
+         fi; \
+       done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-gnome_aclocalDATA
+install-data: install-data-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-gnome_aclocalDATA
+uninstall: uninstall-am
+all-am: Makefile $(DATA)
+all-redirect: all-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+       $(mkinstalldirs)  $(DESTDIR)$(gnome_aclocaldir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+mostlyclean-am:  mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-generic distclean-am
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-gnome_aclocalDATA install-gnome_aclocalDATA tags \
+distdir info-am info dvi-am dvi check check-am installcheck-am \
+installcheck install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-redirect all-am all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+macros.dep: Makefile.am
+       @echo '$$(top_srcdir)/aclocal.m4: $(MACROS:%=macros/%)' > $@
+
+@INSIDE_GNOME_COMMON_TRUE@gnome-macros.dep: Makefile.am
+@INSIDE_GNOME_COMMON_TRUE@     @echo '$$(top_srcdir)/aclocal.m4: $(MACROS:%=$(gnome_aclocaldir)/%)' > $@
+
+# 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/bacula/autoconf/gnome-macros/aclocal-include.m4 b/bacula/autoconf/gnome-macros/aclocal-include.m4
new file mode 100644 (file)
index 0000000..43f9dbc
--- /dev/null
@@ -0,0 +1,16 @@
+# aclocal-include.m4
+# 
+# This macro adds the name macrodir to the set of directories
+# that `aclocal' searches for macros.  
+
+# serial 1
+
+dnl AM_ACLOCAL_INCLUDE(macrodir)
+AC_DEFUN([AM_ACLOCAL_INCLUDE],
+[
+       AM_CONDITIONAL(INSIDE_GNOME_COMMON, false)
+
+       test -n "$ACLOCAL_FLAGS" && ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS"
+
+       for k in $1 ; do ACLOCAL="$ACLOCAL -I $k" ; done
+])
diff --git a/bacula/autoconf/gnome-macros/autogen.sh b/bacula/autoconf/gnome-macros/autogen.sh
new file mode 100644 (file)
index 0000000..71f7dfc
--- /dev/null
@@ -0,0 +1,207 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+DIE=0
+
+if [ -n "$GNOME2_PATH" ]; then
+       ACLOCAL_FLAGS="-I $GNOME2_PATH/share/aclocal $ACLOCAL_FLAGS"
+       PATH="$GNOME2_PATH/bin:$PATH"
+       export PATH
+fi
+
+(autoconf --version) < /dev/null > /dev/null 2>&1 || {
+  echo
+  echo "**Error**: You must have \`autoconf' installed to compile $PKG_NAME."
+  echo "Download the appropriate package for your distribution,"
+  echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+  DIE=1
+}
+
+(grep "^AC_PROG_INTLTOOL" $srcdir/configure.in >/dev/null) && {
+  (intltoolize --version) < /dev/null > /dev/null 2>&1 || {
+    echo 
+    echo "**Error**: You must have \`intltoolize' installed to compile $PKG_NAME."
+    echo "Get ftp://ftp.gnome.org/pub/GNOME/stable/sources/intltool/intltool-0.10.tar.gz"
+    echo "(or a newer version if it is available)"
+    DIE=1
+  }
+}
+
+(grep "^AM_PROG_XML_I18N_TOOLS" $srcdir/configure.in >/dev/null) && {
+  (xml-i18n-toolize --version) < /dev/null > /dev/null 2>&1 || {
+    echo 
+    echo "**Error**: You must have \`xml-i18n-toolize' installed to compile $PKG_NAME."
+    echo "Get ftp://ftp.gnome.org/pub/GNOME/stable/sources/xml-i18n-tools/xml-i18n-tools-0.9.tar.gz"
+    echo "(or a newer version of xml-i18n-tools or intltool if it is available)"
+    DIE=1
+  }
+}
+
+(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && {
+  (libtool --version) < /dev/null > /dev/null 2>&1 || {
+    echo
+    echo "**Error**: You must have \`libtool' installed to compile $PKG_NAME."
+    echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2d.tar.gz"
+    echo "(or a newer version if it is available)"
+    DIE=1
+  }
+}
+
+#grep "^AM_GNU_GETTEXT" $srcdir/configure.in >/dev/null && {
+#  grep "sed.*POTFILES" $srcdir/configure.in >/dev/null || \
+#  (gettext --version) < /dev/null > /dev/null 2>&1 || {
+#    echo
+#    echo "**Error**: You must have \`gettext' installed to compile $PKG_NAME."
+#    echo "Get ftp://ftp.gnu.org/pub/gnu/gettext/gettext-0.10.39.tar.gz"
+#    echo "(or a newer version if it is available)"
+#    DIE=1
+#  }
+#}
+
+#grep "^AM_GNOME_GETTEXT" $srcdir/configure.in >/dev/null && {
+#  grep "sed.*POTFILES" $srcdir/configure.in >/dev/null || \
+#  (gettext --version) < /dev/null > /dev/null 2>&1 || {
+#    echo
+#    echo "**Error**: You must have \`gettext' installed to compile $PKG_NAME."
+#    echo "Get ftp://ftp.gnu.org/pub/gnu/gettext/gettext-0.10.39.tar.gz"
+#    echo "(or a newer version if it is available)"
+#    DIE=1
+#  }
+#}
+
+(automake --version) < /dev/null > /dev/null 2>&1 || {
+  echo
+  echo "**Error**: You must have \`automake' installed to compile $PKG_NAME."
+  echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
+  echo "(or a newer version if it is available)"
+  DIE=1
+  NO_AUTOMAKE=yes
+}
+
+
+# if no automake, don't bother testing for aclocal
+test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
+  echo
+  echo "**Error**: Missing \`aclocal'.  The version of \`automake'"
+  echo "installed doesn't appear recent enough."
+  echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
+  echo "(or a newer version if it is available)"
+  DIE=1
+}
+
+if test "$DIE" -eq 1; then
+  exit 1
+fi
+
+if test -z "$*"; then
+  echo "**Warning**: I am going to run \`configure' with no arguments."
+  echo "If you wish to pass any to it, please specify them on the"
+  echo \`$0\'" command line."
+  echo
+fi
+
+case $CC in
+xlc )
+  am_opt=--include-deps;;
+esac
+
+for coin in `find $srcdir -name configure.in -print`
+do 
+  dr=`dirname $coin`
+  if test -f $dr/NO-AUTO-GEN; then
+    echo skipping $dr -- flagged as no auto-gen
+  else
+    echo processing $dr
+    macrodirs=`sed -n -e 's,AM_ACLOCAL_INCLUDE(\(.*\)),\1,gp' < $coin`
+    ( cd $dr
+      macrosdir=`find . -name macros -print`
+      for i in $macrodirs; do
+       if test -f $i/gnome-gettext.m4; then
+         DELETEFILES="$DELETEFILES $i/gnome-gettext.m4"
+       fi
+      done
+
+      echo "deletefiles is $DELETEFILES"
+      aclocalinclude="$ACLOCAL_FLAGS"
+      for k in $aclocalinclude; do
+       if test -d $k; then
+         if [ -f $k/gnome.m4 -a "$GNOME_INTERFACE_VERSION" = "1" ]; then
+           rm -f $DELETEFILES
+         fi
+        fi
+      done
+      for k in $macrodirs; do
+       if test -d $k; then
+          aclocalinclude="$aclocalinclude -I $k"
+         if [ -f $k/gnome.m4 -a "$GNOME_INTERFACE_VERSION" = "1" ]; then
+           rm -f $DELETEFILES
+         fi
+        fi
+      done
+      if grep "^AM_GNU_GETTEXT" configure.in >/dev/null; then
+       if grep "sed.*POTFILES" configure.in >/dev/null; then
+         : do nothing -- we still have an old unmodified configure.in
+       else
+         echo "Creating $dr/aclocal.m4 ..."
+         test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
+         echo "Running gettextize...  Ignore non-fatal messages."
+         echo "no" | gettextize --force --copy
+         echo "Making $dr/aclocal.m4 writable ..."
+         test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
+        fi
+      fi
+      if grep "^AM_GNOME_GETTEXT" configure.in >/dev/null; then
+       echo "Creating $dr/aclocal.m4 ..."
+       test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
+       echo "Running gettextize...  Ignore non-fatal messages."
+       echo "no" | gettextize --force --copy
+       echo "Making $dr/aclocal.m4 writable ..."
+       test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
+      fi
+      if grep "^AC_PROG_INTLTOOL" configure.in >/dev/null; then
+        echo "Running intltoolize..."
+       intltoolize --copy --force --automake
+      fi
+      if grep "^AM_PROG_XML_I18N_TOOLS" configure.in >/dev/null; then
+        echo "Running xml-i18n-toolize..."
+       xml-i18n-toolize --copy --force --automake
+      fi
+      if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then
+       if test -z "$NO_LIBTOOLIZE" ; then 
+         echo "Running libtoolize..."
+         libtoolize --force --copy
+       fi
+      fi
+      echo "Running aclocal $aclocalinclude ..."
+      aclocal $aclocalinclude || {
+       echo
+       echo "**Error**: aclocal failed. This may mean that you have not"
+       echo "installed all of the packages you need, or you may need to"
+       echo "set ACLOCAL_FLAGS to include \"-I \$prefix/share/aclocal\""
+       echo "for the prefix where you installed the packages whose"
+       echo "macros were not found"
+       exit 1
+      }
+
+      if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then
+       echo "Running autoheader..."
+       autoheader || { echo "**Error**: autoheader failed."; exit 1; }
+      fi
+      echo "Running automake --gnu $am_opt ..."
+      automake --add-missing --gnu $am_opt ||
+       { echo "**Error**: automake failed."; exit 1; }
+      echo "Running autoconf ..."
+      autoconf || { echo "**Error**: autoconf failed."; exit 1; }
+    ) || exit 1
+  fi
+done
+
+conf_flags="--enable-maintainer-mode --enable-compile-warnings" #--enable-iso-c
+
+if test x$NOCONFIGURE = x; then
+  echo Running $srcdir/configure $conf_flags "$@" ...
+  $srcdir/configure $conf_flags "$@" \
+  && echo Now type \`make\' to compile $PKG_NAME || exit 1
+else
+  echo Skipping configure process.
+fi
diff --git a/bacula/autoconf/gnome-macros/compiler-flags.m4 b/bacula/autoconf/gnome-macros/compiler-flags.m4
new file mode 100644 (file)
index 0000000..63f8e2e
--- /dev/null
@@ -0,0 +1,109 @@
+dnl GNOME_COMPILE_WARNINGS
+dnl Turn on many useful compiler warnings
+dnl For now, only works on GCC
+AC_DEFUN([GNOME_COMPILE_WARNINGS],[
+  AC_ARG_ENABLE(compile-warnings, 
+    [  --enable-compile-warnings=[no/minimum/yes]      Turn on compiler warnings.],,enable_compile_warnings=minimum)
+
+  AC_MSG_CHECKING(what warning flags to pass to the C compiler)
+  warnCFLAGS=
+  if test "x$GCC" != xyes; then
+    enable_compile_warnings=no
+  fi
+
+  if test "x$enable_compile_warnings" != "xno"; then
+    if test "x$GCC" = "xyes"; then
+      case " $CFLAGS " in
+      *[\ \    ]-Wall[\ \      ]*) ;;
+      *) warnCFLAGS="-Wall -Wunused" ;;
+      esac
+
+      ## -W is not all that useful.  And it cannot be controlled
+      ## with individual -Wno-xxx flags, unlike -Wall
+      if test "x$enable_compile_warnings" = "xyes"; then
+       warnCFLAGS="$warnCFLAGS -Wmissing-prototypes -Wmissing-declarations"
+      fi
+    fi
+  fi
+  AC_MSG_RESULT($warnCFLAGS)
+
+  AC_ARG_ENABLE(iso-c,
+    [  --enable-iso-c          Try to warn if code is not ISO C ],,
+    enable_iso_c=no)
+
+  AC_MSG_CHECKING(what language compliance flags to pass to the C compiler)
+  complCFLAGS=
+  if test "x$enable_iso_c" != "xno"; then
+    if test "x$GCC" = "xyes"; then
+      case " $CFLAGS " in
+      *[\ \    ]-ansi[\ \      ]*) ;;
+      *) complCFLAGS="$complCFLAGS -ansi" ;;
+      esac
+
+      case " $CFLAGS " in
+      *[\ \    ]-pedantic[\ \  ]*) ;;
+      *) complCFLAGS="$complCFLAGS -pedantic" ;;
+      esac
+    fi
+  fi
+  AC_MSG_RESULT($complCFLAGS)
+  if test "x$cflags_set" != "xyes"; then
+    CFLAGS="$CFLAGS $warnCFLAGS $complCFLAGS"
+    cflags_set=yes
+    AC_SUBST(cflags_set)
+  fi
+])
+
+dnl For C++, do basically the same thing.
+
+AC_DEFUN([GNOME_CXX_WARNINGS],[
+  AC_ARG_ENABLE(cxx-warnings, 
+    [  --enable-cxx-warnings=[no/minimum/yes]  Turn on compiler warnings.],,enable_cxx_warnings=minimum)
+
+  AC_MSG_CHECKING(what warning flags to pass to the C++ compiler)
+  warnCXXFLAGS=
+  if test "x$GCC" != xyes; then
+    enable_compile_warnings=no
+  fi
+  if test "x$enable_cxx_warnings" != "xno"; then
+    if test "x$GCC" = "xyes"; then
+      case " $CXXFLAGS " in
+      *[\ \    ]-Wall[\ \      ]*) ;;
+      *) warnCXXFLAGS="-Wall -Wno-unused" ;;
+      esac
+
+      ## -W is not all that useful.  And it cannot be controlled
+      ## with individual -Wno-xxx flags, unlike -Wall
+      if test "x$enable_cxx_warnings" = "xyes"; then
+       warnCXXFLAGS="$warnCXXFLAGS -Wmissing-prototypes -Wmissing-declarations -Wshadow -Woverloaded-virtual"
+      fi
+    fi
+  fi
+  AC_MSG_RESULT($warnCXXFLAGS)
+
+   AC_ARG_ENABLE(iso-cxx,
+     [  --enable-iso-cxx          Try to warn if code is not ISO C++ ],,
+     enable_iso_cxx=no)
+
+   AC_MSG_CHECKING(what language compliance flags to pass to the C++ compiler)
+   complCXXFLAGS=
+   if test "x$enable_iso_cxx" != "xno"; then
+     if test "x$GCC" = "xyes"; then
+      case " $CXXFLAGS " in
+      *[\ \    ]-ansi[\ \      ]*) ;;
+      *) complCXXFLAGS="$complCXXFLAGS -ansi" ;;
+      esac
+
+      case " $CXXFLAGS " in
+      *[\ \    ]-pedantic[\ \  ]*) ;;
+      *) complCXXFLAGS="$complCXXFLAGS -pedantic" ;;
+      esac
+     fi
+   fi
+  AC_MSG_RESULT($complCXXFLAGS)
+  if test "x$cxxflags_set" != "xyes"; then
+    CXXFLAGS="$CXXFLAGS $warnCXXFLAGS $complCXXFLAGS"
+    cxxflags_set=yes
+    AC_SUBST(cxxflags_set)
+  fi
+])
diff --git a/bacula/autoconf/gnome-macros/curses.m4 b/bacula/autoconf/gnome-macros/curses.m4
new file mode 100644 (file)
index 0000000..5307e13
--- /dev/null
@@ -0,0 +1,318 @@
+dnl Curses detection: Munged from Midnight Commander's configure.in
+dnl
+dnl What it does:
+dnl =============
+dnl
+dnl - Determine which version of curses is installed on your system
+dnl   and set the -I/-L/-l compiler entries and add a few preprocessor
+dnl   symbols 
+dnl - Do an AC_SUBST on the CURSES_INCLUDEDIR and CURSES_LIBS so that
+dnl   @CURSES_INCLUDEDIR@ and @CURSES_LIBS@ will be available in
+dnl   Makefile.in's
+dnl - Modify the following configure variables (these are the only
+dnl   curses.m4 variables you can access from within configure.in)
+dnl   CURSES_INCLUDEDIR - contains -I's and possibly -DRENAMED_CURSES if
+dnl                       an ncurses.h that's been renamed to curses.h
+dnl                       is found.
+dnl   CURSES_LIBS       - sets -L and -l's appropriately
+dnl   CFLAGS            - if --with-sco, add -D_SVID3 
+dnl   has_curses        - exports result of tests to rest of configure
+dnl
+dnl Usage:
+dnl ======
+dnl 1) Add lines indicated below to acconfig.h
+dnl 2) call AC_CHECK_CURSES after AC_PROG_CC in your configure.in
+dnl 3) Instead of #include <curses.h> you should use the following to
+dnl    properly locate ncurses or curses header file
+dnl
+dnl    #if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+dnl    #include <ncurses.h>
+dnl    #else
+dnl    #include <curses.h>
+dnl    #endif
+dnl
+dnl 4) Make sure to add @CURSES_INCLUDEDIR@ to your preprocessor flags
+dnl 5) Make sure to add @CURSES_LIBS@ to your linker flags or LIBS
+dnl
+dnl Notes with automake:
+dnl - call AM_CONDITIONAL(HAS_CURSES, test "$has_curses" = true) from
+dnl   configure.in
+dnl - your Makefile.am can look something like this
+dnl   -----------------------------------------------
+dnl   INCLUDES= blah blah blah $(CURSES_INCLUDEDIR) 
+dnl   if HAS_CURSES
+dnl   CURSES_TARGETS=name_of_curses_prog
+dnl   endif
+dnl   bin_PROGRAMS = other_programs $(CURSES_TARGETS)
+dnl   other_programs_SOURCES = blah blah blah
+dnl   name_of_curses_prog_SOURCES = blah blah blah
+dnl   other_programs_LDADD = blah
+dnl   name_of_curses_prog_LDADD = blah $(CURSES_LIBS)
+dnl   -----------------------------------------------
+dnl
+dnl
+dnl The following lines should be added to acconfig.h:
+dnl ==================================================
+dnl
+dnl /*=== Curses version detection defines ===*/
+dnl /* Found some version of curses that we're going to use */
+dnl #undef HAS_CURSES
+dnl    
+dnl /* Use SunOS SysV curses? */
+dnl #undef USE_SUNOS_CURSES
+dnl 
+dnl /* Use old BSD curses - not used right now */
+dnl #undef USE_BSD_CURSES
+dnl 
+dnl /* Use SystemV curses? */
+dnl #undef USE_SYSV_CURSES
+dnl 
+dnl /* Use Ncurses? */
+dnl #undef USE_NCURSES
+dnl 
+dnl /* If you Curses does not have color define this one */
+dnl #undef NO_COLOR_CURSES
+dnl 
+dnl /* Define if you want to turn on SCO-specific code */
+dnl #undef SCO_FLAVOR
+dnl 
+dnl /* Set to reflect version of ncurses *
+dnl  *   0 = version 1.*
+dnl  *   1 = version 1.9.9g
+dnl  *   2 = version 4.0/4.1 */
+dnl #undef NCURSES_970530
+dnl
+dnl /*=== End new stuff for acconfig.h ===*/
+dnl 
+
+
+AC_DEFUN([AC_CHECK_CURSES],[
+       search_ncurses=true
+       screen_manager=""
+       has_curses=false
+
+       CFLAGS=${CFLAGS--O}
+
+       AC_SUBST(CURSES_LIBS)
+       AC_SUBST(CURSES_INCLUDEDIR)
+
+       AC_ARG_WITH(sco,
+         [  --with-sco              Use this to turn on SCO-specific code],[
+         if test x$withval = xyes; then
+               AC_DEFINE(SCO_FLAVOR)
+               CFLAGS="$CFLAGS -D_SVID3"
+         fi
+       ])
+
+       AC_ARG_WITH(sunos-curses,
+         [  --with-sunos-curses     Used to force SunOS 4.x curses],[
+         if test x$withval = xyes; then
+               AC_USE_SUNOS_CURSES
+         fi
+       ])
+
+       AC_ARG_WITH(osf1-curses,
+         [  --with-osf1-curses      Used to force OSF/1 curses],[
+         if test x$withval = xyes; then
+               AC_USE_OSF1_CURSES
+         fi
+       ])
+
+       AC_ARG_WITH(vcurses,
+         [  --with-vcurses[=incdir] Used to force SysV curses],
+         if test x$withval != xyes; then
+               CURSES_INCLUDEDIR="-I$withval"
+         fi
+         AC_USE_SYSV_CURSES
+       )
+
+       AC_ARG_WITH(ncurses,
+         [  --with-ncurses[=dir]  Compile with ncurses/locate base dir],
+         if test x$withval = xno ; then
+               search_ncurses=false
+         elif test x$withval != xyes ; then
+               CURSES_LIBS="$LIBS -L$withval/lib -lncurses"
+               CURSES_INCLUDEDIR="-I$withval/include"
+               search_ncurses=false
+               screen_manager="ncurses"
+               AC_DEFINE(USE_NCURSES)
+               AC_DEFINE(HAS_CURSES)
+               has_curses=true
+         fi
+       )
+
+       if $search_ncurses
+       then
+               AC_SEARCH_NCURSES()
+       fi
+
+
+])
+
+
+AC_DEFUN([AC_USE_SUNOS_CURSES], [
+       search_ncurses=false
+       screen_manager="SunOS 4.x /usr/5include curses"
+       AC_MSG_RESULT(Using SunOS 4.x /usr/5include curses)
+       AC_DEFINE(USE_SUNOS_CURSES)
+       AC_DEFINE(HAS_CURSES)
+       has_curses=true
+       AC_DEFINE(NO_COLOR_CURSES)
+       AC_DEFINE(USE_SYSV_CURSES)
+       CURSES_INCLUDEDIR="-I/usr/5include"
+       CURSES_LIBS="/usr/5lib/libcurses.a /usr/5lib/libtermcap.a"
+       AC_MSG_RESULT(Please note that some screen refreshs may fail)
+])
+
+AC_DEFUN([AC_USE_OSF1_CURSES], [
+       AC_MSG_RESULT(Using OSF1 curses)
+       search_ncurses=false
+       screen_manager="OSF1 curses"
+       AC_DEFINE(HAS_CURSES)
+       has_curses=true
+       AC_DEFINE(NO_COLOR_CURSES)
+       AC_DEFINE(USE_SYSV_CURSES)
+       CURSES_LIBS="-lcurses"
+])
+
+AC_DEFUN([AC_USE_SYSV_CURSES], [
+       AC_MSG_RESULT(Using SysV curses)
+       AC_DEFINE(HAS_CURSES)
+       has_curses=true
+       AC_DEFINE(USE_SYSV_CURSES)
+       search_ncurses=false
+       screen_manager="SysV/curses"
+       CURSES_LIBS="-lcurses"
+])
+
+dnl AC_ARG_WITH(bsd-curses,
+dnl [--with-bsd-curses         Used to compile with bsd curses, not very fancy],
+dnl    search_ncurses=false
+dnl    screen_manager="Ultrix/cursesX"
+dnl    if test $system = ULTRIX
+dnl    then
+dnl        THIS_CURSES=cursesX
+dnl        else
+dnl        THIS_CURSES=curses
+dnl    fi
+dnl
+dnl    CURSES_LIBS="-l$THIS_CURSES -ltermcap"
+dnl    AC_DEFINE(HAS_CURSES)
+dnl    has_curses=true
+dnl    AC_DEFINE(USE_BSD_CURSES)
+dnl    AC_MSG_RESULT(Please note that some screen refreshs may fail)
+dnl    AC_MSG_WARN(Use of the bsdcurses extension has some)
+dnl    AC_MSG_WARN(display/input problems.)
+dnl    AC_MSG_WARN(Reconsider using xcurses)
+dnl)
+
+       
+dnl
+dnl Parameters: directory filename cureses_LIBS curses_INCLUDEDIR nicename
+dnl
+AC_DEFUN([AC_NCURSES], [
+    if $search_ncurses
+    then
+        if test -f $1/$2
+       then
+           AC_MSG_RESULT(Found ncurses on $1/$2)
+           CURSES_LIBS="$3"
+           CURSES_INCLUDEDIR="$4"
+           search_ncurses=false
+           screen_manager=$5
+            AC_DEFINE(HAS_CURSES)
+            has_curses=true
+           AC_DEFINE(USE_NCURSES)
+       fi
+    fi
+])
+
+AC_DEFUN([AC_SEARCH_NCURSES], [
+    AC_CHECKING("location of ncurses.h file")
+
+    AC_NCURSES(/usr/include, ncurses.h, -lncurses,, "ncurses on /usr/include")
+    AC_NCURSES(/usr/include/ncurses, ncurses.h, -lncurses, -I/usr/include/ncurses, "ncurses on /usr/include/ncurses")
+    AC_NCURSES(/usr/local/include, ncurses.h, -L/usr/local/lib -lncurses, -I/usr/local/include, "ncurses on /usr/local")
+    AC_NCURSES(/usr/local/include/ncurses, ncurses.h, -L/usr/local/lib -L/usr/local/lib/ncurses -lncurses, -I/usr/local/include/ncurses, "ncurses on /usr/local/include/ncurses")
+
+    AC_NCURSES(/usr/local/include/ncurses, curses.h, -L/usr/local/lib -lncurses, -I/usr/local/include/ncurses -DRENAMED_NCURSES, "renamed ncurses on /usr/local/.../ncurses")
+
+    AC_NCURSES(/usr/include/ncurses, curses.h, -lncurses, -I/usr/include/ncurses -DRENAMED_NCURSES, "renamed ncurses on /usr/include/ncurses")
+
+    dnl
+    dnl We couldn't find ncurses, try SysV curses
+    dnl
+    if $search_ncurses 
+    then
+        AC_EGREP_HEADER(init_color, /usr/include/curses.h,
+           AC_USE_SYSV_CURSES)
+       AC_EGREP_CPP(USE_NCURSES,[
+#include <curses.h>
+#ifdef __NCURSES_H
+#undef USE_NCURSES
+USE_NCURSES
+#endif
+],[
+       CURSES_INCLUDEDIR="$CURSES_INCLUDEDIR -DRENAMED_NCURSES"
+        AC_DEFINE(HAS_CURSES)
+       has_curses=true
+        AC_DEFINE(USE_NCURSES)
+        search_ncurses=false
+        screen_manager="ncurses installed as curses"
+])
+    fi
+
+    dnl
+    dnl Try SunOS 4.x /usr/5{lib,include} ncurses
+    dnl The flags USE_SUNOS_CURSES, USE_BSD_CURSES and BUGGY_CURSES
+    dnl should be replaced by a more fine grained selection routine
+    dnl
+    if $search_ncurses
+    then
+       if test -f /usr/5include/curses.h
+       then
+           AC_USE_SUNOS_CURSES
+        fi
+    else
+        # check for ncurses version, to properly ifdef mouse-fix
+       AC_MSG_CHECKING(for ncurses version)
+       ncurses_version=unknown
+cat > conftest.$ac_ext <<EOF
+[#]line __oline__ "configure"
+#include "confdefs.h"
+#ifdef RENAMED_NCURSES
+#include <curses.h>
+#else
+#include <ncurses.h>
+#endif
+#undef VERSION
+VERSION:NCURSES_VERSION
+EOF
+        if (eval "$ac_cpp conftest.$ac_ext") 2>&AC_FD_CC |
+  egrep "VERSION:" >conftest.out 2>&1; then
+changequote(,)dnl
+            ncurses_version=`cat conftest.out|sed -e 's/^[^"]*"//' -e 's/".*//'`
+changequote([,])dnl
+       fi
+       rm -rf conftest*
+        AC_MSG_RESULT($ncurses_version)
+       case "$ncurses_version" in
+changequote(,)dnl
+       4.[01])
+changequote([,])dnl
+            AC_DEFINE(NCURSES_970530,2)
+            ;;
+       1.9.9g)
+            AC_DEFINE(NCURSES_970530,1)
+            ;;
+       1*)
+            AC_DEFINE(NCURSES_970530,0)
+            ;;
+       esac
+    fi
+])
+
+
+
+
+
diff --git a/bacula/autoconf/gnome-macros/gnome-bonobo-check.m4 b/bacula/autoconf/gnome-macros/gnome-bonobo-check.m4
new file mode 100644 (file)
index 0000000..daa109c
--- /dev/null
@@ -0,0 +1,166 @@
+# Configure paths for Bonobo
+# Miguel de Icaza, 99-04-12
+# Stolen from Chris Lahey      99-2-5
+# stolen from Manish Singh again
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_BONOBO ([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for Bonobo, and define BONOBO_CFLAGS and BONOBO_LIBS
+dnl
+AC_DEFUN([AM_PATH_BONOBO],
+[
+dnl 
+dnl Get the cflags and libraries from the gnome-config script
+dnl
+AC_ARG_WITH(bonobo-prefix,[  --with-bonobo-prefix=PFX   Prefix where Bonobo is installed (optional)],
+            bonobo_prefix="$withval", bonobo_prefix="")
+AC_ARG_WITH(bonobo-exec-prefix,[  --with-bonobo-exec-prefix=PFX Exec prefix where Bonobo is installed (optional)],
+            bonobo_exec_prefix="$withval", bonobo_exec_prefix="")
+AC_ARG_ENABLE(bonobotest, [  --disable-bonobotest       Do not try to compile and run a test Bonobo program],
+                   , enable_bonobotest=yes)
+
+  if test x$bonobo_exec_prefix != x ; then
+     bonobo_args="$bonobo_args --exec-prefix=$bonobo_exec_prefix"
+     if test x${GNOME_CONFIG+set} != xset ; then
+        GNOME_CONFIG=$bonobo_exec_prefix/bin/gnome-config
+     fi
+  fi
+  if test x$bonobo_prefix != x ; then
+     bonobo_args="$bonobo_args --prefix=$bonobo_prefix"
+     if test x${GNOME_CONFIG+set} != xset ; then
+        GNOME_CONFIG=$bonobo_prefix/bin/gnome-config
+     fi
+  fi
+
+  AC_PATH_PROG(GNOME_CONFIG, gnome-config, no)
+  min_bonobo_version=ifelse([$1], ,0.1.0,$1)
+  AC_MSG_CHECKING(for BONOBO - version >= $min_bonobo_version)
+  no_bonobo=""
+  if test "$GNOME_CONFIG" = "no" ; then
+    no_bonobo=yes
+  else
+    BONOBO_CFLAGS=`$GNOME_CONFIG $bonoboconf_args --cflags bonobo bonobox`
+    BONOBO_LIBS=`$GNOME_CONFIG $bonoboconf_args --libs bonobo bonobox`
+
+    bonobo_major_version=`$GNOME_CONFIG $bonobo_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    bonobo_minor_version=`$GNOME_CONFIG $bonobo_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    bonobo_micro_version=`$GNOME_CONFIG $bonobo_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_bonobotest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $BONOBO_CFLAGS"
+      LIBS="$LIBS $BONOBO_LIBS"
+dnl
+dnl Now check if the installed BONOBO is sufficiently new. (Also sanity
+dnl checks the results of gnome-config to some extent
+dnl
+      rm -f conf.bonobotest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bonobo.h>
+
+static char*
+my_strdup (char *str)
+{
+  char *new_str;
+  
+  if (str)
+    {
+      new_str = malloc ((strlen (str) + 1) * sizeof(char));
+      strcpy (new_str, str);
+    }
+  else
+    new_str = NULL;
+  
+  return new_str;
+}
+
+int main ()
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  system ("touch conf.bonobotest");
+  bonobo_object_get_type ();
+  return 0;
+}
+
+],, no_bonobo=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_bonobo" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$GNOME_CONFIG" = "no" ; then
+       echo "*** The gnome-config script installed by GNOME-LIBS could not be found"
+       echo "*** If BONOBO was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the GNOME_CONFIG environment variable to the"
+       echo "*** full path to gnome-config."
+     else
+       if test -f conf.bonobotest ; then
+        :
+       else
+          echo "*** Could not run BONOBO test program, checking why..."
+          CFLAGS="$CFLAGS $BONOBO_CFLAGS"
+          LIBS="$LIBS $BONOBO_LIBS"
+          AC_TRY_LINK([
+#include <stdio.h>
+#include <bonobo/gnome-object.h>
+],      [ return 0; ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding BONOBO or finding the wrong"
+          echo "*** version of BONOBO. If it is not finding BONOBO, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+         echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means BONOBO was incorrectly installed"
+          echo "*** or that you have moved BONOBO since it was installed. In the latter case, you"
+          echo "*** may want to edit the gnome-config script: $GNOME_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     BONOBO_CFLAGS=""
+     BONOBO_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(BONOBO_CFLAGS)
+  AC_SUBST(BONOBO_LIBS)
+  rm -f conf.bonobotest
+])
+
+AC_DEFUN([BONOBO_CHECK], [
+       AM_PATH_BONOBO(0.1.0,,[AC_MSG_ERROR(BONOBO not found)])
+])
+
+AC_DEFUN([AM_BONOBO_USES_OAF],
+[
+       AC_REQUIRE([AM_PATH_BONOBO])
+
+       AC_MSG_CHECKING(if Bonobo uses OAF)
+       if ( gnome-config --libs bonobo | grep oaf ) > /dev/null 2>&1 ; then
+         using_oaf="yes"
+         AC_DEFINE(BONOBO_USES_OAF)
+       else
+         using_oaf="no"
+       fi
+
+       AC_MSG_RESULT("$using_oaf")
+
+       AM_CONDITIONAL(BONOBO_USES_OAF, test x"using_oaf" = "xyes")
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-common.m4 b/bacula/autoconf/gnome-macros/gnome-common.m4
new file mode 100644 (file)
index 0000000..83bb00d
--- /dev/null
@@ -0,0 +1,14 @@
+# gnome-common.m4
+# 
+# This only for packages that are not in the GNOME CVS tree.
+
+dnl GNOME_COMMON_INIT
+
+AC_DEFUN([GNOME_COMMON_INIT],
+[
+       GNOME_ACLOCAL_DIR="$GNOME_COMMON_MACROS_DIR"
+       AC_SUBST(GNOME_ACLOCAL_DIR)
+
+       ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS"
+])
+
diff --git a/bacula/autoconf/gnome-macros/gnome-fileutils.m4 b/bacula/autoconf/gnome-macros/gnome-fileutils.m4
new file mode 100644 (file)
index 0000000..a8456f2
--- /dev/null
@@ -0,0 +1,414 @@
+dnl
+dnl GNOME_FILEUTILS_CHECKS
+dnl
+dnl checks that are needed for the diskusage applet.
+dnl
+
+AC_DEFUN([GNOME_FILEUTILS_CHECKS],
+[      
+AC_CHECK_HEADERS(fcntl.h sys/param.h sys/statfs.h sys/fstyp.h \
+mnttab.h mntent.h sys/statvfs.h sys/vfs.h sys/mount.h \
+sys/filsys.h sys/fs_types.h sys/fs/s5param.h)
+
+AC_CHECK_FUNCS(bcopy endgrent endpwent fchdir ftime ftruncate \
+getcwd getmntinfo gettimeofday isascii lchown \
+listmntent memcpy mkfifo strchr strerror strrchr vprintf)
+
+dnl Set some defaults when cross-compiling
+
+if test x$cross_compiling = xyes ; then
+       case "$host_os" in
+       linux*)
+         fu_cv_sys_mounted_getmntent1=yes
+         fu_cv_sys_stat_statfs2_bsize=yes
+         ;;
+       sunos*)
+         fu_cv_sys_stat_statfs4=yes
+         ;;
+       freebsd*)
+         fu_cv_sys_stat_statfs2_bsize=yes
+         ;;
+       osf*)
+         fu_cv_sys_stat_statfs3_osf1=yes
+         ;;
+       esac
+fi
+
+# Determine how to get the list of mounted filesystems.
+list_mounted_fs=
+
+# If the getmntent function is available but not in the standard library,
+# make sure LIBS contains -lsun (on Irix4) or -lseq (on PTX).
+AC_FUNC_GETMNTENT
+
+# This test must precede the ones for getmntent because Unicos-9 is
+# reported to have the getmntent function, but its support is incompatible
+# with other getmntent implementations.
+
+# NOTE: Normally, I wouldn't use a check for system type as I've done for
+# `CRAY' below since that goes against the whole autoconf philosophy.  But
+# I think there is too great a chance that some non-Cray system has a
+# function named listmntent to risk the false positive.
+
+if test -z "$list_mounted_fs"; then
+# Cray UNICOS 9
+AC_MSG_CHECKING([for listmntent of Cray/Unicos-9])
+AC_CACHE_VAL(fu_cv_sys_mounted_cray_listmntent,
+[fu_cv_sys_mounted_cray_listmntent=no
+AC_EGREP_CPP(yes,
+[#ifdef _CRAY
+yes
+#endif
+], [test $ac_cv_func_listmntent = yes \
+&& fu_cv_sys_mounted_cray_listmntent=yes]
+)
+]
+)
+AC_MSG_RESULT($fu_cv_sys_mounted_cray_listmntent)
+if test $fu_cv_sys_mounted_cray_listmntent = yes; then
+list_mounted_fs=found
+AC_DEFINE(MOUNTED_LISTMNTENT)
+fi
+fi
+
+if test $ac_cv_func_getmntent = yes; then
+
+# This system has the getmntent function.
+# Determine whether it's the one-argument variant or the two-argument one.
+
+if test -z "$list_mounted_fs"; then
+# 4.3BSD, SunOS, HP-UX, Dynix, Irix
+AC_MSG_CHECKING([for one-argument getmntent function])
+AC_CACHE_VAL(fu_cv_sys_mounted_getmntent1,
+[test $ac_cv_header_mntent_h = yes \
+&& fu_cv_sys_mounted_getmntent1=yes \
+|| fu_cv_sys_mounted_getmntent1=no])
+AC_MSG_RESULT($fu_cv_sys_mounted_getmntent1)
+if test $fu_cv_sys_mounted_getmntent1 = yes; then
+list_mounted_fs=found
+AC_DEFINE(MOUNTED_GETMNTENT1)
+fi
+fi
+
+if test -z "$list_mounted_fs"; then
+# SVR4
+AC_MSG_CHECKING([for two-argument getmntent function])
+AC_CACHE_VAL(fu_cv_sys_mounted_getmntent2,
+[AC_EGREP_HEADER(getmntent, sys/mnttab.h,
+fu_cv_sys_mounted_getmntent2=yes,
+fu_cv_sys_mounted_getmntent2=no)])
+AC_MSG_RESULT($fu_cv_sys_mounted_getmntent2)
+if test $fu_cv_sys_mounted_getmntent2 = yes; then
+list_mounted_fs=found
+AC_DEFINE(MOUNTED_GETMNTENT2)
+fi
+fi
+
+if test -z "$list_mounted_fs"; then
+AC_MSG_ERROR([could not determine how to read list of mounted filesystems])
+fi
+
+fi
+
+if test -z "$list_mounted_fs"; then
+# DEC Alpha running OSF/1.
+AC_MSG_CHECKING([for getfsstat function])
+AC_CACHE_VAL(fu_cv_sys_mounted_getsstat,
+[AC_TRY_LINK([
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/fs_types.h>],
+[struct statfs *stats;
+int numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT); ],
+fu_cv_sys_mounted_getsstat=yes,
+fu_cv_sys_mounted_getsstat=no)])
+AC_MSG_RESULT($fu_cv_sys_mounted_getsstat)
+if test $fu_cv_sys_mounted_getsstat = yes; then
+list_mounted_fs=found
+AC_DEFINE(MOUNTED_GETFSSTAT)
+fi
+fi
+
+if test -z "$list_mounted_fs"; then
+# AIX.
+AC_MSG_CHECKING([for mntctl function and struct vmount])
+AC_CACHE_VAL(fu_cv_sys_mounted_vmount,
+[AC_TRY_CPP([#include <fshelp.h>],
+fu_cv_sys_mounted_vmount=yes,
+fu_cv_sys_mounted_vmount=no)])
+AC_MSG_RESULT($fu_cv_sys_mounted_vmount)
+if test $fu_cv_sys_mounted_vmount = yes; then
+list_mounted_fs=found
+AC_DEFINE(MOUNTED_VMOUNT)
+fi
+fi
+
+if test -z "$list_mounted_fs"; then
+# SVR3
+AC_MSG_CHECKING([for FIXME existence of three headers])
+AC_CACHE_VAL(fu_cv_sys_mounted_fread_fstyp,
+[AC_TRY_CPP([
+#include <sys/statfs.h>
+#include <sys/fstyp.h>
+#include <mnttab.h>],
+fu_cv_sys_mounted_fread_fstyp=yes,
+fu_cv_sys_mounted_fread_fstyp=no)])
+AC_MSG_RESULT($fu_cv_sys_mounted_fread_fstyp)
+if test $fu_cv_sys_mounted_fread_fstyp = yes; then
+list_mounted_fs=found
+AC_DEFINE(MOUNTED_FREAD_FSTYP)
+fi
+fi
+
+if test -z "$list_mounted_fs"; then
+# 4.4BSD and DEC OSF/1.
+AC_MSG_CHECKING([for getmntinfo function])
+AC_CACHE_VAL(fu_cv_sys_mounted_getmntinfo,
+[
+ok=
+if test $ac_cv_func_getmntinfo = yes; then
+AC_EGREP_HEADER(f_type;, sys/mount.h,
+ok=yes)
+fi
+test -n "$ok" \
+&& fu_cv_sys_mounted_getmntinfo=yes \
+|| fu_cv_sys_mounted_getmntinfo=no
+])
+AC_MSG_RESULT($fu_cv_sys_mounted_getmntinfo)
+if test $fu_cv_sys_mounted_getmntinfo = yes; then
+list_mounted_fs=found
+AC_DEFINE(MOUNTED_GETMNTINFO)
+fi
+fi
+
+# FIXME: add a test for netbsd-1.1 here
+
+if test -z "$list_mounted_fs"; then
+# Ultrix
+AC_MSG_CHECKING([for getmnt function])
+AC_CACHE_VAL(fu_cv_sys_mounted_getmnt,
+[AC_TRY_CPP([
+#include <sys/fs_types.h>
+#include <sys/mount.h>],
+fu_cv_sys_mounted_getmnt=yes,
+fu_cv_sys_mounted_getmnt=no)])
+AC_MSG_RESULT($fu_cv_sys_mounted_getmnt)
+if test $fu_cv_sys_mounted_getmnt = yes; then
+list_mounted_fs=found
+AC_DEFINE(MOUNTED_GETMNT)
+fi
+fi
+
+if test -z "$list_mounted_fs"; then
+# SVR2
+AC_MSG_CHECKING([whether it is possible to resort to fread on /etc/mnttab])
+AC_CACHE_VAL(fu_cv_sys_mounted_fread,
+[AC_TRY_CPP([#include <mnttab.h>],
+fu_cv_sys_mounted_fread=yes,
+fu_cv_sys_mounted_fread=no)])
+AC_MSG_RESULT($fu_cv_sys_mounted_fread)
+if test $fu_cv_sys_mounted_fread = yes; then
+list_mounted_fs=found
+AC_DEFINE(MOUNTED_FREAD)
+fi
+fi
+
+if test -z "$list_mounted_fs"; then
+AC_MSG_ERROR([could not determine how to read list of mounted filesystems])
+# FIXME -- no need to abort building the whole package
+# Cannot build mountlist.c or anything that needs its functions
+fi
+
+AC_CHECKING(how to get filesystem space usage)
+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 $space = no; then
+# SVR4
+AC_CACHE_CHECK([statvfs function (SVR4)], fu_cv_sys_stat_statvfs,
+[AC_TRY_LINK([#include <sys/types.h>
+#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
+space=yes
+AC_DEFINE(STAT_STATVFS)
+fi
+fi
+
+if test $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)));
+}],
+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
+space=yes
+AC_DEFINE(STAT_STATFS3_OSF1)
+fi
+fi
+
+if test $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));
+}],
+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
+space=yes
+AC_DEFINE(STAT_STATFS2_BSIZE)
+fi
+fi
+
+if test $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));
+}],
+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
+space=yes
+AC_DEFINE(STAT_STATFS4)
+fi
+fi
+
+if test $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));
+}],
+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
+space=yes
+AC_DEFINE(STAT_STATFS2_FSIZE)
+fi
+fi
+
+if test $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
+space=yes
+AC_DEFINE(STAT_STATFS2_FS_DATA)
+fi
+fi
+
+if test $space = no; then
+# SVR2
+AC_TRY_CPP([#include <sys/filsys.h>],
+AC_DEFINE(STAT_READ_FILSYS) space=yes)
+fi
+
+if test -n "$list_mounted_fs" && test $space != no; then
+DF_PROG="df"
+# LIBOBJS="$LIBOBJS fsusage.o"
+# LIBOBJS="$LIBOBJS mountlist.o"
+fi
+
+# 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_MSG_CHECKING([for statfs that truncates block counts])
+AC_CACHE_VAL(fu_cv_sys_truncating_statfs,
+[AC_TRY_COMPILE([
+#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);],
+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)
+fi
+AC_MSG_RESULT($fu_cv_sys_truncating_statfs)
+
+AC_CHECKING(for AFS)
+test -d /afs && AC_DEFINE(AFS)
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-ghttp-check.m4 b/bacula/autoconf/gnome-macros/gnome-ghttp-check.m4
new file mode 100644 (file)
index 0000000..0ecacaa
--- /dev/null
@@ -0,0 +1,14 @@
+AC_DEFUN([GNOME_GHTTP_CHECK],[
+       AC_REQUIRE([GNOME_INIT_HOOK])
+       GHTTP_LIB=
+       AC_CHECK_FUNC(connect,,[
+         AC_CHECK_LIB(socket,connect,
+               GHTTP_LIB="-lsocket $GHTTP_LIB",,$GHTTP_LIB)])
+       AC_CHECK_FUNC(gethostbyname,,[
+         AC_CHECK_LIB(nsl,gethostbyname,
+               GHTTP_LIB="-lnsl $GHTTP_LIB",,$GHTTP_LIB)])
+       AC_CHECK_LIB(ghttp, ghttp_request_new, 
+               GHTTP_LIB="-lghttp $GHTTP_LIB",GHTTP_LIB="",-L$gnome_prefix $GHTTP_LIB)
+       AC_SUBST(GHTTP_LIB)
+       AC_PROVIDE([GNOME_GHTTP_CHECK])
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-gnorba-check.m4 b/bacula/autoconf/gnome-macros/gnome-gnorba-check.m4
new file mode 100644 (file)
index 0000000..dbac0a6
--- /dev/null
@@ -0,0 +1,35 @@
+dnl
+dnl GNOME_GNORBA_HOOK (script-if-gnorba-found, failflag)
+dnl
+dnl if failflag is "failure" it aborts if gnorba is not found.
+dnl
+
+AC_DEFUN([GNOME_GNORBA_HOOK],[
+       GNOME_ORBIT_HOOK([],$2)
+       AC_CACHE_CHECK([for gnorba libraries],gnome_cv_gnorba_found,[
+               gnome_cv_gnorba_found=no
+               if test x$gnome_cv_orbit_found = xyes; then
+                       GNORBA_CFLAGS="`gnome-config --cflags gnorba gnomeui`"
+                       GNORBA_LIBS="`gnome-config --libs gnorba gnomeui`"
+                       if test -n "$GNORBA_LIBS"; then
+                               gnome_cv_gnorba_found=yes
+                       fi
+               fi
+       ])
+       AM_CONDITIONAL(HAVE_GNORBA, test x$gnome_cv_gnorba_found = xyes)
+       if test x$gnome_cv_orbit_found = xyes; then
+               $1
+               GNORBA_CFLAGS="`gnome-config --cflags gnorba gnomeui`"
+               GNORBA_LIBS="`gnome-config --libs gnorba gnomeui`"
+               AC_SUBST(GNORBA_CFLAGS)
+               AC_SUBST(GNORBA_LIBS)
+       else
+               if test x$2 = xfailure; then
+                       AC_MSG_ERROR(gnorba library not installed or installation problem)
+               fi
+       fi
+])
+
+AC_DEFUN([GNOME_GNORBA_CHECK], [
+       GNOME_GNORBA_HOOK([],failure)
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-guile-checks.m4 b/bacula/autoconf/gnome-macros/gnome-guile-checks.m4
new file mode 100644 (file)
index 0000000..102351c
--- /dev/null
@@ -0,0 +1,134 @@
+dnl
+dnl GNOME_CHECK_GUILE (failflag)
+dnl
+dnl if failflag is "fail" then GNOME_CHECK_GUILE will abort if guile is not found.
+dnl
+
+AC_DEFUN([GNOME_CHECK_GUILE],
+[
+dnl    AC_MSG_WARN([Withval is: $withval])
+       guile_msg = 'Huh?'
+if test x$withval = xno ; then
+       guile_msg = 'disabled'
+       GUILE_LIBS=
+       GUILE_INCS=
+       AC_SUBST(GUILE_LIBS)
+       AC_SUBST(GUILE_INCS)
+       AM_CONDITIONAL(GUILE, /bin/false)
+else
+       guile_msg="no"
+
+       saved_ldflags="$LDFLAGS"
+       saved_cppflags="$CPPFLAGS"
+       LDFLAGS="$LDFLAGS $GNOME_LIBDIR"
+
+       AC_CHECK_LIB(qthreads,qt_null,[
+               QTTHREADS_LIB="-lqthreads"
+       ],[
+               AC_CHECK_LIB(qt, qt_null, QTTHREADS_LIB="-lqt")
+       ],$LIBS)
+       AC_SUBST(QTTHREADS_LIB)
+
+       AC_CHECK_LIB(termcap,main,TERMCAP_LIB="-ltermcap")
+       AC_CHECK_LIB(readline,main,READLINE_LIB="-lreadline",,$TERMCAP_LIB)
+
+       AC_SUBST(TERMCAP_LIB)
+       AC_SUBST(READLINE_LIB)
+
+       if test "x$cross_compiling" = "xyes" ; then
+         name_build_guile="$target_alias-guile-config"
+       else
+         name_build_guile="guile-config"
+       fi
+
+       AC_CHECK_PROG(BUILD_GUILE, $name_build_guile, yes, no)
+
+       if test "x$BUILD_GUILE" = "xyes"; then
+           AC_MSG_CHECKING(whether $name_build_guile works)
+           if test x`$name_build_guile --version >/dev/null 2>&1 || \
+               echo no` = xno; then
+               BUILD_GUILE=no
+           fi
+           AC_MSG_RESULT($BUILD_GUILE)
+       else
+
+           if test "x$cross_compiling" = "xyes" ; then
+               name_build_guile="$target_alias-build-guile"
+           else        
+               name_build_guile="build-guile"
+           fi
+
+           AC_CHECK_PROG(BUILD_GUILE, $name_build_guile, yes, no)
+
+           if test "x$BUILD_GUILE" = "xyes"; then
+               AC_MSG_CHECKING(whether $name_build_guile works)
+               if test x`$name_build_guile --version >/dev/null 2>&1 || \
+                   echo no` = xno; then
+                   BUILD_GUILE=no
+               fi
+               AC_MSG_RESULT($BUILD_GUILE)
+           fi
+       fi
+
+       AC_CHECK_LIB(m, sin)
+
+       if test "x$BUILD_GUILE" = "xyes"; then
+               AC_MSG_CHECKING(for guile libraries)
+               GUILE_LIBS="`$name_build_guile link`"
+               AC_MSG_RESULT($GUILE_LIBS)
+               AC_MSG_CHECKING(for guile headers)
+               GUILE_INCS="`$name_build_guile compile`"
+               AC_MSG_RESULT($GUILE_INCS)
+       else
+               GUILE_LIBS="$GNOME_LIBDIR"
+               GUILE_INCS="$GNOME_INCLUDEDIR"
+               AC_CHECK_LIB(rx, main, GUILE_LIBS="-lrx $GUILE_LIBS")
+               AC_CHECK_LIB(qt, qt_null, GUILE_LIBS="-lqt $GUILE_LIBS")
+               AC_CHECK_LIB(dl, dlopen, GUILE_LIBS="-ldl $GUILE_LIBS")
+               AC_CHECK_LIB(nsl, t_accept, GUILE_LIBS="$GUILE_LIBS -lnsl")
+               AC_CHECK_LIB(socket, socket, GUILE_LIBS="$GUILE_LIBS -lsocket")
+               GUILE_LIBS="-lguile $GUILE_LIBS $QTTHREADS_LIB $READLINE_LIB $TERMCAP_LIB"
+       fi
+
+       AC_SUBST(GUILE_LIBS)
+       AC_SUBST(GUILE_INCS)
+
+       saved_LIBS="$LIBS"
+       LIBS="$LIBS $GUILE_LIBS"
+       CPPFLAGS="$saved_cppflags $GUILE_INCS"
+
+       AC_MSG_CHECKING(whether guile works)
+       AC_TRY_LINK([
+               #include <libguile.h>
+               #include <guile/gh.h>
+       ],[
+               gh_eval_str("(newline)");
+               scm_boot_guile(0,NULL,NULL,NULL);
+       ],[
+               ac_cv_guile_found=yes
+               AC_DEFINE(HAVE_GUILE)
+       ],[
+               ac_cv_guile_found=no
+       ])
+       AC_MSG_RESULT($ac_cv_guile_found)
+
+       guile_msg=$ac_cv_guile_found
+
+       if test x$ac_cv_guile_found = xno ; then
+               if test x$1 = xfail ; then
+                 AC_MSG_ERROR(Can not find Guile on this system)
+               else
+                 AC_MSG_WARN(Can not find Guile on this system)
+               fi
+               ac_cv_guile_found=no
+               GUILE_LIBS= GUILE_INCS=
+       fi
+
+       LIBS="$saved_LIBS"
+       LDFLAGS="$saved_ldflags"
+       CPPFLAGS="$saved_cppflags"
+
+       AC_SUBST(GUILE_LIBS)
+       AM_CONDITIONAL(GUILE, test x$ac_cv_guile_found = xyes)
+fi
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-libgtop-check.m4 b/bacula/autoconf/gnome-macros/gnome-libgtop-check.m4
new file mode 100644 (file)
index 0000000..1b4e174
--- /dev/null
@@ -0,0 +1,217 @@
+dnl
+dnl LIBGTOP_CHECK_TYPE
+dnl
+dnl Improved version of AC_CHECK_TYPE which takes into account
+dnl that we need to #include some other header files on some
+dnl systems to get some types.
+
+dnl AC_LIBGTOP_CHECK_TYPE(TYPE, DEFAULT)
+AC_DEFUN([AC_LIBGTOP_CHECK_TYPE],
+[AC_REQUIRE([AC_HEADER_STDC])dnl
+AC_MSG_CHECKING(for $1)
+AC_CACHE_VAL(ac_cv_type_$1,
+[AC_EGREP_CPP(dnl
+changequote(<<,>>)dnl
+<<(^|[^a-zA-Z_0-9])$1[^a-zA-Z_0-9]>>dnl
+changequote([,]), [#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+
+/* For Tru64 */
+#ifdef HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl
+AC_MSG_RESULT($ac_cv_type_$1)
+if test $ac_cv_type_$1 = no; then
+  AC_DEFINE($1, $2)
+fi
+])
+
+dnl
+dnl GNOME_LIBGTOP_TYPES
+dnl
+dnl some typechecks for libgtop.
+dnl
+
+AC_DEFUN([GNOME_LIBGTOP_TYPES],
+[
+       AC_CHECK_HEADERS(sys/bitypes.h)
+       AC_LIBGTOP_CHECK_TYPE(u_int64_t, unsigned long long int)
+       AC_LIBGTOP_CHECK_TYPE(int64_t, signed long long int)
+])
+
+dnl
+dnl GNOME_LIBGTOP_HOOK (minversion, script-if-libgtop-enabled, failflag)
+dnl
+dnl if failflag is "fail" then GNOME_LIBGTOP_HOOK will abort if LibGTop
+dnl is not found. 
+dnl
+
+AC_DEFUN([GNOME_LIBGTOP_HOOK],
+[      
+       AC_REQUIRE([GNOME_LIBGTOP_TYPES])
+
+       AC_SUBST(LIBGTOP_LIBDIR)
+       AC_SUBST(LIBGTOP_INCLUDEDIR)
+       AC_SUBST(LIBGTOP_EXTRA_LIBS)
+       AC_SUBST(LIBGTOP_LIBS)
+       AC_SUBST(LIBGTOP_INCS)
+       AC_SUBST(LIBGTOP_NAMES_LIBS)
+       AC_SUBST(LIBGTOP_NAMES_INCS)
+       AC_SUBST(LIBGTOP_MAJOR_VERSION)
+       AC_SUBST(LIBGTOP_MINOR_VERSION)
+       AC_SUBST(LIBGTOP_MICRO_VERSION)
+       AC_SUBST(LIBGTOP_VERSION)
+       AC_SUBST(LIBGTOP_VERSION_CODE)
+       AC_SUBST(LIBGTOP_SERVER_VERSION)
+       AC_SUBST(LIBGTOP_INTERFACE_AGE)
+       AC_SUBST(LIBGTOP_BINARY_AGE)
+       AC_SUBST(LIBGTOP_BINDIR)
+       AC_SUBST(LIBGTOP_SERVER)
+
+       dnl Get the cflags and libraries from the libgtop-config script
+       dnl
+       AC_ARG_WITH(libgtop,
+       [  --with-libgtop=PFX      Prefix where LIBGTOP is installed (optional)],
+       libgtop_config_prefix="$withval", libgtop_config_prefix="")
+       AC_ARG_WITH(libgtop-exec,
+       [  --with-libgtop-exec=PFX Exec prefix where LIBGTOP is installed (optional)],
+       libgtop_config_exec_prefix="$withval", libgtop_config_exec_prefix="")
+
+       if test x$libgtop_config_exec_prefix != x ; then
+         libgtop_config_args="$libgtop_config_args --exec-prefix=$libgtop_config_exec_prefix"
+         if test x${LIBGTOP_CONFIG+set} != xset ; then
+           LIBGTOP_CONFIG=$libgtop_config_exec_prefix/bin/libgtop-config
+         fi
+       fi
+       if test x$libgtop_config_prefix != x ; then
+         libgtop_config_args="$libgtop_config_args --prefix=$libgtop_config_prefix"
+         if test x${LIBGTOP_CONFIG+set} != xset ; then
+           LIBGTOP_CONFIG=$libgtop_config_prefix/bin/libgtop-config
+         fi
+       fi
+
+       AC_PATH_PROG(LIBGTOP_CONFIG, libgtop-config, no)
+       dnl IMPORTANT NOTICE:
+       dnl   If you increase this number here, this means that *ALL*
+       dnl   modules will require the new version, even if they explicitly
+       dnl   give a lower number in their `configure.in' !!!
+       real_min_libgtop_version=1.0.0
+       min_libgtop_version=ifelse([$1], ,$real_min_libgtop_version,$1)
+       dnl I know, the following code looks really ugly, but if you want
+       dnl to make changes, please test it with a brain-dead /bin/sh and
+       dnl with a brain-dead /bin/test (not all shells/tests support the
+       dnl `<' operator to compare strings, that's why I convert everything
+       dnl into numbers and test them).
+       min_libgtop_major=`echo $min_libgtop_version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+       min_libgtop_minor=`echo $min_libgtop_version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+       min_libgtop_micro=`echo $min_libgtop_version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+       test x$min_libgtop_micro = x && min_libgtop_micro=0
+       real_min_libgtop_major=`echo $real_min_libgtop_version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+       real_min_libgtop_minor=`echo $real_min_libgtop_version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+       real_min_libgtop_micro=`echo $real_min_libgtop_version | \
+         sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+       test x$real_min_libgtop_micro = x && real_min_libgtop_micro=0
+       dnl You cannot require a version less then $real_min_libgtop_version,
+       dnl so you don't need to update each `configure.in' when it's increased.
+       if test $real_min_libgtop_major -gt $min_libgtop_major ; then
+         min_libgtop_major=$real_min_libgtop_major
+         min_libgtop_minor=$real_min_libgtop_minor
+         min_libgtop_micro=$real_min_libgtop_micro
+       elif test $real_min_libgtop_major = $min_libgtop_major ; then
+         if test $real_min_libgtop_minor -gt $min_libgtop_minor ; then
+           min_libgtop_minor=$real_min_libgtop_minor
+           min_libgtop_micro=$real_min_libgtop_micro
+         elif test $real_min_libgtop_minor = $min_libgtop_minor ; then
+           if test $real_min_libgtop_micro -gt $min_libgtop_micro ; then
+             min_libgtop_micro=$real_min_libgtop_micro
+           fi
+         fi
+       fi
+       min_libgtop_version="$min_libgtop_major.$min_libgtop_minor.$min_libgtop_micro"
+       AC_MSG_CHECKING(for libgtop - version >= $min_libgtop_version)
+       no_libgtop=""
+       if test "$LIBGTOP_CONFIG" = "no" ; then
+         no_libgtop=yes
+       else
+         configfile=`$LIBGTOP_CONFIG --config`
+         libgtop_major_version=`$LIBGTOP_CONFIG --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+         libgtop_minor_version=`$LIBGTOP_CONFIG --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+         libgtop_micro_version=`$LIBGTOP_CONFIG --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+         if test $libgtop_major_version != $min_libgtop_major ; then 
+           no_libgtop=mismatch
+         else 
+           test $libgtop_minor_version -lt $min_libgtop_minor && no_libgtop=yes
+           if test $libgtop_minor_version = $min_libgtop_minor ; then
+             test $libgtop_micro_version -lt $min_libgtop_micro && no_libgtop=yes
+           fi
+         fi
+         . $configfile
+       fi
+       if test x$no_libgtop = x ; then
+         AC_DEFINE(HAVE_LIBGTOP)
+         AC_DEFINE_UNQUOTED(LIBGTOP_VERSION, "$LIBGTOP_VERSION")
+         AC_DEFINE_UNQUOTED(LIBGTOP_VERSION_CODE, $LIBGTOP_VERSION_CODE)
+         AC_DEFINE_UNQUOTED(LIBGTOP_MAJOR_VERSION, $LIBGTOP_MAJOR_VERSION)
+         AC_DEFINE_UNQUOTED(LIBGTOP_MINOR_VERSION, $LIBGTOP_MINOR_VERSION)
+         AC_DEFINE_UNQUOTED(LIBGTOP_MICRO_VERSION, $LIBGTOP_MICRO_VERSION)
+         AC_DEFINE_UNQUOTED(LIBGTOP_SERVER_VERSION, $LIBGTOP_SERVER_VERSION)
+         AC_MSG_RESULT(yes)
+         dnl Note that an empty true branch is not valid sh syntax.
+         ifelse([$2], [], :, [$2])
+       else
+         AC_MSG_RESULT(no)
+         if test "$no_libgtop"x = mismatchx; then
+           AC_MSG_ERROR(LibGTop major version mismatch $libgtop_major_version != $min_libgtop_major)
+         fi
+         if test "x$3" = "xfail"; then
+           AC_MSG_ERROR(LibGTop >= $min_libgtop_version not found)
+         else
+           AC_MSG_WARN(LibGTop >= $min_libgtop_version not found)
+         fi
+       fi
+
+       AM_CONDITIONAL(HAVE_LIBGTOP, test x$no_libgtop != xyes)
+])
+
+AC_DEFUN([GNOME_INIT_LIBGTOP],[
+       GNOME_LIBGTOP_HOOK($1,[ifelse([$3], [], :, [$3])],$2)
+])
+
+dnl
+dnl GNOME_LIBGTOP_DOCU
+dnl
+dnl checks whether the documentation of LibGTop is installed
+dnl
+
+AC_DEFUN([GNOME_LIBGTOP_DOCU],
+[
+       AC_REQUIRE([GNOME_LIBGTOP_HOOK])
+
+       helpdir="$LIBGTOP_DATADIR/gnome/help/libgtop"
+
+       AC_MSG_CHECKING(whether you have the LibGTop Documentation)
+
+       if test -f "$helpdir/C/topic.dat" ; then
+         have_libgtop_docu=yes
+         AC_DEFINE(HAVE_LIBGTOP_DOCU)
+       else
+         have_libgtop_docu=no
+       fi
+
+       AC_MSG_RESULT($have_libgtop_docu)
+
+       AM_CONDITIONAL(HAVE_LIBGTOP_DOCU, test x$have_libgtop_docu = xyes)
+])
+
diff --git a/bacula/autoconf/gnome-macros/gnome-objc-checks.m4 b/bacula/autoconf/gnome-macros/gnome-objc-checks.m4
new file mode 100644 (file)
index 0000000..c69acb0
--- /dev/null
@@ -0,0 +1,83 @@
+AC_DEFUN([GNOME_CHECK_OBJC],
+[
+dnl Look for an ObjC compiler.
+dnl FIXME: extend list of possible names of ObjC compilers.
+  AC_CHECK_PROGS(OBJC, $OBJC egcs, "")
+  if test "x$OBJC" = "x" ; then
+    AC_CHECK_PROGS(OBJC, $OBJC egcc, "")
+    if test "x$OBJC" = "x" ; then
+      AC_CHECK_PROGS(OBJC, $OBJC gcc, "")
+    fi
+  fi
+
+  AC_REQUIRE([GNOME_PTHREAD_CHECK])
+
+  OBJC_LIBS="-lobjc $PTHREAD_LIB"
+  AC_CHECK_FUNC(sched_yield,,[
+    AC_CHECK_LIB(rt,sched_yield,
+      OBJC_LIBS="$OBJC_LIBS -lrt",[
+      AC_CHECK_LIB(posix4,sched_yield,
+        OBJC_LIBS="$OBJC_LIBS -lposix4",, 
+        $OBJC_LIBS)],
+      $OBJC_LIBS)])
+  AC_SUBST(OBJC_LIBS)
+
+  AC_CACHE_CHECK([if Objective C compiler ($OBJC) works],
+                ac_cv_prog_objc_works, [
+    if test -n "$OBJC"; then
+      cat > conftest.m <<EOF
+#include <objc/Object.h>
+@interface myRandomObj : Object
+{
+}
+@end
+@implementation myRandomObj
+@end
+int main () {
+  /* No, you are not seeing double.  Remember that square brackets
+     are the autoconf m4 quotes.  */
+  id myid = [[myRandomObj alloc]];
+  [[myid free]];
+  return 0;
+}
+EOF
+
+      $OBJC $CFLAGS -o conftest $LDFLAGS conftest.m $OBJC_LIBS 1>&AC_FD_CC 2>&1
+      result=$?
+      rm -f conftest*
+
+      if test $result -eq 0; then
+        ac_cv_prog_objc_works=yes
+      fi
+    else
+      ac_cv_prog_objc_works=no
+    fi
+  ])
+
+  AM_CONDITIONAL(OBJECTIVE_C, test x$ac_cv_prog_objc_works = xyes)
+  dnl Also set the shell variable OBJECTIVE_C to "yes" or "no".
+  OBJECTIVE_C=$ac_cv_prog_objc_works
+])
+
+AC_DEFUN([GNOME_INIT_OBJC],
+[
+       AC_MSG_CHECKING(for an obGnomeConf.sh)
+       my_gnome_libdir=`$GNOME_CONFIG --libdir`
+       if test -f $my_gnome_libdir/obGnomeConf.sh; then
+           . $my_gnome_libdir/obGnomeConf.sh
+           AC_MSG_RESULT(found $my_gnome_libdir)
+           ac_cv_have_gnome_objc=yes
+       else
+           AC_MSG_RESULT(not found)
+           AC_MSG_WARN(Could not find the obGnomeConf.sh file that is generated by gnome-objc install)
+           ac_cv_have_gnome_objc=no
+       fi
+       
+       dnl Add a conditional on whether or not we have gnome-objc
+       AM_CONDITIONAL(HAVE_GNOME_OBJC, test x$ac_cv_have_gnome_objc = xyes)
+       HAVE_GNOME_OBJC=$ac_cv_have_gnome_objc
+
+       AC_SUBST(OBGNOME_INCLUDEDIR)
+       AC_SUBST(OBGNOME_LIBS)
+       AC_SUBST(OBGTK_LIBS)
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-orbit-check.m4 b/bacula/autoconf/gnome-macros/gnome-orbit-check.m4
new file mode 100644 (file)
index 0000000..54bf33a
--- /dev/null
@@ -0,0 +1,33 @@
+dnl
+dnl GNOME_ORBIT_HOOK (script-if-orbit-found, failflag)
+dnl
+dnl if failflag is "failure" it aborts if orbit is not found.
+dnl
+
+AC_DEFUN([GNOME_ORBIT_HOOK],[
+       AC_PATH_PROG(ORBIT_CONFIG,orbit-config,no)
+       AC_PATH_PROG(ORBIT_IDL,orbit-idl,no)
+       AC_CACHE_CHECK([for working ORBit environment],gnome_cv_orbit_found,[
+               if test x$ORBIT_CONFIG = xno -o x$ORBIT_IDL = xno; then
+                       gnome_cv_orbit_found=no
+               else
+                       gnome_cv_orbit_found=yes
+               fi
+       ])
+       AM_CONDITIONAL(HAVE_ORBIT, test x$gnome_cv_orbit_found = xyes)
+       if test x$gnome_cv_orbit_found = xyes; then
+               $1
+               ORBIT_CFLAGS=`orbit-config --cflags client server`
+               ORBIT_LIBS=`orbit-config --use-service=name --libs client server`
+               AC_SUBST(ORBIT_CFLAGS)
+               AC_SUBST(ORBIT_LIBS)
+       else
+               if test x$2 = xfailure; then
+                       AC_MSG_ERROR(ORBit not installed or installation problem)
+               fi
+       fi
+])
+
+AC_DEFUN([GNOME_ORBIT_CHECK], [
+       GNOME_ORBIT_HOOK([],failure)
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-print-check.m4 b/bacula/autoconf/gnome-macros/gnome-print-check.m4
new file mode 100644 (file)
index 0000000..968fcc0
--- /dev/null
@@ -0,0 +1,63 @@
+# Configure paths for GNOME-PRINT
+# Chris Lahey  99-2-5
+# stolen from Manish Singh again
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_GNOME_PRINT([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for GNOME-PRINT, and define GNOME_PRINT_CFLAGS and GNOME_PRINT_LIBS
+dnl
+AC_DEFUN([AM_PATH_GNOME_PRINT],
+[
+  min_version=ifelse([$1],,0.21,$1)
+
+  gnome_print_ok=""
+
+  AC_PATH_PROG(GNOME_CONFIG, gnome-config, no)
+  if test "$GNOME_CONFIG" = "no" ; then
+    AC_MSG_RESULT(gnome-config is missing, check your gnome installation)
+  else
+    AC_MSG_CHECKING(for GNOME-PRINT - version >= $min_version)
+    if `$GNOME_CONFIG --libs print > /dev/null 2>&1`; then
+      rqmajor=`echo "$min_version" | sed -e 's/cvs-//' | sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
+      rqminor=`echo "$min_version" | sed -e 's/cvs-//' | sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
+      major=`$GNOME_CONFIG --modversion print | sed -e 's/gnome-print-//' | sed -e 's/cvs-//' | sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
+      minor=`$GNOME_CONFIG --modversion print | sed -e 's/gnome-print-//' | sed -e 's/cvs-//' | sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
+      if test "$major" -ge "$rqmajor"; then
+        if test "$major" -gt "$rqmajor"; then
+          AC_MSG_RESULT("found $major.$minor")
+          gnome_print_ok="yes"
+        else
+          if test "$minor" -ge "$rqminor"; then
+            AC_MSG_RESULT("found $major.$minor")
+            gnome_print_ok="yes"
+          else
+            AC_MSG_RESULT("you have $major.$minor")
+          fi
+        fi
+      else
+        AC_MSG_RESULT("you have $major.$minor")
+      fi
+    else
+      AC_MSG_RESULT("did not find any version")
+    fi
+  fi
+
+  if test "x$gnome_print_ok" != "x" ; then
+    GNOME_PRINT_CFLAGS=`$GNOME_CONFIG --cflags print`
+    GNOME_PRINT_LIBS=`$GNOME_CONFIG --libs print`
+    ifelse([$2], , :, [$2])
+  else
+     GNOME_PRINT_CFLAGS=""
+     GNOME_PRINT_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+
+  AC_SUBST(GNOME_PRINT_CFLAGS)
+  AC_SUBST(GNOME_PRINT_LIBS)
+])
+
+AC_DEFUN([GNOME_PRINT_CHECK], [
+       AM_PATH_GNOME_PRINT($1,,[AC_MSG_ERROR(GNOME-PRINT not found or wrong version)])
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-pthread-check.m4 b/bacula/autoconf/gnome-macros/gnome-pthread-check.m4
new file mode 100644 (file)
index 0000000..5a1afee
--- /dev/null
@@ -0,0 +1,18 @@
+dnl
+dnl And better, use gthreads instead...
+dnl
+
+AC_DEFUN([GNOME_PTHREAD_CHECK],[
+       PTHREAD_LIB=""
+       AC_CHECK_LIB(pthread, pthread_create, PTHREAD_LIB="-lpthread",
+               [AC_CHECK_LIB(pthreads, pthread_create, PTHREAD_LIB="-lpthreads",
+                   [AC_CHECK_LIB(c_r, pthread_create, PTHREAD_LIB="-lc_r",
+                       [AC_CHECK_LIB(pthread, __pthread_attr_init_system, PTHREAD_LIB="-lpthread",
+                               [AC_CHECK_FUNC(pthread_create)]
+                       )]
+                   )]
+               )]
+       )
+       AC_SUBST(PTHREAD_LIB)
+       AC_PROVIDE([GNOME_PTHREAD_CHECK])
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-support.m4 b/bacula/autoconf/gnome-macros/gnome-support.m4
new file mode 100644 (file)
index 0000000..2c1d049
--- /dev/null
@@ -0,0 +1,68 @@
+dnl GNOME_SUPPORT_CHECKS
+dnl    Check for various support functions needed by the standard
+dnl    Gnome libraries.  Sets LIBOBJS, might define some macros.
+dnl    This should only be used when building the Gnome libs; 
+dnl    Gnome clients should not need this macro.
+AC_DEFUN([GNOME_SUPPORT_CHECKS],[
+  # we need an `awk' to build `gnomesupport.h'
+  AC_REQUIRE([AC_PROG_AWK])
+
+  # this should go away soon
+  need_gnome_support=yes
+
+  save_LIBOBJS="$LIBOBJS"
+  LIBOBJS=
+
+  AC_CHECK_FUNCS(getopt_long,,LIBOBJS="$LIBOBJS getopt.o getopt1.o")
+
+  # for `scandir'
+  AC_HEADER_DIRENT
+
+  # copied from `configure.in' of `libiberty'
+  vars="program_invocation_short_name program_invocation_name sys_errlist"
+  for v in $vars; do
+    AC_MSG_CHECKING([for $v])
+    AC_CACHE_VAL(gnome_cv_var_$v,
+      [AC_TRY_LINK([int *p;], [extern int $v; p = &$v;],
+                  [eval "gnome_cv_var_$v=yes"],
+                  [eval "gnome_cv_var_$v=no"])])
+    if eval "test \"`echo '$gnome_cv_var_'$v`\" = yes"; then
+      AC_MSG_RESULT(yes)
+      n=HAVE_`echo $v | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+      AC_DEFINE_UNQUOTED($n)
+    else
+      AC_MSG_RESULT(no)
+    fi
+  done
+
+  AC_REPLACE_FUNCS(memmove mkstemp scandir strcasecmp strerror strndup strnlen)
+  AC_REPLACE_FUNCS(strtok_r strtod strtol strtoul vasprintf vsnprintf)
+
+  AC_CHECK_FUNCS(realpath,,LIBOBJS="$LIBOBJS canonicalize.o")
+
+  # to include `error.c' error.c has some HAVE_* checks
+  AC_CHECK_FUNCS(vprintf doprnt strerror_r)
+  AM_FUNC_ERROR_AT_LINE
+
+  # This is required if we declare setreuid () and setregid ().
+  AC_TYPE_UID_T
+
+  # see if we need to declare some functions.  Solaris is notorious for
+  # putting functions into the `libc' but not listing them in the headers
+  AC_CHECK_HEADERS(string.h strings.h stdlib.h unistd.h dirent.h)
+  GCC_NEED_DECLARATIONS(gethostname setreuid setregid getpagesize)
+  GCC_NEED_DECLARATION(scandir,[
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+])
+
+  # Turn our LIBOBJS into libtool objects.  This is gross, but it
+  # requires changes to autoconf before it goes away.
+  LTLIBOBJS=`echo "$LIBOBJS" | sed 's/\.o/.lo/g'`
+  AC_SUBST(need_gnome_support)
+  AC_SUBST(LTLIBOBJS)
+
+  LIBOBJS="$save_LIBOBJS"
+  AM_CONDITIONAL(BUILD_GNOME_SUPPORT, test "$need_gnome_support" = yes)
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-undelfs.m4 b/bacula/autoconf/gnome-macros/gnome-undelfs.m4
new file mode 100644 (file)
index 0000000..fe031cd
--- /dev/null
@@ -0,0 +1,22 @@
+dnl GNOME_UNDELFS_CHECKS
+dnl    Check for ext2fs undel support.
+dnl    Set shell variable ext2fs_undel to "yes" if we have it,
+dnl    "no" otherwise.  May define USE_EXT2FSLIB for cpp.
+dnl    Will set EXT2FS_UNDEL_LIBS to required libraries.
+
+AC_DEFUN([GNOME_UNDELFS_CHECKS], [
+  ext2fs_undel=no
+  EXT2FS_UNDEL_LIBS=
+  AC_CHECK_HEADERS(linux/ext2_fs.h)
+  if test x$ac_cv_header_linux_ext2_fs_h = xyes
+  then
+    AC_CHECK_HEADERS(ext2fs/ext2fs.h, , , [#include <stdio.h>
+#include <linux/ext2_fs.h>])
+    if test x$ac_cv_header_ext2fs_ext2fs_h = xyes
+    then
+      AC_DEFINE(USE_EXT2FSLIB)
+      ext2fs_undel=yes
+      EXT2FS_UNDEL_LIBS="-lext2fs -lcom_err"
+    fi
+  fi
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-vfs.m4 b/bacula/autoconf/gnome-macros/gnome-vfs.m4
new file mode 100644 (file)
index 0000000..6dce307
--- /dev/null
@@ -0,0 +1,126 @@
+dnl GNOME_VFS_CHECKS
+dnl   Check for various functions needed by libvfs.
+dnl   This has various effects:
+dnl     Sets GNOME_VFS_LIBS to libraries required
+dnl     Sets termnet  to true or false depending on whether it is required.
+dnl        If yes, defines USE_TERMNET.
+dnl     Sets vfs_flags to "pretty" list of vfs implementations we include.
+dnl     Sets shell variable use_vfs to yes (default, --with-vfs) or
+dnl        "no" (--without-vfs).
+dnl     Calls AC_SUBST(mcserv), which is either empty or "mcserv".
+
+dnl Private define
+AC_DEFUN([GNOME_WITH_VFS],[
+  dnl FIXME: network checks should probably be in their own macro.
+  AC_CHECK_LIB(nsl, t_accept)
+  AC_CHECK_LIB(socket, socket)
+
+  have_socket=no
+  AC_CHECK_FUNCS(socket, have_socket=yes)
+  if test $have_socket = no; then
+    # socket is not in the default libraries.  See if it's in some other.
+    for lib in bsd socket inet; do
+      AC_CHECK_LIB($lib, socket, [
+         LIBS="$LIBS -l$lib"
+         have_socket=yes
+         AC_DEFINE(HAVE_SOCKET)
+         break])
+    done
+  fi
+
+  have_gethostbyname=no
+  AC_CHECK_FUNC(gethostbyname, have_gethostbyname=yes)
+  if test $have_gethostbyname = no; then
+    # gethostbyname is not in the default libraries.  See if it's in some other.
+    for lib in bsd socket inet; do
+      AC_CHECK_LIB($lib, gethostbyname, [LIBS="$LIBS -l$lib"; have_gethostbyname=yes; break])
+    done
+  fi
+
+  vfs_flags="tarfs"
+  use_net_code=false
+  if test $have_socket = yes; then
+      AC_STRUCT_LINGER
+      AC_CHECK_FUNCS(pmap_set, , [
+        AC_CHECK_LIB(rpc, pmap_set, [
+          LIBS="-lrpc $LIBS"
+         AC_DEFINE(HAVE_PMAP_SET)
+         ])])
+      AC_CHECK_FUNCS(pmap_getport pmap_getmaps rresvport)
+      dnl add for source routing support setsockopt
+      AC_CHECK_HEADERS(rpc/pmap_clnt.h, , , [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+                                           ])
+      vfs_flags="$vfs_flags, mcfs, ftpfs, fish"
+      use_net_code=true
+  fi
+
+  dnl
+  dnl Samba support
+  dnl
+  smbfs=""
+  SAMBAFILES=""
+  AC_ARG_WITH(samba,
+         [--with-samba             Support smb virtual file system],[
+         if test "x$withval" != "xno"; then
+                 AC_DEFINE(WITH_SMBFS)
+                 vfs_flags="$vfs_flags, smbfs"
+                 smbfs="smbfs.o"
+                 SAMBAFILES="\$(SAMBAFILES)"
+         fi
+  ])
+  AC_SUBST(smbfs)
+  AC_SUBST(SAMBAFILES)
+  
+  dnl
+  dnl The termnet support
+  dnl
+  termnet=false
+  AC_ARG_WITH(termnet,
+         [--with-termnet             If you want a termified net support],[
+         if test x$withval = xyes; then
+                 AC_DEFINE(USE_TERMNET)
+                 termnet=true          
+         fi
+  ])
+
+  TERMNET=""
+  AC_DEFINE(USE_VFS)
+  if $use_net_code; then
+     AC_DEFINE(USE_NETCODE)
+  fi
+  mcserv=
+  if test $have_socket = yes; then
+     mcserv="mcserv"
+     if $termnet; then
+       TERMNET="-ltermnet"
+     fi
+  fi
+
+  AC_SUBST(TERMNET)
+  AC_SUBST(mcserv)
+
+dnl FIXME:
+dnl GNOME_VFS_LIBS=
+
+])
+
+AC_DEFUN([GNOME_VFS_CHECKS],[
+       use_vfs=yes
+       AC_ARG_WITH(vfs,
+               [--with-vfs                Compile with the VFS code],
+               use_vfs=$withval
+       )
+       case $use_vfs in
+               yes)    GNOME_WITH_VFS;;
+               no)     use_vfs=no;;
+               *)      use_vfs=no;;
+                       dnl Should we issue a warning?
+       esac
+])
+
+
diff --git a/bacula/autoconf/gnome-macros/gnome-x-checks.m4 b/bacula/autoconf/gnome-macros/gnome-x-checks.m4
new file mode 100644 (file)
index 0000000..1e397ef
--- /dev/null
@@ -0,0 +1,80 @@
+dnl GNOME_X_CHECKS
+dnl
+dnl Basic X11 related checks for X11.  At the end, the following will be
+dnl defined/changed:
+dnl   GTK_{CFLAGS,LIBS}      From AM_PATH_GTK
+dnl   CPPFLAGS              Will include $X_CFLAGS
+dnl   GNOME_HAVE_SM         `true' or `false' depending on whether session
+dnl                          management is available.  It is available if
+dnl                          both -lSM and X11/SM/SMlib.h exist.  (Some
+dnl                          Solaris boxes have the library but not the header)
+dnl   XPM_LIBS               -lXpm if Xpm library is present, otherwise ""
+dnl
+dnl The following configure cache variables are defined (but not used):
+dnl   gnome_cv_passdown_{x_libs,X_LIBS,X_CFLAGS}
+dnl
+AC_DEFUN([GNOME_X_CHECKS],
+[
+       AM_PATH_GTK(1.2.0,,AC_MSG_ERROR(GTK not installed, or gtk-config not in path))
+       dnl Hope that GTK_CFLAGS have only -I and -D.  Otherwise, we could
+       dnl   test -z "$x_includes" || CPPFLAGS="$CPPFLAGS -I$x_includes"
+       dnl
+       dnl Use CPPFLAGS instead of CFLAGS because AC_CHECK_HEADERS uses
+       dnl CPPFLAGS, not CFLAGS
+        CPPFLAGS="$CPPFLAGS $GTK_CFLAGS"
+
+        saved_ldflags="$LDFLAGS"
+        LDFLAGS="$LDFLAGS $GTK_LIBS"
+
+       gnome_cv_passdown_x_libs="$GTK_LIBS"
+       gnome_cv_passdown_X_LIBS="$GTK_LIBS"
+       gnome_cv_passdown_X_CFLAGS="$GTK_CFLAGS"
+       gnome_cv_passdown_GTK_LIBS="$GTK_LIBS"
+
+        LDFLAGS="$saved_ldflags $GTK_LIBS"
+
+dnl We are requiring GTK >= 1.1.1, which means this will be fine anyhow.
+       USE_DEVGTK=true
+
+dnl    AC_MSG_CHECKING([whether to use features from (unstable) GTK+ 1.1.x])
+dnl    AC_EGREP_CPP(answer_affirmatively,
+dnl    [#include <gtk/gtkfeatures.h>
+dnl    #ifdef GTK_HAVE_FEATURES_1_1_0
+dnl       answer_affirmatively
+dnl    #endif
+dnl    ], dev_gtk=yes, dev_gtk=no)
+dnl    if test "$dev_gtk" = "yes"; then
+dnl       USE_DEVGTK=true
+dnl    fi
+dnl    AC_MSG_RESULT("$dev_gtk")
+
+       GNOME_HAVE_SM=true
+       case "$GTK_LIBS" in
+        *-lSM*)
+           dnl Already found it.
+           ;;
+        *)
+           dnl Assume that if we have -lSM then we also have -lICE.
+           AC_CHECK_LIB(SM, SmcSaveYourselfDone,
+               [GTK_LIBS="-lSM -lICE $GTK_LIBS"],GNOME_HAVE_SM=false,
+               $x_libs -lICE)
+           ;;
+       esac
+
+       if test "$GNOME_HAVE_SM" = true; then
+          AC_CHECK_HEADERS(X11/SM/SMlib.h,,GNOME_HAVE_SM=false)
+       fi
+
+       if test "$GNOME_HAVE_SM" = true; then
+          AC_DEFINE(HAVE_LIBSM)
+       fi
+
+       XPM_LIBS=""
+       AC_CHECK_LIB(Xpm, XpmFreeXpmImage, [XPM_LIBS="-lXpm"], , $x_libs)
+       AC_SUBST(XPM_LIBS)
+
+       AC_REQUIRE([GNOME_PTHREAD_CHECK])
+        LDFLAGS="$saved_ldflags"
+
+       AC_PROVIDE([GNOME_X_CHECKS])
+])
diff --git a/bacula/autoconf/gnome-macros/gnome-xml-check.m4 b/bacula/autoconf/gnome-macros/gnome-xml-check.m4
new file mode 100644 (file)
index 0000000..1caad10
--- /dev/null
@@ -0,0 +1,32 @@
+dnl
+dnl GNOME_XML_HOOK (script-if-xml-found, failflag)
+dnl
+dnl If failflag is "failure", script aborts due to lack of XML
+dnl 
+dnl Check for availability of the libxml library
+dnl the XML parser uses libz if available too
+dnl
+
+AC_DEFUN([GNOME_XML_HOOK],[
+       AC_PATH_PROG(GNOME_CONFIG,gnome-config,no)
+       if test "$GNOME_CONFIG" = no; then
+               if test x$2 = xfailure; then
+                       AC_MSG_ERROR(Could not find gnome-config)
+               fi
+       fi
+       GNOME_XML_CFLAGS=`$GNOME_CONFIG --cflags xml`
+       AC_SUBST(GNOME_XML_CFLAGS)
+       AC_CHECK_LIB(xml, xmlNewDoc, [
+               $1
+               GNOME_XML_LIB=`$GNOME_CONFIG --libs xml`
+       ], [
+               if test x$2 = xfailure; then 
+                       AC_MSG_ERROR(Could not link sample xml program)
+               fi
+       ], `$GNOME_CONFIG --libs xml`)
+       AC_SUBST(GNOME_XML_LIB)
+])
+
+AC_DEFUN([GNOME_XML_CHECK], [
+       GNOME_XML_HOOK([],failure)
+])
diff --git a/bacula/autoconf/gnome-macros/gnome.m4 b/bacula/autoconf/gnome-macros/gnome.m4
new file mode 100644 (file)
index 0000000..2d23de8
--- /dev/null
@@ -0,0 +1,130 @@
+dnl
+dnl GNOME_INIT_HOOK (script-if-gnome-enabled, [failflag], [additional-inits])
+dnl
+dnl if failflag is "fail" then GNOME_INIT_HOOK will abort if gnomeConf.sh
+dnl is not found. 
+dnl
+
+AC_DEFUN([GNOME_INIT_HOOK],[
+       AC_SUBST(GNOME_LIBS)
+       AC_SUBST(GNOMEUI_LIBS)
+       AC_SUBST(GNOMEGNORBA_LIBS)
+       AC_SUBST(GTKXMHTML_LIBS)
+       AC_SUBST(ZVT_LIBS)
+       AC_SUBST(GNOME_LIBDIR)
+       AC_SUBST(GNOME_INCLUDEDIR)
+
+       AC_ARG_WITH(gnome-includes,
+       [  --with-gnome-includes   Specify location of GNOME headers],[
+       CFLAGS="$CFLAGS -I$withval"
+       ])
+       
+       AC_ARG_WITH(gnome-libs,
+       [  --with-gnome-libs       Specify location of GNOME libs],[
+       LDFLAGS="$LDFLAGS -L$withval"
+       gnome_prefix=$withval
+       ])
+
+       AC_ARG_WITH(gnome,
+       [  --with-gnome            Specify prefix for GNOME files],
+               if test x$withval = xyes; then
+                       want_gnome=yes
+                       dnl Note that an empty true branch is not
+                       dnl valid sh syntax.
+                       ifelse([$1], [], :, [$1])
+               else
+                       if test "x$withval" = xno; then
+                               want_gnome=no
+                       else
+                               want_gnome=yes
+                               LDFLAGS="$LDFLAGS -L$withval/lib"
+                               CFLAGS="$CFLAGS -I$withval/include"
+                               gnome_prefix=$withval/lib
+                       fi
+               fi,
+               want_gnome=yes)
+
+       if test "x$want_gnome" = xyes; then
+
+           AC_PATH_PROG(GNOME_CONFIG,gnome-config,no)
+           if test "$GNOME_CONFIG" = "no"; then
+             no_gnome_config="yes"
+           else
+             AC_MSG_CHECKING(if $GNOME_CONFIG works)
+             if $GNOME_CONFIG --libs-only-l gnome >/dev/null 2>&1; then
+               AC_MSG_RESULT(yes)
+               GNOME_GNORBA_HOOK([],$2)
+               GNOME_LIBS="`$GNOME_CONFIG --libs-only-l gnome`"
+               GNOMEUI_LIBS="`$GNOME_CONFIG --libs-only-l gnomeui`"
+               GNOMEGNORBA_LIBS="`$GNOME_CONFIG --libs-only-l gnorba gnomeui`"
+               GTKXMHTML_LIBS="`$GNOME_CONFIG --libs-only-l gtkxmhtml`"
+               ZVT_LIBS="`$GNOME_CONFIG --libs-only-l zvt`"
+               GNOME_LIBDIR="`$GNOME_CONFIG --libs-only-L gnorba gnomeui`"
+               GNOME_INCLUDEDIR="`$GNOME_CONFIG --cflags gnorba gnomeui`"
+                $1
+             else
+               AC_MSG_RESULT(no)
+               no_gnome_config="yes"
+              fi
+            fi
+
+           if test x$exec_prefix = xNONE; then
+               if test x$prefix = xNONE; then
+                   gnome_prefix=$ac_default_prefix/lib
+               else
+                   gnome_prefix=$prefix/lib
+               fi
+           else
+               gnome_prefix=`eval echo \`echo $libdir\``
+           fi
+       
+           if test "$no_gnome_config" = "yes"; then
+              AC_MSG_CHECKING(for gnomeConf.sh file in $gnome_prefix)
+             if test -f $gnome_prefix/gnomeConf.sh; then
+               AC_MSG_RESULT(found)
+               echo "loading gnome configuration from" \
+                    "$gnome_prefix/gnomeConf.sh"
+               . $gnome_prefix/gnomeConf.sh
+               $1
+             else
+               AC_MSG_RESULT(not found)
+               if test x$2 = xfail; then
+                 AC_MSG_ERROR(Could not find the gnomeConf.sh file that is generated by gnome-libs install)
+               fi
+             fi
+            fi
+       fi
+
+       if test -n "$3"; then
+         n="$3"
+         for i in $n; do
+           AC_MSG_CHECKING(extra library \"$i\")
+           case $i in 
+             applets)
+               AC_SUBST(GNOME_APPLETS_LIBS)
+               GNOME_APPLETS_LIBS=`$GNOME_CONFIG --libs-only-l applets`
+               AC_MSG_RESULT($GNOME_APPLETS_LIBS);;
+             docklets)
+               AC_SUBST(GNOME_DOCKLETS_LIBS)
+               GNOME_DOCKLETS_LIBS=`$GNOME_CONFIG --libs-only-l docklets`
+               AC_MSG_RESULT($GNOME_DOCKLETS_LIBS);;
+             capplet)
+               AC_SUBST(GNOME_CAPPLET_LIBS)
+               GNOME_CAPPLET_LIBS=`$GNOME_CONFIG --libs-only-l capplet`
+               AC_MSG_RESULT($GNOME_CAPPLET_LIBS);;
+             *)
+               AC_MSG_RESULT(unknown library)
+           esac
+            EXTRA_INCLUDEDIR=`$GNOME_CONFIG --cflags $i`
+            GNOME_INCLUDEDIR="$GNOME_INCLUDEDIR $EXTRA_INCLUDEDIR"
+         done
+       fi
+])
+
+dnl
+dnl GNOME_INIT ([additional-inits])
+dnl
+
+AC_DEFUN([GNOME_INIT],[
+       GNOME_INIT_HOOK([],fail,$1)
+])
diff --git a/bacula/autoconf/gnome-macros/gperf-check.m4 b/bacula/autoconf/gnome-macros/gperf-check.m4
new file mode 100644 (file)
index 0000000..3869459
--- /dev/null
@@ -0,0 +1,79 @@
+dnl
+dnl AC_PROG_GPERF (MINIMUM-VERSION)
+dnl
+dnl Check for availability of gperf.
+dnl Abort if not found or if current version is not up to par.
+dnl
+
+AC_DEFUN([AC_PROG_GPERF],[
+       AC_PATH_PROG(GPERF, gperf, no)
+       if test "$GPERF" = no; then
+               AC_MSG_ERROR(Could not find gperf)
+       fi
+       min_gperf_version=ifelse([$1], ,2.7,$1)
+       AC_MSG_CHECKING(for gperf - version >= $min_gperf_version)
+       gperf_major_version=`$GPERF --version | \
+               sed 's/GNU gperf \([[0-9]]*\).\([[0-9]]*\)/\1/'`
+       gperf_minor_version=`$GPERF --version | \
+               sed 's/GNU gperf \([[0-9]]*\).\([[0-9]]*\)/\2/'`
+       no_gperf=""
+dnl
+dnl Now check if the installed gperf is sufficiently new.
+dnl
+       AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char*
+my_strdup (char *str)
+{
+  char *new_str;
+  
+  if (str)
+    {
+      new_str = malloc ((strlen (str) + 1) * sizeof(char));
+      strcpy (new_str, str);
+    }
+  else
+    new_str = NULL;
+  
+  return new_str;
+}
+
+int 
+main ()
+{
+  char  *tmp_version;
+  
+  int    major;
+  int    minor;
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = my_strdup("$min_gperf_version");
+  if (sscanf(tmp_version, "%d.%d", &major, &minor) != 2) {
+    printf ("%s, bad version string\n", "$min_gperf_version");
+    return 1;
+  }
+
+  if (($gperf_major_version > major) ||
+      (($gperf_major_version == major) && ($gperf_minor_version >= minor))) {
+    return 0;
+  } else {
+    printf ("\n");
+    printf ("*** An old version of gperf ($gperf_major_version.$gperf_minor_version) was found.\n");
+    printf ("*** You need a version of gperf newer than %d.%d.%d.  The latest version of\n",
+              major, minor);
+    printf ("*** gperf is always available from ftp://ftp.gnu.org.\n");
+    printf ("***\n");
+    return 1;
+  }
+}
+],,no_gperf=yes,[/bin/true])
+       if test "x$no_gperf" = x ; then
+               AC_MSG_RESULT(yes)
+       else
+               AC_MSG_RESULT(no)
+       fi
+
+])
diff --git a/bacula/autoconf/gnome-macros/linger.m4 b/bacula/autoconf/gnome-macros/linger.m4
new file mode 100644 (file)
index 0000000..f1c7060
--- /dev/null
@@ -0,0 +1,28 @@
+dnl
+dnl Check for struct linger
+dnl
+AC_DEFUN([AC_STRUCT_LINGER], [
+av_struct_linger=no
+AC_MSG_CHECKING(struct linger is available)
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/socket.h>
+
+struct linger li;
+
+int main ()
+{
+    li.l_onoff = 1;
+    li.l_linger = 120;
+    return 0;
+}
+],[
+AC_DEFINE(HAVE_STRUCT_LINGER)
+av_struct_linger=yes
+],[
+av_struct_linger=no
+],[
+av_struct_linger=no
+])
+AC_MSG_RESULT($av_struct_linger)
+])
diff --git a/bacula/autoconf/gnome-macros/need-declaration.m4 b/bacula/autoconf/gnome-macros/need-declaration.m4
new file mode 100644 (file)
index 0000000..8a217b8
--- /dev/null
@@ -0,0 +1,42 @@
+dnl See whether we need a declaration for a function.
+dnl GCC_NEED_DECLARATION(FUNCTION [, EXTRA-HEADER-FILES])
+AC_DEFUN([GCC_NEED_DECLARATION],
+[AC_MSG_CHECKING([whether $1 must be declared])
+AC_CACHE_VAL(gcc_cv_decl_needed_$1,
+[AC_TRY_COMPILE([
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+$2],
+[char *(*pfn) = (char *(*)) $1],
+eval "gcc_cv_decl_needed_$1=no", eval "gcc_cv_decl_needed_$1=yes")])
+if eval "test \"`echo '$gcc_cv_decl_needed_'$1`\" = yes"; then
+  AC_MSG_RESULT(yes)
+  gcc_need_declarations="$gcc_need_declarations $1"
+  gcc_tr_decl=NEED_DECLARATION_`echo $1 | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  AC_DEFINE_UNQUOTED($gcc_tr_decl)
+else
+  AC_MSG_RESULT(no)
+fi
+])dnl
+
+dnl Check multiple functions to see whether each needs a declaration.
+dnl GCC_NEED_DECLARATIONS(FUNCTION... [, EXTRA-HEADER-FILES])
+AC_DEFUN([GCC_NEED_DECLARATIONS],
+[for ac_func in $1
+do
+GCC_NEED_DECLARATION($ac_func, $2)
+done
+]
+)
diff --git a/bacula/autoconf/install-sh b/bacula/autoconf/install-sh
new file mode 100755 (executable)
index 0000000..89fc9b0
--- /dev/null
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/bacula/autoconf/install.sh b/bacula/autoconf/install.sh
new file mode 100755 (executable)
index 0000000..ea88212
--- /dev/null
@@ -0,0 +1,235 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/bacula/autoconf/mkinstalldirs b/bacula/autoconf/mkinstalldirs
new file mode 100755 (executable)
index 0000000..91f6d04
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Last modified: 1994-03-25
+# Public domain
+
+errstatus=0
+
+for file in ${1+"$@"} ; do 
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d in ${1+"$@"} ; do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp" 1>&2
+        mkdir "$pathcomp" || errstatus=$?
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/bacula/configure b/bacula/configure
new file mode 100755 (executable)
index 0000000..2707774
--- /dev/null
@@ -0,0 +1,9480 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --enable-everything     enable standard non-multichoice features: marked *"
+ac_help="$ac_help
+  --enable-gnome       enable build of gnome-console GUI                     *"
+ac_help="$ac_help
+  --with-gnome-includes   Specify location of GNOME headers"
+ac_help="$ac_help
+  --with-gnome-libs       Specify location of GNOME libs"
+ac_help="$ac_help
+  --with-gnome            Specify prefix for GNOME files"
+ac_help="$ac_help
+  --enable-smartalloc     enable smartalloc debugging support             *"
+ac_help="$ac_help
+  --disable-readline      disable readline support "
+ac_help="$ac_help
+       --with-readline[=DIR]   Specify readline library directory"
+ac_help="$ac_help
+  --with-gmp[=DIR]     Specify gmp library directory"
+ac_help="$ac_help
+  --with-cweb[=DIR]     Specify cweb library directory"
+ac_help="$ac_help
+  --with-tcp-wrappers=DIR Enable tcpwrappers support"
+ac_help="$ac_help
+  --with-working-dir=PATH Specify location of Bacula working files"
+ac_help="$ac_help
+  --with-dump-email=Dump email address"
+ac_help="$ac_help
+  --with-job-email=Job output email address"
+ac_help="$ac_help
+  --with-smtp-host=SMTP mail host address"
+ac_help="$ac_help
+  --with-pid-dir=PATH    Specify location of Bacula pid files"
+ac_help="$ac_help
+  --with-subsys-dir=PATH        Specify location of Bacula subsys file"
+ac_help="$ac_help
+  --with-baseport=PORT    Specify base port address for daemons"
+ac_help="$ac_help
+  --with-dir-password=PASSWORD Specify Director's password"
+ac_help="$ac_help
+  --with-fd-password=PASSWORD Specify Client's password"
+ac_help="$ac_help
+  --with-sd-password=PASSWORD Specify Storage daemon's password"
+ac_help="$ac_help
+
+Which one DBMS do you want to use (please select only one):
+  --with-mysql[=DIR]      Include MySQL support.  DIR is the MySQL base
+                          install directory, default is to search through
+                          a number of common places for the MySQL files."
+ac_help="$ac_help
+
+Which one DBMS do you want to use (please select only one):
+  --with-sqlite[=DIR]     Include SQLite support.  DIR is the SQLite base
+                          install directory, default is to search through
+                          a number of common places for the SQLite files."
+ac_help="$ac_help
+  --with-x                use the X Window System"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=src/version.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+BUILD_DIR=`pwd`
+cd ..
+TOP_DIR=`pwd`
+cd ${BUILD_DIR}
+
+ac_aux_dir=
+for ac_dir in ${BUILD_DIR}/autoconf $srcdir/${BUILD_DIR}/autoconf; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in ${BUILD_DIR}/autoconf $srcdir/${BUILD_DIR}/autoconf" 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+
+
+
+
+for ac_prog in true
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:615: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_TRUEPRG'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$TRUEPRG" in
+  /*)
+  ac_cv_path_TRUEPRG="$TRUEPRG" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_TRUEPRG="$TRUEPRG" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_TRUEPRG="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+TRUEPRG="$ac_cv_path_TRUEPRG"
+if test -n "$TRUEPRG"; then
+  echo "$ac_t""$TRUEPRG" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$TRUEPRG" && break
+done
+test -n "$TRUEPRG" || TRUEPRG=":"
+
+for ac_prog in false
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:656: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_FALSEPRG'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$FALSEPRG" in
+  /*)
+  ac_cv_path_FALSEPRG="$FALSEPRG" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_FALSEPRG="$FALSEPRG" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_FALSEPRG="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+FALSEPRG="$ac_cv_path_FALSEPRG"
+if test -n "$FALSEPRG"; then
+  echo "$ac_t""$FALSEPRG" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$FALSEPRG" && break
+done
+test -n "$FALSEPRG" || FALSEPRG=":"
+
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:700: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+  case $nonopt in
+  NONE)
+    if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+    else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+    fi ;;
+  *) host_alias=$nonopt ;;
+  esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+
+VERSION=`sed -n -e 's/^.*VERSION.*"\(.*\)"$/\1/p' ${srcdir}/src/version.h`
+DATE=`sed -n -e 's/^.* \t*DATE.*"\(.*\)"$/\1/p' ${srcdir}/src/version.h`
+LSMDATE=`sed -n -e 's/^.*LSMDATE.*"\(.*\)"$/\1/p' ${srcdir}/src/version.h`
+echo "configuring for bacula $VERSION ($DATE)"
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:731: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:761: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+       continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:812: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:844: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 855 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:860: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:886: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:891: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:900: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:919: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:955: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CXX="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+  echo "$ac_t""$CXX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:987: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 998 "configure"
+#include "confdefs.h"
+
+int main(){return(0);}
+EOF
+if { (eval echo configure:1003: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cxx_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cxx_cross=no
+  else
+    ac_cv_prog_cxx_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+  { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1029: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:1034: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.C <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1043: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gxx=yes
+else
+  ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+
+ac_test_CXXFLAGS="${CXXFLAGS+set}"
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS=
+echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:1062: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+  ac_cv_prog_cxx_g=yes
+else
+  ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS="$ac_save_CXXFLAGS"
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+
+if test "x$CC" != xcc; then
+  echo $ac_n "checking whether $CC and cc understand -c and -o together""... $ac_c" 1>&6
+echo "configure:1095: checking whether $CC and cc understand -c and -o together" >&5
+else
+  echo $ac_n "checking whether cc understands -c and -o together""... $ac_c" 1>&6
+echo "configure:1098: checking whether cc understands -c and -o together" >&5
+fi
+set dummy $CC; ac_cc="`echo $2 |
+                      sed -e 's/[^a-zA-Z0-9_]/_/g' -e 's/^[0-9]/_/'`"
+if eval "test \"`echo '$''{'ac_cv_prog_cc_${ac_cc}_c_o'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'foo(){}' > conftest.c
+# Make sure it works both with $CC and with simple cc.
+# We do the test twice because some compilers refuse to overwrite an
+# existing .o file with -o, though they will create one.
+ac_try='${CC-cc} -c conftest.c -o conftest.o 1>&5'
+if { (eval echo configure:1110: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } &&
+   test -f conftest.o && { (eval echo configure:1111: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; };
+then
+  eval ac_cv_prog_cc_${ac_cc}_c_o=yes
+  if test "x$CC" != xcc; then
+    # Test first that cc exists at all.
+    if { ac_try='cc -c conftest.c 1>&5'; { (eval echo configure:1116: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
+      ac_try='cc -c conftest.c -o conftest.o 1>&5'
+      if { (eval echo configure:1118: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } &&
+        test -f conftest.o && { (eval echo configure:1119: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; };
+      then
+        # cc works too.
+        :
+      else
+        # cc exists but doesn't like -o.
+        eval ac_cv_prog_cc_${ac_cc}_c_o=no
+      fi
+    fi
+  fi
+else
+  eval ac_cv_prog_cc_${ac_cc}_c_o=no
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+  cat >> confdefs.h <<\EOF
+#define NO_MINUS_C_MINUS_O 1
+EOF
+
+fi
+                       echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1145: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1160 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1166: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1177 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1183: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1194 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1200: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:1226: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 1232 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 1250 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+       
+if test x$CC = xgcc
+then
+   cat >> confdefs.h <<\EOF
+#define HAVE_GCC 1
+EOF
+
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1291: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS=        }"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+         if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         else
+           ac_cv_path_install="$ac_dir/$ac_prog -c"
+           break 2
+         fi
+       fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1346: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "mv", so it can be a program name with args.
+set dummy mv; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1376: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_MV'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$MV" in
+  /*)
+  ac_cv_path_MV="$MV" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_MV="$MV" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_MV="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_MV" && ac_cv_path_MV="mv"
+  ;;
+esac
+fi
+MV="$ac_cv_path_MV"
+if test -n "$MV"; then
+  echo "$ac_t""$MV" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "rm", so it can be a program name with args.
+set dummy rm; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1412: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_RM'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$RM" in
+  /*)
+  ac_cv_path_RM="$RM" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_RM="$RM" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_RM="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_RM" && ac_cv_path_RM="rm"
+  ;;
+esac
+fi
+RM="$ac_cv_path_RM"
+if test -n "$RM"; then
+  echo "$ac_t""$RM" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "cp", so it can be a program name with args.
+set dummy cp; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1448: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_CP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$CP" in
+  /*)
+  ac_cv_path_CP="$CP" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_CP="$CP" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_CP="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_CP" && ac_cv_path_CP="cp"
+  ;;
+esac
+fi
+CP="$ac_cv_path_CP"
+if test -n "$CP"; then
+  echo "$ac_t""$CP" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "sed", so it can be a program name with args.
+set dummy sed; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1484: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_SED'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$SED" in
+  /*)
+  ac_cv_path_SED="$SED" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_SED="$SED" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_SED="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_SED" && ac_cv_path_SED="sed"
+  ;;
+esac
+fi
+SED="$ac_cv_path_SED"
+if test -n "$SED"; then
+  echo "$ac_t""$SED" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "awk", so it can be a program name with args.
+set dummy awk; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1520: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_AWK'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$AWK" in
+  /*)
+  ac_cv_path_AWK="$AWK" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_AWK="$AWK" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_AWK="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_AWK" && ac_cv_path_AWK="awk"
+  ;;
+esac
+fi
+AWK="$ac_cv_path_AWK"
+if test -n "$AWK"; then
+  echo "$ac_t""$AWK" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "echo", so it can be a program name with args.
+set dummy echo; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1556: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ECHO'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$ECHO" in
+  /*)
+  ac_cv_path_ECHO="$ECHO" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_ECHO="$ECHO" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_ECHO="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_ECHO" && ac_cv_path_ECHO="echo"
+  ;;
+esac
+fi
+ECHO="$ac_cv_path_ECHO"
+if test -n "$ECHO"; then
+  echo "$ac_t""$ECHO" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "cmp", so it can be a program name with args.
+set dummy cmp; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1592: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_CMP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$CMP" in
+  /*)
+  ac_cv_path_CMP="$CMP" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_CMP="$CMP" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_CMP="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_CMP" && ac_cv_path_CMP="cmp"
+  ;;
+esac
+fi
+CMP="$ac_cv_path_CMP"
+if test -n "$CMP"; then
+  echo "$ac_t""$CMP" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "tbl", so it can be a program name with args.
+set dummy tbl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1628: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_TBL'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$TBL" in
+  /*)
+  ac_cv_path_TBL="$TBL" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_TBL="$TBL" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_TBL="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_TBL" && ac_cv_path_TBL="tbl"
+  ;;
+esac
+fi
+TBL="$ac_cv_path_TBL"
+if test -n "$TBL"; then
+  echo "$ac_t""$TBL" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1664: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_AR'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$AR" in
+  /*)
+  ac_cv_path_AR="$AR" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_AR="$AR" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_AR="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_AR" && ac_cv_path_AR="ar"
+  ;;
+esac
+fi
+AR="$ac_cv_path_AR"
+if test -n "$AR"; then
+  echo "$ac_t""$AR" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1700: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$RANLIB" in
+  /*)
+  ac_cv_path_RANLIB="$RANLIB" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_RANLIB="$RANLIB" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_RANLIB="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_RANLIB" && ac_cv_path_RANLIB="ranlib"
+  ;;
+esac
+fi
+RANLIB="$ac_cv_path_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "openssl", so it can be a program name with args.
+set dummy openssl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1736: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_OPENSSL'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$OPENSSL" in
+  /*)
+  ac_cv_path_OPENSSL="$OPENSSL" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_OPENSSL="$OPENSSL" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_OPENSSL="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_OPENSSL" && ac_cv_path_OPENSSL="none"
+  ;;
+esac
+fi
+OPENSSL="$ac_cv_path_OPENSSL"
+if test -n "$OPENSSL"; then
+  echo "$ac_t""$OPENSSL" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+test -n "$ARFLAG" || ARFLAGS="cr"
+
+
+MAKE_SHELL=/bin/sh
+
+
+
+
+
+
+
+
+
+echo $ac_n "checking for Operating System""... $ac_c" 1>&6
+echo "configure:1784: checking for Operating System" >&5
+echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6
+echo "configure:1786: checking for Cygwin environment" >&5
+if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1791 "configure"
+#include "confdefs.h"
+
+int main() {
+
+#ifndef __CYGWIN__
+#define __CYGWIN__ __CYGWIN32__
+#endif
+return __CYGWIN__;
+; return 0; }
+EOF
+if { (eval echo configure:1802: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_cygwin=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_cygwin=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_cygwin" 1>&6
+CYGWIN=
+test "$ac_cv_cygwin" = yes && CYGWIN=yes
+if test $HAVE_UNAME=yes -a x`uname -s` = xSunOS
+then
+        
+
+if $TRUEPRG; then
+  HAVE_SUN_OS_TRUE=
+  HAVE_SUN_OS_FALSE='#'
+else
+  HAVE_SUN_OS_TRUE='#'
+  HAVE_SUN_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_SUN_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_SUN_OS_TRUE=
+  HAVE_SUN_OS_FALSE='#'
+else
+  HAVE_SUN_OS_TRUE='#'
+  HAVE_SUN_OS_FALSE=
+fi
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xOSF1
+then
+        
+
+if $TRUEPRG; then
+  HAVE_OSF1_OS_TRUE=
+  HAVE_OSF1_OS_FALSE='#'
+else
+  HAVE_OSF1_OS_TRUE='#'
+  HAVE_OSF1_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_OSF1_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_OSF1_OS_TRUE=
+  HAVE_OSF1_OS_FALSE='#'
+else
+  HAVE_OSF1_OS_TRUE='#'
+  HAVE_OSF1_OS_FALSE=
+fi
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xAIX
+then
+        
+
+if $TRUEPRG; then
+  HAVE_AIX_OS_TRUE=
+  HAVE_AIX_OS_FALSE='#'
+else
+  HAVE_AIX_OS_TRUE='#'
+  HAVE_AIX_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_AIX_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_AIX_OS_TRUE=
+  HAVE_AIX_OS_FALSE='#'
+else
+  HAVE_AIX_OS_TRUE='#'
+  HAVE_AIX_OS_FALSE=
+fi
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xHP-UX
+then
+        
+
+if $TRUEPRG; then
+  HAVE_HPUX_OS_TRUE=
+  HAVE_HPUX_OS_FALSE='#'
+else
+  HAVE_HPUX_OS_TRUE='#'
+  HAVE_HPUX_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_HPUX_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_HPUX_OS_TRUE=
+  HAVE_HPUX_OS_FALSE='#'
+else
+  HAVE_HPUX_OS_TRUE='#'
+  HAVE_HPUX_OS_FALSE=
+fi
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xLinux
+then
+        
+
+if $TRUEPRG; then
+  HAVE_LINUX_OS_TRUE=
+  HAVE_LINUX_OS_FALSE='#'
+else
+  HAVE_LINUX_OS_TRUE='#'
+  HAVE_LINUX_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_LINUX_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_LINUX_OS_TRUE=
+  HAVE_LINUX_OS_FALSE='#'
+else
+  HAVE_LINUX_OS_TRUE='#'
+  HAVE_LINUX_OS_FALSE=
+fi
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xFreeBSD
+then
+        
+
+if $TRUEPRG; then
+  HAVE_FREEBSD_OS_TRUE=
+  HAVE_FREEBSD_OS_FALSE='#'
+else
+  HAVE_FREEBSD_OS_TRUE='#'
+  HAVE_FREEBSD_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_FREEBSD_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_FREEBSD_OS_TRUE=
+  HAVE_FREEBSD_OS_FALSE='#'
+else
+  HAVE_FREEBSD_OS_TRUE='#'
+  HAVE_FREEBSD_OS_FALSE=
+fi
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xNetBSD
+then
+        
+
+if $TRUEPRG; then
+  HAVE_NETBSD_OS_TRUE=
+  HAVE_NETBSD_OS_FALSE='#'
+else
+  HAVE_NETBSD_OS_TRUE='#'
+  HAVE_NETBSD_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_NETBSD_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_NETBSD_OS_TRUE=
+  HAVE_NETBSD_OS_FALSE='#'
+else
+  HAVE_NETBSD_OS_TRUE='#'
+  HAVE_NETBSD_OS_FALSE=
+fi
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xOpenBSD
+then
+        
+
+if $TRUEPRG; then
+  HAVE_OPENBSD_OS_TRUE=
+  HAVE_OPENBSD_OS_FALSE='#'
+else
+  HAVE_OPENBSD_OS_TRUE='#'
+  HAVE_OPENBSD_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_OPENBSD_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_OPENBSD_OS_TRUE=
+  HAVE_OPENBSD_OS_FALSE='#'
+else
+  HAVE_OPENBSD_OS_TRUE='#'
+  HAVE_OPENBSD_OS_FALSE=
+fi
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xBSD/OS
+then
+        
+
+if $TRUEPRG; then
+  HAVE_BSDI_OS_TRUE=
+  HAVE_BSDI_OS_FALSE='#'
+else
+  HAVE_BSDI_OS_TRUE='#'
+  HAVE_BSDI_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_BSDI_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_BSDI_OS_TRUE=
+  HAVE_BSDI_OS_FALSE='#'
+else
+  HAVE_BSDI_OS_TRUE='#'
+  HAVE_BSDI_OS_FALSE=
+fi
+fi
+
+if test $HAVE_UNAME=yes -a x`uname -s` = xSGI
+then
+        
+
+if $TRUEPRG; then
+  HAVE_SGI_OS_TRUE=
+  HAVE_SGI_OS_FALSE='#'
+else
+  HAVE_SGI_OS_TRUE='#'
+  HAVE_SGI_OS_FALSE=
+fi
+        cat >> confdefs.h <<\EOF
+#define HAVE_SGI_OS 1
+EOF
+
+else
+        
+
+if $FALSEPRG; then
+  HAVE_SGI_OS_TRUE=
+  HAVE_SGI_OS_FALSE='#'
+else
+  HAVE_SGI_OS_TRUE='#'
+  HAVE_SGI_OS_FALSE=
+fi
+fi
+echo "$ac_t""" "" 1>&6
+
+
+# -----------------------------------------------------------
+# ----------------------------------------------------------
+echo $ac_n "checking for Operating System Distribution""... $ac_c" 1>&6
+echo "configure:2093: checking for Operating System Distribution" >&5
+if test "x$DISTNAME" != "x"
+then
+        echo "distname set to $DISTNAME"
+elif test $HAVE_UNAME=yes -a x`uname -s` = xOSF1
+then
+        DISTNAME=alpha
+elif test $HAVE_UNAME=yes -a x`uname -s` = xHP-UX
+then
+        DISTNAME=hpux
+elif test $HAVE_UNAME=yes -a x`uname -s` = xSunOS
+then
+        DISTNAME=solaris
+elif test $HAVE_UNAME=yes -a x`uname -s` = xFreeBSD
+then
+        DISTNAME=freebsd
+elif test $HAVE_UNAME=yes -a x`uname -s` = xNetBSD
+then
+        DISTNAME=netbsd
+elif test $HAVE_UNAME=yes -a x`uname -s` = xOpenBSD
+then
+        DISTNAME=openbsd
+elif test $HAVE_UNAME=yes -a x`uname -s` = xBSD/OS
+then
+        DISTNAME=bsdi
+elif test -f /etc/SuSE-release
+then
+        DISTNAME=suse
+elif test -d /etc/SuSEconfig
+then
+        DISTNAME=suse5
+elif test -d /usr/src/OpenLinux
+then
+        DISTNAME=caldera
+elif test -f /etc/redhat-release
+then
+        DISTNAME=redhat
+elif test -f /etc/debian_version
+then
+        DISTNAME=debian
+elif test -f /etc/slackware-version
+then
+        DISTNAME=slackware
+elif test "$ac_cv_cygwin" = yes
+then
+        DISTNAME=cygwin
+        cat >> confdefs.h <<\EOF
+#define HAVE_CYGWIN 1
+EOF
+
+else
+        DISTNAME=unknown
+fi
+echo "$ac_t""" "" 1>&6
+
+
+# -----------------------------------------------------------
+# ----------------------------------------------------------
+
+        
+
+if false; then
+  INSIDE_GNOME_COMMON_TRUE=
+  INSIDE_GNOME_COMMON_FALSE='#'
+else
+  INSIDE_GNOME_COMMON_TRUE='#'
+  INSIDE_GNOME_COMMON_FALSE=
+fi
+
+        test -n "$ACLOCAL_FLAGS" && ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS"
+
+        for k in gnome-macros ; do ACLOCAL="$ACLOCAL -I $k" ; done
+
+
+# ------------------------------------------------------------------
+#  If the user has not set --prefix, we set our default to nothing.
+#  In this case, if the user has not set --sysconfdir, we set it
+#  to the package default of /etc/bacula.  If either --prefix or
+#  --sysconfdir is set, we leave sysconfdir alone except to eval it.
+# ------------------------------------------------------------------
+if test x${prefix} = xNONE ; then
+    if test `eval echo ${sysconfdir}` = NONE/etc ; then
+       sysconfdir=/etc/bacula
+    fi
+    prefix=
+fi
+sysconfdir=`eval echo ${sysconfdir}`
+
+# -------------------------------------------------------------------------
+#  If the user has not set --exec-prefix, we default to ${prefix}
+# -------------------------------------------------------------------------
+if test x${exec_prefix} = xNONE ; then
+    exec_prefix=${prefix}
+fi
+
+# ------------------------------------------------------------------
+# If the user has not set --sbindir, we set our default as /sbin
+# ------------------------------------------------------------------
+if test x$sbindir = x'${exec_prefix}/sbin' ; then
+    sbindir=${exec_prefix}/sbin
+fi
+sbindir=`eval echo ${sbindir}`
+                     
+# ------------------------------------------------------------------
+# All list of languages for which a translation exist. Each
+#  language is separated by a space.
+# ------------------------------------------------------------------
+ALL_LINGUAS=""
+
+for ac_prog in msgfmt
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:2207: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$MSGFMT" in
+  /*)
+  ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_MSGFMT="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+MSGFMT="$ac_cv_path_MSGFMT"
+if test -n "$MSGFMT"; then
+  echo "$ac_t""$MSGFMT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$MSGFMT" && break
+done
+test -n "$MSGFMT" || MSGFMT="no"
+
+if test "$MSGFMT" = "no"
+then
+   echo 'msgfmt program not found, disabling NLS !'
+   USE_NLS=no
+   USE_INCLUDED_LIBINTL=no
+#else
+#   AM_GNU_GETTEXT
+fi
+
+
+support_mysql=no
+support_sqlite=no
+support_smartalloc=yes
+cats=
+
+# Check whether --enable-everything or --disable-everything was given.
+if test "${enable_everything+set}" = set; then
+  enableval="$enable_everything"
+  if test x$enableval = xyes; then
+    support_smartalloc=yes
+  fi
+fi
+
+
+# -------------------------------------------
+# gnome (default off)
+# -------------------------------------------
+support_gnome=no
+# Check whether --enable-gnome or --disable-gnome was given.
+if test "${enable_gnome+set}" = set; then
+  enableval="$enable_gnome"
+  if test x$enableval = xyes; then
+    support_gnome=yes
+  fi
+fi
+
+
+GNOME_DIR=
+if test x$support_gnome = xyes; then
+    
+        
+        
+        
+        
+        
+        
+        
+        
+
+        # Check whether --with-gnome-includes or --without-gnome-includes was given.
+if test "${with_gnome_includes+set}" = set; then
+  withval="$with_gnome_includes"
+  
+        CFLAGS="$CFLAGS -I$withval"
+        
+fi
+
+        
+        # Check whether --with-gnome-libs or --without-gnome-libs was given.
+if test "${with_gnome_libs+set}" = set; then
+  withval="$with_gnome_libs"
+  
+        LDFLAGS="$LDFLAGS -L$withval"
+        gnome_prefix=$withval
+        
+fi
+
+
+        # Check whether --with-gnome or --without-gnome was given.
+if test "${with_gnome+set}" = set; then
+  withval="$with_gnome"
+  if test x$withval = xyes; then
+                        want_gnome=yes
+                                                                        :
+                else
+                        if test "x$withval" = xno; then
+                                want_gnome=no
+                        else
+                                want_gnome=yes
+                                LDFLAGS="$LDFLAGS -L$withval/lib"
+                                CFLAGS="$CFLAGS -I$withval/include"
+                                gnome_prefix=$withval/lib
+                        fi
+                fi
+else
+  want_gnome=yes
+fi
+
+
+        if test "x$want_gnome" = xyes; then
+
+            # Extract the first word of "gnome-config", so it can be a program name with args.
+set dummy gnome-config; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:2337: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_GNOME_CONFIG'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$GNOME_CONFIG" in
+  /*)
+  ac_cv_path_GNOME_CONFIG="$GNOME_CONFIG" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_GNOME_CONFIG="$GNOME_CONFIG" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_GNOME_CONFIG="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_GNOME_CONFIG" && ac_cv_path_GNOME_CONFIG="no"
+  ;;
+esac
+fi
+GNOME_CONFIG="$ac_cv_path_GNOME_CONFIG"
+if test -n "$GNOME_CONFIG"; then
+  echo "$ac_t""$GNOME_CONFIG" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+            if test "$GNOME_CONFIG" = "no"; then
+              no_gnome_config="yes"
+            else
+              echo $ac_n "checking if $GNOME_CONFIG works""... $ac_c" 1>&6
+echo "configure:2374: checking if $GNOME_CONFIG works" >&5
+              if $GNOME_CONFIG --libs-only-l gnome >/dev/null 2>&1; then
+                echo "$ac_t""yes" 1>&6
+                
+        
+        # Extract the first word of "orbit-config", so it can be a program name with args.
+set dummy orbit-config; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:2382: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ORBIT_CONFIG'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$ORBIT_CONFIG" in
+  /*)
+  ac_cv_path_ORBIT_CONFIG="$ORBIT_CONFIG" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_ORBIT_CONFIG="$ORBIT_CONFIG" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_ORBIT_CONFIG="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_ORBIT_CONFIG" && ac_cv_path_ORBIT_CONFIG="no"
+  ;;
+esac
+fi
+ORBIT_CONFIG="$ac_cv_path_ORBIT_CONFIG"
+if test -n "$ORBIT_CONFIG"; then
+  echo "$ac_t""$ORBIT_CONFIG" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+        # Extract the first word of "orbit-idl", so it can be a program name with args.
+set dummy orbit-idl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:2418: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ORBIT_IDL'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$ORBIT_IDL" in
+  /*)
+  ac_cv_path_ORBIT_IDL="$ORBIT_IDL" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_ORBIT_IDL="$ORBIT_IDL" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_ORBIT_IDL="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_ORBIT_IDL" && ac_cv_path_ORBIT_IDL="no"
+  ;;
+esac
+fi
+ORBIT_IDL="$ac_cv_path_ORBIT_IDL"
+if test -n "$ORBIT_IDL"; then
+  echo "$ac_t""$ORBIT_IDL" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+        echo $ac_n "checking for working ORBit environment""... $ac_c" 1>&6
+echo "configure:2452: checking for working ORBit environment" >&5
+if eval "test \"`echo '$''{'gnome_cv_orbit_found'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+                if test x$ORBIT_CONFIG = xno -o x$ORBIT_IDL = xno; then
+                        gnome_cv_orbit_found=no
+                else
+                        gnome_cv_orbit_found=yes
+                fi
+        
+fi
+
+echo "$ac_t""$gnome_cv_orbit_found" 1>&6
+        
+
+if test x$gnome_cv_orbit_found = xyes; then
+  HAVE_ORBIT_TRUE=
+  HAVE_ORBIT_FALSE='#'
+else
+  HAVE_ORBIT_TRUE='#'
+  HAVE_ORBIT_FALSE=
+fi
+        if test x$gnome_cv_orbit_found = xyes; then
+                
+                ORBIT_CFLAGS=`orbit-config --cflags client server`
+                ORBIT_LIBS=`orbit-config --use-service=name --libs client server`
+                
+                
+        else
+                if test xfail = xfailure; then
+                        { echo "configure: error: ORBit not installed or installation problem" 1>&2; exit 1; }
+                fi
+        fi
+
+        echo $ac_n "checking for gnorba libraries""... $ac_c" 1>&6
+echo "configure:2488: checking for gnorba libraries" >&5
+if eval "test \"`echo '$''{'gnome_cv_gnorba_found'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+                gnome_cv_gnorba_found=no
+                if test x$gnome_cv_orbit_found = xyes; then
+                        GNORBA_CFLAGS="`gnome-config --cflags gnorba gnomeui`"
+                        GNORBA_LIBS="`gnome-config --libs gnorba gnomeui`"
+                        if test -n "$GNORBA_LIBS"; then
+                                gnome_cv_gnorba_found=yes
+                        fi
+                fi
+        
+fi
+
+echo "$ac_t""$gnome_cv_gnorba_found" 1>&6
+        
+
+if test x$gnome_cv_gnorba_found = xyes; then
+  HAVE_GNORBA_TRUE=
+  HAVE_GNORBA_FALSE='#'
+else
+  HAVE_GNORBA_TRUE='#'
+  HAVE_GNORBA_FALSE=
+fi
+        if test x$gnome_cv_orbit_found = xyes; then
+                
+                GNORBA_CFLAGS="`gnome-config --cflags gnorba gnomeui`"
+                GNORBA_LIBS="`gnome-config --libs gnorba gnomeui`"
+                
+                
+        else
+                if test xfail = xfailure; then
+                        { echo "configure: error: gnorba library not installed or installation problem" 1>&2; exit 1; }
+                fi
+        fi
+
+                GNOME_LIBS="`$GNOME_CONFIG --libs-only-l gnome`"
+                GNOMEUI_LIBS="`$GNOME_CONFIG --libs-only-l gnomeui`"
+                GNOMEGNORBA_LIBS="`$GNOME_CONFIG --libs-only-l gnorba gnomeui`"
+                GTKXMHTML_LIBS="`$GNOME_CONFIG --libs-only-l gtkxmhtml`"
+                ZVT_LIBS="`$GNOME_CONFIG --libs-only-l zvt`"
+                GNOME_LIBDIR="`$GNOME_CONFIG --libs-only-L gnorba gnomeui`"
+                GNOME_INCLUDEDIR="`$GNOME_CONFIG --cflags gnorba gnomeui`"
+                
+              else
+                echo "$ac_t""no" 1>&6
+                no_gnome_config="yes"
+              fi
+            fi
+
+            if test x$exec_prefix = xNONE; then
+                if test x$prefix = xNONE; then
+                    gnome_prefix=$ac_default_prefix/lib
+                else
+                    gnome_prefix=$prefix/lib
+                fi
+            else
+                gnome_prefix=`eval echo \`echo $libdir\``
+            fi
+        
+            if test "$no_gnome_config" = "yes"; then
+              echo $ac_n "checking for gnomeConf.sh file in $gnome_prefix""... $ac_c" 1>&6
+echo "configure:2552: checking for gnomeConf.sh file in $gnome_prefix" >&5
+              if test -f $gnome_prefix/gnomeConf.sh; then
+                echo "$ac_t""found" 1>&6
+                echo "loading gnome configuration from" \
+                     "$gnome_prefix/gnomeConf.sh"
+                . $gnome_prefix/gnomeConf.sh
+                
+              else
+                echo "$ac_t""not found" 1>&6
+                if test xfail = xfail; then
+                  { echo "configure: error: Could not find the gnomeConf.sh file that is generated by gnome-libs install" 1>&2; exit 1; }
+                fi
+              fi
+            fi
+        fi
+
+        if test -n ""; then
+          n=""
+          for i in $n; do
+            echo $ac_n "checking extra library \"$i\"""... $ac_c" 1>&6
+echo "configure:2572: checking extra library \"$i\"" >&5
+            case $i in 
+              applets)
+                
+                GNOME_APPLETS_LIBS=`$GNOME_CONFIG --libs-only-l applets`
+                echo "$ac_t""$GNOME_APPLETS_LIBS" 1>&6;;
+              docklets)
+                
+                GNOME_DOCKLETS_LIBS=`$GNOME_CONFIG --libs-only-l docklets`
+                echo "$ac_t""$GNOME_DOCKLETS_LIBS" 1>&6;;
+              capplet)
+                
+                GNOME_CAPPLET_LIBS=`$GNOME_CONFIG --libs-only-l capplet`
+                echo "$ac_t""$GNOME_CAPPLET_LIBS" 1>&6;;
+              *)
+                echo "$ac_t""unknown library" 1>&6
+            esac
+            EXTRA_INCLUDEDIR=`$GNOME_CONFIG --cflags $i`
+            GNOME_INCLUDEDIR="$GNOME_INCLUDEDIR $EXTRA_INCLUDEDIR"
+          done
+        fi
+
+
+    GNOME_DIR=src/gnome-console
+fi
+
+
+
+# -------------------------------------------
+# smartalloc (default off)
+# -------------------------------------------
+# Check whether --enable-smartalloc or --disable-smartalloc was given.
+if test "${enable_smartalloc+set}" = set; then
+  enableval="$enable_smartalloc"
+  if test x$enableval = xno; then
+    support_smartalloc=no
+  fi
+fi
+
+
+if test x$support_smartalloc = xyes; then
+   cat >> confdefs.h <<\EOF
+#define SMARTALLOC 1
+EOF
+
+fi
+
+
+
+# ---------------------------------------------------
+# Check for readline support/directory (default on)
+# ---------------------------------------------------
+support_readline=yes
+# this allows you to turn it completely off
+# Check whether --enable-readline or --disable-readline was given.
+if test "${enable_readline+set}" = set; then
+  enableval="$enable_readline"
+  if test x$enableval = xno; then
+    support_readline=no
+  fi
+fi
+
+
+got_readline="no"
+READLINE_SRC=
+if test x$support_readline = xyes; then
+   # Check whether --with-readline or --without-readline was given.
+if test "${with_readline+set}" = set; then
+  withval="$with_readline"
+  
+       case "$with_readline" in
+       no) : ;;
+       yes|*)
+         if test "$with_readline" != "yes"; then
+           CONS_INC="-I$with_readline"
+           CONS_LDFLAGS="-L$with_readline"
+         else
+            with_readline="/usr/include/readline" 
+         fi
+         ac_safe=`echo "$with_readline/readline.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $with_readline/readline.h""... $ac_c" 1>&6
+echo "configure:2653: checking for $with_readline/readline.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2658 "configure"
+#include "confdefs.h"
+#include <$with_readline/readline.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2663: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+   echo "$ac_t""yes" 1>&6
+              cat >> confdefs.h <<\EOF
+#define HAVE_READLINE 1
+EOF
+              CONS_LIBS="-lreadline"
+              got_readline="yes"   
+            
+else
+  echo "$ac_t""no" 1>&6
+ { echo "configure: error: *** readline library missing" 1>&2; exit 1; } 
+            
+         
+fi
+
+         ;;
+       esac
+     
+else
+  
+       # check for standard readline library
+       ac_safe=`echo "/usr/include/readline/readline.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for /usr/include/readline/readline.h""... $ac_c" 1>&6
+echo "configure:2702: checking for /usr/include/readline/readline.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2707 "configure"
+#include "confdefs.h"
+#include </usr/include/readline/readline.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2712: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+   echo "$ac_t""yes" 1>&6
+        cat >> confdefs.h <<\EOF
+#define HAVE_READLINE 1
+EOF
+
+        got_readline="yes"
+        CONS_INC="-I/usr/include/readline"
+        CONS_LIBS="-lreadline"
+       
+else
+  echo "$ac_t""no" 1>&6
+
+        # Did not find starndard library, so user our own
+        echo "$ac_t""yes" 1>&6
+        cat >> confdefs.h <<\EOF
+#define HAVE_READLINE 1
+EOF
+
+        got_readline="yes"
+        CONS_INC="-I${TOP_DIR}/depkgs"
+        CONS_LIBS="-lreadline -lhistory"
+        CONS_LDFLAGS="-L${TOP_DIR}/depkgs/readline"
+        READLINE_SRC="${TOP_DIR}/depkgs/readline"
+       
+fi
+
+        
+   
+fi
+
+fi
+
+
+
+
+
+# Minimal stuff for readline Makefile configuration
+MAKE_SHELL=/bin/sh
+
+
+echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6
+echo "configure:2769: checking whether stat file-mode macros are broken" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2774 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(S_ISBLK) && defined(S_IFDIR)
+# if S_ISBLK (S_IFDIR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISBLK) && defined(S_IFCHR)
+# if S_ISBLK (S_IFCHR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISLNK) && defined(S_IFREG)
+# if S_ISLNK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFREG)
+# if S_ISSOCK (S_IFREG)
+You lose.
+# endif
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "You lose" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_header_stat_broken=yes
+else
+  rm -rf conftest*
+  ac_cv_header_stat_broken=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_header_stat_broken" 1>&6
+if test $ac_cv_header_stat_broken = yes; then
+  cat >> confdefs.h <<\EOF
+#define STAT_MACROS_BROKEN 1
+EOF
+
+fi
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:2829: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2834 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:2842: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:2867: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2875 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2886: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:2908: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2916 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2927: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+for ac_func in strcasecmp select setenv putenv tcgetattr setlocale lstat lchown
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2953: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2958 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2981: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+#AC_CHECK_FUNC(getopt_long, AC_DEFINE(HAVE_GETOPT_LONG),
+#   [LIBEXTRAOBJ="$LIBEXTRAOBJ getopt.o getopt1.o"
+#    EXTRAOBJ="$EXTRAOBJ lib/getopt.o lib/getopt1.o"])
+
+echo $ac_n "checking for getopt_long""... $ac_c" 1>&6
+echo "configure:3011: checking for getopt_long" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getopt_long'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3016 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getopt_long(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getopt_long();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getopt_long) || defined (__stub___getopt_long)
+choke me
+#else
+getopt_long();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3039: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getopt_long=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getopt_long=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getopt_long`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_GETOPT_LONG 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+echo $ac_n "checking for working strcoll""... $ac_c" 1>&6
+echo "configure:3064: checking for working strcoll" >&5
+if eval "test \"`echo '$''{'ac_cv_func_strcoll_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_strcoll_works=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3072 "configure"
+#include "confdefs.h"
+#include <string.h>
+main ()
+{
+  exit (strcoll ("abc", "def") >= 0 ||
+       strcoll ("ABC", "DEF") >= 0 ||
+       strcoll ("123", "456") >= 0);
+}
+EOF
+if { (eval echo configure:3082: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_strcoll_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_strcoll_works=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_strcoll_works" 1>&6
+if test $ac_cv_func_strcoll_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRCOLL 1
+EOF
+
+fi
+
+
+for ac_hdr in varargs.h \
+               sys/ptem.h sys/pte.h sys/stream.h \
+               termcap.h termio.h 
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3111: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3116 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3121: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+TERMCAP_LIB=-ltermcap
+
+
+
+# End of readline stuff
+# -----------------------------------------------------------------------
+
+
+# ---------------------------------------------------
+# Check for GMP support/directory
+# ---------------------------------------------------
+GMP_SRC=
+local_gmp="no"
+# Check whether --with-gmp or --without-gmp was given.
+if test "${with_gmp+set}" = set; then
+  withval="$with_gmp"
+  
+     case "$with_gmp" in
+     no) : ;;
+     yes|*)
+       if test "$with_gmp" != "yes"; then
+        GMP_INC="-I$with_gmp"
+        GMP_LIBS="-lgmp"
+        GMP_LDFLAGS="-L$with_gmp"
+       else
+         with_gmp="/usr/include" 
+       fi
+       ac_safe=`echo "$with_gmp/gmp.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $with_gmp/gmp.h""... $ac_c" 1>&6
+echo "configure:3177: checking for $with_gmp/gmp.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3182 "configure"
+#include "confdefs.h"
+#include <$with_gmp/gmp.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3187: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+   echo "$ac_t""yes" 1>&6
+           cat >> confdefs.h <<\EOF
+#define HAVE_GMP 1
+EOF
+           GMP_LIBS="-lgmp"
+           got_gmp="yes"   
+         
+else
+  echo "$ac_t""no" 1>&6
+ { echo "configure: error: *** gmp library missing" 1>&2; exit 1; } 
+         
+       
+fi
+
+       ;;
+     esac
+  
+else
+  
+    # check for standard gmp library
+    ac_safe=`echo "/usr/include/gmp.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for /usr/include/gmp.h""... $ac_c" 1>&6
+echo "configure:3226: checking for /usr/include/gmp.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3231 "configure"
+#include "confdefs.h"
+#include </usr/include/gmp.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3236: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+   echo "$ac_t""yes" 1>&6
+      cat >> confdefs.h <<\EOF
+#define HAVE_GMP 1
+EOF
+
+      got_gmp="yes"
+      GMP_INC=
+      GMP_LIBS="-lgmp"
+    
+else
+  echo "$ac_t""no" 1>&6
+
+      # Did not find standard library, so use our own
+      echo "$ac_t""yes" 1>&6
+      cat >> confdefs.h <<\EOF
+#define HAVE_GMP 1
+EOF
+
+      got_gmp="yes"
+      local_gmp="yes"
+      GMP_INC="-I${TOP_DIR}/depkgs/gmp"
+      GMP_LIBS="-lgmp"
+      GMP_LDFLAGS="-L${TOP_DIR}/depkgs/gmp"
+      GMP_SRC="${TOP_DIR}/depkgs/gmp"
+    
+fi
+
+     
+
+fi
+
+
+
+
+
+
+# End of GMP stuff
+# -----------------------------------------------------------------------
+
+
+# ---------------------------------------------------
+# Check for CWEB support/directory
+# ---------------------------------------------------
+CWEB_SRC=
+local_cweb="no"
+# Check whether --with-cweb or --without-cweb was given.
+if test "${with_cweb+set}" = set; then
+  withval="$with_cweb"
+  
+     case "$with_cweb" in
+     no) : ;;
+     yes|*)
+       if test "$with_cweb" != "yes"; then
+        CWEB_INC="-I$with_cweb"
+        CWEB_LIBS="-lcweb"
+        CWEB_LDFLAGS="-L$with_cweb"
+       else
+         with_cweb="/usr/include" 
+       fi
+       ac_safe=`echo "$with_cweb/cweb.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $with_cweb/cweb.h""... $ac_c" 1>&6
+echo "configure:3313: checking for $with_cweb/cweb.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3318 "configure"
+#include "confdefs.h"
+#include <$with_cweb/cweb.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3323: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+   echo "$ac_t""yes" 1>&6
+           cat >> confdefs.h <<\EOF
+#define HAVE_CWEB 1
+EOF
+           CWEB_LIBS="-lcweb"
+           got_cweb="yes"   
+         
+else
+  echo "$ac_t""no" 1>&6
+ { echo "configure: error: *** cweb library missing" 1>&2; exit 1; } 
+         
+       
+fi
+
+       ;;
+     esac
+  
+else
+  
+    # check for standard cweb library
+    ac_safe=`echo "/usr/include/cweb.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for /usr/include/cweb.h""... $ac_c" 1>&6
+echo "configure:3362: checking for /usr/include/cweb.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3367 "configure"
+#include "confdefs.h"
+#include </usr/include/cweb.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3372: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+   echo "$ac_t""yes" 1>&6
+      cat >> confdefs.h <<\EOF
+#define HAVE_CWEB 1
+EOF
+
+      got_cweb="yes"
+      CWEB_INC=
+      CWEB_LIBS="-lcweb"
+    
+else
+  echo "$ac_t""no" 1>&6
+
+      # Did not find starndard library, so use our own
+      echo "$ac_t""yes" 1>&6
+      cat >> confdefs.h <<\EOF
+#define HAVE_CWEB 1
+EOF
+
+      got_cweb="yes"
+      local_cweb="yes"
+      CWEB_INC="-I${TOP_DIR}/depkgs/cweb"
+      CWEB_LIBS="-lcweb"
+      CWEB_LDFLAGS="-L${TOP_DIR}/depkgs/cweb"
+      CWEB_SRC="${TOP_DIR}/depkgs/cweb"
+    
+fi
+
+     
+
+fi
+
+
+
+
+
+
+# End of CWEB stuff
+# -----------------------------------------------------------------------
+
+
+
+# -----------------------------------------------------------
+# Check whether user wants TCP wrappers support (default off)
+# -----------------------------------------------------------
+TCPW_MSG="no" 
+# Check whether --with-tcp-wrappers or --without-tcp-wrappers was given.
+if test "${with_tcp_wrappers+set}" = set; then
+  withval="$with_tcp_wrappers"
+  
+    if test "x$withval" != "xno" ; then
+       saved_LIBS="$LIBS"
+       LIBS="$LIBS -lwrap -lnsl"
+       echo $ac_n "checking for libwrap""... $ac_c" 1>&6
+echo "configure:3441: checking for libwrap" >&5
+       cat > conftest.$ac_ext <<EOF
+#line 3443 "configure"
+#include "confdefs.h"
+ #include <tcpd.h>
+            int deny_severity = 0;
+            int allow_severity = 0;
+            struct request_info *req; 
+int main() {
+ hosts_access(req); 
+; return 0; }
+EOF
+if { (eval echo configure:3453: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  
+           echo "$ac_t""yes" 1>&6
+           cat >> confdefs.h <<\EOF
+#define HAVE_LIBWRAP 1
+EOF
+
+           TCPW_MSG="yes" 
+         
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  { echo "configure: error: *** libwrap missing" 1>&2; exit 1; } 
+       
+fi
+rm -f conftest*
+    fi
+  
+
+fi
+
+
+# ------------------------------------------
+# Where to place working dir
+# ------------------------------------------
+working_dir=`eval echo ${sysconfdir}/working`
+# Check whether --with-working-dir or --without-working-dir was given.
+if test "${with_working_dir+set}" = set; then
+  withval="$with_working_dir"
+  
+       if test "x$withval" != "xno" ; then     
+             working_dir=$withval
+       fi
+   
+
+fi
+
+
+
+
+# ------------------------------------------
+# Where to send dump email
+# ------------------------------------------
+dump_email=root
+# Check whether --with-dump-email or --without-dump-email was given.
+if test "${with_dump_email+set}" = set; then
+  withval="$with_dump_email"
+  
+       if test "x$withval" != "xno" ; then     
+             dump_email=$withval
+       fi
+   
+
+fi
+
+
+
+
+# ------------------------------------------
+# Where to send job email
+# ------------------------------------------
+job_email=root
+# Check whether --with-job-email or --without-job-email was given.
+if test "${with_job_email+set}" = set; then
+  withval="$with_job_email"
+  
+       if test "x$withval" != "xno" ; then     
+             job_email=$withval
+       fi
+   
+
+fi
+
+
+
+
+# ------------------------------------------
+# Where to find smtp host
+# ------------------------------------------
+smtp_host=localhost
+# Check whether --with-smtp_host or --without-smtp_host was given.
+if test "${with_smtp_host+set}" = set; then
+  withval="$with_smtp_host"
+  
+       if test "x$withval" != "xno" ; then     
+             smtp_host=$withval
+       fi
+   
+
+fi
+
+
+
+
+
+# ------------------------------------
+# Where to place pid files
+# ------------------------------------
+piddir=/var/run
+# Check whether --with-pid-dir or --without-pid-dir was given.
+if test "${with_pid_dir+set}" = set; then
+  withval="$with_pid_dir"
+  
+       if test "x$withval" != "xno" ; then     
+           piddir=$withval
+       fi
+    
+
+fi
+
+
+# make sure the pid directory exists
+if test ! -d $piddir ; then    
+    piddir=`eval echo ${sysconfdir}`
+    case $piddir in
+         NONE/*) piddir=`echo $piddir | sed "s~NONE~$ac_default_prefix~"` ;;
+    esac
+fi
+
+cat >> confdefs.h <<EOF
+#define _PATH_BACULA_PIDDIR "$piddir"
+EOF
+
+
+
+
+# ------------------------------------
+# Where to place subsys "lock file"
+# ------------------------------------
+subsysdir=/var/run/subsys
+# Check whether --with-subsys-dir or --without-subsys-dir was given.
+if test "${with_subsys_dir+set}" = set; then
+  withval="$with_subsys_dir"
+  
+       if test "x$withval" != "xno" ; then     
+           subsysdir=$withval
+       fi
+    
+
+fi
+
+
+# make sure the pid directory exists
+if test ! -d $subsysdir ; then    
+    subsysdir=`eval echo ${sysconfdir}`
+    case $subsysdir in
+       NONE/*) subsysdir=`echo $subsysdir | sed "s~NONE~$ac_default_prefix~"` ;;
+    esac
+fi
+
+
+
+
+
+# ------------------------------------
+# Where to start assigning ports
+# ------------------------------------
+baseport=9101
+# Check whether --with-baseport or --without-baseport was given.
+if test "${with_baseport+set}" = set; then
+  withval="$with_baseport"
+  
+       if test "x$withval" != "xno" ; then     
+            baseport=$withval
+       fi
+    
+
+fi
+
+
+
+dir_port=`expr $baseport`
+fd_port=`expr $baseport + 1`
+sd_port=`expr $fd_port + 1`
+
+
+
+
+
+
+# ------------------------------------------
+# Generate passwords
+# ------------------------------------------
+dir_password=
+# Check whether --with-dir-password or --without-dir-password was given.
+if test "${with_dir_password+set}" = set; then
+  withval="$with_dir_password"
+  
+       if test "x$withval" != "xno" ; then     
+          dir_password=$withval
+       fi
+   
+
+fi
+
+
+if test "x$dir_password" = "x" ; then
+   if test "x$OPENSSL" = "xnone" ; then
+      key=`date | uuencode 1 | tr "\"@\\\`\\ \\=\\,\\(\\)\\#\\.\\!\\-$'" abcdefghijklmnopqrst | awk '{getline} {print} {exit}'`
+   else
+      key=`openssl rand -base64 33`
+   fi
+   dir_password=$key
+fi
+
+fd_password=
+# Check whether --with-fd-password or --without-fd-password was given.
+if test "${with_fd_password+set}" = set; then
+  withval="$with_fd_password"
+  
+       if test "x$withval" != "xno" ; then     
+          fd_password=$withval
+       fi
+   
+
+fi
+
+
+if test "x$fd_password" = "x" ; then
+   if test "x$OPENSSL" = "xnone" ; then
+      key=`date | uuencode 1 | tr "\"@\\\`\\ \\=\\,\\(\\)\\#\\.\\!\\-$'" tsrqponmlkjihgfedcba | awk '{getline} {print} {exit}'`
+   else
+      key=`openssl rand -base64 33`
+   fi
+   fd_password=$key
+fi
+
+sd_password=
+# Check whether --with-sd-password or --without-sd-password was given.
+if test "${with_sd_password+set}" = set; then
+  withval="$with_sd_password"
+  
+       if test "x$withval" != "xno" ; then     
+          sd_password=$withval
+       fi
+   
+
+fi
+
+
+if test "x$sd_password" = "x" ; then
+   if test "x$OPENSSL" = "xnone" ; then
+      key=`date | uuencode 1 | tr "\"@\\\`\\ \\=\\,\\(\\)\\#\\.\\!\\-$'" 123456789uvwxyzabcdef | awk '{getline} {print} {exit}'`
+   else
+      key=`openssl rand -base64 33`
+   fi
+   sd_password=$key
+fi
+
+
+
+
+
+
+
+
+
+
+# ------------------------------------------------
+# Bacula check for various SQL database engines
+# ------------------------------------------------
+
+have_db=no
+db_name=none
+echo $ac_n "checking for MySQL support""... $ac_c" 1>&6
+echo "configure:3720: checking for MySQL support" >&5
+# Check whether --with-mysql or --without-mysql was given.
+if test "${with_mysql+set}" = set; then
+  withval="$with_mysql"
+  
+  if test "$withval" != "no"; then
+        if test "$withval" = "yes"; then
+                if test -f /usr/local/mysql/include/mysql/mysql.h; then
+                        MYSQL_INCDIR=/usr/local/mysql/include/mysql
+                        MYSQL_LIBDIR=/usr/local/mysql/lib/mysql
+                        MYSQL_BINDIR=/usr/local/mysql/bin
+                elif test -f /usr/include/mysql/mysql.h; then
+                        MYSQL_INCDIR=/usr/include/mysql
+                        MYSQL_LIBDIR=/usr/lib/mysql
+                        MYSQL_BINDIR=/usr/bin      
+                elif test -f /usr/include/mysql.h; then
+                        MYSQL_INCDIR=/usr/include
+                        MYSQL_LIBDIR=/usr/lib
+                        MYSQL_BINDIR=/usr/bin
+                elif test -f /usr/local/include/mysql/mysql.h; then
+                        MYSQL_INCDIR=/usr/local/include/mysql
+                        MYSQL_LIBDIR=/usr/local/lib/mysql
+                        MYSQL_BINDIR=/usr/local/bin
+                elif test -f /usr/local/include/mysql.h; then
+                        MYSQL_INCDIR=/usr/local/include
+                        MYSQL_LIBDIR=/usr/local/lib
+                        MYSQL_BINDIR=/usr/local/bin
+                else
+                   echo "$ac_t""no" 1>&6
+                   { echo "configure: error: Unable to find mysql.h in standard locations" 1>&2; exit 1; }
+                fi
+        else
+                if test -f $withval/include/mysql/mysql.h; then
+                        MYSQL_INCDIR=$withval/include/mysql
+                        MYSQL_LIBDIR=$withval/lib/mysql
+                        MYSQL_BINDIR=$withval/bin
+                elif test -f $withval/include/mysql.h; then
+                        MYSQL_INCDIR=$withval/include
+                        MYSQL_LIBDIR=$withval/lib
+                        MYSQL_BINDIR=$withval/bin
+                else
+                   echo "$ac_t""no" 1>&6
+                   { echo "configure: error: Invalid MySQL directory $withval - unable to find mysql.h under $withval" 1>&2; exit 1; }
+                fi
+        fi
+    SQL_INCLUDE=-I$MYSQL_INCDIR
+    SQL_LFLAGS="-L$MYSQL_LIBDIR -lmysqlclient"
+    SQL_BINDIR=$MYSQL_BINDIR
+
+    cat >> confdefs.h <<\EOF
+#define HAVE_MYSQL 1
+EOF
+
+    echo "$ac_t""yes" 1>&6
+    have_db=yes
+    support_mysql=yes
+    db_name=MySQL
+
+  else
+        echo "$ac_t""no" 1>&6
+  fi
+
+else
+  
+  echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+
+  
+
+
+
+# ------------------------------------------------
+# Bacula check for various SQL database engines
+# ------------------------------------------------
+
+have_db=no
+db_name=none
+echo $ac_n "checking for SQLite support""... $ac_c" 1>&6
+echo "configure:3802: checking for SQLite support" >&5
+# Check whether --with-sqlite or --without-sqlite was given.
+if test "${with_sqlite+set}" = set; then
+  withval="$with_sqlite"
+  
+  if test "$withval" != "no"; then
+        if test "$withval" = "yes"; then
+                if test -f /usr/local/include/sqlite.h; then
+                        SQLITE_INCDIR=/usr/local/include
+                        SQLITE_LIBDIR=/usr/local/lib
+                        SQLITE_BINDIR=/usr/local/bin
+                elif test -f /usr/include/sqlite.h; then
+                        SQLITE_INCDIR=/usr/include
+                        SQLITE_LIBDIR=/usr/lib
+                        SQLITE_BINDIR=/usr/bin      
+                else
+                   echo "$ac_t""no" 1>&6
+                   { echo "configure: error: Unable to find sqlite.h in standard locations" 1>&2; exit 1; }
+                fi
+        else
+                if test -f $withval/sqlite.h; then
+                        SQLITE_INCDIR=$withval
+                        SQLITE_LIBDIR=$withval
+                        SQLITE_BINDIR=$withval
+                else
+                   echo "$ac_t""no" 1>&6
+                   { echo "configure: error: Invalid SQLite directory $withval - unable to find sqlite.h under $withval" 1>&2; exit 1; }
+                fi
+        fi
+    SQL_INCLUDE=-I$SQLITE_INCDIR
+    SQL_LFLAGS="-L$SQLITE_LIBDIR -lsqlite"
+    SQL_BINDIR=$SQLITE_BINDIR
+
+    cat >> confdefs.h <<\EOF
+#define HAVE_SQLITE 1
+EOF
+
+    echo "$ac_t""yes" 1>&6
+    have_db=yes
+    support_sqlite=yes
+    db_name=SQLite
+
+  else
+        echo "$ac_t""no" 1>&6
+  fi
+
+else
+  
+  echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+
+  
+
+
+
+cat >> confdefs.h <<\EOF
+#define PROTOTYPES 1
+EOF
+
+
+if test -z "$CFLAGS"; then
+    if test -z "$CCOPTS"; then
+       CCOPTS='-O'
+    fi
+    CFLAGS="$CCOPTS"
+fi
+
+
+echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6
+echo "configure:3875: checking for mingw32 environment" >&5
+if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3880 "configure"
+#include "confdefs.h"
+
+int main() {
+return __MINGW32__;
+; return 0; }
+EOF
+if { (eval echo configure:3887: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_mingw32=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_mingw32=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_mingw32" 1>&6
+MINGW32=
+test "$ac_cv_mingw32" = yes && MINGW32=yes
+
+
+echo $ac_n "checking for executable suffix""... $ac_c" 1>&6
+echo "configure:3906: checking for executable suffix" >&5
+if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$CYGWIN" = yes || test "$MINGW32" = yes; then
+  ac_cv_exeext=.exe
+else
+  rm -f conftest*
+  echo 'int main () { return 0; }' > conftest.$ac_ext
+  ac_cv_exeext=
+  if { (eval echo configure:3916: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+    for file in conftest.*; do
+      case $file in
+      *.c | *.o | *.obj) ;;
+      *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;;
+      esac
+    done
+  else
+    { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; }
+  fi
+  rm -f conftest*
+  test x"${ac_cv_exeext}" = x && ac_cv_exeext=no
+fi
+fi
+
+EXEEXT=""
+test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext}
+echo "$ac_t""${ac_cv_exeext}" 1>&6
+ac_exeext=$EXEEXT
+
+  
+
+
+# If we find X, set shell vars x_includes and x_libraries to the
+# paths, otherwise set no_x=yes.
+# Uses ac_ vars as temps to allow command line to override cache and checks.
+# --without-x overrides everything else, but does not touch the cache.
+echo $ac_n "checking for X""... $ac_c" 1>&6
+echo "configure:3944: checking for X" >&5
+
+# Check whether --with-x or --without-x was given.
+if test "${with_x+set}" = set; then
+  withval="$with_x"
+  :
+fi
+
+# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+if test "x$with_x" = xno; then
+  # The user explicitly disabled X.
+  have_x=disabled
+else
+  if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then
+    # Both variables are already set.
+    have_x=yes
+  else
+if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # One or both of the vars are not set, and there is no cached value.
+ac_x_includes=NO ac_x_libraries=NO
+rm -fr conftestdir
+if mkdir conftestdir; then
+  cd conftestdir
+  # Make sure to not put "make" in the Imakefile rules, since we grep it out.
+  cat > Imakefile <<'EOF'
+acfindx:
+       @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"'
+EOF
+  if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then
+    # GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+    eval `${MAKE-make} acfindx 2>/dev/null | grep -v make`
+    # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+    for ac_extension in a so sl; do
+      if test ! -f $ac_im_usrlibdir/libX11.$ac_extension &&
+        test -f $ac_im_libdir/libX11.$ac_extension; then
+        ac_im_usrlibdir=$ac_im_libdir; break
+      fi
+    done
+    # Screen out bogus values from the imake configuration.  They are
+    # bogus both because they are the default anyway, and because
+    # using them would break gcc on systems where it needs fixed includes.
+    case "$ac_im_incroot" in
+       /usr/include) ;;
+       *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;;
+    esac
+    case "$ac_im_usrlibdir" in
+       /usr/lib | /lib) ;;
+       *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;;
+    esac
+  fi
+  cd ..
+  rm -fr conftestdir
+fi
+
+if test "$ac_x_includes" = NO; then
+  # Guess where to find include files, by looking for this one X11 .h file.
+  test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h
+
+  # First, try using that file with no special directory specified.
+cat > conftest.$ac_ext <<EOF
+#line 4006 "configure"
+#include "confdefs.h"
+#include <$x_direct_test_include>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4011: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  # Look for the header file in a standard set of common directories.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+  for ac_dir in               \
+    /usr/X11/include          \
+    /usr/X11R6/include        \
+    /usr/X11R5/include        \
+    /usr/X11R4/include        \
+                              \
+    /usr/include/X11          \
+    /usr/include/X11R6        \
+    /usr/include/X11R5        \
+    /usr/include/X11R4        \
+                              \
+    /usr/local/X11/include    \
+    /usr/local/X11R6/include  \
+    /usr/local/X11R5/include  \
+    /usr/local/X11R4/include  \
+                              \
+    /usr/local/include/X11    \
+    /usr/local/include/X11R6  \
+    /usr/local/include/X11R5  \
+    /usr/local/include/X11R4  \
+                              \
+    /usr/X386/include         \
+    /usr/x386/include         \
+    /usr/XFree86/include/X11  \
+                              \
+    /usr/include              \
+    /usr/local/include        \
+    /usr/unsupported/include  \
+    /usr/athena/include       \
+    /usr/local/x11r5/include  \
+    /usr/lpp/Xamples/include  \
+                              \
+    /usr/openwin/include      \
+    /usr/openwin/share/include \
+    ; \
+  do
+    if test -r "$ac_dir/$x_direct_test_include"; then
+      ac_x_includes=$ac_dir
+      break
+    fi
+  done
+fi
+rm -f conftest*
+fi # $ac_x_includes = NO
+
+if test "$ac_x_libraries" = NO; then
+  # Check for the libraries.
+
+  test -z "$x_direct_test_library" && x_direct_test_library=Xt
+  test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc
+
+  # See if we find them without any special options.
+  # Don't add to $LIBS permanently.
+  ac_save_LIBS="$LIBS"
+  LIBS="-l$x_direct_test_library $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4080 "configure"
+#include "confdefs.h"
+
+int main() {
+${x_direct_test_function}()
+; return 0; }
+EOF
+if { (eval echo configure:4087: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  LIBS="$ac_save_LIBS"
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  LIBS="$ac_save_LIBS"
+# First see if replacing the include by lib works.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \
+    /usr/X11/lib          \
+    /usr/X11R6/lib        \
+    /usr/X11R5/lib        \
+    /usr/X11R4/lib        \
+                          \
+    /usr/lib/X11          \
+    /usr/lib/X11R6        \
+    /usr/lib/X11R5        \
+    /usr/lib/X11R4        \
+                          \
+    /usr/local/X11/lib    \
+    /usr/local/X11R6/lib  \
+    /usr/local/X11R5/lib  \
+    /usr/local/X11R4/lib  \
+                          \
+    /usr/local/lib/X11    \
+    /usr/local/lib/X11R6  \
+    /usr/local/lib/X11R5  \
+    /usr/local/lib/X11R4  \
+                          \
+    /usr/X386/lib         \
+    /usr/x386/lib         \
+    /usr/XFree86/lib/X11  \
+                          \
+    /usr/lib              \
+    /usr/local/lib        \
+    /usr/unsupported/lib  \
+    /usr/athena/lib       \
+    /usr/local/x11r5/lib  \
+    /usr/lpp/Xamples/lib  \
+    /lib/usr/lib/X11     \
+                          \
+    /usr/openwin/lib      \
+    /usr/openwin/share/lib \
+    ; \
+do
+  for ac_extension in a so sl; do
+    if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then
+      ac_x_libraries=$ac_dir
+      break 2
+    fi
+  done
+done
+fi
+rm -f conftest*
+fi # $ac_x_libraries = NO
+
+if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then
+  # Didn't find X anywhere.  Cache the known absence of X.
+  ac_cv_have_x="have_x=no"
+else
+  # Record where we found X for the cache.
+  ac_cv_have_x="have_x=yes \
+               ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries"
+fi
+fi
+  fi
+  eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+  echo "$ac_t""$have_x" 1>&6
+  no_x=yes
+else
+  # If each of the values was on the command line, it overrides each guess.
+  test "x$x_includes" = xNONE && x_includes=$ac_x_includes
+  test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
+  # Update the cache value to reflect the command line values.
+  ac_cv_have_x="have_x=yes \
+               ac_x_includes=$x_includes ac_x_libraries=$x_libraries"
+  echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6
+fi
+
+if test "$no_x" = yes; then
+  # Not all programs may use this symbol, but it does not hurt to define it.
+  cat >> confdefs.h <<\EOF
+#define X_DISPLAY_MISSING 1
+EOF
+
+  X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
+else
+  if test -n "$x_includes"; then
+    X_CFLAGS="$X_CFLAGS -I$x_includes"
+  fi
+
+  # It would also be nice to do this for all -L options, not just this one.
+  if test -n "$x_libraries"; then
+    X_LIBS="$X_LIBS -L$x_libraries"
+    # For Solaris; some versions of Sun CC require a space after -R and
+    # others require no space.  Words are not sufficient . . . .
+    case "`(uname -sr) 2>/dev/null`" in
+    "SunOS 5"*)
+      echo $ac_n "checking whether -R must be followed by a space""... $ac_c" 1>&6
+echo "configure:4193: checking whether -R must be followed by a space" >&5
+      ac_xsave_LIBS="$LIBS"; LIBS="$LIBS -R$x_libraries"
+      cat > conftest.$ac_ext <<EOF
+#line 4196 "configure"
+#include "confdefs.h"
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:4203: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_R_nospace=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_R_nospace=no
+fi
+rm -f conftest*
+      if test $ac_R_nospace = yes; then
+       echo "$ac_t""no" 1>&6
+       X_LIBS="$X_LIBS -R$x_libraries"
+      else
+       LIBS="$ac_xsave_LIBS -R $x_libraries"
+       cat > conftest.$ac_ext <<EOF
+#line 4219 "configure"
+#include "confdefs.h"
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:4226: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_R_space=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_R_space=no
+fi
+rm -f conftest*
+       if test $ac_R_space = yes; then
+         echo "$ac_t""yes" 1>&6
+         X_LIBS="$X_LIBS -R $x_libraries"
+       else
+         echo "$ac_t""neither works" 1>&6
+       fi
+      fi
+      LIBS="$ac_xsave_LIBS"
+    esac
+  fi
+
+  # Check for system-dependent libraries X programs must link with.
+  # Do this before checking for the system-independent R6 libraries
+  # (-lICE), since we may need -lsocket or whatever for X linking.
+
+  if test "$ISC" = yes; then
+    X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet"
+  else
+    # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X
+    # libraries were built with DECnet support.  And karl@cs.umb.edu says
+    # the Alpha needs dnet_stub (dnet does not exist).
+    echo $ac_n "checking for dnet_ntoa in -ldnet""... $ac_c" 1>&6
+echo "configure:4258: checking for dnet_ntoa in -ldnet" >&5
+ac_lib_var=`echo dnet'_'dnet_ntoa | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldnet  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4266 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char dnet_ntoa();
+
+int main() {
+dnet_ntoa()
+; return 0; }
+EOF
+if { (eval echo configure:4277: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+      echo $ac_n "checking for dnet_ntoa in -ldnet_stub""... $ac_c" 1>&6
+echo "configure:4299: checking for dnet_ntoa in -ldnet_stub" >&5
+ac_lib_var=`echo dnet_stub'_'dnet_ntoa | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldnet_stub  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4307 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char dnet_ntoa();
+
+int main() {
+dnet_ntoa()
+; return 0; }
+EOF
+if { (eval echo configure:4318: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    fi
+
+    # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT,
+    # to get the SysV transport functions.
+    # chad@anasazi.com says the Pyramis MIS-ES running DC/OSx (SVR4)
+    # needs -lnsl.
+    # The nsl library prevents programs from opening the X display
+    # on Irix 5.2, according to dickey@clark.net.
+    echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:4347: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4352 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4375: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    if test $ac_cv_func_gethostbyname = no; then
+      echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
+echo "configure:4396: checking for gethostbyname in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lnsl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4404 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:4415: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    fi
+
+    # lieder@skyler.mavd.honeywell.com says without -lsocket,
+    # socket/setsockopt and other routines are undefined under SCO ODT
+    # 2.0.  But -lsocket is broken on IRIX 5.2 (and is not necessary
+    # on later versions), says simon@lia.di.epfl.ch: it contains
+    # gethostby* variants that don't use the nameserver (or something).
+    # -lsocket must be given before -lnsl if both are needed.
+    # We assume that if connect needs -lnsl, so does gethostbyname.
+    echo $ac_n "checking for connect""... $ac_c" 1>&6
+echo "configure:4445: checking for connect" >&5
+if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4450 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char connect(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char connect();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_connect) || defined (__stub___connect)
+choke me
+#else
+connect();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4473: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_connect=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_connect=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    if test $ac_cv_func_connect = no; then
+      echo $ac_n "checking for connect in -lsocket""... $ac_c" 1>&6
+echo "configure:4494: checking for connect in -lsocket" >&5
+ac_lib_var=`echo socket'_'connect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4502 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char connect();
+
+int main() {
+connect()
+; return 0; }
+EOF
+if { (eval echo configure:4513: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    fi
+
+    # gomez@mi.uni-erlangen.de says -lposix is necessary on A/UX.
+    echo $ac_n "checking for remove""... $ac_c" 1>&6
+echo "configure:4537: checking for remove" >&5
+if eval "test \"`echo '$''{'ac_cv_func_remove'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4542 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char remove(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char remove();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_remove) || defined (__stub___remove)
+choke me
+#else
+remove();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4565: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_remove=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_remove=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'remove`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    if test $ac_cv_func_remove = no; then
+      echo $ac_n "checking for remove in -lposix""... $ac_c" 1>&6
+echo "configure:4586: checking for remove in -lposix" >&5
+ac_lib_var=`echo posix'_'remove | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lposix  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4594 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char remove();
+
+int main() {
+remove()
+; return 0; }
+EOF
+if { (eval echo configure:4605: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    fi
+
+    # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+    echo $ac_n "checking for shmat""... $ac_c" 1>&6
+echo "configure:4629: checking for shmat" >&5
+if eval "test \"`echo '$''{'ac_cv_func_shmat'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4634 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char shmat(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char shmat();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_shmat) || defined (__stub___shmat)
+choke me
+#else
+shmat();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4657: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_shmat=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_shmat=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'shmat`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    if test $ac_cv_func_shmat = no; then
+      echo $ac_n "checking for shmat in -lipc""... $ac_c" 1>&6
+echo "configure:4678: checking for shmat in -lipc" >&5
+ac_lib_var=`echo ipc'_'shmat | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lipc  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4686 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char shmat();
+
+int main() {
+shmat()
+; return 0; }
+EOF
+if { (eval echo configure:4697: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    fi
+  fi
+
+  # Check for libraries that X11R6 Xt/Xaw programs need.
+  ac_save_LDFLAGS="$LDFLAGS"
+  test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries"
+  # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to
+  # check for ICE first), but we must link in the order -lSM -lICE or
+  # we get undefined symbols.  So assume we have SM if we have ICE.
+  # These have to be linked with before -lX11, unlike the other
+  # libraries we check for below, so use a different variable.
+  #  --interran@uluru.Stanford.EDU, kb@cs.umb.edu.
+  echo $ac_n "checking for IceConnectionNumber in -lICE""... $ac_c" 1>&6
+echo "configure:4730: checking for IceConnectionNumber in -lICE" >&5
+ac_lib_var=`echo ICE'_'IceConnectionNumber | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4738 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char IceConnectionNumber();
+
+int main() {
+IceConnectionNumber()
+; return 0; }
+EOF
+if { (eval echo configure:4749: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  LDFLAGS="$ac_save_LDFLAGS"
+
+fi
+
+
+for ac_hdr in \
+       assert.h \
+       fcntl.h \
+       grp.h \
+       libc.h \
+       limits.h \
+       stdarg.h \
+       stdlib.h \
+       string.h \
+       termios.h \
+       unistd.h \
+       sys/byteorder.h \
+       sys/ioctl.h \
+       sys/select.h \
+       sys/sockio.h \
+       sys/time.h \
+
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4794: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4799 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4804: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:4831: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4836 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4844: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 4861 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 4879 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4900 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:4911: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking whether sys/types.h defines makedev""... $ac_c" 1>&6
+echo "configure:4935: checking whether sys/types.h defines makedev" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_types_h_makedev'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4940 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int main() {
+return makedev(0, 0);
+; return 0; }
+EOF
+if { (eval echo configure:4947: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_header_sys_types_h_makedev=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_sys_types_h_makedev=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_header_sys_types_h_makedev" 1>&6
+
+if test $ac_cv_header_sys_types_h_makedev = no; then
+ac_safe=`echo "sys/mkdev.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for sys/mkdev.h""... $ac_c" 1>&6
+echo "configure:4965: checking for sys/mkdev.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4970 "configure"
+#include "confdefs.h"
+#include <sys/mkdev.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4975: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define MAJOR_IN_MKDEV 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+  if test $ac_cv_header_sys_mkdev_h = no; then
+ac_safe=`echo "sys/sysmacros.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for sys/sysmacros.h""... $ac_c" 1>&6
+echo "configure:5003: checking for sys/sysmacros.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5008 "configure"
+#include "confdefs.h"
+#include <sys/sysmacros.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:5013: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define MAJOR_IN_SYSMACROS 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  fi
+fi
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:5045: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5050 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:5058: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:5083: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5091 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:5102: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:5124: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5132 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:5143: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6
+echo "configure:5166: checking whether stat file-mode macros are broken" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5171 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(S_ISBLK) && defined(S_IFDIR)
+# if S_ISBLK (S_IFDIR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISBLK) && defined(S_IFCHR)
+# if S_ISBLK (S_IFCHR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISLNK) && defined(S_IFREG)
+# if S_ISLNK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFREG)
+# if S_ISSOCK (S_IFREG)
+You lose.
+# endif
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "You lose" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_header_stat_broken=yes
+else
+  rm -rf conftest*
+  ac_cv_header_stat_broken=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_header_stat_broken" 1>&6
+if test $ac_cv_header_stat_broken = yes; then
+  cat >> confdefs.h <<\EOF
+#define STAT_MACROS_BROKEN 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:5222: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5227 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:5243: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_sys_wait_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:5264: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5269 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:5278: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for st_blksize in struct stat""... $ac_c" 1>&6
+echo "configure:5299: checking for st_blksize in struct stat" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5304 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() {
+struct stat s; s.st_blksize;
+; return 0; }
+EOF
+if { (eval echo configure:5312: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_st_blksize=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_st_blksize=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_st_blksize" 1>&6
+if test $ac_cv_struct_st_blksize = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ST_BLKSIZE 1
+EOF
+
+fi
+
+echo $ac_n "checking for st_blocks in struct stat""... $ac_c" 1>&6
+echo "configure:5333: checking for st_blocks in struct stat" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_st_blocks'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5338 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() {
+struct stat s; s.st_blocks;
+; return 0; }
+EOF
+if { (eval echo configure:5346: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_st_blocks=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_st_blocks=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_st_blocks" 1>&6
+if test $ac_cv_struct_st_blocks = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ST_BLOCKS 1
+EOF
+
+else
+  LIBOBJS="$LIBOBJS fileblocks.${ac_objext}"
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:5369: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5374 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:5382: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&6
+echo "configure:5403: checking for tm_zone in struct tm" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5408 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_cv_struct_tm>
+int main() {
+struct tm tm; tm.tm_zone;
+; return 0; }
+EOF
+if { (eval echo configure:5416: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm_zone=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm_zone=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm_zone" 1>&6
+if test "$ac_cv_struct_tm_zone" = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_TM_ZONE 1
+EOF
+
+else
+  echo $ac_n "checking for tzname""... $ac_c" 1>&6
+echo "configure:5436: checking for tzname" >&5
+if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5441 "configure"
+#include "confdefs.h"
+#include <time.h>
+#ifndef tzname /* For SGI.  */
+extern char *tzname[]; /* RS6000 and others reject char **tzname.  */
+#endif
+int main() {
+atoi(*tzname);
+; return 0; }
+EOF
+if { (eval echo configure:5451: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_var_tzname=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_var_tzname=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_var_tzname" 1>&6
+  if test $ac_cv_var_tzname = yes; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_TZNAME 1
+EOF
+
+  fi
+fi
+
+
+# It seems that that many machines where <utime.h> seems to be
+# broken just require something like -D_XXX_SOURCE, where XXX might
+# be POSIX, POSIX_C, ALL, HPUX or whatever, depending on the machine.
+
+echo $ac_n "checking for utime.h""... $ac_c" 1>&6
+echo "configure:5478: checking for utime.h" >&5
+if eval "test \"`echo '$''{'tar_cv_header_utime_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5483 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <utime.h>
+int main() {
+struct utimbuf foo
+; return 0; }
+EOF
+if { (eval echo configure:5492: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  tar_cv_header_utime_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  tar_cv_header_utime_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$tar_cv_header_utime_h" 1>&6
+test $tar_cv_header_utime_h = yes && cat >> confdefs.h <<\EOF
+#define HAVE_UTIME_H 1
+EOF
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:5511: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5516 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:5565: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+
+
+echo $ac_n "checking how to get filesystem type""... $ac_c" 1>&6
+echo "configure:5588: checking how to get filesystem type" >&5
+fstype=no
+# The order of these tests is important.
+cat > conftest.$ac_ext <<EOF
+#line 5592 "configure"
+#include "confdefs.h"
+#include <sys/statvfs.h>
+#include <sys/fstyp.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:5598: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define FSTYPE_STATVFS 1
+EOF
+ fstype=SVR4
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+if test $fstype = no; then
+cat > conftest.$ac_ext <<EOF
+#line 5614 "configure"
+#include "confdefs.h"
+#include <sys/statfs.h>
+#include <sys/fstyp.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:5620: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define FSTYPE_USG_STATFS 1
+EOF
+ fstype=SVR3
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+fi
+if test $fstype = no; then
+cat > conftest.$ac_ext <<EOF
+#line 5637 "configure"
+#include "confdefs.h"
+#include <sys/statfs.h>
+#include <sys/vmount.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:5643: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define FSTYPE_AIX_STATFS 1
+EOF
+ fstype=AIX
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+fi
+if test $fstype = no; then  
+cat > conftest.$ac_ext <<EOF
+#line 5660 "configure"
+#include "confdefs.h"
+#include <mntent.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:5665: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define FSTYPE_MNTENT 1
+EOF
+ fstype=4.3BSD
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+fi
+if test $fstype = no; then  
+cat > conftest.$ac_ext <<EOF
+#line 5682 "configure"
+#include "confdefs.h"
+#include <sys/mount.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "f_type;" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define FSTYPE_STATFS 1
+EOF
+ fstype=4.4BSD/OSF1
+fi
+rm -f conftest*
+
+fi
+if test $fstype = no; then  
+cat > conftest.$ac_ext <<EOF
+#line 5699 "configure"
+#include "confdefs.h"
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:5705: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define FSTYPE_GETMNT 1
+EOF
+ fstype=Ultrix
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+fi
+echo "$ac_t""$fstype" 1>&6
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:5723: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5728 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:5745: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+
+echo $ac_n "checking for type of signal functions""... $ac_c" 1>&6
+echo "configure:5765: checking for type of signal functions" >&5
+if eval "test \"`echo '$''{'bash_cv_signal_vintage'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+  cat > conftest.$ac_ext <<EOF
+#line 5771 "configure"
+#include "confdefs.h"
+#include <signal.h>
+int main() {
+
+    sigset_t ss;
+    struct sigaction sa;
+    sigemptyset(&ss); sigsuspend(&ss);
+    sigaction(SIGINT, &sa, (struct sigaction *) 0);
+    sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0);
+  
+; return 0; }
+EOF
+if { (eval echo configure:5784: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  bash_cv_signal_vintage=posix
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  
+    cat > conftest.$ac_ext <<EOF
+#line 5793 "configure"
+#include "confdefs.h"
+#include <signal.h>
+int main() {
+
+        int mask = sigmask(SIGINT);
+        sigsetmask(mask); sigblock(mask); sigpause(mask);
+    
+; return 0; }
+EOF
+if { (eval echo configure:5803: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  bash_cv_signal_vintage=4.2bsd
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  
+      cat > conftest.$ac_ext <<EOF
+#line 5812 "configure"
+#include "confdefs.h"
+
+        #include <signal.h>
+        RETSIGTYPE foo() { }
+int main() {
+
+                int mask = sigmask(SIGINT);
+                sigset(SIGINT, foo); sigrelse(SIGINT);
+                sighold(SIGINT); sigpause(SIGINT);
+        
+; return 0; }
+EOF
+if { (eval echo configure:5825: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  bash_cv_signal_vintage=svr3
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  bash_cv_signal_vintage=v7
+    
+fi
+rm -f conftest*
+  
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$bash_cv_signal_vintage" 1>&6
+if test "$bash_cv_signal_vintage" = posix; then
+cat >> confdefs.h <<\EOF
+#define HAVE_POSIX_SIGNALS 1
+EOF
+
+elif test "$bash_cv_signal_vintage" = "4.2bsd"; then
+cat >> confdefs.h <<\EOF
+#define HAVE_BSD_SIGNALS 1
+EOF
+
+elif test "$bash_cv_signal_vintage" = svr3; then
+cat >> confdefs.h <<\EOF
+#define HAVE_USG_SIGHOLD 1
+EOF
+
+fi
+
+echo $ac_n "checking for mode_t""... $ac_c" 1>&6
+echo "configure:5864: checking for mode_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5869 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_mode_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_mode_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_mode_t" 1>&6
+if test $ac_cv_type_mode_t = no; then
+  cat >> confdefs.h <<\EOF
+#define mode_t int
+EOF
+
+fi
+
+echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:5897: checking for uid_t in sys/types.h" >&5
+if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5902 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "uid_t" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_uid_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_uid_t" 1>&6
+if test $ac_cv_type_uid_t = no; then
+  cat >> confdefs.h <<\EOF
+#define uid_t int
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define gid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:5931: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5936 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:5964: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5969 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_pid_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+  cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:5997: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6002 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_off_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+  cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for ino_t""... $ac_c" 1>&6
+echo "configure:6030: checking for ino_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_ino_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6035 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])ino_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_ino_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_ino_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_ino_t" 1>&6
+if test $ac_cv_type_ino_t = no; then
+  cat >> confdefs.h <<\EOF
+#define ino_t unsigned long
+EOF
+
+fi
+
+echo $ac_n "checking for dev_t""... $ac_c" 1>&6
+echo "configure:6063: checking for dev_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_dev_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6068 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])dev_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_dev_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_dev_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_dev_t" 1>&6
+if test $ac_cv_type_dev_t = no; then
+  cat >> confdefs.h <<\EOF
+#define dev_t unsigned long
+EOF
+
+fi
+
+echo $ac_n "checking for daddr_t""... $ac_c" 1>&6
+echo "configure:6096: checking for daddr_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_daddr_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6101 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])daddr_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_daddr_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_daddr_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_daddr_t" 1>&6
+if test $ac_cv_type_daddr_t = no; then
+  cat >> confdefs.h <<\EOF
+#define daddr_t long
+EOF
+
+fi
+
+echo $ac_n "checking for major_t""... $ac_c" 1>&6
+echo "configure:6129: checking for major_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_major_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6134 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])major_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_major_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_major_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_major_t" 1>&6
+if test $ac_cv_type_major_t = no; then
+  cat >> confdefs.h <<\EOF
+#define major_t int
+EOF
+
+fi
+
+echo $ac_n "checking for minor_t""... $ac_c" 1>&6
+echo "configure:6162: checking for minor_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_minor_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6167 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])minor_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_minor_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_minor_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_minor_t" 1>&6
+if test $ac_cv_type_minor_t = no; then
+  cat >> confdefs.h <<\EOF
+#define minor_t int
+EOF
+
+fi
+
+echo $ac_n "checking for ssize_t""... $ac_c" 1>&6
+echo "configure:6195: checking for ssize_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_ssize_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6200 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])ssize_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_ssize_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_ssize_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_ssize_t" 1>&6
+if test $ac_cv_type_ssize_t = no; then
+  cat >> confdefs.h <<\EOF
+#define ssize_t int
+EOF
+
+fi
+
+echo $ac_n "checking for st_blocks in struct stat""... $ac_c" 1>&6
+echo "configure:6228: checking for st_blocks in struct stat" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_st_blocks'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6233 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() {
+struct stat s; s.st_blocks;
+; return 0; }
+EOF
+if { (eval echo configure:6241: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_st_blocks=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_st_blocks=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_st_blocks" 1>&6
+if test $ac_cv_struct_st_blocks = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ST_BLOCKS 1
+EOF
+
+else
+  LIBOBJS="$LIBOBJS fileblocks.${ac_objext}"
+fi
+
+echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
+echo "configure:6264: checking for st_rdev in struct stat" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6269 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() {
+struct stat s; s.st_rdev;
+; return 0; }
+EOF
+if { (eval echo configure:6277: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_st_rdev=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_st_rdev=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_st_rdev" 1>&6
+if test $ac_cv_struct_st_rdev = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ST_RDEV 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:6298: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6303 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:6311: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:6332: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6337 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:6386: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+
+
+echo $ac_n "checking size of char""... $ac_c" 1>&6
+echo "configure:6409: checking size of char" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_char'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_char=1
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6417 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(char));
+  exit(0);
+}
+EOF
+if { (eval echo configure:6428: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_char=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_char=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_char" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_CHAR $ac_cv_sizeof_char
+EOF
+
+
+echo $ac_n "checking size of short int""... $ac_c" 1>&6
+echo "configure:6448: checking size of short int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_short_int'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_short_int=2
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6456 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(short int));
+  exit(0);
+}
+EOF
+if { (eval echo configure:6467: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_short_int=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_short_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_short_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_SHORT_INT $ac_cv_sizeof_short_int
+EOF
+
+
+echo $ac_n "checking size of int""... $ac_c" 1>&6
+echo "configure:6487: checking size of int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_int=4
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6495 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(int));
+  exit(0);
+}
+EOF
+if { (eval echo configure:6506: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_int=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+EOF
+
+
+echo $ac_n "checking size of long int""... $ac_c" 1>&6
+echo "configure:6526: checking size of long int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_long_int'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_long_int=4
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6534 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(long int));
+  exit(0);
+}
+EOF
+if { (eval echo configure:6545: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_long_int=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_long_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_long_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_LONG_INT $ac_cv_sizeof_long_int
+EOF
+
+
+echo $ac_n "checking size of long long int""... $ac_c" 1>&6
+echo "configure:6565: checking size of long long int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_long_long_int'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_long_long_int=8
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6573 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(long long int));
+  exit(0);
+}
+EOF
+if { (eval echo configure:6584: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_long_long_int=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_long_long_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_long_long_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_LONG_LONG_INT $ac_cv_sizeof_long_long_int
+EOF
+
+
+echo $ac_n "checking size of int *""... $ac_c" 1>&6
+echo "configure:6604: checking size of int *" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_int_p'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_int_p=4
+else
+  cat > conftest.$ac_ext <<EOF
+#line 6612 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(int *));
+  exit(0);
+}
+EOF
+if { (eval echo configure:6623: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_int_p=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_int_p=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_int_p" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_INT_P $ac_cv_sizeof_int_p
+EOF
+
+
+
+# Check for sys/types.h types
+echo $ac_n "checking for u_int type""... $ac_c" 1>&6
+echo "configure:6645: checking for u_int type" >&5
+if eval "test \"`echo '$''{'ac_cv_have_u_int'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+    cat > conftest.$ac_ext <<EOF
+#line 6651 "configure"
+#include "confdefs.h"
+ #include <sys/types.h> 
+int main() {
+ u_int a; a = 1;
+; return 0; }
+EOF
+if { (eval echo configure:6658: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_u_int="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   ac_cv_have_u_int="no" 
+    
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_have_u_int" 1>&6
+if test "x$ac_cv_have_u_int" = "xyes" ; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_U_INT 1
+EOF
+
+   have_u_int=1
+fi
+
+echo $ac_n "checking for intmax_t type""... $ac_c" 1>&6
+echo "configure:6682: checking for intmax_t type" >&5
+if eval "test \"`echo '$''{'ac_cv_have_intmax_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   cat > conftest.$ac_ext <<EOF
+#line 6688 "configure"
+#include "confdefs.h"
+ #include <sys/types.h> 
+int main() {
+ intmax_t a; a = 1;
+; return 0; }
+EOF
+if { (eval echo configure:6695: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_intmax_t="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   
+        cat > conftest.$ac_ext <<EOF
+#line 6704 "configure"
+#include "confdefs.h"
+ #include <stdint.h> 
+int main() {
+ intmax_t a; a = 1;
+; return 0; }
+EOF
+if { (eval echo configure:6711: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_intmax_t="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   ac_cv_have_intmax_t="no" 
+        
+fi
+rm -f conftest*
+      
+   
+fi
+rm -f conftest*            
+
+
+fi
+
+echo "$ac_t""$ac_cv_have_intmax_t" 1>&6
+if test "x$ac_cv_have_intmax_t" = "xyes" ; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_INTMAX_T 1
+EOF
+
+   have_intmax_t=1
+fi
+
+
+echo $ac_n "checking for u_intmax_t type""... $ac_c" 1>&6
+echo "configure:6741: checking for u_intmax_t type" >&5
+if eval "test \"`echo '$''{'ac_cv_have_u_intmax_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   cat > conftest.$ac_ext <<EOF
+#line 6747 "configure"
+#include "confdefs.h"
+ #include <sys/types.h> 
+int main() {
+ u_intmax_t a; a = 1;
+; return 0; }
+EOF
+if { (eval echo configure:6754: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_u_intmax_t="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   
+        cat > conftest.$ac_ext <<EOF
+#line 6763 "configure"
+#include "confdefs.h"
+ #include <stdint.h> 
+int main() {
+ u_intmax_t a; a = 1;
+; return 0; }
+EOF
+if { (eval echo configure:6770: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_u_intmax_t="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   ac_cv_have_u_intmax_t="no" 
+        
+fi
+rm -f conftest*
+      
+   
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_have_u_intmax_t" 1>&6
+if test "x$ac_cv_have_u_intmax_t" = "xyes" ; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_U_INTMAX_T 1
+EOF
+
+   have_u_intmax_t=1
+fi
+
+
+echo $ac_n "checking for intXX_t types""... $ac_c" 1>&6
+echo "configure:6799: checking for intXX_t types" >&5
+if eval "test \"`echo '$''{'ac_cv_have_intxx_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   cat > conftest.$ac_ext <<EOF
+#line 6805 "configure"
+#include "confdefs.h"
+ #include <sys/types.h> 
+int main() {
+ int8_t a; int16_t b; int32_t c; a = b = c = 1;
+; return 0; }
+EOF
+if { (eval echo configure:6812: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_intxx_t="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   ac_cv_have_intxx_t="no" 
+   
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_have_intxx_t" 1>&6
+if test "x$ac_cv_have_intxx_t" = "xyes" ; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_INTXX_T 1
+EOF
+
+   have_intxx_t=1
+fi
+       
+echo $ac_n "checking for int64_t type""... $ac_c" 1>&6
+echo "configure:6836: checking for int64_t type" >&5
+if eval "test \"`echo '$''{'ac_cv_have_int64_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   cat > conftest.$ac_ext <<EOF
+#line 6842 "configure"
+#include "confdefs.h"
+ #include <sys/types.h> 
+int main() {
+ int64_t a; a = 1;
+; return 0; }
+EOF
+if { (eval echo configure:6849: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_int64_t="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   ac_cv_have_int64_t="no" 
+   
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_have_int64_t" 1>&6
+if test "x$ac_cv_have_int64_t" = "xyes" ; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_INT64_T 1
+EOF
+
+   have_int64_t=1
+fi
+       
+echo $ac_n "checking for u_intXX_t types""... $ac_c" 1>&6
+echo "configure:6873: checking for u_intXX_t types" >&5
+if eval "test \"`echo '$''{'ac_cv_have_u_intxx_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   cat > conftest.$ac_ext <<EOF
+#line 6879 "configure"
+#include "confdefs.h"
+ #include <sys/types.h> 
+int main() {
+ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;
+; return 0; }
+EOF
+if { (eval echo configure:6886: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_u_intxx_t="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   ac_cv_have_u_intxx_t="no" 
+   
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_have_u_intxx_t" 1>&6
+if test "x$ac_cv_have_u_intxx_t" = "xyes" ; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_U_INTXX_T 1
+EOF
+
+   have_u_intxx_t=1
+fi
+
+echo $ac_n "checking for u_int64_t types""... $ac_c" 1>&6
+echo "configure:6910: checking for u_int64_t types" >&5
+if eval "test \"`echo '$''{'ac_cv_have_u_int64_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+   cat > conftest.$ac_ext <<EOF
+#line 6916 "configure"
+#include "confdefs.h"
+ #include <sys/types.h> 
+int main() {
+ u_int64_t a; a = 1;
+; return 0; }
+EOF
+if { (eval echo configure:6923: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_u_int64_t="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   ac_cv_have_u_int64_t="no" 
+   
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_have_u_int64_t" 1>&6
+if test "x$ac_cv_have_u_int64_t" = "xyes" ; then
+   cat >> confdefs.h <<\EOF
+#define HAVE_U_INT64_T 1
+EOF
+
+   have_u_int64_t=1
+fi
+
+if (test -z "$have_u_intxx_t" || test -z "$have_intxx_t" && \
+          test "x$ac_cv_header_sys_bitypes_h" = "xyes")
+then
+   echo $ac_n "checking for intXX_t and u_intXX_t types in sys/bitypes.h""... $ac_c" 1>&6
+echo "configure:6950: checking for intXX_t and u_intXX_t types in sys/bitypes.h" >&5
+   cat > conftest.$ac_ext <<EOF
+#line 6952 "configure"
+#include "confdefs.h"
+ #include <sys/bitypes.h>  
+int main() {
+ int8_t a; int16_t b; int32_t c;
+       u_int8_t e; u_int16_t f; u_int32_t g;
+       a = b = c = e = f = g = 1;  
+; return 0; }
+EOF
+if { (eval echo configure:6961: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   cat >> confdefs.h <<\EOF
+#define HAVE_U_INTXX_T 1
+EOF
+
+       cat >> confdefs.h <<\EOF
+#define HAVE_INTXX_T 1
+EOF
+
+       cat >> confdefs.h <<\EOF
+#define HAVE_SYS_BITYPES_H 1
+EOF
+
+       echo "$ac_t""yes" 1>&6 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   echo "$ac_t""no" 1>&6
+   
+fi
+rm -f conftest* 
+fi
+
+if test -z "$have_u_intxx_t" ; then
+   echo $ac_n "checking for uintXX_t types""... $ac_c" 1>&6
+echo "configure:6988: checking for uintXX_t types" >&5
+if eval "test \"`echo '$''{'ac_cv_have_uintxx_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+      cat > conftest.$ac_ext <<EOF
+#line 6994 "configure"
+#include "confdefs.h"
+ #include <sys/types.h> 
+int main() {
+ uint8_t a; uint16_t b; 
+          uint32_t c; a = b = c = 1; 
+; return 0; }
+EOF
+if { (eval echo configure:7002: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+   ac_cv_have_uintxx_t="yes" 
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+   ac_cv_have_uintxx_t="no" 
+      
+fi
+rm -f conftest*
+   
+fi
+
+echo "$ac_t""$ac_cv_have_uintxx_t" 1>&6
+   if test "x$ac_cv_have_uintxx_t" = "xyes" ; then
+      cat >> confdefs.h <<\EOF
+#define HAVE_UINTXX_T 1
+EOF
+
+   fi
+fi
+
+
+for ac_func in \
+       fork \
+       getcwd \
+       gethostname \
+       getpid \
+       setpgid \
+       setpgrp \
+       setsid \
+       signal \
+       strerror \
+       strncmp \
+       strncpy \
+       vfprintf \
+       
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7042: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7047 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7070: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+echo 'configure: cannot find needed function.'; exit 1
+
+fi
+done
+
+
+for ac_func in fchdir
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7100: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7105 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7128: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ cat >> confdefs.h <<\EOF
+#define HAVE_FCHDIR 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+for ac_func in snprintf vsnprintf
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7159: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7164 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7187: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+for ac_func in localtime_r
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7215: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7220 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7243: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ cat >> confdefs.h <<\EOF
+#define HAVE_LOCALTIME_R 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+for ac_func in readdir_r
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7274: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7279 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7302: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ cat >> confdefs.h <<\EOF
+#define HAVE_READDIR_R 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+# Find where sockets are (especially for Solaris)
+echo $ac_n "checking for socket""... $ac_c" 1>&6
+echo "configure:7332: checking for socket" >&5
+if eval "test \"`echo '$''{'ac_cv_func_socket'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7337 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char socket(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_socket) || defined (__stub___socket)
+choke me
+#else
+socket();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7360: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_socket=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_socket=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'socket`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  echo "$ac_t""using libc's socket" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for socket in -lxnet""... $ac_c" 1>&6
+echo "configure:7378: checking for socket in -lxnet" >&5
+ac_lib_var=`echo xnet'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lxnet  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7386 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:7397: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo xnet | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lxnet $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:7425: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7433 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:7444: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    echo $ac_n "checking for socket in -linet""... $ac_c" 1>&6
+echo "configure:7472: checking for socket in -linet" >&5
+ac_lib_var=`echo inet'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-linet  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7480 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:7491: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo inet | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-linet $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+# If resolver functions are not in libc check for -lnsl or -lresolv.
+echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:7523: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7528 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7551: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  echo "$ac_t""using libc's resolver" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
+echo "configure:7569: checking for gethostbyname in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lnsl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7577 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:7588: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lnsl $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+    echo $ac_n "checking for gethostbyname in -lresolv""... $ac_c" 1>&6
+echo "configure:7616: checking for gethostbyname in -lresolv" >&5
+ac_lib_var=`echo resolv'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lresolv  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7624 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:7635: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo resolv | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lresolv $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+
+echo $ac_n "checking for strftime""... $ac_c" 1>&6
+echo "configure:7667: checking for strftime" >&5
+if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7672 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char strftime(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char strftime();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_strftime) || defined (__stub___strftime)
+choke me
+#else
+strftime();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7695: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+# strftime is in -lintl on SCO UNIX.
+echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6
+echo "configure:7717: checking for strftime in -lintl" >&5
+ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lintl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 7725 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char strftime();
+
+int main() {
+strftime()
+; return 0; }
+EOF
+if { (eval echo configure:7736: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+LIBS="-lintl $LIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:7763: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7768 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7791: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:7815: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7820 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:7843: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:7870: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7875 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:7882: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_header_alloca_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:7903: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7908 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  if HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:7936: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_func_alloca_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+  # that cause trouble.  Some versions do not even contain alloca or
+  # contain a buggy version.  If you still want to use their alloca,
+  # use ar to extract alloca.o from them instead of compiling alloca.c.
+  ALLOCA=alloca.${ac_objext}
+  cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:7968: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 7973 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "webecray" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_os_cray=yes
+else
+  rm -rf conftest*
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+  echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:7998: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 8003 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8026: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+  break
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:8053: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat > conftest.$ac_ext <<EOF
+#line 8061 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+  exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:8080: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_stack_direction=1
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+# getmntent is in -lsun on Irix 4, -lseq on Dynix/PTX, -lgen on Unixware.
+echo $ac_n "checking for getmntent in -lsun""... $ac_c" 1>&6
+echo "configure:8103: checking for getmntent in -lsun" >&5
+ac_lib_var=`echo sun'_'getmntent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsun  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8111 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getmntent();
+
+int main() {
+getmntent()
+; return 0; }
+EOF
+if { (eval echo configure:8122: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="-lsun $LIBS"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for getmntent in -lseq""... $ac_c" 1>&6
+echo "configure:8141: checking for getmntent in -lseq" >&5
+ac_lib_var=`echo seq'_'getmntent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lseq  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8149 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getmntent();
+
+int main() {
+getmntent()
+; return 0; }
+EOF
+if { (eval echo configure:8160: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="-lseq $LIBS"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for getmntent in -lgen""... $ac_c" 1>&6
+echo "configure:8179: checking for getmntent in -lgen" >&5
+ac_lib_var=`echo gen'_'getmntent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgen  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8187 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getmntent();
+
+int main() {
+getmntent()
+; return 0; }
+EOF
+if { (eval echo configure:8198: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="-lgen $LIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+fi
+
+echo $ac_n "checking for getmntent""... $ac_c" 1>&6
+echo "configure:8223: checking for getmntent" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getmntent'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 8228 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getmntent(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getmntent();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getmntent) || defined (__stub___getmntent)
+choke me
+#else
+getmntent();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8251: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getmntent=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getmntent=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getmntent`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_GETMNTENT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether closedir returns void""... $ac_c" 1>&6
+echo "configure:8274: checking whether closedir returns void" >&5
+if eval "test \"`echo '$''{'ac_cv_func_closedir_void'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_closedir_void=yes
+else
+  cat > conftest.$ac_ext <<EOF
+#line 8282 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_header_dirent>
+int closedir(); main() { exit(closedir(opendir(".")) != 0); }
+EOF
+if { (eval echo configure:8288: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_closedir_void=no
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_closedir_void=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_closedir_void" 1>&6
+if test $ac_cv_func_closedir_void = yes; then
+  cat >> confdefs.h <<\EOF
+#define CLOSEDIR_VOID 1
+EOF
+
+fi
+
+echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6
+echo "configure:8311: checking whether setpgrp takes no argument" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 8319 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/*
+ * If this system has a BSD-style setpgrp, which takes arguments, exit
+ * successfully.
+ */
+main()
+{
+    if (setpgrp(1,1) == -1)
+       exit(0);
+    else
+       exit(1);
+}
+
+EOF
+if { (eval echo configure:8339: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_setpgrp_void=no
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_setpgrp_void=yes
+fi
+rm -fr conftest*
+fi
+
+
+fi
+
+echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6
+if test $ac_cv_func_setpgrp_void = yes; then
+  cat >> confdefs.h <<\EOF
+#define SETPGRP_VOID 1
+EOF
+
+fi
+                     echo $ac_n "checking for working fnmatch""... $ac_c" 1>&6
+echo "configure:8362: checking for working fnmatch" >&5
+if eval "test \"`echo '$''{'ac_cv_func_fnmatch_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Some versions of Solaris or SCO have a broken fnmatch function.
+# So we run a test program.  If we are cross-compiling, take no chance.
+# Thanks to John Oleynick and Franc,ois Pinard for this test.
+if test "$cross_compiling" = yes; then
+  ac_cv_func_fnmatch_works=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 8373 "configure"
+#include "confdefs.h"
+main() { exit (fnmatch ("a*", "abc", 0) != 0); }
+EOF
+if { (eval echo configure:8377: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_fnmatch_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_fnmatch_works=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_fnmatch_works" 1>&6
+if test $ac_cv_func_fnmatch_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_FNMATCH 1
+EOF
+
+fi
+
+
+
+echo $ac_n "checking for setlocale in -lxpg4""... $ac_c" 1>&6
+echo "configure:8402: checking for setlocale in -lxpg4" >&5
+ac_lib_var=`echo xpg4'_'setlocale | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lxpg4  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8410 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setlocale();
+
+int main() {
+setlocale()
+; return 0; }
+EOF
+if { (eval echo configure:8421: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lxpg4"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+echo $ac_n "checking for getpwnam in -lsun""... $ac_c" 1>&6
+echo "configure:8444: checking for getpwnam in -lsun" >&5
+ac_lib_var=`echo sun'_'getpwnam | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsun  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8452 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getpwnam();
+
+int main() {
+getpwnam()
+; return 0; }
+EOF
+if { (eval echo configure:8463: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo sun | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lsun $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for deflate in -lz""... $ac_c" 1>&6
+echo "configure:8491: checking for deflate in -lz" >&5
+ac_lib_var=`echo z'_'deflate | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lz  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8499 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char deflate();
+
+int main() {
+deflate()
+; return 0; }
+EOF
+if { (eval echo configure:8510: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  FDLIBS="-lz"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+have_zlib=no
+if test x$FDLIBS = x-lz; then
+  have_zlib=yes
+fi
+
+PTHREAD_LIB=""
+echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6
+echo "configure:8537: checking for pthread_create in -lpthread" >&5
+ac_lib_var=`echo pthread'_'pthread_create | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lpthread  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8545 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_create();
+
+int main() {
+pthread_create()
+; return 0; }
+EOF
+if { (eval echo configure:8556: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  PTHREAD_LIB="-lpthread"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for pthread_create in -lpthreads""... $ac_c" 1>&6
+echo "configure:8575: checking for pthread_create in -lpthreads" >&5
+ac_lib_var=`echo pthreads'_'pthread_create | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lpthreads  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8583 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_create();
+
+int main() {
+pthread_create()
+; return 0; }
+EOF
+if { (eval echo configure:8594: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  PTHREAD_LIB="-lpthreads"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for pthread_create in -lc_r""... $ac_c" 1>&6
+echo "configure:8613: checking for pthread_create in -lc_r" >&5
+ac_lib_var=`echo c_r'_'pthread_create | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lc_r  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 8621 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_create();
+
+int main() {
+pthread_create()
+; return 0; }
+EOF
+if { (eval echo configure:8632: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  PTHREAD_LIB="-lc_r"
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for pthread_create""... $ac_c" 1>&6
+echo "configure:8651: checking for pthread_create" >&5
+if eval "test \"`echo '$''{'ac_cv_func_pthread_create'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 8656 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char pthread_create(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_create();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_pthread_create) || defined (__stub___pthread_create)
+choke me
+#else
+pthread_create();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:8679: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_pthread_create=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_pthread_create=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'pthread_create`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+           
+fi
+
+       
+fi
+
+
+fi
+
+
+
+cat >> confdefs.h <<\EOF
+#define FDLIBS 1
+EOF
+
+
+
+CFLAGS=${CFLAGS--O}
+LDFLAGS=${LDFLAGS--O}
+LIBS="${LIBS} ${SQL_LFLAGS}"
+
+CPPFLAGS="$CPPFLAGS"
+
+
+
+
+
+
+
+
+
+
+
+OBJLIST=
+
+
+lld="lld"
+llu="llu"
+
+#
+# Finally we set appropriate distribution specific
+#  variables and defaults
+#
+# PFILES are platform specific files
+PFILES="platforms/Makefile"
+PSCMD="ps -e"
+WIN32=
+hostname=`hostname`
+case "$DISTNAME" in
+alpha)
+       DISTVER=`uname -r`
+       PTHREAD_LIB="-lpthread -lexc"
+       if test "${CC}" = "gcc" ; then
+          lld="lld"
+          llu="llu"
+       else
+          lld="ld"
+          llu="lu"
+       fi
+       TAPEDRIVE="/dev/nrmt0"
+  ;;
+bsdi)
+       DISTVER=`uname -a |awk '{print $3}'`
+       TAPEDRIVE="/dev/nrst0"
+  ;;
+caldera)
+       DISTVER=`cat /etc/.issue | grep Version | cut -f 2 -d ' '`
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+cygwin)
+       DISTVER=`uname -a |awk '{print $3}'`
+       TAPEDRIVE="/dev/nrst0"
+       WIN32=win32
+       CFLAGS="${CFLAGS} -mwindows"
+       LDFLAGS="${LDFLAGS} -mwindows"
+  ;;
+debian)
+       DISTVER=`cat /etc/debian_version`
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+freebsd)
+       DISTVER=`uname -a |awk '{print $3}'`
+       PTHREAD_LIB="-pthread"
+       CFLAGS="${CFLAGS} -pthread"
+       lld="qd"
+       llu="qu"
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -x -o pid,command"
+       PFILES="${PFILES} \
+           platforms/freebsd/Makefile \
+           platforms/freebsd/bacula-fd \
+           platforms/freebsd/bacula-sd \
+           platforms/freebsd/bacula-dir"
+       hostname=`hostname -s`
+  ;;
+hpux)
+       DISTVER=`uname -r`
+       TAPEDRIVE="/dev/rmt/0hnb"
+  ;;
+netbsd)
+       DISTVER=`uname -a |awk '{print $3}'`
+       lld="qd"
+       llu="qu"
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -a -o pid,command"
+  ;;
+openbsd)
+       DISTVER=`uname -a |awk '{print $3}'`
+       lld="qd"
+       llu="qu"
+       TAPEDRIVE="/dev/nrst0"
+       PSCMD="ps -a -o pid,command"
+  ;;
+redhat)
+       DISTVER=`cat /etc/redhat-release | grep release |\
+                               cut -f 5 -d ' '`
+       TAPEDRIVE="/dev/nst0"
+       PSCMD="ps -e -o pid,command"
+       PFILES="${PFILES} \
+           platforms/redhat/Makefile \
+           platforms/redhat/bacula-fd \
+           platforms/redhat/bacula-sd \
+           platforms/redhat/bacula-dir"
+       hostname=`hostname -s`
+  ;;
+slackware)
+       DISTVER=`cat /etc/slackware-version`
+       TAPEDRIVE="/dev/nst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+solaris)
+       DISTVER=Solaris
+       TAPEDRIVE="/dev/rmt/0cbn"
+       PSCMD="ps -e -o pid,comm"
+       PFILES="${PFILES} \
+           platforms/solaris/Makefile \
+           platforms/solaris/bacula-fd \
+           platforms/solaris/bacula-sd \
+           platforms/solaris/bacula-dir"
+  ;;
+suse)
+       DISTVER=`cat /etc/SuSE-release |grep VERSION|\
+                               cut -f 3 -d ' '`
+       TAPEDRIVE="/dev/nst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+suse5)
+       DISTNAME=suse
+       DISTVER=5.x
+       TAPEDRIVE="/dev/nst0"
+       PSCMD="ps -e -o pid,command"
+       hostname=`hostname -s`
+  ;;
+unknown)
+       DISTVER=unknown
+       TAPEDRIVE="/dev/nst0"
+  ;;
+*)
+  echo " === Something went wrong. Unknown DISTNAME $DISTNAME ==="
+  ;;
+esac  
+
+
+
+
+LIBS="$PTHREAD_LIB $LIBS"
+
+cat >> confdefs.h <<EOF
+#define lld "$lld"
+EOF
+
+cat >> confdefs.h <<EOF
+#define llu "$llu"
+EOF
+
+
+
+
+
+
+
+
+MCOMMON=./autoconf/Make.common
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "autoconf/Make.common \
+          Makefile \
+          startmysql \
+          stopmysql \
+          btraceback \
+          startit \
+          stopit \
+          bacula \
+          fd \
+          doc/Makefile \
+          src/Makefile \
+          src/console/Makefile \
+          src/console/console.conf \
+          src/gnome-console/Makefile \
+          src/gnome-console/gnome-console.conf \
+          src/dird/Makefile \
+          src/dird/bacula-dir.conf \
+          src/lib/Makefile \
+          src/stored/Makefile \
+          src/stored/bacula-sd.conf \
+          src/filed/Makefile \
+          src/filed/bacula-fd.conf \
+          src/filed/win32/Makefile \
+          src/cats/Makefile \
+          src/cats/make_mysql_tables \
+          src/cats/drop_mysql_tables \
+          src/cats/create_mysql_database \
+          src/cats/grant_mysql_privileges \
+          src/cats/make_sqlite_tables \
+          src/cats/sqlite \
+          src/findlib/Makefile \
+          $PFILES  src/config.h:autoconf/config.h.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@BUILD_DIR@%$BUILD_DIR%g
+s%@TRUEPRG@%$TRUEPRG%g
+s%@FALSEPRG@%$FALSEPRG%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@VERSION@%$VERSION%g
+s%@DATE@%$DATE%g
+s%@LSMDATE@%$LSMDATE%g
+s%@CC@%$CC%g
+s%@CXX@%$CXX%g
+s%@CPP@%$CPP%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@RANLIB@%$RANLIB%g
+s%@MV@%$MV%g
+s%@RM@%$RM%g
+s%@CP@%$CP%g
+s%@SED@%$SED%g
+s%@AWK@%$AWK%g
+s%@ECHO@%$ECHO%g
+s%@CMP@%$CMP%g
+s%@TBL@%$TBL%g
+s%@AR@%$AR%g
+s%@OPENSSL@%$OPENSSL%g
+s%@ARFLAGS@%$ARFLAGS%g
+s%@MAKE_SHELL@%$MAKE_SHELL%g
+s%@LOCAL_LIBS@%$LOCAL_LIBS%g
+s%@LOCAL_CFLAGS@%$LOCAL_CFLAGS%g
+s%@LOCAL_LDFLAGS@%$LOCAL_LDFLAGS%g
+s%@LOCAL_DEFS@%$LOCAL_DEFS%g
+s%@HAVE_SUN_OS_TRUE@%$HAVE_SUN_OS_TRUE%g
+s%@HAVE_SUN_OS_FALSE@%$HAVE_SUN_OS_FALSE%g
+s%@HAVE_OSF1_OS_TRUE@%$HAVE_OSF1_OS_TRUE%g
+s%@HAVE_OSF1_OS_FALSE@%$HAVE_OSF1_OS_FALSE%g
+s%@HAVE_AIX_OS_TRUE@%$HAVE_AIX_OS_TRUE%g
+s%@HAVE_AIX_OS_FALSE@%$HAVE_AIX_OS_FALSE%g
+s%@HAVE_HPUX_OS_TRUE@%$HAVE_HPUX_OS_TRUE%g
+s%@HAVE_HPUX_OS_FALSE@%$HAVE_HPUX_OS_FALSE%g
+s%@HAVE_LINUX_OS_TRUE@%$HAVE_LINUX_OS_TRUE%g
+s%@HAVE_LINUX_OS_FALSE@%$HAVE_LINUX_OS_FALSE%g
+s%@HAVE_FREEBSD_OS_TRUE@%$HAVE_FREEBSD_OS_TRUE%g
+s%@HAVE_FREEBSD_OS_FALSE@%$HAVE_FREEBSD_OS_FALSE%g
+s%@HAVE_NETBSD_OS_TRUE@%$HAVE_NETBSD_OS_TRUE%g
+s%@HAVE_NETBSD_OS_FALSE@%$HAVE_NETBSD_OS_FALSE%g
+s%@HAVE_OPENBSD_OS_TRUE@%$HAVE_OPENBSD_OS_TRUE%g
+s%@HAVE_OPENBSD_OS_FALSE@%$HAVE_OPENBSD_OS_FALSE%g
+s%@HAVE_BSDI_OS_TRUE@%$HAVE_BSDI_OS_TRUE%g
+s%@HAVE_BSDI_OS_FALSE@%$HAVE_BSDI_OS_FALSE%g
+s%@HAVE_SGI_OS_TRUE@%$HAVE_SGI_OS_TRUE%g
+s%@HAVE_SGI_OS_FALSE@%$HAVE_SGI_OS_FALSE%g
+s%@INSIDE_GNOME_COMMON_TRUE@%$INSIDE_GNOME_COMMON_TRUE%g
+s%@INSIDE_GNOME_COMMON_FALSE@%$INSIDE_GNOME_COMMON_FALSE%g
+s%@MSGFMT@%$MSGFMT%g
+s%@GNOME_LIBS@%$GNOME_LIBS%g
+s%@GNOMEUI_LIBS@%$GNOMEUI_LIBS%g
+s%@GNOMEGNORBA_LIBS@%$GNOMEGNORBA_LIBS%g
+s%@GTKXMHTML_LIBS@%$GTKXMHTML_LIBS%g
+s%@ZVT_LIBS@%$ZVT_LIBS%g
+s%@GNOME_LIBDIR@%$GNOME_LIBDIR%g
+s%@GNOME_INCLUDEDIR@%$GNOME_INCLUDEDIR%g
+s%@GNOME_CONFIG@%$GNOME_CONFIG%g
+s%@ORBIT_CONFIG@%$ORBIT_CONFIG%g
+s%@ORBIT_IDL@%$ORBIT_IDL%g
+s%@HAVE_ORBIT_TRUE@%$HAVE_ORBIT_TRUE%g
+s%@HAVE_ORBIT_FALSE@%$HAVE_ORBIT_FALSE%g
+s%@ORBIT_CFLAGS@%$ORBIT_CFLAGS%g
+s%@ORBIT_LIBS@%$ORBIT_LIBS%g
+s%@HAVE_GNORBA_TRUE@%$HAVE_GNORBA_TRUE%g
+s%@HAVE_GNORBA_FALSE@%$HAVE_GNORBA_FALSE%g
+s%@GNORBA_CFLAGS@%$GNORBA_CFLAGS%g
+s%@GNORBA_LIBS@%$GNORBA_LIBS%g
+s%@GNOME_APPLETS_LIBS@%$GNOME_APPLETS_LIBS%g
+s%@GNOME_DOCKLETS_LIBS@%$GNOME_DOCKLETS_LIBS%g
+s%@GNOME_CAPPLET_LIBS@%$GNOME_CAPPLET_LIBS%g
+s%@GNOME_DIR@%$GNOME_DIR%g
+s%@CONS_INC@%$CONS_INC%g
+s%@CONS_LIBS@%$CONS_LIBS%g
+s%@CONS_LDFLAGS@%$CONS_LDFLAGS%g
+s%@READLINE_SRC@%$READLINE_SRC%g
+s%@TERMCAP_LIB@%$TERMCAP_LIB%g
+s%@GMP_INC@%$GMP_INC%g
+s%@GMP_LIBS@%$GMP_LIBS%g
+s%@GMP_LDFLAGS@%$GMP_LDFLAGS%g
+s%@GMP_SRC@%$GMP_SRC%g
+s%@CWEB_INC@%$CWEB_INC%g
+s%@CWEB_LIBS@%$CWEB_LIBS%g
+s%@CWEB_LDFLAGS@%$CWEB_LDFLAGS%g
+s%@CWEB_SRC@%$CWEB_SRC%g
+s%@working_dir@%$working_dir%g
+s%@dump_email@%$dump_email%g
+s%@job_email@%$job_email%g
+s%@smtp_host@%$smtp_host%g
+s%@piddir@%$piddir%g
+s%@subsysdir@%$subsysdir%g
+s%@baseport@%$baseport%g
+s%@dir_port@%$dir_port%g
+s%@fd_port@%$fd_port%g
+s%@sd_port@%$sd_port%g
+s%@dir_password@%$dir_password%g
+s%@fd_password@%$fd_password%g
+s%@sd_password@%$sd_password%g
+s%@cats@%$cats%g
+s%@SQL_LFLAGS@%$SQL_LFLAGS%g
+s%@SQL_INCLUDE@%$SQL_INCLUDE%g
+s%@SQL_BINDIR@%$SQL_BINDIR%g
+s%@EXEEXT@%$EXEEXT%g
+s%@X_CFLAGS@%$X_CFLAGS%g
+s%@X_PRE_LIBS@%$X_PRE_LIBS%g
+s%@X_LIBS@%$X_LIBS%g
+s%@X_EXTRA_LIBS@%$X_EXTRA_LIBS%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@ALLOCA@%$ALLOCA%g
+s%@FDLIBS@%$FDLIBS%g
+s%@DEBUG@%$DEBUG%g
+s%@DINCLUDE@%$DINCLUDE%g
+s%@DLIB@%$DLIB%g
+s%@OBJLIST@%$OBJLIST%g
+s%@hostname@%$hostname%g
+s%@TAPEDRIVE@%$TAPEDRIVE%g
+s%@PSCMD@%$PSCMD%g
+s%@WIN32@%$WIN32%g
+s%@DISTNAME@%$DISTNAME%g
+s%@DISTVER@%$DISTVER%g
+/@MCOMMON@/r $MCOMMON
+s%@MCOMMON@%%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"autoconf/Make.common \
+          Makefile \
+          startmysql \
+          stopmysql \
+          btraceback \
+          startit \
+          stopit \
+          bacula \
+          fd \
+          doc/Makefile \
+          src/Makefile \
+          src/console/Makefile \
+          src/console/console.conf \
+          src/gnome-console/Makefile \
+          src/gnome-console/gnome-console.conf \
+          src/dird/Makefile \
+          src/dird/bacula-dir.conf \
+          src/lib/Makefile \
+          src/stored/Makefile \
+          src/stored/bacula-sd.conf \
+          src/filed/Makefile \
+          src/filed/bacula-fd.conf \
+          src/filed/win32/Makefile \
+          src/cats/Makefile \
+          src/cats/make_mysql_tables \
+          src/cats/drop_mysql_tables \
+          src/cats/create_mysql_database \
+          src/cats/grant_mysql_privileges \
+          src/cats/make_sqlite_tables \
+          src/cats/sqlite \
+          src/findlib/Makefile \
+          $PFILES "}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([  ]*\)#\([        ]*define[       ][      ]*\)'
+ac_dB='\([     ][      ]*\)[^  ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_uB='\([     ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="src/config.h:autoconf/config.h.in"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[   ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+(echo "Doing make of dependencies"; make depend;) 
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+chmod 755 startmysql stopmysql bacula startit stopit btraceback
+cp -f startit stopit btraceback btraceback.gdb src/console
+cp -f startit stopit btraceback btraceback.gdb src/dird
+cp -f startit stopit btraceback btraceback.gdb src/filed
+cp -f startit stopit btraceback btraceback.gdb src/lib
+cp -f startit stopit btraceback btraceback.gdb src/stored
+chmod 755 src/cats/make_mysql_tables src/cats/drop_mysql_tables
+chmod 755 src/cats/make_test_tables src/cats/drop_test_tables
+chmod 755 src/cats/create_mysql_database
+chmod 755 src/cats/grant_mysql_privileges
+chmod 755 src/cats/make_sqlite_tables 
+chmod 755 src/cats/sqlite
+
+
+echo "
+Configuration:
+
+  Host:                      ${DISTNAME} ${DISTVER}
+  Bacula version:            ${VERSION} (${DATE})
+  Source code location:       ${srcdir}
+  Install binaries:          ${sbindir}
+  Install config files:       ${sysconfdir}
+  C Compiler:                ${CC}
+  C++ Compiler:              ${CXX}
+  Compiler flags:            ${CFLAGS} 
+  Linker flags:              ${LDFLAGS}
+  Libraries:                 ${LIBS}
+  Database found:            ${have_db}
+  Database type:             ${db_name}
+
+  Job Output Email:          ${job_email}
+  Traceback Email:           ${dump_email}
+  SMTP Host Address:         ${smtp_host}
+  Director Port              ${dir_port}
+  File daemon Port           ${fd_port}
+  Storage daemon Port        ${sd_port}
+  Working directory          ${working_dir}
+  SQL binaries Directory      ${SQL_BINDIR}
+
+  readline support:          ${got_readline} ${READLINE_SRC}
+  cweb support:              ${got_cweb} ${CWEB_SRC}
+  TCP Wrappers support:       ${TCPW_MSG}
+  ZLIB support:              ${have_zlib}
+  enable-smartalloc:         ${support_smartalloc} 
+  enable-gnome:              ${support_gnome}
+  gmp support:               ${got_gmp} ${GMP_SRC}
+
+  "
diff --git a/bacula/intl/ChangeLog b/bacula/intl/ChangeLog
new file mode 100644 (file)
index 0000000..1989501
--- /dev/null
@@ -0,0 +1,1086 @@
+1998-04-29  Ulrich Drepper  <drepper@cygnus.com>
+
+       * intl/localealias.c (read_alias_file): Use unsigned char for
+       local variables.  Remove unused variable tp.
+       * intl/l10nflist.c (_nl_normalize_codeset): Use unsigned char *
+       for type of codeset.  For loosing Solaris systems.
+       * intl/loadinfo.h: Adapt prototype of _nl_normalize_codeset.
+       * intl/bindtextdom.c (BINDTEXTDOMAIN): Don't define local variable
+       len if not needed.
+       Patches by Jim Meyering.
+
+1998-04-28  Ulrich Drepper  <drepper@cygnus.com>
+
+       * loadmsgcat.c (_nl_load_domain): Don't assign the element use_mmap if
+       mmap is not supported.
+
+       * hash-string.h: Don't include <values.h>.
+
+1998-04-27  Ulrich Drepper  <drepper@cygnus.com>
+
+       * textdomain.c: Use strdup is available.
+
+       * localealias.c: Define HAVE_MEMPCPY so that we can use this
+       function.  Define and use semapahores to protect modfication of
+       global objects when compiling for glibc.  Add code to allow
+       freeing alias table.
+
+       * l10nflist.c: Don't assume stpcpy not being a macro.
+
+       * gettextP.h: Define internal_function macri if not already done.
+       Use glibc byte-swap macros instead of defining SWAP when compiled
+       for glibc.
+       (struct loaded_domain): Add elements to allow unloading.
+
+       * Makefile.in (distclean): Don't remove libintl.h here.
+
+       * bindtextdomain.c: Carry over changes from glibc.  Use strdup if
+       available.
+
+       * dcgettext.c: Don't assume stpcpy not being a macro.  Mark internal
+       functions.  Add memory freeing code for glibc.
+
+       * dgettext.c: Update copyright.
+
+       * explodename.c: Include stdlib.h and string.h only if they exist.
+       Use strings.h eventually.
+
+       * finddomain.c: Mark internal functions.  Use strdup if available.
+       Add memory freeing code for glibc.
+
+1997-10-10 20:00  Ulrich Drepper  <drepper@cygnus.com>
+
+       * libgettext.h: Fix dummy textdomain and bindtextdomain macros.
+       They should return reasonable values.
+       Reported by Tom Tromey <tromey@cygnus.com>.
+
+1997-09-16 03:33  Ulrich Drepper  <drepper@cygnus.com>
+
+       * libgettext.h: Define PARAMS also to `args' if __cplusplus is defined.
+       * intlh.inst.in: Likewise.
+       Reported by Jean-Marc Lasgouttes <Jean-Marc.Lasgouttes@inria.fr>.
+
+       * libintl.glibc: Update from current glibc version.
+
+1997-09-06 02:10  Ulrich Drepper  <drepper@cygnus.com>
+
+       * intlh.inst.in: Reformat copyright.
+
+1997-08-19 15:22  Ulrich Drepper  <drepper@cygnus.com>
+
+       * dcgettext.c (DCGETTEXT): Remove wrong comment.
+
+1997-08-16 00:13  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (install-data): Don't change directory to install.
+
+1997-08-01 14:30  Ulrich Drepper  <drepper@cygnus.com>
+
+       * cat-compat.c: Fix copyright.
+
+       * localealias.c: Don't define strchr unless !HAVE_STRCHR.
+
+       * loadmsgcat.c: Update copyright.  Fix typos.
+
+       * l10nflist.c: Don't define strchr unless !HAVE_STRCHR.
+       (_nl_make_l10nflist): Handle sponsor and revision correctly.
+
+       * gettext.c: Update copyright.
+       * gettext.h: Likewise.
+       * hash-string.h: Likewise.
+
+       * finddomain.c: Remoave dead code.  Define strchr only if
+       !HAVE_STRCHR.
+
+       * explodename.c: Include <sys/types.h>.
+
+       * explodename.c: Reformat copyright text.
+       (_nl_explode_name): Fix typo.
+
+       * dcgettext.c: Define and use __set_errno.
+       (guess_category_value): Don't use setlocale if HAVE_LC_MESSAGES is
+       not defined.
+
+       * bindtextdom.c: Pretty printing.
+
+1997-05-01 02:25  Ulrich Drepper  <drepper@cygnus.com>
+
+       * dcgettext.c (guess_category_value): Don't depend on
+       HAVE_LC_MESSAGES.  We don't need the macro here.
+       Patch by Bruno Haible <haible@ilog.fr>.
+
+       * cat-compat.c (textdomain): DoN't refer to HAVE_SETLOCALE_NULL
+       macro.  Instead use HAVE_LOCALE_NULL and define it when using
+       glibc, as in dcgettext.c.
+       Patch by Bruno Haible <haible@ilog.fr>.
+
+       * Makefile.in (CPPFLAGS): New variable.  Reported by Franc,ois
+       Pinard.
+
+Mon Mar 10 06:51:17 1997  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in: Implement handling of libtool.
+
+       * gettextP.h: Change data structures for use of generic lowlevel
+       i18n file handling.
+
+Wed Dec  4 20:21:18 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * textdomain.c: Put parentheses around arguments of memcpy macro
+       definition.
+       * localealias.c: Likewise.
+       * l10nflist.c: Likewise.
+       * finddomain.c: Likewise.
+       * bindtextdom.c: Likewise.
+       Reported by Thomas Esken.
+
+Mon Nov 25 22:57:51 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * textdomain.c: Move definition of `memcpy` macro to right
+       position.
+
+Fri Nov 22 04:01:58 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * finddomain.c [!HAVE_STRING_H && !_LIBC]: Define memcpy using
+       bcopy if not already defined.  Reported by Thomas Esken.
+       * bindtextdom.c: Likewise.
+       * l10nflist.c: Likewise.
+       * localealias.c: Likewise.
+       * textdomain.c: Likewise.
+
+Tue Oct 29 11:10:27 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (libdir): Change to use exec_prefix instead of
+       prefix.  Reported by Knut-HÃ¥vardAksnes <etokna@eto.ericsson.se>.
+
+Sat Aug 31 03:07:09 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c (_nl_normalize_codeset): We convert to lower case,
+       so don't prepend uppercase `ISO' for only numeric arg.
+
+Fri Jul 19 00:15:46 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c: Move inclusion of argz.h, ctype.h, stdlib.h after
+       definition of _GNU_SOURCE.  Patch by Roland McGrath.
+
+       * Makefile.in (uninstall): Fix another bug with `for' loop and
+       empty arguments.  Patch by Jim Meyering.  Correct name os
+       uninstalled files: no intl- prefix anymore.
+
+       * Makefile.in (install-data): Again work around shells which
+       cannot handle mpty for list.  Reported by Jim Meyering.
+
+Sat Jul 13 18:11:35 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (install): Split goal.  Now depend on install-exec
+        and install-data.
+       (install-exec, install-data): New goals.  Created from former
+       install goal.
+       Reported by Karl Berry.
+
+Sat Jun 22 04:58:14 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (MKINSTALLDIRS): New variable.  Path to
+        mkinstalldirs script.
+       (install): use MKINSTALLDIRS variable or if the script is not present
+       try to find it in the $top_scrdir).
+
+Wed Jun 19 02:56:56 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c: Linux libc *partly* includes the argz_* functions.
+       Grr.  Work around by renaming the static version and use macros
+       for renaming.
+
+Tue Jun 18 20:11:17 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c: Correct presence test macros of __argz_* functions.
+
+       * l10nflist.c: Include <argz.h> based on test of it instead when
+       __argz_* functions are available.
+       Reported by Andreas Schwab.
+
+Thu Jun 13 15:17:44 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * explodename.c, l10nflist.c: Define NULL for dumb systems.
+
+Tue Jun 11 17:05:13 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * intlh.inst.in, libgettext.h (dcgettext): Rename local variable
+       result to __result to prevent name clash.
+
+       * l10nflist.c, localealias.c, dcgettext.c: Define _GNU_SOURCE to
+        get prototype for stpcpy and strcasecmp.
+
+       * intlh.inst.in, libgettext.h: Move declaration of
+       `_nl_msg_cat_cntr' outside __extension__ block to prevent warning
+       from gcc's -Wnested-extern option.
+
+Fri Jun  7 01:58:00 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (install): Remove comment.
+
+Thu Jun  6 17:28:17 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (install): Work around for another Buglix stupidity.
+       Always use an `else' close for `if's.  Reported by Nelson Beebe.
+
+       * Makefile.in (intlh.inst): Correct typo in phony rule.
+       Reported by Nelson Beebe.
+
+Thu Jun  6 01:49:52 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * dcgettext.c (read_alias_file): Rename variable alloca_list to
+       block_list as the macro calls assume.
+       Patch by Eric Backus.
+
+       * localealias.c [!HAVE_ALLOCA]: Define alloca as macro using
+        malloc.
+       (read_alias_file): Rename varriabe alloca_list to block_list as the
+       macro calls assume.
+       Patch by Eric Backus.
+
+       * l10nflist.c: Correct conditional for <argz.h> inclusion.
+       Reported by Roland McGrath.
+
+       * Makefile.in (all): Depend on all-@USE_INCLUDED_LIBINTL@, not
+        all-@USE_NLS@.
+
+       * Makefile.in (install): intlh.inst comes from local dir, not
+        $(srcdir).
+
+       * Makefile.in (intlh.inst): Special handling of this goal.  If
+       used in gettext, this is really a rul to construct this file.  If
+       used in any other package it is defined as a .PHONY rule with
+       empty body.
+
+       * finddomain.c: Extract locale file information handling into
+       l10nfile.c.  Rename local stpcpy__ function to stpcpy.
+
+       * dcgettext.c (stpcpy): Add local definition.
+
+       * l10nflist.c: Solve some portability problems.  Patches partly by
+       Thomas Esken.  Add local definition of stpcpy.
+
+Tue Jun  4 02:47:49 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * intlh.inst.in: Don't depend including <locale.h> on
+       HAVE_LOCALE_H.  Instead configure must rewrite this fiile
+       depending on the result of the configure run.
+
+       * Makefile.in (install): libintl.inst is now called intlh.inst.
+       Add rules for updating intlh.inst from intlh.inst.in.
+
+       * libintl.inst: Renamed to intlh.inst.in.
+
+       * localealias.c, dcgettext.c [__GNUC__]: Define HAVE_ALLOCA to 1
+        because gcc has __buitlin_alloca.
+       Reported by Roland McGrath.
+
+Mon Jun  3 00:32:16 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (installcheck): New goal to fulfill needs of
+        automake's distcheck.
+
+       * Makefile.in (install): Reorder commands so that VERSION is
+        found.
+
+       * Makefile.in (gettextsrcdir): Now use subdirectory intl/ in
+        @datadir@/gettext.
+       (COMSRCS): Add l10nfile.c.
+       (OBJECTS): Add l10nfile.o.
+       (DISTFILES): Rename to DISTFILE.normal.  Remove $(DISTFILES.common).
+       (DISTFILE.gettext): Remove $(DISTFILES.common).
+       (all-gettext): Remove goal.
+       (install): If $(PACKAGE) = gettext install, otherwose do nothing.  No
+       package but gettext itself should install libintl.h + headers.
+       (dist): Extend goal to work for gettext, too.
+       (dist-gettext): Remove goal.
+
+       * dcgettext.c [!HAVE_ALLOCA]: Define macro alloca by using malloc.
+
+Sun Jun  2 17:33:06 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * loadmsgcat.c (_nl_load_domain): Parameter is now comes from
+        find_l10nfile.
+
+Sat Jun  1 02:23:03 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c (__argz_next): Add definition.
+
+       * dcgettext.c [!HAVE_ALLOCA]: Add code for handling missing alloca
+       code.  Use new l10nfile handling.
+
+       * localealias.c [!HAVE_ALLOCA]: Add code for handling missing
+        alloca code.
+
+       * l10nflist.c: Initial revision.
+
+Tue Apr  2 18:51:18 1996  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (all-gettext): New goal.  Same as all-yes.
+
+Thu Mar 28 23:01:22 1996  Karl Eichwalder  <ke@ke.central.de>
+
+       * Makefile.in (gettextsrcdir): Define using @datadir@.
+
+Tue Mar 26 12:39:14 1996  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c: Include <ctype.h>.  Reported by Roland McGrath.
+
+Sat Mar 23 02:00:35 1996  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (stpcpy): Rename to stpcpy__ to prevent clashing
+        with external declaration.
+
+Sat Mar  2 00:47:09 1996  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (all-no): Rename from all_no.
+
+Sat Feb 17 00:25:59 1996  Ulrich Drepper  <drepper@myware>
+
+       * gettextP.h [loaded_domain]: Array `successor' must now contain up
+        to 63 elements (because of codeset name normalization).
+
+       * finddomain.c: Implement codeset name normalization.
+
+Thu Feb 15 04:39:09 1996  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (all): Define to `all-@USE_NLS@'.
+       (all-yes, all_no): New goals.  `all-no' is noop, `all-yes'
+       is former all.
+
+Mon Jan 15 21:46:01 1996  Howard Gayle  <howard@hal.com>
+
+       * localealias.c (alias_compare): Increment string pointers in loop
+        of strcasecmp replacement.
+
+Fri Dec 29 21:16:34 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (install-src): Who commented this goal out ? :-)
+
+Fri Dec 29 15:08:16 1995  Ulrich Drepper  <drepper@myware>
+
+       * dcgettext.c (DCGETTEXT): Save `errno'.  Failing system calls
+       should not effect it because a missing catalog is no error.
+       Reported by Harald K<o:>nig <koenig@tat.physik.uni-tuebingen.de>.
+
+Tue Dec 19 22:09:13 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (Makefile): Explicitly use $(SHELL) for running
+        shell scripts.
+
+Fri Dec 15 17:34:59 1995  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+       * Makefile.in (install-src): Only install library and header when
+       we use the own implementation.  Don't do it when using the
+       system's gettext or catgets functions.
+
+       * dcgettext.c (find_msg): Must not swap domain->hash_size here.
+
+Sat Dec  9 16:24:37 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c, libintl.inst, libgettext.h, hash-string.h,
+       gettextP.h, finddomain.c, dcgettext.c, cat-compat.c:
+       Use PARAMS instead of __P.  Suggested by Roland McGrath.
+
+Tue Dec  5 11:39:14 1995  Larry Schwimmer  <rosebud@cyclone.stanford.edu>
+
+       * libgettext.h: Use `#if !defined (_LIBINTL_H)' instead of `#if
+       !_LIBINTL_H' because Solaris defines _LIBINTL_H as empty.
+
+Mon Dec  4 15:42:07 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (install-src):
+       Install libintl.inst instead of libintl.h.install.
+
+Sat Dec  2 22:51:38 1995  Marcus Daniels  <marcus@sysc.pdx.edu>
+
+       * cat-compat.c (textdomain):
+       Reverse order in which files are tried you load.  First
+       try local file, when this failed absolute path.
+
+Wed Nov 29 02:03:53 1995  Nelson H. F. Beebe  <beebe@math.utah.edu>
+
+       * cat-compat.c (bindtextdomain): Add missing { }.
+
+Sun Nov 26 18:21:41 1995  Ulrich Drepper  <drepper@myware>
+
+       * libintl.inst: Add missing __P definition.  Reported by Nelson Beebe.
+
+       * Makefile.in:
+       Add dummy `all' and `dvi' goals.  Reported by Tom Tromey.
+
+Sat Nov 25 16:12:01 1995  Franc,ois Pinard  <pinard@iro.umontreal.ca>
+
+       * hash-string.h: Capitalize arguments of macros.
+
+Sat Nov 25 12:01:36 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES): Prevent files names longer than 13
+       characters.  libintl.h.glibc->libintl.glibc,
+       libintl.h.install->libintl.inst.  Reported by Joshua R. Poulson.
+
+Sat Nov 25 11:31:12 1995  Eric Backus  <ericb@lsid.hp.com>
+
+       * dcgettext.c: Fix bug in preprocessor conditionals.
+
+Sat Nov 25 02:35:27 1995  Nelson H. F. Beebe  <beebe@math.utah.edu>
+
+       * libgettext.h: Solaris cc does not understand
+        #if !SYMBOL1 && !SYMBOL2.  Sad but true.
+
+Thu Nov 23 16:22:14 1995  Ulrich Drepper  <drepper@myware>
+
+       * hash-string.h (hash_string):
+       Fix for machine with >32 bit `unsigned long's.
+
+       * dcgettext.c (DCGETTEXT):
+       Fix horrible bug in loop for alternative translation.
+
+Thu Nov 23 01:45:29 1995  Ulrich Drepper  <drepper@myware>
+
+       * po2tbl.sed.in, linux-msg.sed, xopen-msg.sed:
+       Some further simplifications in message number generation.
+
+Mon Nov 20 21:08:43 1995  Ulrich Drepper  <drepper@myware>
+
+       * libintl.h.glibc: Use __const instead of const in prototypes.
+
+       * Makefile.in (install-src):
+       Install libintl.h.install instead of libintl.h.  This
+       is a stripped-down version.  Suggested by Peter Miller.
+
+       * libintl.h.install, libintl.h.glibc: Initial revision.
+
+       * localealias.c (_nl_expand_alias, read_alias_file):
+       Protect prototypes in type casts by __P.
+
+Tue Nov 14 16:43:58 1995  Ulrich Drepper  <drepper@myware>
+
+       * hash-string.h: Correct prototype for hash_string.
+
+Sun Nov 12 12:42:30 1995  Ulrich Drepper  <drepper@myware>
+
+       * hash-string.h (hash_string): Add prototype.
+
+       * gettextP.h: Fix copyright.
+       (SWAP): Add prototype.
+
+Wed Nov  8 22:56:33 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c (read_alias_file): Forgot sizeof.
+       Avoid calling *printf function.  This introduces a big overhead.
+       Patch by Roland McGrath.
+
+Tue Nov  7 14:21:08 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c, cat-compat.c: Wrong indentation in #if for stpcpy.
+
+       * finddomain.c (stpcpy):
+       Define substitution function local.  The macro was to flaky.
+
+       * cat-compat.c: Fix typo.
+
+       * xopen-msg.sed, linux-msg.sed:
+       While bringing message number to right place only accept digits.
+
+       * linux-msg.sed, xopen-msg.sed: Now that the counter does not have
+       leading 0s we don't need to remove them.  Reported by Marcus
+       Daniels.
+
+       * Makefile.in (../po/cat-id-tbl.o): Use $(top_srdir) in
+       dependency.  Reported by Marcus Daniels.
+
+       * cat-compat.c: (stpcpy) [!_LIBC && !HAVE_STPCPY]: Define replacement.
+       Generally cleanup using #if instead of #ifndef.
+
+       * Makefile.in: Correct typos in comment.  By Franc,ois Pinard.
+
+Mon Nov  6 00:27:02 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (install-src): Don't install libintl.h and libintl.a
+       if we use an available gettext implementation.
+
+Sun Nov  5 22:02:08 1995  Ulrich Drepper  <drepper@myware>
+
+       * libgettext.h: Fix typo: HAVE_CATGETTS -> HAVE_CATGETS.  Reported
+       by Franc,ois Pinard.
+
+       * libgettext.h: Use #if instead of #ifdef/#ifndef.
+
+       * finddomain.c:
+       Comments describing what has to be done should start with FIXME.
+
+Sun Nov  5 19:38:01 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES): Split.  Use DISTFILES with normal meaning.
+       DISTFILES.common names the files common to both dist goals.
+       DISTFILES.gettext are the files only distributed in GNU gettext.
+
+Sun Nov  5 17:32:54 1995  Ulrich Drepper  <drepper@myware>
+
+       * dcgettext.c (DCGETTEXT): Correct searching in derived locales.
+       This was necessary since a change in _nl_find_msg several weeks
+       ago.  I really don't know this is still not fixed.
+
+Sun Nov  5 12:43:12 1995  Ulrich Drepper  <drepper@myware>
+
+       * loadmsgcat.c (_nl_load_domain): Test for FILENAME == NULL.  This
+       might mark a special condition.
+
+       * finddomain.c (make_entry_rec): Don't make illegal entry as decided.
+
+       * Makefile.in (dist): Suppress error message when ln failed.
+       Get files from $(srcdir) explicitly.
+
+       * libgettext.h (gettext_const): Rename to gettext_noop.
+
+Fri Nov  3 07:36:50 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (make_entry_rec):
+       Protect against wrong locale names by testing mask.
+
+       * libgettext.h (gettext_const): Add macro definition.
+       Capitalize macro arguments.
+
+Thu Nov  2 23:15:51 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (_nl_find_domain):
+       Test for pointer != NULL before accessing value.
+       Reported by Tom Tromey.
+
+       * gettext.c (NULL):
+       Define as (void*)0 instad of 0.  Reported by Franc,ois Pinard.
+
+Mon Oct 30 21:28:52 1995  Ulrich Drepper  <drepper@myware>
+
+       * po2tbl.sed.in: Serious typo bug fixed by Jim Meyering.
+
+Sat Oct 28 23:20:47 1995  Ulrich Drepper  <drepper@myware>
+
+       * libgettext.h: Disable dcgettext optimization for Solaris 2.3.
+
+       * localealias.c (alias_compare):
+       Peter Miller reported that tolower in some systems is
+       even dumber than I thought.  Protect call by `isupper'.
+
+Fri Oct 27 22:22:51 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (libdir, includedir): New variables.
+       (install-src): Install libintl.a and libintl.h in correct dirs.
+
+Fri Oct 27 22:07:29 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (SOURCES): Fix typo: intrl.compat.c -> intl-compat.c.
+
+       * po2tbl.sed.in: Patch for buggy SEDs by Christian von Roques.
+
+       * localealias.c:
+       Fix typo and superflous test.  Reported by Christian von Roques.
+
+Fri Oct  6 11:52:05 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (_nl_find_domain):
+       Correct some remainder from the pre-CEN syntax.  Now
+       we don't have a constant number of successors anymore.
+
+Wed Sep 27 21:41:13 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES): Add libintl.h.glibc.
+
+       * Makefile.in (dist-libc): Add goal for packing sources for glibc.
+       (COMSRCS, COMHDRS): Splitted to separate sources shared with glibc.
+
+       * loadmsgcat.c: Forget to continue #if line.
+
+       * localealias.c:
+       [_LIBC]: Rename strcasecmp to __strcasecmp to keep ANSI C name
+       space clean.
+
+       * dcgettext.c, finddomain.c: Better comment to last change.
+
+       * loadmsgcat.c:
+       [_LIBC]: Rename fstat, open, close, read, mmap, and munmap to
+       __fstat, __open, __close, __read, __mmap, and __munmap resp
+       to keep ANSI C name space clean.
+
+       * finddomain.c:
+       [_LIBC]: Rename stpcpy to __stpcpy to keep ANSI C name space clean.
+
+       * dcgettext.c:
+       [_LIBC]: Rename getced and stpcpy to __getcwd and __stpcpy resp to
+       keep ANSI C name space clean.
+
+       * libgettext.h:
+       Include sys/types.h for those old SysV systems out there.
+       Reported by Francesco Potorti`.
+
+       * loadmsgcat.c (use_mmap): Define if compiled for glibc.
+
+       * bindtextdom.c: Include all those standard headers
+       unconditionally if _LIBC is defined.
+
+       * finddomain.c: Fix 2 times defiend -> defined.
+
+       * textdomain.c: Include libintl.h instead of libgettext.h when
+       compiling for glibc.  Include all those standard headers
+       unconditionally if _LIBC is defined.
+
+       * localealias.c, loadmsgcat.c: Prepare to be compiled in glibc.
+
+       * gettext.c:
+       Include libintl.h instead of libgettext.h when compiling for glibc.
+       Get NULL from stddef.h if we compile for glibc.
+
+       * finddomain.c: Include libintl.h instead of libgettext.h when
+       compiling for glibc.  Include all those standard headers
+       unconditionally if _LIBC is defined.
+
+       * dcgettext.c: Include all those standard headers unconditionally
+       if _LIBC is defined.
+
+       * dgettext.c: If compiled in glibc include libintl.h instead of
+       libgettext.h.
+       (locale.h): Don't rely on HAVE_LOCALE_H when compiling for glibc.
+
+       * dcgettext.c: If compiled in glibc include libintl.h instead of
+       libgettext.h.
+       (getcwd): Don't rely on HAVE_GETCWD when compiling for glibc.
+
+       * bindtextdom.c:
+       If compiled in glibc include libintl.h instead of libgettext.h.
+
+Mon Sep 25 22:23:06 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c (_nl_expand_alias): Don't call bsearch if NMAP <= 0.
+       Reported by Marcus Daniels.
+
+       * cat-compat.c (bindtextdomain):
+       String used in putenv must not be recycled.
+       Reported by Marcus Daniels.
+
+       * libgettext.h (__USE_GNU_GETTEXT):
+       Additional symbol to signal that we use GNU gettext
+       library.
+
+       * cat-compat.c (bindtextdomain):
+       Fix bug with the strange stpcpy replacement.
+       Reported by Nelson Beebe.
+
+Sat Sep 23 08:23:51 1995  Ulrich Drepper  <drepper@myware>
+
+       * cat-compat.c: Include <string.h> for stpcpy prototype.
+
+       * localealias.c (read_alias_file):
+       While expand strdup code temporary variable `cp' hided
+       higher level variable with same name.  Rename to `tp'.
+
+       * textdomain.c (textdomain):
+       Avoid warning by using temporary variable in strdup code.
+
+       * finddomain.c (_nl_find_domain): Remove unused variable `application'.
+
+Thu Sep 21 15:51:44 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c (alias_compare):
+       Use strcasecmp() only if available.  Else use
+       implementation in place.
+
+       * intl-compat.c:
+       Wrapper functions now call *__ functions instead of __*.
+
+       * libgettext.h: Declare prototypes for *__ functions instead for __*.
+
+       * cat-compat.c, loadmsgcat.c:
+       Don't use xmalloc, xstrdup, and stpcpy.  These functions are not part
+       of the standard libc and so prevent libintl.a from being used
+       standalone.
+
+       * bindtextdom.c:
+       Don't use xmalloc, xstrdup, and stpcpy.  These functions are not part
+       of the standard libc and so prevent libintl.a from being used
+       standalone.
+       Rename to bindtextdomain__ if not used in GNU C Library.
+
+       * dgettext.c:
+       Rename function to dgettext__ if not used in GNU C Library.
+
+       * gettext.c:
+       Don't use xmalloc, xstrdup, and stpcpy.  These functions are not part
+       of the standard libc and so prevent libintl.a from being used
+       standalone.
+       Functions now called gettext__ if not used in GNU C Library.
+
+       * dcgettext.c, localealias.c, textdomain.c, finddomain.c:
+       Don't use xmalloc, xstrdup, and stpcpy.  These functions are not part
+       of the standard libc and so prevent libintl.a from being used
+       standalone.
+
+Sun Sep 17 23:14:49 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c: Correct some bugs in handling of CEN standard
+       locale definitions.
+
+Thu Sep  7 01:49:28 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c: Implement CEN syntax.
+
+       * gettextP.h (loaded_domain): Extend number of successors to 31.
+
+Sat Aug 19 19:25:29 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (aliaspath): Remove path to X11 locale dir.
+
+       * Makefile.in: Make install-src depend on install.  This helps
+       gettext to install the sources and other packages can use the
+       install goal.
+
+Sat Aug 19 15:19:33 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (uninstall): Remove stuff installed by install-src.
+
+Tue Aug 15 13:13:53 1995  Ulrich Drepper  <drepper@myware>
+
+       * VERSION.in: Initial revision.
+
+       * Makefile.in (DISTFILES):
+       Add VERSION file.  This is not necessary for gettext, but
+       for other packages using this library.
+
+Tue Aug 15 06:16:44 1995  Ulrich Drepper  <drepper@myware>
+
+       * gettextP.h (_nl_find_domain):
+       New prototype after changing search strategy.
+
+       * finddomain.c (_nl_find_domain):
+       We now try only to find a specified catalog.  Fall back to other
+       catalogs listed in the locale list is now done in __dcgettext.
+
+       * dcgettext.c (__dcgettext):
+       Now we provide message fall back even to different languages.
+       I.e. if a message is not available in one language all the other
+       in the locale list a tried.  Formerly fall back was only possible
+       within one language.  Implemented by moving one loop from
+       _nl_find_domain to here.
+
+Mon Aug 14 23:45:50 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (gettextsrcdir):
+       Directory where source of GNU gettext library are made
+       available.
+       (INSTALL, INSTALL_DATA): Programs used for installing sources.
+       (gettext-src): New.  Rule to install GNU gettext sources for use in
+       gettextize shell script.
+
+Sun Aug 13 14:40:48 1995  Ulrich Drepper  <drepper@myware>
+
+       * loadmsgcat.c (_nl_load_domain):
+       Use mmap for loading only when munmap function is
+       also available.
+
+       * Makefile.in (install): Depend on `all' goal.
+
+Wed Aug  9 11:04:33 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c (read_alias_file):
+       Do not overwrite '\n' when terminating alias value string.
+
+       * localealias.c (read_alias_file):
+       Handle long lines.  Ignore the rest not fitting in
+       the buffer after the initial `fgets' call.
+
+Wed Aug  9 00:54:29 1995  Ulrich Drepper  <drepper@myware>
+
+       * gettextP.h (_nl_load_domain):
+       Add prototype, replacing prototype for _nl_load_msg_cat.
+
+       * finddomain.c (_nl_find_domain):
+       Remove unneeded variable filename and filename_len.
+       (expand_alias): Remove prototype because functions does not
+       exist anymore.
+
+       * localealias.c (read_alias_file):
+       Change type of fname_len parameter to int.
+       (xmalloc): Add prototype.
+
+       * loadmsgcat.c: Better prototypes for xmalloc.
+
+Tue Aug  8 22:30:39 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (_nl_find_domain):
+       Allow alias name to be constructed from the four components.
+
+       * Makefile.in (aliaspath): New variable.  Set to preliminary value.
+       (SOURCES): Add localealias.c.
+       (OBJECTS): Add localealias.o.
+
+       * gettextP.h: Add prototype for _nl_expand_alias.
+
+       * finddomain.c: Aliasing handled in intl/localealias.c.
+
+       * localealias.c: Aliasing for locale names.
+
+       * bindtextdom.c: Better prototypes for xmalloc and xstrdup.
+
+Mon Aug  7 23:47:42 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES): gettext.perl is now found in misc/.
+
+       * cat-compat.c (bindtextdomain):
+       Correct implementation.  dirname parameter was not used.
+       Reported by Marcus Daniels.
+
+       * gettextP.h (loaded_domain):
+       New fields `successor' and `decided' for oo, lazy
+       message handling implementation.
+
+       * dcgettext.c:
+       Adopt for oo, lazy message handliing.
+       Now we can inherit translations from less specific locales.
+       (find_msg): New function.
+
+       * loadmsgcat.c, finddomain.c:
+       Complete rewrite.  Implement oo, lazy message handling :-).
+       We now have an additional environment variable `LANGUAGE' with
+       a higher priority than LC_ALL for the LC_MESSAGE locale.
+       Here we can set a colon separated list of specifications each
+       of the form `language[_territory[.codeset]][@modifier]'.
+
+Sat Aug  5 09:55:42 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (unistd.h):
+       Include to get _PC_PATH_MAX defined on system having it.
+
+Fri Aug  4 22:42:00 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (stpcpy): Include prototype.
+
+       * Makefile.in (dist): Remove `copying instead' message.
+
+Wed Aug  2 18:52:03 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (ID, TAGS): Do not use $^.
+
+Tue Aug  1 20:07:11 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (TAGS, ID): Use $^ as command argument.
+       (TAGS): Give etags -o option t write to current directory,
+       not $(srcdir).
+       (ID): Use $(srcdir) instead os $(top_srcdir)/src.
+       (distclean): Remove ID.
+
+Sun Jul 30 11:51:46 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (gnulocaledir):
+       New variable, always using share/ for data directory.
+       (DEFS): Add GNULOCALEDIR, used in finddomain.c.
+
+       * finddomain.c (_nl_default_dirname):
+       Set to GNULOCALEDIR, because it always has to point
+       to the directory where GNU gettext Library writes it to.
+
+       * intl-compat.c (textdomain, bindtextdomain):
+       Undefine macros before function definition.
+
+Sat Jul 22 01:10:02 1995  Ulrich Drepper  <drepper@myware>
+
+       * libgettext.h (_LIBINTL_H):
+       Protect definition in case where this file is included as
+       libgettext.h on Solaris machines.  Add comment about this.
+
+Wed Jul 19 02:36:42 1995  Ulrich Drepper  <drepper@myware>
+
+       * intl-compat.c (textdomain): Correct typo.
+
+Wed Jul 19 01:51:35 1995  Ulrich Drepper  <drepper@myware>
+
+       * dcgettext.c (dcgettext): Function now called __dcgettext.
+
+       * dgettext.c (dgettext): Now called __dgettext and calls
+       __dcgettext.
+
+       * gettext.c (gettext):
+       Function now called __gettext and calls __dgettext.
+
+       * textdomain.c (textdomain): Function now called __textdomain.
+
+       * bindtextdom.c (bindtextdomain): Function now called
+       __bindtextdomain.
+
+       * intl-compat.c: Initial revision.
+
+       * Makefile.in (SOURCES): Add intl-compat.c.
+       (OBJECTS): We always compile the GNU gettext library functions.
+       OBJECTS contains all objects but cat-compat.o, ../po/cat-if-tbl.o,
+       and intl-compat.o.
+       (GETTOBJS): Contains now only intl-compat.o.
+
+       * libgettext.h:
+       Re-include protection matches dualistic character of libgettext.h.
+       For all functions in GNU gettext library define __ counter part.
+
+       * finddomain.c (strchr): Define as index if not found in C library.
+       (_nl_find_domain): For relative paths paste / in between.
+
+Tue Jul 18 16:37:45 1995  Ulrich Drepper  <drepper@myware>
+
+       * loadmsgcat.c, finddomain.c: Add inclusion of sys/types.h.
+
+       * xopen-msg.sed: Fix bug with `msgstr ""' lines.
+       A little bit better comments.
+
+Tue Jul 18 01:18:27 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in:
+       po-mode.el, makelinks, combine-sh are now found in ../misc.
+
+       * po-mode.el, makelinks, combine-sh, elisp-comp:
+       Moved to ../misc/.
+
+       * libgettext.h, gettextP.h, gettext.h: Uniform test for __STDC__.
+
+Sun Jul 16 22:33:02 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (INSTALL, INSTALL_DATA): New variables.
+       (install-data, uninstall): Install/uninstall .elc file.
+
+       * po-mode.el (Installation comment):
+       Add .pox as possible extension of .po files.
+
+Sun Jul 16 13:23:27 1995  Ulrich Drepper  <drepper@myware>
+
+       * elisp-comp: Complete new version by Franc,ois: This does not
+       fail when not compiling in the source directory.
+
+Sun Jul 16 00:12:17 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (../po/cat-id-tbl.o):
+       Use $(MAKE) instead of make for recursive make.
+
+       * Makefile.in (.el.elc): Use $(SHELL) instead of /bin/sh.
+       (install-exec): Add missing dummy goal.
+       (install-data, uninstall): @ in multi-line shell command at
+       beginning, not in front of echo.  Reported by Eric Backus.
+
+Sat Jul 15 00:21:28 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES):
+       Rename libgettext.perl to gettext.perl to fit in 14 chars
+       file systems.
+
+       * gettext.perl:
+       Rename to gettext.perl to fit in 14 chars file systems.
+
+Thu Jul 13 23:17:20 1995  Ulrich Drepper  <drepper@myware>
+
+       * cat-compat.c: If !STDC_HEADERS try to include malloc.h.
+
+Thu Jul 13 20:55:02 1995  Ulrich Drepper  <drepper@myware>
+
+       * po2tbl.sed.in: Pretty printing.
+
+       * linux-msg.sed, xopen-msg.sed:
+       Correct bugs with handling substitute flags in branches.
+
+       * hash-string.h (hash_string):
+       Old K&R compilers don't under stand `unsigned char'.
+
+       * gettext.h (nls_uint32):
+       Some old K&R compilers (eg HP) don't understand `unsigned int'.
+
+       * cat-compat.c (msg_to_cat_id): De-ANSI-fy prototypes.
+
+Thu Jul 13 01:34:33 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (ELCFILES): New variable.
+       (DISTFILES): Add elisp-comp.
+       Add implicit rule for .el -> .elc compilation.
+       (install-data): install $ELCFILES
+       (clean): renamed po-to-tbl and po-to-msg to po2tbl and po2msg resp.
+
+       * elisp-comp: Initial revision
+
+Wed Jul 12 16:14:52 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in:
+       cat-id-tbl.c is now found in po/.  This enables us to use an identical
+       intl/ directory in all packages.
+
+       * dcgettext.c (dcgettext): hashing does not work for table size <= 2.
+
+       * textdomain.c: fix typo (#if def -> #if defined)
+
+Tue Jul 11 18:44:43 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (stamp-cat-id): use top_srcdir to address source files
+       (DISTFILES,distclean): move tupdate.perl to src/
+
+       * po-to-tbl.sed.in:
+       add additional jump to clear change flag to recognize multiline strings
+
+Tue Jul 11 01:32:50 1995  Ulrich Drepper  <drepper@myware>
+
+       * textdomain.c: Protect inclusion of stdlib.h and string.h.
+
+       * loadmsgcat.c: Protect inclusion of stdlib.h.
+
+       * libgettext.h: Protect inclusion of locale.h.
+       Allow use in C++ programs.
+       Define NULL is not happened already.
+
+       * Makefile.in (DISTFILES): ship po-to-tbl.sed.in instead of
+       po-to-tbl.sed.
+       (distclean): remove po-to-tbl.sed and tupdate.perl.
+
+       * tupdate.perl.in: Substitute Perl path even in exec line.
+       Don't include entries without translation from old .po file.
+
+Tue Jul  4 00:41:51 1995  Ulrich Drepper  <drepper@myware>
+
+       * tupdate.perl.in: use "Updated: " in msgid "".
+
+       * cat-compat.c: Fix typo (LOCALDIR -> LOCALEDIR).
+       Define getenv if !__STDC__.
+
+       * bindtextdom.c: Protect stdlib.h and string.h inclusion.
+       Define free if !__STDC__.
+
+       * finddomain.c: Change DEF_MSG_DOM_DIR to LOCALEDIR.
+       Define free if !__STDC__.
+
+       * cat-compat.c: Change DEF_MSG_DOM_DIR to LOCALEDIR.
+
+Mon Jul  3 23:56:30 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in: Use LOCALEDIR instead of DEF_MSG_DOM_DIR.
+       Remove unneeded $(srcdir) from Makefile.in dependency.
+
+       * makelinks: Add copyright and short description.
+
+       * po-mode.el: Last version for 0.7.
+
+       * tupdate.perl.in: Fix die message.
+
+       * dcgettext.c: Protect include of string.h.
+
+       * gettext.c: Protect include of stdlib.h and further tries to get NULL.
+
+       * finddomain.c: Some corrections in includes.
+
+       * Makefile.in (INCLUDES): Prune list correct path to Makefile.in.
+
+       * po-to-tbl.sed: Adopt for new .po file format.
+
+       * linux-msg.sed, xopen-msg.sed: Adopt for new .po file format.
+
+Sun Jul  2 23:55:03 1995  Ulrich Drepper  <drepper@myware>
+
+       * tupdate.perl.in: Complete rewrite for new .po file format.
+
+Sun Jul  2 02:06:50 1995  Ulrich Drepper  <drepper@myware>
+
+       * First official release.  This directory contains all the code
+       needed to internationalize own packages.  It provides functions
+       which allow to use the X/Open catgets function with an interface
+       like the Uniforum gettext function.  For system which does not
+       have neither of those a complete implementation is provided.
diff --git a/bacula/intl/Makefile.in b/bacula/intl/Makefile.in
new file mode 100644 (file)
index 0000000..3f14c13
--- /dev/null
@@ -0,0 +1,216 @@
+# Makefile for directory with message catalog handling in GNU NLS Utilities.
+# Copyright (C) 1995, 1996, 1997 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = ..
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+transform = @program_transform_name@
+libdir = $(exec_prefix)/lib
+includedir = $(prefix)/include
+datadir = $(prefix)/@DATADIRNAME@
+localedir = $(datadir)/locale
+gnulocaledir = $(prefix)/share/locale
+gettextsrcdir = $(datadir)/gettext/intl
+aliaspath = $(localedir):.
+subdir = intl
+
+DESTDIR =
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+
+l = @l@
+
+AR = ar
+CC = @CC@
+LIBTOOL = @LIBTOOL@
+RANLIB = @RANLIB@
+
+DEFS = -DLOCALEDIR=\"$(localedir)\" -DGNULOCALEDIR=\"$(gnulocaledir)\" \
+-DLOCALE_ALIAS_PATH=\"$(aliaspath)\" @DEFS@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+HEADERS = $(COMHDRS) libgettext.h loadinfo.h
+COMHDRS = gettext.h gettextP.h hash-string.h
+SOURCES = $(COMSRCS) intl-compat.c cat-compat.c
+COMSRCS = bindtextdom.c dcgettext.c dgettext.c gettext.c \
+finddomain.c loadmsgcat.c localealias.c textdomain.c l10nflist.c \
+explodename.c
+OBJECTS = @INTLOBJS@ bindtextdom.$lo dcgettext.$lo dgettext.$lo gettext.$lo \
+finddomain.$lo loadmsgcat.$lo localealias.$lo textdomain.$lo l10nflist.$lo \
+explodename.$lo
+CATOBJS = cat-compat.$lo ../po/cat-id-tbl.$lo
+GETTOBJS = intl-compat.$lo
+DISTFILES.common = ChangeLog Makefile.in linux-msg.sed po2tbl.sed.in \
+xopen-msg.sed $(HEADERS) $(SOURCES)
+DISTFILES.normal = VERSION
+DISTFILES.gettext = libintl.glibc intlh.inst.in
+
+.SUFFIXES:
+.SUFFIXES: .c .o .lo
+.c.o:
+       $(COMPILE) $<
+.c.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) $<
+
+INCLUDES = -I.. -I. -I$(top_srcdir)/intl -I$(top_srcdir)/lib
+
+all: all-@USE_INCLUDED_LIBINTL@
+
+all-yes: libintl.$la intlh.inst
+all-no:
+
+libintl.a: $(OBJECTS)
+       rm -f $@
+       $(AR) cru $@ $(OBJECTS)
+       $(RANLIB) $@
+
+libintl.la: $(OBJECTS)
+       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(OBJECTS) \
+                  -version-info 1:0 -rpath $(libdir)
+
+../po/cat-id-tbl.$lo: ../po/cat-id-tbl.c $(top_srcdir)/po/$(PACKAGE).pot
+       cd ../po && $(MAKE) cat-id-tbl.$lo
+
+check: all
+
+# This installation goal is only used in GNU gettext.  Packages which
+# only use the library should use install instead.
+
+# We must not install the libintl.h/libintl.a files if we are on a
+# system which has the gettext() function in its C library or in a
+# separate library or use the catgets interface.  A special case is
+# where configure found a previously installed GNU gettext library.
+# If you want to use the one which comes with this version of the
+# package, you have to use `configure --with-included-gettext'.
+install: install-exec install-data
+install-exec: all
+       if test "$(PACKAGE)" = "gettext" \
+          && test '@INTLOBJS@' = '$(GETTOBJS)'; then \
+         if test -r $(MKINSTALLDIRS); then \
+           $(MKINSTALLDIRS) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \
+         else \
+           $(top_srcdir)/mkinstalldirs $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \
+         fi; \
+         $(INSTALL_DATA) intlh.inst $(DESTDIR)$(includedir)/libintl.h; \
+         $(INSTALL_DATA) libintl.a $(DESTDIR)$(libdir)/libintl.a; \
+       else \
+         : ; \
+       fi
+install-data: all
+       if test "$(PACKAGE)" = "gettext"; then \
+         if test -r $(MKINSTALLDIRS); then \
+           $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
+         else \
+           $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
+         fi; \
+         $(INSTALL_DATA) VERSION $(DESTDIR)$(gettextsrcdir)/VERSION; \
+         dists="$(DISTFILES.common)"; \
+         for file in $$dists; do \
+           $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(gettextsrcdir)/$$file; \
+         done; \
+       else \
+         : ; \
+       fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+       dists="$(DISTFILES.common)"; \
+       for file in $$dists; do \
+         rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
+       done
+
+info dvi:
+
+$(OBJECTS): ../config.h libgettext.h
+bindtextdom.$lo finddomain.$lo loadmsgcat.$lo: gettextP.h gettext.h loadinfo.h
+dcgettext.$lo: gettextP.h gettext.h hash-string.h loadinfo.h
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES)
+       here=`pwd`; cd $(srcdir) && etags -o $$here/TAGS $(HEADERS) $(SOURCES)
+
+id: ID
+
+ID: $(HEADERS) $(SOURCES)
+       here=`pwd`; cd $(srcdir) && mkid -f$$here/ID $(HEADERS) $(SOURCES)
+
+
+mostlyclean:
+       rm -f *.a *.o *.lo core core.*
+
+clean: mostlyclean
+
+distclean: clean
+       rm -f Makefile ID TAGS po2msg.sed po2tbl.sed
+
+maintainer-clean: distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+
+# GNU gettext needs not contain the file `VERSION' but contains some
+# other files which should not be distributed in other packages.
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: Makefile $(DISTFILES)
+       if test "$(PACKAGE)" = gettext; then \
+         additional="$(DISTFILES.gettext)"; \
+       else \
+         additional="$(DISTFILES.normal)"; \
+       fi; \
+       for file in $(DISTFILES.common) $$additional; do \
+         ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+           || cp -p $(srcdir)/$$file $(distdir); \
+       done
+
+dist-libc:
+       tar zcvf intl-glibc.tar.gz $(COMSRCS) $(COMHDRS) libintl.h.glibc
+
+Makefile: Makefile.in ../config.status
+       cd .. \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+# The dependency for intlh.inst is different in gettext and all other
+# packages.  Because we cannot you GNU make features we have to solve
+# the problem while rewriting Makefile.in.
+@GT_YES@intlh.inst: intlh.inst.in ../config.status
+@GT_YES@       cd .. \
+@GT_YES@       && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= \
+@GT_YES@         $(SHELL) ./config.status
+@GT_NO@.PHONY: intlh.inst
+@GT_NO@intlh.inst:
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/bacula/intl/VERSION b/bacula/intl/VERSION
new file mode 100644 (file)
index 0000000..ee66b06
--- /dev/null
@@ -0,0 +1 @@
+GNU gettext library from gettext-0.10.35
diff --git a/bacula/intl/bindtextdom.c b/bacula/intl/bindtextdom.c
new file mode 100644 (file)
index 0000000..d9c3f34
--- /dev/null
@@ -0,0 +1,203 @@
+/* Implementation of the bindtextdomain(3) function
+   Copyright (C) 1995, 1996, 1997, 1998 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+#include "gettext.h"
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+/* Contains the default location of the message catalogs.  */
+extern const char _nl_default_dirname[];
+
+/* List with bindings of specific domains.  */
+extern struct binding *_nl_domain_bindings;
+
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define BINDTEXTDOMAIN __bindtextdomain
+# ifndef strdup
+#  define strdup(str) __strdup (str)
+# endif
+#else
+# define BINDTEXTDOMAIN bindtextdomain__
+#endif
+
+/* Specify that the DOMAINNAME message catalog will be found
+   in DIRNAME rather than in the system locale data base.  */
+char *
+BINDTEXTDOMAIN (domainname, dirname)
+     const char *domainname;
+     const char *dirname;
+{
+  struct binding *binding;
+
+  /* Some sanity checks.  */
+  if (domainname == NULL || domainname[0] == '\0')
+    return NULL;
+
+  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
+    {
+      int compare = strcmp (domainname, binding->domainname);
+      if (compare == 0)
+       /* We found it!  */
+       break;
+      if (compare < 0)
+       {
+         /* It is not in the list.  */
+         binding = NULL;
+         break;
+       }
+    }
+
+  if (dirname == NULL)
+    /* The current binding has be to returned.  */
+    return binding == NULL ? (char *) _nl_default_dirname : binding->dirname;
+
+  if (binding != NULL)
+    {
+      /* The domain is already bound.  If the new value and the old
+        one are equal we simply do nothing.  Otherwise replace the
+        old binding.  */
+      if (strcmp (dirname, binding->dirname) != 0)
+       {
+         char *new_dirname;
+
+         if (strcmp (dirname, _nl_default_dirname) == 0)
+           new_dirname = (char *) _nl_default_dirname;
+         else
+           {
+#if defined _LIBC || defined HAVE_STRDUP
+             new_dirname = strdup (dirname);
+             if (new_dirname == NULL)
+               return NULL;
+#else
+             size_t len = strlen (dirname) + 1;
+             new_dirname = (char *) malloc (len);
+             if (new_dirname == NULL)
+               return NULL;
+
+             memcpy (new_dirname, dirname, len);
+#endif
+           }
+
+         if (binding->dirname != _nl_default_dirname)
+           free (binding->dirname);
+
+         binding->dirname = new_dirname;
+       }
+    }
+  else
+    {
+      /* We have to create a new binding.  */
+#if !defined _LIBC && !defined HAVE_STRDUP
+      size_t len;
+#endif
+      struct binding *new_binding =
+       (struct binding *) malloc (sizeof (*new_binding));
+
+      if (new_binding == NULL)
+       return NULL;
+
+#if defined _LIBC || defined HAVE_STRDUP
+      new_binding->domainname = strdup (domainname);
+      if (new_binding->domainname == NULL)
+       return NULL;
+#else
+      len = strlen (domainname) + 1;
+      new_binding->domainname = (char *) malloc (len);
+      if (new_binding->domainname == NULL)
+       return NULL;
+      memcpy (new_binding->domainname, domainname, len);
+#endif
+
+      if (strcmp (dirname, _nl_default_dirname) == 0)
+       new_binding->dirname = (char *) _nl_default_dirname;
+      else
+       {
+#if defined _LIBC || defined HAVE_STRDUP
+         new_binding->dirname = strdup (dirname);
+         if (new_binding->dirname == NULL)
+           return NULL;
+#else
+         len = strlen (dirname) + 1;
+         new_binding->dirname = (char *) malloc (len);
+         if (new_binding->dirname == NULL)
+           return NULL;
+         memcpy (new_binding->dirname, dirname, len);
+#endif
+       }
+
+      /* Now enqueue it.  */
+      if (_nl_domain_bindings == NULL
+         || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
+       {
+         new_binding->next = _nl_domain_bindings;
+         _nl_domain_bindings = new_binding;
+       }
+      else
+       {
+         binding = _nl_domain_bindings;
+         while (binding->next != NULL
+                && strcmp (domainname, binding->next->domainname) > 0)
+           binding = binding->next;
+
+         new_binding->next = binding->next;
+         binding->next = new_binding;
+       }
+
+      binding = new_binding;
+    }
+
+  return binding->dirname;
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__bindtextdomain, bindtextdomain);
+#endif
diff --git a/bacula/intl/cat-compat.c b/bacula/intl/cat-compat.c
new file mode 100644 (file)
index 0000000..867d901
--- /dev/null
@@ -0,0 +1,262 @@
+/* Compatibility code for gettext-using-catgets interface.
+   Copyright (C) 1995, 1997 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#else
+char *getenv ();
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# endif
+#endif
+
+#ifdef HAVE_NL_TYPES_H
+# include <nl_types.h>
+#endif
+
+#include "libgettext.h"
+
+/* @@ end of prolog @@ */
+
+/* XPG3 defines the result of `setlocale (category, NULL)' as:
+   ``Directs `setlocale()' to query `category' and return the current
+     setting of `local'.''
+   However it does not specify the exact format.  And even worse: POSIX
+   defines this not at all.  So we can use this feature only on selected
+   system (e.g. those using GNU C Library).  */
+#ifdef _LIBC
+# define HAVE_LOCALE_NULL
+#endif
+
+/* The catalog descriptor.  */
+static nl_catd catalog = (nl_catd) -1;
+
+/* Name of the default catalog.  */
+static const char default_catalog_name[] = "messages";
+
+/* Name of currently used catalog.  */
+static const char *catalog_name = default_catalog_name;
+
+/* Get ID for given string.  If not found return -1.  */
+static int msg_to_cat_id PARAMS ((const char *msg));
+
+/* Substitution for systems lacking this function in their C library.  */
+#if !_LIBC && !HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+#endif
+
+
+/* Set currently used domain/catalog.  */
+char *
+textdomain (domainname)
+     const char *domainname;
+{
+  nl_catd new_catalog;
+  char *new_name;
+  size_t new_name_len;
+  char *lang;
+
+#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES \
+    && defined HAVE_LOCALE_NULL
+  lang = setlocale (LC_MESSAGES, NULL);
+#else
+  lang = getenv ("LC_ALL");
+  if (lang == NULL || lang[0] == '\0')
+    {
+      lang = getenv ("LC_MESSAGES");
+      if (lang == NULL || lang[0] == '\0')
+       lang = getenv ("LANG");
+    }
+#endif
+  if (lang == NULL || lang[0] == '\0')
+    lang = "C";
+
+  /* See whether name of currently used domain is asked.  */
+  if (domainname == NULL)
+    return (char *) catalog_name;
+
+  if (domainname[0] == '\0')
+    domainname = default_catalog_name;
+
+  /* Compute length of added path element.  */
+  new_name_len = sizeof (LOCALEDIR) - 1 + 1 + strlen (lang)
+                + sizeof ("/LC_MESSAGES/") - 1 + sizeof (PACKAGE) - 1
+                + sizeof (".cat");
+
+  new_name = (char *) malloc (new_name_len);
+  if (new_name == NULL)
+    return NULL;
+
+  strcpy (new_name, PACKAGE);
+  new_catalog = catopen (new_name, 0);
+
+  if (new_catalog == (nl_catd) -1)
+    {
+      /* NLSPATH search didn't work, try absolute path */
+      sprintf (new_name, "%s/%s/LC_MESSAGES/%s.cat", LOCALEDIR, lang,
+              PACKAGE);
+      new_catalog = catopen (new_name, 0);
+
+      if (new_catalog == (nl_catd) -1)
+       {
+         free (new_name);
+         return (char *) catalog_name;
+       }
+    }
+
+  /* Close old catalog.  */
+  if (catalog != (nl_catd) -1)
+    catclose (catalog);
+  if (catalog_name != default_catalog_name)
+    free ((char *) catalog_name);
+
+  catalog = new_catalog;
+  catalog_name = new_name;
+
+  return (char *) catalog_name;
+}
+
+char *
+bindtextdomain (domainname, dirname)
+     const char *domainname;
+     const char *dirname;
+{
+#if HAVE_SETENV || HAVE_PUTENV
+  char *old_val, *new_val, *cp;
+  size_t new_val_len;
+
+  /* This does not make much sense here but to be compatible do it.  */
+  if (domainname == NULL)
+    return NULL;
+
+  /* Compute length of added path element.  If we use setenv we don't need
+     the first byts for NLSPATH=, but why complicate the code for this
+     peanuts.  */
+  new_val_len = sizeof ("NLSPATH=") - 1 + strlen (dirname)
+               + sizeof ("/%L/LC_MESSAGES/%N.cat");
+
+  old_val = getenv ("NLSPATH");
+  if (old_val == NULL || old_val[0] == '\0')
+    {
+      old_val = NULL;
+      new_val_len += 1 + sizeof (LOCALEDIR) - 1
+                    + sizeof ("/%L/LC_MESSAGES/%N.cat");
+    }
+  else
+    new_val_len += strlen (old_val);
+
+  new_val = (char *) malloc (new_val_len);
+  if (new_val == NULL)
+    return NULL;
+
+# if HAVE_SETENV
+  cp = new_val;
+# else
+  cp = stpcpy (new_val, "NLSPATH=");
+# endif
+
+  cp = stpcpy (cp, dirname);
+  cp = stpcpy (cp, "/%L/LC_MESSAGES/%N.cat:");
+
+  if (old_val == NULL)
+    {
+# if __STDC__
+      stpcpy (cp, LOCALEDIR "/%L/LC_MESSAGES/%N.cat");
+# else
+
+      cp = stpcpy (cp, LOCALEDIR);
+      stpcpy (cp, "/%L/LC_MESSAGES/%N.cat");
+# endif
+    }
+  else
+    stpcpy (cp, old_val);
+
+# if HAVE_SETENV
+  setenv ("NLSPATH", new_val, 1);
+  free (new_val);
+# else
+  putenv (new_val);
+  /* Do *not* free the environment entry we just entered.  It is used
+     from now on.   */
+# endif
+
+#endif
+
+  return (char *) domainname;
+}
+
+#undef gettext
+char *
+gettext (msg)
+     const char *msg;
+{
+  int msgid;
+
+  if (msg == NULL || catalog == (nl_catd) -1)
+    return (char *) msg;
+
+  /* Get the message from the catalog.  We always use set number 1.
+     The message ID is computed by the function `msg_to_cat_id'
+     which works on the table generated by `po-to-tbl'.  */
+  msgid = msg_to_cat_id (msg);
+  if (msgid == -1)
+    return (char *) msg;
+
+  return catgets (catalog, 1, msgid, (char *) msg);
+}
+
+/* Look through the table `_msg_tbl' which has `_msg_tbl_length' entries
+   for the one equal to msg.  If it is found return the ID.  In case when
+   the string is not found return -1.  */
+static int
+msg_to_cat_id (msg)
+     const char *msg;
+{
+  int cnt;
+
+  for (cnt = 0; cnt < _msg_tbl_length; ++cnt)
+    if (strcmp (msg, _msg_tbl[cnt]._msg) == 0)
+      return _msg_tbl[cnt]._msg_number;
+
+  return -1;
+}
+
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library.  So we
+   avoid the non-standard function stpcpy.  In GNU C Library this
+   function is available, though.  Also allow the symbol HAVE_STPCPY
+   to be defined.  */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+     char *dest;
+     const char *src;
+{
+  while ((*dest++ = *src++) != '\0')
+    /* Do nothing. */ ;
+  return dest - 1;
+}
+#endif
diff --git a/bacula/intl/dcgettext.c b/bacula/intl/dcgettext.c
new file mode 100644 (file)
index 0000000..c4c7a2c
--- /dev/null
@@ -0,0 +1,624 @@
+/* Implementation of the dcgettext(3) function.
+   Copyright (C) 1995, 1996, 1997, 1998 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# if defined HAVE_ALLOCA_H || defined _LIBC
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca
+char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+char *getenv ();
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# ifndef _GNU_SOURCE
+#  define _GNU_SOURCE  1
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+#  define strchr index
+# endif
+#endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+#include "hash-string.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions.  This is required by the standard
+   because some ANSI C functions will require linking with this object
+   file and the name space must not be polluted.  */
+# define getcwd __getcwd
+# ifndef stpcpy
+#  define stpcpy __stpcpy
+# endif
+#else
+# if !defined HAVE_GETCWD
+char *getwd ();
+#  define getcwd(buf, max) getwd (buf)
+# else
+char *getcwd ();
+# endif
+# ifndef HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+# endif
+#endif
+
+/* Amount to increase buffer size by in each try.  */
+#define PATH_INCR 32
+
+/* The following is from pathmax.h.  */
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+   PATH_MAX but might cause redefinition warnings when sys/param.h is
+   later included (as on MORE/BSD 4.3).  */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+# include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+# define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been.  */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+# include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+# define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+/* XPG3 defines the result of `setlocale (category, NULL)' as:
+   ``Directs `setlocale()' to query `category' and return the current
+     setting of `local'.''
+   However it does not specify the exact format.  And even worse: POSIX
+   defines this not at all.  So we can use this feature only on selected
+   system (e.g. those using GNU C Library).  */
+#ifdef _LIBC
+# define HAVE_LOCALE_NULL
+#endif
+
+/* Name of the default domain used for gettext(3) prior any call to
+   textdomain(3).  The default value for this is "messages".  */
+const char _nl_default_default_domain[] = "messages";
+
+/* Value used as the default domain for gettext(3).  */
+const char *_nl_current_default_domain = _nl_default_default_domain;
+
+/* Contains the default location of the message catalogs.  */
+const char _nl_default_dirname[] = GNULOCALEDIR;
+
+/* List with bindings of specific domains created by bindtextdomain()
+   calls.  */
+struct binding *_nl_domain_bindings;
+
+/* Prototypes for local functions.  */
+static char *find_msg PARAMS ((struct loaded_l10nfile *domain_file,
+                              const char *msgid)) internal_function;
+static const char *category_to_name PARAMS ((int category)) internal_function;
+static const char *guess_category_value PARAMS ((int category,
+                                                const char *categoryname))
+     internal_function;
+
+
+/* For those loosing systems which don't have `alloca' we have to add
+   some additional code emulating it.  */
+#ifdef HAVE_ALLOCA
+/* Nothing has to be done.  */
+# define ADD_BLOCK(list, address) /* nothing */
+# define FREE_BLOCKS(list) /* nothing */
+#else
+struct block_list
+{
+  void *address;
+  struct block_list *next;
+};
+# define ADD_BLOCK(list, addr)                                               \
+  do {                                                                       \
+    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
+    /* If we cannot get a free block we cannot add the new element to        \
+       the list.  */                                                         \
+    if (newp != NULL) {                                                              \
+      newp->address = (addr);                                                \
+      newp->next = (list);                                                   \
+      (list) = newp;                                                         \
+    }                                                                        \
+  } while (0)
+# define FREE_BLOCKS(list)                                                   \
+  do {                                                                       \
+    while (list != NULL) {                                                   \
+      struct block_list *old = list;                                         \
+      list = list->next;                                                     \
+      free (old);                                                            \
+    }                                                                        \
+  } while (0)
+# undef alloca
+# define alloca(size) (malloc (size))
+#endif /* have alloca */
+
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define DCGETTEXT __dcgettext
+#else
+# define DCGETTEXT dcgettext__
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+   locale.  */
+char *
+DCGETTEXT (domainname, msgid, category)
+     const char *domainname;
+     const char *msgid;
+     int category;
+{
+#ifndef HAVE_ALLOCA
+  struct block_list *block_list = NULL;
+#endif
+  struct loaded_l10nfile *domain;
+  struct binding *binding;
+  const char *categoryname;
+  const char *categoryvalue;
+  char *dirname, *xdomainname;
+  char *single_locale;
+  char *retval;
+  int saved_errno = errno;
+
+  /* If no real MSGID is given return NULL.  */
+  if (msgid == NULL)
+    return NULL;
+
+  /* If DOMAINNAME is NULL, we are interested in the default domain.  If
+     CATEGORY is not LC_MESSAGES this might not make much sense but the
+     defintion left this undefined.  */
+  if (domainname == NULL)
+    domainname = _nl_current_default_domain;
+
+  /* First find matching binding.  */
+  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
+    {
+      int compare = strcmp (domainname, binding->domainname);
+      if (compare == 0)
+       /* We found it!  */
+       break;
+      if (compare < 0)
+       {
+         /* It is not in the list.  */
+         binding = NULL;
+         break;
+       }
+    }
+
+  if (binding == NULL)
+    dirname = (char *) _nl_default_dirname;
+  else if (binding->dirname[0] == '/')
+    dirname = binding->dirname;
+  else
+    {
+      /* We have a relative path.  Make it absolute now.  */
+      size_t dirname_len = strlen (binding->dirname) + 1;
+      size_t path_max;
+      char *ret;
+
+      path_max = (unsigned) PATH_MAX;
+      path_max += 2;           /* The getcwd docs say to do this.  */
+
+      dirname = (char *) alloca (path_max + dirname_len);
+      ADD_BLOCK (block_list, dirname);
+
+      __set_errno (0);
+      while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
+       {
+         path_max += PATH_INCR;
+         dirname = (char *) alloca (path_max + dirname_len);
+         ADD_BLOCK (block_list, dirname);
+         __set_errno (0);
+       }
+
+      if (ret == NULL)
+       {
+         /* We cannot get the current working directory.  Don't signal an
+            error but simply return the default string.  */
+         FREE_BLOCKS (block_list);
+         __set_errno (saved_errno);
+         return (char *) msgid;
+       }
+
+      stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
+    }
+
+  /* Now determine the symbolic name of CATEGORY and its value.  */
+  categoryname = category_to_name (category);
+  categoryvalue = guess_category_value (category, categoryname);
+
+  xdomainname = (char *) alloca (strlen (categoryname)
+                                + strlen (domainname) + 5);
+  ADD_BLOCK (block_list, xdomainname);
+
+  stpcpy (stpcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
+                 domainname),
+         ".mo");
+
+  /* Creating working area.  */
+  single_locale = (char *) alloca (strlen (categoryvalue) + 1);
+  ADD_BLOCK (block_list, single_locale);
+
+
+  /* Search for the given string.  This is a loop because we perhaps
+     got an ordered list of languages to consider for th translation.  */
+  while (1)
+    {
+      /* Make CATEGORYVALUE point to the next element of the list.  */
+      while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
+       ++categoryvalue;
+      if (categoryvalue[0] == '\0')
+       {
+         /* The whole contents of CATEGORYVALUE has been searched but
+            no valid entry has been found.  We solve this situation
+            by implicitly appending a "C" entry, i.e. no translation
+            will take place.  */
+         single_locale[0] = 'C';
+         single_locale[1] = '\0';
+       }
+      else
+       {
+         char *cp = single_locale;
+         while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
+           *cp++ = *categoryvalue++;
+         *cp = '\0';
+       }
+
+      /* If the current locale value is C (or POSIX) we don't load a
+        domain.  Return the MSGID.  */
+      if (strcmp (single_locale, "C") == 0
+         || strcmp (single_locale, "POSIX") == 0)
+       {
+         FREE_BLOCKS (block_list);
+         __set_errno (saved_errno);
+         return (char *) msgid;
+       }
+
+
+      /* Find structure describing the message catalog matching the
+        DOMAINNAME and CATEGORY.  */
+      domain = _nl_find_domain (dirname, single_locale, xdomainname);
+
+      if (domain != NULL)
+       {
+         retval = find_msg (domain, msgid);
+
+         if (retval == NULL)
+           {
+             int cnt;
+
+             for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
+               {
+                 retval = find_msg (domain->successor[cnt], msgid);
+
+                 if (retval != NULL)
+                   break;
+               }
+           }
+
+         if (retval != NULL)
+           {
+             FREE_BLOCKS (block_list);
+             __set_errno (saved_errno);
+             return retval;
+           }
+       }
+    }
+  /* NOTREACHED */
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__dcgettext, dcgettext);
+#endif
+
+
+static char *
+internal_function
+find_msg (domain_file, msgid)
+     struct loaded_l10nfile *domain_file;
+     const char *msgid;
+{
+  size_t top, act, bottom;
+  struct loaded_domain *domain;
+
+  if (domain_file->decided == 0)
+    _nl_load_domain (domain_file);
+
+  if (domain_file->data == NULL)
+    return NULL;
+
+  domain = (struct loaded_domain *) domain_file->data;
+
+  /* Locate the MSGID and its translation.  */
+  if (domain->hash_size > 2 && domain->hash_tab != NULL)
+    {
+      /* Use the hashing table.  */
+      nls_uint32 len = strlen (msgid);
+      nls_uint32 hash_val = hash_string (msgid);
+      nls_uint32 idx = hash_val % domain->hash_size;
+      nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
+      nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
+
+      if (nstr == 0)
+       /* Hash table entry is empty.  */
+       return NULL;
+
+      if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
+         && strcmp (msgid,
+                    domain->data + W (domain->must_swap,
+                                      domain->orig_tab[nstr - 1].offset)) == 0)
+       return (char *) domain->data + W (domain->must_swap,
+                                         domain->trans_tab[nstr - 1].offset);
+
+      while (1)
+       {
+         if (idx >= domain->hash_size - incr)
+           idx -= domain->hash_size - incr;
+         else
+           idx += incr;
+
+         nstr = W (domain->must_swap, domain->hash_tab[idx]);
+         if (nstr == 0)
+           /* Hash table entry is empty.  */
+           return NULL;
+
+         if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
+             && strcmp (msgid,
+                        domain->data + W (domain->must_swap,
+                                          domain->orig_tab[nstr - 1].offset))
+                == 0)
+           return (char *) domain->data
+             + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
+       }
+      /* NOTREACHED */
+    }
+
+  /* Now we try the default method:  binary search in the sorted
+     array of messages.  */
+  bottom = 0;
+  top = domain->nstrings;
+  while (bottom < top)
+    {
+      int cmp_val;
+
+      act = (bottom + top) / 2;
+      cmp_val = strcmp (msgid, domain->data
+                              + W (domain->must_swap,
+                                   domain->orig_tab[act].offset));
+      if (cmp_val < 0)
+       top = act;
+      else if (cmp_val > 0)
+       bottom = act + 1;
+      else
+       break;
+    }
+
+  /* If an translation is found return this.  */
+  return bottom >= top ? NULL : (char *) domain->data
+                                + W (domain->must_swap,
+                                    domain->trans_tab[act].offset);
+}
+
+
+/* Return string representation of locale CATEGORY.  */
+static const char *
+internal_function
+category_to_name (category)
+     int category;
+{
+  const char *retval;
+
+  switch (category)
+  {
+#ifdef LC_COLLATE
+  case LC_COLLATE:
+    retval = "LC_COLLATE";
+    break;
+#endif
+#ifdef LC_CTYPE
+  case LC_CTYPE:
+    retval = "LC_CTYPE";
+    break;
+#endif
+#ifdef LC_MONETARY
+  case LC_MONETARY:
+    retval = "LC_MONETARY";
+    break;
+#endif
+#ifdef LC_NUMERIC
+  case LC_NUMERIC:
+    retval = "LC_NUMERIC";
+    break;
+#endif
+#ifdef LC_TIME
+  case LC_TIME:
+    retval = "LC_TIME";
+    break;
+#endif
+#ifdef LC_MESSAGES
+  case LC_MESSAGES:
+    retval = "LC_MESSAGES";
+    break;
+#endif
+#ifdef LC_RESPONSE
+  case LC_RESPONSE:
+    retval = "LC_RESPONSE";
+    break;
+#endif
+#ifdef LC_ALL
+  case LC_ALL:
+    /* This might not make sense but is perhaps better than any other
+       value.  */
+    retval = "LC_ALL";
+    break;
+#endif
+  default:
+    /* If you have a better idea for a default value let me know.  */
+    retval = "LC_XXX";
+  }
+
+  return retval;
+}
+
+/* Guess value of current locale from value of the environment variables.  */
+static const char *
+internal_function
+guess_category_value (category, categoryname)
+     int category;
+     const char *categoryname;
+{
+  const char *retval;
+
+  /* The highest priority value is the `LANGUAGE' environment
+     variable.  This is a GNU extension.  */
+  retval = getenv ("LANGUAGE");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* `LANGUAGE' is not set.  So we have to proceed with the POSIX
+     methods of looking to `LC_ALL', `LC_xxx', and `LANG'.  On some
+     systems this can be done by the `setlocale' function itself.  */
+#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
+  return setlocale (category, NULL);
+#else
+  /* Setting of LC_ALL overwrites all other.  */
+  retval = getenv ("LC_ALL");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* Next comes the name of the desired category.  */
+  retval = getenv (categoryname);
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* Last possibility is the LANG environment variable.  */
+  retval = getenv ("LANG");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* We use C as the default domain.  POSIX says this is implementation
+     defined.  */
+  return "C";
+#endif
+}
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library.  So we
+   avoid the non-standard function stpcpy.  In GNU C Library this
+   function is available, though.  Also allow the symbol HAVE_STPCPY
+   to be defined.  */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+     char *dest;
+     const char *src;
+{
+  while ((*dest++ = *src++) != '\0')
+    /* Do nothing. */ ;
+  return dest - 1;
+}
+#endif
+
+
+#ifdef _LIBC
+/* If we want to free all resources we have to do some work at
+   program's end.  */
+static void __attribute__ ((unused))
+free_mem (void)
+{
+  struct binding *runp;
+
+  for (runp = _nl_domain_bindings; runp != NULL; runp = runp->next)
+    {
+      free (runp->domainname);
+      if (runp->dirname != _nl_default_dirname)
+       /* Yes, this is a pointer comparison.  */
+       free (runp->dirname);
+    }
+
+  if (_nl_current_default_domain != _nl_default_default_domain)
+    /* Yes, again a pointer comparison.  */
+    free ((char *) _nl_current_default_domain);
+}
+
+text_set_element (__libc_subfreeres, free_mem);
+#endif
diff --git a/bacula/intl/dgettext.c b/bacula/intl/dgettext.c
new file mode 100644 (file)
index 0000000..0510c2b
--- /dev/null
@@ -0,0 +1,59 @@
+/* Implementation of the dgettext(3) function
+   Copyright (C) 1995, 1996, 1997 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined HAVE_LOCALE_H || defined _LIBC
+# include <locale.h>
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define DGETTEXT __dgettext
+# define DCGETTEXT __dcgettext
+#else
+# define DGETTEXT dgettext__
+# define DCGETTEXT dcgettext__
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog of the current
+   LC_MESSAGES locale.  */
+char *
+DGETTEXT (domainname, msgid)
+     const char *domainname;
+     const char *msgid;
+{
+  return DCGETTEXT (domainname, msgid, LC_MESSAGES);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__dgettext, dgettext);
+#endif
diff --git a/bacula/intl/explodename.c b/bacula/intl/explodename.c
new file mode 100644 (file)
index 0000000..8066dc2
--- /dev/null
@@ -0,0 +1,188 @@
+/* Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   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.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#include <sys/types.h>
+
+#include "loadinfo.h"
+
+/* On some strange systems still no definition of NULL is found.  Sigh!  */
+#ifndef NULL
+# if defined __STDC__ && __STDC__
+#  define NULL ((void *) 0)
+# else
+#  define NULL 0
+# endif
+#endif
+
+/* @@ end of prolog @@ */
+
+int
+_nl_explode_name (name, language, modifier, territory, codeset,
+                 normalized_codeset, special, sponsor, revision)
+     char *name;
+     const char **language;
+     const char **modifier;
+     const char **territory;
+     const char **codeset;
+     const char **normalized_codeset;
+     const char **special;
+     const char **sponsor;
+     const char **revision;
+{
+  enum { undecided, xpg, cen } syntax;
+  char *cp;
+  int mask;
+
+  *modifier = NULL;
+  *territory = NULL;
+  *codeset = NULL;
+  *normalized_codeset = NULL;
+  *special = NULL;
+  *sponsor = NULL;
+  *revision = NULL;
+
+  /* Now we determine the single parts of the locale name.  First
+     look for the language.  Termination symbols are `_' and `@' if
+     we use XPG4 style, and `_', `+', and `,' if we use CEN syntax.  */
+  mask = 0;
+  syntax = undecided;
+  *language = cp = name;
+  while (cp[0] != '\0' && cp[0] != '_' && cp[0] != '@'
+        && cp[0] != '+' && cp[0] != ',')
+    ++cp;
+
+  if (*language == cp)
+    /* This does not make sense: language has to be specified.  Use
+       this entry as it is without exploding.  Perhaps it is an alias.  */
+    cp = strchr (*language, '\0');
+  else if (cp[0] == '_')
+    {
+      /* Next is the territory.  */
+      cp[0] = '\0';
+      *territory = ++cp;
+
+      while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@'
+            && cp[0] != '+' && cp[0] != ',' && cp[0] != '_')
+       ++cp;
+
+      mask |= TERRITORY;
+
+      if (cp[0] == '.')
+       {
+         /* Next is the codeset.  */
+         syntax = xpg;
+         cp[0] = '\0';
+         *codeset = ++cp;
+
+         while (cp[0] != '\0' && cp[0] != '@')
+           ++cp;
+
+         mask |= XPG_CODESET;
+
+         if (*codeset != cp && (*codeset)[0] != '\0')
+           {
+             *normalized_codeset = _nl_normalize_codeset (*codeset,
+                                                          cp - *codeset);
+             if (strcmp (*codeset, *normalized_codeset) == 0)
+               free ((char *) *normalized_codeset);
+             else
+               mask |= XPG_NORM_CODESET;
+           }
+       }
+    }
+
+  if (cp[0] == '@' || (syntax != xpg && cp[0] == '+'))
+    {
+      /* Next is the modifier.  */
+      syntax = cp[0] == '@' ? xpg : cen;
+      cp[0] = '\0';
+      *modifier = ++cp;
+
+      while (syntax == cen && cp[0] != '\0' && cp[0] != '+'
+            && cp[0] != ',' && cp[0] != '_')
+       ++cp;
+
+      mask |= XPG_MODIFIER | CEN_AUDIENCE;
+    }
+
+  if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_'))
+    {
+      syntax = cen;
+
+      if (cp[0] == '+')
+       {
+         /* Next is special application (CEN syntax).  */
+         cp[0] = '\0';
+         *special = ++cp;
+
+         while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_')
+           ++cp;
+
+         mask |= CEN_SPECIAL;
+       }
+
+      if (cp[0] == ',')
+       {
+         /* Next is sponsor (CEN syntax).  */
+         cp[0] = '\0';
+         *sponsor = ++cp;
+
+         while (cp[0] != '\0' && cp[0] != '_')
+           ++cp;
+
+         mask |= CEN_SPONSOR;
+       }
+
+      if (cp[0] == '_')
+       {
+         /* Next is revision (CEN syntax).  */
+         cp[0] = '\0';
+         *revision = ++cp;
+
+         mask |= CEN_REVISION;
+       }
+    }
+
+  /* For CEN syntax values it might be important to have the
+     separator character in the file name, not for XPG syntax.  */
+  if (syntax == xpg)
+    {
+      if (*territory != NULL && (*territory)[0] == '\0')
+       mask &= ~TERRITORY;
+
+      if (*codeset != NULL && (*codeset)[0] == '\0')
+       mask &= ~XPG_CODESET;
+
+      if (*modifier != NULL && (*modifier)[0] == '\0')
+       mask &= ~XPG_MODIFIER;
+    }
+
+  return mask;
+}
diff --git a/bacula/intl/finddomain.c b/bacula/intl/finddomain.c
new file mode 100644 (file)
index 0000000..81ea29b
--- /dev/null
@@ -0,0 +1,216 @@
+/* Handle list of needed message catalogs
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   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.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+#  define strchr index
+# endif
+#endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+/* List of already loaded domains.  */
+static struct loaded_l10nfile *_nl_loaded_domains;
+
+
+/* Return a data structure describing the message catalog described by
+   the DOMAINNAME and CATEGORY parameters with respect to the currently
+   established bindings.  */
+struct loaded_l10nfile *
+internal_function
+_nl_find_domain (dirname, locale, domainname)
+     const char *dirname;
+     char *locale;
+     const char *domainname;
+{
+  struct loaded_l10nfile *retval;
+  const char *language;
+  const char *modifier;
+  const char *territory;
+  const char *codeset;
+  const char *normalized_codeset;
+  const char *special;
+  const char *sponsor;
+  const char *revision;
+  const char *alias_value;
+  int mask;
+
+  /* LOCALE can consist of up to four recognized parts for the XPG syntax:
+
+               language[_territory[.codeset]][@modifier]
+
+     and six parts for the CEN syntax:
+
+       language[_territory][+audience][+special][,[sponsor][_revision]]
+
+     Beside the first part all of them are allowed to be missing.  If
+     the full specified locale is not found, the less specific one are
+     looked for.  The various parts will be stripped off according to
+     the following order:
+               (1) revision
+               (2) sponsor
+               (3) special
+               (4) codeset
+               (5) normalized codeset
+               (6) territory
+               (7) audience/modifier
+   */
+
+  /* If we have already tested for this locale entry there has to
+     be one data set in the list of loaded domains.  */
+  retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
+                              strlen (dirname) + 1, 0, locale, NULL, NULL,
+                              NULL, NULL, NULL, NULL, NULL, domainname, 0);
+  if (retval != NULL)
+    {
+      /* We know something about this locale.  */
+      int cnt;
+
+      if (retval->decided == 0)
+       _nl_load_domain (retval);
+
+      if (retval->data != NULL)
+       return retval;
+
+      for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
+       {
+         if (retval->successor[cnt]->decided == 0)
+           _nl_load_domain (retval->successor[cnt]);
+
+         if (retval->successor[cnt]->data != NULL)
+           break;
+       }
+      return cnt >= 0 ? retval : NULL;
+      /* NOTREACHED */
+    }
+
+  /* See whether the locale value is an alias.  If yes its value
+     *overwrites* the alias name.  No test for the original value is
+     done.  */
+  alias_value = _nl_expand_alias (locale);
+  if (alias_value != NULL)
+    {
+#if defined _LIBC || defined HAVE_STRDUP
+      locale = strdup (alias_value);
+      if (locale == NULL)
+       return NULL;
+#else
+      size_t len = strlen (alias_value) + 1;
+      locale = (char *) malloc (len);
+      if (locale == NULL)
+       return NULL;
+
+      memcpy (locale, alias_value, len);
+#endif
+    }
+
+  /* Now we determine the single parts of the locale name.  First
+     look for the language.  Termination symbols are `_' and `@' if
+     we use XPG4 style, and `_', `+', and `,' if we use CEN syntax.  */
+  mask = _nl_explode_name (locale, &language, &modifier, &territory,
+                          &codeset, &normalized_codeset, &special,
+                          &sponsor, &revision);
+
+  /* Create all possible locale entries which might be interested in
+     generalization.  */
+  retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
+                              strlen (dirname) + 1, mask, language, territory,
+                              codeset, normalized_codeset, modifier, special,
+                              sponsor, revision, domainname, 1);
+  if (retval == NULL)
+    /* This means we are out of core.  */
+    return NULL;
+
+  if (retval->decided == 0)
+    _nl_load_domain (retval);
+  if (retval->data == NULL)
+    {
+      int cnt;
+      for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
+       {
+         if (retval->successor[cnt]->decided == 0)
+           _nl_load_domain (retval->successor[cnt]);
+         if (retval->successor[cnt]->data != NULL)
+           break;
+       }
+    }
+
+  /* The room for an alias was dynamically allocated.  Free it now.  */
+  if (alias_value != NULL)
+    free (locale);
+
+  return retval;
+}
+
+
+#ifdef _LIBC
+static void __attribute__ ((unused))
+free_mem (void)
+{
+  struct loaded_l10nfile *runp = _nl_loaded_domains;
+
+  while (runp != NULL)
+    {
+      struct loaded_l10nfile *here = runp;
+      if (runp->data != NULL)
+       _nl_unload_domain ((struct loaded_domain *) runp->data);
+      runp = runp->next;
+      free (here);
+    }
+}
+
+text_set_element (__libc_subfreeres, free_mem);
+#endif
diff --git a/bacula/intl/gettext.c b/bacula/intl/gettext.c
new file mode 100644 (file)
index 0000000..d929f98
--- /dev/null
@@ -0,0 +1,70 @@
+/* Implementation of gettext(3) function.
+   Copyright (C) 1995, 1997 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define __need_NULL
+# include <stddef.h>
+#else
+# ifdef STDC_HEADERS
+#  include <stdlib.h>          /* Just for NULL.  */
+# else
+#  ifdef HAVE_STRING_H
+#   include <string.h>
+#  else
+#   define NULL ((void *) 0)
+#  endif
+# endif
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define GETTEXT __gettext
+# define DGETTEXT __dgettext
+#else
+# define GETTEXT gettext__
+# define DGETTEXT dgettext__
+#endif
+
+/* Look up MSGID in the current default message catalog for the current
+   LC_MESSAGES locale.  If not found, returns MSGID itself (the default
+   text).  */
+char *
+GETTEXT (msgid)
+     const char *msgid;
+{
+  return DGETTEXT (NULL, msgid);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__gettext, gettext);
+#endif
diff --git a/bacula/intl/gettext.h b/bacula/intl/gettext.h
new file mode 100644 (file)
index 0000000..3cd23d7
--- /dev/null
@@ -0,0 +1,105 @@
+/* Internal header for GNU gettext internationalization functions.
+   Copyright (C) 1995, 1997 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 Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETTEXT_H
+#define _GETTEXT_H 1
+
+#include <stdio.h>
+
+#if HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* @@ end of prolog @@ */
+
+/* The magic number of the GNU message catalog format.  */
+#define _MAGIC 0x950412de
+#define _MAGIC_SWAPPED 0xde120495
+
+/* Revision number of the currently used .mo (binary) file format.  */
+#define MO_REVISION_NUMBER 0
+
+/* The following contortions are an attempt to use the C preprocessor
+   to determine an unsigned integral type that is 32 bits wide.  An
+   alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+   doing that would require that the configure script compile and *run*
+   the resulting executable.  Locally running cross-compiled executables
+   is usually not possible.  */
+
+#if __STDC__
+# define UINT_MAX_32_BITS 4294967295U
+#else
+# define UINT_MAX_32_BITS 0xFFFFFFFF
+#endif
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+   This should be valid for all systems GNU cares about because
+   that doesn't include 16-bit systems, and only modern systems
+   (that certainly have <limits.h>) have 64+-bit integral types.  */
+
+#ifndef UINT_MAX
+# define UINT_MAX UINT_MAX_32_BITS
+#endif
+
+#if UINT_MAX == UINT_MAX_32_BITS
+typedef unsigned nls_uint32;
+#else
+# if USHRT_MAX == UINT_MAX_32_BITS
+typedef unsigned short nls_uint32;
+# else
+#  if ULONG_MAX == UINT_MAX_32_BITS
+typedef unsigned long nls_uint32;
+#  else
+  /* The following line is intended to throw an error.  Using #error is
+     not portable enough.  */
+  "Cannot determine unsigned 32-bit data type."
+#  endif
+# endif
+#endif
+
+
+/* Header for binary .mo file format.  */
+struct mo_file_header
+{
+  /* The magic number.  */
+  nls_uint32 magic;
+  /* The revision number of the file format.  */
+  nls_uint32 revision;
+  /* The number of strings pairs.  */
+  nls_uint32 nstrings;
+  /* Offset of table with start offsets of original strings.  */
+  nls_uint32 orig_tab_offset;
+  /* Offset of table with start offsets of translation strings.  */
+  nls_uint32 trans_tab_offset;
+  /* Size of hashing table.  */
+  nls_uint32 hash_tab_size;
+  /* Offset of first hashing entry.  */
+  nls_uint32 hash_tab_offset;
+};
+
+struct string_desc
+{
+  /* Length of addressed string.  */
+  nls_uint32 length;
+  /* Offset of string in file.  */
+  nls_uint32 offset;
+};
+
+/* @@ begin of epilog @@ */
+
+#endif /* gettext.h  */
diff --git a/bacula/intl/gettextP.h b/bacula/intl/gettextP.h
new file mode 100644 (file)
index 0000000..00c5203
--- /dev/null
@@ -0,0 +1,89 @@
+/* Header describing internals of gettext library
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   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.  */
+
+#ifndef _GETTEXTP_H
+#define _GETTEXTP_H
+
+#include "loadinfo.h"
+
+/* @@ end of prolog @@ */
+
+#ifndef PARAMS
+# if __STDC__
+#  define PARAMS(args) args
+# else
+#  define PARAMS(args) ()
+# endif
+#endif
+
+#ifndef internal_function
+# define internal_function
+#endif
+
+#ifndef W
+# define W(flag, data) ((flag) ? SWAP (data) : (data))
+#endif
+
+
+#ifdef _LIBC
+# include <byteswap.h>
+# define SWAP(i) bswap_32 (i)
+#else
+static nls_uint32 SWAP PARAMS ((nls_uint32 i));
+
+static inline nls_uint32
+SWAP (i)
+     nls_uint32 i;
+{
+  return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
+}
+#endif
+
+
+struct loaded_domain
+{
+  const char *data;
+  int use_mmap;
+  size_t mmap_size;
+  int must_swap;
+  nls_uint32 nstrings;
+  struct string_desc *orig_tab;
+  struct string_desc *trans_tab;
+  nls_uint32 hash_size;
+  nls_uint32 *hash_tab;
+};
+
+struct binding
+{
+  struct binding *next;
+  char *domainname;
+  char *dirname;
+};
+
+struct loaded_l10nfile *_nl_find_domain PARAMS ((const char *__dirname,
+                                                char *__locale,
+                                                const char *__domainname))
+     internal_function;
+void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain))
+     internal_function;
+void _nl_unload_domain PARAMS ((struct loaded_domain *__domain))
+     internal_function;
+
+/* @@ begin of epilog @@ */
+
+#endif /* gettextP.h  */
diff --git a/bacula/intl/hash-string.h b/bacula/intl/hash-string.h
new file mode 100644 (file)
index 0000000..cacb38e
--- /dev/null
@@ -0,0 +1,59 @@
+/* Implements a string hashing function.
+   Copyright (C) 1995, 1997 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 Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* @@ end of prolog @@ */
+
+#ifndef PARAMS
+# if __STDC__
+#  define PARAMS(Args) Args
+# else
+#  define PARAMS(Args) ()
+# endif
+#endif
+
+/* We assume to have `unsigned long int' value with at least 32 bits.  */
+#define HASHWORDBITS 32
+
+
+/* Defines the so called `hashpjw' function by P.J. Weinberger
+   [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+   1986, 1987 Bell Telephone Laboratories, Inc.]  */
+static unsigned long hash_string PARAMS ((const char *__str_param));
+
+static inline unsigned long
+hash_string (str_param)
+     const char *str_param;
+{
+  unsigned long int hval, g;
+  const char *str = str_param;
+
+  /* Compute the hash value for the given string.  */
+  hval = 0;
+  while (*str != '\0')
+    {
+      hval <<= 4;
+      hval += (unsigned long) *str++;
+      g = hval & ((unsigned long) 0xf << (HASHWORDBITS - 4));
+      if (g != 0)
+       {
+         hval ^= g >> (HASHWORDBITS - 8);
+         hval ^= g;
+       }
+    }
+  return hval;
+}
diff --git a/bacula/intl/intl-compat.c b/bacula/intl/intl-compat.c
new file mode 100644 (file)
index 0000000..503efa0
--- /dev/null
@@ -0,0 +1,76 @@
+/* intl-compat.c - Stub functions to call gettext functions from GNU gettext
+   Library.
+   Copyright (C) 1995 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libgettext.h"
+
+/* @@ end of prolog @@ */
+
+
+#undef gettext
+#undef dgettext
+#undef dcgettext
+#undef textdomain
+#undef bindtextdomain
+
+
+char *
+bindtextdomain (domainname, dirname)
+     const char *domainname;
+     const char *dirname;
+{
+  return bindtextdomain__ (domainname, dirname);
+}
+
+
+char *
+dcgettext (domainname, msgid, category)
+     const char *domainname;
+     const char *msgid;
+     int category;
+{
+  return dcgettext__ (domainname, msgid, category);
+}
+
+
+char *
+dgettext (domainname, msgid)
+     const char *domainname;
+     const char *msgid;
+{
+  return dgettext__ (domainname, msgid);
+}
+
+
+char *
+gettext (msgid)
+     const char *msgid;
+{
+  return gettext__ (msgid);
+}
+
+
+char *
+textdomain (domainname)
+     const char *domainname;
+{
+  return textdomain__ (domainname);
+}
diff --git a/bacula/intl/l10nflist.c b/bacula/intl/l10nflist.c
new file mode 100644 (file)
index 0000000..9c7dc18
--- /dev/null
@@ -0,0 +1,411 @@
+/* Handle list of needed message catalogs
+   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   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.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+
+#if defined HAVE_STRING_H || defined _LIBC
+# ifndef _GNU_SOURCE
+#  define _GNU_SOURCE  1
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+#  define strchr index
+# endif
+#endif
+
+#if defined _LIBC || defined HAVE_ARGZ_H
+# include <argz.h>
+#endif
+#include <ctype.h>
+#include <sys/types.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#include "loadinfo.h"
+
+/* On some strange systems still no definition of NULL is found.  Sigh!  */
+#ifndef NULL
+# if defined __STDC__ && __STDC__
+#  define NULL ((void *) 0)
+# else
+#  define NULL 0
+# endif
+#endif
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions.  This is required by the standard
+   because some ANSI C functions will require linking with this object
+   file and the name space must not be polluted.  */
+# ifndef stpcpy
+#  define stpcpy(dest, src) __stpcpy(dest, src)
+# endif
+#else
+# ifndef HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+# endif
+#endif
+
+/* Define function which are usually not available.  */
+
+#if !defined _LIBC && !defined HAVE___ARGZ_COUNT
+/* Returns the number of strings in ARGZ.  */
+static size_t argz_count__ PARAMS ((const char *argz, size_t len));
+
+static size_t
+argz_count__ (argz, len)
+     const char *argz;
+     size_t len;
+{
+  size_t count = 0;
+  while (len > 0)
+    {
+      size_t part_len = strlen (argz);
+      argz += part_len + 1;
+      len -= part_len + 1;
+      count++;
+    }
+  return count;
+}
+# undef __argz_count
+# define __argz_count(argz, len) argz_count__ (argz, len)
+#endif /* !_LIBC && !HAVE___ARGZ_COUNT */
+
+#if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
+/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+   except the last into the character SEP.  */
+static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
+
+static void
+argz_stringify__ (argz, len, sep)
+     char *argz;
+     size_t len;
+     int sep;
+{
+  while (len > 0)
+    {
+      size_t part_len = strlen (argz);
+      argz += part_len;
+      len -= part_len + 1;
+      if (len > 0)
+       *argz++ = sep;
+    }
+}
+# undef __argz_stringify
+# define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
+#endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
+
+#if !defined _LIBC && !defined HAVE___ARGZ_NEXT
+static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
+                                 const char *entry));
+
+static char *
+argz_next__ (argz, argz_len, entry)
+     char *argz;
+     size_t argz_len;
+     const char *entry;
+{
+  if (entry)
+    {
+      if (entry < argz + argz_len)
+        entry = strchr (entry, '\0') + 1;
+
+      return entry >= argz + argz_len ? NULL : (char *) entry;
+    }
+  else
+    if (argz_len > 0)
+      return argz;
+    else
+      return 0;
+}
+# undef __argz_next
+# define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
+#endif /* !_LIBC && !HAVE___ARGZ_NEXT */
+
+
+/* Return number of bits set in X.  */
+static int pop PARAMS ((int x));
+
+static inline int
+pop (x)
+     int x;
+{
+  /* We assume that no more than 16 bits are used.  */
+  x = ((x & ~0x5555) >> 1) + (x & 0x5555);
+  x = ((x & ~0x3333) >> 2) + (x & 0x3333);
+  x = ((x >> 4) + x) & 0x0f0f;
+  x = ((x >> 8) + x) & 0xff;
+
+  return x;
+}
+
+\f
+struct loaded_l10nfile *
+_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
+                   territory, codeset, normalized_codeset, modifier, special,
+                   sponsor, revision, filename, do_allocate)
+     struct loaded_l10nfile **l10nfile_list;
+     const char *dirlist;
+     size_t dirlist_len;
+     int mask;
+     const char *language;
+     const char *territory;
+     const char *codeset;
+     const char *normalized_codeset;
+     const char *modifier;
+     const char *special;
+     const char *sponsor;
+     const char *revision;
+     const char *filename;
+     int do_allocate;
+{
+  char *abs_filename;
+  struct loaded_l10nfile *last = NULL;
+  struct loaded_l10nfile *retval;
+  char *cp;
+  size_t entries;
+  int cnt;
+
+  /* Allocate room for the full file name.  */
+  abs_filename = (char *) malloc (dirlist_len
+                                 + strlen (language)
+                                 + ((mask & TERRITORY) != 0
+                                    ? strlen (territory) + 1 : 0)
+                                 + ((mask & XPG_CODESET) != 0
+                                    ? strlen (codeset) + 1 : 0)
+                                 + ((mask & XPG_NORM_CODESET) != 0
+                                    ? strlen (normalized_codeset) + 1 : 0)
+                                 + (((mask & XPG_MODIFIER) != 0
+                                     || (mask & CEN_AUDIENCE) != 0)
+                                    ? strlen (modifier) + 1 : 0)
+                                 + ((mask & CEN_SPECIAL) != 0
+                                    ? strlen (special) + 1 : 0)
+                                 + (((mask & CEN_SPONSOR) != 0
+                                     || (mask & CEN_REVISION) != 0)
+                                    ? (1 + ((mask & CEN_SPONSOR) != 0
+                                            ? strlen (sponsor) + 1 : 0)
+                                       + ((mask & CEN_REVISION) != 0
+                                          ? strlen (revision) + 1 : 0)) : 0)
+                                 + 1 + strlen (filename) + 1);
+
+  if (abs_filename == NULL)
+    return NULL;
+
+  retval = NULL;
+  last = NULL;
+
+  /* Construct file name.  */
+  memcpy (abs_filename, dirlist, dirlist_len);
+  __argz_stringify (abs_filename, dirlist_len, ':');
+  cp = abs_filename + (dirlist_len - 1);
+  *cp++ = '/';
+  cp = stpcpy (cp, language);
+
+  if ((mask & TERRITORY) != 0)
+    {
+      *cp++ = '_';
+      cp = stpcpy (cp, territory);
+    }
+  if ((mask & XPG_CODESET) != 0)
+    {
+      *cp++ = '.';
+      cp = stpcpy (cp, codeset);
+    }
+  if ((mask & XPG_NORM_CODESET) != 0)
+    {
+      *cp++ = '.';
+      cp = stpcpy (cp, normalized_codeset);
+    }
+  if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
+    {
+      /* This component can be part of both syntaces but has different
+        leading characters.  For CEN we use `+', else `@'.  */
+      *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
+      cp = stpcpy (cp, modifier);
+    }
+  if ((mask & CEN_SPECIAL) != 0)
+    {
+      *cp++ = '+';
+      cp = stpcpy (cp, special);
+    }
+  if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
+    {
+      *cp++ = ',';
+      if ((mask & CEN_SPONSOR) != 0)
+       cp = stpcpy (cp, sponsor);
+      if ((mask & CEN_REVISION) != 0)
+       {
+         *cp++ = '_';
+         cp = stpcpy (cp, revision);
+       }
+    }
+
+  *cp++ = '/';
+  stpcpy (cp, filename);
+
+  /* Look in list of already loaded domains whether it is already
+     available.  */
+  last = NULL;
+  for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
+    if (retval->filename != NULL)
+      {
+       int compare = strcmp (retval->filename, abs_filename);
+       if (compare == 0)
+         /* We found it!  */
+         break;
+       if (compare < 0)
+         {
+           /* It's not in the list.  */
+           retval = NULL;
+           break;
+         }
+
+       last = retval;
+      }
+
+  if (retval != NULL || do_allocate == 0)
+    {
+      free (abs_filename);
+      return retval;
+    }
+
+  retval = (struct loaded_l10nfile *)
+    malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
+                               * (1 << pop (mask))
+                               * sizeof (struct loaded_l10nfile *)));
+  if (retval == NULL)
+    return NULL;
+
+  retval->filename = abs_filename;
+  retval->decided = (__argz_count (dirlist, dirlist_len) != 1
+                    || ((mask & XPG_CODESET) != 0
+                        && (mask & XPG_NORM_CODESET) != 0));
+  retval->data = NULL;
+
+  if (last == NULL)
+    {
+      retval->next = *l10nfile_list;
+      *l10nfile_list = retval;
+    }
+  else
+    {
+      retval->next = last->next;
+      last->next = retval;
+    }
+
+  entries = 0;
+  /* If the DIRLIST is a real list the RETVAL entry corresponds not to
+     a real file.  So we have to use the DIRLIST separation mechanism
+     of the inner loop.  */
+  cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
+  for (; cnt >= 0; --cnt)
+    if ((cnt & ~mask) == 0
+       && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
+       && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
+      {
+       /* Iterate over all elements of the DIRLIST.  */
+       char *dir = NULL;
+
+       while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
+              != NULL)
+         retval->successor[entries++]
+           = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
+                                 language, territory, codeset,
+                                 normalized_codeset, modifier, special,
+                                 sponsor, revision, filename, 1);
+      }
+  retval->successor[entries] = NULL;
+
+  return retval;
+}
+\f
+/* Normalize codeset name.  There is no standard for the codeset
+   names.  Normalization allows the user to use any of the common
+   names.  */
+const char *
+_nl_normalize_codeset (codeset, name_len)
+     const unsigned char *codeset;
+     size_t name_len;
+{
+  int len = 0;
+  int only_digit = 1;
+  char *retval;
+  char *wp;
+  size_t cnt;
+
+  for (cnt = 0; cnt < name_len; ++cnt)
+    if (isalnum (codeset[cnt]))
+      {
+       ++len;
+
+       if (isalpha (codeset[cnt]))
+         only_digit = 0;
+      }
+
+  retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
+
+  if (retval != NULL)
+    {
+      if (only_digit)
+       wp = stpcpy (retval, "iso");
+      else
+       wp = retval;
+
+      for (cnt = 0; cnt < name_len; ++cnt)
+       if (isalpha (codeset[cnt]))
+         *wp++ = tolower (codeset[cnt]);
+       else if (isdigit (codeset[cnt]))
+         *wp++ = codeset[cnt];
+
+      *wp = '\0';
+    }
+
+  return (const char *) retval;
+}
+
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library.  So we
+   avoid the non-standard function stpcpy.  In GNU C Library this
+   function is available, though.  Also allow the symbol HAVE_STPCPY
+   to be defined.  */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+     char *dest;
+     const char *src;
+{
+  while ((*dest++ = *src++) != '\0')
+    /* Do nothing. */ ;
+  return dest - 1;
+}
+#endif
diff --git a/bacula/intl/libgettext.h b/bacula/intl/libgettext.h
new file mode 100644 (file)
index 0000000..3a92960
--- /dev/null
@@ -0,0 +1,182 @@
+/* Message catalogs for internationalization.
+   Copyright (C) 1995, 1996, 1997, 1998 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Because on some systems (e.g. Solaris) we sometimes have to include
+   the systems libintl.h as well as this file we have more complex
+   include protection above.  But the systems header might perhaps also
+   define _LIBINTL_H and therefore we have to protect the definition here.  */
+
+#if !defined _LIBINTL_H || !defined _LIBGETTEXT_H
+#ifndef _LIBINTL_H
+# define _LIBINTL_H    1
+#endif
+#define _LIBGETTEXT_H  1
+
+/* We define an additional symbol to signal that we use the GNU
+   implementation of gettext.  */
+#define __USE_GNU_GETTEXT 1
+
+#include <sys/types.h>
+
+#if HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* @@ end of prolog @@ */
+
+#ifndef PARAMS
+# if __STDC__ || defined __cplusplus
+#  define PARAMS(args) args
+# else
+#  define PARAMS(args) ()
+# endif
+#endif
+
+#ifndef NULL
+# if !defined __cplusplus || defined __GNUC__
+#  define NULL ((void *) 0)
+# else
+#  define NULL (0)
+# endif
+#endif
+
+#if !HAVE_LC_MESSAGES
+/* This value determines the behaviour of the gettext() and dgettext()
+   function.  But some system does not have this defined.  Define it
+   to a default value.  */
+# define LC_MESSAGES (-1)
+#endif
+
+
+/* Declarations for gettext-using-catgets interface.  Derived from
+   Jim Meyering's libintl.h.  */
+struct _msg_ent
+{
+  const char *_msg;
+  int _msg_number;
+};
+
+
+#if HAVE_CATGETS
+/* These two variables are defined in the automatically by po-to-tbl.sed
+   generated file `cat-id-tbl.c'.  */
+extern const struct _msg_ent _msg_tbl[];
+extern int _msg_tbl_length;
+#endif
+
+
+/* For automatical extraction of messages sometimes no real
+   translation is needed.  Instead the string itself is the result.  */
+#define gettext_noop(Str) (Str)
+
+/* Look up MSGID in the current default message catalog for the current
+   LC_MESSAGES locale.  If not found, returns MSGID itself (the default
+   text).  */
+extern char *gettext PARAMS ((const char *__msgid));
+extern char *gettext__ PARAMS ((const char *__msgid));
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current
+   LC_MESSAGES locale.  */
+extern char *dgettext PARAMS ((const char *__domainname, const char *__msgid));
+extern char *dgettext__ PARAMS ((const char *__domainname,
+                                const char *__msgid));
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+   locale.  */
+extern char *dcgettext PARAMS ((const char *__domainname, const char *__msgid,
+                               int __category));
+extern char *dcgettext__ PARAMS ((const char *__domainname,
+                                 const char *__msgid, int __category));
+
+
+/* Set the current default message catalog to DOMAINNAME.
+   If DOMAINNAME is null, return the current default.
+   If DOMAINNAME is "", reset to the default of "messages".  */
+extern char *textdomain PARAMS ((const char *__domainname));
+extern char *textdomain__ PARAMS ((const char *__domainname));
+
+/* Specify that the DOMAINNAME message catalog will be found
+   in DIRNAME rather than in the system locale data base.  */
+extern char *bindtextdomain PARAMS ((const char *__domainname,
+                                 const char *__dirname));
+extern char *bindtextdomain__ PARAMS ((const char *__domainname,
+                                   const char *__dirname));
+
+#if ENABLE_NLS
+
+/* Solaris 2.3 has the gettext function but dcgettext is missing.
+   So we omit this optimization for Solaris 2.3.  BTW, Solaris 2.4
+   has dcgettext.  */
+# if !HAVE_CATGETS && (!HAVE_GETTEXT || HAVE_DCGETTEXT)
+
+#  define gettext(Msgid)                                                     \
+     dgettext (NULL, Msgid)
+
+#  define dgettext(Domainname, Msgid)                                        \
+     dcgettext (Domainname, Msgid, LC_MESSAGES)
+
+#  if defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+/* This global variable is defined in loadmsgcat.c.  We need a sign,
+   whether a new catalog was loaded, which can be associated with all
+   translations.  */
+extern int _nl_msg_cat_cntr;
+
+#   define dcgettext(Domainname, Msgid, Category)                            \
+  (__extension__                                                             \
+   ({                                                                        \
+     char *__result;                                                         \
+     if (__builtin_constant_p (Msgid))                                       \
+       {                                                                     \
+        static char *__translation__;                                        \
+        static int __catalog_counter__;                                      \
+        if (! __translation__ || __catalog_counter__ != _nl_msg_cat_cntr)    \
+          {                                                                  \
+            __translation__ =                                                \
+              dcgettext__ (Domainname, Msgid, Category);                     \
+            __catalog_counter__ = _nl_msg_cat_cntr;                          \
+          }                                                                  \
+        __result = __translation__;                                          \
+       }                                                                     \
+     else                                                                    \
+       __result = dcgettext__ (Domainname, Msgid, Category);                 \
+     __result;                                                               \
+    }))
+#  endif
+# endif
+
+#else
+
+# define gettext(Msgid) (Msgid)
+# define dgettext(Domainname, Msgid) (Msgid)
+# define dcgettext(Domainname, Msgid, Category) (Msgid)
+# define textdomain(Domainname) ((char *) Domainname)
+# define bindtextdomain(Domainname, Dirname) ((char *) Dirname)
+
+#endif
+
+/* @@ begin of epilog @@ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bacula/intl/linux-msg.sed b/bacula/intl/linux-msg.sed
new file mode 100644 (file)
index 0000000..5918e72
--- /dev/null
@@ -0,0 +1,100 @@
+# po2msg.sed - Convert Uniforum style .po file to Linux style .msg file
+# Copyright (C) 1995 Free Software Foundation, Inc.
+# Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+#
+# 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.
+#
+#
+# The first directive in the .msg should be the definition of the
+# message set number.  We use always set number 1.
+#
+1 {
+  i\
+$set 1 # Automatically created by po2msg.sed
+  h
+  s/.*/0/
+  x
+}
+#
+# Mitch's old catalog format does not allow comments.
+#
+# We copy the original message as a comment into the .msg file.
+#
+/^msgid/ {
+  s/msgid[     ]*"//
+#
+# This does not work now with the new format.
+# /"$/! {
+#   s/\\$//
+#   s/$/ ... (more lines following)"/
+# }
+  x
+# The following nice solution is by
+# Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de>
+  td
+# Increment a decimal number in pattern space.
+# First hide trailing `9' digits.
+  :d
+  s/9\(_*\)$/_\1/
+  td
+# Assure at least one digit is available.
+  s/^\(_*\)$/0\1/
+# Increment the last digit.
+  s/8\(_*\)$/9\1/
+  s/7\(_*\)$/8\1/
+  s/6\(_*\)$/7\1/
+  s/5\(_*\)$/6\1/
+  s/4\(_*\)$/5\1/
+  s/3\(_*\)$/4\1/
+  s/2\(_*\)$/3\1/
+  s/1\(_*\)$/2\1/
+  s/0\(_*\)$/1\1/
+# Convert the hidden `9' digits to `0's.
+  s/_/0/g
+  x
+  G
+  s/\(.*\)"\n\([0-9]*\)/$ #\2 Original Message:(\1)/p
+}
+#
+# The .msg file contains, other then the .po file, only the translations
+# but each given a unique ID.  Starting from 1 and incrementing by 1 for
+# each message we assign them to the messages.
+# It is important that the .po file used to generate the cat-id-tbl.c file
+# (with po-to-tbl) is the same as the one used here.  (At least the order
+# of declarations must not be changed.)
+#
+/^msgstr/ {
+  s/msgstr[    ]*"\(.*\)"/# \1/
+# Clear substitution flag.
+  tb
+# Append the next line.
+  :b
+  N
+# Look whether second part is continuation line.
+  s/\(.*\n\)"\(.*\)"/\1\2/
+# Yes, then branch.
+  ta
+  P
+  D
+# Note that D includes a jump to the start!!
+# We found a continuation line.  But before printing insert '\'.
+  :a
+  s/\(.*\)\(\n.*\)/\1\\\2/
+  P
+# We cannot use D here.
+  s/.*\n\(.*\)/\1/
+  tb
+}
+d
diff --git a/bacula/intl/loadinfo.h b/bacula/intl/loadinfo.h
new file mode 100644 (file)
index 0000000..f4ebf6d
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 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, 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.  */
+
+#ifndef PARAMS
+# if __STDC__
+#  define PARAMS(args) args
+# else
+#  define PARAMS(args) ()
+# endif
+#endif
+
+/* Encoding of locale name parts.  */
+#define CEN_REVISION           1
+#define CEN_SPONSOR            2
+#define CEN_SPECIAL            4
+#define XPG_NORM_CODESET       8
+#define XPG_CODESET            16
+#define TERRITORY              32
+#define CEN_AUDIENCE           64
+#define XPG_MODIFIER           128
+
+#define CEN_SPECIFIC   (CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE)
+#define XPG_SPECIFIC   (XPG_CODESET|XPG_NORM_CODESET|XPG_MODIFIER)
+
+
+struct loaded_l10nfile
+{
+  const char *filename;
+  int decided;
+
+  const void *data;
+
+  struct loaded_l10nfile *next;
+  struct loaded_l10nfile *successor[1];
+};
+
+
+extern const char *_nl_normalize_codeset PARAMS ((const unsigned char *codeset,
+                                                 size_t name_len));
+
+extern struct loaded_l10nfile *
+_nl_make_l10nflist PARAMS ((struct loaded_l10nfile **l10nfile_list,
+                           const char *dirlist, size_t dirlist_len, int mask,
+                           const char *language, const char *territory,
+                           const char *codeset,
+                           const char *normalized_codeset,
+                           const char *modifier, const char *special,
+                           const char *sponsor, const char *revision,
+                           const char *filename, int do_allocate));
+
+
+extern const char *_nl_expand_alias PARAMS ((const char *name));
+
+extern int _nl_explode_name PARAMS ((char *name, const char **language,
+                                    const char **modifier,
+                                    const char **territory,
+                                    const char **codeset,
+                                    const char **normalized_codeset,
+                                    const char **special,
+                                    const char **sponsor,
+                                    const char **revision));
diff --git a/bacula/intl/loadmsgcat.c b/bacula/intl/loadmsgcat.c
new file mode 100644 (file)
index 0000000..515892d
--- /dev/null
@@ -0,0 +1,222 @@
+/* Load needed message catalogs.
+   Copyright (C) 1995, 1996, 1997, 1998 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP) || defined _LIBC
+# include <sys/mman.h>
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ISO C functions.  This is required by the standard
+   because some ISO C functions will require linking with this object
+   file and the name space must not be polluted.  */
+# define open   __open
+# define close  __close
+# define read   __read
+# define mmap   __mmap
+# define munmap __munmap
+#endif
+
+/* We need a sign, whether a new catalog was loaded, which can be associated
+   with all translations.  This is important if the translations are
+   cached by one of GCC's features.  */
+int _nl_msg_cat_cntr = 0;
+
+
+/* Load the message catalogs specified by FILENAME.  If it is no valid
+   message catalog do nothing.  */
+void
+internal_function
+_nl_load_domain (domain_file)
+     struct loaded_l10nfile *domain_file;
+{
+  int fd;
+  size_t size;
+  struct stat st;
+  struct mo_file_header *data = (struct mo_file_header *) -1;
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+    || defined _LIBC
+  int use_mmap = 0;
+#endif
+  struct loaded_domain *domain;
+
+  domain_file->decided = 1;
+  domain_file->data = NULL;
+
+  /* If the record does not represent a valid locale the FILENAME
+     might be NULL.  This can happen when according to the given
+     specification the locale file name is different for XPG and CEN
+     syntax.  */
+  if (domain_file->filename == NULL)
+    return;
+
+  /* Try to open the addressed file.  */
+  fd = open (domain_file->filename, O_RDONLY);
+  if (fd == -1)
+    return;
+
+  /* We must know about the size of the file.  */
+  if (fstat (fd, &st) != 0
+      || (size = (size_t) st.st_size) != st.st_size
+      || size < sizeof (struct mo_file_header))
+    {
+      /* Something went wrong.  */
+      close (fd);
+      return;
+    }
+
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+    || defined _LIBC
+  /* Now we are ready to load the file.  If mmap() is available we try
+     this first.  If not available or it failed we try to load it.  */
+  data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
+                                        MAP_PRIVATE, fd, 0);
+
+  if (data != (struct mo_file_header *) -1)
+    {
+      /* mmap() call was successful.  */
+      close (fd);
+      use_mmap = 1;
+    }
+#endif
+
+  /* If the data is not yet available (i.e. mmap'ed) we try to load
+     it manually.  */
+  if (data == (struct mo_file_header *) -1)
+    {
+      size_t to_read;
+      char *read_ptr;
+
+      data = (struct mo_file_header *) malloc (size);
+      if (data == NULL)
+       return;
+
+      to_read = size;
+      read_ptr = (char *) data;
+      do
+       {
+         long int nb = (long int) read (fd, read_ptr, to_read);
+         if (nb == -1)
+           {
+             close (fd);
+             return;
+           }
+
+         read_ptr += nb;
+         to_read -= nb;
+       }
+      while (to_read > 0);
+
+      close (fd);
+    }
+
+  /* Using the magic number we can test whether it really is a message
+     catalog file.  */
+  if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
+    {
+      /* The magic number is wrong: not a message catalog file.  */
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+    || defined _LIBC
+      if (use_mmap)
+       munmap ((caddr_t) data, size);
+      else
+#endif
+       free (data);
+      return;
+    }
+
+  domain_file->data
+    = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
+  if (domain_file->data == NULL)
+    return;
+
+  domain = (struct loaded_domain *) domain_file->data;
+  domain->data = (char *) data;
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+    || defined _LIBC
+  domain->use_mmap = use_mmap;
+#endif
+  domain->mmap_size = size;
+  domain->must_swap = data->magic != _MAGIC;
+
+  /* Fill in the information about the available tables.  */
+  switch (W (domain->must_swap, data->revision))
+    {
+    case 0:
+      domain->nstrings = W (domain->must_swap, data->nstrings);
+      domain->orig_tab = (struct string_desc *)
+       ((char *) data + W (domain->must_swap, data->orig_tab_offset));
+      domain->trans_tab = (struct string_desc *)
+       ((char *) data + W (domain->must_swap, data->trans_tab_offset));
+      domain->hash_size = W (domain->must_swap, data->hash_tab_size);
+      domain->hash_tab = (nls_uint32 *)
+       ((char *) data + W (domain->must_swap, data->hash_tab_offset));
+      break;
+    default:
+      /* This is an illegal revision.  */
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+    || defined _LIBC
+      if (use_mmap)
+       munmap ((caddr_t) data, size);
+      else
+#endif
+       free (data);
+      free (domain);
+      domain_file->data = NULL;
+      return;
+    }
+
+  /* Show that one domain is changed.  This might make some cached
+     translations invalid.  */
+  ++_nl_msg_cat_cntr;
+}
+
+
+#ifdef _LIBC
+void
+internal_function
+_nl_unload_domain (domain)
+     struct loaded_domain *domain;
+{
+  if (domain->use_mmap)
+    munmap ((caddr_t) domain->data, domain->mmap_size);
+  else
+    free ((void *) domain->data);
+
+  free (domain);
+}
+#endif
diff --git a/bacula/intl/localealias.c b/bacula/intl/localealias.c
new file mode 100644 (file)
index 0000000..bca555a
--- /dev/null
@@ -0,0 +1,424 @@
+/* Handle aliases for locale names.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   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.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# if defined HAVE_ALLOCA_H || defined _LIBC
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca
+char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+char *getenv ();
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# ifndef _GNU_SOURCE
+#  define _GNU_SOURCE  1
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+#  define strchr index
+# endif
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions.  This is required by the standard
+   because some ANSI C functions will require linking with this object
+   file and the name space must not be polluted.  */
+# define strcasecmp __strcasecmp
+
+# define mempcpy __mempcpy
+# define HAVE_MEMPCPY  1
+
+/* We need locking here since we can be called from different places.  */
+# include <bits/libc-lock.h>
+
+__libc_lock_define_initialized (static, lock);
+#endif
+
+
+/* For those loosing systems which don't have `alloca' we have to add
+   some additional code emulating it.  */
+#ifdef HAVE_ALLOCA
+/* Nothing has to be done.  */
+# define ADD_BLOCK(list, address) /* nothing */
+# define FREE_BLOCKS(list) /* nothing */
+#else
+struct block_list
+{
+  void *address;
+  struct block_list *next;
+};
+# define ADD_BLOCK(list, addr)                                               \
+  do {                                                                       \
+    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
+    /* If we cannot get a free block we cannot add the new element to        \
+       the list.  */                                                         \
+    if (newp != NULL) {                                                              \
+      newp->address = (addr);                                                \
+      newp->next = (list);                                                   \
+      (list) = newp;                                                         \
+    }                                                                        \
+  } while (0)
+# define FREE_BLOCKS(list)                                                   \
+  do {                                                                       \
+    while (list != NULL) {                                                   \
+      struct block_list *old = list;                                         \
+      list = list->next;                                                     \
+      free (old);                                                            \
+    }                                                                        \
+  } while (0)
+# undef alloca
+# define alloca(size) (malloc (size))
+#endif /* have alloca */
+
+
+struct alias_map
+{
+  const char *alias;
+  const char *value;
+};
+
+
+static char *string_space = NULL;
+static size_t string_space_act = 0;
+static size_t string_space_max = 0;
+static struct alias_map *map;
+static size_t nmap = 0;
+static size_t maxmap = 0;
+
+
+/* Prototypes for local functions.  */
+static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
+     internal_function;
+static void extend_alias_table PARAMS ((void));
+static int alias_compare PARAMS ((const struct alias_map *map1,
+                                 const struct alias_map *map2));
+
+
+const char *
+_nl_expand_alias (name)
+    const char *name;
+{
+  static const char *locale_alias_path = LOCALE_ALIAS_PATH;
+  struct alias_map *retval;
+  const char *result = NULL;
+  size_t added;
+
+#ifdef _LIBC
+  __libc_lock_lock (lock);
+#endif
+
+  do
+    {
+      struct alias_map item;
+
+      item.alias = name;
+
+      if (nmap > 0)
+       retval = (struct alias_map *) bsearch (&item, map, nmap,
+                                              sizeof (struct alias_map),
+                                              (int (*) PARAMS ((const void *,
+                                                                const void *))
+                                               ) alias_compare);
+      else
+       retval = NULL;
+
+      /* We really found an alias.  Return the value.  */
+      if (retval != NULL)
+       {
+         result = retval->value;
+         break;
+       }
+
+      /* Perhaps we can find another alias file.  */
+      added = 0;
+      while (added == 0 && locale_alias_path[0] != '\0')
+       {
+         const char *start;
+
+         while (locale_alias_path[0] == ':')
+           ++locale_alias_path;
+         start = locale_alias_path;
+
+         while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
+           ++locale_alias_path;
+
+         if (start < locale_alias_path)
+           added = read_alias_file (start, locale_alias_path - start);
+       }
+    }
+  while (added != 0);
+
+#ifdef _LIBC
+  __libc_lock_unlock (lock);
+#endif
+
+  return result;
+}
+
+
+static size_t
+internal_function
+read_alias_file (fname, fname_len)
+     const char *fname;
+     int fname_len;
+{
+#ifndef HAVE_ALLOCA
+  struct block_list *block_list = NULL;
+#endif
+  FILE *fp;
+  char *full_fname;
+  size_t added;
+  static const char aliasfile[] = "/locale.alias";
+
+  full_fname = (char *) alloca (fname_len + sizeof aliasfile);
+  ADD_BLOCK (block_list, full_fname);
+#ifdef HAVE_MEMPCPY
+  mempcpy (mempcpy (full_fname, fname, fname_len),
+          aliasfile, sizeof aliasfile);
+#else
+  memcpy (full_fname, fname, fname_len);
+  memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
+#endif
+
+  fp = fopen (full_fname, "r");
+  if (fp == NULL)
+    {
+      FREE_BLOCKS (block_list);
+      return 0;
+    }
+
+  added = 0;
+  while (!feof (fp))
+    {
+      /* It is a reasonable approach to use a fix buffer here because
+        a) we are only interested in the first two fields
+        b) these fields must be usable as file names and so must not
+           be that long
+       */
+      unsigned char buf[BUFSIZ];
+      unsigned char *alias;
+      unsigned char *value;
+      unsigned char *cp;
+
+      if (fgets (buf, sizeof buf, fp) == NULL)
+       /* EOF reached.  */
+       break;
+
+      /* Possibly not the whole line fits into the buffer.  Ignore
+        the rest of the line.  */
+      if (strchr (buf, '\n') == NULL)
+       {
+         char altbuf[BUFSIZ];
+         do
+           if (fgets (altbuf, sizeof altbuf, fp) == NULL)
+             /* Make sure the inner loop will be left.  The outer loop
+                will exit at the `feof' test.  */
+             break;
+         while (strchr (altbuf, '\n') == NULL);
+       }
+
+      cp = buf;
+      /* Ignore leading white space.  */
+      while (isspace (cp[0]))
+       ++cp;
+
+      /* A leading '#' signals a comment line.  */
+      if (cp[0] != '\0' && cp[0] != '#')
+       {
+         alias = cp++;
+         while (cp[0] != '\0' && !isspace (cp[0]))
+           ++cp;
+         /* Terminate alias name.  */
+         if (cp[0] != '\0')
+           *cp++ = '\0';
+
+         /* Now look for the beginning of the value.  */
+         while (isspace (cp[0]))
+           ++cp;
+
+         if (cp[0] != '\0')
+           {
+             size_t alias_len;
+             size_t value_len;
+
+             value = cp++;
+             while (cp[0] != '\0' && !isspace (cp[0]))
+               ++cp;
+             /* Terminate value.  */
+             if (cp[0] == '\n')
+               {
+                 /* This has to be done to make the following test
+                    for the end of line possible.  We are looking for
+                    the terminating '\n' which do not overwrite here.  */
+                 *cp++ = '\0';
+                 *cp = '\n';
+               }
+             else if (cp[0] != '\0')
+               *cp++ = '\0';
+
+             if (nmap >= maxmap)
+               extend_alias_table ();
+
+             alias_len = strlen (alias) + 1;
+             value_len = strlen (value) + 1;
+
+             if (string_space_act + alias_len + value_len > string_space_max)
+               {
+                 /* Increase size of memory pool.  */
+                 size_t new_size = (string_space_max
+                                    + (alias_len + value_len > 1024
+                                       ? alias_len + value_len : 1024));
+                 char *new_pool = (char *) realloc (string_space, new_size);
+                 if (new_pool == NULL)
+                   {
+                     FREE_BLOCKS (block_list);
+                     return added;
+                   }
+                 string_space = new_pool;
+                 string_space_max = new_size;
+               }
+
+             map[nmap].alias = memcpy (&string_space[string_space_act],
+                                       alias, alias_len);
+             string_space_act += alias_len;
+
+             map[nmap].value = memcpy (&string_space[string_space_act],
+                                       value, value_len);
+             string_space_act += value_len;
+
+             ++nmap;
+             ++added;
+           }
+       }
+    }
+
+  /* Should we test for ferror()?  I think we have to silently ignore
+     errors.  --drepper  */
+  fclose (fp);
+
+  if (added > 0)
+    qsort (map, nmap, sizeof (struct alias_map),
+          (int (*) PARAMS ((const void *, const void *))) alias_compare);
+
+  FREE_BLOCKS (block_list);
+  return added;
+}
+
+
+static void
+extend_alias_table ()
+{
+  size_t new_size;
+  struct alias_map *new_map;
+
+  new_size = maxmap == 0 ? 100 : 2 * maxmap;
+  new_map = (struct alias_map *) realloc (map, (new_size
+                                               * sizeof (struct alias_map)));
+  if (new_map == NULL)
+    /* Simply don't extend: we don't have any more core.  */
+    return;
+
+  map = new_map;
+  maxmap = new_size;
+}
+
+
+#ifdef _LIBC
+static void __attribute__ ((unused))
+free_mem (void)
+{
+  if (string_space != NULL)
+    free (string_space);
+  if (map != NULL)
+    free (map);
+}
+text_set_element (__libc_subfreeres, free_mem);
+#endif
+
+
+static int
+alias_compare (map1, map2)
+     const struct alias_map *map1;
+     const struct alias_map *map2;
+{
+#if defined _LIBC || defined HAVE_STRCASECMP
+  return strcasecmp (map1->alias, map2->alias);
+#else
+  const unsigned char *p1 = (const unsigned char *) map1->alias;
+  const unsigned char *p2 = (const unsigned char *) map2->alias;
+  unsigned char c1, c2;
+
+  if (p1 == p2)
+    return 0;
+
+  do
+    {
+      /* I know this seems to be odd but the tolower() function in
+        some systems libc cannot handle nonalpha characters.  */
+      c1 = isupper (*p1) ? tolower (*p1) : *p1;
+      c2 = isupper (*p2) ? tolower (*p2) : *p2;
+      if (c1 == '\0')
+       break;
+      ++p1;
+      ++p2;
+    }
+  while (c1 == c2);
+
+  return c1 - c2;
+#endif
+}
diff --git a/bacula/intl/po2tbl.sed b/bacula/intl/po2tbl.sed
new file mode 100644 (file)
index 0000000..93c0435
--- /dev/null
@@ -0,0 +1,60 @@
+1 {
+  i\
+/* Automatically generated by po2tbl.sed from @PACKAGE NAME@.pot.  */\
+\
+#if HAVE_CONFIG_H\
+# include <config.h>\
+#endif\
+\
+#include "libgettext.h"\
+\
+const struct _msg_ent _msg_tbl[] = {
+  h
+  s/.*/0/
+  x
+}
+/^msgid/ {
+  s/msgid[     ]*\(".*"\)/  {\1/
+  tb
+  :b
+  N
+  s/\(.*\)"\(\n\)"\(.*"\)/\1\2\3/
+  ta
+  s/\(.*\)\n.*/\1/
+  bc
+  :a
+  s/\(.*\)\(\n.*\)/\1\\\2/
+  P
+  s/.*\n\(.*\)/\1/
+  tb
+  :c
+  x
+  td
+  :d
+  s/9\(_*\)$/_\1/
+  td
+  s/^\(_*\)$/0\1/
+  s/8\(_*\)$/9\1/
+  s/7\(_*\)$/8\1/
+  s/6\(_*\)$/7\1/
+  s/5\(_*\)$/6\1/
+  s/4\(_*\)$/5\1/
+  s/3\(_*\)$/4\1/
+  s/2\(_*\)$/3\1/
+  s/1\(_*\)$/2\1/
+  s/0\(_*\)$/1\1/
+  s/_/0/g
+  x
+  G
+  s/\(.*\)\n\([0-9]*\)/\1, \2},/
+  s/\(.*\)"$/\1/
+  p
+}
+$ {
+  i\
+};\
+
+  g
+  s/0*\(.*\)/int _msg_tbl_length = \1;/p
+}
+d
diff --git a/bacula/intl/po2tbl.sed.in b/bacula/intl/po2tbl.sed.in
new file mode 100644 (file)
index 0000000..b3bcca4
--- /dev/null
@@ -0,0 +1,102 @@
+# po2tbl.sed - Convert Uniforum style .po file to lookup table for catgets
+# Copyright (C) 1995 Free Software Foundation, Inc.
+# Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+#
+# 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.
+#
+1 {
+  i\
+/* Automatically generated by po2tbl.sed from @PACKAGE NAME@.pot.  */\
+\
+#if HAVE_CONFIG_H\
+# include <config.h>\
+#endif\
+\
+#include "libgettext.h"\
+\
+const struct _msg_ent _msg_tbl[] = {
+  h
+  s/.*/0/
+  x
+}
+#
+# Write msgid entries in C array form.
+#
+/^msgid/ {
+  s/msgid[     ]*\(".*"\)/  {\1/
+  tb
+# Append the next line
+  :b
+  N
+# Look whether second part is continuation line.
+  s/\(.*\)"\(\n\)"\(.*"\)/\1\2\3/
+# Yes, then branch.
+  ta
+# Because we assume that the input file correctly formed the line
+# just read cannot be again be a msgid line.  So it's safe to ignore
+# it.
+  s/\(.*\)\n.*/\1/
+  bc
+# We found a continuation line.  But before printing insert '\'.
+  :a
+  s/\(.*\)\(\n.*\)/\1\\\2/
+  P
+# We cannot use D here.
+  s/.*\n\(.*\)/\1/
+# Some buggy seds do not clear the `successful substitution since last ``t'''
+# flag on `N', so we do a `t' here to clear it.
+  tb
+# Not reached
+  :c
+  x
+# The following nice solution is by
+# Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de>
+  td
+# Increment a decimal number in pattern space.
+# First hide trailing `9' digits.
+  :d
+  s/9\(_*\)$/_\1/
+  td
+# Assure at least one digit is available.
+  s/^\(_*\)$/0\1/
+# Increment the last digit.
+  s/8\(_*\)$/9\1/
+  s/7\(_*\)$/8\1/
+  s/6\(_*\)$/7\1/
+  s/5\(_*\)$/6\1/
+  s/4\(_*\)$/5\1/
+  s/3\(_*\)$/4\1/
+  s/2\(_*\)$/3\1/
+  s/1\(_*\)$/2\1/
+  s/0\(_*\)$/1\1/
+# Convert the hidden `9' digits to `0's.
+  s/_/0/g
+  x
+  G
+  s/\(.*\)\n\([0-9]*\)/\1, \2},/
+  s/\(.*\)"$/\1/
+  p
+}
+#
+# Last line.
+#
+$ {
+  i\
+};\
+
+  g
+  s/0*\(.*\)/int _msg_tbl_length = \1;/p
+}
+d
diff --git a/bacula/intl/textdomain.c b/bacula/intl/textdomain.c
new file mode 100644 (file)
index 0000000..8855746
--- /dev/null
@@ -0,0 +1,108 @@
+/* Implementation of the textdomain(3) function.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   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.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined STDC_HEADERS || defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Name of the default text domain.  */
+extern const char _nl_default_default_domain[];
+
+/* Default text domain in which entries for gettext(3) are to be found.  */
+extern const char *_nl_current_default_domain;
+
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define TEXTDOMAIN __textdomain
+# ifndef strdup
+#  define strdup(str) __strdup (str)
+# endif
+#else
+# define TEXTDOMAIN textdomain__
+#endif
+
+/* Set the current default message catalog to DOMAINNAME.
+   If DOMAINNAME is null, return the current default.
+   If DOMAINNAME is "", reset to the default of "messages".  */
+char *
+TEXTDOMAIN (domainname)
+     const char *domainname;
+{
+  char *old;
+
+  /* A NULL pointer requests the current setting.  */
+  if (domainname == NULL)
+    return (char *) _nl_current_default_domain;
+
+  old = (char *) _nl_current_default_domain;
+
+  /* If domain name is the null string set to default domain "messages".  */
+  if (domainname[0] == '\0'
+      || strcmp (domainname, _nl_default_default_domain) == 0)
+    _nl_current_default_domain = _nl_default_default_domain;
+  else
+    {
+      /* If the following malloc fails `_nl_current_default_domain'
+        will be NULL.  This value will be returned and so signals we
+        are out of core.  */
+#if defined _LIBC || defined HAVE_STRDUP
+      _nl_current_default_domain = strdup (domainname);
+#else
+      size_t len = strlen (domainname) + 1;
+      char *cp = (char *) malloc (len);
+      if (cp != NULL)
+       memcpy (cp, domainname, len);
+      _nl_current_default_domain = cp;
+#endif
+    }
+
+  if (old != _nl_default_default_domain)
+    free (old);
+
+  return (char *) _nl_current_default_domain;
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__textdomain, textdomain);
+#endif
diff --git a/bacula/intl/xopen-msg.sed b/bacula/intl/xopen-msg.sed
new file mode 100644 (file)
index 0000000..b19c0bb
--- /dev/null
@@ -0,0 +1,104 @@
+# po2msg.sed - Convert Uniforum style .po file to X/Open style .msg file
+# Copyright (C) 1995 Free Software Foundation, Inc.
+# Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+#
+# 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.
+#
+#
+# The first directive in the .msg should be the definition of the
+# message set number.  We use always set number 1.
+#
+1 {
+  i\
+$set 1 # Automatically created by po2msg.sed
+  h
+  s/.*/0/
+  x
+}
+#
+# We copy all comments into the .msg file.  Perhaps they can help.
+#
+/^#/ s/^#[     ]*/$ /p
+#
+# We copy the original message as a comment into the .msg file.
+#
+/^msgid/ {
+# Does not work now
+#  /"$/! {
+#    s/\\$//
+#    s/$/ ... (more lines following)"/
+#  }
+  s/^msgid[    ]*"\(.*\)"$/$ Original Message: \1/
+  p
+}
+#
+# The .msg file contains, other then the .po file, only the translations
+# but each given a unique ID.  Starting from 1 and incrementing by 1 for
+# each message we assign them to the messages.
+# It is important that the .po file used to generate the cat-id-tbl.c file
+# (with po-to-tbl) is the same as the one used here.  (At least the order
+# of declarations must not be changed.)
+#
+/^msgstr/ {
+  s/msgstr[    ]*"\(.*\)"/\1/
+  x
+# The following nice solution is by
+# Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de>
+  td
+# Increment a decimal number in pattern space.
+# First hide trailing `9' digits.
+  :d
+  s/9\(_*\)$/_\1/
+  td
+# Assure at least one digit is available.
+  s/^\(_*\)$/0\1/
+# Increment the last digit.
+  s/8\(_*\)$/9\1/
+  s/7\(_*\)$/8\1/
+  s/6\(_*\)$/7\1/
+  s/5\(_*\)$/6\1/
+  s/4\(_*\)$/5\1/
+  s/3\(_*\)$/4\1/
+  s/2\(_*\)$/3\1/
+  s/1\(_*\)$/2\1/
+  s/0\(_*\)$/1\1/
+# Convert the hidden `9' digits to `0's.
+  s/_/0/g
+  x
+# Bring the line in the format `<number> <message>'
+  G
+  s/^[^\n]*$/& /
+  s/\(.*\)\n\([0-9]*\)/\2 \1/
+# Clear flag from last substitution.
+  tb
+# Append the next line.
+  :b
+  N
+# Look whether second part is a continuation line.
+  s/\(.*\n\)"\(.*\)"/\1\2/
+# Yes, then branch.
+  ta
+  P
+  D
+# Note that `D' includes a jump to the start!!
+# We found a continuation line.  But before printing insert '\'.
+  :a
+  s/\(.*\)\(\n.*\)/\1\\\2/
+  P
+# We cannot use the sed command `D' here
+  s/.*\n\(.*\)/\1/
+  tb
+}
+d
diff --git a/bacula/platforms/Makefile.in b/bacula/platforms/Makefile.in
new file mode 100644 (file)
index 0000000..9152769
--- /dev/null
@@ -0,0 +1,86 @@
+#
+# This is the makefile template for the platform directory
+# which contains general platform installation.
+#
+#  15 November 2001 -- Kern Sibbald
+# 
+#   for Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL = @INSTALL@
+
+SUBDIRS = freebsd redhat solaris unknown hpux suse openbsd \
+                 slackware alpha netbsd caldera debian
+
+MAKE = make
+
+DISTNAME=@DISTNAME@
+DISTVER=@DISTVER@
+
+all:
+       @for subdir in ${SUBDIRS}; do \
+           if [ -f $${subdir}/Makefile ]; then \
+              (cd $${subdir}; make;) \
+           fi; \
+       done
+
+
+install: install-autostart-dir install-autostart-fd install-autostart-sd
+
+install-autostart-dir:
+       @if test x$(DISTNAME) != x ; then \
+          (cd $(DISTNAME); \
+             $(MAKE) "DISTNAME=$(DISTNAME)" "DISTVER=$(DISTVER)" $@) \
+       fi
+
+install-autostart-fd:
+       @if test x$(DISTNAME) != x ; then \
+          (cd $(DISTNAME); \
+             $(MAKE) "DISTNAME=$(DISTNAME)" "DISTVER=$(DISTVER)" $@) \
+       fi
+
+install-autostart-sd:
+       @if test x$(DISTNAME) != x ; then \
+          (cd $(DISTNAME); \
+             $(MAKE) "DISTNAME=$(DISTNAME)" "DISTVER=$(DISTVER)" $@) \
+       fi
+
+uninstall: uninstall-autostart-dir uninstall-autostart-fd uninstall-autrun-sd
+
+uninstall-autostart-dir:
+       @if test x$(DISTNAME) != x ; then \
+          (cd $(DISTNAME); \
+            $(MAKE) "DISTNAME=$(DISTNAME)" "DISTVER=$(DISTVER)" $@) \
+       fi
+
+uninstall-autostart-fd:
+       @if test x$(DISTNAME) != x ; then \
+          (cd $(DISTNAME); \
+            $(MAKE) "DISTNAME=$(DISTNAME)" "DISTVER=$(DISTVER)" $@) \
+       fi
+
+uninstall-autostart-sd:
+       @if test x$(DISTNAME) != x ; then \
+          (cd $(DISTNAME); \
+            $(MAKE) "DISTNAME=$(DISTNAME)" "DISTVER=$(DISTVER)" $@) \
+       fi
+
+depend:
+
+clean:
+       @for subdir in ${SUBDIRS}; do \
+           if [ -f $${subdir}/Makefile ]; then \
+                   (cd $${subdir}; make clean;) \
+           fi; \
+       done
+       rm -f 1 2 3
+
+distclean:
+       rm -f Makefile
+       @for subdir in ${SUBDIRS}; do \
+           if [ -f $${subdir}/Makefile ]; then \
+                    (cd $${subdir}; make distclean;) \
+           fi; \
+       done
diff --git a/bacula/platforms/README b/bacula/platforms/README
new file mode 100644 (file)
index 0000000..e8d2152
--- /dev/null
@@ -0,0 +1,5 @@
+
+This directory, <bacula-src>/platforms, contains the platform
+specific installation files. Files that are common to all
+platforms are in this directory, and files that are specific
+to a particular platform are contained in subdirectories.
diff --git a/bacula/platforms/freebsd/Makefile.in b/bacula/platforms/freebsd/Makefile.in
new file mode 100644 (file)
index 0000000..bb7169a
--- /dev/null
@@ -0,0 +1,135 @@
+# 
+# This file is used as the template to create the
+# Makefile for the Solaris specific installation.
+#
+#  15 November 2001 -- Kern Sibbald
+#
+#  for Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+VPATH = @srcdir@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+SED = /usr/bin/sed
+
+nothing:
+
+install: install-autostart
+
+install-autostart: install-autostart-fd install-autostart-sd install-autostart-dir
+
+       
+install-autostart-fd:
+       @echo "FreeBSD platform installation"
+       $(INSTALL_PROGRAM) -m 744 bacula-fd /etc/rc.bacula-fd
+       @-today="`date +%Y%m%d%H%M`"; \
+       grep -q /etc/rc.bacula-fd /etc/rc.local; \
+       if [ $$? -eq 0 ]; then \
+           echo "/etc/rc.local already patched"; \
+       else \
+           rm -f /etc/rc.local.$$today; \
+           cp -p /etc/rc.local /etc/rc.local.$$today; \
+           ( echo "Start the Bacula File daemon. Do not remove the 'TAG_BACULA_FD' text"; \
+             echo "if [ -x /etc/rc.bacula-fd ]; then     # TAG_BACULA_FD"; \
+             echo "        /etc/rc.bacula-fd start       # TAG_BACULA_FD"; \
+             echo "fi                                    # TAG_BACULA_FD"; \
+           ) >> /etc/rc.local; \
+           echo ""; \
+       fi
+
+
+install-autostart-sd:
+       @echo "FreeBSD platform installation"
+       $(INSTALL_PROGRAM) -m 744 bacula-sd /etc/rc.bacula-sd
+       @-today="`date +%Y%m%d%H%M`"; \
+       grep -q /etc/rc.bacula-sd /etc/rc.local; \
+       if [ $$? -eq 0 ]; then \
+           echo "/etc/rc.local already patched"; \
+       else \
+           rm -f /etc/rc.local.$$today; \
+           cp -p /etc/rc.local /etc/rc.local.$$today; \
+           ( echo "Start the Bacula Storage daemon. Do not remove the 'TAG_BACULA_SD' text"; \
+             echo "if [ -x /etc/rc.bacula-fd ]; then     # TAG_BACULA_SD"; \
+             echo "        /etc/rc.bacula-fd start       # TAG_BACULA_SD"; \
+             echo "fi                                    # TAG_BACULA_SD"; \
+           ) >> /etc/rc.local; \
+           echo ""; \
+       fi
+
+install-autostart-dir:
+       @echo "FreeBSD platform installation"
+       $(INSTALL_PROGRAM) -m 744 bacula-dir /etc/rc.bacula-dir
+       @-today="`date +%Y%m%d%H%M`"; \
+       grep -q /etc/rc.bacula-dir /etc/rc.local; \
+       if [ $$? -eq 0 ]; then \
+           echo "/etc/rc.local already patched"; \
+       else \
+           rm -f /etc/rc.local.$$today; \
+           cp -p /etc/rc.local /etc/rc.local.$$today; \
+           ( echo "Start the Bacula Director. Do not remove the 'TAG_BACULA_DIR' text"; \
+             echo "if [ -x /etc/rc.bacula-dir ]; then    # TAG_BACULA_DIR"; \
+             echo "        /etc/rc.bacula-dir start      # TAG_BACULA_DIR"; \
+             echo "fi                                    # TAG_BACULA_DIR"; \
+           ) >> /etc/rc.local; \
+           echo ""; \
+       fi
+
+
+uninstall: uninstall-autostart
+
+uninstall-autostart: uninstall-autostart-fd uninstall-autostart-sd uninstall-autostart-dir
+
+uninstall-autostart-fd:
+       @echo "FreeBSD platform uninstall"
+       rm -f /etc/rc.bacula-fd
+       @-today="`date +%Y%m%d%H%M`"; \
+       for f in /etc/rc.local ; do \
+           grep -q '# TAG_BACULA_FD' $$f; \
+           if [ $$? -eq 0 ]; then \
+                   echo "removing Bacula lines from $$f"; \
+                   rm -f $$f.$$today; \
+                   cp -p $$f $$f.$$today; \
+                   $(SED) -e '/TAG_BACULA_FD/d;' \
+                           < $$f.$$today > $$f; \
+                   chmod 644 $$f; \
+           fi; \
+       done
+
+
+uninstall-autostart-sd:
+       @echo "FreeBSD platform uninstall"
+       rm -f /etc/rc.bacula-sd
+       @-today="`date +%Y%m%d%H%M`"; \
+       for f in /etc/rc.local ; do \
+           grep -q '# TAG_BACULA_SD' $$f; \
+           if [ $$? -eq 0 ]; then \
+                   echo "removing Bacula lines from $$f"; \
+                   rm -f $$f.$$today; \
+                   cp -p $$f $$f.$$today; \
+                   $(SED) -e '/TAG_BACULA_SD/d;' \
+                           < $$f.$$today > $$f; \
+                   chmod 644 $$f; \
+           fi; \
+       done
+
+uninstall-autostart-dir:
+       @echo "FreeBSD platform uninstall"
+       rm -f /etc/rc.bacula-dir
+       @-today="`date +%Y%m%d%H%M`"; \
+       for f in /etc/rc.local ; do \
+           grep -q '# TAG_BACULA_DIR' $$f; \
+           if [ $$? -eq 0 ]; then \
+                   echo "removing Bacula lines from $$f"; \
+                   rm -f $$f.$$today; \
+                   cp -p $$f $$f.$$today; \
+                   $(SED) -e '/TAG_BACULA_DIR/d;' \
+                           < $$f.$$today > $$f; \
+                   chmod 644 $$f; \
+           fi; \
+       done
+
+clean:
+       @rm -f bacula-sd bacula-fd bacula-dir
+
+distclean: clean
+       @rm -f Makefile bacula-*.spec
diff --git a/bacula/platforms/freebsd/bacula-dir.in b/bacula/platforms/freebsd/bacula-dir.in
new file mode 100755 (executable)
index 0000000..8ff0919
--- /dev/null
@@ -0,0 +1,38 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula Director daemon
+#
+# chkconfig: 2345 20 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+RETVAL=0
+case "$1" in
+    start)
+       echo "Starting the Bacula Director: "
+       @sbindir@/bacula-dir $2 -c @sysconfdir@/bacula-dir.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-dir
+       ;;
+    stop)
+       echo "Stopping the Director daemon: "
+#      killproc @sbindir@/bacula-dir
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-dir
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/freebsd/bacula-fd.in b/bacula/platforms/freebsd/bacula-fd.in
new file mode 100755 (executable)
index 0000000..9f26ade
--- /dev/null
@@ -0,0 +1,37 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula File daemon.
+#
+# chkconfig: 2345 20 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+case "$1" in
+    start)
+       echo "Starting the Bacula File daemon: "
+       @sbindir@/bacula-fd $2 -c @sysconfdir@/bacula-fd.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-fd
+       ;;
+    stop)
+       echo "Stopping the Bacula File daemon: "
+#      killproc @sbindir@/bacula-fd
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-fd
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/freebsd/bacula-sd.in b/bacula/platforms/freebsd/bacula-sd.in
new file mode 100755 (executable)
index 0000000..79e1a91
--- /dev/null
@@ -0,0 +1,37 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula Storage daemon.
+#
+# chkconfig: 2345 20 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+case "$1" in
+    start)
+       echo "Starting the Bacula Storage daemon: "
+       @sbindir@/bacula-sd $2 -c @sysconfdir@/bacula-sd.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-sd
+       ;;
+    stop)
+       echo "Stopping the Bacula Storage daemon: "
+#      killproc @sbindir@/bacula-sd
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-sd
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/install-symlinks b/bacula/platforms/install-symlinks
new file mode 100755 (executable)
index 0000000..ed91cd6
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/sh
+#
+# install-symlinks.sh - shell script for installing symbolic lynks
+# for system startup
+#
+# Copyright (C) 1999-2000 Riccardo Facchetti <riccardo@master.oasi.gpa.it>
+#
+#  Modified for use with Bacula  15 November 2001, Kern Sibbald
+#
+#
+# Theory of operation:
+# this script attempts to detect which runlevels are appropriate for
+# apcupsd startup and consequently installs the OS startup symbolic links
+# in the correct locations.
+#
+# For example, suse distribution uses sysvinit so the scripts will do:
+# 1. searches for init scripts directory
+# 2. try to detect on which runlevels is appropriate to run apcupsd
+#    (presumably all the runlevels at which also syslogd runs)
+# 3. installs the symbolic links into the previously detected runlevels
+
+action=$1
+dist=$2
+
+if [ -z "$action" -o -z "$dist" ]
+then
+  echo "Missing parameter on command line."
+  exit 1
+fi
+
+case $action in
+  install)
+    echo "Generic symlinks installation..."
+    case $dist in
+      suse)
+
+        if [ -d /etc/rc.d ]
+        then
+          initrcd="/etc/rc.d"
+        elif [ -d /sbin/init.d ]
+        then
+          initrcd="/sbin/init.d"
+        else
+          echo "Can not find init scripts directory."
+          exit 1
+        fi
+
+        for runlevel in 1 2 3 4 5
+        do
+          if [ -L $initrcd/rc$runlevel.d/S*syslog ]
+          then
+            echo "  Installing runlevel $runlevel..."
+            ln -sf $initrcd/apcupsd $initrcd/rc$runlevel.d/K20apcupsd
+            ln -sf $initrcd/apcupsd $initrcd/rc$runlevel.d/S20apcupsd
+          fi
+        done
+        ;;
+      *)
+        echo "  relying on $dist-specific Makefile for symlink installation"
+        ;;
+    esac
+    ;;
+  uninstall)
+    echo "Genering symlinks uninstallation..."
+    case $dist in
+      suse)
+
+        if [ -d /etc/rc.d ]
+        then
+          initrcd="/etc/rc.d"
+        elif [ -d /sbin/init.d ]
+        then
+          initrcd="/sbin/init.d"
+        else
+          echo "Can not detect init scripts directory."
+          exit 1
+        fi
+
+        for runlevel in 1 2 3 4 5
+        do
+          if [ -L $initrcd/rc$runlevel.d/S20apcupsd ]
+          then
+            echo "  Removing runlevel $runlevel..."
+            rm -f $initrcd/rc$runlevel.d/K20apcupsd
+            rm -f $initrcd/rc$runlevel.d/S20apcupsd
+          fi
+        done
+        ;;
+      *)
+        echo "  relying on $dist-specific Makefile for symlink uninstallation"
+        ;;
+    esac
+    ;;
+  *)
+    echo "Wrong parameter $action."
+    exit 1
+esac
+
+exit 0
diff --git a/bacula/platforms/redhat/Makefile.in b/bacula/platforms/redhat/Makefile.in
new file mode 100644 (file)
index 0000000..96ffa2e
--- /dev/null
@@ -0,0 +1,74 @@
+# 
+# This file is used as the template to create the
+# Makefile for the RedHat specific installation.
+#
+#  15 November 2001 -- Kern Sibbald
+#
+#  for Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+
+nothing:
+
+install: install-autostart
+
+install-autostart: install-autostart-fd install-autostart-sd install-autostart-dir
+
+       
+install-autostart-fd:
+       @if test -f /etc/rc.d/init.d/bacula-fd; then \
+           /sbin/chkconfig --del bacula-fd; \
+       fi
+       @$(INSTALL_PROGRAM) -m 744 bacula-fd /etc/rc.d/init.d/bacula-fd
+       # set symlinks for script at startup and shutdown
+       @/sbin/chkconfig --add bacula-fd
+
+
+install-autostart-sd:
+       @if test -f /etc/rc.d/init.d/bacula-sd; then \
+           /sbin/chkconfig --del bacula-sd; \
+       fi
+       @$(INSTALL_PROGRAM) -m 744 bacula-sd /etc/rc.d/init.d/bacula-sd
+       # set symlinks for script at startup and shutdown
+       @/sbin/chkconfig --add bacula-sd
+
+
+install-autostart-dir:
+       @if test -f /etc/rc.d/init.d/bacula-dir; then \
+           /sbin/chkconfig --del bacula-dir; \
+       fi
+       @$(INSTALL_PROGRAM) -m 744 bacula-dir /etc/rc.d/init.d/bacula-dir
+       # set symlinks for script at startup and shutdown
+       @/sbin/chkconfig --add bacula-dir
+
+
+uninstall: uninstall-autostart
+
+uninstall-autostart: uninstall-autostart-fd uninstall-autostart-sd uninstall-autostart-dir
+
+uninstall-autostart-fd:
+       @if test -f /etc/rc.d/init.d/bacula-fd; then \
+           /sbin/chkconfig --del bacula-fd; \
+       fi
+       @rm -f /etc/rc.d/init.d/bacula-fd
+
+
+uninstall-autostart-sd:
+       @if test -f /etc/rc.d/init.d/bacula-sd; then \
+           /sbin/chkconfig --del bacula-sd; \
+       fi
+       @rm -f /etc/rc.d/init.d/bacula-sd
+
+uninstall-autostart-dir:
+       @if test -f /etc/rc.d/init.d/bacula-dir; then \
+           /sbin/chkconfig --del bacula-dir; \
+       fi
+       @rm -f /etc/rc.d/init.d/bacula-dir
+
+clean:
+
+distclean: clean
+       @rm -f Makefile bacula-*.spec
+       @rm -f bacula-sd bacula-fd bacula-dir
diff --git a/bacula/platforms/redhat/bacula-dir.in b/bacula/platforms/redhat/bacula-dir.in
new file mode 100755 (executable)
index 0000000..d568cdb
--- /dev/null
@@ -0,0 +1,44 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula Director daemon
+#
+# chkconfig: 2345 20 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+# Source function library
+. /etc/rc.d/init.d/functions
+
+RETVAL=0
+case "$1" in
+    start)
+       echo -n "Starting the Bacula Director: "
+       daemon @sbindir@/bacula-dir $2 -c @sysconfdir@/bacula-dir.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-dir
+       ;;
+    stop)
+       echo -n "Stopping the Director daemon: "
+       killproc @sbindir@/bacula-dir
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-dir
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    status)
+       status @sbindir@/bacula-dir
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart|status}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/redhat/bacula-fd.in b/bacula/platforms/redhat/bacula-fd.in
new file mode 100755 (executable)
index 0000000..19f04f0
--- /dev/null
@@ -0,0 +1,43 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula File daemon.
+#
+# chkconfig: 2345 20 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+# Source function library
+. /etc/rc.d/init.d/functions
+
+case "$1" in
+    start)
+       echo -n "Starting the Bacula File daemon: "
+       daemon @sbindir@/bacula-fd $2 -c @sysconfdir@/bacula-fd.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-fd
+       ;;
+    stop)
+       echo -n "Stopping the Bacula File daemon: "
+       killproc @sbindir@/bacula-fd
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-fd
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    status)
+       status @sbindir@/bacula-fd
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart|status}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/redhat/bacula-sd.in b/bacula/platforms/redhat/bacula-sd.in
new file mode 100755 (executable)
index 0000000..a4bfdd4
--- /dev/null
@@ -0,0 +1,43 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula Storage daemon.
+#
+# chkconfig: 2345 20 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+# Source function library
+. /etc/rc.d/init.d/functions
+
+case "$1" in
+    start)
+       echo -n "Starting the Bacula Storage daemon: "
+       daemon @sbindir@/bacula-sd $2 -c @sysconfdir@/bacula-sd.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-sd
+       ;;
+    stop)
+       echo -n "Stopping the Bacula Storage daemon: "
+       killproc @sbindir@/bacula-sd
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-sd
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    status)
+       status @sbindir@/bacula-sd
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart|status}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/solaris/Makefile.in b/bacula/platforms/solaris/Makefile.in
new file mode 100644 (file)
index 0000000..0d49463
--- /dev/null
@@ -0,0 +1,80 @@
+# 
+# This file is used as the template to create the
+# Makefile for the Solaris specific installation.
+#
+#  15 November 2001 -- Kern Sibbald
+#
+#  for Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+
+nothing:
+
+install: install-autostart
+
+install-autostart: install-autostart-fd install-autostart-sd install-autostart-dir
+
+       
+install-autostart-fd:
+       @rm -f /etc/rc0.d/K20bacula-fd
+       @rm -f /etc/rc1.d/S99bacula-fd
+       @rm -f /etc/rc2.d/S99bacula-fd
+       @$(INSTALL_PROGRAM) -m 744 bacula-fd /etc/init.d/bacula-fd
+       # set symlinks for script at startup and shutdown
+       @ln -f -s /etc/init.d/bacula-fd /etc/rc0.d/K20bacula-fd
+       @ln -f -s /etc/init.d/bacula-fd /etc/rc1.d/S99bacula-fd
+       @ln -f -s /etc/init.d/bacula-fd /etc/rc2.d/S99bacula-fd
+
+
+install-autostart-sd:
+       @rm -f /etc/rc0.d/K20bacula-sd
+       @rm -f /etc/rc1.d/S99bacula-sd
+       @rm -f /etc/rc2.d/S99bacula-sd
+       @$(INSTALL_PROGRAM) -m 744 bacula-sd /etc/rc.d/init.d/bacula-sd
+       # set symlinks for script at startup and shutdown
+       @ln -f -s /etc/init.d/bacula-sd /etc/rc0.d/K20bacula-sd
+       @ln -f -s /etc/init.d/bacula-sd /etc/rc1.d/S99bacula-sd
+       @ln -f -s /etc/init.d/bacula-sd /etc/rc2.d/S99bacula-sd
+
+
+install-autostart-dir:
+       @rm -f /etc/rc0.d/K20bacula-dir
+       @rm -f /etc/rc1.d/S99bacula-dir
+       @rm -f /etc/rc2.d/S99bacula-dir
+       @$(INSTALL_PROGRAM) -m 744 bacula-dir /etc/rc.d/init.d/bacula-dir
+       # set symlinks for script at startup and shutdown
+       @ln -f -s /etc/init.d/bacula-dir /etc/rc0.d/K20bacula-dir
+       @ln -f -s /etc/init.d/bacula-dir /etc/rc1.d/S99bacula-dir
+       @ln -f -s /etc/init.d/bacula-dir /etc/rc2.d/S99bacula-dir
+
+
+uninstall: uninstall-autostart
+
+uninstall-autostart: uninstall-autostart-fd uninstall-autostart-sd uninstall-autostart-dir
+
+uninstall-autostart-fd:
+       @rm -f /etc/rc0.d/K20bacula-fd
+       @rm -f /etc/rc1.d/S99bacula-fd
+       @rm -f /etc/rc2.d/S99bacula-fd
+       @rm -f /etc/rc.d/init.d/bacula-fd
+
+
+uninstall-autostart-sd:
+       @rm -f /etc/rc0.d/K20bacula-sd
+       @rm -f /etc/rc1.d/S99bacula-sd
+       @rm -f /etc/rc2.d/S99bacula-sd
+       @rm -f /etc/rc.d/init.d/bacula-sd
+
+uninstall-autostart-dir:
+       @rm -f /etc/rc0.d/K20bacula-dir
+       @rm -f /etc/rc1.d/S99bacula-dir
+       @rm -f /etc/rc2.d/S99bacula-dir
+       @rm -f /etc/rc.d/init.d/bacula-dir
+
+clean:
+       @rm -f bacula-sd bacula-fd bacula-dir
+
+distclean: clean
+       @rm -f Makefile bacula-*.spec
diff --git a/bacula/platforms/solaris/bacula-dir.in b/bacula/platforms/solaris/bacula-dir.in
new file mode 100755 (executable)
index 0000000..8ff0919
--- /dev/null
@@ -0,0 +1,38 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula Director daemon
+#
+# chkconfig: 2345 20 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+RETVAL=0
+case "$1" in
+    start)
+       echo "Starting the Bacula Director: "
+       @sbindir@/bacula-dir $2 -c @sysconfdir@/bacula-dir.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-dir
+       ;;
+    stop)
+       echo "Stopping the Director daemon: "
+#      killproc @sbindir@/bacula-dir
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-dir
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/solaris/bacula-fd.in b/bacula/platforms/solaris/bacula-fd.in
new file mode 100755 (executable)
index 0000000..9f26ade
--- /dev/null
@@ -0,0 +1,37 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula File daemon.
+#
+# chkconfig: 2345 20 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+case "$1" in
+    start)
+       echo "Starting the Bacula File daemon: "
+       @sbindir@/bacula-fd $2 -c @sysconfdir@/bacula-fd.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-fd
+       ;;
+    stop)
+       echo "Stopping the Bacula File daemon: "
+#      killproc @sbindir@/bacula-fd
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-fd
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/solaris/bacula-sd.in b/bacula/platforms/solaris/bacula-sd.in
new file mode 100755 (executable)
index 0000000..79e1a91
--- /dev/null
@@ -0,0 +1,37 @@
+#! /bin/sh
+#
+# bacula       This shell script takes care of starting and stopping
+#             the bacula Storage daemon.
+#
+# chkconfig: 2345 20 99
+# description: It comes by night and sucks the vital essence from your computers.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+case "$1" in
+    start)
+       echo "Starting the Bacula Storage daemon: "
+       @sbindir@/bacula-sd $2 -c @sysconfdir@/bacula-sd.conf
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && touch @subsysdir@/bacula-sd
+       ;;
+    stop)
+       echo "Stopping the Bacula Storage daemon: "
+#      killproc @sbindir@/bacula-sd
+       RETVAL=$?
+       echo
+       [ $RETVAL -eq 0 ] && rm -f @subsysdir@/bacula-sd
+       ;;
+    restart)
+       $0 stop
+       sleep 5
+       $0 start
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|restart}"
+       exit 1
+       ;;
+esac
+exit 0
diff --git a/bacula/platforms/unknown/Makefile.in b/bacula/platforms/unknown/Makefile.in
new file mode 100644 (file)
index 0000000..f05b139
--- /dev/null
@@ -0,0 +1,43 @@
+# 
+# This file is used as the template to create the
+# Makefile for the unknown specific installation.
+#
+#  15 November 2001 -- Kern Sibbald
+#
+#  for Bacula release @VERSION@ (@DATE@) -- @DISTNAME@
+#
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+
+install: install-autostart
+
+all: install-autostart
+
+install-autostart: install-autostart-FD install-autostart-SD install-autostart-DIR
+
+       
+install-autostart-FD:
+
+
+install-autostart-SD:
+
+
+install-autostart-DIR:
+
+
+uninstall: uninstall-autostart
+
+uninstall-autostart: uninstall-autostart-FD uninstall-autostart-SD uninstall-autostart-DIR
+
+uninstall-autostart-FD:
+
+
+uninstall-autostart-SD:
+
+uninstall-autostart-DIR:
+
+clean:
+
+distclean:
+       @rm -f bacula-SD bacula-FD bacula-DIR Makefile bacula-*.spec
diff --git a/bacula/po/ChangeLog b/bacula/po/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/bacula/po/Makefile.in b/bacula/po/Makefile.in
new file mode 100644 (file)
index 0000000..51e7a07
--- /dev/null
@@ -0,0 +1,250 @@
+# Generated automatically from Makefile.in.in by configure.
+# Makefile for program source directory in GNU NLS utilities package.
+# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+#
+# This file file be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+PACKAGE = bacula
+VERSION = 0.1
+
+SHELL = /bin/sh
+
+
+srcdir = .
+top_srcdir = ..
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+datadir = $(prefix)/share
+localedir = $(datadir)/locale
+gnulocaledir = $(prefix)/share/locale
+gettextsrcdir = $(prefix)/share/gettext/po
+subdir = po
+
+DESTDIR =
+
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+MKINSTALLDIRS = $(top_srcdir)/./mkinstalldirs
+
+CC = gcc
+GENCAT = 
+GMSGFMT = PATH=../src:$$PATH /usr/bin/msgfmt
+MSGFMT = /usr/bin/msgfmt
+XGETTEXT = PATH=../src:$$PATH /usr/bin/xgettext
+MSGMERGE = PATH=../src:$$PATH msgmerge
+
+DEFS = -DHAVE_CONFIG_H
+CFLAGS = -g -O2 -Wall -Wunused -Wmissing-prototypes -Wmissing-declarations 
+CPPFLAGS =  -I/usr/include/gtk-1.2 -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/X11R6/include
+
+INCLUDES = -I.. -I$(top_srcdir)/intl
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+SOURCES = cat-id-tbl.c
+POFILES = 
+GMOFILES = 
+DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(PACKAGE).pot \
+stamp-cat-id $(POFILES) $(GMOFILES) $(SOURCES)
+
+POTFILES = \
+
+CATALOGS = 
+CATOBJEXT = .gmo
+INSTOBJEXT = .mo
+
+.SUFFIXES:
+.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
+
+.c.o:
+       $(COMPILE) $<
+
+.po.pox:
+       $(MAKE) $(PACKAGE).pot
+       $(MSGMERGE) $< $(srcdir)/$(PACKAGE).pot -o $*.pox
+
+.po.mo:
+       $(MSGFMT) -o $@ $<
+
+.po.gmo:
+       file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \
+         && rm -f $$file && $(GMSGFMT) -o $$file $<
+
+.po.cat:
+       sed -f ../intl/po2msg.sed < $< > $*.msg \
+         && rm -f $@ && $(GENCAT) $@ $*.msg
+
+
+all: all-yes
+
+all-yes: cat-id-tbl.c $(CATALOGS)
+all-no:
+
+$(srcdir)/$(PACKAGE).pot: $(POTFILES)
+       $(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(top_srcdir) \
+         --add-comments --keyword=_ --keyword=N_ \
+         --files-from=$(srcdir)/POTFILES.in \
+       && test ! -f $(PACKAGE).po \
+          || ( rm -f $(srcdir)/$(PACKAGE).pot \
+               && mv $(PACKAGE).po $(srcdir)/$(PACKAGE).pot )
+
+$(srcdir)/cat-id-tbl.c: stamp-cat-id; @:
+$(srcdir)/stamp-cat-id: $(PACKAGE).pot
+       rm -f cat-id-tbl.tmp
+       sed -f ../intl/po2tbl.sed $(srcdir)/$(PACKAGE).pot \
+               | sed -e "s/@PACKAGE NAME@/$(PACKAGE)/" > cat-id-tbl.tmp
+       if cmp -s cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; then \
+         rm cat-id-tbl.tmp; \
+       else \
+         echo cat-id-tbl.c changed; \
+         rm -f $(srcdir)/cat-id-tbl.c; \
+         mv cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; \
+       fi
+       cd $(srcdir) && rm -f stamp-cat-id && echo timestamp > stamp-cat-id
+
+
+install: install-exec install-data
+install-exec:
+install-data: install-data-yes
+install-data-no: all
+install-data-yes: all
+       if test -r "$(MKINSTALLDIRS)"; then \
+         $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \
+       else \
+         $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \
+       fi
+       @catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         case "$$cat" in \
+           *.gmo) destdir=$(DESTDIR)$(gnulocaledir);; \
+           *)     destdir=$(DESTDIR)$(localedir);; \
+         esac; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         dir=$$destdir/$$lang/LC_MESSAGES; \
+         if test -r "$(MKINSTALLDIRS)"; then \
+           $(MKINSTALLDIRS) $$dir; \
+         else \
+           $(SHELL) $(top_srcdir)/mkinstalldirs $$dir; \
+         fi; \
+         if test -r $$cat; then \
+           $(INSTALL_DATA) $$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+           echo "installing $$cat as $$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+         else \
+           $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+           echo "installing $(srcdir)/$$cat as" \
+                "$$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+         fi; \
+         if test -r $$cat.m; then \
+           $(INSTALL_DATA) $$cat.m $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+           echo "installing $$cat.m as $$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+         else \
+           if test -r $(srcdir)/$$cat.m ; then \
+             $(INSTALL_DATA) $(srcdir)/$$cat.m \
+               $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+             echo "installing $(srcdir)/$$cat as" \
+                  "$$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+           else \
+             true; \
+           fi; \
+         fi; \
+       done
+       if test "$(PACKAGE)" = "gettext"; then \
+         if test -r "$(MKINSTALLDIRS)"; then \
+           $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
+         else \
+           $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
+         fi; \
+         $(INSTALL_DATA) $(srcdir)/Makefile.in.in \
+                         $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
+       else \
+         : ; \
+       fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+         rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+         rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+         rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+       done
+       rm -f $(DESTDIR)$(gettextsrcdir)/po-Makefile.in.in
+
+check: all
+
+cat-id-tbl.o: ../intl/libgettext.h
+
+dvi info tags TAGS ID:
+
+mostlyclean:
+       rm -f core core.* *.pox $(PACKAGE).po *.old.po cat-id-tbl.tmp
+       rm -fr *.o
+
+clean: mostlyclean
+
+distclean: clean
+       rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
+
+maintainer-clean: distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+       rm -f $(GMOFILES)
+
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: update-po $(DISTFILES)
+       dists="$(DISTFILES)"; \
+       for file in $$dists; do \
+         ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+           || cp -p $(srcdir)/$$file $(distdir); \
+       done
+
+update-po: Makefile
+       $(MAKE) $(PACKAGE).pot
+       PATH=`pwd`/../src:$$PATH; \
+       cd $(srcdir); \
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         mv $$lang.po $$lang.old.po; \
+         echo "$$lang:"; \
+         if $(MSGMERGE) $$lang.old.po $(PACKAGE).pot -o $$lang.po; then \
+           rm -f $$lang.old.po; \
+         else \
+           echo "msgmerge for $$cat failed!"; \
+           rm -f $$lang.po; \
+           mv $$lang.old.po $$lang.po; \
+         fi; \
+       done
+
+POTFILES: POTFILES.in
+       ( if test 'x$(srcdir)' != 'x.'; then \
+           posrcprefix='$(top_srcdir)/'; \
+         else \
+           posrcprefix="../"; \
+         fi; \
+         rm -f $@-t $@ \
+           && (sed -e '/^#/d' -e '/^[  ]*$$/d' \
+                   -e "s@.*@   $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
+               | sed -e '$$s/\\$$//') > $@-t \
+           && chmod a-w $@-t \
+           && mv $@-t $@ )
+
+Makefile: Makefile.in.in ../config.status POTFILES
+       cd .. \
+         && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \
+              $(SHELL) ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/bacula/po/Makefile.in.in b/bacula/po/Makefile.in.in
new file mode 100644 (file)
index 0000000..cf3aa8c
--- /dev/null
@@ -0,0 +1,250 @@
+# Makefile for program source directory in GNU NLS utilities package.
+# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+#
+# This file file be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datadir = $(prefix)/@DATADIRNAME@
+localedir = $(datadir)/locale
+gnulocaledir = $(prefix)/share/locale
+gettextsrcdir = $(prefix)/share/gettext/po
+subdir = po
+
+DESTDIR =
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+MKINSTALLDIRS = $(top_srcdir)/@MKINSTALLDIRS@
+
+CC = @CC@
+GENCAT = @GENCAT@
+GMSGFMT = PATH=../src:$$PATH @GMSGFMT@
+MSGFMT = @MSGFMT@
+XGETTEXT = PATH=../src:$$PATH @XGETTEXT@
+MSGMERGE = PATH=../src:$$PATH msgmerge
+
+DEFS = @DEFS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+
+INCLUDES = -I.. -I$(top_srcdir)/intl
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+SOURCES = cat-id-tbl.c
+POFILES = @POFILES@
+GMOFILES = @GMOFILES@
+DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(PACKAGE).pot \
+stamp-cat-id $(POFILES) $(GMOFILES) $(SOURCES)
+
+POTFILES = \
+
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+INSTOBJEXT = @INSTOBJEXT@
+
+.SUFFIXES:
+.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
+
+.c.o:
+       $(COMPILE) $<
+
+.po.pox:
+       $(MAKE) $(PACKAGE).pot
+       $(MSGMERGE) $< $(srcdir)/$(PACKAGE).pot -o $*.pox
+
+.po.mo:
+       $(MSGFMT) -o $@ $<
+
+.po.gmo:
+       file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \
+         && rm -f $$file && $(GMSGFMT) -o $$file $<
+
+.po.cat:
+       sed -f ../intl/po2msg.sed < $< > $*.msg \
+         && rm -f $@ && $(GENCAT) $@ $*.msg
+
+
+all: all-@USE_NLS@
+
+all-yes: cat-id-tbl.c $(CATALOGS)
+all-no:
+
+$(srcdir)/$(PACKAGE).pot: $(POTFILES)
+       $(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(top_srcdir) \
+         --add-comments --keyword=_ --keyword=N_ \
+         --files-from=$(srcdir)/POTFILES.in \
+       && test ! -f $(PACKAGE).po \
+          || ( rm -f $(srcdir)/$(PACKAGE).pot \
+               && mv $(PACKAGE).po $(srcdir)/$(PACKAGE).pot )
+
+$(srcdir)/cat-id-tbl.c: stamp-cat-id; @:
+$(srcdir)/stamp-cat-id: $(PACKAGE).pot
+       rm -f cat-id-tbl.tmp
+       sed -f ../intl/po2tbl.sed $(srcdir)/$(PACKAGE).pot \
+               | sed -e "s/@PACKAGE NAME@/$(PACKAGE)/" > cat-id-tbl.tmp
+       if cmp -s cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; then \
+         rm cat-id-tbl.tmp; \
+       else \
+         echo cat-id-tbl.c changed; \
+         rm -f $(srcdir)/cat-id-tbl.c; \
+         mv cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; \
+       fi
+       cd $(srcdir) && rm -f stamp-cat-id && echo timestamp > stamp-cat-id
+
+
+install: install-exec install-data
+install-exec:
+install-data: install-data-@USE_NLS@
+install-data-no: all
+install-data-yes: all
+       if test -r "$(MKINSTALLDIRS)"; then \
+         $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \
+       else \
+         $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \
+       fi
+       @catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         case "$$cat" in \
+           *.gmo) destdir=$(DESTDIR)$(gnulocaledir);; \
+           *)     destdir=$(DESTDIR)$(localedir);; \
+         esac; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         dir=$$destdir/$$lang/LC_MESSAGES; \
+         if test -r "$(MKINSTALLDIRS)"; then \
+           $(MKINSTALLDIRS) $$dir; \
+         else \
+           $(SHELL) $(top_srcdir)/mkinstalldirs $$dir; \
+         fi; \
+         if test -r $$cat; then \
+           $(INSTALL_DATA) $$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+           echo "installing $$cat as $$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+         else \
+           $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+           echo "installing $(srcdir)/$$cat as" \
+                "$$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+         fi; \
+         if test -r $$cat.m; then \
+           $(INSTALL_DATA) $$cat.m $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+           echo "installing $$cat.m as $$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+         else \
+           if test -r $(srcdir)/$$cat.m ; then \
+             $(INSTALL_DATA) $(srcdir)/$$cat.m \
+               $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+             echo "installing $(srcdir)/$$cat as" \
+                  "$$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+           else \
+             true; \
+           fi; \
+         fi; \
+       done
+       if test "$(PACKAGE)" = "gettext"; then \
+         if test -r "$(MKINSTALLDIRS)"; then \
+           $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
+         else \
+           $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
+         fi; \
+         $(INSTALL_DATA) $(srcdir)/Makefile.in.in \
+                         $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
+       else \
+         : ; \
+       fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+         rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+         rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+         rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+       done
+       rm -f $(DESTDIR)$(gettextsrcdir)/po-Makefile.in.in
+
+check: all
+
+cat-id-tbl.o: ../intl/libgettext.h
+
+dvi info tags TAGS ID:
+
+mostlyclean:
+       rm -f core core.* *.pox $(PACKAGE).po *.old.po cat-id-tbl.tmp
+       rm -fr *.o
+
+clean: mostlyclean
+
+distclean: clean
+       rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
+
+maintainer-clean: distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+       rm -f $(GMOFILES)
+
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: update-po $(DISTFILES)
+       dists="$(DISTFILES)"; \
+       for file in $$dists; do \
+         ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+           || cp -p $(srcdir)/$$file $(distdir); \
+       done
+
+update-po: Makefile
+       $(MAKE) $(PACKAGE).pot
+       PATH=`pwd`/../src:$$PATH; \
+       cd $(srcdir); \
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         mv $$lang.po $$lang.old.po; \
+         echo "$$lang:"; \
+         if $(MSGMERGE) $$lang.old.po $(PACKAGE).pot -o $$lang.po; then \
+           rm -f $$lang.old.po; \
+         else \
+           echo "msgmerge for $$cat failed!"; \
+           rm -f $$lang.po; \
+           mv $$lang.old.po $$lang.po; \
+         fi; \
+       done
+
+POTFILES: POTFILES.in
+       ( if test 'x$(srcdir)' != 'x.'; then \
+           posrcprefix='$(top_srcdir)/'; \
+         else \
+           posrcprefix="../"; \
+         fi; \
+         rm -f $@-t $@ \
+           && (sed -e '/^#/d' -e '/^[  ]*$$/d' \
+                   -e "s@.*@   $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
+               | sed -e '$$s/\\$$//') > $@-t \
+           && chmod a-w $@-t \
+           && mv $@-t $@ )
+
+Makefile: Makefile.in.in ../config.status POTFILES
+       cd .. \
+         && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \
+              $(SHELL) ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/bacula/po/POTFILES.in b/bacula/po/POTFILES.in
new file mode 100644 (file)
index 0000000..ab2d29e
--- /dev/null
@@ -0,0 +1,6 @@
+# List of source files containing translatable strings.
+
+src/main.c
+src/interface.c
+src/callbacks.c
+src/support.c
diff --git a/bacula/po/bacula.pot b/bacula/po/bacula.pot
new file mode 100644 (file)
index 0000000..acc18f0
--- /dev/null
@@ -0,0 +1,69 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2002-03-17 12:43+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+#: src/interface.c:22
+msgid "_New File"
+msgstr ""
+
+#: src/interface.c:88
+msgid "Bacula"
+msgstr ""
+
+#: src/interface.c:211
+msgid "Connect"
+msgstr ""
+
+#: src/interface.c:212
+msgid "New File"
+msgstr ""
+
+#: src/interface.c:223
+msgid "Open"
+msgstr ""
+
+#: src/interface.c:224
+msgid "Open File"
+msgstr ""
+
+#: src/interface.c:235
+msgid "Save"
+msgstr ""
+
+#: src/interface.c:236
+msgid "Save File"
+msgstr ""
+
+#: src/interface.c:271
+msgid "label1"
+msgstr ""
+
+#: src/interface.c:311
+msgid "Copyright (c) 1999 - 2002, Kern Sibbald and John Walker"
+msgstr ""
+
+#: src/interface.c:313
+msgid "It comes by night and sucks the essence from your computers."
+msgstr ""
+
+#: src/support.c:100 src/support.c:138
+#, c-format
+msgid "Couldn't find pixmap file: %s"
+msgstr ""
+
+#: src/support.c:116
+#, c-format
+msgid "Couldn't create pixmap from file: %s"
+msgstr ""
diff --git a/bacula/po/cat-id-tbl.c b/bacula/po/cat-id-tbl.c
new file mode 100644 (file)
index 0000000..8011ec1
--- /dev/null
@@ -0,0 +1,26 @@
+/* Automatically generated by po2tbl.sed from bacula.pot.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libgettext.h"
+
+const struct _msg_ent _msg_tbl[] = {
+  {"", 1},
+  {"_New File", 2},
+  {"Bacula", 3},
+  {"Connect", 4},
+  {"New File", 5},
+  {"Open", 6},
+  {"Open File", 7},
+  {"Save", 8},
+  {"Save File", 9},
+  {"label1", 10},
+  {"Copyright (c) 1999 - 2002, Kern Sibbald and John Walker", 11},
+  {"It comes by night and sucks the essence from your computers.", 12},
+  {"Couldn't find pixmap file: %s", 13},
+  {"Couldn't create pixmap from file: %s", 14},
+};
+
+int _msg_tbl_length = 14;
diff --git a/bacula/po/stamp-cat-id b/bacula/po/stamp-cat-id
new file mode 100644 (file)
index 0000000..9788f70
--- /dev/null
@@ -0,0 +1 @@
+timestamp
diff --git a/bacula/src/.indent.pro b/bacula/src/.indent.pro
new file mode 100644 (file)
index 0000000..36fbed7
--- /dev/null
@@ -0,0 +1,27 @@
+--dont-format-comments
+--procnames-start-lines
+--parameter-indentation4
+--indent-level4
+--line-comments-indentation4
+--cuddle-else
+--brace-indent0
+--start-left-side-of-comments
+--no-blank-lines-after-commas
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--comment-indentation33
+--declaration-comment-column33
+--no-comment-delimiters-on-blank-lines
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--no-space-after-casts
+--no-blank-before-sizeof
+--declaration-indentation16
+--continue-at-parentheses
+--no-space-after-function-call-names
+--swallow-optional-blank-lines
+--space-special-semicolon
+--tab-size8
+--line-length79
+--braces-on-if-line
diff --git a/bacula/src/Makefile.in b/bacula/src/Makefile.in
new file mode 100644 (file)
index 0000000..00e075d
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#
+@MCOMMON@
+
+srcdir =       .
+VPATH =        .
+.PATH:         .
+
+# one up
+basedir = ..
+# top dir
+topdir = ..
+# this dir relative to top dir
+thisdir = src
+
+DEBUG=-DDEBUG_STRICT @DEBUG@
+
+first_rule: all
+dummy:
+
+#
+# these are the objects that are changed by the .configure process
+EXTRAOBJS = @OBJLIST@
+
+# it's ``be kind to gmake week''
+#EXTPROS = $(SRCS:S,.c,.extpro,)
+EXTPROS = 
+
+.SUFFIXES:     .c .o
+.PHONY:
+.DONTCARE:
+
+# inference rules
+.c.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I. -I$(basedir) -I$(srcdir) $(DINCLUDE) $(CFLAGS) $<
+
+.cc.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I. -I$(basedir) -I$(srcdir) $(DINCLUDE) $(CFLAGS) $<
+#-------------------------------------------------------------------------
+all: Makefile 
+
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+clean:
+       @$(RMF) core core.* a.out *.o *.bak *~ *.intpro *.extpro 1 2 3
+
+realclean: clean
+       @$(RMF) tags
+
+distclean: realclean
+       if test $(srcdir) = .; then $(MAKE) realclean; fi
+       @(cd $(srcdir); $(RMF) Makefile)
+       @$(RMF) config.h
+
+install:
+
+
+uninstall:
+
+
+depend:
diff --git a/bacula/src/baconfig.h b/bacula/src/baconfig.h
new file mode 100644 (file)
index 0000000..9051c75
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * General header file configurations that apply to
+ * all daemons.  System dependent stuff goes here.
+ */
+/*
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+ */
+
+
+#ifndef _BACONFIG_H
+#define _BACONFIG_H 1
+
+/* Bacula common configuration defines */
+
+#define DEBUG 1                       /* turn on debug code */
+
+#define TRUE  1
+#define FALSE 0
+
+#ifdef PROTOTYPES
+# define __PROTO(p)     p
+#else
+# define __PROTO(p)     ()
+#endif
+
+/* #define ASSERT(x) if (!(x)) Emsg1(M_ABORT, 0, "Failed ASSERT: %s\n", __STRING(x)) */
+#define ASSERT(x) if (!(x)) Emsg1(M_ABORT, 0, "Failed ASSERT: %s\n", #x)
+
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(s) gettext((s))
+#define N_(s) (s)
+#else
+#define _(s) (s)
+#define N_(s) (s)
+#define textdomain(x)
+#endif
+
+
+/* This should go away! ****FIXME***** */
+#define MAXSTRING 500
+
+/* Maximum length to edit time/date */
+#define MAX_TIME_LENGTH 30
+
+/* Maximum Name length including EOS */
+#define MAX_NAME_LENGTH 128
+
+/* All tape operations MUST be a multiple of this */
+#define TAPE_BSIZE 1024
+#if !defined(DEV_BSIZE) && defined(BSIZE)
+#define DEV_BSIZE BSIZE
+#else 
+#define DEV_BSIZE 512
+#endif
+
+/* Maximum number of bytes that you can push into a
+ * socket.
+ */
+#define MAX_NETWORK_BUFFER_SIZE (32 * 1024)
+
+/* Stream definitions.  Once defined these must NEVER
+ * change as they go on the storage media
+ */
+#define STREAM_UNIX_ATTRIBUTES  1     /* Generic Unix attributes */
+#define STREAM_FILE_DATA        2     /* Standard uncompressed data */
+#define STREAM_MD5_SIGNATURE    3     /* MD5 signature for the file */
+#define STREAM_GZIP_DATA        4     /* GZip compressed file data */
+
+
+/* This is for dumb compilers like Solaris. Linux GCC
+ * does it correctly, so it might be worthwhile
+ * to remove the isascii(c) with ifdefs on such
+ * "smart" systems.
+ */
+#undef  ISSPACE
+#undef  ISALPHA
+#undef  ISUPPER
+#undef  ISDIGIT
+#define ISSPACE(c) (isascii((int)(c)) && isspace((int)(c)))
+#define ISALPHA(c) (isascii((int)(c)) && isalpha((int)(c)))
+#define ISUPPER(c) (isascii((int)(c)) && isupper((int)(c)))
+#define ISDIGIT(c) (isascii((int)(c)) && isdigit((int)(c)))
+
+
+typedef void (HANDLER)();
+typedef int (INTHANDLER)();
+
+#ifdef SETPGRP_VOID
+# define SETPGRP_ARGS(x, y) /* No arguments */
+#else
+# define SETPGRP_ARGS(x, y) (x, y)
+#endif
+
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFM) == S_IFLNK)
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
+#endif
+
+#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
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifndef MODE_RW
+#define MODE_RW 0666
+#endif
+
+#ifdef DEBUG_MUTEX
+extern void _p(char *file, int line, pthread_mutex_t *m);
+extern void _v(char *file, int line, pthread_mutex_t *m);
+
+#define P(x) _p(__FILE__, __LINE__, &(x))
+#define V(x) _v(__FILE__, __LINE__, &(x))
+
+#else
+
+/* These probably should be subroutines */
+#define P(x) \
+   do { int errstat; if ((errstat=pthread_mutex_lock(&(x)))) \
+      e_msg(__FILE__, __LINE__, M_ABORT, 0, "Mutex lock failure. ERR=%s\n",\
+           strerror(errstat)); \
+   } while(0)
+
+#define V(x) \
+   do { int errstat; if ((errstat=pthread_mutex_unlock(&(x)))) \
+         e_msg(__FILE__, __LINE__, M_ABORT, 0, "Mutex unlock failure. ERR=%s\n",\
+           strerror(errstat)); \
+   } while(0)
+
+#endif /* DEBUG_MUTEX */
+
+/*
+ * The digit following Dmsg and Emsg indicates the number of substitutions in
+ * the message string. We need to do this kludge because non-GNU compilers
+ * do not handle varargs #defines.
+ */
+/* Debug Messages that are printed */
+#ifdef DEBUG
+#define Dmsg0(lvl, msg)             d_msg(__FILE__, __LINE__, lvl, msg)
+#define Dmsg1(lvl, msg, a1)         d_msg(__FILE__, __LINE__, lvl, msg, a1)
+#define Dmsg2(lvl, msg, a1, a2)     d_msg(__FILE__, __LINE__, lvl, msg, a1, a2)
+#define Dmsg3(lvl, msg, a1, a2, a3) d_msg(__FILE__, __LINE__, lvl, msg, a1, a2, a3)
+#define Dmsg4(lvl, msg, arg1, arg2, arg3, arg4) d_msg(__FILE__, __LINE__, lvl, msg, arg1, arg2, arg3, arg4)
+#define Dmsg5(lvl, msg, a1, a2, a3, a4, a5) d_msg(__FILE__, __LINE__, lvl, msg, a1, a2, a3, a4, a5)
+#define Dmsg6(lvl, msg, a1, a2, a3, a4, a5, a6) d_msg(__FILE__, __LINE__, lvl, msg, a1, a2, a3, a4, a5, a6)
+#define Dmsg7(lvl, msg, a1, a2, a3, a4, a5, a6, a7) d_msg(__FILE__, __LINE__, lvl, msg, a1, a2, a3, a4, a5, a6, a7)
+#define Dmsg8(lvl, msg, a1, a2, a3, a4, a5, a6, a7, a8) d_msg(__FILE__, __LINE__, lvl, msg, a1, a2, a3, a4, a5, a6, a7, a8)
+#define Dmsg11(lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) d_msg(__FILE__,__LINE__,lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
+#else
+#define Dmsg0(lvl, msg)
+#define Dmsg1(lvl, msg, a1)
+#define Dmsg2(lvl, msg, a1, a2)
+#define Dmsg3(lvl, msg, a1, a2, a3)
+#define Dmsg4(lvl, msg, arg1, arg2, arg3, arg4)
+#define Dmsg5(lvl, msg, a1, a2, a3, a4, a5)
+#define Dmsg6(lvl, msg, a1, a2, a3, a4, a5, a6)
+#define Dmsg7(lvl, msg, a1, a2, a3, a4, a5, a6, a7)
+#define Dmsg8(lvl, msg, a1, a2, a3, a4, a5, a6, a7, a8)
+#define Dmsg11(lvl,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
+#endif /* DEBUG */
+       
+/* Daemon Error Messages that are delivered according to the message resource */
+#define Emsg0(typ, lvl, msg)             e_msg(__FILE__, __LINE__, typ, lvl, msg)
+#define Emsg1(typ, lvl, msg, a1)         e_msg(__FILE__, __LINE__, typ, lvl, msg, a1)
+#define Emsg2(typ, lvl, msg, a1, a2)     e_msg(__FILE__, __LINE__, typ, lvl, msg, a1, a2)
+#define Emsg3(typ, lvl, msg, a1, a2, a3) e_msg(__FILE__, __LINE__, typ, lvl, msg, a1, a2, a3)
+#define Emsg4(typ, lvl, msg, a1, a2, a3, a4) e_msg(__FILE__, __LINE__, typ, lvl, msg, a1, a2, a3, a4)
+#define Emsg5(typ, lvl, msg, a1, a2, a3, a4, a5) e_msg(__FILE__, __LINE__, typ, lvl, msg, a1, a2, a3, a4, a5)
+#define Emsg6(typ, lvl, msg, a1, a2, a3, a4, a5, a6) e_msg(__FILE__, __LINE__, typ, lvl, msg, a1, a2, a3, a4, a5, a6)
+
+/* Job Error Messages that are delivered according to the message resource */
+#define Jmsg0(jcr, typ, lvl, msg)             j_msg(__FILE__, __LINE__, jcr, typ, lvl, msg)
+#define Jmsg1(jcr, typ, lvl, msg, a1)         j_msg(__FILE__, __LINE__, jcr, typ, lvl, msg, a1)
+#define Jmsg2(jcr, typ, lvl, msg, a1, a2)     j_msg(__FILE__, __LINE__, jcr, typ, lvl, msg, a1, a2)
+#define Jmsg3(jcr, typ, lvl, msg, a1, a2, a3) j_msg(__FILE__, __LINE__, jcr, typ, lvl, msg, a1, a2, a3)
+#define Jmsg4(jcr, typ, lvl, msg, a1, a2, a3, a4) j_msg(__FILE__, __LINE__, jcr, typ, lvl, msg, a1, a2, a3, a4)
+#define Jmsg5(jcr, typ, lvl, msg, a1, a2, a3, a4, a5) j_msg(__FILE__, __LINE__, jcr, typ, lvl, msg, a1, a2, a3, a4, a5)
+#define Jmsg6(jcr, typ, lvl, msg, a1, a2, a3, a4, a5, a6) j_msg(__FILE__, __LINE__, jcr, typ, lvl, msg, a1, a2, a3, a4, a5, a6)
+
+
+/* Memory Messages that are edited into a Pool Memory buffer */
+#define Mmsg0(buf, msg)             m_msg(__FILE__, __LINE__, buf, msg)
+#define Mmsg1(buf, msg, a1)         m_msg(__FILE__, __LINE__, buf, msg, a1)
+#define Mmsg2(buf, msg, a1, a2)     m_msg(__FILE__, __LINE__, buf, msg, a1, a2)
+#define Mmsg3(buf, msg, a1, a2, a3) m_msg(__FILE__, __LINE__, buf, msg, a1, a2, a3)
+#define Mmsg4(buf, msg, a1, a2, a3, a4) m_msg(__FILE__, __LINE__, buf, msg, a1, a2, a3, a4)
+#define Mmsg5(buf, msg, a1, a2, a3, a4, a5) m_msg(__FILE__, __LINE__, buf, msg, a1, a2, a3, a4, a5)
+#define Mmsg6(buf, msg, a1, a2, a3, a4, a5, a6) m_msg(__FILE__, __LINE__, buf, msg, a1, a2, a3, a4, a5, a6)
+#define Mmsg7(buf, msg, a1, a2, a3, a4, a5, a6, a7) m_msg(__FILE__, __LINE__, buf, msg, a1, a2, a3, a4, a5, a6)
+#define Mmsg8(buf,msg,a1,a2,a3,a4,a5,a6,a7,a8) m_msg(__FILE__,__LINE__,buf,msg,a1,a2,a3,a4,a5,a6)
+#define Mmsg11(buf,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) m_msg(__FILE__,__LINE__,buf,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)
+#define Mmsg15(buf,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) m_msg(__FILE__,__LINE__,buf,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)
+
+/* Edit message into Pool Memory buffer -- no __FILE__ and __LINE__ */
+int  Mmsg(char **msgbuf, char *fmt,...);
+
+
+void d_msg(char *file, int line, int level, char *fmt,...);
+void e_msg(char *file, int line, int type, int level, char *fmt,...);
+void j_msg(char *file, int line, void *vjcr, int type, int level, char *fmt,...);
+int  m_msg(char *file, int line, char **msgbuf, char *fmt,...);
+
+
+/* Use our strdup with smartalloc */
+#undef strdup
+#define strdup(buf) bad_call_on_strdup_use_bstrdup(buf)
+
+#ifdef DEBUG
+#define bstrdup(str) strcpy((char *) b_malloc(__FILE__,__LINE__,strlen((str))+1),(str))
+#else
+#define bstrdup(str) strcpy((char *) bmalloc(strlen((str))+1),(str))
+#endif
+
+#ifdef DEBUG
+#define bmalloc(size) b_malloc(__FILE__, __LINE__, (size))
+#endif
+
+#ifdef __alpha__
+#define OSF 1
+#endif
+
+#ifdef HAVE_SUN_OS
+   /* 
+    * On Solaris 2.5, threads are not timesliced by default, so we need to
+    * explictly increase the conncurrency level.
+    */
+#include <thread.h>
+#define set_thread_concurrency(x)  thr_setconcurrency(x)
+extern int thr_setconcurrency(int);
+#define SunOS 1
+
+#else
+
+/* Not needed on most systems */
+#define set_thread_concurrency(x)
+
+#endif
+
+#define ALIGN_SIZE (sizeof(double))
+#define BALIGN(x) (((x) + ALIGN_SIZE - 1) & ~(ALIGN_SIZE -1))
+
+#endif /* _BACONFIG_H */
diff --git a/bacula/src/bacula.h b/bacula/src/bacula.h
new file mode 100644 (file)
index 0000000..fa0ea3f
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * bacula.h -- main header file to include in all Bacula source
+ *
+ */
+
+/*
+
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef _BACULA_H
+#define _BACULA_H 1
+
+#include "config.h"
+
+#define _REENTRANT    1
+#define _THREAD_SAFE  1
+#define _POSIX_PTHREAD_SEMANTICS 1
+
+/* System includes */
+#include <stdarg.h>
+#include <stdio.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_GETOPT_LONG
+#include <getopt.h>
+#else
+#include "lib/getopt.h"
+#endif
+
+#include <string.h>
+#include <strings.h>
+#include <signal.h>
+#include <ctype.h>
+#include <syslog.h>
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#include <pwd.h>
+#include <time.h>
+#include <netdb.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+     
+/* Local Bacula includes. Be sure to put all the system
+ *  includes before these.  
+ */
+#include "version.h"
+#include "baconfig.h"
+#include "bc_types.h"
+#include "lib/lib.h"
+
+#endif
diff --git a/bacula/src/bc_types.h b/bacula/src/bc_types.h
new file mode 100644 (file)
index 0000000..2ab537f
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+    Integer types.  These types should be be used in all
+    contexts in which the length of an integer stored on
+    removable media must be known regardless of the
+    architecture of the platform.
+
+    Bacula types are:
+
+    int8_t,  int16_t,  int32_t,  int64_t
+    uint8_t, uint16_t, uint32_t, uint64_t
+    float32_t, float64_t
+
+    Also, we define types such as file address lengths.
+
+ */
+/*
+
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#ifndef __bc_types_INCLUDED
+#define __bc_types_INCLUDED
+
+/* ****FIXME***** implement 64 bit file addresses ! */
+#define faddr_t long 
+
+/* Types */
+
+/* If sys/types.h does not supply intXX_t, supply them ourselves */
+/* (or die trying) */
+
+#ifndef HAVE_U_INT
+typedef unsigned int u_int;
+#endif
+
+#ifndef HAVE_INTXX_T
+# if (SIZEOF_CHAR == 1)
+typedef char int8_t;
+# else
+#  error "8 bit int type not found."
+# endif
+# if (SIZEOF_SHORT_INT == 2)
+typedef short int int16_t;
+# else
+#  error "16 bit int type not found."
+# endif
+# if (SIZEOF_INT == 4)
+typedef int int32_t;
+# else
+#  error "32 bit int type not found."
+# endif
+#endif
+
+/* If sys/types.h does not supply u_intXX_t, supply them ourselves */
+#ifndef HAVE_U_INTXX_T
+# ifdef HAVE_UINTXX_T
+typedef uint8_t u_int8_t;
+typedef uint16_t u_int16_t;
+typedef uint32_t u_int32_t;
+# define HAVE_U_INTXX_T 1
+# else
+#  if (SIZEOF_CHAR == 1)
+typedef unsigned char u_int8_t;
+#  else
+#   error "8 bit int type not found."
+#  endif
+#  if (SIZEOF_SHORT_INT == 2)
+typedef unsigned short int u_int16_t;
+#  else
+#   error "16 bit int type not found."
+#  endif
+#  if (SIZEOF_INT == 4)
+typedef unsigned int u_int32_t;
+#  else
+#   error "32 bit int type not found."
+#  endif
+# endif
+#endif
+
+/* 64-bit types */
+#ifndef HAVE_INT64_T
+# if (SIZEOF_LONG_LONG_INT == 8)
+typedef long long int int64_t;
+#   define HAVE_INT64_T 1
+# else
+#  if (SIZEOF_LONG_INT == 8)
+typedef long int int64_t;
+#   define HAVE_INT64_T 1
+#  endif
+# endif
+#endif
+
+#ifndef HAVE_INTMAX_T
+# ifdef HAVE_INT64_T
+typedef int64_t intmax_t;
+# else
+typedef int32_t intmax_t;
+# endif
+#endif
+
+#ifndef HAVE_U_INT64_T
+# if (SIZEOF_LONG_LONG_INT == 8)
+typedef unsigned long long int u_int64_t;
+#   define HAVE_U_INT64_T 1
+# else
+#  if (SIZEOF_LONG_INT == 8)
+typedef unsigned long int u_int64_t;
+#   define HAVE_U_INT64_T 1
+#  endif
+# endif
+#endif
+
+#ifndef HAVE_U_INTMAX_T
+# ifdef HAVE_U_INT64_T
+typedef u_int64_t u_intmax_t;
+# else
+typedef u_int32_t u_intmax_t;
+# endif
+#endif
+
+
+/* Limits for the above types. */
+#undef INT8_MIN  
+#undef INT8_MAX  
+#undef UINT8_MAX 
+#undef INT16_MIN 
+#undef INT16_MAX 
+#undef UINT16_MAX
+#undef INT32_MIN 
+#undef INT32_MAX 
+#undef UINT32_MAX
+
+#define INT8_MIN        (-127-1)
+#define INT8_MAX        (127)
+#define UINT8_MAX       (255u)
+#define INT16_MIN       (-32767-1)
+#define INT16_MAX       (32767)
+#define UINT16_MAX      (65535u)
+#define INT32_MIN       (-2147483647-1)
+#define INT32_MAX       (2147483647)
+#define UINT32_MAX      (4294967295u)
+
+typedef double            float64_t;
+typedef float             float32_t;
+
+#endif /* __bc_types_INCLUDED */
+
+/* Define the uint versions actually used in Bacula */
+#define uint8_t u_int8_t
+#define uint16_t u_int16_t
+#define uint32_t u_int32_t
+#define uint64_t u_int64_t
+#define uintmax_t u_intmax_t
+
+#ifdef HAVE_CYGWIN
+#define socklen_t int
+#endif
diff --git a/bacula/src/c b/bacula/src/c
new file mode 100644 (file)
index 0000000..de15677
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
diff --git a/bacula/src/c.scr b/bacula/src/c.scr
new file mode 100644 (file)
index 0000000..206188e
--- /dev/null
@@ -0,0 +1,8 @@
+l Copyright (C)
+-1
+mark
+l */
+mark
+db
+inc /home/kern/bacula/k/src/c
+e
diff --git a/bacula/src/cats/Makefile.in b/bacula/src/cats/Makefile.in
new file mode 100644 (file)
index 0000000..4478ee9
--- /dev/null
@@ -0,0 +1,99 @@
+# 
+@MCOMMON@
+
+srcdir =       .
+.PATH:         .
+
+# one up
+basedir = ..
+# top dir
+topdir = ../..
+# this dir relative to top dir
+thisdir = src/cats
+
+DEBUG=@DEBUG@
+
+SQL_INC=@SQL_INCLUDE@
+
+first_rule: all
+dummy:
+
+#
+SVRSRCS = cats.c sql.c
+SVROBJS = cats.o sql.o
+
+LIBSRCS = mysql.c bdb.c bdb_create.c bdb_get.c bdb_update.c \
+         bdb_delete.c bdb_find.c bdb_list.c \
+         sql.c sql_create.c sql_delete.c sql_find.c \
+         sql_get.c sql_list.c sql_update.c sqlite.c 
+LIBOBJS = mysql.o bdb.o bdb_create.o bdb_get.o bdb_update.o \
+         bdb_delete.o bdb_find.o bdb_list.o \
+         sql.o sql_create.o sql_delete.o sql_find.o \
+         sql_get.o sql_list.o sql_update.o sqlite.o
+
+.SUFFIXES:     .c .o
+.PHONY:
+.DONTCARE:
+
+# inference rules
+.c.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(SQL_INC) $(DINCLUDE) $(CFLAGS) $<
+#-------------------------------------------------------------------------
+all: Makefile libsql.a
+       @echo "==== Make of cats is good ===="
+       @echo " "
+
+libsql.a: $(LIBOBJS)
+       $(AR) rcs $@ $(LIBOBJS)
+       $(RANLIB) $@
+
+cats: $(SVROBJS) ../findlib/libfind.a
+       $(CC) $(LDFLAGS) -L../findlib -L../lib -o $@ $(SVROBJS) $(LIBS) $(DLIB) -lfind -lbac
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+clean:
+       $(RMF) cats core a.out *.o *.a *.bak *~ *.intpro *.extpro 1 2 3
+
+realclean: clean
+       $(RMF) tags
+       $(RMF) make_mysql_tables grant_mysql_privileges drop_mysql_tables
+       $(RMF) create_mysql_database make_sqlite_tables sqlite
+
+distclean: realclean
+       if test $(srcdir) = .; then $(MAKE) realclean; fi
+       (cd $(srcdir); $(RMF) Makefile)
+
+install:
+       $(INSTALL_SCRIPT) create_mysql_database $(DESTDIR)$(sysconfdir)/create_mysql_database
+       $(INSTALL_SCRIPT) drop_mysql_tables $(DESTDIR)$(sysconfdir)/drop_mysql_tables
+       $(INSTALL_SCRIPT) make_mysql_tables $(DESTDIR)$(sysconfdir)/make_mysql_tables
+
+uninstall:
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) create_mysql_database)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) drop_mysql_tables)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) make_mysql_tables)
+
+
+# Semi-automatic generation of dependencies:
+# Use gcc -MM because X11 `makedepend' doesn't work on all systems
+# and it also includes system headers.
+# `semi'-automatic since dependencies are generated at distribution time.
+
+depend:
+       @$(MV) Makefile Makefile.bak
+       @$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile
+       @$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile
+       @$(CC) -S -M $(CPPFLAGS) $(XINC) -I$(srcdir) -I$(basedir) $(SQL_INC) *.c >> Makefile
+       @if test -f Makefile ; then \
+           $(RMF) Makefile.bak; \
+       else \
+          $(MV) Makefile.bak Makefile; \
+          echo -e "Something went wrong\n\a"; \
+       fi
+
+# -----------------------------------------------------------------------
+# DO NOT DELETE: nice dependency list follows
diff --git a/bacula/src/cats/bdb.c b/bacula/src/cats/bdb.c
new file mode 100644 (file)
index 0000000..95ebf71
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Bacula Catalog Database routines written specifically
+ *  for Bacula.  Note, these routines are VERY dumb and
+ *  do not provide all the functionality of an SQL database.
+ *  The purpose of these routines is to ensure that Bacula
+ *  can limp along if no real database is loaded on the
+ *  system.
+ *   
+ *    Kern Sibbald, January MMI 
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#ifdef HAVE_BACULA_DB
+
+/* Forward referenced functions */
+
+extern char *working_directory;
+
+/* List of open databases */
+static BQUEUE db_list = {&db_list, &db_list};
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* -----------------------------------------------------------------------
+ *
+ *   Bacula specific defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+
+#define DB_CONTROL_FILENAME  "control.db"
+#define DB_JOBS_FILENAME     "jobs.db"
+#define DB_POOLS_FILENAME    "pools.db"
+#define DB_MEDIA_FILENAME    "media.db"
+#define DB_JOBMEDIA_FILENAME "jobmedia.db"
+#define DB_CLIENT_FILENAME   "client.db"
+#define DB_FILESET_FILENAME  "fileset.db"
+
+static char *make_filename(B_DB *mdb, char *name)
+{
+   char *dbf, sep;
+
+   dbf = (char *) get_pool_memory(PM_FNAME);
+   if (working_directory[strlen(working_directory)-1] == '/') {
+      sep = 0;
+   } else {
+      sep = '/'; 
+   }
+   Mmsg(&dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
+   return dbf;
+}
+
+int bdb_write_control_file(B_DB *mdb)
+{
+   mdb->control.time = time(NULL);
+   lseek(mdb->cfd, 0, SEEK_SET);
+   if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
+      Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
+      Emsg0(M_FATAL, 0, mdb->errmsg);
+      return 0;
+   }
+   return 1;
+}
+
+/*
+ * Initialize database data structure. In principal this should
+ * never have errors, or it is really fatal.
+ */
+B_DB *
+db_init_database(char *db_name, char *db_user, char *db_password)
+{
+   B_DB *mdb;
+   P(mutex);                         /* lock DB queue */
+   /* Look to see if DB already open */
+   for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
+      if (strcmp(mdb->db_name, db_name) == 0) {
+         Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
+        mdb->ref_count++;
+        V(mutex);
+        return mdb;                  /* already open */
+      }
+   }
+   Dmsg0(200, "db_open first time\n");
+   mdb = (B_DB *) malloc(sizeof(B_DB));
+   memset(mdb, 0, sizeof(B_DB));
+   Dmsg0(200, "DB struct init\n");
+   mdb->db_name = bstrdup(db_name);
+   mdb->errmsg = (char *) get_pool_memory(PM_EMSG);
+   *mdb->errmsg = 0;
+   mdb->cmd = (char *) get_pool_memory(PM_EMSG);  /* command buffer */
+   mdb->ref_count = 1;
+   qinsert(&db_list, &mdb->bq);       /* put db in list */
+   Dmsg0(200, "Done db_open_database()\n");
+   mdb->cfd = -1;
+   V(mutex);
+   return mdb;
+}
+
+/*
+ * Now actually open the database.  This can generate errors,
+ * which are returned in the errmsg
+ */
+int
+db_open_database(B_DB *mdb)
+{
+   char *dbf;
+   int fd, badctl;
+   int errstat;
+   off_t filend;
+
+   Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
+
+   P(mutex);
+   if ((errstat = pthread_mutex_init(&(mdb->mutex), NULL)) != 0) {
+      Mmsg1(&mdb->errmsg, "Unable to initialize DB mutex. ERR=%s\n", strerror(errstat));
+      V(mutex);
+      return 0;
+   }
+   P(mdb->mutex);                    /* test it once */
+   V(mdb->mutex);
+
+   Dmsg0(200, "make_filename\n");
+   dbf = make_filename(mdb, DB_CONTROL_FILENAME);
+   mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600); 
+   free_memory(dbf);
+   if (mdb->cfd < 0) {
+      Mmsg2(&mdb->errmsg, "Unable to open Catalog DB control file %s: ERR=%s\n", 
+        dbf, strerror(errno));
+      V(mutex);
+      return 0;
+   }
+   Dmsg0(200, "DB open\n");
+   /* See if the file was previously written */
+   filend = lseek(mdb->cfd, 0, SEEK_END);
+   if (filend == 0) {                /* No, initialize everything */
+      Dmsg0(200, "Init DB files\n");
+      memset(&mdb->control, 0, sizeof(mdb->control));
+      mdb->control.bdb_version = BDB_VERSION;
+      bdb_write_control_file(mdb);
+
+      /* Create Jobs File */
+      dbf = make_filename(mdb, DB_JOBS_FILENAME);
+      fd = open(dbf, O_CREAT|O_RDWR, 0600);
+      free_memory(dbf);
+      close(fd);
+
+      /* Create Pools File */
+      dbf = make_filename(mdb, DB_POOLS_FILENAME);
+      fd = open(dbf, O_CREAT|O_RDWR, 0600);
+      free_memory(dbf);
+      close(fd);
+
+      /* Create Media File */
+      dbf = make_filename(mdb, DB_MEDIA_FILENAME);
+      fd = open(dbf, O_CREAT|O_RDWR, 0600);
+      free_memory(dbf);
+      close(fd);
+
+      /* Create JobMedia File */
+      dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
+      fd = open(dbf, O_CREAT|O_RDWR, 0600);
+      free_memory(dbf);
+      close(fd);
+
+      /* Create Client File */
+      dbf = make_filename(mdb, DB_CLIENT_FILENAME);
+      fd = open(dbf, O_CREAT|O_RDWR, 0600);
+      free_memory(dbf);
+      close(fd);
+
+      /* Create FileSet File */
+      dbf = make_filename(mdb, DB_FILESET_FILENAME);
+      fd = open(dbf, O_CREAT|O_RDWR, 0600);
+      free_memory(dbf);
+      close(fd);
+   }
+
+   Dmsg0(200, "Read control file\n");
+   badctl = 0;
+   lseek(mdb->cfd, 0, SEEK_SET);      /* seek to begining of control file */
+   if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
+      Mmsg1(&mdb->errmsg, "Error reading catalog DB control file. ERR=%s\n", strerror(errno));
+      badctl = 1;
+   } else if (mdb->control.bdb_version != BDB_VERSION) {
+      Mmsg2(&mdb->errmsg, "Error, catalog DB control file wrong version. \
+Wanted %d, got %d\n\
+Please reinitialize the working directory.\n", 
+        BDB_VERSION, mdb->control.bdb_version);
+      badctl = 1;
+   }
+   if (badctl) {
+      V(mutex);
+      return 0;
+   }
+   V(mutex);
+   return 1;
+}
+
+void db_close_database(B_DB *mdb)           
+{
+   P(mutex);
+   mdb->ref_count--;
+   if (mdb->ref_count == 0) {
+      qdchain(&mdb->bq);
+      /*  close file descriptors */
+      if (mdb->cfd >= 0) {
+        close(mdb->cfd);
+      }
+      free(mdb->db_name);
+      if (mdb->jobfd) {
+        fclose(mdb->jobfd);
+      }
+      if (mdb->poolfd) {
+        fclose(mdb->poolfd);
+      }
+      if (mdb->mediafd) {
+        fclose(mdb->mediafd);
+      }
+      if (mdb->jobmediafd) {
+        fclose(mdb->jobmediafd);
+      }
+      if (mdb->clientfd) {
+        fclose(mdb->clientfd);
+      }
+      if (mdb->filesetfd) {
+        fclose(mdb->filesetfd);
+      }
+      pthread_mutex_destroy(&mdb->mutex);
+      free_pool_memory(mdb->errmsg);
+      free_pool_memory(mdb->cmd);
+      free(mdb);
+   }
+   V(mutex);
+}
+
+
+void db_escape_string(char *snew, char *old, int len)
+{
+   strcpy(snew, old);
+}
+
+char *db_strerror(B_DB *mdb)
+{
+   return mdb->errmsg;
+}
+
+int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
+{
+   return 1;
+}
+
+/*
+ * Open the Jobs file for reading/writing
+ */
+int bdb_open_jobs_file(B_DB *mdb)
+{
+   char *dbf;
+
+   if (!mdb->jobfd) {  
+      dbf = make_filename(mdb, DB_JOBS_FILENAME);
+      mdb->jobfd = fopen(dbf, "r+");
+      if (!mdb->jobfd) {
+         Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n", 
+           dbf, strerror(errno));
+        Emsg0(M_FATAL, 0, mdb->errmsg);
+        free_memory(dbf);
+        return 0;
+      }
+      free_memory(dbf);
+   }
+   return 1;
+}
+
+/*
+ * Open the JobMedia file for reading/writing
+ */
+int bdb_open_jobmedia_file(B_DB *mdb)
+{
+   char *dbf;
+
+   if (!mdb->jobmediafd) {  
+      dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
+      mdb->jobmediafd = fopen(dbf, "r+");
+      if (!mdb->jobmediafd) {
+         Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n", 
+           dbf, strerror(errno));
+        Emsg0(M_FATAL, 0, mdb->errmsg);
+        free_memory(dbf);
+        return 0;
+      }
+      free_memory(dbf);
+   }
+   return 1;
+}
+
+
+/*
+ * Open the Pools file for reading/writing
+ */
+int bdb_open_pools_file(B_DB *mdb)
+{
+   char *dbf;
+
+   if (!mdb->poolfd) { 
+      dbf = make_filename(mdb, DB_POOLS_FILENAME);
+      mdb->poolfd = fopen(dbf, "r+");
+      if (!mdb->poolfd) {
+         Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n", 
+           dbf, strerror(errno));
+        Emsg0(M_FATAL, 0, mdb->errmsg);
+        free_memory(dbf);
+        return 0;
+      }
+      Dmsg1(200, "Opened pool file %s\n", dbf);
+      free_memory(dbf);
+   }
+   return 1;
+}
+
+/*
+ * Open the Client file for reading/writing
+ */
+int bdb_open_client_file(B_DB *mdb)
+{
+   char *dbf;
+
+   if (!mdb->clientfd) {  
+      dbf = make_filename(mdb, DB_CLIENT_FILENAME);
+      mdb->clientfd = fopen(dbf, "r+");
+      if (!mdb->clientfd) {
+         Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n", 
+           dbf, strerror(errno));
+        Emsg0(M_FATAL, 0, mdb->errmsg);
+        free_memory(dbf);
+        return 0;
+      }
+      free_memory(dbf);
+   }
+   return 1;
+}
+
+/*
+ * Open the FileSet file for reading/writing
+ */
+int bdb_open_fileset_file(B_DB *mdb)
+{
+   char *dbf;
+
+   if (!mdb->filesetfd) {  
+      dbf = make_filename(mdb, DB_CLIENT_FILENAME);
+      mdb->filesetfd = fopen(dbf, "r+");
+      if (!mdb->filesetfd) {
+         Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n", 
+           dbf, strerror(errno));
+        Emsg0(M_FATAL, 0, mdb->errmsg);
+        free_memory(dbf);
+        return 0;
+      }
+      free_memory(dbf);
+   }
+   return 1;
+}
+
+
+
+/*
+ * Open the Media file for reading/writing
+ */
+int bdb_open_media_file(B_DB *mdb)
+{
+   char *dbf;
+
+   if (!mdb->mediafd) {  
+      dbf = make_filename(mdb, DB_MEDIA_FILENAME);
+      mdb->mediafd = fopen(dbf, "r+");
+      if (!mdb->mediafd) {
+         Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n", 
+           dbf, strerror(errno));
+        free_memory(dbf);
+        return 0;
+      }
+      free_memory(dbf);
+   }
+   return 1;
+}
+
+#endif /* HAVE_BACULA_DB */
diff --git a/bacula/src/cats/bdb.h b/bacula/src/cats/bdb.h
new file mode 100644 (file)
index 0000000..67bb3f5
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Definitions common to the Bacula Database Routines (bdb).
+ */
+
+/* bdb.c */
+extern int bdb_open_jobs_file(B_DB *mdb);
+extern int bdb_write_control_file(B_DB *mdb);
+extern int bdb_open_jobmedia_file(B_DB *mdb);
+extern int bdb_open_pools_file(B_DB *mdb);
+extern int bdb_open_media_file(B_DB *mdb);
+extern int bdb_open_client_file(B_DB *mdb);
+extern int bdb_open_fileset_file(B_DB *mdb);
+extern int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr);
diff --git a/bacula/src/cats/bdb_create.c b/bacula/src/cats/bdb_create.c
new file mode 100644 (file)
index 0000000..b415463
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Bacula Catalog Database Create record routines
+ *
+ * Bacula Catalog Database routines written specifically
+ *  for Bacula.  Note, these routines are VERY dumb and
+ *  do not provide all the functionality of an SQL database.
+ *  The purpose of these routines is to ensure that Bacula
+ *  can limp along if no real database is loaded on the
+ *  system.
+ *   
+ *    Kern Sibbald, January MMI 
+ */
+
+/*
+   Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+#include "bdb.h"
+
+#ifdef HAVE_BACULA_DB
+
+/* Forward referenced functions */
+int db_create_pool_record(B_DB *mdb, POOL_DBR *pr);
+
+/* -----------------------------------------------------------------------
+ *
+ *   Bacula specific defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+int db_create_file_attributes_record(B_DB *mdb, ATTR_DBR *ar)
+{
+   /* *****FIXME***** implement this */
+   return 1;
+}
+
+int db_create_file_item(B_DB *mdb, ATTR_DBR *ar)
+{           
+   /****FIXME***** not implemented */
+   return 1;
+}
+
+
+/*  
+ * Create a new record for the Job    
+ *   This record is created at the start of the Job,
+ *   it is updated in bdb_update.c when the Job terminates.
+ *
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int db_create_job_record(B_DB *mdb, JOB_DBR *jr)
+{
+   int len;
+
+   P(mdb->mutex);
+   if (!bdb_open_jobs_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   mdb->control.JobId++;
+   bdb_write_control_file(mdb);
+
+   len = sizeof(JOB_DBR);
+   jr->JobId = mdb->control.JobId;
+   fseek(mdb->jobfd, 0L, SEEK_END);
+   if (fwrite(jr, len, 1, mdb->jobfd) != 1) {
+      Mmsg1(&mdb->errmsg, "Error writing DB Jobs file. ERR=%s\n", strerror(errno));
+      V(mdb->mutex);
+      return 0;
+   }
+   fflush(mdb->jobfd);
+   V(mdb->mutex);
+   return 1;
+}
+
+/* Create a JobMedia record for Volume used this job   
+ * Returns: 0 on failure
+ *         record-id on success
+ */
+int db_create_jobmedia_record(B_DB *mdb, JOBMEDIA_DBR *jm)
+{
+   int len;
+
+   P(mdb->mutex);
+   if (!bdb_open_jobmedia_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   mdb->control.JobMediaId++;
+   jm->JobMediaId = mdb->control.JobMediaId;
+   bdb_write_control_file(mdb);
+
+   len = sizeof(JOBMEDIA_DBR);
+
+   fseek(mdb->jobmediafd, 0L, SEEK_END);
+   if (fwrite(jm, len, 1, mdb->jobmediafd) != 1) {
+      Mmsg1(&mdb->errmsg, "Error writing DB JobMedia file. ERR=%s\n", strerror(errno));
+      V(mdb->mutex);
+      return 0;
+   }
+   fflush(mdb->jobmediafd);
+   V(mdb->mutex);
+   return jm->JobMediaId;
+}
+
+
+/*
+ *  Create a unique Pool record
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int db_create_pool_record(B_DB *mdb, POOL_DBR *pr)
+{
+   int len;
+   POOL_DBR mpr;
+
+   memset(&mpr, 0, sizeof(mpr));
+   strcpy(mpr.Name, pr->Name);
+   if (db_get_pool_record(mdb, &mpr)) {
+      Mmsg1(&mdb->errmsg, "Pool record %s already exists\n", mpr.Name);
+      return 0;
+   }
+
+   P(mdb->mutex);
+   if (!bdb_open_pools_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+
+   mdb->control.PoolId++;
+   pr->PoolId = mdb->control.PoolId;
+   bdb_write_control_file(mdb);
+
+   len = sizeof(mpr);
+   fseek(mdb->poolfd, 0L, SEEK_END);
+   if (fwrite(pr, len, 1, mdb->poolfd) != 1) {
+      Mmsg1(&mdb->errmsg, "Error writing DB Pools file. ERR=%s\n", strerror(errno));
+      V(mdb->mutex);
+      return 0;
+   }
+   fflush(mdb->poolfd);
+   V(mdb->mutex);
+   return 1;
+}
+
+
+/* 
+ * Create Unique Media record. This record
+ *   contains all the data pertaining to a specific
+ *   Volume.
+ *
+ * Returns: 0 on failure
+ *         1 on success
+ */ 
+int db_create_media_record(B_DB *mdb, MEDIA_DBR *mr)
+{
+   int len;
+   MEDIA_DBR mmr;
+
+   memset(&mmr, 0, sizeof(mmr));
+   strcpy(mmr.VolumeName, mr->VolumeName);
+   if (db_get_media_record(mdb, &mmr)) {
+      Mmsg1(&mdb->errmsg, "Media record %s already exists\n", mmr.VolumeName);
+      return 0;
+   }
+
+   P(mdb->mutex);
+
+   mdb->control.MediaId++;
+   mr->MediaId = mdb->control.MediaId;
+   bdb_write_control_file(mdb);
+
+   len = sizeof(mmr);
+   fseek(mdb->mediafd, 0L, SEEK_END);
+   if (fwrite(mr, len, 1, mdb->mediafd) != 1) {
+      Mmsg1(&mdb->errmsg, "Error writing DB Media file. ERR=%s\n", strerror(errno));
+      V(mdb->mutex);
+      return 0;
+   }
+   fflush(mdb->mediafd);
+   V(mdb->mutex);
+   return 1;
+}
+
+
+/*
+ *  Create a unique Client record or return existing record
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int db_create_client_record(B_DB *mdb, CLIENT_DBR *cr)
+{
+   int len;
+   CLIENT_DBR lcr;
+
+   cr->ClientId = 0;
+   if (db_get_client_record(mdb, cr)) {
+      Mmsg1(&mdb->errmsg, "Client record %s already exists\n", cr->Name);
+      return 1;
+   }
+
+   P(mdb->mutex);
+   if (!bdb_open_client_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+
+   mdb->control.ClientId++;
+   cr->ClientId = mdb->control.ClientId;
+   bdb_write_control_file(mdb);
+
+   fseek(mdb->clientfd, 0L, SEEK_END);
+   len = sizeof(lcr);
+   if (fwrite(cr, len, 1, mdb->clientfd) != 1) {
+      Mmsg1(&mdb->errmsg, "Error writing DB Client file. ERR=%s\n", strerror(errno));
+      V(mdb->mutex);
+      return 0;
+   }
+   fflush(mdb->clientfd);
+   V(mdb->mutex);
+   return 1;
+}
+
+/*
+ *  Create a unique FileSet record or return existing record
+ *
+ *   Note, here we write the FILESET_DBR structure 
+ *
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int db_create_fileset_record(B_DB *mdb, FILESET_DBR *fsr)
+{
+   int len;
+   FILESET_DBR lfsr;
+
+   fsr->FileSetId = 0;
+   if (db_get_fileset_record(mdb, fsr)) {
+      Mmsg1(&mdb->errmsg, "FileSet record %s already exists\n", fsr->FileSet);
+      return 1;
+   }
+
+   P(mdb->mutex);
+   if (!bdb_open_fileset_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+
+   mdb->control.FileSetId++;
+   fsr->FileSetId = mdb->control.FileSetId;
+   bdb_write_control_file(mdb);
+
+   fseek(mdb->clientfd, 0L, SEEK_END);
+   len = sizeof(lfsr);
+   if (fwrite(fsr,  len, 1, mdb->filesetfd) != 1) {
+      Mmsg1(&mdb->errmsg, "Error writing DB FileSet file. ERR=%s\n", strerror(errno));
+      V(mdb->mutex);
+      return 0;
+   }
+   fflush(mdb->filesetfd);
+   V(mdb->mutex);
+   return 1;
+}
+
+#endif /* HAVE_BACULA_DB */
diff --git a/bacula/src/cats/bdb_delete.c b/bacula/src/cats/bdb_delete.c
new file mode 100644 (file)
index 0000000..3537ef3
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Bacula Catalog Database Delete record interface routines
+ *
+ * Bacula Catalog Database routines written specifically
+ *  for Bacula.  Note, these routines are VERY dumb and
+ *  do not provide all the functionality of an SQL database.
+ *  The purpose of these routines is to ensure that Bacula
+ *  can limp along if no real database is loaded on the
+ *  system.
+ *   
+ *    Kern Sibbald, January MMI 
+ */
+
+/*
+   Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+#include "bdb.h"
+
+#ifdef HAVE_BACULA_DB
+
+/* Forward referenced functions */
+
+/* -----------------------------------------------------------------------
+ *
+ *   Bacula specific defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+
+/*
+ * Delete a Pool record given the Name
+ *
+ * Returns: 0 on error
+ *         the number of records deleted on success 
+ */
+int db_delete_pool_record(B_DB *mdb, POOL_DBR *pr)
+{
+   int stat;
+   POOL_DBR opr;
+
+   pr->PoolId = 0;                   /* Search on Pool Name */
+   if (!db_get_pool_record(mdb, pr)) {
+      Mmsg1(&mdb->errmsg, "No pool record %s exists\n", pr->Name);
+      return 0;
+   }
+   P(mdb->mutex);
+   fseek(mdb->poolfd, pr->rec_addr, SEEK_SET);
+   memset(&opr, 0, sizeof(opr));
+   stat = fwrite(&opr, sizeof(opr), 1, mdb->poolfd);
+   V(mdb->mutex);
+   return stat; 
+}
+
+int db_delete_media_record(B_DB *mdb, MEDIA_DBR *mr) 
+{ 
+   int stat;
+   MEDIA_DBR omr;
+
+   if (!db_get_media_record(mdb, mr)) {
+      Mmsg0(&mdb->errmsg, "Media record not found.\n");
+      return 0;
+   }
+   P(mdb->mutex);
+   fseek(mdb->mediafd, mr->rec_addr, SEEK_SET);
+   memset(&omr, 0, sizeof(omr));
+   stat = fwrite(&omr, sizeof(omr), 1, mdb->mediafd);
+   V(mdb->mutex);
+   return stat; 
+}
+
+#endif /* HAVE_BACULA_DB */
diff --git a/bacula/src/cats/bdb_find.c b/bacula/src/cats/bdb_find.c
new file mode 100644 (file)
index 0000000..71363d3
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Bacula Catalog Database Find record interface routines
+ *
+ *  Note, generally, these routines are more complicated
+ *       that a simple search by name or id. Such simple
+ *       request are in get.c
+ *
+ * Bacula Catalog Database routines written specifically
+ *  for Bacula.  Note, these routines are VERY dumb and
+ *  do not provide all the functionality of an SQL database.
+ *  The purpose of these routines is to ensure that Bacula
+ *  can limp along if no real database is loaded on the
+ *  system.
+ *   
+ *    Kern Sibbald, January MMI 
+ */
+
+/*
+   Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+#include "bdb.h"
+
+#ifdef HAVE_BACULA_DB
+
+/* Forward referenced functions */
+int db_find_job_start_time(B_DB *mdb, JOB_DBR *jr, char *stime);
+
+/* -----------------------------------------------------------------------
+ *
+ *   Bacula specific defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+
+/* 
+ * Find job start time. Used to find last full save that terminated normally
+ * so we can do Incremental and Differential saves.
+ *
+ * Returns: 0 on failure
+ *         1 on success, jr unchanged, but stime set
+ */
+int db_find_job_start_time(B_DB *mdb, JOB_DBR *jr, char *stime)
+{
+   char cmd[MAXSTRING], Name[MAX_NAME_LENGTH], StartTime[MAXSTRING];
+   int Type, Level;
+   uint32_t JobId, EndId, ClientId;
+   char cType[10], cLevel[10], JobStatus[10];
+   int stat = 0;
+   int found;
+   long addr;
+
+   strcpy(stime, "0000-00-00 00:00:00");   /* default */
+   P(mdb->mutex);
+   if (!bdb_open_jobs_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   fseek(mdb->jobfd, 0L, SEEK_SET);   /* rewind file */
+   /* Linear search through JobStart records
+    */
+
+   while (fgets(cmd, sizeof(cmd), mdb->jobfd)) {
+      if (sscanf(cmd, "JobStart JobId=%d Name=%127s Type=%1s Level=%1s \
+StartTime=%100s", &JobId, Name, cType, cLevel, StartTime) == 5) {
+        if (JobId < jr->JobId) {
+           continue;                 /* older not a candidate */
+        }
+        Type = cType[0];
+        Level = cLevel[0];
+        unbash_spaces(Name);
+        unbash_spaces(StartTime);
+         Dmsg4(200, "Got Type=%c Level=%c Name=%s StartTime=%s\n",
+           Type, Level, Name, StartTime);
+         Dmsg3(200, "Want Type=%c Level=%c Name=%s\n", jr->Type, jr->Level,     
+           jr->Name);
+        /* Differential is since last Full backup */
+        /* Incremental is since last FULL or Incremental or Differential */
+        if (((jr->Level == L_DIFFERENTIAL) && (Type == jr->Type && 
+              Level == L_FULL && strcmp(Name, jr->Name) == 0)) ||
+            ((jr->Level == L_INCREMENTAL) && (Type == jr->Type && 
+              (Level == L_FULL || Level == L_INCREMENTAL ||
+               Level == L_DIFFERENTIAL) && strcmp(Name, jr->Name) == 0))) {
+           addr = ftell(mdb->jobfd);    /* save current location */
+           JobStatus[0] = 0;
+           found = 0;
+           /* Search for matching JobEnd record */
+           while (!found && fgets(cmd, sizeof(cmd), mdb->jobfd)) {
+               if (sscanf(cmd, "JobEnd JobId=%d JobStatus=%1s ClientId=%d",
+                 &EndId, JobStatus, &ClientId) == 3) {
+                  if (EndId == JobId && *JobStatus == 'T' && ClientId == jr->ClientId) {
+                     Dmsg0(200, "====found EndJob matching Job\n");
+                    found = 1;
+                    break;
+                 }
+              }
+           }
+           /* Reset for next read */
+           fseek(mdb->jobfd, addr, SEEK_SET);
+           if (found) {
+              strcpy(stime, StartTime);
+              stat = 1;              /* Got a candidate */
+               Dmsg5(200, "Got candidate JobId=%d Type=%c Level=%c Name=%s StartTime=%s\n",
+                 JobId, Type, Level, Name, StartTime);
+           }
+        }
+      }
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+
+/* 
+ * Find Available Media (Volume) for Pool
+ *
+ * Find a Volume for a given PoolId, MediaType, and VolStatus
+ *
+ * Returns: 0 on failure
+ *         numrows on success
+ */
+int db_find_next_volume(B_DB *mdb, int item, MEDIA_DBR *mr)
+{
+   MEDIA_DBR omr;
+   int stat = 0;
+   int index = 0;
+   int len;
+
+   P(mdb->mutex);
+   if (!bdb_open_media_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   fseek(mdb->mediafd, 0L, SEEK_SET);  /* rewind file */
+   len = sizeof(omr);
+   while (fread(&omr, len, 1, mdb->mediafd) > 0) {
+      if (mr->PoolId == omr.PoolId && strcmp(mr->VolStatus, omr.VolStatus) == 0 &&
+         strcmp(mr->MediaType, omr.MediaType) == 0) {
+         if (!(++index == item)) {    /* looking for item'th entry */
+            Dmsg0(200, "Media record matches, but not index\n");
+           continue;
+        }
+         Dmsg0(200, "Media record matches\n");
+        memcpy(mr, &omr, len);
+         Dmsg1(200, "Findnextvol MediaId=%d\n", mr->MediaId);
+        stat = 1;
+        break;                       /* found it */
+      }
+   }
+   V(mdb->mutex);
+   return stat;                
+}
+
+int db_find_last_full_verify(B_DB *mdb, JOB_DBR *jr) { return 0; }
+
+
+#endif /* HAVE_BACULA_DB */
diff --git a/bacula/src/cats/bdb_get.c b/bacula/src/cats/bdb_get.c
new file mode 100644 (file)
index 0000000..c94c3e7
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Bacula Catalog Database Get record interface routines
+ *  Note, these routines generally get a record by id or
+ *       by name.  If more logic is involved, the routine
+ *       should be in find.c 
+ *
+ * Bacula Catalog Database routines written specifically
+ *  for Bacula.  Note, these routines are VERY dumb and
+ *  do not provide all the functionality of an SQL database.
+ *  The purpose of these routines is to ensure that Bacula
+ *  can limp along if no real database is loaded on the
+ *  system.
+ *   
+ *    Kern Sibbald, January MMI 
+ */
+
+/*
+   Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+#include "bdb.h"
+
+#ifdef HAVE_BACULA_DB
+
+/* Forward referenced functions */
+int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr);
+int db_get_pool_record(B_DB *mdb, POOL_DBR *pr);
+
+
+/* -----------------------------------------------------------------------
+ *
+ *   Bacula specific defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+
+/* 
+ * Get Job record for given JobId
+ * Returns: 0 on failure
+ *         1 on success
+ */
+
+int db_get_job_record(B_DB *mdb, JOB_DBR *jr)
+{ 
+   JOB_DBR ojr;
+   faddr_t rec_addr;
+   int found = 0;
+   int stat = 0;
+   int len;
+
+   P(mdb->mutex);
+   if (jr->JobId == 0 && jr->Name[0] == 0) { /* he wants # of Job records */
+      jr->JobId = mdb->control.JobId;
+      V(mdb->mutex);
+      return 1;
+   }
+   Dmsg0(200, "Open Jobs\n");
+   if (!bdb_open_jobs_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   fseek(mdb->jobfd, 0L, SEEK_SET);   /* rewind file */
+   rec_addr = 0;
+   /* Linear search through Job records
+    */
+   len = sizeof(ojr);
+   while (fread(&ojr, len, 1, mdb->jobfd) > 0) {
+      /* If id not zero, search by Id */
+      if (jr->JobId != 0) {
+        if (jr->JobId == ojr.JobId) {
+          found = 1;
+        }
+      /* Search by Job */
+      } else if (strcmp(jr->Job, ojr.Job) == 0) {
+        found = 1;
+         Dmsg1(200, "Found Job: %s\n", ojr.Job);
+      }
+      if (!found) {
+        rec_addr = ftell(mdb->jobfd); /* save start next record */
+        continue;
+      }
+      /* Found desired record, now return it */
+      memcpy(jr, &ojr, len);
+      jr->rec_addr = rec_addr;
+      stat = ojr.JobId;
+      Dmsg2(200, "Found job record: JobId=%d Job=%s",
+        ojr.JobId, ojr.Job);
+      break;
+   }
+   if (!found) {
+      strcpy(mdb->errmsg, "Job record not found.\n");
+   }
+   V(mdb->mutex);
+   Dmsg1(200, "Return job stat=%d\n", stat);
+   return stat;
+}
+
+
+/* 
+ * Get the number of pool records
+ *
+ * Returns: -1 on failure
+ *         number on success
+ */
+int db_get_num_pool_records(B_DB *mdb)
+{
+   int stat = 0;
+
+   P(mdb->mutex);
+   stat = mdb->control.PoolId;
+   V(mdb->mutex);
+   return stat;
+}
+
+/*
+ * This function returns a list of all the Pool record ids.
+ *  The caller must free ids if non-NULL.
+ *
+ *  Returns 0: on failure
+ *         1: on success
+ */
+int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
+{
+   int i = 0;
+   uint32_t *id;
+   POOL_DBR opr;
+   int len;
+
+   P(mdb->mutex);
+   *ids = NULL;
+   if (!bdb_open_pools_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   fseek(mdb->poolfd, 0L, SEEK_SET);   /* rewind file */
+   /* Linear search through Pool records
+    */
+   len = sizeof(opr);
+   *num_ids = mdb->control.PoolId;
+   id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
+   while (fread(&opr, len, 1, mdb->poolfd) > 0) {
+      id[i++] = opr.PoolId;
+   }
+   *ids = id;
+   V(mdb->mutex);
+   return 1;
+}
+
+
+/* 
+ * Get Pool Record   
+ * If the PoolId is non-zero, we get its record,
+ *  otherwise, we search on the PoolName
+ *
+ * Returns: 0 on failure
+ *         id on success 
+ */
+int db_get_pool_record(B_DB *mdb, POOL_DBR *pr)
+{
+   POOL_DBR opr;
+   faddr_t rec_addr;
+   int found = 0;
+   int stat = 0;
+   int len;
+
+   P(mdb->mutex);
+   Dmsg0(200, "Open pools\n");
+   if (!bdb_open_pools_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   fseek(mdb->poolfd, 0L, SEEK_SET);   /* rewind file */
+   rec_addr = 0;
+   /* Linear search through Pool records
+    */
+   len = sizeof(opr);
+   while (fread(&opr, len, 1, mdb->poolfd) > 0) {
+      /* If id not zero, search by Id */
+      if (pr->PoolId != 0) {
+        if (pr->PoolId == opr.PoolId) {
+          found = 1;
+        }
+      /* Search by Name */
+      } else if (strcmp(pr->Name, opr.Name) == 0) {
+        found = 1;
+         Dmsg1(200, "Found pool: %s\n", opr.Name);
+      }
+      if (!found) {
+        rec_addr = ftell(mdb->poolfd); /* save start next record */
+        continue;
+      }
+      /* Found desired record, now return it */
+      memcpy(pr, &opr, len);
+      pr->rec_addr = rec_addr;
+      stat = opr.PoolId;
+      Dmsg3(200, "Found pool record: PoolId=%d Name=%s PoolType=%s\n",
+        opr.PoolId, opr.Name, opr.PoolType);
+      break;
+   }
+   if (!found) {
+      strcpy(mdb->errmsg, "Pool record not found.\n");
+   }
+   V(mdb->mutex);
+   Dmsg1(200, "Return pool stat=%d\n", stat);
+   return stat;
+}
+
+/* 
+ * Get the number of Media records
+ *
+ * Returns: -1 on failure
+ *         number on success
+ */
+int db_get_num_media_records(B_DB *mdb)
+{
+   int stat = 0;
+
+   P(mdb->mutex);
+   stat = mdb->control.MediaId;
+   V(mdb->mutex);
+   return stat;
+}
+
+/*
+ * This function returns a list of all the Media record ids.
+ *  The caller must free ids if non-NULL.
+ *
+ *  Returns 0: on failure
+ *         1: on success
+ */
+int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
+{
+   int i = 0;
+   uint32_t *id;
+   MEDIA_DBR omr;
+   int len;
+
+   P(mdb->mutex);
+   *ids = NULL;
+   if (!bdb_open_media_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   fseek(mdb->mediafd, 0L, SEEK_SET);  /* rewind file */
+   /* Linear search through Pool records
+    */
+   len = sizeof(omr);
+   *num_ids = mdb->control.MediaId;
+   id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
+   while (fread(&omr, len, 1, mdb->mediafd) > 0) {
+      id[i++] = omr.MediaId;
+   }
+   *ids = id;
+   V(mdb->mutex);
+   return 1;
+}
+
+/* 
+ * Get Media Record   
+ * If the MediaId is non-zero, we get its record,
+ *  otherwise, we search on the MediaName
+ *
+ * Returns: 0 on failure
+ *         id on success 
+ */
+int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr)
+{
+   faddr_t rec_addr;
+   int found = 0;
+   int stat = 0;
+   int len;
+   MEDIA_DBR omr;
+
+   P(mdb->mutex);
+   if (!bdb_open_media_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   fseek(mdb->mediafd, 0L, SEEK_SET);  /* rewind file */
+   rec_addr = 0;
+   /* Linear search through Media records
+    */
+   len = sizeof(omr);
+   while (fread(&omr, len, 1, mdb->mediafd) > 0) {
+      if (omr.MediaId == 0) {
+        continue;                    /* deleted record */
+      }
+      Dmsg1(200, "VolName=%s\n", omr.VolumeName);
+      /* If id not zero, search by Id */
+      if (mr->MediaId != 0) {
+         Dmsg1(200, "MediaId=%d\n", mr->MediaId);
+        if (mr->MediaId == omr.MediaId) {
+          found = 1;
+        }
+      /* Search by Name */
+      } else if (strcmp(mr->VolumeName, omr.VolumeName) == 0) {
+        found = 1;
+      }
+      if (!found) {
+        rec_addr = ftell(mdb->mediafd); /* save start next record */
+        continue;
+      }
+      /* Found desired record, now return it */
+      memcpy(mr, &omr, len);
+      mr->rec_addr = rec_addr;
+      stat = omr.MediaId;
+      Dmsg3(200, "Found media record: MediaId=%d Name=%s MediaType=%s\n",
+        omr.MediaId, omr.VolumeName, mr->MediaType);
+      break;
+   }
+   if (stat == 0) {
+      strcpy(mdb->errmsg, "Could not find requested Media record.\n");
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+/*
+ * Find VolumeNames for a give JobId
+ *  Returns: 0 on error or no Volumes found
+ *          number of volumes on success
+ *             Volumes are concatenated in VolumeNames
+ *             separated by a vertical bar (|).
+ */
+int db_get_job_volume_names(B_DB *mdb, uint32_t JobId, char *VolumeNames)
+{
+   int found = 0;
+   JOBMEDIA_DBR jm;
+   MEDIA_DBR mr;
+   int jmlen, mrlen;
+
+   P(mdb->mutex);
+   if (!bdb_open_jobmedia_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   if (!bdb_open_media_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   jmlen = sizeof(jm);
+   mrlen = sizeof(mr);
+   *VolumeNames = 0;
+   fseek(mdb->jobmediafd, 0L, SEEK_SET); /* rewind the file */
+   while (fread(&jm, jmlen, 1, mdb->jobmediafd) > 0) {
+      if (jm.JobId == JobId) {
+        /* Now look up VolumeName in Media file given MediaId */
+        fseek(mdb->mediafd, 0L, SEEK_SET);
+        while (fread(&mr, mrlen, 1, mdb->mediafd) > 0) {
+           if (jm.MediaId == mr.MediaId) {
+              if (*VolumeNames != 0) {         /* if not first name, */
+                  strcat(VolumeNames, "|");     /* add separator */
+              }
+              strcat(VolumeNames, mr.VolumeName); /* add Volume Name */
+              found++;
+           }
+        }
+      }
+   }
+   if (!found) {
+      strcpy(mdb->errmsg, "No Volumes found.\n");
+   }
+   V(mdb->mutex);
+   return found; 
+}
+
+/* 
+ * Get Client Record   
+ * If the ClientId is non-zero, we get its record,
+ *  otherwise, we search on the Name
+ *
+ * Returns: 0 on failure
+ *         id on success 
+ */
+int db_get_client_record(B_DB *mdb, CLIENT_DBR *cr)
+{
+   CLIENT_DBR lcr;
+   int len;
+   int stat = 0;
+
+   P(mdb->mutex);
+   if (!bdb_open_client_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   fseek(mdb->clientfd, 0L, SEEK_SET);  /* rewind file */
+   /*
+    * Linear search through Client records
+    */
+   len = sizeof(lcr);
+   while (fread(&lcr, len, 1, mdb->clientfd)) {
+      /* If id not zero, search by Id */
+      if (cr->ClientId != 0) {
+        if (cr->ClientId != lcr.ClientId) {
+           continue;
+        }
+      /* Search by Name */
+      } else if (strcmp(cr->Name, lcr.Name) != 0) {
+        continue;                 /* not found */
+      }
+      memcpy(cr, &lcr, len);
+      stat = lcr.ClientId;
+      Dmsg2(200, "Found Client record: ClientId=%d Name=%s\n", 
+           lcr.ClientId, lcr.Name);
+      break;
+   }
+   if (!stat) {
+      strcpy(mdb->errmsg, "Client record not found.\n");
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+/* 
+ * Get FileSet Record  (We read the FILESET_DBR structure)
+ * If the FileSetId is non-zero, we get its record,
+ *  otherwise, we search on the FileSet (its name).
+ *
+ * Returns: 0 on failure
+ *         id on success 
+ */
+int db_get_fileset_record(B_DB *mdb, FILESET_DBR *fsr)
+{
+   FILESET_DBR lfsr;
+   int stat = 0;
+
+   P(mdb->mutex);
+   if (!bdb_open_fileset_file(mdb)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   fseek(mdb->filesetfd, 0L, SEEK_SET);   /* rewind file */
+   /*
+    * Linear search through FileSet records
+    */
+   while (fread(&lfsr, sizeof(lfsr), 1, mdb->filesetfd) > 0) {
+      /* If id not zero, search by Id */
+      if (fsr->FileSetId != 0) {
+        if (fsr->FileSetId != lfsr.FileSetId) {
+           continue;
+        }
+      /* Search by Name & MD5 */
+      } else if (strcmp(fsr->FileSet, lfsr.FileSet) != 0 ||
+                strcmp(fsr->MD5, lfsr.MD5) != 0) {
+        continue;                 /* not found */
+      }
+      /* Found desired record, now return it */
+      memcpy(fsr, &lfsr, sizeof(lfsr));
+      stat = fsr->FileSetId;
+      Dmsg2(200, "Found FileSet record: FileSetId=%d FileSet=%s\n", 
+           lfsr.FileSetId, lfsr.FileSet);
+      break;
+   }
+   if (!stat) {
+      strcpy(mdb->errmsg, "FileSet record not found.\n");
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+
+
+int db_get_file_attributes_record(B_DB *mdb, char *fname, FILE_DBR *fdbr) 
+{ return 0; }
+
+
+
+#endif /* HAVE_BACULA_DB */
diff --git a/bacula/src/cats/bdb_list.c b/bacula/src/cats/bdb_list.c
new file mode 100644 (file)
index 0000000..6cf9512
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Bacula Catalog Database List records interface routines
+ *
+ * Bacula Catalog Database routines written specifically
+ *  for Bacula.  Note, these routines are VERY dumb and
+ *  do not provide all the functionality of an SQL database.
+ *  The purpose of these routines is to ensure that Bacula
+ *  can limp along if no real database is loaded on the
+ *  system.
+ *   
+ *    Kern Sibbald, January MMI 
+ */
+
+/*
+   Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+#include "bdb.h"
+
+#ifdef HAVE_BACULA_DB
+
+/* Forward referenced functions */
+
+/* -----------------------------------------------------------------------
+ *
+ *   Bacula specific defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/* 
+ * Submit general SQL query
+ */
+int db_list_sql_query(B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, void *ctx)
+{
+   sendit(ctx, "SQL Queries not implemented with internal database.\n");
+   return 0;
+}
+
+
+/*
+ * List all the pool records
+ */
+void db_list_pool_records(B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx)
+{
+   int len;
+   POOL_DBR pr;
+
+   Dmsg0(90, "Enter list_pool_records\n");
+   P(mdb->mutex);
+   if (!bdb_open_pools_file(mdb)) {
+      V(mdb->mutex);
+      return;
+   }
+   sendit(ctx, "  PoolId NumVols MaxVols  Type       PoolName\n");
+   sendit(ctx, "===================================================\n");
+   fseek(mdb->poolfd, 0L, SEEK_SET);   /* rewind file */
+   len = sizeof(pr);
+   while (fread(&pr, len, 1, mdb->poolfd) > 0) {
+         Mmsg(&mdb->cmd, " %7d  %6d  %6d  %-10s %s\n",
+           pr.PoolId, pr.NumVols, pr.MaxVols, pr.PoolType, pr.Name);
+        sendit(ctx, mdb->cmd);
+   }
+   sendit(ctx, "===================================================\n");
+   V(mdb->mutex);
+   Dmsg0(90, "Leave list_pool_records\n");
+   return;
+}
+
+
+/*
+ * List Media records
+ */
+void db_list_media_records(B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, void *ctx)
+{
+   char ewc[30];
+   int len;
+   MEDIA_DBR mr;
+
+   P(mdb->mutex);
+   if (!bdb_open_media_file(mdb)) {
+      V(mdb->mutex);
+      return;
+   }
+   sendit(ctx, "  Status           VolBytes  MediaType        VolumeName\n");
+   sendit(ctx, "=============================================================\n");
+   fseek(mdb->mediafd, 0L, SEEK_SET);  /* rewind file */
+   len = sizeof(mr);
+   while (fread(&mr, len, 1, mdb->mediafd) > 0) {
+         Mmsg(&mdb->cmd, " %-10s %17s %-15s  %s\n",
+           mr.VolStatus, edit_uint_with_commas(mr.VolBytes, ewc),
+           mr.MediaType, mr.VolumeName);
+        sendit(ctx, mdb->cmd);
+   }
+   sendit(ctx, "====================================================================\n");
+   V(mdb->mutex);
+   return;
+}
+
+void db_list_jobmedia_records(B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit, void *ctx)
+{
+   JOBMEDIA_DBR jm;
+   MEDIA_DBR mr;
+   int jmlen, mrlen;
+
+   P(mdb->mutex);
+   if (!bdb_open_jobmedia_file(mdb)) {
+      V(mdb->mutex);
+      return;
+   }
+   if (!bdb_open_media_file(mdb)) {
+      V(mdb->mutex);
+      return;
+   }
+   sendit(ctx, "    JobId VolumeName    FirstIndex LastIndex\n");
+   sendit(ctx, "============================================\n");
+   jmlen = sizeof(jm);
+   mrlen = sizeof(mr);
+   fseek(mdb->jobmediafd, 0L, SEEK_SET); /* rewind the file */
+   while (fread(&jm, jmlen, 1, mdb->jobmediafd) > 0) {
+      /* List by JobId */
+      if (JobId != 0) {
+        if (jm.JobId == JobId) {
+           /* Now find VolumeName in corresponding Media record */
+           fseek(mdb->mediafd, 0L, SEEK_SET);
+           while (fread(&mr, mrlen, 1, mdb->mediafd) > 0) {
+              if (mr.MediaId == jm.MediaId) {
+                  Mmsg(&mdb->cmd, " %7d  %-10s %10d %10d\n",
+                      jm.JobId, mr.VolumeName, jm.FirstIndex, jm.LastIndex);
+                 sendit(ctx, mdb->cmd);
+                 break;
+              }
+           }
+        }
+      } else {
+        /* List all records */
+        fseek(mdb->mediafd, 0L, SEEK_SET);
+        while (fread(&mr, mrlen, 1, mdb->mediafd) > 0) {
+           if (mr.MediaId == jm.MediaId) {
+               Mmsg(&mdb->cmd, " %7d  %-10s %10d %10d\n",
+                   jm.JobId, mr.VolumeName, jm.FirstIndex, jm.LastIndex);
+              sendit(ctx, mdb->cmd);
+              break;
+           }
+        }
+      }
+   }
+
+   sendit(ctx, "============================================\n");
+   V(mdb->mutex);
+   return;
+}
+
+
+/*
+ * List Job records
+ */
+void db_list_job_records(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
+{
+   int jrlen;
+   JOB_DBR ojr;
+   int done = 0;
+   char ewc1[30], ewc2[30];
+   char dt[MAX_TIME_LENGTH];
+   struct tm tm;
+
+   P(mdb->mutex);
+   if (!bdb_open_jobs_file(mdb)) {
+      V(mdb->mutex);
+      return;
+   }
+   fseek(mdb->jobfd, 0L, SEEK_SET);   /* rewind file */
+   /* 
+    * Linear search through Job records
+    */
+   sendit(ctx, "   JobId   StartTime   Type Level         Bytes      Files Stat JobName\n");
+   sendit(ctx, "==========================================================================\n");
+   jrlen = sizeof(ojr);
+   while (!done && fread(&ojr, jrlen, 1, mdb->jobfd) > 0) {
+      if (jr->JobId != 0) {
+        if (jr->JobId == ojr.JobId) {
+           done = 1;
+        } else {
+           continue;
+        }
+      }
+      localtime_r(&ojr.StartTime, &tm);
+      strftime(dt, sizeof(dt), "%m-%d %H:%M", &tm);
+      Mmsg(&mdb->cmd, " %7d  %-10s   %c    %c   %14s %10s  %c  %s\n", 
+               ojr.JobId, dt, (char)ojr.Type, (char)ojr.Level, 
+               edit_uint_with_commas(ojr.JobBytes, ewc1), 
+               edit_uint_with_commas(ojr.JobFiles, ewc2),
+               (char)ojr.JobStatus, ojr.Name);
+      sendit(ctx, mdb->cmd);
+   }
+   sendit(ctx, "============================================================================\n");
+   V(mdb->mutex);
+   return;
+}
+
+
+/*
+ * List Job Totals
+ */
+void db_list_job_totals(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
+{
+   char ewc1[30], ewc2[30], ewc3[30];
+   int jrlen;
+   JOB_DBR ojr;
+   uint64_t total_bytes = 0;
+   uint64_t total_files = 0;
+   uint32_t total_jobs = 0;
+
+   P(mdb->mutex);
+   if (!bdb_open_jobs_file(mdb)) {
+      V(mdb->mutex);
+      return;
+   }
+   fseek(mdb->jobfd, 0L, SEEK_SET);   /* rewind file */
+   /* 
+    * Linear search through JobStart records
+    */
+   sendit(ctx, "   NumJobs   NumFiles          NumBytes\n");
+   sendit(ctx, "=======================================\n");
+   jrlen = sizeof(ojr);
+   while (fread(&ojr, jrlen, 1, mdb->jobfd) > 0) {
+      total_files += ojr.JobFiles;
+      total_bytes += ojr.JobBytes;
+      total_jobs++;
+   }
+   Mmsg(&mdb->cmd, " %7s  %10s   %15s\n", 
+            edit_uint_with_commas(total_jobs, ewc1),
+            edit_uint_with_commas(total_files, ewc2), 
+            edit_uint_with_commas(total_bytes, ewc3));
+   sendit(ctx, mdb->cmd);
+   sendit(ctx, "=======================================\n");
+   V(mdb->mutex);
+   return;
+}
+
+
+
+void db_list_files_for_job(B_DB *mdb, uint32_t jobid, DB_LIST_HANDLER *sendit, void *ctx) {}
+
+#endif /* HAVE_BACULA_DB */
diff --git a/bacula/src/cats/bdb_update.c b/bacula/src/cats/bdb_update.c
new file mode 100755 (executable)
index 0000000..e0eba75
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Bacula Catalog Database Update record interface routines
+ *
+ * Bacula Catalog Database routines written specifically
+ *  for Bacula.  Note, these routines are VERY dumb and
+ *  do not provide all the functionality of an SQL database.
+ *  The purpose of these routines is to ensure that Bacula
+ *  can limp along if no real database is loaded on the
+ *  system.
+ *   
+ *    Kern Sibbald, January MMI 
+ */
+
+/*
+   Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+#include "bdb.h"
+
+#ifdef HAVE_BACULA_DB
+
+/* Forward referenced functions */
+
+/* -----------------------------------------------------------------------
+ *
+ *   Bacula specific defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+
+/*
+ * This is called at Job start time to add the
+ * most current start fields to the job record.
+ * It is assumed that you did a db_create_job_record() already.
+ */
+int db_update_job_start_record(B_DB *mdb, JOB_DBR *jr)   
+{
+   int len, stat;
+   JOB_DBR ojr;
+
+   Dmsg0(200, "In db_update_job_start_record\n");
+   len = sizeof(ojr);
+   memcpy(&ojr, jr, len);
+
+   if (!db_get_job_record(mdb, &ojr)) {
+      return 0;
+   }
+
+   P(mdb->mutex);
+
+   fseek(mdb->jobfd, ojr.rec_addr, SEEK_SET);
+   if (fwrite(jr, len, 1, mdb->jobfd) != 1) {
+      Mmsg1(&mdb->errmsg, _("Error updating DB Job file. ERR=%s\n"), strerror(errno));
+      stat = 0;
+   }
+   fflush(mdb->jobfd);
+
+   V(mdb->mutex);
+   return stat;
+}
+
+/*
+ * This is called at Job termination time to add all the
+ * other fields to the job record.
+ */
+int db_update_job_end_record(B_DB *mdb, JOB_DBR *jr)   
+{
+   int len, stat;
+   JOB_DBR ojr;
+
+   Dmsg0(200, "In db_update_job_start_record\n");
+   len = sizeof(ojr);
+   memcpy(&ojr, jr, len);
+
+   if (!db_get_job_record(mdb, &ojr)) {
+      return 0;
+   }
+
+   P(mdb->mutex);
+
+   fseek(mdb->jobfd, ojr.rec_addr, SEEK_SET);
+   if (fwrite(jr, len, 1, mdb->jobfd) != 1) {
+      Mmsg1(&mdb->errmsg, _("Error updating DB Job file. ERR=%s\n"), strerror(errno));
+      stat = 0;
+   }
+   fflush(mdb->jobfd);
+
+   V(mdb->mutex);
+   return stat;
+}
+
+
+int db_update_media_record(B_DB *mdb, MEDIA_DBR *mr) 
+{ 
+   int stat = 1;
+   MEDIA_DBR omr;
+   int len;
+       
+   Dmsg0(200, "In db_update_media_record\n");
+   mr->MediaId = 0;
+   len = sizeof(omr);
+   memcpy(&omr, mr, len);
+
+   if (!db_get_media_record(mdb, &omr)) {
+      return 0;
+   }
+
+   P(mdb->mutex);
+
+   /* Don't allow some fields to change by copying from master record */
+   strcpy(mr->VolumeName, omr.VolumeName);
+   strcpy(mr->MediaType, omr.MediaType);
+   mr->MediaId = omr.MediaId;
+   mr->PoolId = omr.PoolId;
+   mr->VolMaxBytes = omr.VolMaxBytes;
+   mr->VolCapacityBytes = omr.VolCapacityBytes;
+   strcpy(mr->Recycle, omr.Recycle);
+
+   fseek(mdb->mediafd, omr.rec_addr, SEEK_SET);
+   if (fwrite(mr, len, 1, mdb->mediafd) != 1) {
+      Mmsg1(&mdb->errmsg, _("Error updating DB Media file. ERR=%s\n"), strerror(errno));
+      stat = 0;
+   }
+   fflush(mdb->mediafd);
+
+   V(mdb->mutex);
+   return stat;
+}
+
+int db_update_pool_record(B_DB *mdb, POOL_DBR *pr) 
+{ 
+   int stat = 1;
+   POOL_DBR opr;
+   int len;
+       
+   Dmsg0(200, "In db_update_pool_record\n");
+   len = sizeof(opr);
+   memcpy(&opr, pr, len);
+
+   if (!db_get_pool_record(mdb, &opr)) {
+      return 0;
+   }
+
+   P(mdb->mutex);
+
+   /* Update specific fields */
+   opr.NumVols = pr->NumVols;
+   opr.MaxVols = pr->MaxVols; 
+   opr.UseOnce = pr->UseOnce;
+   opr.UseCatalog = pr->UseCatalog;
+   opr.AcceptAnyVolume = pr->AcceptAnyVolume;
+   strcpy(opr.LabelFormat, pr->LabelFormat);
+
+   fseek(mdb->poolfd, opr.rec_addr, SEEK_SET);
+   if (fwrite(&opr, len, 1, mdb->poolfd) != 1) {
+      Mmsg1(&mdb->errmsg, _("Error updating DB Media file. ERR=%s\n"), strerror(errno));
+      stat = 0;
+   } else {
+      memcpy(pr, &opr, len);         /* return record written */
+   }
+   fflush(mdb->poolfd);
+
+   V(mdb->mutex);
+   return stat;
+}
+
+int db_add_MD5_to_file_record(B_DB *mdb, FileId_t FileId, char *MD5)   
+{
+   return 1;
+}
+
+int db_mark_file_record(B_DB *mdb, FileId_t FileId, int JobId) 
+{ 
+   return 1;
+}
+
+
+#endif /* HAVE_BACULA_DB */
diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h
new file mode 100644 (file)
index 0000000..55bfe85
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * SQL header file
+ *
+ *   Anyone who accesses the database will need to include
+ *   this file.
+ *
+ * This file contains definitions common to sql.c and
+ * the external world, and definitions destined only
+ * for the external world. This is control with
+ * the define __SQL_C, which is defined only in sql.c
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef __SQL_H_
+#define __SQL_H_ 1
+
+typedef void (DB_LIST_HANDLER)(void *, char *);
+typedef int (DB_RESULT_HANDLER)(void *, int, char **);
+#ifdef __SQL_C
+
+#ifdef HAVE_SQLITE
+
+#include <sqlite.h>
+
+/* Define opaque structure for sqlite */
+struct sqlite {
+   char dummy;
+};
+
+#define IS_NUM(x)             ((x) == 1)
+#define IS_NOT_NULL(x)        ((x) == 1)
+
+typedef struct s_sql_field {
+   char *name;                        /* name of column */
+   uint32_t length;                   /* length */
+   uint32_t max_length;               /* max length */
+   uint32_t type;                     /* type */
+   uint32_t flags;                    /* flags */
+} SQL_FIELD;
+
+/*
+ * This is the "real" definition that should only be
+ * used inside sql.c and associated database interface
+ * subroutines.
+ *                    S Q L I T E
+ */
+typedef struct s_db {
+   BQUEUE bq;                         /* queue control */
+   pthread_mutex_t mutex;
+   struct sqlite *db;
+   char **result;
+   int nrow;                          /* nrow returned from sqlite */
+   int ncolumn;                       /* ncolum returned from sqlite */
+   int num_rows;                      /* used by code */
+   int row;                           /* seek row */
+   int have_insert_id;                /* do not have insert id */
+   int fields_defined;                /* set when fields defined */
+   int field;                         /* seek field */
+   SQL_FIELD **fields;                /* defined fields */
+   int ref_count;
+   char *db_name;
+   char *db_user;
+   char *db_password;
+   int connected;
+   char *sqlite_errmsg;               /* error message returned by sqlite */
+   char *errmsg;                      /* nicely edited error message */
+   char *cmd;                         /* SQL command string */
+} B_DB;
+
+
+/* 
+ * "Generic" names for easier conversion   
+ *
+ *                    S Q L I T E
+ */
+#define sql_store_result(x)   x->result
+#define sql_free_result(x)    my_sqlite_free_table(x)
+#define sql_fetch_row(x)      my_sqlite_fetch_row(x)
+#define sql_query(x, y)       my_sqlite_query(x, y)
+#define sql_close(x)          sqlite_close(x->db)  
+#define sql_strerror(x)       x->sqlite_errmsg?x->sqlite_errmsg:"unknown"
+#define sql_num_rows(x)       x->nrow
+#define sql_data_seek(x, i)   x->row = i
+#define sql_affected_rows(x)  1
+#define sql_insert_id(x)      sqlite_last_insert_rowid(x->db)
+#define sql_field_seek(x, y)  my_sqlite_field_seek(x, y)
+#define sql_fetch_field(x)    my_sqlite_fetch_field(x)
+#define sql_num_fields(x)     (unsigned)((x)->ncolumn)
+#define SQL_ROW               char**   
+
+
+
+/* In cats/sqlite.c */
+extern int     my_sqlite_query(B_DB *mdb, char *cmd);
+extern SQL_ROW my_sqlite_fetch_row(B_DB *mdb);
+extern void my_sqlite_free_table(B_DB *mdb);
+
+#else
+
+#ifdef HAVE_MYSQL
+
+#include <mysql.h>
+
+/*
+ * This is the "real" definition that should only be
+ * used inside sql.c and associated database interface
+ * subroutines.
+ *
+ *                     M Y S Q L
+ */
+typedef struct s_db {
+   BQUEUE bq;                         /* queue control */
+   pthread_mutex_t mutex;
+   MYSQL mysql;
+   MYSQL *db;
+   MYSQL_RES *result;
+   my_ulonglong num_rows;
+   int ref_count;
+   char *db_name;
+   char *db_user;
+   char *db_password;
+   int have_insert_id;                /* do have insert_id() */
+   int connected;
+   char *errmsg;                      /* nicely edited error message */
+   char *cmd;                         /* SQL command string */
+} B_DB;
+
+
+/* "Generic" names for easier conversion */
+#define sql_store_result(x)   mysql_store_result(x->db)
+#define sql_free_result(x)    mysql_free_result(x->result)
+#define sql_fetch_row(x)      mysql_fetch_row(x->result)
+#define sql_query(x, y)       mysql_query(x->db, y)
+#define sql_close(x)          mysql_close(x->db)  
+#define sql_strerror(x)       mysql_error(x->db)
+#define sql_num_rows(x)       mysql_num_rows(x->result)
+#define sql_data_seek(x, i)   mysql_data_seek(x->result, i)
+#define sql_affected_rows(x)  mysql_affected_rows(x->db)
+#define sql_insert_id(x)      mysql_insert_id(x->db)
+#define sql_field_seek(x, y)  mysql_field_seek(x->result, y)
+#define sql_fetch_field(x)    mysql_fetch_field(x->result)
+#define sql_num_fields(x)     mysql_num_fields(x->result)
+#define SQL_ROW               MYSQL_ROW
+#define SQL_FIELD             MYSQL_FIELD
+
+#else  /* USE BACULA DB routines */
+
+#define HAVE_BACULA_DB 1
+
+/* Change this each time there is some incompatible
+ * file format change!!!!
+ */
+#define BDB_VERSION 7                 /* file version number */
+
+struct s_control {
+   int bdb_version;                   /* Version number */
+   uint32_t JobId;                    /* next Job Id */
+   uint32_t PoolId;                   /* next Pool Id */
+   uint32_t MediaId;                  /* next Media Id */
+   uint32_t JobMediaId;               /* next JobMedia Id */
+   uint32_t ClientId;                 /* next Client Id */
+   uint32_t FileSetId;                /* nest FileSet Id */
+   time_t time;                       /* time file written */
+};
+
+
+/* This is the REAL definition for using the
+ *  Bacula internal DB
+ */
+typedef struct s_db {
+   BQUEUE bq;                         /* queue control */
+   pthread_mutex_t mutex;             /* single thread lock */
+   int ref_count;                     /* number of times opened */
+   struct s_control control;          /* control file structure */
+   int cfd;                           /* control file device */
+   FILE *jobfd;                       /* Jobs records file descriptor */
+   FILE *poolfd;                      /* Pool records fd */
+   FILE *mediafd;                     /* Media records fd */
+   FILE *jobmediafd;                  /* JobMedia records fd */
+   FILE *clientfd;                    /* Client records fd */
+   FILE *filesetfd;                   /* FileSet records fd */
+   char *db_name;                     /* name of database */
+   char *errmsg;                      /* nicely edited error message */
+   char *cmd;                         /* Command string */
+} B_DB;
+
+#endif /* HAVE_MYSQL */
+#endif /* HAVE_SQLITE */
+
+/* Use for better error location printing */
+#define UPDATE_DB(db, cmd) UpdateDB(__FILE__, __LINE__, db, cmd)
+#define INSERT_DB(db, cmd) InsertDB(__FILE__, __LINE__, db, cmd)
+#define QUERY_DB(db, cmd) QueryDB(__FILE__, __LINE__, db, cmd)
+#define DELETE_DB(db, cmd) DeleteDB(__FILE__, __LINE__, db, cmd)
+
+
+#else    /* not __SQL_C */
+
+/* This is a "dummy" definition for use outside of sql.c
+ */
+typedef struct s_db {     
+   int dummy;                         /* for SunOS compiler */
+} B_DB;  
+
+#endif /*  __SQL_C */
+
+/* ***FIXME*** FileId_t should be uint64_t */
+typedef uint32_t FileId_t;
+typedef uint32_t DBId_t;              /* general DB id type */
+
+
+/* Job information passed to create job record and update
+ * job record at end of job. Note, although this record
+ * contains all the fields found in the Job database record,
+ * it also contains fields found in the JobMedia record.
+ */
+/* Job record */
+typedef struct {
+   uint32_t JobId;
+   char Job[MAX_NAME_LENGTH];         /* Job unique name */
+   char Name[MAX_NAME_LENGTH];        /* Job base name */
+   int Type;                          /* actually char(1) */
+   int Level;                         /* actually char(1) */
+   int JobStatus;                     /* actually char(1) */
+   uint32_t ClientId;                 /* Id of client */
+   uint32_t PoolId;                   /* Id of pool */
+   uint32_t FileSetId;                /* Id of FileSet */
+   time_t SchedTime;                  /* Time job scheduled */
+   time_t StartTime;                  /* Job start time */
+   time_t EndTime;                    /* Job termination time */
+   uint32_t VolSessionId;
+   uint32_t VolSessionTime;
+   uint32_t JobFiles;
+   uint32_t JobErrors;
+   uint32_t JobMissingFiles;
+   uint64_t JobBytes;
+
+   /* Note, FirstIndex, LastIndex, Start/End File and Block
+    * are only used in the JobMedia record.
+    */
+   uint32_t FirstIndex;               /* First index this Volume */
+   uint32_t LastIndex;                /* Last index this Volume */
+   uint32_t StartFile;
+   uint32_t EndFile;
+   uint32_t StartBlock;
+   uint32_t EndBlock;
+
+   char cSchedTime[MAX_NAME_LENGTH];
+   char cStartTime[MAX_NAME_LENGTH];
+   char cEndTime[MAX_NAME_LENGTH];
+   /* Extra stuff not in DB */
+   faddr_t rec_addr;
+} JOB_DBR;
+
+/* Job Media information used to create the media records
+ * for each Volume used for the job.
+ */
+/* JobMedia record */
+typedef struct {
+   uint32_t JobMediaId;               /* record id */
+   uint32_t JobId;                    /* JobId */
+   uint32_t MediaId;                  /* MediaId */
+   uint32_t FirstIndex;               /* First index this Volume */
+   uint32_t LastIndex;                /* Last index this Volume */
+   uint32_t StartFile;                /* File for start of data */
+   uint32_t EndFile;                  /* End file on Volume */
+   uint32_t StartBlock;               /* start block on tape */
+   uint32_t EndBlock;                 /* last block */
+} JOBMEDIA_DBR;
+
+
+
+
+/* Attributes record -- NOT same as in database because
+ *  in general, this "record" creates multiple database
+ *  records (e.g. pathname, filename, fileattributes).
+ */
+typedef struct {
+   char *fname;                       /* full path & filename */
+   char *link;                        /* link if any */
+   char *attr;                        /* attributes statp */
+   uint32_t FileIndex;
+   uint32_t Stream;
+   uint32_t JobId;
+   uint32_t ClientId;
+   uint32_t PathId;
+   uint32_t FilenameId;
+   FileId_t FileId;
+} ATTR_DBR;
+
+
+/* File record -- same format as database */
+typedef struct {
+   FileId_t FileId;
+   uint32_t FileIndex;
+   uint32_t JobId;
+   uint32_t FilenameId;
+   uint32_t PathId;
+   char LStat[256];
+/*   int Status; */
+   char MD5[50];
+} FILE_DBR;
+
+/* Pool record -- same format as database */
+typedef struct {
+   uint32_t PoolId;
+   char Name[MAX_NAME_LENGTH];        /* Pool name */
+   uint32_t NumVols;                  /* total number of volumes */
+   uint32_t MaxVols;                  /* max allowed volumes */
+   int UseOnce;                       /* set to use once only */
+   int UseCatalog;                    /* set to use catalog */
+   int AcceptAnyVolume;               /* set to accept any volume sequence */
+   char PoolType[MAX_NAME_LENGTH];             
+   char LabelFormat[MAX_NAME_LENGTH];
+   /* Extra stuff not in DB */
+   faddr_t rec_addr;
+} POOL_DBR;
+
+/* Media record -- same as the database */
+typedef struct {
+   uint32_t MediaId;                  /* Unique volume id */
+   char VolumeName[MAX_NAME_LENGTH];  /* Volume name */
+   char MediaType[MAX_NAME_LENGTH];   /* Media type */
+   uint32_t PoolId;                   /* Pool id */
+   time_t FirstWritten;               /* Time Volume first written */
+   time_t LastWritten;                /* Time Volume last written */
+   time_t LabelDate;                  /* Date/Time Volume labelled */
+   uint32_t VolJobs;                  /* number of jobs on this medium */
+   uint32_t VolFiles;                 /* Number of files */
+   uint32_t VolBlocks;                /* Number of blocks */
+   uint32_t VolMounts;                /* Number of times mounted */
+   uint32_t VolErrors;                /* Number of read/write errors */
+   uint32_t VolWrites;                /* Number of writes */
+   uint32_t VolReads;                 /* Number of reads */
+   uint64_t VolBytes;                 /* Number of bytes written */
+   uint64_t VolMaxBytes;              /* max bytes to write */
+   uint64_t VolCapacityBytes;         /* capacity estimate */
+   char VolStatus[20];                /* Volume status */
+   char Recycle[20];                  /* Recycle yes/no */
+   /* Extra stuff not in DB */
+   faddr_t rec_addr;                  /* found record address */
+} MEDIA_DBR;
+
+/* Client record -- same as the database */
+typedef struct {
+   uint32_t ClientId;                 /* Unique Client id */
+   char Name[MAX_NAME_LENGTH];        /* Client name */
+   char Uname[256];                   /* Uname for client */
+} CLIENT_DBR;
+
+/* FileSet record -- same as the database */
+typedef struct {
+   uint32_t FileSetId;                /* Unique FileSet id */
+   char FileSet[MAX_NAME_LENGTH];     /* FileSet name */
+   char MD5[50];                      /* MD5 signature of include/exclude */
+} FILESET_DBR;
+
+
+
+#include "protos.h"
+
+#include "jcr.h"
+
+#endif /* __SQL_H_ */
diff --git a/bacula/src/cats/create_mysql_database.in b/bacula/src/cats/create_mysql_database.in
new file mode 100644 (file)
index 0000000..f0bae06
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+#
+# shell script to create Bacula database(s)
+#
+
+bindir=@SQL_BINDIR@
+
+if $bindir/mysql -f <<END-OF-DATA
+CREATE DATABASE bacula;
+END-OF-DATA
+then
+   echo "Creation of bacula database succeeded."
+else
+   echo "Creation of bacula database failed."
+fi
+exit 0
diff --git a/bacula/src/cats/create_test_database b/bacula/src/cats/create_test_database
new file mode 100644 (file)
index 0000000..643acb5
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# shell script to create Bacula database(s)
+#
+
+bindir=~kern/mysql/bin
+
+if $bindir/mysql -f <<END-OF-DATA
+CREATE DATABASE baculatest;
+END-OF-DATA
+then
+   echo "Creation of baculatest database succeeded."
+else
+   echo "Creation of baculatest database failed."
+fi
+exit 0
diff --git a/bacula/src/cats/drop_mysql_tables.in b/bacula/src/cats/drop_mysql_tables.in
new file mode 100644 (file)
index 0000000..0dfaefb
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# shell script to delete Bacula tables
+
+bindir=@SQL_BINDIR@
+
+if $bindir/mysql <<END-OF-DATA
+USE bacula;
+DROP TABLE IF EXISTS Filename;
+DROP TABLE IF EXISTS Path;
+DROP TABLE IF EXISTS LongName;
+DROP TABLE IF EXISTS File;
+DROP TABLE IF EXISTS Client;
+DROP TABLE IF EXISTS Job;
+DROP TABLE IF EXISTS Media;
+DROP TABLE IF EXISTS JobMedia;
+DROP TABLE IF EXISTS Pool;
+DROP TABLE IF EXISTS MultiVolume;
+DROP TABLE IF EXISTS FileSave;  
+DROP TABLE IF EXISTS FileSet;  
+END-OF-DATA
+then
+   echo "Deletion of Bacula tables succeeded."
+else
+   echo "Deletion of Bacula tables failed."
+fi
+exit 0
diff --git a/bacula/src/cats/drop_test_tables b/bacula/src/cats/drop_test_tables
new file mode 100755 (executable)
index 0000000..0635563
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# shell script to delete Bacula tables for test database
+
+bindir=~kern/mysql/bin
+
+if $bindir/mysql <<END-OF-DATA
+USE baculatest;
+DROP TABLE IF EXISTS Filename;
+DROP TABLE IF EXISTS Path;
+DROP TABLE IF EXISTS LongName;
+DROP TABLE IF EXISTS File;
+DROP TABLE IF EXISTS Client;
+DROP TABLE IF EXISTS Job;
+DROP TABLE IF EXISTS Media;
+DROP TABLE IF EXISTS JobMedia;
+DROP TABLE IF EXISTS Pool;
+DROP TABLE IF EXISTS MultiVolume;
+DROP TABLE IF EXISTS FileSet;
+END-OF-DATA
+then
+   echo "Deletion of Baculatest tables succeeded."
+else
+   echo "Deletion of Baculatest tables failed."
+fi
+exit 0
diff --git a/bacula/src/cats/grant_mysql_privileges.in b/bacula/src/cats/grant_mysql_privileges.in
new file mode 100644 (file)
index 0000000..d66c884
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# shell script to create Bacula database(s)
+#
+
+bindir=@SQL_BINDIR@
+
+if $bindir/mysql -u root -f <<END-OF-DATA
+use mysql
+grant all privileges on *.* to kern@localhost with grant option;
+grant all privileges on *.* to kern@"%" with grant option;
+grant all privileges on *.* to kelvin@localhost with grant option;
+grant all privileges on *.* to kelvin@"%" with grant option;
+grant all privileges on *.* to bacula@localhost with grant option;
+grant all privileges on *.* to bacula@"%" with grant option;
+select * from user;
+flush privileges;
+END-OF-DATA
+then
+   echo "Privileges for kern, kelvin, and bacula granted."
+   exit 0
+else
+   echo "Error creating privileges."
+   exit 1
+fi
diff --git a/bacula/src/cats/grant_privileges b/bacula/src/cats/grant_privileges
new file mode 100644 (file)
index 0000000..4150a17
--- /dev/null
@@ -0,0 +1,10 @@
+use mysql
+grant all privileges on *.* to kern@localhost with grant option;
+grant all privileges on *.* to kern@"%" with grant option;
+grant all privileges on *.* to kelvin@localhost with grant option;
+grant all privileges on *.* to kelvin@"%" with grant option;
+grant all privileges on *.* to bacula@localhost with grant option;
+grant all privileges on *.* to bacula@"%" with grant option;
+select * from user;
+flush privileges;
+exit
diff --git a/bacula/src/cats/make_mysql_tables.in b/bacula/src/cats/make_mysql_tables.in
new file mode 100644 (file)
index 0000000..0ffb178
--- /dev/null
@@ -0,0 +1,151 @@
+#!/bin/sh
+#
+# shell script to create Bacula tables
+
+bindir=@SQL_BINDIR@
+
+if $bindir/mysql -f <<END-OF-DATA
+USE bacula;
+CREATE TABLE Filename (
+  FilenameId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+  Name BLOB NOT NULL,
+  PRIMARY KEY(FilenameId),
+  INDEX (Name(30))
+  );
+
+CREATE TABLE Path (
+   PathId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   Path BLOB NOT NULL,
+   PRIMARY KEY(PathId),
+   INDEX (Path(50))
+   );
+
+
+# ****FIXME**** make FileId BIGINT *****
+CREATE TABLE File (
+   FileId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   FileIndex INTEGER UNSIGNED NOT NULL,
+   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+   PathId INTEGER UNSIGNED NOT NULL REFERENCES Path,
+   FilenameId INTEGER NOT NULL REFERENCES Filename,
+   LStat TINYBLOB NOT NULL,
+   MD5 TINYBLOB NOT NULL,
+   PRIMARY KEY(FileId),
+   INDEX (JobId),
+   INDEX (PathId),
+   INDEX (FilenameId)
+   );
+
+
+CREATE TABLE Job (
+   JobId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   Job TINYBLOB NOT NULL,
+   Name TINYBLOB NOT NULL,
+   PurgedFiles TINYINT NOT NULL DEFAULT 0,
+   Type BINARY(1) NOT NULL,
+   Level BINARY(1) NOT NULL,
+   ClientId INTEGER NOT NULL REFERENCES Client,
+   JobStatus BINARY(1) NOT NULL,
+   SchedTime DATETIME NOT NULL,
+   StartTime DATETIME NOT NULL,
+   EndTime DATETIME NOT NULL,
+   StartDay INTEGER UNSIGNED NOT NULL,
+   VolSessionId INTEGER UNSIGNED NOT NULL,
+   VolSessionTime INTEGER UNSIGNED NOT NULL,
+   JobFiles INTEGER UNSIGNED NOT NULL,
+   JobBytes BIGINT UNSIGNED NOT NULL,
+   JobErrors INTEGER UNSIGNED NOT NULL,
+   JobMissingFiles INTEGER UNSIGNED NOT NULL,
+   PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool,
+   FileSetId INTEGER UNSIGNED NOT NULL REFERENCES FileSet,
+   PRIMARY KEY(JobId),
+   INDEX (Name(128))
+   );
+
+# 
+CREATE TABLE FileSet (
+   FileSetId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   FileSet TINYBLOB NOT NULL,
+   MD5 TINYBLOB NOT NULL,
+   PRIMARY KEY(FileSetId)
+   );
+
+CREATE TABLE JobMedia (
+   JobMediaId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+   MediaId INTEGER UNSIGNED NOT NULL REFERENCES Media,
+   FirstIndex INTEGER UNSIGNED NOT NULL,
+   LastIndex INTEGER UNSIGNED NOT NULL,
+   StartFile INTEGER UNSIGNED NOT NULL,
+   EndFile INTEGER UNSIGNED NOT NULL,
+   StartBlock INTEGER UNSIGNED NOT NULL,
+   EndBlock INTEGER UNSIGNED NOT NULL,
+   PRIMARY KEY(JobMediaId),
+   INDEX (JobId, MediaId)
+   );
+
+
+CREATE TABLE Media (
+   MediaId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   VolumeName TINYBLOB NOT NULL,
+   PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool,
+   MediaType TINYBLOB NOT NULL,
+   FirstWritten DATETIME NOT NULL,
+   LastWritten DATETIME NOT NULL,
+   LabelDate DATETIME NOT NULL,
+   VolJobs INTEGER UNSIGNED NOT NULL,
+   VolFiles INTEGER UNSIGNED NOT NULL,
+   VolBlocks INTEGER UNSIGNED NOT NULL,
+   VolMounts INTEGER UNSIGNED NOT NULL,
+   VolBytes BIGINT UNSIGNED NOT NULL,
+   VolErrors INTEGER UNSIGNED NOT NULL,
+   VolWrites INTEGER UNSIGNED NOT NULL,
+   VolMaxBytes BIGINT UNSIGNED NOT NULL,
+   VolCapacityBytes BIGINT UNSIGNED NOT NULL,
+   VolStatus ENUM('Full', 'Archive', 'Append', 'Recycle', 
+    'Read-Only', 'Disabled', 'Error', 'Busy') NOT NULL,
+   Recycle ENUM('No', 'Yes') NOT NULL,
+   PRIMARY KEY(MediaId),
+   INDEX (PoolId)
+   );
+
+CREATE TABLE Pool (
+   PoolId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   Name TINYBLOB NOT NULL,
+   NumVols INTEGER UNSIGNED NOT NULL,
+   MaxVols INTEGER UNSIGNED NOT NULL,
+   UseOnce TINYINT NOT NULL,
+   UseCatalog TINYINT NOT NULL,
+   AcceptAnyVolume TINYINT NOT NULL,
+   PoolType ENUM('Backup', 'Copy', 'Cloned', 'Archive', 'Migration') NOT NULL,
+   LabelFormat TINYBLOB,
+   UNIQUE (Name(128)),
+   PRIMARY KEY (PoolId)
+   );
+
+
+CREATE TABLE Client (
+   ClientId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   Name TINYBLOB NOT NULL,
+   Uname TINYBLOB NOT NULL,      /* full uname -a of client */
+   UNIQUE (Name(128)),
+   PRIMARY KEY(ClientId)
+   );
+
+## Experimental
+#CREATE TABLE FileSave (
+#   FileSaveId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+#   FileIndex INTEGER UNSIGNED NOT NULL,
+#   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+#   FileId INTEGER UNSIGNED NOT NULL REFERENCES File,
+#   VLStat TINYBLOB NOT NULL,
+#   PRIMARY KEY(FileSaveId),
+#   );
+
+END-OF-DATA
+then
+   echo "Creation of Bacula tables succeeded."
+else
+   echo "Creation of Bacula tables failed."
+fi
+exit 0
diff --git a/bacula/src/cats/make_sqlite_tables.in b/bacula/src/cats/make_sqlite_tables.in
new file mode 100644 (file)
index 0000000..f811e69
--- /dev/null
@@ -0,0 +1,153 @@
+#!/bin/sh
+#
+# shell script to create Bacula tables
+
+bindir=@SQL_BINDIR@
+cd @working_dir@
+
+$bindir/sqlite bacula.db <<END-OF-DATA
+CREATE TABLE Filename (
+  FilenameId INTEGER UNSIGNED AUTOINCREMENT,
+  Name TEXT DEFAULT "",
+  PRIMARY KEY(FilenameId) 
+  );
+
+CREATE TABLE Path (
+   PathId INTEGER UNSIGNED AUTOINCREMENT,
+   Path TEXT DEFAULT "",
+   PRIMARY KEY(PathId) 
+   );
+
+
+CREATE TABLE File (
+   FileId INTEGER UNSIGNED AUTOINCREMENT,
+   FileIndex INTEGER UNSIGNED NOT NULL,
+   JobId INTEGER UNSIGNED REFERENCES Job NOT NULL,
+   PathId INTEGER UNSIGNED REFERENCES Path NOT NULL,
+   FilenameId INTEGER REFERENCES Filename NOT NULL,
+   LStat VARCHAR(255) NOT NULL,
+   MD5 VARCHAR(25) NOT NULL,
+   PRIMARY KEY(FileId) 
+   );
+
+CREATE TABLE Job (
+   JobId INTEGER UNSIGNED NOT NULL,
+   Job VARCHAR(128) NOT NULL,
+   Name VARCHAR(128) NOT NULL,
+   PurgedFiles TINYINT DEFAULT 0,
+   Type CHAR NOT NULL,
+   Level CHAR NOT NULL,
+   ClientId INTEGER REFERENCES Client DEFAULT 0,
+   JobStatus CHAR,
+   SchedTime DATETIME NOT NULL,
+   StartTime DATETIME DEFAULT 0,
+   EndTime DATETIME DEFAULT 0,
+   StartDay INTEGER UNSIGNED DEFAULT 0,
+   VolSessionId INTEGER UNSIGNED DEFAULT 0,
+   VolSessionTime INTEGER UNSIGNED DEFAULT 0,
+   JobFiles INTEGER UNSIGNED DEFAULT 0,
+   JobBytes BIGINT UNSIGNED DEFAULT 0,
+   JobErrors INTEGER UNSIGNED DEFAULT 0,
+   JobMissingFiles INTEGER UNSIGNED DEFAULT 0,
+   PoolId INTEGER UNSIGNED REFERENCES Pool DEFAULT 0,
+   FileSetId INTEGER UNSIGNED REFERENCES FileSet DEFAULT 0,
+   PRIMARY KEY(JobId) 
+   );
+
+CREATE TABLE FileSet (
+   FileSetId INTEGER UNSIGNED AUTOINCREMENT,
+   FileSet VARCHAR(128) NOT NULL,
+   MD5 VARCHAR(25) NOT NULL,
+   PRIMARY KEY(FileSetId)
+   );
+
+CREATE TABLE JobMedia (
+   JobMediaId INTEGER UNSIGNED AUTOINCREMENT,
+   JobId INTEGER UNSIGNED REFERENCES Job NOT NULL,
+   MediaId INTEGER UNSIGNED REFERENCES Media NOT NULL,
+   FirstIndex INTEGER UNSIGNED NOT NULL,
+   LastIndex INTEGER UNSIGNED NOT NULL,
+   StartFile INTEGER UNSIGNED DEFAULT 0,
+   EndFile INTEGER UNSIGNED DEFAULT 0,
+   StartBlock INTEGER UNSIGNED DEFAULT 0,
+   EndBlock INTEGER UNSIGNED DEFAULT 0,
+   PRIMARY KEY(JobMediaId) 
+   );
+
+
+CREATE TABLE Media (
+   MediaId INTEGER UNSIGNED AUTOINCREMENT,
+   VolumeName VARCHAR(128) NOT NULL,
+   PoolId INTEGER UNSIGNED REFERENCES Pool NOT NULL,
+   MediaType VARCHAR(128) NOT NULL,
+   FirstWritten DATETIME DEFAULT 0,
+   LastWritten DATETIME DEFAULT 0,
+   LabelDate DATETIME DEFAULT 0,
+   VolJobs INTEGER UNSIGNED DEFAULT 0,
+   VolFiles INTEGER UNSIGNED DEFAULT 0,
+   VolBlocks INTEGER UNSIGNED DEFAULT 0,
+   VolMounts INTEGER UNSIGNED DEFAULT 0,
+   VolBytes BIGINT UNSIGNED DEFAULT 0,
+   VolErrors INTEGER UNSIGNED DEFAULT 0,
+   VolWrites INTEGER UNSIGNED DEFAULT 0,
+   VolMaxBytes BIGINT UNSIGNED DEFAULT 0,
+   VolCapacityBytes BIGINT UNSIGNED DEFAULT 0,
+   VolStatus VARCHAR(20) NOT NULL,
+   Recycle VARCHAR(20) NOT NULL,
+   PRIMARY KEY(MediaId)
+   );
+
+CREATE TABLE Pool (
+   PoolId INTEGER UNSIGNED AUTOINCREMENT,
+   Name VARCHAR(128) NOT NULL,
+   NumVols INTEGER UNSIGNED NOT NULL,
+   MaxVols INTEGER UNSIGNED NOT NULL,
+   UseOnce TINYINT NOT NULL,
+   UseCatalog TINYINT NOT NULL,
+   AcceptAnyVolume TINYINT NOT NULL,
+   PoolType VARCHAR(20) NOT NULL,
+   LabelFormat VARCHAR(128) NOT NULL,
+   UNIQUE (Name),
+   PRIMARY KEY (PoolId)
+   );
+
+
+CREATE TABLE Client (
+   ClientId INTEGER UNSIGNED AUTOINCREMENT,
+   Name VARCHAR(128) NOT NULL,
+   Uname VARCHAR(255) NOT NULL,   -- uname -a field
+   UNIQUE (Name),
+   PRIMARY KEY(ClientId)
+   );
+
+CREATE TABLE NextId (
+   id INTEGER UNSIGNED DEFAULT 0,
+   TableName TEXT NOT NULL,
+   PRIMARY KEY (TableName)
+   );
+
+-- Initialize JobId to start at 1
+INSERT INTO NextId (id, TableName) VALUES (1, "Job");
+
+-- Experimental stuff below. Not used.
+-- Invariant part of File
+CREATE TABLE BaseFile (
+   FileId INTEGER UNSIGNED AUTOINCREMENT,
+   PathId INTEGER UNSIGNED REFERENCES Path NOT NULL,
+   FilenameId INTEGER REFERENCES Filename NOT NULL,
+   LStat VARCHAR(255) NOT NULL,
+   MD5 VARCHAR(25) NOT NULL,
+   PRIMARY KEY(FileId) 
+   );
+
+-- Variable part of File
+CREATE TABLE FileSave (
+   FileId INTEGER UNSIGNED REFERENCES BaseFile NOT NULL,
+   FileIndex INTEGER UNSIGNED NOT NULL,
+   JobId INTEGER UNSIGNED REFERENCES Job NOT NULL,
+   PRIMARY KEY(FileId) 
+   );
+
+
+END-OF-DATA
+exit 0
diff --git a/bacula/src/cats/make_test_tables b/bacula/src/cats/make_test_tables
new file mode 100755 (executable)
index 0000000..9dd0fa5
--- /dev/null
@@ -0,0 +1,152 @@
+#!/bin/sh
+#
+# shell script to create Bacula Developer Test tables
+
+bindir=$HOME/mysql/bin
+
+if $bindir/mysql -f <<END-OF-DATA
+USE baculatest;
+CREATE TABLE Filename (
+  FilenameId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+  Name VARCHAR(255) NOT NULL,
+  PRIMARY KEY(FilenameId),
+  INDEX (Name(30))
+  );
+
+CREATE TABLE Path (
+   PathId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   Path VARCHAR(255) NOT NULL,
+   PRIMARY KEY(PathId),
+   INDEX (Path(50))
+   );
+
+
+CREATE TABLE File (
+   FileId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   FileIndex INTEGER UNSIGNED NOT NULL,
+   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+   PathId INTEGER UNSIGNED NOT NULL REFERENCES Path,
+   FilenameId INTEGER NOT NULL REFERENCES Filename,
+   LStat VARCHAR(255) NOT NULL,
+   MD5 VARCHAR(25) NOT NULL,
+   PRIMARY KEY(FileId),
+   INDEX (FilenameId, PathId)
+   );
+
+
+CREATE TABLE Job (
+   JobId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   Name VARCHAR(127) NOT NULL,
+   Class CHAR NOT NULL,
+   Type CHAR NOT NULL,
+   Level CHAR NOT NULL,
+   ClientId INTEGER NOT NULL REFERENCES Client,
+   JobStatus CHAR NOT NULL,
+   SchedTime DATETIME NOT NULL,
+   StartTime DATETIME NOT NULL,
+   EndTime DATETIME NOT NULL,
+   VolSessionId INTEGER UNSIGNED NOT NULL,
+   VolSessionTime INTEGER UNSIGNED NOT NULL,
+   JobFiles INTEGER UNSIGNED NOT NULL,
+   JobBytes BIGINT UNSIGNED NOT NULL,
+   JobErrors INTEGER UNSIGNED NOT NULL,
+   JobMissingFiles INTEGER UNSIGNED NOT NULL,
+   PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool,
+   FileSetId INTEGER UNSIGNED NOT NULL REFERENCES FileSet,
+   PRIMARY KEY(JobId),
+   INDEX (Name)
+   );
+
+# 
+CREATE TABLE FileSet (
+   FileSetId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   FileSet VARCHAR(127), 
+   MD5 VARCHAR(25),
+   PRIMARY KEY(FileSetId)
+   );
+
+CREATE TABLE JobMedia (
+   JobMediaId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+   MediaId INTEGER UNSIGNED NOT NULL REFERENCES Media,
+   FirstIndex INTEGER UNSIGNED NOT NULL,
+   LastIndex INTEGER UNSIGNED NOT NULL,
+   StartFile INTEGER UNSIGNED NOT NULL,
+   EndFile INTEGER UNSIGNED NOT NULL,
+   StartBlock INTEGER UNSIGNED NOT NULL,
+   EndBlock INTEGER UNSIGNED NOT NULL,
+   PRIMARY KEY(JobMediaId),
+   INDEX (JobId, MediaId)
+   );
+
+
+CREATE TABLE Media (
+   MediaId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   VolumeName VARCHAR(127) NOT NULL,
+   PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool,
+   MediaType VARCHAR(127),
+   FirstWritten DATETIME NOT NULL,
+   LastWritten DATETIME NOT NULL,
+   LabelDate DATETIME NOT NULL,
+   VolJobs INTEGER UNSIGNED NOT NULL,
+   VolFiles INTEGER UNSIGNED NOT NULL,
+   VolBlocks INTEGER UNSIGNED NOT NULL,
+   VolMounts INTEGER UNSIGNED NOT NULL,
+   VolBytes BIGINT UNSIGNED NOT NULL,
+   VolErrors INTEGER UNSIGNED NOT NULL,
+   VolWrites INTEGER UNSIGNED NOT NULL,
+   VolMaxBytes BIGINT UNSIGNED NOT NULL,
+   VolCapacityBytes BIGINT UNSIGNED NOT NULL,
+   VolStatus ENUM('Full', 'Archive', 'Append', 'Recycle', 'Read-Only', 'Disabled') NOT NULL,
+   Recycle ENUM('No', 'Yes') Not NULL,
+   PRIMARY KEY(MediaId),
+   INDEX (PoolId)
+   );
+
+CREATE TABLE Pool (
+   PoolId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   Name VARCHAR(127) NOT NULL,
+   NumVols INTEGER UNSIGNED NOT NULL,
+   MaxVols INTEGER UNSIGNED NOT NULL,
+   UseOnce TINYINT NOT NULL,
+   UseCatalog TINYINT NOT NULL,
+   AcceptAnyVolume TINYINT NOT NULL,
+   PoolType ENUM('Backup', 'Copy', 'Cloned', 'Archive', 'Migration') NOT NULL,
+   LabelFormat VARCHAR(127),
+   UNIQUE (Name),
+   PRIMARY KEY (PoolId)
+   );
+
+
+CREATE TABLE Client (
+   ClientId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+   Name VARCHAR(127) NOT NULL,
+   Uname VARCHAR(255) NOT NULL,       /* full uname -a of client */
+   UNIQUE (Name),
+   PRIMARY KEY(ClientId)
+   );
+
+## Experimental
+#CREATE TABLE FileSave (
+#   FileSaveId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+#   FileIndex INTEGER UNSIGNED NOT NULL,
+#   JobId INTEGER UNSIGNED NOT NULL REFERENCES Job,
+#   FileId INTEGER UNSIGNED NOT NULL REFERENCES File,
+#   VLStat VARCHAR(255) NOT NULL,
+#   PRIMARY KEY(FileSaveId),
+#   );
+
+#CREATE TABLE LongName (
+#   LongNameId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+#   Name TEXT NOT NULL,
+#   PRIMARY KEY (LongNameId)
+#   );
+
+       
+END-OF-DATA
+then
+   echo "Creation of Baculatest tables succeeded."
+else
+   echo "Creation of Baculatest tables failed."
+fi
+exit 0
diff --git a/bacula/src/cats/mysql.c b/bacula/src/cats/mysql.c
new file mode 100644 (file)
index 0000000..f420b21
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Bacula Catalog Database routines specific to MySQL
+ *   These are MySQL specific routines -- hopefully all
+ *    other files are generic.
+ *
+ *    Kern Sibbald, March 2000
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#ifdef HAVE_MYSQL
+
+/* -----------------------------------------------------------------------
+ *
+ *   MySQL dependent defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/* List of open databases */
+static BQUEUE db_list = {&db_list, &db_list};
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Initialize database data structure. In principal this should
+ * never have errors, or it is really fatal.
+ */
+B_DB *
+db_init_database(char *db_name, char *db_user, char *db_password)
+{
+   B_DB *mdb;
+
+   P(mutex);                         /* lock DB queue */
+   /* Look to see if DB already open */
+   for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
+      if (strcmp(mdb->db_name, db_name) == 0) {
+         Dmsg2(100, "DB REopen %d %s\n", mdb->ref_count, db_name);
+        mdb->ref_count++;
+        V(mutex);
+        return mdb;                  /* already open */
+      }
+   }
+   Dmsg0(100, "db_open first time\n");
+   mdb = (B_DB *) malloc(sizeof(B_DB));
+   memset(mdb, 0, sizeof(B_DB));
+   mdb->db_name = bstrdup(db_name);
+   mdb->db_user = bstrdup(db_user);
+   mdb->db_password = bstrdup(db_password);
+   mdb->have_insert_id = TRUE;
+   mdb->errmsg = (char *) get_pool_memory(PM_EMSG); /* get error message buffer */
+   *mdb->errmsg = 0;
+   mdb->cmd = (char *) get_pool_memory(PM_EMSG);    /* get command buffer */
+   mdb->ref_count = 1;
+   qinsert(&db_list, &mdb->bq);           /* put db in list */
+   V(mutex);
+   return mdb;
+}
+
+/*
+ * Now actually open the database.  This can generate errors,
+ * which are returned in the errmsg
+ */
+int
+db_open_database(B_DB *mdb)
+{
+   P(mutex);
+   if (mdb->connected) {
+      V(mutex);
+      return 1;
+   }
+   mdb->connected = FALSE;
+   if (pthread_mutex_init(&mdb->mutex, NULL) != 0) {
+      Mmsg1(&mdb->errmsg, "Unable to initialize DB mutex. ERR=%s\n", strerror(errno));
+      V(mutex);
+      return 0;
+   }
+
+   /* connect to the database */
+   mysql_init(&(mdb->mysql));
+   Dmsg0(50, "mysql_init done\n");
+   mdb->db = mysql_real_connect(
+       &(mdb->mysql),                /* db */
+       NULL,                         /* default = localhost */
+       mdb->db_user,                 /*  login name */
+       mdb->db_password,             /*  password */
+       mdb->db_name,                 /* database name */
+       0,                            /* default port */
+       NULL,                         /* default = socket */
+       0);                           /* flags = none */
+
+   /* If no connect, try once more incase it is a timing problem */
+   if (mdb->db == NULL) {
+      mdb->db = mysql_real_connect(
+          &(mdb->mysql),                /* db */
+          NULL,                         /* default = localhost */
+          mdb->db_user,                 /*  login name */
+          mdb->db_password,             /*  password */
+          mdb->db_name,                 /* database name */
+          0,                            /* default port */
+          NULL,                         /* default = socket */
+          0);                           /* flags = none */
+   }
+    
+   Dmsg0(50, "mysql_real_connect done\n");
+   Dmsg3(50, "db_user=%s db_name=%s db_password=%s\n", mdb->db_user, mdb->db_name, 
+            mdb->db_password==NULL?"(NULL)":mdb->db_password);
+  
+   if (mdb->db == NULL) {
+      Mmsg2(&mdb->errmsg, _("Unable to connect to MySQL server. \n\
+Database=%s User=%s\n\
+It is probably not running or your password is incorrect.\n"), 
+        mdb->db_name, mdb->db_user);
+      V(mutex);
+      return 0;
+   }
+   mdb->connected = TRUE;
+   V(mutex);
+   return 1;
+}
+
+void
+db_close_database(B_DB *mdb)
+{
+   P(mutex);
+   mdb->ref_count--;
+   if (mdb->ref_count == 0) {
+      qdchain(&mdb->bq);
+      if (mdb->connected && mdb->db) {
+        sql_close(mdb);
+      }
+      pthread_mutex_destroy(&mdb->mutex);
+      free_pool_memory(mdb->errmsg);
+      free_pool_memory(mdb->cmd);
+      if (mdb->db_name) {
+        free(mdb->db_name);
+      }
+      if (mdb->db_user) {
+        free(mdb->db_user);
+      }
+      if (mdb->db_password) {
+        free(mdb->db_password);
+      }
+      free(mdb);
+   }
+   V(mutex);
+}
+
+/*
+ * Return the next unique index (auto-increment) for
+ * the given table.  Return NULL on error.
+ *  
+ * For MySQL, NULL causes the auto-increment value
+ *  to be updated.
+ */
+char *db_next_index(B_DB *mdb, char *table)
+{
+   return "NULL";
+}   
+
+
+
+void
+db_escape_string(char *snew, char *old, int len)
+{
+   mysql_escape_string(snew, old, len);
+}
+
+/*
+ * Submit a general SQL command (cmd), and for each row returned,
+ *  the sqlite_handler is called with the ctx.
+ */
+int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
+{
+   SQL_ROW row;
+  
+   P(mdb->mutex);
+   if (sql_query(mdb, query) != 0) {
+      Mmsg(&mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror(mdb));
+      V(mdb->mutex);
+      return 0;
+   }
+   if (result_handler != NULL) {
+      if ((mdb->result = sql_store_result(mdb)) != NULL) {
+        int num_fields = sql_num_fields(mdb);
+
+        while ((row = sql_fetch_row(mdb)) != NULL) {
+           if (result_handler(ctx, num_fields, row))
+              break;
+        }
+
+        sql_free_result(mdb);
+      }
+   }
+   V(mdb->mutex);
+   return 1;
+
+}
+
+
+static void
+list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
+{
+   SQL_FIELD  *field;
+   unsigned int i, j;
+
+   sql_field_seek(mdb, 0);
+   send(ctx, "+");
+   for (i = 0; i < sql_num_fields(mdb); i++) {
+      field = sql_fetch_field(mdb);
+      for (j = 0; j < field->max_length + 2; j++)
+              send(ctx, "-");
+      send(ctx, "+");
+   }
+   send(ctx, "\n");
+}
+
+void
+list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
+{
+   SQL_FIELD *field;
+   SQL_ROW    row;
+   unsigned int i, col_len;
+   char buf[2000], ewc[30];
+
+   if (mdb->result == NULL) {
+      return;
+   }
+   /* determine column display widths */
+   sql_field_seek(mdb, 0);
+   for (i = 0; i < sql_num_fields(mdb); i++) {
+      field = sql_fetch_field(mdb);
+      if (IS_NUM(field->type) && field->max_length > 0) { /* fixup for commas */
+        field->max_length += (field->max_length - 1) / 3;
+      }
+      col_len = strlen(field->name);
+      if (col_len < field->max_length)
+             col_len = field->max_length;
+      if (col_len < 4 && !IS_NOT_NULL(field->flags))
+              col_len = 4;    /* 4 = length of the word "NULL" */
+      field->max_length = col_len;    /* reset column info */
+   }
+
+   list_dashes(mdb, send, ctx);
+   send(ctx, "|");
+   sql_field_seek(mdb, 0);
+   for (i = 0; i < sql_num_fields(mdb); i++) {
+      field = sql_fetch_field(mdb);
+      sprintf(buf, " %-*s |", field->max_length, field->name);
+      send(ctx, buf);
+   }
+   send(ctx, "\n");
+   list_dashes(mdb, send, ctx);
+
+   while ((row = sql_fetch_row(mdb)) != NULL) {
+      sql_field_seek(mdb, 0);
+      send(ctx, "|");
+      for (i = 0; i < sql_num_fields(mdb); i++) {
+        field = sql_fetch_field(mdb);
+        if (row[i] == NULL) {
+            sprintf(buf, " %-*s |", field->max_length, "NULL");
+        } else if (IS_NUM(field->type)) {
+            sprintf(buf, " %*s |", field->max_length,       
+              add_commas(row[i], ewc));
+        } else {
+            sprintf(buf, " %-*s |", field->max_length, row[i]);
+        }
+        send(ctx, buf);
+      }
+      send(ctx, "\n");
+   }
+   list_dashes(mdb, send, ctx);
+}
+
+
+#endif /* HAVE_MYSQL */
diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h
new file mode 100644 (file)
index 0000000..59335b2
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef __SQL_PROTOS_H
+#define __SQL_PROTOS_H
+
+#include "cats.h"
+
+/* Database prototypes */
+
+/* sql.c */
+B_DB *db_init_database(char *db_name, char *db_user, char *db_password);
+int db_open_database(B_DB *db);
+void db_close_database(B_DB *db);
+void db_escape_string(char *snew, char *old, int len);
+char *db_strerror(B_DB *mdb);
+int get_sql_record_max(B_DB *mdb);
+char *db_next_index(B_DB *mdb, char *table);
+int db_sql_query(B_DB *mdb, char *cmd, DB_RESULT_HANDLER *result_handler, void *ctx);
+
+/* create.c */
+int db_create_file_attributes_record(B_DB *mdb, ATTR_DBR *ar);
+int db_create_job_record(B_DB *db, JOB_DBR *jr);
+int db_create_media_record(B_DB *db, MEDIA_DBR *media_dbr);
+int db_create_client_record(B_DB *db, CLIENT_DBR *cr);
+int db_create_fileset_record(B_DB *db, FILESET_DBR *fsr);
+int db_create_pool_record(B_DB *db, POOL_DBR *pool_dbr);
+int db_create_jobmedia_record(B_DB *mdb, JOBMEDIA_DBR *jr);
+
+/* delete.c */
+int db_delete_pool_record(B_DB *db, POOL_DBR *pool_dbr);
+int db_delete_media_record(B_DB *mdb, MEDIA_DBR *mr);
+
+/* find.c */
+int db_find_job_start_time(B_DB *mdb, JOB_DBR *jr, char *stime);
+int db_find_last_full_verify(B_DB *mdb, JOB_DBR *jr);
+int db_find_next_volume(B_DB *mdb, int index, MEDIA_DBR *mr);
+
+/* get.c */
+int db_get_pool_record(B_DB *db, POOL_DBR *pdbr);
+int db_get_client_record(B_DB *mdb, CLIENT_DBR *cr);
+int db_get_job_record(B_DB *mdb, JOB_DBR *jr);
+int db_get_job_volume_names(B_DB *mdb, uint32_t JobId, char *VolumeNames);
+int db_get_file_attributes_record(B_DB *mdb, char *fname, FILE_DBR *fdbr);
+int db_get_fileset_record(B_DB *mdb, FILESET_DBR *fsr);
+int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr);
+int db_get_num_media_records(B_DB *mdb);
+int db_get_num_pool_records(B_DB *mdb);
+int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t **ids);
+int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t **ids);
+
+
+/* list.c */
+void db_list_pool_records(B_DB *db, DB_LIST_HANDLER sendit, void *ctx);
+void db_list_job_records(B_DB *db, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx);
+void db_list_job_totals(B_DB *db, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx);
+void db_list_files_for_job(B_DB *db, uint32_t jobid, DB_LIST_HANDLER sendit, void *ctx);
+void db_list_media_records(B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, void *ctx);
+void db_list_jobmedia_records(B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit, void *ctx);
+int  db_list_sql_query(B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, void *ctx);
+
+/* update.c */
+int  db_update_job_start_record(B_DB *db, JOB_DBR *jr);
+int  db_update_job_end_record(B_DB *db, JOB_DBR *jr);
+int  db_update_pool_record(B_DB *db, POOL_DBR *pr);
+int  db_update_media_record(B_DB *db, MEDIA_DBR *mr);
+int  db_add_MD5_to_file_record(B_DB *mdb, FileId_t FileId, char *MD5);  
+int  db_mark_file_record(B_DB *mdb, FileId_t FileId, int JobId);
+
+#endif /* __SQL_PROTOS_H */
diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c
new file mode 100644 (file)
index 0000000..c8436fa
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Bacula Catalog Database interface routines
+ * 
+ *     Almost generic set of SQL database interface routines
+ *     (with a little more work)
+ *
+ *    Kern Sibbald, March 2000
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of B_DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#if    HAVE_MYSQL | HAVE_SQLITE
+
+/* Forward referenced subroutines */
+void print_dashes(B_DB *mdb);
+void print_result(B_DB *mdb);
+
+
+/* NOTE!!! The following routines expect that the
+ *  calling subroutine sets and clears the mutex
+ */
+
+/* Utility routine for queries */
+int
+QueryDB(char *file, int line, B_DB *mdb, char *cmd)
+{
+   if (sql_query(mdb, cmd)) {
+      m_msg(file, line, &mdb->errmsg, _("query %s failed:\n%s\n"), cmd, sql_strerror(mdb));
+      e_msg(file, line, M_FATAL, 0, mdb->errmsg);
+      return 0;
+   }
+   mdb->result = sql_store_result(mdb);
+   
+   return mdb->result != NULL;
+}
+
+/* 
+ * Utility routine to do inserts   
+ * Returns: 0 on failure      
+ *         1 on success
+ */
+int
+InsertDB(char *file, int line, B_DB *mdb, char *cmd)
+{
+   if (sql_query(mdb, cmd)) {
+      m_msg(file, line, &mdb->errmsg,  _("insert %s failed:\n%s\n"), cmd, sql_strerror(mdb));
+      e_msg(file, line, M_FATAL, 0, mdb->errmsg);
+      return 0;
+   }
+   if (mdb->have_insert_id) {
+      mdb->num_rows = sql_affected_rows(mdb);
+   } else {
+      mdb->num_rows = 1;
+   }
+   if (mdb->num_rows != 1) {
+      m_msg(file, line, &mdb->errmsg, _("Insertion problem: affect_rows=%" lld "\n"), mdb->num_rows);
+      e_msg(file, line, M_FATAL, 0, mdb->errmsg);  /* ***FIXME*** remove me */
+      return 0;
+   }
+   return 1;
+}
+
+/* Utility routine for updates.
+ *  Returns: 0 on failure
+ *          1 on success  
+ */
+int
+UpdateDB(char *file, int line, B_DB *mdb, char *cmd)
+{
+
+   if (sql_query(mdb, cmd)) {
+      m_msg(file, line, &mdb->errmsg, _("update %s failed:\n%s\n"), cmd, sql_strerror(mdb));
+      e_msg(file, line, M_ERROR, 0, mdb->errmsg);
+      e_msg(file, line, M_ERROR, 0, "%s\n", cmd);
+      return 0;
+   }
+   mdb->num_rows = sql_affected_rows(mdb);
+   if (mdb->num_rows != 1) {
+      m_msg(file, line, &mdb->errmsg, _("Update problem: affect_rows=%" lld "\n"), mdb->num_rows);
+      e_msg(file, line, M_ERROR, 0, mdb->errmsg);
+      e_msg(file, line, M_ERROR, 0, "%s\n", cmd);
+      return 0;
+   }
+   return 1;
+}
+
+/* Utility routine for deletes  
+ *
+ * Returns: -1 on error
+ *          n number of rows affected
+ */
+int
+DeleteDB(char *file, int line, B_DB *mdb, char *cmd)
+{
+
+   if (sql_query(mdb, cmd)) {
+      m_msg(file, line, &mdb->errmsg, _("delete %s failed:\n%s\n"), cmd, sql_strerror(mdb));
+      e_msg(file, line, M_ERROR, 0, mdb->errmsg);
+      return -1;
+   }
+   return sql_affected_rows(mdb);
+}
+
+
+/*
+ * Get record max. Query is already in mdb->cmd
+ *  No locking done
+ *
+ * Returns: -1 on failure
+ *         count on success
+ */
+int get_sql_record_max(B_DB *mdb)
+{
+   SQL_ROW row;
+   int stat = 0;
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+      if ((row = sql_fetch_row(mdb)) == NULL) {
+         Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
+        stat = -1;
+      } else {
+        stat = atoi(row[0]);
+      }
+      sql_free_result(mdb);
+   } else {
+      Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
+      stat = -1;
+   }
+   return stat;
+}
+
+char *db_strerror(B_DB *mdb)
+{
+   return mdb->errmsg;
+}
+
+#endif /* HAVE_MYSQL | HAVE_SQLITE */
diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c
new file mode 100644 (file)
index 0000000..7ad6497
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * Bacula Catalog Database Create record interface routines
+ * 
+ *    Kern Sibbald, March 2000
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#if    HAVE_MYSQL || HAVE_SQLITE
+
+/* -----------------------------------------------------------------------
+ *
+ *   Generic Routines (or almost generic)
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/* Forward referenced subroutines */
+static int db_create_file_record(B_DB *mdb, ATTR_DBR *ar);
+static int db_create_filename_record(B_DB *mdb, ATTR_DBR *ar, char *fname);
+static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path);
+
+
+/* Imported subroutines */
+extern void print_dashes(B_DB *mdb);
+extern void print_result(B_DB *mdb);
+extern int QueryDB(char *file, int line, B_DB *db, char *select_cmd);
+extern int InsertDB(char *file, int line, B_DB *db, char *select_cmd);
+
+
+/* Create a new record for the Job
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int
+db_create_job_record(B_DB *mdb, JOB_DBR *jr)
+{
+   char dt[MAX_TIME_LENGTH];
+   time_t stime;
+   struct tm tm;
+   int stat;
+   char *JobId;
+   int32_t StartDay;
+
+   stime = jr->SchedTime;
+
+   localtime_r(&stime, &tm); 
+   strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm);
+   StartDay = (int32_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) -
+       date_encode(2000, 1, 1));
+
+   P(mdb->mutex);
+   JobId = db_next_index(mdb, "Job");
+   if (!JobId) {
+      jr->JobId = 0;
+      V(mdb->mutex);
+      return 0;
+   }
+   /* Must create it */
+   Mmsg(&mdb->cmd,
+"INSERT INTO Job (JobId, Job, Name, Type, Level, SchedTime, StartDay) VALUES \
+(%s, \"%s\", \"%s\", \"%c\", \"%c\", \"%s\", %d)", 
+          JobId, jr->Job, jr->Name, (char)(jr->Type), (char)(jr->Level), dt,
+          StartDay);
+
+   if (!INSERT_DB(mdb, mdb->cmd)) {
+      Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"), 
+           mdb->cmd, sql_strerror(mdb));
+      jr->JobId = 0;
+      stat = 0;
+   } else {
+      jr->JobId = sql_insert_id(mdb);
+      stat = 1;
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+/* Create a JobMedia record for medium used this job   
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int
+db_create_jobmedia_record(B_DB *mdb, JOBMEDIA_DBR *jm)
+{
+   int stat;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT JobId, MediaId FROM JobMedia WHERE \
+JobId=%d AND MediaId=%d", jm->JobId, jm->MediaId);
+
+   Dmsg0(30, mdb->cmd);
+   if (QUERY_DB(mdb, mdb->cmd)) {
+      mdb->num_rows = sql_num_rows(mdb);
+      if (mdb->num_rows > 0) {
+         Mmsg0(&mdb->errmsg, _("Create JobMedia failed. Record already exists.\n"));
+        sql_free_result(mdb);
+        V(mdb->mutex);
+         Dmsg0(0, "Already have JobMedia record\n");
+        return 0;
+      }
+      sql_free_result(mdb);
+   }
+
+   /* Must create it */
+   Mmsg(&mdb->cmd, 
+"INSERT INTO JobMedia (JobId, MediaId, FirstIndex, LastIndex) \
+VALUES (%d, %d, %u, %u)", 
+       jm->JobId, jm->MediaId, jm->FirstIndex, jm->LastIndex);
+
+   Dmsg0(30, mdb->cmd);
+   if (!INSERT_DB(mdb, mdb->cmd)) {
+      Mmsg2(&mdb->errmsg, _("Create db JobMedia record %s failed. ERR=%s\n"), mdb->cmd, 
+        sql_strerror(mdb));
+      stat = 0;
+   } else {
+      stat = 1;
+   }
+   V(mdb->mutex);
+   Dmsg0(30, "Return from JobMedia\n");
+   return stat;
+}
+
+
+
+/* Create Unique Pool record
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int
+db_create_pool_record(B_DB *mdb, POOL_DBR *pool_dbr)
+{
+   int stat;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name=\"%s\"", pool_dbr->Name);
+   Dmsg1(20, "selectpool: %s\n", mdb->cmd);
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+
+      mdb->num_rows = sql_num_rows(mdb);
+   
+      if (mdb->num_rows > 0) {
+         Mmsg1(&mdb->errmsg, _("pool record %s already exists\n"), pool_dbr->Name);
+        sql_free_result(mdb);
+        V(mdb->mutex);
+        return 0;
+      }
+      sql_free_result(mdb);
+   }
+
+   /* Must create it */
+   Mmsg(&mdb->cmd, 
+"INSERT INTO Pool (Name, NumVols, MaxVols, UseOnce, UseCatalog, \
+AcceptAnyVolume, PoolType, LabelFormat) \
+VALUES (\"%s\", %d, %d, %d, %d, %d, \"%s\", \"%s\")", 
+                 pool_dbr->Name,
+                 pool_dbr->NumVols, pool_dbr->MaxVols,
+                 pool_dbr->UseOnce, pool_dbr->UseCatalog,
+                 pool_dbr->AcceptAnyVolume,
+                 pool_dbr->PoolType, pool_dbr->LabelFormat);
+
+   if (!INSERT_DB(mdb, mdb->cmd)) {
+      Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"), 
+           mdb->cmd, sql_strerror(mdb));
+      pool_dbr->PoolId = 0;
+      stat = 0;
+   } else {
+      pool_dbr->PoolId = sql_insert_id(mdb);
+      stat = 1;
+   }
+   V(mdb->mutex);
+   
+   return stat;
+}
+
+
+/* 
+ * Create Unique Media record  
+ * Returns: 0 on failure
+ *         1 on success
+ */ 
+int
+db_create_media_record(B_DB *mdb, MEDIA_DBR *mr)
+{
+   int stat;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName=\"%s\"", 
+          mr->VolumeName);
+   Dmsg1(110, "selectpool: %s\n", mdb->cmd);
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+      mdb->num_rows = sql_num_rows(mdb);
+      if (mdb->num_rows > 0) {
+         Mmsg1(&mdb->errmsg, _("Media record %s already exists\n"), mr->VolumeName);
+        sql_free_result(mdb);
+        V(mdb->mutex);
+        return 0;
+      }
+      sql_free_result(mdb);
+   }
+
+   /* Must create it */
+   Mmsg(&mdb->cmd, 
+"INSERT INTO Media (VolumeName, MediaType, PoolId, VolMaxBytes, VolCapacityBytes, \
+VolStatus, Recycle) VALUES (\"%s\", \"%s\", %d, %" lld ", %" lld ", \"%s\", \"%s\")", 
+                 mr->VolumeName,
+                 mr->MediaType, mr->PoolId, 
+                 mr->VolMaxBytes, mr->VolCapacityBytes, 
+                 mr->VolStatus, mr->Recycle);
+
+   if (!INSERT_DB(mdb, mdb->cmd)) {
+      Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
+           mdb->cmd, sql_strerror(mdb));
+      stat = 0;
+   } else {
+      mr->MediaId = sql_insert_id(mdb);
+      stat = 1;
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+
+
+/* 
+ * Create a Unique record for the client -- no duplicates 
+ * Returns: 0 on failure
+ *         1 on success with id in cr->ClientId
+ */
+int db_create_client_record(B_DB *mdb, CLIENT_DBR *cr)
+{
+   SQL_ROW row;
+   int stat;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT ClientId FROM Client WHERE Name=\"%s\"", cr->Name);
+
+   cr->ClientId = 0;
+   if (QUERY_DB(mdb, mdb->cmd)) {
+
+      mdb->num_rows = sql_num_rows(mdb);
+      
+      /* If more than one, report error, but return first row */
+      if (mdb->num_rows > 1) {
+         Mmsg1(&mdb->errmsg, _("More than one Client!: %d\n"), (int)(mdb->num_rows));
+        Emsg0(M_ERROR, 0, mdb->errmsg);
+      }
+      if (mdb->num_rows >= 1) {
+        if ((row = sql_fetch_row(mdb)) == NULL) {
+            Mmsg1(&mdb->errmsg, _("error fetching Client row: %s\n"), sql_strerror(mdb));
+           Emsg0(M_ERROR, 0, mdb->errmsg);
+           sql_free_result(mdb);
+           V(mdb->mutex);
+           return 0;
+        }
+        sql_free_result(mdb);
+        cr->ClientId = atoi(row[0]);
+        V(mdb->mutex);
+        return 1;
+      }
+      sql_free_result(mdb);
+   }
+
+   /* Must create it */
+   Mmsg(&mdb->cmd, "INSERT INTO Client (Name, Uname) VALUES \
+(\"%s\", \"%s\")", cr->Name, cr->Uname);
+
+   if (!INSERT_DB(mdb, mdb->cmd)) {
+      Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
+           mdb->cmd, sql_strerror(mdb));
+      cr->ClientId = 0;
+      stat = 0;
+   } else {
+      cr->ClientId = sql_insert_id(mdb);
+      stat = 1;
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+
+/* 
+ * Create a FileSet record. This record is unique in the
+ *  name and the MD5 signature of the include/exclude sets.
+ *  Returns: 0 on failure
+ *          1 on success with FileSetId in record
+ */
+int db_create_fileset_record(B_DB *mdb, FILESET_DBR *fsr)
+{
+   SQL_ROW row;
+   int stat;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT FileSetId FROM FileSet WHERE \
+FileSet=\"%s\" and MD5=\"%s\"", fsr->FileSet, fsr->MD5);
+
+   fsr->FileSetId = 0;
+   if (QUERY_DB(mdb, mdb->cmd)) {
+
+      mdb->num_rows = sql_num_rows(mdb);
+      
+      if (mdb->num_rows > 1) {
+         Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows));
+        Emsg0(M_ERROR, 0, mdb->errmsg);
+      }
+      if (mdb->num_rows >= 1) {
+        if ((row = sql_fetch_row(mdb)) == NULL) {
+            Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb));
+           Emsg0(M_ERROR, 0, mdb->errmsg);
+           sql_free_result(mdb);
+           V(mdb->mutex);
+           return 0;
+        }
+        sql_free_result(mdb);
+        fsr->FileSetId = atoi(row[0]);
+        V(mdb->mutex);
+        return 1;
+      }
+      sql_free_result(mdb);
+   }
+
+   /* Must create it */
+   Mmsg(&mdb->cmd, "INSERT INTO FileSet (FileSet, MD5) VALUES \
+(\"%s\", \"%s\")", fsr->FileSet, fsr->MD5);
+
+   if (!INSERT_DB(mdb, mdb->cmd)) {
+      Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
+           mdb->cmd, sql_strerror(mdb));
+      fsr->FileSetId = 0;
+      stat = 0;
+   } else {
+      fsr->FileSetId = sql_insert_id(mdb);
+      stat = 1;
+   }
+
+   V(mdb->mutex);
+   return stat;
+}
+
+
+/*
+ *  struct stat
+ *  {
+ *     dev_t         st_dev;       * device *
+ *     ino_t         st_ino;       * inode *
+ *     mode_t        st_mode;      * protection *
+ *     nlink_t       st_nlink;     * number of hard links *
+ *     uid_t         st_uid;       * user ID of owner *
+ *     gid_t         st_gid;       * group ID of owner *
+ *     dev_t         st_rdev;      * device type (if inode device) *
+ *     off_t         st_size;      * total size, in bytes *
+ *     unsigned long st_blksize;   * blocksize for filesystem I/O *
+ *     unsigned long st_blocks;    * number of blocks allocated *
+ *     time_t        st_atime;     * time of last access *
+ *     time_t        st_mtime;     * time of last modification *
+ *     time_t        st_ctime;     * time of last inode change *            
+ *  };
+ */
+
+
+
+/* 
+ * Create File record in B_DB  
+ *
+ *  In order to reduce database size, we store the File attributes,
+ *  the FileName, and the Path separately.  In principle, there   
+ *  is a single FileName record and a single Path record, no matter
+ *  how many times it occurs.  This is this subroutine, we separate
+ *  the file and the path and create three database records.
+ */
+int db_create_file_attributes_record(B_DB *mdb, ATTR_DBR *ar)
+{
+   int fnl, pnl;
+   char *l, *p;
+   /* ****FIXME***** malloc these */
+   char file[MAXSTRING];
+   char spath[MAXSTRING];
+   char buf[MAXSTRING];
+
+   Dmsg1(100, "Fname=%s\n", ar->fname);
+   Dmsg0(50, "put_file_into_catalog\n");
+   /* For the moment, we only handle Unix attributes.  Note, we are
+    * also getting any MD5 signature that was computed.
+    */
+   if (ar->Stream != STREAM_UNIX_ATTRIBUTES) {
+      Mmsg0(&mdb->errmsg, _("Attempt to put non-attributes into catalog\n"));
+      return 0;
+   }
+
+   /* Find path without the filename.  
+    * I.e. everything after the last / is a "filename".
+    * OK, maybe it is a directory name, but we treat it like
+    * a filename. If we don't find a / then the whole name
+    * must be a path name (e.g. c:).
+    */
+   for (p=l=ar->fname; *p; p++) {
+      if (*p == '/') {
+        l = p;                       /* set pos of last slash */
+      }
+   }
+   if (*l == '/') {                   /* did we find a slash? */
+      l++;                           /* yes, point to filename */
+   } else {                          /* no, whole thing must be path name */
+      l = p;
+   }
+
+   /* If filename doesn't exist (i.e. root directory), we
+    * simply create a blank name consisting of a single 
+    * space. This makes handling zero length filenames
+    * easier.
+    */
+   fnl = p - l;
+   if (fnl > 255) {
+      Emsg1(M_WARNING, 0, _("Filename truncated to 255 chars: %s\n"), l);
+      fnl = 255;
+   }
+   if (fnl > 0) {
+      strncpy(file, l, fnl);         /* copy filename */
+      file[fnl] = 0;
+   } else {
+      file[0] = ' ';                  /* blank filename */
+      file[1] = 0;
+   }
+
+   pnl = l - ar->fname;    
+   if (pnl > 255) {
+      Emsg1(M_WARNING, 0, _("Path name truncated to 255 chars: %s\n"), ar->fname);
+      pnl = 255;
+   }
+   strncpy(spath, ar->fname, pnl);
+   spath[pnl] = 0;
+
+   if (pnl == 0) {
+      Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), ar->fname);
+      Emsg0(M_ERROR, 0, mdb->errmsg);
+      spath[0] = ' ';
+      spath[1] = 0;
+   }
+
+   Dmsg1(100, "spath=%s\n", spath);
+   Dmsg1(100, "file=%s\n", file);
+
+   db_escape_string(buf, file, fnl);
+
+   if (!db_create_filename_record(mdb, ar, buf)) {
+      return 0;
+   }
+   Dmsg1(100, "db_create_filename_record: %s\n", buf);
+
+   db_escape_string(buf, spath, pnl);
+
+   if (!db_create_path_record(mdb, ar, buf)) {
+      return 0;
+   }
+   Dmsg1(100, "db_create_path_record\n", buf);
+
+   if (!db_create_file_record(mdb, ar)) {
+      return 0;
+   }
+   Dmsg0(50, "db_create_file_record\n");
+
+   Dmsg3(100, "Path=%s File=%s FilenameId=%d\n", spath, file, ar->FilenameId);
+
+   return 1;
+}
+
+static int db_create_file_record(B_DB *mdb, ATTR_DBR *ar)
+{
+   int stat;
+
+   P(mdb->mutex);
+   /* Must create it */
+   Mmsg(&mdb->cmd,
+"INSERT INTO File (FileIndex, JobId, PathId, FilenameId, \
+LStat, MD5) VALUES (%d, %d, %d, %d, \"%s\", \" \")", 
+     (int)ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId, 
+      ar->attr);
+
+   if (!INSERT_DB(mdb, mdb->cmd)) {
+      Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),       
+        mdb->cmd, sql_strerror(mdb));
+      Emsg1(M_ERROR, 0, "%s", mdb->errmsg);
+      ar->FileId = 0;
+      stat = 0;
+   } else {
+      ar->FileId = sql_insert_id(mdb);
+      stat = 1;
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+/* Create a Unique record for the Path -- no duplicates */
+static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path)
+{
+   SQL_ROW row;
+   static uint32_t cached_id = 0;
+   static char cached_path[MAXSTRING];
+   int stat;
+
+   if (*path == 0) {
+      Mmsg0(&mdb->errmsg, _("Null path given to db_create_path_record\n"));
+      Emsg0(M_ERROR, 0, mdb->errmsg);
+      ar->PathId = 0;
+      return 0;
+   }
+
+   P(mdb->mutex);
+
+   if (cached_id != 0 && strcmp(cached_path, path) == 0) {
+      ar->PathId = cached_id;
+      V(mdb->mutex);
+      return 1;
+   }
+
+   Mmsg(&mdb->cmd, "SELECT PathId FROM Path WHERE Path=\"%s\"", path);
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+
+      mdb->num_rows = sql_num_rows(mdb);
+
+      if (mdb->num_rows > 1) {
+         Mmsg2(&mdb->errmsg, _("More than one Path!: %" lld " for Path=%s\n"), 
+           mdb->num_rows, path);
+         Emsg1(M_ERROR, 0, "%s", mdb->errmsg);
+         Emsg1(M_ERROR, 0, "%s\n", mdb->cmd);
+      }
+      if (mdb->num_rows >= 1) {
+        if ((row = sql_fetch_row(mdb)) == NULL) {
+           V(mdb->mutex);
+            Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
+           Emsg0(M_ERROR, 0, mdb->errmsg);
+           sql_free_result(mdb);
+           ar->PathId = 0;
+           return 0;
+        }
+        sql_free_result(mdb);
+        ar->PathId = atoi(row[0]);
+        if (ar->PathId != cached_id) {
+           cached_id = ar->PathId;
+           strncpy(cached_path, path, sizeof(cached_path));
+           cached_path[sizeof(cached_path)-1] = 0;
+        }
+        V(mdb->mutex);
+        return 1;
+      }
+
+      sql_free_result(mdb);
+   }
+
+   Mmsg(&mdb->cmd, "INSERT INTO Path (Path)  VALUES (\"%s\")", path);
+
+   if (!INSERT_DB(mdb, mdb->cmd)) {
+      Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"), 
+        mdb->cmd, sql_strerror(mdb));
+      Emsg1(M_ERROR, 0, "%s", mdb->errmsg);
+      ar->PathId = 0;
+      stat = 0;
+   } else {
+      ar->PathId = sql_insert_id(mdb);
+      stat = 1;
+   }
+
+   if (ar->PathId != cached_id) {
+      cached_id = ar->PathId;
+      strncpy(cached_path, path, sizeof(cached_path));
+      cached_path[sizeof(cached_path)-1] = 0;
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+/* Create a Unique record for the filename -- no duplicates */
+static int db_create_filename_record(B_DB *mdb, ATTR_DBR *ar, char *fname) 
+{
+   SQL_ROW row;
+   int stat;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name=\"%s\"", fname);
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+      mdb->num_rows = sql_num_rows(mdb);
+      if (mdb->num_rows > 1) {
+         Mmsg2(&mdb->errmsg, _("More than one Filename!: %d File=%s\n"), 
+           (int)(mdb->num_rows), fname);
+         Emsg1(M_ERROR, 0, "%s", mdb->errmsg);
+         Emsg1(M_ERROR, 0, "%s\n", mdb->cmd);
+      }
+      if (mdb->num_rows >= 1) {
+        if ((row = sql_fetch_row(mdb)) == NULL) {
+            Mmsg2(&mdb->errmsg, _("error fetching row for file=%s: ERR=%s\n"), 
+               fname, sql_strerror(mdb));
+           sql_free_result(mdb);
+           V(mdb->mutex);
+           Emsg0(M_ERROR, 0, mdb->errmsg);
+           ar->FilenameId = 0;
+           return 0;
+        }
+        sql_free_result(mdb);
+        ar->FilenameId = atoi(row[0]);
+        V(mdb->mutex);
+        return 1;
+      }
+      sql_free_result(mdb);
+   }
+
+   Mmsg(&mdb->cmd, "INSERT INTO Filename (Name) \
+VALUES (\"%s\")", fname);
+
+   if (!INSERT_DB(mdb, mdb->cmd)) {
+      Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"), 
+           mdb->cmd, sql_strerror(mdb));
+      Emsg1(M_ERROR, 0, "%s", mdb->errmsg);
+      ar->FilenameId = 0;
+      stat = 0;
+   } else {
+      ar->FilenameId = sql_insert_id(mdb);
+      stat = 1;
+   }
+
+   V(mdb->mutex);
+   return stat;
+}
+
+#endif /* HAVE_MYSQL || HAVE_SQLITE */
diff --git a/bacula/src/cats/sql_delete.c b/bacula/src/cats/sql_delete.c
new file mode 100644 (file)
index 0000000..5fd896a
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Bacula Catalog Database Delete record interface routines
+ * 
+ *    Kern Sibbald, December 2000
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+
+#if    HAVE_MYSQL || HAVE_SQLITE
+/* -----------------------------------------------------------------------
+ *
+ *   Generic Routines (or almost generic)
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/* Imported subroutines */
+extern void print_dashes(B_DB *mdb);
+extern void print_result(B_DB *mdb);
+extern int QueryDB(char *file, int line, B_DB *db, char *select_cmd);
+extern int DeleteDB(char *file, int line, B_DB *db, char *delete_cmd);
+       
+/*
+ * Delete Pool record, must also delete all associated
+ *  Media records.
+ *
+ *  Returns: 0 on error
+ *          1 on success
+ *          PoolId = number of Pools deleted (should be 1)
+ *          NumVols = number of Media records deleted
+ */
+int
+db_delete_pool_record(B_DB *mdb, POOL_DBR *pr)
+{
+   SQL_ROW row;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT PoolId FROM Pool WHERE Name=\"%s\"", pr->Name);
+   Dmsg1(10, "selectpool: %s\n", mdb->cmd);
+
+   pr->PoolId = pr->NumVols = 0;
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+
+      mdb->num_rows = sql_num_rows(mdb);
+   
+      if (mdb->num_rows == 0) {
+         Mmsg(&mdb->errmsg, _("No pool record %s exists\n"), pr->Name);
+        sql_free_result(mdb);
+        V(mdb->mutex);
+        return 0;
+      } else if (mdb->num_rows != 1) {
+         Mmsg(&mdb->errmsg, _("Expecting one pool record, got %d\n"), mdb->num_rows);
+        sql_free_result(mdb);
+        V(mdb->mutex);
+        return 0;
+      }
+      if ((row = sql_fetch_row(mdb)) == NULL) {
+        V(mdb->mutex);
+         Emsg1(M_ABORT, 0, _("Error fetching row %s\n"), sql_strerror(mdb));
+      }
+      pr->PoolId = atoi(row[0]);
+      sql_free_result(mdb);
+   }
+
+   /* Delete Media owned by this pool */
+   Mmsg(&mdb->cmd,
+"DELETE FROM Media WHERE Media.PoolId = %d", pr->PoolId);
+
+   pr->NumVols = DELETE_DB(mdb, mdb->cmd);
+   Dmsg1(200, "Deleted %d Media records\n", pr->NumVols);
+
+   /* Delete Pool */
+   Mmsg(&mdb->cmd,
+"DELETE FROM Pool WHERE Pool.PoolId = %d", pr->PoolId);
+   pr->PoolId = DELETE_DB(mdb, mdb->cmd);
+   Dmsg1(200, "Deleted %d Pool records\n", pr->PoolId);
+
+   V(mdb->mutex);
+   return 1;
+}
+
+
+/* Delete Media record */
+int db_delete_media_record(B_DB *mdb, MEDIA_DBR *mr)
+{
+
+   P(mdb->mutex);
+   if (mr->MediaId == 0) {
+      Mmsg(&mdb->cmd, "DELETE FROM Media WHERE VolumeName=\"%s\"", 
+          mr->VolumeName);
+   } else {
+      Mmsg(&mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", 
+          mr->MediaId);
+   }
+
+   mr->MediaId = DELETE_DB(mdb, mdb->cmd);
+
+   V(mdb->mutex);
+   return 1;
+}
+
+#endif /* HAVE_MYSQL || HAVE_SQLITE */
diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c
new file mode 100644 (file)
index 0000000..d49efab
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Bacula Catalog Database Find record interface routines
+ *
+ *  Note, generally, these routines are more complicated
+ *       that a simple search by name or id. Such simple
+ *       request are in get.c
+ * 
+ *    Kern Sibbald, December 2000
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#if    HAVE_MYSQL || HAVE_SQLITE
+
+/* -----------------------------------------------------------------------
+ *
+ *   Generic Routines (or almost generic)
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/* Imported subroutines */
+extern void print_result(B_DB *mdb);
+extern int QueryDB(char *file, int line, B_DB *db, char *select_cmd);
+
+
+/* Find job start time. Used to find last full save
+ * for Incremental and Differential saves.
+ *     
+ * Returns: 0 on failure
+ *         1 on success, jr is unchanged, but stime is set
+ */
+int
+db_find_job_start_time(B_DB *mdb, JOB_DBR *jr, char *stime)
+{
+   SQL_ROW row;
+   int JobId;
+
+   strcpy(stime, "0000-00-00 00:00:00");   /* default */
+   P(mdb->mutex);
+   /* If no Id given, we must find corresponding job */
+   if (jr->JobId == 0) {
+      /* Differential is since last Full backup */
+      if (jr->Level == L_DIFFERENTIAL) {
+        Mmsg(&mdb->cmd, 
+"SELECT JobId from Job WHERE JobStatus='T' and Type='%c' and \
+Level='%c' and Name=\"%s\" and ClientId=%d and FileSetId=%d \
+ORDER by StartTime DESC LIMIT 1",
+          jr->Type, L_FULL, jr->Name, jr->ClientId, jr->FileSetId);
+      /* Incremental is since last Full, Incremental, or Differential */
+      } else if (jr->Level == L_INCREMENTAL) {
+        Mmsg(&mdb->cmd, 
+"SELECT JobId from Job WHERE JobStatus='T' and Type='%c' and \
+(Level='%c' or Level='%c' or Level='%c') and Name=\"%s\" and ClientId=%d \
+ORDER by StartTime DESC LIMIT 1",
+          jr->Type, L_INCREMENTAL, L_DIFFERENTIAL, L_FULL, jr->Name,
+          jr->ClientId);
+      } else {
+         Mmsg1(&mdb->errmsg, _("Unknown level=%d\n"), jr->Level);
+        Emsg0(M_ERROR, 0, mdb->errmsg);
+        V(mdb->mutex);
+        return 0;
+      }
+      Dmsg1(100, "Submitting: %s\n", mdb->cmd);
+      if (!QUERY_DB(mdb, mdb->cmd)) {
+         Emsg1(M_ERROR, 0, _("Query error for start time request: %s\n"), mdb->cmd);
+        V(mdb->mutex);
+        return 0;
+      }
+      if ((row = sql_fetch_row(mdb)) == NULL) {
+        sql_free_result(mdb);
+        V(mdb->mutex);
+        return 0;
+      }
+      JobId = atoi(row[0]);
+      sql_free_result(mdb);
+   } else {
+      JobId = jr->JobId;             /* search for particular id */
+   }
+
+   Dmsg1(100, "Submitting: %s\n", mdb->cmd);
+   Mmsg(&mdb->cmd, "SELECT StartTime from Job WHERE Job.JobId=%d", JobId);
+
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      Emsg1(M_ERROR, 0, _("Query error for start time request: %s\n"), mdb->cmd);
+      V(mdb->mutex);
+      return 0;
+   }
+
+   if ((row = sql_fetch_row(mdb)) == NULL) {
+      *stime = 0;                    /* set EOS */
+      Emsg2(M_ERROR, 0, _("No Job found for JobId=%d: %s\n"), JobId, sql_strerror(mdb));
+      sql_free_result(mdb);
+      V(mdb->mutex);
+      return 0;
+   }
+   Dmsg1(100, "Got start time: %s\n", row[0]);
+   strcpy(stime, row[0]);
+
+   sql_free_result(mdb);
+
+   V(mdb->mutex);
+   return 1;
+}
+
+/* 
+ * Find JobId of last full verify 
+ * Returns: 1 on success
+ *         0 on failure
+ */
+int
+db_find_last_full_verify(B_DB *mdb, JOB_DBR *jr)
+{
+   SQL_ROW row;
+
+   /* Find last full */
+   P(mdb->mutex);
+   if (jr->Level != L_VERIFY_CATALOG) {
+      Emsg2(M_FATAL, 0, _("Expecting Level=%c, got %c\n"), L_VERIFY_CATALOG, jr->Level);
+      return 0;
+   }
+   Mmsg(&mdb->cmd, 
+"SELECT JobId from Job WHERE Type='%c' and Level='%c' and Name=\"%s\" and \
+ClientId=%d ORDER by StartTime DESC LIMIT 1",
+          JT_VERIFY, L_VERIFY_INIT, jr->Name, jr->ClientId);
+
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return 0;
+   }
+   if ((row = sql_fetch_row(mdb)) == NULL) {
+      Emsg0(M_FATAL, 0, _("No Job found for last full verify.\n"));
+      sql_free_result(mdb);
+      V(mdb->mutex);
+      return 0;
+   }
+
+   jr->JobId = atoi(row[0]);
+   sql_free_result(mdb);
+
+   Dmsg1(100, "db_get_last_full_verify: got JobId=%d\n", jr->JobId);
+   if (jr->JobId <= 0) {
+      Emsg1(M_FATAL, 0, _("No Verify Job found for: %s\n"), mdb->cmd);
+      V(mdb->mutex);
+      return 0;
+   }
+
+   V(mdb->mutex);
+   return 1;
+}
+
+/* 
+ * Find Available Media (Volume) for Pool
+ *
+ * Find a Volume for a given PoolId, MediaType, and Status.
+ *
+ * Returns: 0 on failure
+ *         numrows on success
+ */
+int
+db_find_next_volume(B_DB *mdb, int item, MEDIA_DBR *mr) 
+{
+   SQL_ROW row;
+   int numrows;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
+VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes \
+FROM Media WHERE PoolId=%d AND MediaType=\"%s\" AND VolStatus=\"%s\" \
+ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); 
+
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return 0;
+   }
+
+   numrows = sql_num_rows(mdb);
+   if (item > numrows) {
+      V(mdb->mutex);
+      return 0;
+   }
+   
+   /* Seek to desired item 
+    * Note, we use base 1; SQL uses base 0
+    */
+   sql_data_seek(mdb, item-1);
+
+   if ((row = sql_fetch_row(mdb)) == NULL) {
+      Emsg1(M_ERROR, 0, _("No media record found for item %d.\n"), item);
+      sql_free_result(mdb);
+      V(mdb->mutex);
+      return 0;
+   }
+
+   /* Return fields in Media Record */
+   mr->MediaId = atoi(row[0]);
+   strcpy(mr->VolumeName, row[1]);
+   mr->VolJobs = atoi(row[2]);
+   mr->VolFiles = atoi(row[3]);
+   mr->VolBlocks = atoi(row[4]);
+   mr->VolBytes = (uint64_t)strtod(row[5], NULL);
+   mr->VolMounts = atoi(row[6]);
+   mr->VolErrors = atoi(row[7]);
+   mr->VolWrites = atoi(row[8]);
+   mr->VolMaxBytes = (uint64_t)strtod(row[9], NULL);
+   mr->VolCapacityBytes = (uint64_t)strtod(row[10], NULL);
+
+   sql_free_result(mdb);
+
+   V(mdb->mutex);
+   return numrows;
+}
+
+
+#endif /* HAVE_MYSQL || HAVE_SQLITE */
diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c
new file mode 100644 (file)
index 0000000..a50a179
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * Bacula Catalog Database Get record interface routines
+ *  Note, these routines generally get a record by id or
+ *       by name.  If more logic is involved, the routine
+ *       should be in find.c 
+ *
+ *    Kern Sibbald, March 2000
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#if    HAVE_MYSQL || HAVE_SQLITE
+
+/* -----------------------------------------------------------------------
+ *
+ *   Generic Routines (or almost generic)
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/* Forward referenced functions */
+static int db_get_file_record(B_DB *mdb, FILE_DBR *fdbr);
+static int db_get_filename_record(B_DB *mdb, char *fname);
+static int db_get_path_record(B_DB *mdb, char *path);
+
+
+/* Imported subroutines */
+extern void print_result(B_DB *mdb);
+extern int QueryDB(char *file, int line, B_DB *db, char *select_cmd);
+
+
+/*
+ * Given a full filename (with path), look up the File record
+ * (with attributes) in the database.
+ *
+ *  Returns: 0 on failure
+ *          1 on success with the File record in FILE_DBR
+ */
+int db_get_file_attributes_record(B_DB *mdb, char *fname, FILE_DBR *fdbr)
+{
+   int fnl, pnl;
+   char *l, *p;
+   uint64_t id;
+   char file[MAXSTRING];
+   char spath[MAXSTRING];
+   char buf[MAXSTRING];
+   Dmsg0(20, "get_file_from_catalog\n");
+
+   /* Find path without the filename */
+   for (p=l=fname; *p; p++) {
+      if (*p == '/') {
+        l = p;
+      }
+   }
+   if (*l == '/') {
+      l++;
+   }
+
+   fnl = p - l;
+   strcpy(file, l);
+
+   pnl = l - fname;    
+   strncpy(spath, fname, pnl);
+   spath[l-fname] = 0;
+
+   if (pnl == 0) {
+      return 0;
+   }
+
+   strip_trailing_junk(spath);
+   Dmsg1(50, "spath=%s\n", spath);
+
+   strip_trailing_junk(file);
+   Dmsg1(50, "file=%s\n", file);
+
+   db_escape_string(buf, file, fnl);
+   fdbr->FilenameId = db_get_filename_record(mdb, buf);
+   Dmsg1(50, "db_get_filename_record FilenameId=%d\n", fdbr->FilenameId);
+
+   db_escape_string(buf, spath, pnl);
+   fdbr->PathId = db_get_path_record(mdb, buf);
+   Dmsg1(50, "db_get_path_record PathId=%d\n", fdbr->PathId);
+
+   id = db_get_file_record(mdb, fdbr);
+
+   return id;
+}
+
+
+/* Get a File record   
+ * Returns: 0 on failure
+ *         1 on success
+ */
+static
+int db_get_file_record(B_DB *mdb, FILE_DBR *fdbr)
+{
+   SQL_ROW row;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, 
+"SELECT FileId, LStat, MD5 from File where File.JobId=%d and File.PathId=%d and \
+File.FilenameId=%d", fdbr->JobId, fdbr->PathId, fdbr->FilenameId);
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+
+      mdb->num_rows = sql_num_rows(mdb);
+
+      /* 
+       * Note, we can find more than one File record with the same
+       *  filename if the file is linked.   ????????
+       */
+      if (mdb->num_rows > 1) {
+         Emsg1(M_WARNING, 0, _("get_file_record want 1 got rows=%d\n"), mdb->num_rows);
+         Emsg1(M_WARNING, 0, "%s\n", mdb->cmd);
+      }
+      if (mdb->num_rows >= 1) {
+        if ((row = sql_fetch_row(mdb)) == NULL) {
+            Emsg1(M_ERROR, 0, "Error fetching row: %s\n", sql_strerror(mdb));
+        } else {
+           fdbr->FileId = (FileId_t)strtod(row[0], NULL);
+           strncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
+           fdbr->LStat[sizeof(fdbr->LStat)] = 0;
+           strncpy(fdbr->MD5, row[2], sizeof(fdbr->MD5));
+           fdbr->MD5[sizeof(fdbr->MD5)] = 0;
+           sql_free_result(mdb);
+           V(mdb->mutex);
+           return 1;
+        }
+      }
+
+      sql_free_result(mdb);
+   }
+   V(mdb->mutex);
+   return 0;                         /* failed */
+
+}
+
+/* Get Filename record  
+ * Returns: 0 on failure
+ *         FilenameId on success
+ */
+static int db_get_filename_record(B_DB *mdb, char *fname) 
+{
+   SQL_ROW row;
+   int FilenameId;
+
+   if (*fname == 0) {
+      Mmsg0(&mdb->errmsg, _("Null name given to db_get_filename_record\n"));
+      Emsg0(M_ABORT, 0, mdb->errmsg);
+   }
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name=\"%s\"", fname);
+   if (QUERY_DB(mdb, mdb->cmd)) {
+
+      mdb->num_rows = sql_num_rows(mdb);
+
+      if (mdb->num_rows > 1) {
+         Mmsg1(&mdb->errmsg, _("More than one Filename!: %d\n"), (int)(mdb->num_rows));
+        Emsg0(M_FATAL, 0, mdb->errmsg);
+      } else if (mdb->num_rows == 1) {
+        if ((row = sql_fetch_row(mdb)) == NULL) {
+            Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
+           Emsg0(M_FATAL, 0, mdb->errmsg);
+        }
+        FilenameId = atoi(row[0]);
+        if (FilenameId <= 0) {
+            Mmsg2(&mdb->errmsg, _("Create db Filename record %s found bad record: %d\n"),
+              mdb->cmd, FilenameId); 
+           Emsg0(M_ERROR, 0, mdb->errmsg);
+        }
+        sql_free_result(mdb);
+        V(mdb->mutex);
+        return FilenameId;
+
+      }
+      sql_free_result(mdb);
+   }
+   V(mdb->mutex);
+   return 0;                         /* failed */
+}
+
+/* Get path record   
+ * Returns: 0 on failure
+ *         PathId on success
+ */
+static int db_get_path_record(B_DB *mdb, char *path)
+{
+   SQL_ROW row;
+   int PathId;
+   /*******FIXME***** move into mdb record and allocate */
+   static int cached_id = 0;
+   static char cached_path[MAXSTRING];
+
+   if (*path == 0) {
+      Emsg0(M_ABORT, 0, _("Null path given to db_get_path_record\n"));
+   }
+   if (cached_id != 0 && strcmp(cached_path, path) == 0) {
+      return cached_id;
+   }         
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT PathId FROM Path WHERE Path=\"%s\"", path);
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+
+      mdb->num_rows = sql_num_rows(mdb);
+
+      if (mdb->num_rows > 1) {
+         Mmsg1(&mdb->errmsg, _("More than one Path!: %" lld "\n"), mdb->num_rows);
+        Emsg0(M_FATAL, 0, mdb->errmsg);
+      } else if (mdb->num_rows == 1) {
+        if ((row = sql_fetch_row(mdb)) == NULL) {
+            Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
+           Emsg0(M_FATAL, 0, mdb->errmsg);
+        }
+        PathId = atoi(row[0]);
+        if (PathId != cached_id) {
+           cached_id = PathId;
+           strcpy(cached_path, path);
+        }
+        sql_free_result(mdb);
+        V(mdb->mutex);
+        return PathId;
+      }
+
+      sql_free_result(mdb);
+   }
+   V(mdb->mutex);
+   return 0;                         /* failed */
+}
+
+
+/* 
+ * Get Job record for given JobId or Job name
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int db_get_job_record(B_DB *mdb, JOB_DBR *jr)
+{
+   SQL_ROW row;
+
+   P(mdb->mutex);
+   if (jr->JobId == 0) {
+      Mmsg(&mdb->cmd, "SELECT VolSessionId, VolSessionTime, \
+PoolId, StartTime, EndTime, JobFiles, JobBytes, Job \
+FROM Job WHERE Job=\"%s\"", jr->Job);
+    } else {
+      Mmsg(&mdb->cmd, "SELECT VolSessionId, VolSessionTime, \
+PoolId, StartTime, EndTime, JobFiles, JobBytes, Job \
+FROM Job WHERE JobId=%d", jr->JobId);
+    }
+
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return 0;                      /* failed */
+   }
+   if ((row = sql_fetch_row(mdb)) == NULL) {
+      Mmsg1(&mdb->errmsg, _("No Job found for JobId %d\n"), jr->JobId);
+      sql_free_result(mdb);
+      V(mdb->mutex);
+      return 0;                      /* failed */
+   }
+
+   jr->VolSessionId = atol(row[0]);
+   jr->VolSessionTime = atol(row[1]);
+   jr->PoolId = atoi(row[2]);
+   strcpy(jr->cStartTime, row[3]);
+   strcpy(jr->cEndTime, row[4]);
+   jr->JobFiles = atol(row[5]);
+   jr->JobBytes = (uint64_t)strtod(row[6], NULL);
+   strcpy(jr->Job, row[7]);
+   sql_free_result(mdb);
+
+   V(mdb->mutex);
+   return 1;
+}
+
+/*
+ * Find VolumeNames for a give JobId
+ *  Returns: 0 on error or no Volumes found
+ *          number of volumes on success
+ *             Volumes are concatenated in VolumeNames
+ *             separated by a vertical bar (|).
+ */
+int db_get_job_volume_names(B_DB *mdb, uint32_t JobId, char *VolumeNames)
+{
+   SQL_ROW row;
+   int stat = 0;
+   int i;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, 
+"SELECT VolumeName FROM JobMedia,Media WHERE JobMedia.JobId=%d \
+AND JobMedia.MediaId=Media.MediaId", JobId);
+
+   Dmsg1(130, "VolNam=%s\n", mdb->cmd);
+   VolumeNames[0] = 0;
+   if (QUERY_DB(mdb, mdb->cmd)) {
+      mdb->num_rows = sql_num_rows(mdb);
+      Dmsg1(130, "Num rows=%d\n", mdb->num_rows);
+      if (mdb->num_rows <= 0) {
+         Mmsg1(&mdb->errmsg, _("No volumes found for JobId=%d"), JobId);
+        stat = 0;
+      } else {
+        stat = mdb->num_rows;
+        for (i=0; i < stat; i++) {
+           if ((row = sql_fetch_row(mdb)) == NULL) {
+               Mmsg2(&mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb));
+              stat = 0;
+              break;
+           } else {
+              if (VolumeNames[0] != 0) {
+                  strcat(VolumeNames, "|");
+              }
+              strcat(VolumeNames, row[0]);
+           }
+        }
+      }
+      sql_free_result(mdb);
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+
+/* 
+ * Get the number of pool records
+ *
+ * Returns: -1 on failure
+ *         number on success
+ */
+int db_get_num_pool_records(B_DB *mdb)
+{
+   int stat = 0;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT count(*) from Pool");
+   stat = get_sql_record_max(mdb);
+   V(mdb->mutex);
+   return stat;
+}
+
+/*
+ * This function returns a list of all the Pool record ids.
+ *  The caller must free ids if non-NULL.
+ *
+ *  Returns 0: on failure
+ *         1: on success
+ */
+int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
+{
+   SQL_ROW row;
+   int stat = 0;
+   int i = 0;
+   uint32_t *id;
+
+   P(mdb->mutex);
+   *ids = NULL;
+   Mmsg(&mdb->cmd, "SELECT PoolId FROM Pool");
+   if (QUERY_DB(mdb, mdb->cmd)) {
+      *num_ids = sql_num_rows(mdb);
+      if (*num_ids > 0) {
+        id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
+        while ((row = sql_fetch_row(mdb)) != NULL) {
+           id[i++] = (uint32_t)atoi(row[0]);
+        }
+        *ids = id;
+      }
+      sql_free_result(mdb);
+      stat = 1;
+   } else {
+      Mmsg(&mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
+      stat = 0;
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+
+/* Get Pool Record   
+ * If the PoolId is non-zero, we get its record,
+ *  otherwise, we search on the PoolName
+ *
+ * Returns: 0 on failure
+ *         id on success 
+ */
+int db_get_pool_record(B_DB *mdb, POOL_DBR *pdbr)
+{
+   SQL_ROW row;
+   int stat = 0;
+
+   P(mdb->mutex);
+   if (pdbr->PoolId != 0) {              /* find by id */
+      Mmsg(&mdb->cmd, 
+"SELECT PoolId, Name, NumVols, MaxVols, UseOnce, UseCatalog, AcceptAnyVolume, \
+PoolType, LabelFormat FROM Pool WHERE Pool.PoolId=%d", pdbr->PoolId);
+   } else {                          /* find by name */
+      Mmsg(&mdb->cmd, 
+"SELECT PoolId, Name, NumVols, MaxVols, UseOnce, UseCatalog, AcceptAnyVolume, \
+PoolType, LabelFormat FROM Pool WHERE Pool.Name=\"%s\"", pdbr->Name);
+   }  
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+      mdb->num_rows = sql_num_rows(mdb);
+      if (mdb->num_rows > 1) {
+         Mmsg1(&mdb->errmsg, _("More than one Pool!: %" lld "\n"), mdb->num_rows);
+        Emsg0(M_ERROR, 0, mdb->errmsg);
+      } else if (mdb->num_rows == 1) {
+        if ((row = sql_fetch_row(mdb)) == NULL) {
+            Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
+           Emsg0(M_ERROR, 0, mdb->errmsg);
+        } else {
+           pdbr->PoolId = atoi(row[0]);
+           strcpy(pdbr->Name, row[1]);
+           pdbr->NumVols = atoi(row[2]);
+           pdbr->MaxVols = atoi(row[3]);
+           pdbr->UseOnce = atoi(row[4]);
+           pdbr->UseCatalog = atoi(row[5]);
+           pdbr->AcceptAnyVolume = atoi(row[6]);
+           strcpy(pdbr->PoolType, row[7]);
+           if (row[8]) {
+              strcpy(pdbr->LabelFormat, row[8]);
+           } else {
+              pdbr->LabelFormat[0] = 0;
+           }
+           stat = pdbr->PoolId;
+        }
+      }
+      sql_free_result(mdb);
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+
+/* 
+ * Get the number of Media records
+ *
+ * Returns: -1 on failure
+ *         number on success
+ */
+int db_get_num_media_records(B_DB *mdb)
+{
+   int stat = 0;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "SELECT count(*) from Media");
+   stat = get_sql_record_max(mdb);
+   V(mdb->mutex);
+   return stat;
+}
+
+
+/*
+ * This function returns a list of all the Media record ids.
+ *  The caller must free ids if non-NULL.
+ *
+ *  Returns 0: on failure
+ *         1: on success
+ */
+int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t *ids[])
+{
+   SQL_ROW row;
+   int stat = 0;
+   int i = 0;
+   uint32_t *id;
+
+   P(mdb->mutex);
+   *ids = NULL;
+   Mmsg(&mdb->cmd, "SELECT MediaId FROM Media");
+   if (QUERY_DB(mdb, mdb->cmd)) {
+      *num_ids = sql_num_rows(mdb);
+      if (*num_ids > 0) {
+        id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t));
+        while ((row = sql_fetch_row(mdb)) != NULL) {
+           id[i++] = (uint32_t)atoi(row[0]);
+        }
+        *ids = id;
+      }
+      sql_free_result(mdb);
+      stat = 1;
+   } else {
+      Mmsg(&mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
+      stat = 0;
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+
+/* Get Media Record   
+ *
+ * Returns: 0 on failure
+ *         id on success 
+ */
+int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr)
+{
+   SQL_ROW row;
+   int stat = 0;
+
+   P(mdb->mutex);
+   if (mr->MediaId == 0 && mr->VolumeName[0] == 0) {
+      Mmsg(&mdb->cmd, "SELECT count(*) from Media");
+      mr->MediaId = get_sql_record_max(mdb);
+      V(mdb->mutex);
+      return 1;
+   }
+   if (mr->MediaId != 0) {              /* find by id */
+      Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
+VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\
+MediaType,VolStatus,PoolId \
+FROM Media WHERE MediaId=%d", mr->MediaId);
+   } else {                          /* find by name */
+      Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
+VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\
+MediaType,VolStatus,PoolId \
+FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName);
+   }  
+
+   if (QUERY_DB(mdb, mdb->cmd)) {
+      mdb->num_rows = sql_num_rows(mdb);
+      if (mdb->num_rows > 1) {
+         Mmsg1(&mdb->errmsg, _("More than one Volume!: %" lld "\n"), mdb->num_rows);
+        Emsg0(M_ERROR, 0, mdb->errmsg);
+      } else if (mdb->num_rows == 1) {
+        if ((row = sql_fetch_row(mdb)) == NULL) {
+            Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
+           Emsg0(M_ERROR, 0, mdb->errmsg);
+        } else {
+           /* return values */
+           mr->MediaId = atoi(row[0]);
+           strcpy(mr->VolumeName, row[1]);
+           mr->VolJobs = atoi(row[2]);
+           mr->VolFiles = atoi(row[3]);
+           mr->VolBlocks = atoi(row[4]);
+           mr->VolBytes = (uint64_t)strtod(row[5], NULL);
+           mr->VolMounts = atoi(row[6]);
+           mr->VolErrors = atoi(row[7]);
+           mr->VolWrites = atoi(row[8]);
+           mr->VolMaxBytes = (uint64_t)strtod(row[9], NULL);
+           mr->VolCapacityBytes = (uint64_t)strtod(row[10], NULL);
+           strcpy(mr->MediaType, row[11]);
+           strcpy(mr->VolStatus, row[12]);
+           mr->PoolId = atoi(row[13]);
+           stat = mr->MediaId;
+        }
+      }
+      sql_free_result(mdb);
+   }
+   V(mdb->mutex);
+   return stat;
+}
+
+
+#endif /* HAVE_MYSQL || HAVE_SQLITE */
diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c
new file mode 100644 (file)
index 0000000..a6757a8
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Bacula Catalog Database List records interface routines
+ * 
+ *    Kern Sibbald, March 2000
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#if    HAVE_MYSQL || HAVE_SQLITE
+
+/* -----------------------------------------------------------------------
+ *
+ *   Generic Routines (or almost generic)
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/* Imported subroutines */
+extern void list_result(B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx);
+extern int QueryDB(char *file, int line, B_DB *db, char *select_cmd);
+
+
+/* 
+ * Submit general SQL query
+ */
+int db_list_sql_query(B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, void *ctx)
+{
+   P(mdb->mutex);
+   if (sql_query(mdb, query) != 0) {
+      Mmsg(&mdb->errmsg, _("Query failed: %s\n"), sql_strerror(mdb));
+      sendit(ctx, mdb->errmsg);
+      V(mdb->mutex);
+      return 0;
+   }
+
+   mdb->result = sql_store_result(mdb);
+
+   if (mdb->result) {
+      list_result(mdb, sendit, ctx);
+      sql_free_result(mdb);
+   }
+   V(mdb->mutex);
+   return 1;
+}
+
+void
+db_list_pool_records(B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx) 
+{
+   Mmsg(&mdb->cmd, "SELECT PoolId,Name,NumVols,MaxVols,PoolType,LabelFormat \
+FROM Pool");
+
+   P(mdb->mutex);
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return;
+   }
+
+   list_result(mdb, sendit, ctx);
+   
+   sql_free_result(mdb);
+   V(mdb->mutex);
+}
+
+void
+db_list_media_records(B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, void *ctx)
+{
+
+   Mmsg(&mdb->cmd, "SELECT VolumeName,MediaType,VolStatus,\
+VolBytes,LastWritten \
+FROM Media WHERE Media.PoolId=%d ORDER BY MediaId", mdbr->PoolId);
+
+   P(mdb->mutex);
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return;
+   }
+
+   list_result(mdb, sendit, ctx);
+   
+   sql_free_result(mdb);
+   V(mdb->mutex);
+}
+
+void db_list_jobmedia_records(B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit, void *ctx)
+{
+   if (JobId > 0) {                  /* do by JobId */
+      Mmsg(&mdb->cmd, "SELECT JobId, Media.VolumeName, FirstIndex, LastIndex \
+FROM JobMedia, Media WHERE Media.MediaId=JobMedia.MediaId and JobMedia.JobId=%d", 
+          JobId);
+   } else {
+      Mmsg(&mdb->cmd, "SELECT JobId, Media.VolumeName, FirstIndex, LastIndex \
+FROM JobMedia, Media WHERE Media.MediaId=JobMedia.MediaId");
+   }
+
+   P(mdb->mutex);
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return;
+   }
+
+   list_result(mdb, sendit, ctx);
+   
+   sql_free_result(mdb);
+   V(mdb->mutex);
+}
+
+
+
+/*
+ * List Job record(s) that match JOB_DBR
+ *
+ *  Currently, we return all jobs or if jr->JobId is set,
+ *  only the job with the specified id.
+ */
+void
+db_list_job_records(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
+{
+
+   if (jr->JobId == 0 && jr->Job[0] == 0) {
+      Mmsg(&mdb->cmd, "SELECT JobId,Name,StartTime,Type,Level,\
+JobFiles,JobBytes,JobStatus FROM Job");
+   } else {                          /* single record */
+      Mmsg(&mdb->cmd, "SELECT JobId,Name,StartTime,Type,Level,\
+JobFiles,JobBytes,JobStatus FROM Job WHERE Job.JobId=%d", jr->JobId);
+   }
+
+   P(mdb->mutex);
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return;
+   }
+
+   list_result(mdb, sendit, ctx);
+   
+   sql_free_result(mdb);
+   V(mdb->mutex);
+}
+
+/*
+ * List Job totals
+ *
+ */
+void
+db_list_job_totals(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
+{
+
+
+   P(mdb->mutex);
+
+   /* List by Job */
+   Mmsg(&mdb->cmd, "SELECT  count(*) AS Jobs, sum(JobFiles) \
+AS Files, sum(JobBytes) AS Bytes, Name AS Job FROM Job GROUP BY Name");
+
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return;
+   }
+
+   list_result(mdb, sendit, ctx);
+   
+   sql_free_result(mdb);
+
+   /* Do Grand Total */
+   Mmsg(&mdb->cmd, "SELECT count(*) AS Jobs,sum(JobFiles) \
+AS Files,sum(JobBytes) As Bytes FROM Job");
+
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return;
+   }
+
+   list_result(mdb, sendit, ctx);
+   
+   sql_free_result(mdb);
+   V(mdb->mutex);
+}
+
+
+void
+db_list_files_for_job(B_DB *mdb, uint32_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
+{
+
+   Mmsg(&mdb->cmd, "SELECT Path.Path,Filename.Name FROM File,\
+Filename,Path WHERE File.JobId=%d and Filename.FilenameId=File.FilenameId \
+and Path.PathId=File.PathId",
+      jobid);
+
+   P(mdb->mutex);
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      V(mdb->mutex);
+      return;
+   }
+
+   list_result(mdb, sendit, ctx);
+   
+   sql_free_result(mdb);
+   V(mdb->mutex);
+}
+
+
+#endif /* HAVE_MYSQL || HAVE_SQLITE */
diff --git a/bacula/src/cats/sql_update.c b/bacula/src/cats/sql_update.c
new file mode 100644 (file)
index 0000000..4a2183a
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Bacula Catalog Database Update record interface routines
+ * 
+ *    Kern Sibbald, March 2000
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#if    HAVE_MYSQL || HAVE_SQLITE
+
+/* -----------------------------------------------------------------------
+ *
+ *   Generic Routines (or almost generic)
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/* Imported subroutines */
+extern void print_result(B_DB *mdb);
+extern int UpdateDB(char *file, int line, B_DB *db, char *update_cmd);
+
+static int do_update(B_DB *mdb, char *cmd)
+{
+   int stat;
+
+   stat = UPDATE_DB(mdb, cmd);
+   return stat;
+}
+
+/* -----------------------------------------------------------------------
+ *
+ *   Generic Routines (or almost generic)
+ *
+ * -----------------------------------------------------------------------
+ */
+/* Update the attributes record by adding the MD5 signature */
+int
+db_add_MD5_to_file_record(B_DB *mdb, FileId_t FileId, char *MD5)
+{
+   int stat;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "UPDATE File SET MD5=\"%s\" WHERE FileId=%d", MD5, FileId);
+   stat = UPDATE_DB(mdb, mdb->cmd);
+   V(mdb->mutex);
+   return stat;
+}
+
+/* Mark the file record as being visited during database
+ * verify compare. Stuff JobId into FileIndex field
+ */
+int db_mark_file_record(B_DB *mdb, FileId_t FileId, int JobId) 
+{
+   int stat;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "UPDATE File SET FileIndex=%d WHERE FileId=%d", JobId, FileId);
+   stat = UPDATE_DB(mdb, mdb->cmd);
+   V(mdb->mutex);
+   return stat;
+}
+
+/*
+ * Update the Job record at end of Job
+ *
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int
+db_update_job_start_record(B_DB *mdb, JOB_DBR *jr)
+{
+   char dt[MAX_TIME_LENGTH];
+   time_t stime;
+   struct tm tm;
+   int32_t StartDay;
+   int stat;
+       
+   stime = jr->StartTime;
+   localtime_r(&stime, &tm);
+   strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm);
+   StartDay = (int32_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) -
+       date_encode(2000, 1, 1));
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd, "UPDATE Job SET Level='%c', StartTime=\"%s\", \
+ClientId=%d, StartDay=%d WHERE JobId=%d",
+      (char)(jr->Level), dt, jr->ClientId, StartDay, jr->JobId);
+   stat = UPDATE_DB(mdb, mdb->cmd);
+   V(mdb->mutex);
+   return stat;
+}
+
+
+
+/*
+ * Update the Job record at end of Job
+ *
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int
+db_update_job_end_record(B_DB *mdb, JOB_DBR *jr)
+{
+   char dt[MAX_TIME_LENGTH];
+   time_t ttime;
+   struct tm tm;
+   int stat;
+       
+   ttime = jr->EndTime;
+   localtime_r(&ttime, &tm);
+   strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm);
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd,
+      "UPDATE Job SET JobStatus='%c', EndTime='%s', \
+ClientId=%d, JobBytes=%" lld ", JobFiles=%d, JobErrors=%d, VolSessionId=%d, \
+VolSessionTime=%d, PoolId=%d, FileSetId=%d WHERE JobId=%d",
+      (char)(jr->JobStatus), dt, jr->ClientId, jr->JobBytes, jr->JobFiles,
+      jr->JobErrors, jr->VolSessionId, jr->VolSessionTime, 
+      jr->PoolId, jr->FileSetId, jr->JobId);
+
+   stat = UPDATE_DB(mdb, mdb->cmd);
+   V(mdb->mutex);
+   return stat;
+}
+
+
+int
+db_update_pool_record(B_DB *mdb, POOL_DBR *pr)
+{
+   int stat;
+
+   P(mdb->mutex);
+   Mmsg(&mdb->cmd,
+"UPDATE Pool SET NumVols=%d, MaxVols=%d, UseOnce=%d, UseCatalog=%d, \
+AcceptAnyVolume=%d, LabelFormat=\"%s\" WHERE PoolId=%d",
+      pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog,
+      pr->AcceptAnyVolume, pr->LabelFormat, pr->PoolId);
+
+   stat = UPDATE_DB(mdb, mdb->cmd);
+   V(mdb->mutex);
+   return stat;
+}
+
+/* 
+ * Update the Media Record at end of Session
+ *
+ * Returns: 0 on failure
+ *         numrows on success
+ */
+int
+db_update_media_record(B_DB *mdb, MEDIA_DBR *mr) 
+{
+   char dt[MAX_TIME_LENGTH];
+   time_t ttime;
+   struct tm tm;
+   int stat;
+       
+   ttime = mr->LastWritten;
+   localtime_r(&ttime, &tm);
+   strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm);
+
+   P(mdb->mutex);
+   if (mr->VolMounts == 1) {
+      Mmsg(&mdb->cmd, "UPDATE Media SET FirstWritten=\"%s\" WHERE \
+         VolumeName=\"%s\"", dt, mr->VolumeName);
+      if (do_update(mdb, mdb->cmd) == 0) {
+        V(mdb->mutex);
+        return 0;
+      }
+   }
+
+   Mmsg(&mdb->cmd, "UPDATE Media SET VolJobs=%d,\
+ VolFiles=%d, VolBlocks=%d, VolBytes=%" lld ", VolMounts=%d, VolErrors=%d,\
+ VolWrites=%d, VolMaxBytes=%" lld ", LastWritten=\"%s\", VolStatus=\"%s\" \
+ WHERE VolumeName=\"%s\"",
+   mr->VolJobs, mr->VolFiles, mr->VolBlocks, mr->VolBytes, mr->VolMounts,
+   mr->VolErrors, mr->VolWrites, mr->VolMaxBytes, dt, mr->VolStatus,
+   mr->VolumeName);
+
+   stat = UPDATE_DB(mdb, mdb->cmd);
+   V(mdb->mutex);
+   return stat;
+}
+
+#endif /* HAVE_MYSQL || HAVE_SQLITE */
diff --git a/bacula/src/cats/sqlite.c b/bacula/src/cats/sqlite.c
new file mode 100644 (file)
index 0000000..b9a43ce
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * Bacula Catalog Database routines specific to SQLite
+ *
+ *    Kern Sibbald, January 2002
+ */
+
+/*
+   Copyright (C) 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C                      /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#ifdef HAVE_SQLITE
+
+/* -----------------------------------------------------------------------
+ *
+ *    SQLite dependent defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+extern char *working_directory;
+
+/* List of open databases */
+static BQUEUE db_list = {&db_list, &db_list};
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int QueryDB(char *file, int line, B_DB *db, char *select_cmd);
+
+
+/*
+ * Initialize database data structure. In principal this should
+ * never have errors, or it is really fatal.
+ */
+B_DB *
+db_init_database(char *db_name, char *db_user, char *db_password)
+{
+   B_DB *mdb;
+
+   P(mutex);                         /* lock DB queue */
+   /* Look to see if DB already open */
+   for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
+      if (strcmp(mdb->db_name, db_name) == 0) {
+         Dmsg2(100, "DB REopen %d %s\n", mdb->ref_count, db_name);
+        mdb->ref_count++;
+        V(mutex);
+        return mdb;                  /* already open */
+      }
+   }
+   Dmsg0(100, "db_open first time\n");
+   mdb = (B_DB *) malloc(sizeof(B_DB));
+   memset(mdb, 0, sizeof(B_DB));
+   mdb->db_name = bstrdup(db_name);
+   mdb->have_insert_id = TRUE; 
+   mdb->errmsg = (char *) get_pool_memory(PM_EMSG); /* get error message buffer */
+   *mdb->errmsg = 0;
+   mdb->cmd = (char *) get_pool_memory(PM_EMSG);    /* get command buffer */
+   mdb->ref_count = 1;
+   qinsert(&db_list, &mdb->bq);           /* put db in list */
+   V(mutex);
+   return mdb;
+}
+
+/*
+ * Now actually open the database.  This can generate errors,
+ * which are returned in the errmsg
+ */
+int
+db_open_database(B_DB *mdb)
+{
+   char *db_name;
+   int len;
+   struct stat statbuf;
+
+   P(mutex);
+   if (mdb->connected) {
+      V(mutex);
+      return 1;
+   }
+   mdb->connected = FALSE;
+   if (pthread_mutex_init(&mdb->mutex, NULL) != 0) {
+      Mmsg1(&mdb->errmsg, _("Unable to initialize DB mutex. ERR=%s\n"), strerror(errno));
+      V(mutex);
+      return 0;
+   }
+
+   /* open the database */
+   len = strlen(working_directory) + strlen(mdb->db_name) + 5; 
+   db_name = (char *)malloc(len);
+   strcpy(db_name, working_directory);
+   strcat(db_name, "/");
+   strcat(db_name, mdb->db_name);
+   strcat(db_name, ".db");
+   if (stat(db_name, &statbuf) != 0) {
+      Mmsg1(&mdb->errmsg, _("Database %s does not exist, please create it.\n"), 
+        db_name);
+      free(db_name);
+      V(mutex);
+      return 0;
+   }
+   mdb->db = sqlite_open(
+       db_name,                      /* database name */
+       644,                          /* mode */
+       &mdb->sqlite_errmsg);         /* error message */
+
+   Dmsg0(50, "sqlite_open\n");
+  
+   if (mdb->db == NULL) {
+      Mmsg2(&mdb->errmsg, _("Unable to open Database=%s. ERR=%s\n"),
+         db_name, mdb->sqlite_errmsg ? mdb->sqlite_errmsg : _("unknown"));
+      free(db_name);
+      V(mutex);
+      return 0;
+   }
+   free(db_name);
+   mdb->connected = TRUE;
+   V(mutex);
+   return 1;
+}
+
+void
+db_close_database(B_DB *mdb)
+{
+   P(mutex);
+   mdb->ref_count--;
+   if (mdb->ref_count == 0) {
+      qdchain(&mdb->bq);
+      if (mdb->connected && mdb->db) {
+        sqlite_close(mdb->db);
+      }
+      pthread_mutex_destroy(&mdb->mutex);
+      free_pool_memory(mdb->errmsg);
+      free_pool_memory(mdb->cmd);
+      if (mdb->db_name) {
+        free(mdb->db_name);
+      }
+      free(mdb);
+   }
+   V(mutex);
+}
+
+/*
+ * Return the next unique index (auto-increment) for
+ * the given table.  Return NULL on error.
+ */
+char *db_next_index(B_DB *mdb, char *table)
+{
+   SQL_ROW row;
+   static char id[20];
+
+   QUERY_DB(mdb, "BEGIN TRANSACTION");
+   sql_free_result(mdb);
+
+   Mmsg(&mdb->cmd,
+"SELECT id FROM NextId WHERE TableName=\"%s\"", table);
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      Mmsg(&mdb->errmsg, _("next_index query error: ERR=%s\n"), sql_strerror(mdb));
+      QUERY_DB(mdb, "ROLLBACK");
+      return NULL;
+   }
+   if ((row = sql_fetch_row(mdb)) == NULL) {
+      Mmsg(&mdb->errmsg, _("Error fetching index: ERR=%s\n"), sql_strerror(mdb));
+      QUERY_DB(mdb, "ROLLBACK");
+      return NULL;
+   }
+   strncpy(id, row[0], sizeof(id));
+   id[sizeof(id)-1] = 0;
+   sql_free_result(mdb);
+
+   Mmsg(&mdb->cmd,
+"UPDATE NextId SET id=id+1 WHERE TableName=\"%s\"", table);
+   if (!QUERY_DB(mdb, mdb->cmd)) {
+      Mmsg(&mdb->errmsg, _("next_index update error: ERR=%s\n"), sql_strerror(mdb));
+      QUERY_DB(mdb, "ROLLBACK");
+      return NULL;
+   }
+   sql_free_result(mdb);
+
+   QUERY_DB(mdb, "COMMIT");
+   sql_free_result(mdb);
+   return id;
+}   
+
+
+
+void
+db_escape_string(char *snew, char *old, int len)
+{
+   char *n, *o;
+
+   n = snew;
+   o = old;
+   while (len--) {
+      switch (*o) {
+      case '\'':
+         *n++ = '\\';
+         *n++ = '\'';
+        o++;
+        break;
+      case '"':
+         *n++ = '\\';
+         *n++ = '"';
+        o++;
+        break;
+      case 0:
+         *n++ = '\\';
+        *n++ = 0;
+        o++;
+        break;
+      default:
+        *n++ = *o++;
+        break;
+      }
+   }
+   *n = 0;
+}
+
+struct rh_data {
+   DB_RESULT_HANDLER *result_handler;
+   void *ctx;
+};
+
+/*  
+ * Convert SQLite's callback into Bacula DB callback  
+ */
+static int sqlite_result(void *arh_data, int num_fields, char **rows, char **col_names)
+{
+   struct rh_data *rh_data = (struct rh_data *)arh_data;   
+
+   if (rh_data->result_handler) {
+      (*(rh_data->result_handler))(rh_data->ctx, num_fields, rows);
+   }
+   return 0;
+}
+
+/*
+ * Submit a general SQL command (cmd), and for each row returned,
+ *  the sqlite_handler is called with the ctx.
+ */
+int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
+{
+   struct rh_data rh_data;
+   int stat;
+
+   P(mdb->mutex);
+   if (mdb->sqlite_errmsg) {
+      actuallyfree(mdb->sqlite_errmsg);
+      mdb->sqlite_errmsg = NULL;
+   }
+   rh_data.result_handler = result_handler;
+   rh_data.ctx = ctx;
+   stat = sqlite_exec(mdb->db, query, sqlite_result, (void *)&rh_data, &mdb->sqlite_errmsg);
+   if (stat != 0) {
+      Mmsg(&mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror(mdb));
+      V(mdb->mutex);
+      return 0;
+   }
+   V(mdb->mutex);
+   return 1;
+}
+
+/*
+ * Submit a sqlite query and retrieve all the data
+ */
+int my_sqlite_query(B_DB *mdb, char *cmd) 
+{
+   int stat;
+
+   if (mdb->sqlite_errmsg) {
+      actuallyfree(mdb->sqlite_errmsg);
+      mdb->sqlite_errmsg = NULL;
+   }
+   stat = sqlite_get_table(mdb->db, cmd, &mdb->result, &mdb->nrow, &mdb->ncolumn,
+           &mdb->sqlite_errmsg);
+   mdb->row = 0;                     /* row fetched */
+   return stat;
+}
+
+/* Fetch one row at a time */
+SQL_ROW my_sqlite_fetch_row(B_DB *mdb)
+{
+   if (mdb->row >= mdb->nrow) {
+      return NULL;
+   }
+   mdb->row++;
+   return &mdb->result[mdb->ncolumn * mdb->row];
+}
+
+void my_sqlite_free_table(B_DB *mdb)
+{
+   unsigned int i;
+
+   if (mdb->fields_defined) {
+      for (i=0; i < sql_num_fields(mdb); i++) {
+        free(mdb->fields[i]);
+      }
+      free(mdb->fields);
+      mdb->fields_defined = FALSE;
+   }
+   sqlite_free_table(mdb->result);
+   mdb->nrow = mdb->ncolumn = 0; 
+}
+
+void my_sqlite_field_seek(B_DB *mdb, int field)
+{
+   unsigned int i, j;
+   if (mdb->result == NULL) {
+      return;
+   }
+   /* On first call, set up the fields */
+   if (!mdb->fields_defined && sql_num_fields(mdb) > 0) {
+      mdb->fields = (SQL_FIELD **)malloc(sizeof(SQL_FIELD) * mdb->ncolumn);
+      for (i=0; i < sql_num_fields(mdb); i++) {
+        mdb->fields[i] = (SQL_FIELD *)malloc(sizeof(SQL_FIELD));
+        mdb->fields[i]->name = mdb->result[i];
+        mdb->fields[i]->length = strlen(mdb->fields[i]->name);
+        mdb->fields[i]->max_length = mdb->fields[i]->length;
+        for (j=1; j <= (unsigned)mdb->nrow; j++) {
+           uint32_t len;
+           if (mdb->result[i + mdb->ncolumn *j]) {
+              len = (uint32_t)strlen(mdb->result[i + mdb->ncolumn * j]);
+           } else {
+              len = 0;
+           }
+           if (len > mdb->fields[i]->max_length) {
+              mdb->fields[i]->max_length = len;
+           }
+        }
+        mdb->fields[i]->type = 0;
+        mdb->fields[i]->flags = 1;        /* not null */
+      }
+      mdb->fields_defined = TRUE;
+   }
+   if (field > (int)sql_num_fields(mdb)) {
+      field = (int)sql_num_fields(mdb);
+    }
+    mdb->field = field;
+
+}
+
+SQL_FIELD *my_sqlite_fetch_field(B_DB *mdb)
+{
+   return mdb->fields[mdb->field++];
+}
+
+static void
+list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
+{
+   SQL_FIELD *field;
+   unsigned int i, j;
+
+   sql_field_seek(mdb, 0);
+   send(ctx, "+");
+   for (i = 0; i < sql_num_fields(mdb); i++) {
+      field = sql_fetch_field(mdb);
+      for (j = 0; j < field->max_length + 2; j++)
+              send(ctx, "-");
+      send(ctx, "+");
+   }
+   send(ctx, "\n");
+}
+
+void
+list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
+{
+   SQL_FIELD *field;
+   SQL_ROW row;
+   unsigned int i, col_len;
+   char buf[2000], ewc[30];
+
+   if (mdb->result == NULL || mdb->nrow == 0) {
+      return;
+   }
+   /* determine column display widths */
+   sql_field_seek(mdb, 0);
+   for (i = 0; i < sql_num_fields(mdb); i++) {
+      field = sql_fetch_field(mdb);
+      if (IS_NUM(field->type) && field->max_length > 0) { /* fixup for commas */
+        field->max_length += (field->max_length - 1) / 3;
+      }
+      col_len = strlen(field->name);
+      if (col_len < field->max_length)
+             col_len = field->max_length;
+      if (col_len < 4 && !IS_NOT_NULL(field->flags))
+              col_len = 4;    /* 4 = length of the word "NULL" */
+      field->max_length = col_len;    /* reset column info */
+   }
+
+   list_dashes(mdb, send, ctx);
+   send(ctx, "|");
+   sql_field_seek(mdb, 0);
+   for (i = 0; i < sql_num_fields(mdb); i++) {
+      field = sql_fetch_field(mdb);
+      sprintf(buf, " %-*s |", field->max_length, field->name);
+      send(ctx, buf);
+   }
+   send(ctx, "\n");
+   list_dashes(mdb, send, ctx);
+
+   while ((row = sql_fetch_row(mdb)) != NULL) {
+      sql_field_seek(mdb, 0);
+      send(ctx, "|");
+      for (i = 0; i < sql_num_fields(mdb); i++) {
+        field = sql_fetch_field(mdb);
+        if (row[i] == NULL) {
+            sprintf(buf, " %-*s |", field->max_length, "NULL");
+        } else if (IS_NUM(field->type)) {
+            sprintf(buf, " %*s |", field->max_length,       
+              add_commas(row[i], ewc));
+        } else {
+            sprintf(buf, " %-*s |", field->max_length, row[i]);
+        }
+        send(ctx, buf);
+      }
+      send(ctx, "\n");
+   }
+   list_dashes(mdb, send, ctx);
+}
+
+
+#endif /* HAVE_SQLITE */
diff --git a/bacula/src/cats/sqlite.in b/bacula/src/cats/sqlite.in
new file mode 100644 (file)
index 0000000..63c2ba2
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+#
+# shell script to invoke SQLite on Bacula database
+
+@bindir@/sqlite @working_dir@/bacula.db
diff --git a/bacula/src/console.glade b/bacula/src/console.glade
new file mode 100644 (file)
index 0000000..e0ba071
--- /dev/null
@@ -0,0 +1,1271 @@
+<?xml version="1.0"?>
+<GTK-Interface>
+
+<project>
+  <name>Console</name>
+  <program_name>gnome-console</program_name>
+  <directory></directory>
+  <source_directory>gnome-console</source_directory>
+  <pixmaps_directory></pixmaps_directory>
+  <language>C</language>
+  <gnome_support>True</gnome_support>
+  <gettext_support>True</gettext_support>
+  <output_main_file>False</output_main_file>
+  <output_support_files>False</output_support_files>
+  <output_build_files>False</output_build_files>
+</project>
+
+<widget>
+  <class>GnomeAbout</class>
+  <name>about</name>
+  <visible>False</visible>
+  <modal>True</modal>
+  <copyright>Copyright (c) 1999 - 2002, Kern Sibbald and John Walker</copyright>
+  <authors>Kern Sibbald and John Walker
+</authors>
+  <comments>It comes by night and sucks the essence from your computers.</comments>
+</widget>
+
+<widget>
+  <class>GnomeMessageBox</class>
+  <name>messagebox1</name>
+  <message_box_type>GNOME_MESSAGE_BOX_INFO</message_box_type>
+  <message>Message</message>
+  <title>Information</title>
+  <position>GTK_WIN_POS_NONE</position>
+  <modal>False</modal>
+  <allow_shrink>False</allow_shrink>
+  <allow_grow>False</allow_grow>
+  <auto_shrink>False</auto_shrink>
+  <auto_close>True</auto_close>
+  <hide_on_close>False</hide_on_close>
+
+  <widget>
+    <class>GtkVBox</class>
+    <child_name>GnomeDialog:vbox</child_name>
+    <name>dialog-vbox1</name>
+    <homogeneous>False</homogeneous>
+    <spacing>8</spacing>
+    <child>
+      <padding>4</padding>
+      <expand>True</expand>
+      <fill>True</fill>
+    </child>
+
+    <widget>
+      <class>GtkHButtonBox</class>
+      <child_name>GnomeDialog:action_area</child_name>
+      <name>dialog-action_area1</name>
+      <layout_style>GTK_BUTTONBOX_END</layout_style>
+      <spacing>8</spacing>
+      <child_min_width>85</child_min_width>
+      <child_min_height>27</child_min_height>
+      <child_ipad_x>7</child_ipad_x>
+      <child_ipad_y>0</child_ipad_y>
+      <child>
+       <padding>0</padding>
+       <expand>False</expand>
+       <fill>True</fill>
+       <pack>GTK_PACK_END</pack>
+      </child>
+
+      <widget>
+       <class>GtkButton</class>
+       <name>button4</name>
+       <can_default>True</can_default>
+       <can_focus>True</can_focus>
+       <stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
+      </widget>
+    </widget>
+  </widget>
+</widget>
+
+<widget>
+  <class>GnomeDialog</class>
+  <name>SelectDirectorDialog</name>
+  <title>Select Director</title>
+  <type>GTK_WINDOW_TOPLEVEL</type>
+  <position>GTK_WIN_POS_NONE</position>
+  <modal>True</modal>
+  <allow_shrink>False</allow_shrink>
+  <allow_grow>True</allow_grow>
+  <auto_shrink>False</auto_shrink>
+  <auto_close>False</auto_close>
+  <hide_on_close>False</hide_on_close>
+
+  <widget>
+    <class>GtkVBox</class>
+    <child_name>GnomeDialog:vbox</child_name>
+    <name>dialog-vbox2</name>
+    <homogeneous>False</homogeneous>
+    <spacing>1</spacing>
+    <child>
+      <padding>0</padding>
+      <expand>True</expand>
+      <fill>True</fill>
+    </child>
+
+    <widget>
+      <class>GtkHButtonBox</class>
+      <child_name>GnomeDialog:action_area</child_name>
+      <name>dialog-action_area2</name>
+      <layout_style>GTK_BUTTONBOX_END</layout_style>
+      <spacing>8</spacing>
+      <child_min_width>85</child_min_width>
+      <child_min_height>27</child_min_height>
+      <child_ipad_x>7</child_ipad_x>
+      <child_ipad_y>0</child_ipad_y>
+      <child>
+       <padding>0</padding>
+       <expand>False</expand>
+       <fill>True</fill>
+       <pack>GTK_PACK_END</pack>
+      </child>
+
+      <widget>
+       <class>GtkButton</class>
+       <name>button11</name>
+       <can_default>True</can_default>
+       <can_focus>True</can_focus>
+       <signal>
+         <name>clicked</name>
+         <handler>on_select_director_clicked</handler>
+         <last_modification_time>Sun, 17 Mar 2002 21:07:26 GMT</last_modification_time>
+       </signal>
+       <stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
+      </widget>
+
+      <widget>
+       <class>GtkButton</class>
+       <name>button13</name>
+       <can_default>True</can_default>
+       <can_focus>True</can_focus>
+       <stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
+      </widget>
+    </widget>
+
+    <widget>
+      <class>GtkVBox</class>
+      <name>vbox4</name>
+      <homogeneous>False</homogeneous>
+      <spacing>0</spacing>
+      <child>
+       <padding>0</padding>
+       <expand>True</expand>
+       <fill>True</fill>
+      </child>
+
+      <widget>
+       <class>GtkLabel</class>
+       <name>label20</name>
+       <label>Select Director</label>
+       <justify>GTK_JUSTIFY_CENTER</justify>
+       <wrap>False</wrap>
+       <xalign>0.5</xalign>
+       <yalign>0.5</yalign>
+       <xpad>0</xpad>
+       <ypad>0</ypad>
+       <child>
+         <padding>3</padding>
+         <expand>False</expand>
+         <fill>False</fill>
+       </child>
+      </widget>
+
+      <widget>
+       <class>GtkHBox</class>
+       <name>hbox10</name>
+       <homogeneous>False</homogeneous>
+       <spacing>0</spacing>
+       <child>
+         <padding>0</padding>
+         <expand>True</expand>
+         <fill>True</fill>
+       </child>
+
+       <widget>
+         <class>GtkCombo</class>
+         <name>combo1</name>
+         <value_in_list>False</value_in_list>
+         <ok_if_empty>True</ok_if_empty>
+         <case_sensitive>False</case_sensitive>
+         <use_arrows>True</use_arrows>
+         <use_arrows_always>False</use_arrows_always>
+         <items></items>
+         <child>
+           <padding>0</padding>
+           <expand>True</expand>
+           <fill>True</fill>
+         </child>
+
+         <widget>
+           <class>GtkEntry</class>
+           <child_name>GtkCombo:entry</child_name>
+           <name>combo-entry9</name>
+           <can_focus>True</can_focus>
+           <editable>True</editable>
+           <text_visible>True</text_visible>
+           <text_max_length>0</text_max_length>
+           <text></text>
+         </widget>
+       </widget>
+      </widget>
+    </widget>
+  </widget>
+</widget>
+
+<widget>
+  <class>GnomeDialog</class>
+  <name>RunDialog</name>
+  <title>Run a Job</title>
+  <type>GTK_WINDOW_TOPLEVEL</type>
+  <position>GTK_WIN_POS_NONE</position>
+  <modal>True</modal>
+  <allow_shrink>False</allow_shrink>
+  <allow_grow>False</allow_grow>
+  <auto_shrink>False</auto_shrink>
+  <auto_close>False</auto_close>
+  <hide_on_close>False</hide_on_close>
+
+  <widget>
+    <class>GtkVBox</class>
+    <child_name>GnomeDialog:vbox</child_name>
+    <name>dialog-vbox4</name>
+    <homogeneous>False</homogeneous>
+    <spacing>8</spacing>
+    <child>
+      <padding>4</padding>
+      <expand>True</expand>
+      <fill>True</fill>
+    </child>
+
+    <widget>
+      <class>GtkHButtonBox</class>
+      <child_name>GnomeDialog:action_area</child_name>
+      <name>dialog-action_area4</name>
+      <layout_style>GTK_BUTTONBOX_END</layout_style>
+      <spacing>8</spacing>
+      <child_min_width>85</child_min_width>
+      <child_min_height>27</child_min_height>
+      <child_ipad_x>7</child_ipad_x>
+      <child_ipad_y>0</child_ipad_y>
+      <child>
+       <padding>0</padding>
+       <expand>False</expand>
+       <fill>True</fill>
+       <pack>GTK_PACK_END</pack>
+      </child>
+
+      <widget>
+       <class>GtkButton</class>
+       <name>button17</name>
+       <can_default>True</can_default>
+       <can_focus>True</can_focus>
+       <stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
+      </widget>
+
+      <widget>
+       <class>GtkButton</class>
+       <name>button19</name>
+       <can_default>True</can_default>
+       <can_focus>True</can_focus>
+       <stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
+      </widget>
+    </widget>
+
+    <widget>
+      <class>GtkVBox</class>
+      <name>vbox5</name>
+      <homogeneous>False</homogeneous>
+      <spacing>0</spacing>
+      <child>
+       <padding>0</padding>
+       <expand>True</expand>
+       <fill>True</fill>
+      </child>
+
+      <widget>
+       <class>GtkLabel</class>
+       <name>label24</name>
+       <label>Run a Job</label>
+       <justify>GTK_JUSTIFY_CENTER</justify>
+       <wrap>False</wrap>
+       <xalign>0.5</xalign>
+       <yalign>0.5</yalign>
+       <xpad>0</xpad>
+       <ypad>9</ypad>
+       <child>
+         <padding>2</padding>
+         <expand>False</expand>
+         <fill>False</fill>
+       </child>
+      </widget>
+
+      <widget>
+       <class>GtkHBox</class>
+       <name>hbox11</name>
+       <homogeneous>False</homogeneous>
+       <spacing>0</spacing>
+       <child>
+         <padding>2</padding>
+         <expand>False</expand>
+         <fill>False</fill>
+       </child>
+
+       <widget>
+         <class>GtkHBox</class>
+         <name>hbox12</name>
+         <homogeneous>False</homogeneous>
+         <spacing>0</spacing>
+         <child>
+           <padding>0</padding>
+           <expand>True</expand>
+           <fill>True</fill>
+         </child>
+
+         <widget>
+           <class>GtkLabel</class>
+           <name>label25</name>
+           <width>70</width>
+           <label>Job:</label>
+           <justify>GTK_JUSTIFY_RIGHT</justify>
+           <wrap>False</wrap>
+           <xalign>0.5</xalign>
+           <yalign>0.5</yalign>
+           <xpad>0</xpad>
+           <ypad>0</ypad>
+           <child>
+             <padding>0</padding>
+             <expand>False</expand>
+             <fill>False</fill>
+           </child>
+         </widget>
+
+         <widget>
+           <class>GtkCombo</class>
+           <name>combo9</name>
+           <value_in_list>False</value_in_list>
+           <ok_if_empty>True</ok_if_empty>
+           <case_sensitive>False</case_sensitive>
+           <use_arrows>True</use_arrows>
+           <use_arrows_always>False</use_arrows_always>
+           <items></items>
+           <child>
+             <padding>1</padding>
+             <expand>True</expand>
+             <fill>True</fill>
+           </child>
+
+           <widget>
+             <class>GtkEntry</class>
+             <child_name>GtkCombo:entry</child_name>
+             <name>entry2</name>
+             <can_focus>True</can_focus>
+             <editable>True</editable>
+             <text_visible>True</text_visible>
+             <text_max_length>0</text_max_length>
+             <text></text>
+           </widget>
+         </widget>
+
+         <widget>
+           <class>GtkLabel</class>
+           <name>label26</name>
+           <label>   Type:</label>
+           <justify>GTK_JUSTIFY_CENTER</justify>
+           <wrap>False</wrap>
+           <xalign>0.5</xalign>
+           <yalign>0.5</yalign>
+           <xpad>0</xpad>
+           <ypad>0</ypad>
+           <child>
+             <padding>0</padding>
+             <expand>False</expand>
+             <fill>False</fill>
+           </child>
+         </widget>
+
+         <widget>
+           <class>GtkCombo</class>
+           <name>combo10</name>
+           <width>131</width>
+           <value_in_list>False</value_in_list>
+           <ok_if_empty>True</ok_if_empty>
+           <case_sensitive>False</case_sensitive>
+           <use_arrows>True</use_arrows>
+           <use_arrows_always>False</use_arrows_always>
+           <items></items>
+           <child>
+             <padding>6</padding>
+             <expand>False</expand>
+             <fill>False</fill>
+           </child>
+
+           <widget>
+             <class>GtkEntry</class>
+             <child_name>GtkCombo:entry</child_name>
+             <name>entry3</name>
+             <width>127</width>
+             <can_focus>True</can_focus>
+             <editable>True</editable>
+             <text_visible>True</text_visible>
+             <text_max_length>0</text_max_length>
+             <text></text>
+           </widget>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label27</name>
+         <label> </label>
+         <justify>GTK_JUSTIFY_CENTER</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>30</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+      </widget>
+
+      <widget>
+       <class>GtkHBox</class>
+       <name>hbox13</name>
+       <homogeneous>False</homogeneous>
+       <spacing>0</spacing>
+       <child>
+         <padding>0</padding>
+         <expand>True</expand>
+         <fill>True</fill>
+       </child>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label28</name>
+         <width>70</width>
+         <label>Client:</label>
+         <justify>GTK_JUSTIFY_RIGHT</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>0</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+
+       <widget>
+         <class>GtkCombo</class>
+         <name>combo11</name>
+         <width>236</width>
+         <value_in_list>False</value_in_list>
+         <ok_if_empty>True</ok_if_empty>
+         <case_sensitive>False</case_sensitive>
+         <use_arrows>True</use_arrows>
+         <use_arrows_always>False</use_arrows_always>
+         <items></items>
+         <child>
+           <padding>1</padding>
+           <expand>True</expand>
+           <fill>True</fill>
+         </child>
+
+         <widget>
+           <class>GtkEntry</class>
+           <child_name>GtkCombo:entry</child_name>
+           <name>entry4</name>
+           <can_focus>True</can_focus>
+           <editable>True</editable>
+           <text_visible>True</text_visible>
+           <text_max_length>0</text_max_length>
+           <text></text>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label29</name>
+         <label> </label>
+         <justify>GTK_JUSTIFY_CENTER</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>123</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+      </widget>
+
+      <widget>
+       <class>GtkHBox</class>
+       <name>hbox14</name>
+       <homogeneous>False</homogeneous>
+       <spacing>0</spacing>
+       <child>
+         <padding>2</padding>
+         <expand>True</expand>
+         <fill>True</fill>
+       </child>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label30</name>
+         <width>70</width>
+         <label>FileSet: </label>
+         <justify>GTK_JUSTIFY_RIGHT</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>0</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+
+       <widget>
+         <class>GtkCombo</class>
+         <name>combo12</name>
+         <value_in_list>False</value_in_list>
+         <ok_if_empty>True</ok_if_empty>
+         <case_sensitive>False</case_sensitive>
+         <use_arrows>True</use_arrows>
+         <use_arrows_always>False</use_arrows_always>
+         <items></items>
+         <child>
+           <padding>0</padding>
+           <expand>True</expand>
+           <fill>True</fill>
+         </child>
+
+         <widget>
+           <class>GtkEntry</class>
+           <child_name>GtkCombo:entry</child_name>
+           <name>entry5</name>
+           <can_focus>True</can_focus>
+           <editable>True</editable>
+           <text_visible>True</text_visible>
+           <text_max_length>0</text_max_length>
+           <text></text>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkButton</class>
+         <name>button20</name>
+         <height>12</height>
+         <can_focus>True</can_focus>
+         <label>  View FileSet  </label>
+         <relief>GTK_RELIEF_NORMAL</relief>
+         <child>
+           <padding>10</padding>
+           <expand>False</expand>
+           <fill>True</fill>
+         </child>
+       </widget>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label31</name>
+         <label>  </label>
+         <justify>GTK_JUSTIFY_CENTER</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>65</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+      </widget>
+
+      <widget>
+       <class>GtkHBox</class>
+       <name>hbox15</name>
+       <homogeneous>False</homogeneous>
+       <spacing>0</spacing>
+       <child>
+         <padding>2</padding>
+         <expand>True</expand>
+         <fill>True</fill>
+       </child>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label32</name>
+         <width>70</width>
+         <label>Level:</label>
+         <justify>GTK_JUSTIFY_RIGHT</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>0</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+
+       <widget>
+         <class>GtkCombo</class>
+         <name>combo13</name>
+         <value_in_list>False</value_in_list>
+         <ok_if_empty>True</ok_if_empty>
+         <case_sensitive>False</case_sensitive>
+         <use_arrows>True</use_arrows>
+         <use_arrows_always>False</use_arrows_always>
+         <items></items>
+         <child>
+           <padding>0</padding>
+           <expand>True</expand>
+           <fill>True</fill>
+         </child>
+
+         <widget>
+           <class>GtkEntry</class>
+           <child_name>GtkCombo:entry</child_name>
+           <name>entry6</name>
+           <can_focus>True</can_focus>
+           <editable>True</editable>
+           <text_visible>True</text_visible>
+           <text_max_length>0</text_max_length>
+           <text></text>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label33</name>
+         <label>             </label>
+         <justify>GTK_JUSTIFY_CENTER</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>100</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+      </widget>
+
+      <widget>
+       <class>GtkHBox</class>
+       <name>hbox16</name>
+       <homogeneous>False</homogeneous>
+       <spacing>0</spacing>
+       <child>
+         <padding>2</padding>
+         <expand>True</expand>
+         <fill>True</fill>
+       </child>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label34</name>
+         <width>70</width>
+         <label>Messages: </label>
+         <justify>GTK_JUSTIFY_CENTER</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>0</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+
+       <widget>
+         <class>GtkCombo</class>
+         <name>combo14</name>
+         <value_in_list>False</value_in_list>
+         <ok_if_empty>True</ok_if_empty>
+         <case_sensitive>False</case_sensitive>
+         <use_arrows>True</use_arrows>
+         <use_arrows_always>False</use_arrows_always>
+         <items></items>
+         <child>
+           <padding>0</padding>
+           <expand>True</expand>
+           <fill>True</fill>
+         </child>
+
+         <widget>
+           <class>GtkEntry</class>
+           <child_name>GtkCombo:entry</child_name>
+           <name>entry7</name>
+           <can_focus>True</can_focus>
+           <editable>True</editable>
+           <text_visible>True</text_visible>
+           <text_max_length>0</text_max_length>
+           <text></text>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label35</name>
+         <label>   </label>
+         <justify>GTK_JUSTIFY_CENTER</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>120</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+      </widget>
+
+      <widget>
+       <class>GtkHBox</class>
+       <name>hbox17</name>
+       <homogeneous>False</homogeneous>
+       <spacing>0</spacing>
+       <child>
+         <padding>2</padding>
+         <expand>True</expand>
+         <fill>True</fill>
+       </child>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label36</name>
+         <width>70</width>
+         <label>Where: </label>
+         <justify>GTK_JUSTIFY_CENTER</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>0</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+
+       <widget>
+         <class>GtkCombo</class>
+         <name>combo15</name>
+         <value_in_list>False</value_in_list>
+         <ok_if_empty>True</ok_if_empty>
+         <case_sensitive>False</case_sensitive>
+         <use_arrows>True</use_arrows>
+         <use_arrows_always>False</use_arrows_always>
+         <items></items>
+         <child>
+           <padding>0</padding>
+           <expand>True</expand>
+           <fill>True</fill>
+         </child>
+
+         <widget>
+           <class>GtkEntry</class>
+           <child_name>GtkCombo:entry</child_name>
+           <name>entry8</name>
+           <can_focus>True</can_focus>
+           <editable>True</editable>
+           <text_visible>True</text_visible>
+           <text_max_length>0</text_max_length>
+           <text></text>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label37</name>
+         <label>      </label>
+         <justify>GTK_JUSTIFY_CENTER</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>114</padding>
+           <expand>False</expand>
+           <fill>False</fill>
+         </child>
+       </widget>
+      </widget>
+    </widget>
+  </widget>
+</widget>
+
+<widget>
+  <class>GtkWindow</class>
+  <name>app1</name>
+  <signal>
+    <name>delete_event</name>
+    <handler>on_app1_delete_event</handler>
+    <last_modification_time>Mon, 01 Apr 2002 07:29:22 GMT</last_modification_time>
+  </signal>
+  <signal>
+    <name>show</name>
+    <handler>on_app1_show</handler>
+    <last_modification_time>Mon, 01 Apr 2002 07:29:16 GMT</last_modification_time>
+  </signal>
+  <title>Bacula Console</title>
+  <type>GTK_WINDOW_TOPLEVEL</type>
+  <position>GTK_WIN_POS_NONE</position>
+  <modal>False</modal>
+  <allow_shrink>True</allow_shrink>
+  <allow_grow>True</allow_grow>
+  <auto_shrink>False</auto_shrink>
+
+  <widget>
+    <class>GtkVBox</class>
+    <name>vbox6</name>
+    <homogeneous>False</homogeneous>
+    <spacing>0</spacing>
+
+    <widget>
+      <class>GtkHandleBox</class>
+      <name>handlebox1</name>
+      <border_width>1</border_width>
+      <shadow_type>GTK_SHADOW_OUT</shadow_type>
+      <handle_position>GTK_POS_LEFT</handle_position>
+      <snap_edge>GTK_POS_TOP</snap_edge>
+      <child>
+       <padding>0</padding>
+       <expand>False</expand>
+       <fill>True</fill>
+      </child>
+
+      <widget>
+       <class>GtkMenuBar</class>
+       <name>menubar1</name>
+       <shadow_type>GTK_SHADOW_NONE</shadow_type>
+
+       <widget>
+         <class>GtkMenuItem</class>
+         <name>file1</name>
+         <stock_item>GNOMEUIINFO_MENU_FILE_TREE</stock_item>
+
+         <widget>
+           <class>GtkMenu</class>
+           <name>file1_menu</name>
+
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>connect1</name>
+             <tooltip>Connect to Director</tooltip>
+             <signal>
+               <name>activate</name>
+               <handler>on_connect_activate</handler>
+               <last_modification_time>Wed, 20 Mar 2002 10:21:09 GMT</last_modification_time>
+             </signal>
+             <label>_Connect</label>
+             <right_justify>False</right_justify>
+           </widget>
+
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>disconnect1</name>
+             <tooltip>Disconnect from Director</tooltip>
+             <signal>
+               <name>activate</name>
+               <handler>on_disconnect_activate</handler>
+               <last_modification_time>Wed, 20 Mar 2002 10:15:45 GMT</last_modification_time>
+             </signal>
+             <label>_Disconnect</label>
+             <right_justify>False</right_justify>
+           </widget>
+
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>menuitem4</name>
+             <right_justify>False</right_justify>
+           </widget>
+
+           <widget>
+             <class>GtkPixmapMenuItem</class>
+             <name>exit1</name>
+             <signal>
+               <name>activate</name>
+               <handler>on_exit_activate</handler>
+               <last_modification_time>Wed, 20 Mar 2002 10:24:55 GMT</last_modification_time>
+             </signal>
+             <stock_item>GNOMEUIINFO_MENU_EXIT_ITEM</stock_item>
+           </widget>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkMenuItem</class>
+         <name>edit1</name>
+         <stock_item>GNOMEUIINFO_MENU_EDIT_TREE</stock_item>
+
+         <widget>
+           <class>GtkMenu</class>
+           <name>edit1_menu</name>
+
+           <widget>
+             <class>GtkPixmapMenuItem</class>
+             <name>cut1</name>
+             <signal>
+               <name>activate</name>
+               <handler>on_cut1_activate</handler>
+               <last_modification_time>Sat, 16 Mar 2002 21:48:15 GMT</last_modification_time>
+             </signal>
+             <stock_item>GNOMEUIINFO_MENU_CUT_ITEM</stock_item>
+           </widget>
+
+           <widget>
+             <class>GtkPixmapMenuItem</class>
+             <name>copy1</name>
+             <signal>
+               <name>activate</name>
+               <handler>on_copy1_activate</handler>
+               <last_modification_time>Sat, 16 Mar 2002 21:48:15 GMT</last_modification_time>
+             </signal>
+             <stock_item>GNOMEUIINFO_MENU_COPY_ITEM</stock_item>
+           </widget>
+
+           <widget>
+             <class>GtkPixmapMenuItem</class>
+             <name>paste1</name>
+             <signal>
+               <name>activate</name>
+               <handler>on_paste1_activate</handler>
+               <last_modification_time>Sat, 16 Mar 2002 21:48:15 GMT</last_modification_time>
+             </signal>
+             <stock_item>GNOMEUIINFO_MENU_PASTE_ITEM</stock_item>
+           </widget>
+
+           <widget>
+             <class>GtkPixmapMenuItem</class>
+             <name>clear1</name>
+             <signal>
+               <name>activate</name>
+               <handler>on_clear1_activate</handler>
+               <last_modification_time>Sat, 16 Mar 2002 21:48:15 GMT</last_modification_time>
+             </signal>
+             <stock_item>GNOMEUIINFO_MENU_CLEAR_ITEM</stock_item>
+           </widget>
+
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>separator1</name>
+             <right_justify>False</right_justify>
+           </widget>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkMenuItem</class>
+         <name>item1</name>
+         <tooltip>Display Messages</tooltip>
+         <stock_item>GNOMEUIINFO_MENU_VIEW_TREE</stock_item>
+
+         <widget>
+           <class>GtkMenu</class>
+           <name>item1_menu</name>
+
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>msgs</name>
+             <signal>
+               <name>activate</name>
+               <handler>on_msgs_activate</handler>
+               <last_modification_time>Wed, 20 Mar 2002 09:57:22 GMT</last_modification_time>
+             </signal>
+             <label>_Display Messages</label>
+             <right_justify>False</right_justify>
+           </widget>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkMenuItem</class>
+         <name>settings1</name>
+         <stock_item>GNOMEUIINFO_MENU_SETTINGS_TREE</stock_item>
+
+         <widget>
+           <class>GtkMenu</class>
+           <name>settings1_menu</name>
+
+           <widget>
+             <class>GtkPixmapMenuItem</class>
+             <name>preferences1</name>
+             <signal>
+               <name>activate</name>
+               <handler>on_preferences1_activate</handler>
+               <last_modification_time>Sat, 16 Mar 2002 21:48:15 GMT</last_modification_time>
+             </signal>
+             <stock_item>GNOMEUIINFO_MENU_PREFERENCES_ITEM</stock_item>
+           </widget>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkMenuItem</class>
+         <name>help1</name>
+         <stock_item>GNOMEUIINFO_MENU_HELP_TREE</stock_item>
+
+         <widget>
+           <class>GtkMenu</class>
+           <name>help1_menu</name>
+
+           <widget>
+             <class>GtkPixmapMenuItem</class>
+             <name>about1</name>
+             <signal>
+               <name>activate</name>
+               <handler>on_about_activate</handler>
+               <last_modification_time>Wed, 20 Mar 2002 10:19:17 GMT</last_modification_time>
+             </signal>
+             <stock_item>GNOMEUIINFO_MENU_ABOUT_ITEM</stock_item>
+           </widget>
+         </widget>
+       </widget>
+      </widget>
+    </widget>
+
+    <widget>
+      <class>GtkHandleBox</class>
+      <name>handlebox2</name>
+      <border_width>1</border_width>
+      <shadow_type>GTK_SHADOW_OUT</shadow_type>
+      <handle_position>GTK_POS_LEFT</handle_position>
+      <snap_edge>GTK_POS_TOP</snap_edge>
+      <child>
+       <padding>0</padding>
+       <expand>False</expand>
+       <fill>True</fill>
+      </child>
+
+      <widget>
+       <class>GtkToolbar</class>
+       <name>toolbar2</name>
+       <border_width>1</border_width>
+       <orientation>GTK_ORIENTATION_HORIZONTAL</orientation>
+       <type>GTK_TOOLBAR_BOTH</type>
+       <space_size>16</space_size>
+       <space_style>GTK_TOOLBAR_SPACE_LINE</space_style>
+       <relief>GTK_RELIEF_NONE</relief>
+       <tooltips>True</tooltips>
+
+       <widget>
+         <class>GtkButton</class>
+         <child_name>Toolbar:button</child_name>
+         <name>connect_button1</name>
+         <tooltip>Connect to Director</tooltip>
+         <signal>
+           <name>clicked</name>
+           <handler>on_connect_button_clicked</handler>
+           <last_modification_time>Wed, 20 Mar 2002 10:18:40 GMT</last_modification_time>
+         </signal>
+         <label>Connect</label>
+         <stock_pixmap>GNOME_STOCK_PIXMAP_NEW</stock_pixmap>
+       </widget>
+
+       <widget>
+         <class>GtkButton</class>
+         <child_name>Toolbar:button</child_name>
+         <name>run_button1</name>
+         <tooltip>Run a Job</tooltip>
+         <signal>
+           <name>clicked</name>
+           <handler>on_run_button_clicked</handler>
+           <last_modification_time>Wed, 20 Mar 2002 10:13:42 GMT</last_modification_time>
+         </signal>
+         <label>Run</label>
+         <stock_pixmap>GNOME_STOCK_PIXMAP_EXEC</stock_pixmap>
+       </widget>
+
+       <widget>
+         <class>GtkButton</class>
+         <child_name>Toolbar:button</child_name>
+         <name>msgs_button</name>
+         <tooltip>Display Messages</tooltip>
+         <signal>
+           <name>clicked</name>
+           <handler>on_msgs_button_clicked</handler>
+           <last_modification_time>Tue, 19 Mar 2002 20:32:44 GMT</last_modification_time>
+         </signal>
+         <label>Msgs</label>
+         <stock_pixmap>GNOME_STOCK_PIXMAP_SEARCH</stock_pixmap>
+       </widget>
+      </widget>
+    </widget>
+
+    <widget>
+      <class>GtkVBox</class>
+      <name>vbox7</name>
+      <homogeneous>False</homogeneous>
+      <spacing>0</spacing>
+      <child>
+       <padding>0</padding>
+       <expand>True</expand>
+       <fill>True</fill>
+      </child>
+
+      <widget>
+       <class>GtkScrolledWindow</class>
+       <name>scrolledwindow3</name>
+       <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy>
+       <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy>
+       <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy>
+       <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy>
+       <child>
+         <padding>0</padding>
+         <expand>True</expand>
+         <fill>True</fill>
+       </child>
+
+       <widget>
+         <class>GtkText</class>
+         <name>text1</name>
+         <editable>False</editable>
+         <text></text>
+       </widget>
+      </widget>
+
+      <widget>
+       <class>GtkHBox</class>
+       <name>hbox18</name>
+       <homogeneous>False</homogeneous>
+       <spacing>0</spacing>
+       <child>
+         <padding>0</padding>
+         <expand>False</expand>
+         <fill>True</fill>
+       </child>
+
+       <widget>
+         <class>GtkLabel</class>
+         <name>label38</name>
+         <label> Command: </label>
+         <justify>GTK_JUSTIFY_CENTER</justify>
+         <wrap>False</wrap>
+         <xalign>0.5</xalign>
+         <yalign>0.5</yalign>
+         <xpad>0</xpad>
+         <ypad>0</ypad>
+         <child>
+           <padding>0</padding>
+           <expand>False</expand>
+           <fill>True</fill>
+         </child>
+       </widget>
+
+       <widget>
+         <class>GtkEntry</class>
+         <name>entry1</name>
+         <tooltip>Enter Commands Here</tooltip>
+         <can_default>True</can_default>
+         <has_default>True</has_default>
+         <can_focus>True</can_focus>
+         <has_focus>True</has_focus>
+         <signal>
+           <name>key_press_event</name>
+           <handler>on_entry1_key_press_event</handler>
+           <last_modification_time>Mon, 01 Apr 2002 07:32:11 GMT</last_modification_time>
+         </signal>
+         <editable>True</editable>
+         <text_visible>True</text_visible>
+         <text_max_length>0</text_max_length>
+         <text></text>
+         <child>
+           <padding>0</padding>
+           <expand>True</expand>
+           <fill>True</fill>
+         </child>
+       </widget>
+      </widget>
+
+      <widget>
+       <class>GtkHBox</class>
+       <name>hbox19</name>
+       <homogeneous>False</homogeneous>
+       <spacing>0</spacing>
+       <child>
+         <padding>0</padding>
+         <expand>False</expand>
+         <fill>True</fill>
+       </child>
+
+       <widget>
+         <class>GtkFrame</class>
+         <name>frame1</name>
+         <width>66</width>
+         <label_xalign>0</label_xalign>
+         <shadow_type>GTK_SHADOW_IN</shadow_type>
+         <child>
+           <padding>0</padding>
+           <expand>False</expand>
+           <fill>True</fill>
+         </child>
+
+         <widget>
+           <class>GtkLabel</class>
+           <name>label39</name>
+           <label> Status: </label>
+           <justify>GTK_JUSTIFY_CENTER</justify>
+           <wrap>False</wrap>
+           <xalign>0.5</xalign>
+           <yalign>0.5</yalign>
+           <xpad>0</xpad>
+           <ypad>0</ypad>
+         </widget>
+       </widget>
+
+       <widget>
+         <class>GtkFrame</class>
+         <name>frame2</name>
+         <label_xalign>0</label_xalign>
+         <shadow_type>GTK_SHADOW_IN</shadow_type>
+         <child>
+           <padding>0</padding>
+           <expand>True</expand>
+           <fill>True</fill>
+         </child>
+
+         <widget>
+           <class>GtkLabel</class>
+           <name>status1</name>
+           <label></label>
+           <justify>GTK_JUSTIFY_LEFT</justify>
+           <wrap>False</wrap>
+           <xalign>0</xalign>
+           <yalign>0.5</yalign>
+           <xpad>0</xpad>
+           <ypad>0</ypad>
+         </widget>
+       </widget>
+      </widget>
+    </widget>
+  </widget>
+</widget>
+
+</GTK-Interface>
diff --git a/bacula/src/console/Makefile.in b/bacula/src/console/Makefile.in
new file mode 100644 (file)
index 0000000..f061bcd
--- /dev/null
@@ -0,0 +1,97 @@
+@MCOMMON@
+
+srcdir =       .
+VPATH =        .
+.PATH:         .
+
+# one up
+basedir = ..
+# top dir
+topdir = ../..
+# this dir relative to top dir
+thisdir = src/console
+
+DEBUG=@DEBUG@
+
+first_rule: all
+dummy:
+
+#
+CONSSRCS = console.c console_conf.c authenticate.c
+CONSOBJS = console.o console_conf.o authenticate.o
+
+# these are the objects that are changed by the .configure process
+EXTRAOBJS = @OBJLIST@
+
+CONS_INC=@CONS_INC@
+CONS_LIBS=@CONS_LIBS@
+CONS_LDFLAGS=@CONS_LDFLAGS@
+
+.SUFFIXES:     .c .o
+.PHONY:
+.DONTCARE:
+
+# inference rules
+.c.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) $(CONS_INC) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
+#-------------------------------------------------------------------------
+all: Makefile console
+       @echo "==== Make of console is good ===="
+       @echo " "
+
+
+console: $(CONSOBJS) ../lib/libbac.a ../cats/libsql.a
+       $(CXX) $(LDFLAGS) $(CONS_LDFLAGS) -L../lib -L../cats -o $@ $(CONSOBJS) \
+             $(LIBS) $(DLIB) $(CONS_LIBS) -lbac -lsql -lm -ltermcap
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+clean:
+       $(RMF) console core core.* a.out *.o *.bak *~ *.intpro *.extpro 1 2 3
+
+realclean: clean
+       $(RMF) tags console.conf
+
+distclean: realclean
+       if test $(srcdir) = .; then $(MAKE) realclean; fi
+       (cd $(srcdir); $(RMF) Makefile)
+
+install: all
+       $(INSTALL_SCRIPT) console $(DESTDIR)$(sbindir)/console
+       @srcconf=console.conf; \
+       if  test -f ${DESTDIR}${sysconfdir}/$$srcconf; then \
+          destconf=$$srcconf.new; \
+          echo "  ==> Found existing $$srcconf, installing new conf file as $$destconf"; \
+       else \
+          destconf=$$srcconf; \
+       fi; \
+       echo "${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf"; \
+       ${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf
+
+uninstall:
+       (cd $(DESTDIR)$(sbindir); $(RMF) console)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) console.conf
+
+
+
+# Semi-automatic generation of dependencies:
+# Use gcc -MM because X11 `makedepend' doesn't work on all systems
+# and it also includes system headers.
+# `semi'-automatic since dependencies are generated at distribution time.
+
+depend:
+       @$(MV) Makefile Makefile.bak
+       @$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile
+       @$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile
+       @$(CC) -S -M $(CPPFLAGS) $(XINC) -I$(srcdir) -I$(basedir) $(SQL_INC) *.c >> Makefile
+       @if test -f Makefile ; then \
+           $(RMF) Makefile.bak; \
+       else \
+          $(MV) Makefile.bak Makefile; \
+          echo -e "Something went wrong\n\a"; \
+       fi
+
+# -----------------------------------------------------------------------
+# DO NOT DELETE: nice dependency list follows
diff --git a/bacula/src/console/authenticate.c b/bacula/src/console/authenticate.c
new file mode 100644 (file)
index 0000000..72a0651
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *
+ *   Bacula UA authentication. Provides authentication with
+ *     the Director.
+ *
+ *     Kern Sibbald, June MMI
+ *
+ *    This routine runs as a thread and must be thread reentrant.
+ *
+ *  Basic tasks done here:
+ *
+ */
+/*
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+ */
+
+#include "bacula.h"
+#include "console_conf.h"
+#include "jcr.h"
+
+
+/* Commands sent to Director */
+static char hello[]    = "Hello %s calling\n";
+
+/* Response from Director */
+static char OKhello[]   = "1000 OK:";
+
+/* Forward referenced functions */
+
+/*
+ * Authenticate Director
+ */
+int authenticate_director(JCR *jcr, DIRRES *director)
+{
+   BSOCK *dir = jcr->dir_bsock;
+
+   /* 
+    * Send my name to the Director then do authentication
+    */
+   bnet_fsend(dir, hello, "UserAgent");
+
+   if (!cram_md5_get_auth(dir, director->password) || 
+       !cram_md5_auth(dir, director->password)) {
+      Dmsg0(-1, "Director authorization problem.\n");
+      return 0;
+   }
+
+   Dmsg1(6, ">dird: %s", dir->msg);
+   if (bnet_recv(dir) <= 0) {
+      Dmsg1(-1, "Bad response to Hello command: ERR=%s\n",
+        bnet_strerror(dir));
+      Dmsg0(-1, "The Director is probably not running.\n");
+      return 0;
+   }
+   Dmsg1(10, "<dird: %s", dir->msg);
+   if (strncmp(dir->msg, OKhello, sizeof(OKhello)-1) != 0) {
+      Dmsg0(-1, "Director rejected Hello command\n");
+      return 0;
+   } else {
+      Dmsg1(-1, "%s", dir->msg);
+   }
+   return 1;
+}
diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c
new file mode 100644 (file)
index 0000000..8929df6
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ *
+ *   Bacula Console interface to the Director
+ *
+ *     Kern Sibbald, September MM
+ */
+
+/*
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+ */
+
+#include <termios.h>
+#include "bacula.h"
+#include "console_conf.h"
+#include "jcr.h"
+
+/* Imported functions */
+int authenticate_director(JCR *jcr, DIRRES *director);
+
+       
+/* Exported variables */
+
+
+#ifdef HAVE_CYGWIN
+int rl_catch_signals;
+#else
+extern int rl_catch_signals;
+#endif
+
+/* Forward referenced functions */
+static void terminate_console(int sig);
+int get_cmd(char *prompt, BSOCK *sock, int sec);
+
+/* Static variables */
+static char *configfile = NULL;
+static BSOCK *UA_sock = NULL;
+static DIRRES *dir; 
+
+#define CONFIG_FILE "./console.conf"   /* default configuration file */
+
+static void usage()
+{
+   fprintf(stderr,
+"\nVersion: " VERSION " (" DATE ")\n\n"
+"Usage: console [-s] [-c config_file] [-d debug_level] [config_file]\n"
+"       -c <file>   set configuration file to file\n"
+"       -dnn        set debug level to nn\n"
+"       -s          no signals\n"
+"       -t          test - read configuration and exit\n"
+"       -?          print this message.\n"  
+"\n");
+
+   exit(1);
+}
+
+
+/*********************************************************************
+ *
+ *        Main Bacula Console -- User Interface Program
+ *
+ */
+int main(int argc, char *argv[])
+{
+   int ch, stat, i, ndir, item;
+   int no_signals = FALSE;
+   int test_config = FALSE;
+   JCR jcr;
+   char *prompt = "*";
+   int at_prompt = FALSE;
+
+   init_stack_dump();
+   my_name_is(argc, argv, "console");
+   working_directory = "/tmp";
+
+   /*
+    * Ensure that every message is always printed
+    */
+   for (i=1; i<=M_MAX; i++) {
+      add_msg_dest(MD_STDOUT, i, NULL, NULL);
+   }
+
+
+   while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
+      switch (ch) {
+         case 'c':                    /* configuration file */
+           if (configfile != NULL)
+              free(configfile);
+           configfile = bstrdup(optarg);
+           break;
+
+         case 'd':
+           debug_level = atoi(optarg);
+           if (debug_level <= 0)
+              debug_level = 1;
+           break;
+
+         case 's':                    /* turn off signals */
+           no_signals = TRUE;
+           break;
+
+         case 't':
+           test_config = TRUE;
+           break;
+
+         case '?':
+        default:
+           usage();
+
+      }  
+   }
+   argc -= optind;
+   argv += optind;
+
+   if (!no_signals) {
+      init_signals(terminate_console);
+   }
+   signal(SIGCHLD, SIG_IGN);
+
+   if (argc) {
+      usage();
+   }
+
+   if (configfile == NULL) {
+      configfile = bstrdup(CONFIG_FILE);
+   }
+
+   parse_config(configfile);
+
+   LockRes();
+   ndir = 0;
+   for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
+      ndir++;
+   }
+   UnlockRes();
+   if (ndir == 0) {
+      Emsg1(M_ABORT, 0, "No director resource defined in %s\n\
+Without that I don't how to speak to the Director :-(\n", configfile);
+   }
+
+   if (test_config) {
+      terminate_console(0);
+      exit(0);
+   }
+
+   memset(&jcr, 0, sizeof(jcr));
+
+   if (ndir > 1) {
+      UA_sock = init_bsock(0, "", "", 0);
+try_again:
+      printf("Available Directors:\n");
+      LockRes();
+      ndir = 0;
+      for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
+         printf("%d  %s at %s:%d\n", 1+ndir++, dir->hdr.name, dir->address,
+           dir->DIRport);
+      }
+      UnlockRes();
+      if (get_cmd("Select Director: ", UA_sock, 600) < 0) {
+        return 1;
+      }
+      item = atoi(UA_sock->msg);
+      if (item < 0 || item > ndir) {
+         printf("You must enter a number between 1 and %d\n", ndir);
+        goto try_again;
+      }
+      LockRes();
+      dir = NULL;
+      for (i=0; i<item; i++) {
+        dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
+      }
+      UnlockRes();
+      term_bsock(UA_sock);
+   } else {
+      LockRes();
+      dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
+      UnlockRes();
+   }
+      
+
+   Dmsg2(-1, "Connecting to Director %s:%d\n", dir->address,dir->DIRport);
+   UA_sock = bnet_connect(&jcr, 5, 15, "Director daemon", dir->address, 
+                         NULL, dir->DIRport, 0);
+   if (UA_sock == NULL) {
+      terminate_console(0);
+      return 1;
+   }
+   jcr.dir_bsock = UA_sock;
+   if (!authenticate_director(&jcr, dir)) {
+      printf("ERR: %s", UA_sock->msg);
+      terminate_console(0);
+      return 1;
+   }
+
+   Dmsg0(40, "Opened connection with Director daemon\n");
+
+   for ( ;; ) { 
+      if (at_prompt) {                /* don't prompt multiple times */
+         prompt = "";
+      } else {
+         prompt = "*";
+        at_prompt = TRUE;
+      }
+      stat = get_cmd(prompt, UA_sock, 30);
+      if (stat < 0) { 
+        break;                       /* error */
+      } else if (stat == 0) {        /* timeout */
+         bnet_fsend(UA_sock, ".messages");
+      } else {
+        at_prompt = FALSE;
+        if (!bnet_send(UA_sock)) {   /* send command */
+           break;                    /* error */
+        }
+      }
+      if (strcmp(UA_sock->msg, "quit") == 0 || strcmp(UA_sock->msg, "exit") == 0) {
+        break;
+      }
+      while ((stat = bnet_recv(UA_sock)) > 0) {
+        if (at_prompt) {
+            printf("\n");
+           at_prompt = FALSE;
+        }
+         printf("%s", UA_sock->msg);
+      }
+      fflush(stdout);
+      if (stat < 0) {
+        break;                       /* error */
+      } else if (stat == 0) {
+        if (UA_sock->msglen == BNET_PROMPT) {
+           at_prompt = TRUE;
+        }
+         Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
+      }
+   }
+   if (UA_sock) {
+      bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
+      bnet_close(UA_sock);
+   }
+
+   terminate_console(0);
+   return 0;
+}
+
+
+/* Cleanup and then exit */
+static void terminate_console(int sig)
+{
+   static int already_here = FALSE;
+
+   if (already_here)                 /* avoid recursive temination problems */
+      exit(1);
+   already_here = TRUE;
+   exit(0);
+}
+
+#ifdef HAVE_READLINE
+#undef free
+#include "readline/readline.h"
+#include "readline/history.h"
+
+int 
+get_cmd(char *prompt, BSOCK *sock, int sec)
+{
+   char *line;
+
+   rl_catch_signals = 1;
+   line = readline(prompt);
+
+   if (!line) {
+      exit(1);
+   }
+   strcpy(sock->msg, line);
+   strip_trailing_junk(sock->msg);
+   sock->msglen = strlen(sock->msg);
+   if (sock->msglen) {
+      add_history(sock->msg);
+   }
+   free(line);
+   return 1;
+}
+
+#else /* no readline, do it ourselves */
+
+/*
+ *   Returns: 1 if data available
+ *           0 if timeout
+ *          -1 if error
+ */
+static int
+wait_for_data(int fd, int sec)
+{
+   fd_set fdset;
+   struct timeval tv;
+
+   FD_ZERO(&fdset);
+   FD_SET(fd, &fdset);
+   tv.tv_sec = sec;
+   tv.tv_usec = 0;
+   for ( ;; ) {
+      switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
+        case 0:                         /* timeout */
+           return 0;
+        case -1:
+           if (errno == EINTR || errno == EAGAIN) {
+              continue;
+           }
+           return -1;                  /* error return */
+        default:
+           return 1;
+      }
+   }
+}
+
+/*     
+ * Get next input command from terminal. 
+ *
+ *   Returns: 1 if got input
+ *           0 if timeout
+ *          -1 if EOF or error
+ */
+int 
+get_cmd(char *prompt, BSOCK *sock, int sec)
+{
+   fprintf(stdout, prompt);
+   fflush(stdout);
+   switch (wait_for_data(fileno(stdin), sec)) {
+      case 0:
+        return 0;                    /* timeout */
+      case -1: 
+        return -1;                   /* error */
+      default:
+        if (fgets(sock->msg, 200, stdin) == NULL) {
+           return -1;
+        }
+        break;
+   }
+   strip_trailing_junk(sock->msg);
+   sock->msglen = strlen(sock->msg);
+   return 1;
+}
+
+#endif
diff --git a/bacula/src/console/console_conf.c b/bacula/src/console/console_conf.c
new file mode 100644 (file)
index 0000000..fc5284c
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *   Main configuration file parser for Bacula User Agent
+ *    some parts may be split into separate files such as
+ *    the schedule configuration (sch_config.c).
+ *
+ *   Note, the configuration file parser consists of three parts
+ *
+ *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
+ *
+ *   2. The generic config  scanner in lib/parse_config.c and 
+ *     lib/parse_config.h.
+ *     These files contain the parser code, some utility
+ *     routines, and the common store routines (name, int,
+ *     string).
+ *
+ *   3. The daemon specific file, which contains the Resource
+ *     definitions as well as any specific store routines
+ *     for the resource records.
+ *
+ *     Kern Sibbald, January MM, September MM
+ */
+
+/*
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+ */
+
+#include "bacula.h"
+#include "console_conf.h"
+
+/* Define the first and last resource ID record
+ * types. Note, these should be unique for each
+ * daemon though not a requirement.
+ */
+int r_first = R_FIRST;
+int r_last  = R_LAST;
+pthread_mutex_t res_mutex =  PTHREAD_MUTEX_INITIALIZER;
+
+/* Forward referenced subroutines */
+
+
+/* We build the current resource here as we are
+ * scanning the resource configuration definition,
+ * then move it to allocated memory when the resource
+ * scan is complete.
+ */
+URES res_all;
+int  res_all_size = sizeof(res_all);
+
+/* Definition of records permitted within each
+ * resource with the routine to process the record 
+ * information.
+ */ 
+static struct res_items dir_items[] = {
+   {"name",        store_name,     ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str,      ITEM(res_dir.hdr.desc), 0, 0, 0},
+   {"dirport",     store_int,      ITEM(res_dir.DIRport),  0, ITEM_REQUIRED, 0},
+   {"address",     store_str,      ITEM(res_dir.address),  0, ITEM_REQUIRED, 0},
+   {"password",    store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* 
+ * This is the master resource definition.  
+ * It must have one item for each of the resources.
+ */
+struct s_res resources[] = {
+   {"director",      dir_items,   R_DIRECTOR,  NULL},
+   {NULL,           NULL,        0,           NULL}
+};
+
+
+/* Dump contents of resource */
+void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...), void *sock)
+{
+   URES *res = (URES *)reshdr;
+   int recurse = 1;
+
+   if (res == NULL) {
+      printf("No record for %d %s\n", type, res_to_str(type));
+      return;
+   }
+   if (type < 0) {                   /* no recursion */
+      type = - type;
+      recurse = 0;
+   }
+   switch (type) {
+      case R_DIRECTOR:
+         printf("Director: name=%s address=%s DIRport=%d\n", reshdr->name, 
+                res->res_dir.address, res->res_dir.DIRport);
+        break;
+      default:
+         printf("Unknown resource type %d\n", type);
+   }
+   if (recurse && res->res_dir.hdr.next) {
+      dump_resource(type, res->res_dir.hdr.next, sendit, sock);
+   }
+}
+
+/* 
+ * Free memory of resource.  
+ * NB, we don't need to worry about freeing any references
+ * to other resources as they will be freed when that 
+ * resource chain is traversed.  Mainly we worry about freeing
+ * allocated strings (names).
+ */
+void free_resource(int type)
+{
+   URES *res;
+   RES *nres;
+   int rindex = type - r_first;
+
+   res = (URES *)resources[rindex].res_head;
+
+   if (res == NULL)
+      return;
+
+   /* common stuff -- free the resource name */
+   nres = (RES *)res->res_dir.hdr.next;
+   if (res->res_dir.hdr.name)
+      free(res->res_dir.hdr.name);
+   if (res->res_dir.hdr.desc)
+      free(res->res_dir.hdr.desc);
+
+   switch (type) {
+      case R_DIRECTOR:
+        if (res->res_dir.address)
+           free(res->res_dir.address);
+        break;
+      default:
+         printf("Unknown resource type %d\n", type);
+   }
+   /* Common stuff again -- free the resource, recurse to next one */
+   free(res);
+   resources[rindex].res_head = nres;
+   if (nres)
+      free_resource(type);
+}
+
+/* Save the new resource by chaining it into the head list for
+ * the resource. If this is pass 2, we update any resource
+ * pointers (currently only in the Job resource).
+ */
+void save_resource(int type, struct res_items *items, int pass)
+{
+   URES *res;
+   int rindex = type - r_first;
+   int i, size;
+   int error = 0;
+
+   /* 
+    * Ensure that all required items are present
+    */
+   for (i=0; items[i].name; i++) {
+      if (items[i].flags & ITEM_REQUIRED) {
+           if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {  
+               Emsg2(M_ABORT, 0, "%s item is required in %s resource, but not found.\n",
+                items[i].name, resources[rindex]);
+            }
+      }
+   }
+
+   /* During pass 2, we looked up pointers to all the resources
+    * referrenced in the current resource, , now we
+    * must copy their address from the static record to the allocated
+    * record.
+    */
+   if (pass == 2) {
+      switch (type) {
+        /* Resources not containing a resource */
+        case R_DIRECTOR:
+           break;
+
+        default:
+            Emsg1(M_ERROR, 0, "Unknown resource type %d\n", type);
+           error = 1;
+           break;
+      }
+      /* Note, the resoure name was already saved during pass 1,
+       * so here, we can just release it.
+       */
+      if (res_all.res_dir.hdr.name) {
+        free(res_all.res_dir.hdr.name);
+        res_all.res_dir.hdr.name = NULL;
+      }
+      if (res_all.res_dir.hdr.desc) {
+        free(res_all.res_dir.hdr.desc);
+        res_all.res_dir.hdr.desc = NULL;
+      }
+      return;
+   }
+
+   switch (type) {
+      case R_DIRECTOR:
+        size = sizeof(DIRRES);
+        break;
+      default:
+         printf("Unknown resource type %d\n", type);
+        error = 1;
+        break;
+   }
+   /* Common */
+   if (!error) {
+      res = (URES *) malloc(size);
+      memcpy(res, &res_all, size);
+      res->res_dir.hdr.next = resources[rindex].res_head;
+      resources[rindex].res_head = (RES *)res;
+      Dmsg1(90, "dir_conf: inserting res: %s\n", res->res_dir.hdr.name);
+   }
+
+}
diff --git a/bacula/src/console/console_conf.h b/bacula/src/console/console_conf.h
new file mode 100644 (file)
index 0000000..04fdc7b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Bacula User Agent specific configuration and defines
+ *
+ *     Kern Sibbald, Sep MM
+ */
+
+/*
+ * Resource codes -- they must be sequential for indexing   
+ */
+#define R_FIRST                       1001
+
+#define R_DIRECTOR                    1001
+
+#define R_LAST                        R_DIRECTOR
+
+/*
+ * Some resource attributes
+ */
+#define R_NAME                        1020
+#define R_ADDRESS                     1021
+#define R_PASSWORD                    1022
+#define R_TYPE                        1023
+#define R_BACKUP                      1024
+
+
+/* Definition of the contents of each Resource */
+struct s_res_dir {
+   RES   hdr;
+   int   DIRport;                     /* UA server port */
+   char *address;                     /* UA server address */
+   char *password;                    /* UA server password */
+};
+typedef struct s_res_dir DIRRES;
+
+
+/* Define the Union of all the above
+ * resource structure definitions.
+ */
+union u_res {
+   struct s_res_dir     res_dir;
+   RES hdr;
+};
+
+typedef union u_res URES;
diff --git a/bacula/src/count-doc b/bacula/src/count-doc
new file mode 100755 (executable)
index 0000000..94a93ec
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+rm -f 1
+touch 1
+for i in ../doc/html-manual; do
+  ls -1 $i/*.html >>1
+done
+cat 1 | lines
+rm -f 1
diff --git a/bacula/src/count-lines b/bacula/src/count-lines
new file mode 100755 (executable)
index 0000000..5f545b0
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+rm -f 1
+touch 1
+for i in . console gnome-console cats dird filed findlib lib stored; do
+  ls -1 $i/*.c $i/*.h $i/*.in >>1
+done
+cat 1 | lines
+# rm -f 1
diff --git a/bacula/src/dird/Makefile.in b/bacula/src/dird/Makefile.in
new file mode 100644 (file)
index 0000000..699d0a8
--- /dev/null
@@ -0,0 +1,121 @@
+#
+#  Bacula Director Makefile
+#  
+@MCOMMON@
+
+srcdir =       .
+VPATH =        .
+.PATH:         .
+
+# one up
+basedir = ..
+# top dir
+topdir = ../..
+# this dir relative to top dir
+thisdir = src/dird
+
+DEBUG=@DEBUG@
+
+first_rule: all
+dummy:
+
+#
+SVRSRCS = dird.c authenticate.c backup.c catreq.c dird_conf.c \
+         fd_cmds.c getmsg.c job.c \
+         mountreq.c msgchan.c newvol.c run_conf.c restore.c \
+         scheduler.c ua_cmds.c \
+         ua_dotcmds.c \
+         ua_db_query.c ua_retention.c \
+         ua_input.c ua_output.c ua_run.c \
+         ua_select.c ua_server.c \
+         ua_status.c verify.c
+SVROBJS = dird.o authenticate.o backup.o catreq.o dird_conf.o \
+         fd_cmds.o getmsg.o job.o \
+         mountreq.o msgchan.o newvol.o run_conf.o restore.o \
+         scheduler.o ua_cmds.o \
+         ua_dotcmds.o \
+         ua_db_query.o ua_retention.o \
+         ua_input.o ua_output.o ua_run.o \
+         ua_select.o ua_server.o \
+         ua_status.o verify.o
+
+# these are the objects that are changed by the .configure process
+EXTRAOBJS = @OBJLIST@
+
+.SUFFIXES:     .c .o
+.PHONY:
+.DONTCARE:
+
+# inference rules
+.c.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
+#-------------------------------------------------------------------------
+all: Makefile bacula-dir
+       @echo "==== Make of dird is good ===="
+       @echo " "
+
+bacula-dir:  $(SVROBJS) ../lib/libbac.a ../cats/libsql.a
+       $(CXX) $(LDFLAGS) -L../lib -L../cats -o $@ $(SVROBJS) \
+             -lsql $(LIBS) $(DLIB) -lbac -lm
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+clean:
+       @$(RMF) dird bacula-dir core core.* a.out *.o *.bak *~ *.intpro *.extpro 1 2 3
+
+realclean: clean
+       @$(RMF) tags bacula-dir.conf
+
+distclean: realclean
+       if test $(srcdir) = .; then $(MAKE) realclean; fi
+       (cd $(srcdir); $(RMF) Makefile)
+
+install: all
+       $(INSTALL_PROGRAM) bacula-dir $(DESTDIR)$(sbindir)/bacula-dir
+       @srcconf=bacula-dir.conf; \
+       if  test -f ${DESTDIR}${sysconfdir}/$$srcconf; then \
+          destconf=$$srcconf.new; \
+          echo "  ==> Found existing $$srcconf, installing new conf file as $$destconf"; \
+       else \
+          destconf=$$srcconf; \
+       fi; \
+       echo "${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf"; \
+       ${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf
+       @srcconf=query.sql; \
+       if  test -f ${DESTDIR}${sysconfdir}/$$srcconf; then \
+          destconf=$$srcconf.new; \
+          echo "  ==> Found existing $$srcconf, installing new conf file as $$destconf"; \
+       else \
+          destconf=$$srcconf; \
+       fi; \
+       echo "${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf"; \
+       ${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf
+
+
+uninstall:
+       (cd $(DESTDIR)$(sbindir); $(RMF) bacula-dir)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) bacula-dir.conf)
+
+
+
+# Semi-automatic generation of dependencies:
+# Use gcc -MM because X11 `makedepend' doesn't work on all systems
+# and it also includes system headers.
+# `semi'-automatic since dependencies are generated at distribution time.
+
+depend:
+       @$(MV) Makefile Makefile.bak
+       @$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile
+       @$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile
+       @$(CC) -S -M $(CPPFLAGS) $(XINC) -I$(srcdir) -I$(basedir) $(SQL_INC) *.c >> Makefile
+       @if test -f Makefile ; then \
+           $(RMF) Makefile.bak; \
+       else \
+          $(MV) Makefile.bak Makefile; \
+          echo -e "Something went wrong\n\a"; \
+       fi
+
+# -----------------------------------------------------------------------
+# DO NOT DELETE: nice dependency list follows
diff --git a/bacula/src/dird/README-config b/bacula/src/dird/README-config
new file mode 100644 (file)
index 0000000..b3ae34f
--- /dev/null
@@ -0,0 +1,134 @@
+
+To add a new resource -- as an example, the BAZ resource,
+  which will have foo record which is an integer,    
+  a storage record, which is the name of a storage
+  resource, and a special time field.
+
+ 1. Define the Resource type (R_xxx) in dir_config.h
+    Be sure to update the R_LAST define.
+     #define R_BAZ 1011
+     update R_LAST to be R_BAZ
+
+ 2. Add a new definition of the resource in dir_config.h
+    The first three are mandatory (will soon be changed
+    to a header structure).
+    struct s_res_baz {
+       char * name;
+       int rcode
+       struct s_res_baz *next;
+
+       int foo;
+       struct res_store *storage;
+       int time;
+    };
+
+ 3. In dir_config.c add the new resource to the table
+    of resources (resources[])
+
+    {"baz",     baz_items,  R_BAZ,  NULL},
+
+ 4. Create a baz_items, which defines the records that
+    can appear within the BAZ resource:
+
+    static struct res_items bas_items[] = {
+        name,   store sub,   where to store,   extra info
+       {"name", store_name, ITEM(res_baz.name), 0},    /* manditory */
+       {"foo",  store_int,  ITEM(res_baz.foo), 0}, 
+       {"storage", stor_res, ITEM(res_baz.storage), 0},
+       {"time",  store_time, ITME(res_baz.time), 0},
+    };
+
+ 5. Update the dump_resource() subroutine to handle printing
+    your resource.
+
+ 6. Update the free_resource() subroutine to handle releasing
+    any allocated memory.
+
+ 7. Check for any special initialization in init_resource().
+    Normally, everything is just zeroed.
+
+ 8. Update the new_resource() subroutine to handle the two
+    passes of the configurator to be able to create your
+    resource.  Pass 2 is used only for finding a reference
+    to a resource and stuffing its address. In the above example,
+    you will need to include the storage resource.  See the 
+    example for the Job Resource.
+    
+    Add an entry so that the correct size of your resource is
+    allocated for pass one.
+
+ 9. Write any new store routines that you may need.  In this case,
+    we used the store_int and store_res, which are already defined,
+    but we need to add the new special routine store_time().
+    Note, the store subroutine gets control when the parser has
+    identified the record. Everything after the record name
+    must be scanned in the store routine.
+
+
+To add a new resource record:
+
+  1. Add the new record definition to the resource structure definition.
+     See step 2 above. In this case, however, we only add a new field
+     to the existing structure.
+
+  2. Add the new record to the existing res_items structure.  See
+     step 4 above. In this case, however, we only add a new record
+     definition to the exising structure.
+
+  3. Update the dump_resource() routine to dump the new record.
+   
+  4. Update the free_resource() routine if you allocated any memory.
+
+  5. Update init_resource() if you have any special requirements (not
+     normally the case).
+
+  6. Update the new_resource() routine if necessary (not normally the
+     case).
+
+  7. Write any new store routine that you may have created to store
+     your record.
+     Note, the store subroutine gets control when the parser has
+     identified the record. Everything after the record name
+     must be scanned in the store routine.  See the examples of
+     store routines that exist.
+
+Note, the core parsing code is in lib/parse_config.c and lib/parse_config.h.
+lib/parse_config.c provides the following store routines:
+    
+      store_name   stores a resource name
+      store_str    stores a string
+      store_res    stores a resource
+      store_int    stores an integer
+
+and the following utilities:
+
+      scan_to_eol  causes the lexical scanner to scan to the end of the line
+      scan_error   prints an error message
+      GetResWithName  returns the resource of a specified type and name
+      GetNextRes   returns the next resource of a specified type 
+      parse_config parses the configuration file
+      free_config_resources  frees all the resources allocated.
+
+Note: when your store routine gets control, the parser will have already
+scanned the record name (i.e. "baz =") before calling your routine.
+The lexical scanner is by default in a mode where spaces will be
+compressed out of unquoted strings. Consequently if you want to scan
+     baz = full backup every sunday
+
+and you do not want to get "full backup every sunday" as a single token
+"fullbackupeverysunday", you must set the no identifier option in the
+lexical scanner options field:
+
+   int options = lc->options;
+
+   lc->options |= LOPT_NO_IDENT;      /* don't eat spaces */
+     
+   get_token(lc) ...
+   ...
+
+   lc->options = options;
+   return;
+
+
+             
diff --git a/bacula/src/dird/authenticate.c b/bacula/src/dird/authenticate.c
new file mode 100644 (file)
index 0000000..f6ffa20
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *
+ *   Bacula Director -- authorize.c -- handles authorization of
+ *     Storage and File daemons.
+ *
+ *     Kern Sibbald, May MMI
+ *
+ *    This routine runs as a thread and must be thread reentrant.
+ *
+ *  Basic tasks done here:
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+extern DIRRES *director;
+extern char my_name[];
+
+/* Commands sent to Storage daemon and File daemon and received
+ *  from the User Agent */
+static char hello[]    = "Hello Director %s calling\n";
+
+/* Response from Storage daemon */
+static char OKhello[]   = "3000 OK Hello\n";
+static char FDOKhello[] = "2000 OK Hello\n";
+
+/* Sent to User Agent */
+static char Dir_sorry[]  = N_("1999 You are not authorized.\n");
+
+/* Forward referenced functions */
+
+/*
+ * Authenticate Storage daemon connection
+ */
+int authenticate_storage_daemon(JCR *jcr)
+{
+   BSOCK *sd = jcr->store_bsock;
+
+   /* 
+    * Send my name to the Storage daemon then do authentication
+    */
+   if (!bnet_fsend(sd, hello, director->hdr.name)) {
+      Emsg1(M_FATAL, 0, _("Auth send error. ERR=%s\n"), bnet_strerror(sd));
+   }
+   if (!cram_md5_get_auth(sd, jcr->store->password) || 
+       !cram_md5_auth(sd, jcr->store->password)) {
+      Emsg0(M_FATAL, 0, _("Storage daemon authorization failed.\n"));
+      return 0;
+   }
+   Dmsg1(6, ">stored: %s", sd->msg);
+   if (bnet_recv(sd) <= 0) {
+      Emsg1(M_FATAL, 0, _("bdird<stored: bad response to Hello command: ERR=%s\n"),
+        bnet_strerror(sd));
+      return 0;
+   }
+   Dmsg1(10, "<stored: %s", sd->msg);
+   if (strncmp(sd->msg, OKhello, sizeof(OKhello)) != 0) {
+      Emsg0(M_FATAL, 0, _("Storage daemon rejected Hello command\n"));
+      return 0;
+   }
+   return 1;
+}
+
+/*
+ * Authenticate File daemon connection
+ */
+int authenticate_file_daemon(JCR *jcr)
+{
+   BSOCK *fd = jcr->file_bsock;
+
+   /* 
+    * Send my name to the File daemon then do authentication
+    */
+   bnet_fsend(fd, hello, director->hdr.name);
+   if (!cram_md5_get_auth(fd, jcr->client->password) || 
+       !cram_md5_auth(fd, jcr->client->password)) {
+      Emsg0(M_FATAL, 0, _("File daemon authentication failed.\n"));
+      return 0;
+   }
+   Dmsg1(6, ">filed: %s", fd->msg);
+   if (bnet_recv(fd) <= 0) {
+      Emsg1(M_FATAL, 0, _("bdird<filed: bad response to Hello command: ERR=%s\n"),
+        bnet_strerror(fd));
+      return 0;
+   }
+   Dmsg1(10, "<stored: %s", fd->msg);
+   if (strncmp(fd->msg, FDOKhello, sizeof(FDOKhello)) != 0) {
+      Emsg0(M_FATAL, 0, _("File daemon rejected Hello command\n"));
+      return 0;
+   }
+   return 1;
+}
+
+/********************************************************************* 
+ *
+ */
+int authenticate_user_agent(BSOCK *ua)
+{
+   char name[128];
+   int ok = 0;
+
+
+   if (sscanf(ua->msg, "Hello %127s calling\n", name) != 1) {
+      Emsg1(M_FATAL, 0, _("Authentication failure: %s"), ua->msg);
+      return 0;
+   }
+
+   ok = cram_md5_auth(ua, director->password) &&
+       cram_md5_get_auth(ua, director->password);
+
+   if (!ok) {
+      bnet_fsend(ua, "%s", _(Dir_sorry));
+      Emsg0(M_WARNING, 0, _("Unable to authenticate User Agent\n"));
+      return 0;
+   }
+   bnet_fsend(ua, "1000 OK: %s Version: " VERSION " (" DATE ")\n", my_name);
+   return 1;
+}
diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c
new file mode 100644 (file)
index 0000000..3d5c4c2
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ *
+ *   Bacula Director -- backup.c -- responsible for doing backup jobs
+ *
+ *     Kern Sibbald, March MM
+ *
+ *    This routine is called as a thread. It may not yet be totally
+ *     thread reentrant!!!
+ *
+ *  Basic tasks done here:
+ *     Open DB and create records for this job.
+ *     Open Message Channel with Storage daemon to tell him a job will be starting.
+ *     Open connection with File daemon and pass him commands
+ *      to do the backup.
+ *     When the File daemon finishes the job, update the DB.
+ *
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Commands sent to File daemon */
+static char backupcmd[] = "backup\n";
+static char storaddr[]  = "storage address=%s port=%d\n";
+static char levelcmd[]  = "level = %s%s\n";
+
+/* Responses received from File daemon */
+static char OKbackup[] = "2000 OK backup\n";
+static char OKstore[]  = "2000 OK storage\n";
+static char OKlevel[]  = "2000 OK level\n";
+
+/* Forward referenced functions */
+static void backup_cleanup(JCR *jcr, int TermCode, char *since);
+static int wait_for_job_termination(JCR *jcr);              
+
+/* External functions */
+
+/* 
+ * Do a backup of the specified FileSet
+ *    
+ *  Returns:  0 on failure
+ *           1 on success
+ */
+int do_backup(JCR *jcr) 
+{
+   char since[MAXSTRING];
+   int stat;
+   BSOCK   *fd;
+   POOL_DBR pr;
+#ifdef needed
+   MEDIA_DBR mr;
+#endif
+   CLIENT_DBR cr;
+   FILESET_DBR fsr;
+
+   since[0] = 0;
+   /*
+    * Get or Create client record
+    */
+   memset(&cr, 0, sizeof(cr));
+   strcpy(cr.Name, jcr->client->hdr.name);
+   if (jcr->client_name) {
+      free(jcr->client_name);
+   }
+   jcr->client_name = bstrdup(jcr->client->hdr.name);
+   if (!db_create_client_record(jcr->db, &cr)) {
+      Jmsg(jcr, M_ERROR, 0, _("Could not create Client record. %s"), 
+        db_strerror(jcr->db));
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+   jcr->jr.ClientId = cr.ClientId;
+   Dmsg2(9, "Created Client %s record %d\n", jcr->client->hdr.name, 
+      jcr->jr.ClientId);
+
+   /*
+    * Get or Create FileSet record
+    */
+   memset(&fsr, 0, sizeof(fsr));
+   strcpy(fsr.FileSet, jcr->fileset->hdr.name);
+   if (jcr->fileset->have_MD5) {
+      struct MD5Context md5c;
+      unsigned char signature[16];
+      memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
+      MD5Final(signature, &md5c);
+      bin_to_base64(fsr.MD5, (char *)signature, 16); /* encode 16 bytes */
+   } else {
+      Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 signature not found.\n"));
+   }
+   if (!db_create_fileset_record(jcr->db, &fsr)) {
+      Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet record. %s"), 
+        db_strerror(jcr->db));
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }   
+   jcr->jr.FileSetId = fsr.FileSetId;
+   Dmsg2(9, "Created FileSet %s record %d\n", jcr->fileset->hdr.name, 
+      jcr->jr.FileSetId);
+
+
+   /* Look up the last
+    * FULL backup job to get the time/date for a 
+    * differential or incremental save.
+    */
+   jcr->stime = (char *) get_pool_memory(PM_MESSAGE);
+   jcr->stime[0] = 0;
+   since[0] = 0;
+   switch (jcr->level) {
+      case L_DIFFERENTIAL:
+      case L_INCREMENTAL:
+        /* Look up start time of last job */
+        jcr->jr.JobId = 0;
+        if (!db_find_job_start_time(jcr->db, &jcr->jr, jcr->stime)) {
+            Jmsg(jcr, M_INFO, 0, _("Last FULL backup time not found. Doing FULL backup.\n"));
+           jcr->level = L_FULL;
+           jcr->jr.Level = L_FULL;
+        } else {
+            strcpy(since, ", since=");
+           strcat(since, jcr->stime);
+        }
+         Dmsg1(15, "Last start time = %s\n", jcr->stime);
+        break;
+   }
+
+   jcr->jr.JobId = jcr->JobId;
+   jcr->jr.StartTime = jcr->start_time;
+   if (!db_update_job_start_record(jcr->db, &jcr->jr)) {
+      Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+
+   jcr->fname = (char *) get_pool_memory(PM_FNAME);
+
+   /* Print Job Start message */
+   Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %d, Job=%s\n"),
+       jcr->JobId, jcr->Job);
+
+   /* 
+    * Get the Pool record  
+    */
+   memset(&pr, 0, sizeof(pr));
+   strcpy(pr.Name, jcr->pool->hdr.name);
+   while (!db_get_pool_record(jcr->db, &pr)) { /* get by Name */
+      /* Try to create the pool */
+      if (create_pool(jcr->db, jcr->pool) < 0) {
+         Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name, 
+           db_strerror(jcr->db));
+        backup_cleanup(jcr, JS_ErrorTerminated, since);
+        return 0;
+      } else {
+         Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
+      }
+   }
+   jcr->PoolId = pr.PoolId;              /****FIXME**** this can go away */
+   jcr->jr.PoolId = pr.PoolId;
+
+#ifdef needed
+   /* NOTE, THIS IS NOW DONE BY THE STORAGE DAEMON
+    *
+    * Find at least one Volume associated with this Pool
+    *  It must be marked Append, and be of the correct Media Type
+    *  for the storage type.
+    */
+   memset(&mr, 0, sizeof(mr));
+   mr.PoolId = pr.PoolId;
+   strcpy(mr.VolStatus, "Append");
+   strcpy(mr.MediaType, jcr->store->media_type);
+   if (!db_find_next_volume(jcr->db, 1, &mr)) {
+      if (!newVolume(jcr)) {
+         Jmsg(jcr, M_FATAL, 0, _("No writable %s media in Pool %s.\n\
+      Please use the Console program to add available Volumes.\n"), mr.MediaType, pr.Name);
+        backup_cleanup(jcr, JS_ErrorTerminated, since);
+        return 0;
+      }
+   }
+#endif
+
+   /*
+    * Open a message channel connection with the Storage
+    * daemon. This is to let him know that our client
+    * will be contacting him for a backup  session.
+    *
+    */
+   Dmsg0(10, "Open connection with storage daemon\n");
+   jcr->JobStatus = JS_Blocked;
+   /*
+    * Start conversation with Storage daemon  
+    */
+   if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+   /*
+    * Now start a job with the Storage daemon
+    */
+   if (!start_storage_daemon_job(jcr)) {
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+   /*
+    * Now start a Storage daemon message thread
+    */
+   if (!start_storage_daemon_message_thread(jcr)) {
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+
+   Dmsg0(50, "Storage daemon connection OK\n");
+
+   if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+
+   jcr->JobStatus = JS_Running;
+   fd = jcr->file_bsock;
+
+   if (!send_include_list(jcr)) {
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+
+   if (!send_exclude_list(jcr)) {
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+
+   /* 
+    * send Storage daemon address to the File daemon
+    */
+   if (jcr->store->SDDport == 0) {
+      jcr->store->SDDport = jcr->store->SDport;
+   }
+   bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
+   if (!response(fd, OKstore, "Storage")) {
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+
+   /* 
+    * Send Level command to File daemon
+    */
+   switch (jcr->level) {
+      case L_FULL:
+         bnet_fsend(fd, levelcmd, "full", " ");
+        break;
+      case L_DIFFERENTIAL:
+      case L_INCREMENTAL:
+         bnet_fsend(fd, levelcmd, "since ", jcr->stime);
+        free_pool_memory(jcr->stime);
+        jcr->stime = NULL;
+        break;
+      case L_SINCE:
+      default:
+         Emsg1(M_FATAL, 0, _("Unimplemented backup level %d\n"), jcr->level);
+        backup_cleanup(jcr, JS_ErrorTerminated, since);
+        return 0;
+   }
+   Dmsg1(20, ">filed: %s", fd->msg);
+   if (!response(fd, OKlevel, "Level")) {
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+
+   /* Send backup command */
+   bnet_fsend(fd, backupcmd);
+   if (!response(fd, OKbackup, "backup")) {
+      backup_cleanup(jcr, JS_ErrorTerminated, since);
+      return 0;
+   }
+
+   /* Pickup Job termination data */       
+   stat = wait_for_job_termination(jcr);
+   backup_cleanup(jcr, stat, since);
+   return 1;
+}
+
+/*
+ *  NOTE! This is no longer really needed as the Storage
+ *       daemon now passes this information directly
+ *       back to us.   
+ */
+static int wait_for_job_termination(JCR *jcr)
+{
+   int32_t n = 0;
+   BSOCK *fd = jcr->file_bsock;
+
+   jcr->JobStatus = JS_WaitFD;
+   /* Wait for Client to terminate */
+   while ((n = bget_msg(fd, 0)) > 0 && !job_cancelled(jcr)) {
+      /* get and discard Client output */
+   }
+   bnet_sig(fd, BNET_TERMINATE);      /* tell Client we are terminating */
+   if (n < 0) {
+      Jmsg(jcr, M_FATAL, 0, _("<filed: network error during BACKUP command. ERR=%s\n"),
+         bnet_strerror(fd));
+   }
+
+   /* Now wait for Storage daemon to terminate our message thread */
+   P(jcr->mutex);
+   jcr->JobStatus = JS_WaitSD;
+   while (!jcr->msg_thread_done && !job_cancelled(jcr)) {
+      struct timeval tv;
+      struct timezone tz;
+      struct timespec timeout;
+
+      gettimeofday(&tv, &tz);
+      timeout.tv_nsec = 0;
+      timeout.tv_sec = tv.tv_sec + 10; /* wait 10 seconds */
+      Dmsg0(300, "I'm waiting for message thread termination.\n");
+      pthread_cond_timedwait(&jcr->term_wait, &jcr->mutex, &timeout);
+   }
+   V(jcr->mutex);
+   if (n < 0) {                                    
+      return JS_ErrorTerminated;
+   }
+   return jcr->SDJobStatus;
+}
+
+/*
+ * Release resources allocated during backup.
+ */
+static void backup_cleanup(JCR *jcr, int TermCode, char *since)
+{
+   char sdt[50], edt[50];
+   char ec1[30], ec2[30], ec3[30];
+   char term_code[100];
+   char *term_msg;
+   int msg_type;
+   MEDIA_DBR mr;
+
+   memset(&mr, 0, sizeof(mr));
+   Dmsg0(100, "Enter backup_cleanup()\n");
+   if (jcr->jr.EndTime == 0) {
+      jcr->jr.EndTime = time(NULL);
+   }
+   jcr->end_time = jcr->jr.EndTime;
+   jcr->jr.JobId = jcr->JobId;
+   jcr->jr.JobStatus = jcr->JobStatus = TermCode;
+   jcr->jr.JobFiles = jcr->JobFiles;
+   jcr->jr.JobBytes = jcr->JobBytes;
+   jcr->jr.VolSessionId = jcr->VolSessionId;
+   jcr->jr.VolSessionTime = jcr->VolSessionTime;
+   if (!db_update_job_end_record(jcr->db, &jcr->jr)) {
+      Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"), 
+        db_strerror(jcr->db));
+   }
+   if (!db_get_job_record(jcr->db, &jcr->jr)) {
+      Jmsg(jcr, M_WARNING, 0, _("Error getting job record for stats: %s"), 
+        db_strerror(jcr->db));
+   }
+
+   strcpy(mr.VolumeName, jcr->VolumeName);
+   if (!db_get_media_record(jcr->db, &mr)) {
+      Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for stats: %s"), 
+        db_strerror(jcr->db));
+   }
+
+      
+   msg_type = M_INFO;                /* by default INFO message */
+   switch (TermCode) {
+      case JS_Terminated:
+         term_msg = _("Backup OK");
+        break;
+      case JS_Errored:
+         term_msg = _("*** Backup Error ***"); 
+        msg_type = M_ERROR;          /* Generate error message */
+        if (jcr->store_bsock) {
+           bnet_sig(jcr->store_bsock, BNET_TERMINATE);
+           pthread_cancel(jcr->SD_msg_chan);
+        }
+        break;
+      case JS_Cancelled:
+         term_msg = _("Backup Cancelled");
+        if (jcr->store_bsock) {
+           bnet_sig(jcr->store_bsock, BNET_TERMINATE);
+           pthread_cancel(jcr->SD_msg_chan);
+        }
+        break;
+      default:
+        term_msg = term_code;
+         sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
+        break;
+   }
+   bstrftime(sdt, sizeof(sdt), jcr->jr.StartTime);
+   bstrftime(edt, sizeof(edt), jcr->jr.EndTime);
+   if (!db_get_job_volume_names(jcr->db, jcr->jr.JobId, jcr->VolumeName)) {
+      jcr->VolumeName[0] = 0;        /* none */
+   }
+
+   Jmsg(jcr, msg_type, 0, _("%s\n\
+JobId:                  %d\n\
+Job:                    %s\n\
+FileSet:                %s\n\
+Backup Level:           %s%s\n\
+Client:                 %s\n\
+Start time:             %s\n\
+End time:               %s\n\
+Bytes Written:          %s\n\
+Files Written:          %s\n\
+Volume names(s):        %s\n\
+Volume Session Id:      %d\n\
+Volume Session Time:    %d\n\
+Volume Bytes:           %s\n\
+Termination:            %s\n"),
+       edt,
+       jcr->jr.JobId,
+       jcr->jr.Job,
+       jcr->fileset->hdr.name,
+       level_to_str(jcr->level), since,
+       jcr->client->hdr.name,
+       sdt,
+       edt,
+       edit_uint_with_commas(jcr->jr.JobBytes, ec1),
+       edit_uint_with_commas(jcr->jr.JobFiles, ec2),
+       jcr->VolumeName,
+       jcr->VolSessionId,
+       jcr->VolSessionTime,
+       edit_uint_with_commas(mr.VolBytes, ec3),
+       term_msg);
+
+   Dmsg0(100, "Leave backup_cleanup()\n");
+}
diff --git a/bacula/src/dird/bacula-dir.conf.in b/bacula/src/dird/bacula-dir.conf.in
new file mode 100644 (file)
index 0000000..ee60d0d
--- /dev/null
@@ -0,0 +1,133 @@
+#
+# Default Bacula Director Configuration file
+#
+#  The only thing that MUST be changed is to add one or more
+#   file or directory names in the Include directive of the
+#   FileSet resource.
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@ @DISTVER@
+#
+#  You might also want to change the default email address
+#   from root to your address.  See the "mail" and "operator"
+#   directives in the Messages resource.
+#
+
+Director {                            # define myself
+  Name = @hostname@-dir
+  DIRport = @dir_port@                # where we listen for UA connections
+  QueryFile = "@sysconfdir@/query.sql"
+  WorkingDirectory = "@working_dir@"
+  PidDirectory = "@piddir@"
+  SubSysDirectory = "@subsysdir@"
+  Maximum Concurrent Jobs = 1
+  Password = "@dir_password@"         # Console password
+}
+
+# Define the backup Job
+Job {
+  Name = "NightlySave"
+  Backup = Client=@hostname@-fd FileSet="Full Set"
+  Schedule = "WeeklyCycle"
+  Storage = DLTDrive
+  Messages = Standard
+  Pool = Default
+}
+
+# List of files to be backed up
+FileSet {
+  Name = "Full Set"
+  Include = signature=MD5 { 
+#    
+#  Put your list of files here, one per line or include an
+#    external list with:
+#
+#    @file-name
+#
+#  Note: / backs up everything
+
+  /
+
+  }
+  Exclude = { }
+}
+
+# When to do the backups
+Schedule {
+  Name = "WeeklyCycle"
+  Run = Full sun at 1:05
+  Run = Incremental mon-sat at 1:05
+}
+
+# Client (File Services) to backup
+Client {
+  Name = @hostname@-fd
+  Address = @hostname@
+  FDPort = @fd_port@
+  Catalog = MyCatalog
+  Password = "@fd_password@"          # password for FileDaemon
+}
+
+
+# Definition of DLT tape storage device
+Storage {
+  Name = DLTDrive
+  Address = @hostname@
+  SDPort = @sd_port@
+  Password = "@sd_password@"          # password for Storage daemon
+  Device = "HP DLT 80"                # must be same as Device in Storage daemon
+  Media Type = DLT8000                # must be same as MediaType in Storage daemon
+}
+
+# Definition of DDS tape storage device
+Storage {
+  Name = SDT-10000
+  Address = @hostname@
+  SDPort = @sd_port@
+  Password = "@sd_password@"          # password for Storage daemon
+  Device = SDT-10000                  # must be same as Device in Storage daemon
+  Media Type = DDS-4                  # must be same as MediaType in Storage daemon
+}
+
+# Definition of 8mm tape storage device
+Storage {
+  Name = "8mmDrive"
+  Address = @hostname@
+  SDPort = @sd_port@
+  Password = "@sd_password@"
+  Device = "Exabyte 8mm"
+  MediaType = "8mm"
+}
+
+# Definiton of file storage device
+Storage {
+  Name = File
+  Address = @hostname@
+  SDPort = @sd_port@
+  Password = "@sd_password@"
+  Device = FileStorage
+  Media Type = File
+}
+
+
+# Generic catalog service
+Catalog {
+  Name = MyCatalog
+  dbname = bacula; user = bacula; password = ""
+}
+
+# Reasonable message delivery -- send most everything to email address
+#  and to the console
+Messages {
+  Name = Standard
+  mailcommand = "@sbindir@/smtp -h @smtp_host@ -f \"Bacula <%r>\" -s \"Bacula: %t %e of %c %l\" %r"
+  operatorcommand = "@sbindir@/smtp -h @smtp_host@ -f \"Bacula <%r>\" -s \"Bacula: Intervention needed for %j\" %r"
+  mail = @job_email@ = all, !skipped, !terminate
+  operator = @job_email@ = mount
+  console = all, !skipped, !saved
+}
+    
+# Default pool definition
+Pool {
+  Name = Default
+  Pool Type = Backup
+}
diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c
new file mode 100644 (file)
index 0000000..f4e82ce
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ *
+ *   Bacula Director -- catreq.c -- handles the message channel
+ *    catalog request from the Storage daemon.
+ *
+ *     Kern Sibbald, March MMI
+ *
+ *    This routine runs as a thread and must be thread reentrant.
+ *
+ *  Basic tasks done here:
+ *     Handle Catalog services.
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/*
+ * Handle catalog request
+ *  For now, we simply return next Volume to be used
+ */
+
+/* Requests from the Storage daemon */
+static char Find_media[] = "CatReq Job=%127s FindMedia=%d\n";
+static char Find_Vol_Info[] = "CatReq Job=%127s GetVolInfo VolName=%127s\n";
+
+static char Update_media[] = "CatReq Job=%127s UpdateMedia VolName=%s\
+ VolJobs=%d VolFiles=%d VolBlocks=%d VolBytes=%" lld " VolMounts=%d\
+ VolErrors=%d VolWrites=%d VolMaxBytes=%" lld " EndTime=%d VolStatus=%10s\
+ FirstIndex=%d LastIndex=%d StartFile=%d EndFile=%d \
+ StartBlock=%d EndBlock=%d\n";
+
+/* Responses  sent to Storage daemon */
+static char OK_media[] = "1000 OK VolName=%s VolJobs=%d VolFiles=%d\
+ VolBlocks=%d VolBytes=%" lld " VolMounts=%d VolErrors=%d VolWrites=%d\
+ VolMaxBytes=%" lld " VolCapacityBytes=%" lld "\n";
+
+static char OK_update[] = "1000 OK UpdateMedia\n";
+
+/* static char FileAttributes[] = "UpdCat Job=%127s FileAttributes "; */
+
+
+void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
+{
+   MEDIA_DBR mr; 
+   JOBMEDIA_DBR jm;
+   char Job[MAX_NAME_LENGTH];
+   int index, ok;
+   char *omsg;
+
+   memset(&mr, 0, sizeof(mr));
+   memset(&jm, 0, sizeof(jm));
+
+   /*
+    * Request to find next appendable Volume for this Job
+    */
+   Dmsg1(20, "catreq %s", bs->msg);
+   if (sscanf(bs->msg, Find_media, &Job, &index) == 2) {
+      mr.PoolId = jcr->PoolId;
+      strcpy(mr.MediaType, jcr->store->media_type);
+      strcpy(mr.VolStatus, "Append");
+      Dmsg3(120, "CatReq FindMedia: Id=%d, MediaType=%s, Status=%s\n",
+        mr.PoolId, mr.MediaType, mr.VolStatus);
+      /*
+       * Find the Volume
+       */
+      ok = FALSE;
+      if (db_find_next_volume(jcr->db, index, &mr)) {
+        jcr->MediaId = mr.MediaId;
+         Dmsg1(20, "Find_next_vol MediaId=%d\n", jcr->MediaId);
+        strcpy(jcr->VolumeName, mr.VolumeName);
+
+        ok = TRUE;
+      } else {
+        /* See if we can create a new Volume */
+        ok = newVolume(jcr);
+      }
+      /*
+       * Send Find Media response to Storage daemon 
+       */
+      if (ok) {
+        bash_spaces(mr.VolumeName);
+        bnet_fsend(bs, OK_media, mr.VolumeName, mr.VolJobs,
+           mr.VolFiles, mr.VolBlocks, mr.VolBytes, mr.VolMounts, mr.VolErrors,
+           mr.VolWrites, mr.VolMaxBytes, mr.VolCapacityBytes);
+      } else {
+         bnet_fsend(bs, "1999 No Media\n");
+      }
+
+   /* 
+    * Request to find specific volume information
+    */
+   } else if (sscanf(bs->msg, Find_Vol_Info, &Job, &mr.VolumeName) == 2) {
+      Dmsg1(120, "CatReq GetVolInfo Vol=%s\n", mr.VolumeName);
+      /*
+       * Find the Volume
+       */
+      unbash_spaces(mr.VolumeName);
+      if (db_get_media_record(jcr->db, &mr)) {
+        jcr->MediaId = mr.MediaId;
+         Dmsg1(20, "VolumeInfo MediaId=%d\n", jcr->MediaId);
+        strcpy(jcr->VolumeName, mr.VolumeName);
+        /* 
+         * Make sure this volume is suitable for this job
+         */
+        if (mr.PoolId == jcr->PoolId && 
+             strcmp(mr.VolStatus, "Append") == 0 &&
+            strcmp(mr.MediaType, jcr->store->media_type) == 0) {
+           /*
+            * Send Find Media response to Storage daemon 
+            */
+           bash_spaces(mr.VolumeName);
+           bnet_fsend(bs, OK_media, mr.VolumeName, mr.VolJobs,
+              mr.VolFiles, mr.VolBlocks, mr.VolBytes, mr.VolMounts, mr.VolErrors,
+              mr.VolWrites, mr.VolMaxBytes, mr.VolCapacityBytes);
+        } else { 
+            Dmsg4(000, "get_media_record PoolId=%d wanted %d, Status=%s, \
+MediaType=%s\n", mr.PoolId, jcr->PoolId, mr.VolStatus, mr.MediaType);
+           /* Not suitable volume */
+            bnet_fsend(bs, "1998 Volume not appropriate.\n");
+        }
+
+      } else {
+         bnet_fsend(bs, "1999 Volume Not Found.\n");
+      }
+
+   
+   /*
+    * Request to update Media record. Comes typically at the end
+    *  of a Storage daemon Job Session
+    */
+   } else if (sscanf(bs->msg, Update_media, &Job, &mr.VolumeName, &mr.VolJobs,
+      &mr.VolFiles, &mr.VolBlocks, &mr.VolBytes, &mr.VolMounts, &mr.VolErrors,
+      &mr.VolWrites, &mr.VolMaxBytes, &mr.LastWritten, &mr.VolStatus, 
+      &jm.FirstIndex, &jm.LastIndex, &jm.StartFile, &jm.EndFile,
+      &jm.StartBlock, &jm.EndBlock) == 18) {
+      /*     
+       * Update Media Record
+       */
+      if ((mr.VolMaxBytes > 0 && mr.VolBytes >= mr.VolMaxBytes) ||
+         (mr.VolBytes > 0 && jcr->pool->use_volume_once)) {
+         strcpy(mr.VolStatus, "Full");
+      }
+
+      jm.JobId = jcr->JobId;
+      jm.MediaId = jcr->MediaId;
+      /*
+       * A single write means we just labeled the tape,
+       * so no need to create a jobmedia record.
+       * Otherwise, record the fact that this job used this Volume 
+       */
+      if (mr.VolWrites > 1) {
+         Dmsg4(20, "create_jobmedia JobId=%d MediaId=%d FI=%d LI=%d\n",
+           jm.JobId, jm.MediaId, jm.FirstIndex, jm.LastIndex);
+        if(!db_create_jobmedia_record(jcr->db, &jm)) {
+            Jmsg(jcr, M_ERROR, 0, _("Catalog error creating JobMedia record. %s"),
+              db_strerror(jcr->db));
+            bnet_fsend(bs, "1991 Update JobMedia error\n");
+        } else {
+            Dmsg0(20, "JobMedia record created\n");
+        }
+      }
+
+      Dmsg0(20, "db_update_media_record\n");
+      if (db_update_media_record(jcr->db, &mr)) {
+        bnet_fsend(bs, OK_update);
+         Dmsg0(90, "send OK\n");
+      } else {
+         Jmsg(jcr, M_ERROR, 0, _("Catalog error updating Media record. %s"),
+           db_strerror(jcr->db));
+         bnet_fsend(bs, "1992 Update Media error\n");
+         Dmsg0(90, "send error\n");
+      }
+   } else {
+      omsg = (char *) get_memory(bs->msglen+1);
+      strcpy(omsg, bs->msg);
+      bnet_fsend(bs, "1990 Invalid Catalog Request: %s", omsg);    
+      free_memory(omsg);
+   }
+   Dmsg1(20, ">CatReq response: %s", bs->msg);
+   return;
+}
+
+/*
+ * Update File Attributes in the catalog with data
+ *  sent by the Storage daemon.
+ */
+void catalog_update(JCR *jcr, BSOCK *bs, char *msg)
+{
+   unser_declare;
+   uint32_t VolSessionId, VolSessionTime;
+   int32_t Stream;
+   uint32_t FileIndex;
+   uint32_t data_len;
+   char *p = bs->msg;
+   int len;
+   char *fname, *attr;
+   ATTR_DBR ar;
+
+   if (!jcr->pool->catalog_files) {
+      return;
+   }
+   skip_nonspaces(&p);               /* UpdCat */
+   skip_spaces(&p);
+   skip_nonspaces(&p);               /* Job=nnn */
+   skip_spaces(&p);
+   skip_nonspaces(&p);               /* FileAttributes */
+   p += 1;
+   unser_begin(p, 0);
+   unser_uint32(VolSessionId);
+   unser_uint32(VolSessionTime);
+   unser_int32(FileIndex);
+   unser_int32(Stream);
+   unser_uint32(data_len);
+   p += unser_length(p);
+
+   Dmsg1(99, "UpdCat msg=%s\n", bs->msg);
+   Dmsg5(99, "UpdCat VolSessId=%d VolSessT=%d FI=%d Strm=%d data_len=%d\n",
+      VolSessionId, VolSessionTime, FileIndex, Stream, data_len);
+
+   if (Stream == STREAM_UNIX_ATTRIBUTES) {
+      skip_nonspaces(&p);            /* skip FileIndex */
+      skip_spaces(&p);
+      skip_nonspaces(&p);            /* skip FileType */
+      skip_spaces(&p);
+      fname = p;
+      len = strlen(fname);       /* length before attributes */
+      attr = &fname[len+1];
+
+      Dmsg2(99, "dird<stored: stream=%d %s\n", Stream, fname);
+      Dmsg1(99, "dird<stored: attr=%s\n", attr);
+      ar.attr = attr; 
+      ar.fname = fname;
+      ar.FileIndex = FileIndex;
+      ar.Stream = Stream;
+      ar.link = NULL;
+      ar.JobId = jcr->JobId;
+
+      Dmsg2(11, "dird<filed: stream=%d %s\n", Stream, fname);
+      Dmsg1(20, "dird<filed: attr=%s\n", attr);
+
+      /* ***FIXME*** fix link field */
+      if (!db_create_file_attributes_record(jcr->db, &ar)) {
+         Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
+      }
+      /* Save values for MD5 update */
+      jcr->FileId = ar.FileId;
+      jcr->FileIndex = FileIndex;
+   } else if (Stream == STREAM_MD5_SIGNATURE) {
+      fname = p;
+      if (jcr->FileIndex != FileIndex) {    
+         Jmsg(jcr, M_WARNING, 0, "Got MD5 but not same block as attributes\n");
+      } else {
+        /* Update MD5 signature in catalog */
+        char MD5buf[50];           /* 24 bytes should be enough */
+        bin_to_base64(MD5buf, fname, 16);
+         Dmsg2(90, "MD5len=%d MD5=%s\n", strlen(MD5buf), MD5buf);
+        if (!db_add_MD5_to_file_record(jcr->db, jcr->FileId, MD5buf)) {
+            Jmsg(jcr, M_ERROR, 0, _("Catalog error updating MD5. %s"), 
+              db_strerror(jcr->db));
+        }
+      }
+   }
+}
diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c
new file mode 100644 (file)
index 0000000..bc1607d
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ *
+ *   Bacula Director daemon -- this is the main program
+ *
+ *     Kern Sibbald, March MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Forward referenced subroutines */
+static void terminate_dird(int sig);
+static int check_resources();
+static void reload_config(int sig);
+
+/* Exported subroutines */
+
+
+/* Imported subroutines */
+extern JCR *wait_for_next_job(char *runjob);
+extern void term_scheduler();
+extern void term_ua_server();
+extern int do_backup(JCR *jcr);
+extern void backup_cleanup(void);
+extern void start_UA_server(int port);
+extern void run_job(JCR *jcr);
+extern void init_job_server(int max_workers);
+
+static char *configfile = NULL;
+static char *runjob = NULL;
+
+static int background = 1;
+
+/* Globals Exported */
+DIRRES *director;                    /* Director resource */
+int FDConnectTimeout;
+int SDConnectTimeout;
+
+#define CONFIG_FILE "./bacula-dir.conf" /* default configuration file */
+
+static void usage()
+{
+   fprintf(stderr, _(
+"\nVersion: " VERSION " (" DATE ")\n\n"
+"Usage: dird [-f -s] [-c config_file] [-d debug_level] [config_file]\n"
+"       -c <file>   set configuration file to file\n"
+"       -dnn        set debug level to nn\n"
+"       -f          run in foreground (for debugging)\n"
+"       -r <job>    run <job> now\n"
+"       -s          no signals\n"
+"       -t          test - read configuration and exit\n"
+"       -?          print this message.\n"  
+"\n"));
+
+   exit(1);
+}
+
+
+/*********************************************************************
+ *
+ *        Main Bacula Server program
+ *
+ */
+int main (int argc, char *argv[])
+{
+   int ch;
+   JCR *jcr;
+   int no_signals = FALSE;
+   int test_config = FALSE;
+
+   init_stack_dump();
+   my_name_is(argc, argv, "bacula-dir");
+   daemon_start_time = time(NULL);
+   memset(&last_job, 0, sizeof(last_job));
+
+   while ((ch = getopt(argc, argv, "c:d:fr:st?")) != -1) {
+      switch (ch) {
+         case 'c':                    /* specify config file */
+           if (configfile != NULL) {
+              free(configfile);
+           }
+           configfile = bstrdup(optarg);
+           break;
+
+         case 'd':                    /* set debug level */
+           debug_level = atoi(optarg);
+           if (debug_level <= 0) {
+              debug_level = 1; 
+           }
+            Dmsg1(0, "Debug level = %d\n", debug_level);
+           break;
+
+         case 'f':                    /* run in foreground */
+           background = FALSE;
+           break;
+
+         case 'r':                    /* run job */
+           if (runjob != NULL) {
+              free(runjob);
+           }
+           if (optarg) {
+              runjob = bstrdup(optarg);
+           }
+           break;
+
+         case 's':                    /* turn off signals */
+           no_signals = TRUE;
+           break;
+
+         case 't':                    /* test config */
+           test_config = TRUE;
+           break;
+
+         case '?':
+        default:
+           usage();
+
+      }  
+   }
+   argc -= optind;
+   argv += optind;
+
+   if (!no_signals) {
+      init_signals(terminate_dird);
+   }
+   signal(SIGCHLD, SIG_IGN);
+
+   if (argc) {
+      if (configfile != NULL) {
+        free(configfile);
+      }
+      configfile = bstrdup(*argv);
+      argc--; 
+      argv++;
+   }
+   if (argc) {
+      usage();
+   }
+
+   if (configfile == NULL) {
+      configfile = bstrdup(CONFIG_FILE);
+   }
+
+   init_msg(NULL);                   /* initialize message handler */
+   parse_config(configfile);
+
+   if (!check_resources()) {
+      Emsg1(M_ABORT, 0, "Please correct configuration file: %s\n", configfile);
+   }
+
+   my_name_is(0, (char **)NULL, director->hdr.name);   /* set user defined name */
+
+   FDConnectTimeout = director->FDConnectTimeout;
+   SDConnectTimeout = director->SDConnectTimeout;
+
+
+   if (test_config) {
+      terminate_dird(0);
+      exit(0);
+   }
+
+   if (background) {
+      daemon_start();
+      init_stack_dump();             /* grab new pid */
+   }
+
+   signal(SIGHUP, reload_config);
+
+   init_console_msg(working_directory);
+
+   Dmsg0(200, "Start UA server\n");
+   start_UA_server(director->DIRport);
+
+   init_watchdog();                  /* start network watchdog thread */
+
+   init_job_server(director->MaxConcurrentJobs);
+  
+   Dmsg0(200, "wait for next job\n");
+   /* Main loop -- call scheduler to get next job to run */
+   while ((jcr = wait_for_next_job(runjob))) {
+      run_job(jcr);                  /* run job */
+      if (runjob)                    /* command line, run a single job? */
+        break;                       /* yes, terminate */
+   }
+
+   terminate_dird(0);
+   exit(0);                          /* for compiler */
+}
+
+/* Cleanup and then exit */
+static void terminate_dird(int sig)
+{
+   static int already_here = FALSE;
+
+   if (already_here) {               /* avoid recursive temination problems */
+      exit(1);
+   }
+   already_here = TRUE;
+   term_watchdog();
+   signal(SIGCHLD, SIG_IGN);          /* don't worry about children now */
+   term_scheduler();
+   if (runjob) {
+      free(runjob);
+   }
+   if (configfile != NULL) {
+      free(configfile);
+   }
+   if (debug_level > 5) {
+      print_memory_pool_stats(); 
+   }
+   free_config_resources();
+   term_ua_server();
+   close_memory_pool();              /* free memory in pool */
+   term_msg();                       /* terminate message handler */
+   sm_dump(False);
+   exit(0);
+}
+
+/*
+ * If we get here, we have received a SIGHUP, which means to
+ * reread our configuration file. 
+ *
+ *  ***FIXME***  Check that there are no jobs running before
+ *              doing this. 
+ */
+static void reload_config(int sig)
+{
+   static int already_here = FALSE;
+   sigset_t set;       
+
+   if (already_here) {
+      abort();                       /* Oops, recursion -> die */
+   }
+   already_here = TRUE;
+   sigfillset(&set);
+   sigprocmask(SIG_BLOCK, &set, NULL);
+
+   free_config_resources();
+
+   parse_config(configfile);
+
+   Dmsg0(200, "check_resources()\n");
+   if (!check_resources()) {
+      Emsg1(M_ABORT, 0, _("Please correct configuration file: %s\n"), configfile);
+   }
+
+   /* Reset globals */
+   working_directory = director->working_directory;
+   FDConnectTimeout = director->FDConnectTimeout;
+   SDConnectTimeout = director->SDConnectTimeout;
+   sigprocmask(SIG_UNBLOCK, &set, NULL);
+   signal(SIGHUP, reload_config);
+   already_here = FALSE;
+   Dmsg0(0, "Director's configuration file reread.\n");
+}
+
+/*
+ * Make a quick check to see that we have all the
+ * resources needed.
+ *
+ *  **** FIXME **** this routine could be a lot more
+ *   intelligent and comprehensive.
+ */
+static int check_resources()
+{
+   int OK = TRUE;
+   JOB *job;
+
+   LockRes();
+
+   job = (JOB *)GetNextRes(R_JOB, NULL);
+   director = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
+   if (!director) {
+      Emsg1(M_WARNING, 0, _("No Director resource defined in %s\n\
+Without that I don't know who I am :-(\n"), configfile);
+      OK = FALSE;
+   }
+   if (GetNextRes(R_DIRECTOR, (RES *)director) != NULL) {
+      Emsg1(M_WARNING, 0, _("Only one Director resource permitted in %s\n"),
+        configfile);
+      OK = FALSE;
+   } 
+   if (!director->working_directory) {
+      Emsg0(M_WARNING, 0, _("No working directory specified. Cannot continue.\n"));
+      OK = FALSE;
+   }      
+   working_directory = director->working_directory;
+   if (!job) {
+      Emsg1(M_WARNING, 0, _("No Job records defined in %s\n"), configfile);
+      OK = FALSE;
+   }
+   for (job=NULL; (job = (JOB *)GetNextRes(R_JOB, (RES *)job)); ) {
+      if (!job->client) {
+         Emsg1(M_WARNING, 0, _("No Client record defined for job %s\n"), job->hdr.name);
+        OK = FALSE;
+      }
+      if (!job->fs) {
+         Emsg1(M_WARNING, 0, _("No FileSet record defined for job %s\n"), job->hdr.name);
+        OK = FALSE;
+      }
+      if (!job->storage && job->JobType != JT_VERIFY) {
+         Emsg1(M_WARNING, 0, _("No Storage resource defined for job %s\n"), job->hdr.name);
+        OK = FALSE;
+      }
+      if (!job->pool) {
+         Emsg1(M_WARNING, 0, _("No Pool resource defined for job %s\n"), job->hdr.name);
+        OK = FALSE;
+      }
+      if (job->client->catalog) {
+        CAT *catalog = job->client->catalog;
+        B_DB *db;
+
+        /*
+         * Make sure we can open catalog, otherwise print a warning
+         * message because the server is probably not running.
+         */
+        db = db_init_database(catalog->db_name, catalog->db_user,
+                           catalog->db_password);
+        if (!db_open_database(db)) {
+            Emsg1(M_WARNING,  0, "%s", db_strerror(db));
+        }
+        db_close_database(db);
+      } else {
+         Emsg1(M_WARNING, 0, _("No Catalog resource defined for client %s\n"), 
+              job->client->hdr.name);
+        OK = FALSE;
+      }
+   }
+
+   UnlockRes();
+   return OK;
+}
diff --git a/bacula/src/dird/dird.h b/bacula/src/dird/dird.h
new file mode 100644 (file)
index 0000000..28d8cae
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Includes specific to the Director
+ *
+ *     Kern Sibbald, December MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "dird_conf.h"
+
+#define DIRECTOR_DAEMON 1
+
+/* The following includes are at the bottom of 
+ * this file rather than at the top because the
+ *  #include "jcr.h" uses the definition of JOB
+ * as supplied above.
+ */
+
+#include "cats/cats.h"
+
+#include "jcr.h"
+
+#include "protos.h"
+
+/* Globals that dird.c exports */
+extern int debug_level;
+extern time_t start_time;
+extern DIRRES *director;                     /* Director resource */
+extern char *working_directory;              /* export our working directory */
+extern int FDConnectTimeout;
+extern int SDConnectTimeout;
+
+/* From job.c */
+void dird_free_jcr(JCR *jcr);
diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c
new file mode 100644 (file)
index 0000000..aea47de
--- /dev/null
@@ -0,0 +1,1077 @@
+/*
+ *   Main configuration file parser for Bacula Directors,
+ *    some parts may be split into separate files such as
+ *    the schedule configuration (sch_config.c).
+ *
+ *   Note, the configuration file parser consists of three parts
+ *
+ *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
+ *
+ *   2. The generic config  scanner in lib/parse_config.c and 
+ *     lib/parse_config.h.
+ *     These files contain the parser code, some utility
+ *     routines, and the common store routines (name, int,
+ *     string).
+ *
+ *   3. The daemon specific file, which contains the Resource
+ *     definitions as well as any specific store routines
+ *     for the resource records.
+ *
+ *     Kern Sibbald, January MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Define the first and last resource ID record
+ * types. Note, these should be unique for each
+ * daemon though not a requirement.
+ */
+int r_first = R_FIRST;
+int r_last  = R_LAST;
+pthread_mutex_t res_mutex =  PTHREAD_MUTEX_INITIALIZER;
+
+/* Imported subroutines */
+extern void store_run(LEX *lc, struct res_items *item, int index, int pass);
+
+
+/* Forward referenced subroutines */
+
+static void store_inc(LEX *lc, struct res_items *item, int index, int pass);
+static void store_backup(LEX *lc, struct res_items *item, int index, int pass);
+static void store_restore(LEX *lc, struct res_items *item, int index, int pass);
+
+
+/* We build the current resource here as we are
+ * scanning the resource configuration definition,
+ * then move it to allocated memory when the resource
+ * scan is complete.
+ */
+URES res_all;
+int  res_all_size = sizeof(res_all);
+
+
+/* Definition of records permitted within each
+ * resource with the routine to process the record 
+ * information.  NOTE! quoted names must be in lower case.
+ */ 
+/* 
+ *    Director Resource
+ *
+ *   name         handler     value                 code flags    default_value
+ */
+static struct res_items dir_items[] = {
+   {"name",        store_name,     ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str,      ITEM(res_dir.hdr.desc), 0, 0, 0},
+   {"messages",    store_res,      ITEM(res_dir.messages), R_MSGS, 0, 0},
+   {"dirport",     store_pint,     ITEM(res_dir.DIRport),  0, ITEM_REQUIRED, 0},
+   {"queryfile",   store_dir,      ITEM(res_dir.query_file), 0, 0, 0},
+   {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
+   {"piddirectory", store_dir,     ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
+   {"subsysdirectory", store_dir,  ITEM(res_dir.subsys_directory), 0, ITEM_REQUIRED, 0},
+   {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
+   {"password",    store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
+   {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
+   {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
+
+   {NULL, NULL, NULL, 0, 0, 0}
+};
+
+/* 
+ *    Client or File daemon resource
+ *
+ *   name         handler     value                 code flags    default_value
+ */
+
+static struct res_items cli_items[] = {
+   {"name",     store_name,       ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str,     ITEM(res_client.hdr.desc), 0, 0, 0},
+   {"address",  store_str,        ITEM(res_client.address),  0, ITEM_REQUIRED, 0},
+   {"fdport",   store_pint,       ITEM(res_client.FDport),   0, ITEM_REQUIRED, 0},
+   {"password", store_password,   ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
+   {"catalog",  store_res,        ITEM(res_client.catalog),  R_CATALOG, 0, 0},
+   {"catalogretentionperiod", store_time,      
+                        ITEM(res_client.cat_ret_period), 0, ITEM_DEFAULT, 60},
+   {"mediaretentionperiod", store_time,      
+                        ITEM(res_client.media_ret_period), 0, ITEM_DEFAULT, 60},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* Storage daemon resource
+ *
+ *   name         handler     value                 code flags    default_value
+ */
+static struct res_items store_items[] = {
+   {"name",      store_name,     ITEM(res_store.hdr.name),   0, ITEM_REQUIRED, 0},
+   {"description", store_str,    ITEM(res_store.hdr.desc),   0, 0, 0},
+   {"sdport",    store_pint,     ITEM(res_store.SDport),     0, ITEM_REQUIRED, 0},
+   {"sddport",   store_pint,     ITEM(res_store.SDDport),    0, 0, 0}, /* deprecated */
+   {"address",   store_str,      ITEM(res_store.address),    0, ITEM_REQUIRED, 0},
+   {"password",  store_password, ITEM(res_store.password),   0, ITEM_REQUIRED, 0},
+   {"device",    store_strname,  ITEM(res_store.dev_name),   0, ITEM_REQUIRED, 0},
+   {"mediatype", store_strname,  ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* 
+ *    Catalog Resource Directives
+ *
+ *   name         handler     value                 code flags    default_value
+ */
+static struct res_items cat_items[] = {
+   {"name",     store_name,     ITEM(res_cat.hdr.name),    0, ITEM_REQUIRED, 0},
+   {"description", store_str,   ITEM(res_cat.hdr.desc),    0, 0, 0},
+   {"address",  store_str,      ITEM(res_cat.address),     0, 0, 0},
+   {"dbport",   store_pint,     ITEM(res_cat.DBport),      0, 0, 0},
+   /* keep this password as store_str for the moment */
+   {"password", store_str,      ITEM(res_cat.db_password), 0, 0, 0},
+   {"user",     store_str,      ITEM(res_cat.db_user),     0, 0, 0},
+   {"dbname",   store_str,      ITEM(res_cat.db_name),     0, ITEM_REQUIRED, 0},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* 
+ *    Job Resource Directives
+ *
+ *   name         handler     value                 code flags    default_value
+ */
+static struct res_items job_items[] = {
+   {"name",     store_name,   ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
+   {"backup",   store_backup, ITEM(res_job),          JT_BACKUP, 0, 0},
+   {"verify",   store_backup, ITEM(res_job),          JT_VERIFY, 0, 0},
+   {"restore",  store_restore, ITEM(res_job),         JT_RESTORE, 0, 0},
+   {"schedule", store_res,    ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
+   {"messages", store_res,    ITEM(res_job.messages), R_MSGS, 0, 0},
+   {"storage",  store_res,    ITEM(res_job.storage),  R_STORAGE, 0, 0},
+   {"pool",     store_res,    ITEM(res_job.pool),     R_POOL, 0, 0},
+   {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
+   {"maxstartdelay", store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* FileSet resource
+ *
+ *   name         handler     value                 code flags    default_value
+ */
+static struct res_items fs_items[] = {
+   {"name",        store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str,  ITEM(res_fs.hdr.desc), 0, 0, 0},
+   {"include",     store_inc,  NULL,                  0, 0, 0},
+   {"exclude",     store_inc,  NULL,                  1, 0, 0},
+   {NULL,         NULL,       NULL,                  0, 0, 0} 
+};
+
+/* Schedule -- see run_conf.c */
+/* Schedule
+ *
+ *   name         handler     value                 code flags    default_value
+ */
+static struct res_items sch_items[] = {
+   {"name",     store_name,  ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
+   {"run",      store_run,   ITEM(res_sch.run),      0, 0, 0},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* Group resource -- not implemented
+ *
+ *   name         handler     value                 code flags    default_value
+ */
+static struct res_items group_items[] = {
+   {"name",        store_name, ITEM(res_group.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str,  ITEM(res_group.hdr.desc), 0, 0, 0},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* Pool resource
+ *
+ *   name            handler     value                        code flags default_value
+ */
+static struct res_items pool_items[] = {
+   {"name",            store_name,    ITEM(res_pool.hdr.name),        0, ITEM_REQUIRED, 0},
+   {"description",     store_str,     ITEM(res_pool.hdr.desc),        0, 0,             0},
+   {"pooltype",        store_strname, ITEM(res_pool.pool_type),       0, ITEM_REQUIRED, 0},
+   {"labelformat",     store_strname, ITEM(res_pool.label_format),    0, 0,             0},
+   {"usecatalog",      store_yesno, ITEM(res_pool.use_catalog),     1, ITEM_DEFAULT,  1},
+   {"usevolumeonce",   store_yesno, ITEM(res_pool.use_volume_once), 1, 0,             0},
+   {"maximumvolumes",  store_pint,  ITEM(res_pool.max_volumes),     0, 0,             0},
+   {"acceptanyvolume", store_yesno, ITEM(res_pool.accept_any_volume), 1, 0,           0},
+   {"catalogfiles",    store_yesno, ITEM(res_pool.catalog_files),   1, ITEM_DEFAULT,  1},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* Message resource */
+extern struct res_items msgs_items[];
+
+/* 
+ * This is the master resource definition.  
+ * It must have one item for each of the resources.
+ *
+ *  name            items        rcode        res_head
+ */
+struct s_res resources[] = {
+   {"director",      dir_items,   R_DIRECTOR,  NULL},
+   {"client",        cli_items,   R_CLIENT,    NULL},
+   {"job",           job_items,   R_JOB,       NULL},
+   {"storage",       store_items, R_STORAGE,   NULL},
+   {"catalog",       cat_items,   R_CATALOG,   NULL},
+   {"schedule",      sch_items,   R_SCHEDULE,  NULL},
+   {"fileset",       fs_items,    R_FILESET,   NULL},
+   {"group",         group_items, R_GROUP,     NULL},
+   {"pool",          pool_items,  R_POOL,      NULL},
+   {"messages",      msgs_items,  R_MSGS,      NULL},
+   {NULL,           NULL,        0,           NULL}
+};
+
+
+/* Keywords (RHS) permitted in Job Level records   
+ *
+ *   level_name      level             level_class
+ */
+struct s_jl joblevels[] = {
+   {"full",          L_FULL,            JT_BACKUP},
+   {"incremental",   L_INCREMENTAL,     JT_BACKUP},
+   {"differential",  L_DIFFERENTIAL,    JT_BACKUP},
+   {"level",         L_LEVEL,           JT_BACKUP},
+   {"since",         L_SINCE,           JT_BACKUP},
+   {"catalog",       L_VERIFY_CATALOG,  JT_VERIFY},
+   {"initcatalog",   L_VERIFY_INIT,     JT_VERIFY},
+   {"volume",        L_VERIFY_VOLUME,   JT_VERIFY},
+   {"data",          L_VERIFY_DATA,     JT_VERIFY},
+   {NULL,           0}
+};
+
+/* Keywords (RHS) permitted in Backup and Verify records */
+static struct s_kw BakVerFields[] = {
+   {"client",        'C'},
+   {"fileset",       'F'},
+   {"level",         'L'}, 
+   {NULL,           0}
+};
+
+/* Keywords (RHS) permitted in Restore records */
+static struct s_kw RestoreFields[] = {
+   {"client",        'C'},
+   {"fileset",       'F'},
+   {"jobid",         'J'},            /* JobId to restore */
+   {"where",         'W'},            /* root of restore */
+   {"replace",       'R'},            /* replacement options */
+   {NULL,             0}
+};
+
+/* Options permitted in Restore replace= */
+static struct s_kw ReplaceOptions[] = {
+   {"always",         'A'},           /* always */
+   {"ifnewer",        'W'},
+   {"never",          'N'},
+   {NULL,              0}
+};
+
+
+
+/* Define FileSet KeyWord values */
+
+#define FS_KW_NONE        0
+#define FS_KW_COMPRESSION  1
+#define FS_KW_SIGNATURE    2
+#define FS_KW_ENCRYPTION   3
+#define FS_KW_VERIFY      4
+
+/* FileSet keywords */
+static struct s_kw FS_option_kw[] = {
+   {"compression", FS_KW_COMPRESSION},
+   {"signature",   FS_KW_SIGNATURE},
+   {"encryption",  FS_KW_ENCRYPTION},
+   {"verify",      FS_KW_VERIFY},
+   {NULL,         0}
+};
+
+/* Options for FileSet keywords */
+
+struct s_fs_opt {
+   char *name;
+   int keyword;
+   char option;
+};
+
+/* Options permitted for each keyword and resulting value */
+static struct s_fs_opt FS_options[] = {
+   {"md5",      FS_KW_SIGNATURE,    'M'},
+   {"gzip",     FS_KW_COMPRESSION,  'Z'},
+   {"blowfish", FS_KW_ENCRYPTION,   'B'},   /* ***FIXME*** not implemented */
+   {"3des",     FS_KW_ENCRYPTION,   '3'},   /* ***FIXME*** not implemented */
+   {NULL,      0,                   0}
+};
+
+char *level_to_str(int level)
+{
+   int i;
+   static char level_no[30];
+   char *str = level_no;
+
+   sprintf(level_no, "%d", level);    /* default if not found */
+   for (i=0; joblevels[i].level_name; i++) {
+      if (level == joblevels[i].level) {
+        str = joblevels[i].level_name;
+        break;
+      }
+   }
+   return str;
+}
+
+
+
+/* Dump contents of resource */
+void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...), void *sock)
+{
+   int i;
+   URES *res = (URES *)reshdr;
+   int recurse = 1;
+
+   if (res == NULL) {
+      sendit(sock, "No %s resource defined\n", res_to_str(type));
+      return;
+   }
+   if (type < 0) {                   /* no recursion */
+      type = - type;
+      recurse = 0;
+   }
+   switch (type) {
+      case R_DIRECTOR:
+         sendit(sock, "Director: name=%s maxjobs=%d FDtimeout=%d SDtimeout=%d\n", 
+           reshdr->name, res->res_dir.MaxConcurrentJobs, 
+           res->res_dir.FDConnectTimeout,
+           res->res_dir.SDConnectTimeout);
+        if (res->res_dir.query_file) {
+            sendit(sock, "   query_file=%s\n", res->res_dir.query_file);
+        }
+        if (res->res_dir.messages) {
+            sendit(sock, "  --> ");
+           dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
+        }
+        break;
+      case R_CLIENT:
+         sendit(sock, "Client: name=%s address=%s FDport=%d\n",
+           res->res_client.hdr.name, res->res_client.address, res->res_client.FDport);
+         sendit(sock, "CatRetPeriod=%d MediaRetPeriod=%d\n",
+           res->res_client.cat_ret_period, res->res_client.media_ret_period);
+        if (res->res_client.catalog) {
+            sendit(sock, "  --> ");
+           dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
+        }
+        break;
+      case R_STORAGE:
+         sendit(sock, "Storage: name=%s address=%s SDport=%d\n\
+         DeviceName=%s MediaType=%s\n",
+           res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
+           res->res_store.dev_name, res->res_store.media_type);
+        break;
+      case R_CATALOG:
+         sendit(sock, "Catalog: name=%s address=%s DBport=%d db_name=%s\n\
+         db_user=%s\n",
+           res->res_cat.hdr.name, res->res_cat.address, res->res_cat.DBport,
+           res->res_cat.db_name, res->res_cat.db_user);
+        break;
+      case R_JOB:
+         sendit(sock, "Job: name=%s JobType=%d level=%s\n", res->res_job.hdr.name, 
+           res->res_job.JobType, level_to_str(res->res_job.level));
+        if (res->res_job.client) {
+            sendit(sock, "  --> ");
+           dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
+        }
+        if (res->res_job.fs) {
+            sendit(sock, "  --> ");
+           dump_resource(-R_FILESET, (RES *)res->res_job.fs, sendit, sock);
+        }
+        if (res->res_job.schedule) {
+            sendit(sock, "  --> ");
+           dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
+        }
+        if (res->res_job.RestoreWhere) {
+            sendit(sock, "  --> Where=%s\n", res->res_job.RestoreWhere);
+        }
+        if (res->res_job.storage) {
+            sendit(sock, "  --> ");
+           dump_resource(-R_STORAGE, (RES *)res->res_job.storage, sendit, sock);
+        }
+        if (res->res_job.pool) {
+            sendit(sock, "  --> ");
+           dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
+        } else {
+            sendit(sock, "!!! No Pool resource\n");
+        }
+        if (res->res_job.messages) {
+            sendit(sock, "  --> ");
+           dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
+        }
+        break;
+      case R_FILESET:
+         sendit(sock, "FileSet: name=%s\n", res->res_fs.hdr.name);
+        for (i=0; i<res->res_fs.num_includes; i++)
+            sendit(sock, "      Inc: %s\n", res->res_fs.include_array[i]);
+        for (i=0; i<res->res_fs.num_excludes; i++)
+            sendit(sock, "      Exc: %s\n", res->res_fs.exclude_array[i]);
+        break;
+      case R_SCHEDULE:
+        if (res->res_sch.run)
+            sendit(sock, "Schedule: name=%s Level=%s\n", res->res_sch.hdr.name,
+              level_to_str(res->res_sch.run->level));
+        else
+            sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name);
+        break;
+      case R_GROUP:
+         sendit(sock, "Group: name=%s\n", res->res_group.hdr.name);
+        break;
+      case R_POOL:
+         sendit(sock, "Pool: name=%s PoolType=%s\n", res->res_pool.hdr.name,
+                res->res_pool.pool_type);
+         sendit(sock, "      use_cat=%d use_once=%d acpt_any=%d\n",
+                res->res_pool.use_catalog, res->res_pool.use_volume_once,
+                res->res_pool.accept_any_volume);
+         sendit(sock, "      cat_files=%d max_vols=%d\n",
+                res->res_pool.catalog_files, res->res_pool.max_volumes);
+         sendit(sock, "      LabelFormat=%s\n", res->res_pool.label_format?
+                 res->res_pool.label_format:"NONE");
+        break;
+      case R_MSGS:
+         sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
+        if (res->res_msgs.mail_cmd) 
+            sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
+        if (res->res_msgs.operator_cmd) 
+            sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
+        break;
+      default:
+         sendit(sock, "Unknown resource type %d\n", type);
+        break;
+   }
+   if (recurse && res->res_dir.hdr.next) {
+      dump_resource(type, res->res_dir.hdr.next, sendit, sock);
+   }
+}
+
+/* 
+ * Free memory of resource.  
+ * NB, we don't need to worry about freeing any references
+ * to other resources as they will be freed when that 
+ * resource chain is traversed.  Mainly we worry about freeing
+ * allocated strings (names).
+ */
+void free_resource(int type)
+{
+   int num;
+   URES *res;
+   RES *nres;
+   int rindex = type - r_first;
+
+   res = (URES *)resources[rindex].res_head;
+
+   if (res == NULL)
+      return;
+
+   /* common stuff -- free the resource name and description */
+   nres = (RES *)res->res_dir.hdr.next;
+   if (res->res_dir.hdr.name) {
+      free(res->res_dir.hdr.name);
+   }
+   if (res->res_dir.hdr.desc) {
+      free(res->res_dir.hdr.desc);
+   }
+
+   switch (type) {
+      case R_DIRECTOR:
+        if (res->res_dir.working_directory)
+           free(res->res_dir.working_directory);
+        if (res->res_dir.pid_directory)
+           free(res->res_dir.pid_directory);
+        if (res->res_dir.subsys_directory)
+           free(res->res_dir.subsys_directory);
+        if (res->res_dir.password)
+           free(res->res_dir.password);
+        if (res->res_dir.query_file)
+           free(res->res_dir.query_file);
+        break;
+      case R_CLIENT:
+        if (res->res_client.address)
+           free(res->res_client.address);
+        if (res->res_client.password)
+           free(res->res_client.password);
+        break;
+      case R_STORAGE:
+        if (res->res_store.address)
+           free(res->res_store.address);
+        if (res->res_store.password)
+           free(res->res_store.password);
+        if (res->res_store.media_type)
+           free(res->res_store.media_type);
+        if (res->res_store.dev_name)
+           free(res->res_store.dev_name);
+        break;
+      case R_CATALOG:
+        if (res->res_cat.address)
+           free(res->res_cat.address);
+        if (res->res_cat.db_user)
+           free(res->res_cat.db_user);
+        if (res->res_cat.db_name)
+           free(res->res_cat.db_name);
+        if (res->res_cat.db_password)
+           free(res->res_cat.db_password);
+        break;
+      case R_FILESET:
+        if ((num=res->res_fs.num_includes)) {
+           while (--num >= 0)    
+              free(res->res_fs.include_array[num]);
+           free(res->res_fs.include_array);
+        }
+        if ((num=res->res_fs.num_excludes)) {
+           while (--num >= 0)    
+              free(res->res_fs.exclude_array[num]);
+           free(res->res_fs.exclude_array);
+        }
+        break;
+      case R_POOL:
+        if (res->res_pool.pool_type) {
+           free(res->res_pool.pool_type);
+        }
+        if (res->res_pool.label_format) {
+           free(res->res_pool.label_format);
+        }
+        break;
+      case R_SCHEDULE:
+        if (res->res_sch.run) {
+           RUN *nrun, *next;
+           nrun = res->res_sch.run;
+           while (nrun) {
+              next = nrun->next;
+              free(nrun);
+              nrun = next;
+           }
+        }
+        break;
+      case R_JOB:
+        if (res->res_job.RestoreWhere) {
+           free(res->res_job.RestoreWhere);
+        }
+        break;
+      case R_MSGS:
+        if (res->res_msgs.mail_cmd)
+           free(res->res_msgs.mail_cmd);
+        if (res->res_msgs.operator_cmd)
+           free(res->res_msgs.operator_cmd);
+
+        break;
+      case R_GROUP:
+        break;
+      default:
+         printf("Unknown resource type %d\n", type);
+   }
+   /* Common stuff again -- free the resource, recurse to next one */
+   free(res);
+   resources[rindex].res_head = nres;
+   if (nres)
+      free_resource(type);
+}
+
+/* Save the new resource by chaining it into the head list for
+ * the resource. If this is pass 2, we update any resource
+ * pointers (currently only in the Job resource).
+ */
+void save_resource(int type, struct res_items *items, int pass)
+{
+   URES *res;
+   int rindex = type - r_first;
+   int i, size;
+   int error = 0;
+   
+   /* 
+    * Ensure that all required items are present
+    */
+   for (i=0; items[i].name; i++) {
+      if (items[i].flags & ITEM_REQUIRED) {
+           if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {  
+               Emsg2(M_ABORT, 0, "%s item is required in %s resource, but not found.\n",
+                items[i].name, resources[rindex]);
+            }
+      }
+      /* If this triggers, take a look at lib/parse_conf.h */
+      if (i >= MAX_RES_ITEMS) {
+         Emsg1(M_ABORT, 0, "Too many items in %s resource\n", resources[rindex]);
+      }
+   }
+
+   /* During pass 2, we looked up pointers to all the resources
+    * referrenced in the current resource, , now we
+    * must copy their address from the static record to the allocated
+    * record.
+    */
+   if (pass == 2) {
+      switch (type) {
+        /* Resources not containing a resource */
+        case R_CATALOG:
+        case R_STORAGE:
+        case R_FILESET:
+        case R_SCHEDULE:
+        case R_GROUP:
+        case R_POOL:
+        case R_MSGS:
+           break;
+
+        /* Resources containing another resource */
+        case R_DIRECTOR:
+           if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
+               Emsg1(M_ABORT, 0, "Cannot find Director resource %s\n", res_all.res_dir.hdr.name);
+           }
+           res->res_dir.messages = res_all.res_dir.messages;
+           break;
+        case R_JOB:
+           if ((res = (URES *)GetResWithName(R_JOB, res_all.res_dir.hdr.name)) == NULL) {
+               Emsg1(M_ABORT, 0, "Cannot find Job resource %s\n", res_all.res_dir.hdr.name);
+           }
+           res->res_job.messages = res_all.res_job.messages;
+           res->res_job.schedule = res_all.res_job.schedule;
+           res->res_job.client   = res_all.res_job.client;
+           res->res_job.fs       = res_all.res_job.fs;
+           res->res_job.storage  = res_all.res_job.storage;
+           res->res_job.pool     = res_all.res_job.pool;
+           break;
+        case R_CLIENT:
+           if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
+               Emsg1(M_ABORT, 0, "Cannot find Client resource %s\n", res_all.res_client.hdr.name);
+           }
+           res->res_client.catalog = res_all.res_client.catalog;
+           break;
+        default:
+            Emsg1(M_ERROR, 0, "Unknown resource type %d\n", type);
+           error = 1;
+           break;
+      }
+      /* Note, the resource name was already saved during pass 1,
+       * so here, we can just release it.
+       */
+      if (res_all.res_dir.hdr.name) {
+        free(res_all.res_dir.hdr.name);
+        res_all.res_dir.hdr.name = NULL;
+      }
+      return;
+   }
+
+   switch (type) {
+      case R_DIRECTOR:
+        size = sizeof(DIRRES);
+        break;
+      case R_CLIENT:
+        size =sizeof(CLIENT);
+        break;
+      case R_STORAGE:
+        size = sizeof(STORE); 
+        break;
+      case R_CATALOG:
+        size = sizeof(CAT);
+        break;
+      case R_JOB:
+        size = sizeof(JOB);
+        break;
+      case R_FILESET:
+        size = sizeof(FILESET);
+        break;
+      case R_SCHEDULE:
+        size = sizeof(SCHED);
+        break;
+      case R_GROUP:
+        size = sizeof(GROUP);
+        break;
+      case R_POOL:
+        size = sizeof(POOL);
+        break;
+      case R_MSGS:
+        size = sizeof(MSGS);
+        break;
+      default:
+         printf("Unknown resource type %d\n", type);
+        error = 1;
+        break;
+   }
+   /* Common */
+   if (!error) {
+      res = (URES *) malloc(size);
+      memcpy(res, &res_all, size);
+      res->res_dir.hdr.next = resources[rindex].res_head;
+      resources[rindex].res_head = (RES *)res;
+      Dmsg2(90, "dir_conf: inserting %s res: %s\n", res_to_str(type),
+        res->res_dir.hdr.name);
+   }
+
+}
+
+/* 
+ * Store backup/verify info for Job record 
+ *
+ * Note, this code is used for both BACKUP and VERIFY jobs
+ *
+ *    Backup = Client=<client-name> FileSet=<FileSet-name> Level=<level>
+ */
+static void store_backup(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token, i;
+   RES *res;
+   int options = lc->options;
+
+   lc->options |= LOPT_NO_IDENT;      /* make spaces significant */
+
+   
+   ((JOB *)(item->value))->JobType = item->code;
+   while ((token = lex_get_token(lc)) != T_EOL) {
+      int found;
+
+      if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+         scan_err1(lc, "Expected a backup/verify keyword, got: %s", lc->str);
+      } else {
+        lcase(lc->str);
+         Dmsg1(190, "Got keyword: %s\n", lc->str);
+        found = FALSE;
+        for (i=0; BakVerFields[i].name; i++) {
+           if (strcmp(lc->str, BakVerFields[i].name) == 0) {
+              found = TRUE;
+              if (lex_get_token(lc) != T_EQUALS) {
+                  scan_err1(lc, "Expected an equals, got: %s", lc->str);
+              }
+              token = lex_get_token(lc);
+              if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+                  scan_err1(lc, "Expected a keyword name, got: %s", lc->str);
+              }
+               Dmsg1(190, "Got value: %s\n", lc->str);
+              switch (BakVerFields[i].token) {
+                  case 'C':
+                    /* Find Client Resource */
+                    if (pass == 2) {
+                       res = GetResWithName(R_CLIENT, lc->str);
+                       if (res == NULL) {
+                           scan_err1(lc, "Could not find specified Client Resource: %s",
+                                     lc->str);
+                       }
+                       res_all.res_job.client = (CLIENT *)res;
+                    }
+                    break;
+                  case 'F':
+                    /* Find FileSet Resource */
+                    if (pass == 2) {
+                       res = GetResWithName(R_FILESET, lc->str);
+                       if (res == NULL) {
+                           scan_err1(lc, "Could not find specified FileSet Resource: %s\n",
+                                      lc->str);
+                       }
+                       res_all.res_job.fs = (FILESET *)res;
+                    }
+                    break;
+                  case 'L':
+                    /* Get level */
+                    lcase(lc->str);
+                    for (i=0; joblevels[i].level_name; i++) {
+                       if (joblevels[i].job_class == item->code && 
+                            strcmp(lc->str, joblevels[i].level_name) == 0) {
+                          ((JOB *)(item->value))->level = joblevels[i].level;
+                          i = 0;
+                          break;
+                       }
+                    }
+                    if (i != 0) {
+                        scan_err1(lc, "Expected a Job Level keyword, got: %s", lc->str);
+                    }
+                    break;
+              } /* end switch */
+              break;
+           } /* end if strcmp() */
+        } /* end for */
+        if (!found) {
+            scan_err1(lc, "%s not a valid Backup/verify keyword", lc->str);
+        }
+      }
+   } /* end while */
+   lc->options = options;            /* reset original options */
+   set_bit(index, res_all.hdr.item_present);
+}
+
+/* 
+ * Store restore info for Job record 
+ *
+ *    Restore = JobId=<job-id> Where=<root-directory> Replace=<options>
+ *
+ */
+static void store_restore(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token, i;
+   RES *res;
+   int options = lc->options;
+
+   lc->options |= LOPT_NO_IDENT;      /* make spaces significant */
+
+   Dmsg0(190, "Enter store_restore()\n");
+   
+   ((JOB *)(item->value))->JobType = item->code;
+   while ((token = lex_get_token(lc)) != T_EOL) {
+      int found; 
+
+      if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+         scan_err1(lc, "Expected a Restore keyword, got: %s", lc->str);
+      } else {
+        lcase(lc->str);
+        found = FALSE;
+        for (i=0; RestoreFields[i].name; i++) {
+            Dmsg1(190, "Restore kw=%s\n", lc->str);
+           if (strcmp(lc->str, RestoreFields[i].name) == 0) {
+              found = TRUE;
+              if (lex_get_token(lc) != T_EQUALS) {
+                  scan_err1(lc, "Expected an equals, got: %s", lc->str);
+              }
+              token = lex_get_token(lc);
+               Dmsg1(190, "Restore value=%s\n", lc->str);
+              switch (RestoreFields[i].token) {
+                  case 'C':
+                    /* Find Client Resource */
+                    if (pass == 2) {
+                       res = GetResWithName(R_CLIENT, lc->str);
+                       if (res == NULL) {
+                           scan_err1(lc, "Could not find specified Client Resource: %s",
+                                     lc->str);
+                       }
+                       res_all.res_job.client = (CLIENT *)res;
+                    }
+                    break;
+                  case 'F':
+                    /* Find FileSet Resource */
+                    if (pass == 2) {
+                       res = GetResWithName(R_FILESET, lc->str);
+                       if (res == NULL) {
+                           scan_err1(lc, "Could not find specified FileSet Resource: %s\n",
+                                      lc->str);
+                       }
+                       res_all.res_job.fs = (FILESET *)res;
+                    }
+                    break;
+                  case 'J':
+                    /* JobId */
+                    if (token != T_NUMBER) {
+                        scan_err1(lc, "expected an integer number, got: %s", lc->str);
+                    }
+                    errno = 0;
+                    res_all.res_job.RestoreJobId = strtol(lc->str, NULL, 0);
+                     Dmsg1(190, "RestorJobId=%d\n", res_all.res_job.RestoreJobId);
+                    if (errno != 0) {
+                        scan_err1(lc, "expected an integer number, got: %s", lc->str);
+                    }
+                    break;
+                  case 'W':
+                    /* Where */
+                    if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+                        scan_err1(lc, "Expected a Restore root directory, got: %s", lc->str);
+                    }
+                    if (pass == 1) {
+                       res_all.res_job.RestoreWhere = bstrdup(lc->str);
+                    }
+                    break;
+                  case 'R':
+                    /* Replacement options */
+                    if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+                        scan_err1(lc, "Expected a keyword name, got: %s", lc->str);
+                    }
+                    lcase(lc->str);
+                    /* Fix to scan Replacement options */
+                    for (i=0; ReplaceOptions[i].name; i++) {
+                       if (strcmp(lc->str, ReplaceOptions[i].name) == 0) {
+                           ((JOB *)(item->value))->RestoreOptions = ReplaceOptions[i].token;
+                          i = 0;
+                          break;
+                       }
+                    }
+                    if (i != 0) {
+                        scan_err1(lc, "Expected a Restore replacement option, got: %s", lc->str);
+                    }
+                    break;
+              } /* end switch */
+              break;
+           } /* end if strcmp() */
+        } /* end for */
+        if (!found) {
+            scan_err1(lc, "%s not a valid Restore keyword", lc->str);
+        }
+      }
+   } /* end while */
+   lc->options = options;            /* reset original options */
+   set_bit(index, res_all.hdr.item_present);
+}
+
+
+
+/* 
+ * Scan for FileSet options
+ */
+static char *scan_fs_options(LEX *lc, int keyword)
+{
+   int token, i;
+   static char opts[100];
+   char option[2];
+
+   option[0] = 0;                    /* default option = none */
+   opts[0] = option[1] = 0;          /* terminate options */
+   for (;;) {
+      token = lex_get_token(lc);            /* expect at least one option */       
+      if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+         scan_err1(lc, "expected a FileSet option, got: %s", lc->str);
+      }
+      lcase(lc->str);
+      if (keyword == FS_KW_VERIFY) { /* special case */
+        /* ***FIXME**** ensure these are in permitted set */
+         strcpy(option, "V");         /* indicate Verify */
+        strcat(option, lc->str);
+         strcat(option, ":");         /* terminate it */
+      } else {
+        for (i=0; FS_options[i].name; i++) {
+           if (strcmp(lc->str, FS_options[i].name) == 0 && FS_options[i].keyword == keyword) {
+              option[0] = FS_options[i].option;
+              i = 0;
+              break;
+           }
+        }
+        if (i != 0) {
+            scan_err1(lc, "Expected a FileSet option keyword, got: %s", lc->str);
+        }
+      }
+      strcat(opts, option);
+
+      /* check if more options are specified */
+      if (lc->ch != ',') {
+        break;                       /* no, get out */
+      }
+      token = lex_get_token(lc);      /* yes, eat comma */
+   }
+
+   return opts;
+}
+
+
+/* Store FileSet Include/Exclude info */
+static void store_inc(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token, i;
+   int options = lc->options;
+   int keyword;
+   char *fname;
+   char inc_opts[100];
+   int inc_opts_len;
+
+   lc->options |= LOPT_NO_IDENT;      /* make spaces significant */
+
+   /* Get include options */
+   strcpy(inc_opts, "0");             /* set no options */
+   while ((token=lex_get_token(lc)) != T_BOB) {
+      if (token != T_STRING) {
+         scan_err1(lc, "expected a FileSet option keyword, got: %s", lc->str);
+      } else {
+        keyword = FS_KW_NONE;
+        lcase(lc->str);
+        for (i=0; FS_option_kw[i].name; i++) {
+           if (strcmp(lc->str, FS_option_kw[i].name) == 0) {
+              keyword = FS_option_kw[i].token;
+              break;
+           }
+        }
+        if (keyword == FS_KW_NONE) {
+            scan_err1(lc, "Expected a FileSet keyword, got: %s", lc->str);
+        }
+      }
+      /* Option keyword should be following by = <option> */
+      if ((token=lex_get_token(lc)) != T_EQUALS) {
+         scan_err1(lc, "expected an = following keyword, got: %s", lc->str);
+      }
+      strcat(inc_opts, scan_fs_options(lc, keyword));
+      if (token == T_BOB) {
+        break;
+      }
+   }
+   strcat(inc_opts, " ");             /* add field separator */
+   inc_opts_len = strlen(inc_opts);
+
+
+   if (pass == 1) {
+      if (!res_all.res_fs.have_MD5) {
+        MD5Init(&res_all.res_fs.md5c);
+        res_all.res_fs.have_MD5 = TRUE;
+      }
+      /* Pickup include/exclude names. Note, they are stored as
+       * XYZ fname
+       * where XYZ are the include/exclude options for the FileSet
+       *     a "0 " (zero) indicates no options,
+       * and fname is the file/directory name given
+       */
+      while ((token = lex_get_token(lc)) != T_EOB) {
+        switch (token) {
+           case T_COMMA:
+           case T_EOL:
+              continue;
+
+           case T_IDENTIFIER:
+           case T_STRING:
+           case T_QUOTED_STRING:
+              fname = (char *) malloc(lc->str_len + inc_opts_len + 1);
+              strcpy(fname, inc_opts);
+              strcat(fname, lc->str);
+              if (res_all.res_fs.have_MD5) {
+                 MD5Update(&res_all.res_fs.md5c, (unsigned char *) fname, inc_opts_len + lc->str_len);
+              }
+              if (item->code == 0) { /* include */
+                 if (res_all.res_fs.num_includes == res_all.res_fs.include_size) {
+                    res_all.res_fs.include_size += 10;
+                    if (res_all.res_fs.include_array == NULL) {
+                       res_all.res_fs.include_array = (char **) malloc(sizeof(char *) * res_all.res_fs.include_size);
+                    } else {
+                       res_all.res_fs.include_array = (char **) realloc(res_all.res_fs.include_array,
+                          sizeof(char *) * res_all.res_fs.include_size);
+                    }
+                 }
+                 res_all.res_fs.include_array[res_all.res_fs.num_includes++] =    
+                    fname;
+              } else {                /* exclude */
+                 if (res_all.res_fs.num_excludes == res_all.res_fs.exclude_size) {
+                    res_all.res_fs.exclude_size += 10;
+                    if (res_all.res_fs.exclude_array == NULL) {
+                       res_all.res_fs.exclude_array = (char **) malloc(sizeof(char *) * res_all.res_fs.exclude_size);
+                    } else {
+                       res_all.res_fs.exclude_array = (char **) realloc(res_all.res_fs.exclude_array,
+                          sizeof(char *) * res_all.res_fs.exclude_size);
+                    }
+                 }
+                 res_all.res_fs.exclude_array[res_all.res_fs.num_excludes++] =    
+                    fname;
+              }
+              break;
+           default:
+               scan_err1(lc, "Expected a filename, got: %s", lc->str);
+        }                                 
+      }
+   } else { /* pass 2 */
+      while (lex_get_token(lc) != T_EOB) 
+        {}
+   }
+   scan_to_eol(lc);
+   lc->options = options;
+   set_bit(index, res_all.hdr.item_present);
+}
diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h
new file mode 100644 (file)
index 0000000..161ac4f
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Director specific configuration and defines
+ *
+ *     Kern Sibbald, Feb MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* NOTE:  #includes at the end of this file */
+
+/*
+ * Resource codes -- they must be sequential for indexing   
+ */
+#define R_FIRST                      1001
+
+#define R_DIRECTOR                   1001
+#define R_CLIENT                     1002
+#define R_JOB                        1003
+#define R_STORAGE                    1004
+#define R_CATALOG                    1005
+#define R_SCHEDULE                   1006
+#define R_FILESET                    1007
+#define R_GROUP                      1008
+#define R_POOL                       1009
+#define R_MSGS                       1010
+
+#define R_LAST                       R_MSGS
+
+/*
+ * Some resource attributes
+ */
+#define R_NAME                       1020
+#define R_ADDRESS                    1021
+#define R_PASSWORD                   1022
+#define R_TYPE                       1023
+#define R_BACKUP                     1024
+
+
+/* Used for certain KeyWord tables */
+struct s_kw {      
+   char *name;
+   int token;  
+};
+
+/* Job Level keyword structure */
+struct s_jl {
+   char *level_name;
+   int level;
+   int job_class;
+};
+
+
+/* Definition of the contents of each Resource */
+
+/* 
+ *   Director Resource 
+ *
+ */
+struct s_res_dir {
+   RES  hdr;
+   int  DIRport;                     /* where we listen -- UA port server port */
+   char *password;                   /* Password for UA access */
+   char *query_file;                 /* SQL query file */
+   char *working_directory;          /* WorkingDirectory */
+   char *pid_directory;              /* PidDirectory */
+   char *subsys_directory;           /* SubsysDirectory */
+   struct s_res_msgs *messages;
+   int  MaxConcurrentJobs;
+   int  FDConnectTimeout;            /* timeout for connect in seconds */
+   int  SDConnectTimeout;            /* timeout in seconds */
+};
+typedef struct s_res_dir DIRRES;
+
+/*
+ *   Client Resource
+ *
+ */
+struct s_res_client {
+   RES  hdr;
+
+   int  FDport;                      /* Where File daemon listens */
+   int32_t cat_ret_period;           /* Catalog retention period */
+   int32_t media_ret_period;         /* Media retention period */
+   char *address;
+   char *password;
+   struct s_res_cat    *catalog;       /* Catalog resource */
+};
+typedef struct s_res_client CLIENT;
+
+/*
+ *   Store Resource
+ * 
+ */
+struct s_res_store {
+   RES  hdr;
+
+   int  SDport;                      /* port where Directors connect */
+   int  SDDport;                     /* data port for File daemon */
+   char *address;
+   char *password;
+   char *media_type;
+   char *dev_name;   
+};
+typedef struct s_res_store STORE;
+
+/*
+ *   Catalog Resource
+ *
+ */
+struct s_res_cat {
+   RES  hdr;
+
+   int  DBport;                      /* Port -- not yet implemented */
+   char *address;
+   char *db_password;
+   char *db_user;
+   char *db_name;
+};
+typedef struct s_res_cat CAT;
+
+/*
+ *   Job Resource
+ *
+ */
+struct s_res_job {
+   RES  hdr;
+
+   int  JobType;                     /* job type (backup, verify, restore */
+   int  level;                       /* default backup/verify level */
+   int  RestoreJobId;                /* What -- JobId to restore */
+   char *RestoreWhere;               /* Where on disk to restore -- directory */
+   int  RestoreOptions;              /* How (overwrite, ..) */
+   int  MaxRunTime;                  /* max run time in seconds */
+   int  MaxStartDelay;               /* max start delay in seconds */
+
+   struct s_res_msgs   *messages;     /* How and where to send messages */
+   struct s_res_sch    *schedule;     /* When -- Automatic schedule */
+   struct s_res_client *client;       /* Who to backup */
+   struct s_res_fs     *fs;          /* What to backup -- Fileset */
+   struct s_res_store  *storage;      /* Where is device -- Storage daemon */
+   struct s_res_pool   *pool;        /* Where is media -- Media Pool */
+};
+typedef struct s_res_job JOB;
+
+/* 
+ *   FileSet Resource
+ *
+ */
+struct s_res_fs {
+   RES  hdr;
+
+   char **include_array;
+   int num_includes;
+   int include_size;
+   char **exclude_array;
+   int num_excludes;
+   int exclude_size;
+   int have_MD5;                     /* set if MD5 initialized */
+   struct MD5Context md5c;           /* MD5 of include/exclude */
+};
+typedef struct s_res_fs FILESET;
+
+/* 
+ *   Schedule Resource
+ *
+ */
+struct s_res_sch {
+   RES  hdr;
+
+   struct s_run *run;
+};
+typedef struct s_res_sch SCHED;
+
+/*
+ *   Group Resource (not used)
+ *
+ */
+struct s_res_group {
+   RES  hdr;
+};
+typedef struct s_res_group GROUP;
+
+/*
+ *   Pool Resource   
+ *
+ */
+struct s_res_pool {
+   RES  hdr;
+
+   char *pool_type;
+   char *label_format;               /* Label format string */
+   int  use_catalog;                 /* maintain catalog for media */
+   int  catalog_files;               /* maintain file entries in catalog */
+   int  use_volume_once;             /* write on volume only once */
+   int  accept_any_volume;           /* accept any volume */
+   int  max_volumes;                 /* max number of volumes */
+};
+typedef struct s_res_pool POOL;
+
+
+/* Define the Union of all the above
+ * resource structure definitions.
+ */
+union u_res {
+   struct s_res_dir    res_dir;
+   struct s_res_client res_client;
+   struct s_res_store  res_store;
+   struct s_res_cat    res_cat;
+   struct s_res_job    res_job;
+   struct s_res_fs     res_fs;
+   struct s_res_sch    res_sch;
+   struct s_res_group  res_group;
+   struct s_res_pool   res_pool;
+   struct s_res_msgs   res_msgs;
+   RES hdr;
+};
+
+typedef union u_res URES;
+
+
+/* Run structure contained in Schedule Resource */
+struct s_run {
+   struct s_run *next;               /* points to next run record */
+   int level;
+   int job_class;  
+   char *since;
+   int level_no;
+   int minute;                       /* minute to run job */
+   time_t last_run;                  /* last time run */
+   time_t next_run;                  /* next time to run */
+   char hour[nbytes_for_bits(24)];    /* bit set for each hour */
+   char mday[nbytes_for_bits(31)];    /* bit set for each day of month */
+   char month[nbytes_for_bits(12)];   /* bit set for each month */
+   char wday[nbytes_for_bits(7)];     /* bit set for each day of the week */
+};
+typedef struct s_run RUN;
diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c
new file mode 100644 (file)
index 0000000..f358f4e
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ *
+ *   Bacula Director -- fd_cmds.c -- send commands to File daemon
+ *
+ *     Kern Sibbald, October MM
+ *
+ *    This routine is run as a separate thread.  There may be more
+ *    work to be done to make it totally reentrant!!!!
+ * 
+ *  Utility functions for sending info to File Daemon.
+ *   These functions are used by both backup and verify.
+ *   
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Commands sent to File daemon */
+static char inc[]         = "include\n";
+static char exc[]         = "exclude\n";
+static char jobcmd[]      = "JobId=%d Job=%s SDid=%u SDtime=%u Authorization=%s\n";
+
+
+/* Responses received from File daemon */
+static char OKinc[]      = "2000 OK include\n";
+static char OKexc[]      = "2000 OK exclude\n";
+static char OKjob[]      = "2000 OK Job\n";
+
+/* Forward referenced functions */
+
+/* External functions */
+extern int debug_level;
+extern DIRRES *director; 
+extern int FDConnectTimeout;
+
+/*
+ * Open connection with File daemon. 
+ * Try connecting every 10 seconds, give up after 1 hour.
+ */
+
+int connect_to_file_daemon(JCR *jcr, int retry_interval, int max_retry_time,
+                          int verbose)
+{
+   BSOCK   *fd;
+
+   fd = bnet_connect(jcr, retry_interval, max_retry_time,
+        _("File daemon"), jcr->client->address, 
+       NULL, jcr->client->FDport, verbose);
+   if (fd == NULL) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+   Dmsg0(10, "Opened connection with File daemon\n");
+   fd->res = (RES *)jcr->client;      /* save resource in BSOCK */
+   jcr->file_bsock = fd;
+   jcr->JobStatus = JS_Running;
+
+   if (!authenticate_file_daemon(jcr)) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+       
+   /*
+    * Now send JobId and authorization key
+    */
+   bnet_fsend(fd, jobcmd, jcr->JobId, jcr->Job, jcr->VolSessionId, 
+      jcr->VolSessionTime, jcr->sd_auth_key);
+   Dmsg1(10, ">filed: %s", fd->msg);
+   if (bnet_recv(fd) > 0) {
+       Dmsg1(10, "<filed: %s", fd->msg);
+       if (strcmp(fd->msg, OKjob) != 0) {
+          Jmsg(jcr, M_FATAL, 0, _("File daemon rejected Job command: %s\n"), fd->msg);
+         jcr->JobStatus = JS_ErrorTerminated;
+         return 0;
+       } 
+   } else {
+      Jmsg(jcr, M_FATAL, 0, _("<filed: bad response to JobId command: %s\n"),
+        bnet_strerror(fd));
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+   return 1;
+}
+
+
+/*
+ * Send include list to File daemon
+ */
+int send_include_list(JCR *jcr)
+{
+   FILESET *fileset;
+   BSOCK   *fd;
+   int i;
+   char *msgsave;
+
+   fd = jcr->file_bsock;
+   fileset = jcr->fileset;
+
+   msgsave = fd->msg;
+
+   fd->msglen = sprintf(fd->msg, inc);
+   bnet_send(fd);
+   for (i=0; i < fileset->num_includes; i++) {
+      fd->msglen = strlen(fileset->include_array[i]);
+      Dmsg1(20, "dird>filed: include file: %s\n", fileset->include_array[i]);
+      fd->msg = fileset->include_array[i];
+      if (!bnet_send(fd)) {
+         Emsg0(M_FATAL, 0, _(">filed: write error on socket\n"));
+        jcr->JobStatus = JS_ErrorTerminated;
+        return 0;
+      }
+   }
+   bnet_sig(fd, BNET_EOF);
+   fd->msg = msgsave;
+   if (!response(fd, OKinc, "Include")) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+   return 1;
+}
+
+/*
+ * Send exclude list to File daemon 
+ */
+int send_exclude_list(JCR *jcr)
+{
+   FILESET *fileset;
+   BSOCK   *fd;
+   int i;
+   char *msgsave;
+
+   fd = jcr->file_bsock;
+   fileset = jcr->fileset;
+
+   msgsave = fd->msg;
+   fd->msglen = sprintf(fd->msg, exc);
+   bnet_send(fd);
+   for (i=0; i < fileset->num_excludes; i++) {
+      fd->msglen = strlen(fileset->exclude_array[i]);
+      Dmsg1(20, "dird>filed: exclude file: %s\n", fileset->exclude_array[i]);
+      fd->msg = fileset->exclude_array[i];
+      if (!bnet_send(fd)) {
+         Emsg0(M_FATAL, 0, _(">filed: write error on socket\n"));
+        jcr->JobStatus = JS_ErrorTerminated;
+        return 0;
+      }
+   }
+   bnet_sig(fd, BNET_EOF);
+   fd->msg = msgsave;
+   if (!response(fd, OKexc, "Exclude")) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+   return 1;
+}
+
+
+/* 
+ * Read the attributes from the File daemon for
+ * a Verify job and store them in the catalog.
+ */
+int get_attributes_and_put_in_catalog(JCR *jcr)
+{
+   BSOCK   *fd;
+   int n;
+   ATTR_DBR ar;
+
+   fd = jcr->file_bsock;
+   jcr->jr.FirstIndex = 1;
+   memset(&ar, 0, sizeof(ar));
+
+   Dmsg0(20, "bdird: waiting to receive file attributes\n");
+   /* Pickup file attributes and signature */
+   while (!fd->errors && (n = bget_msg(fd, 0)) > 0) {
+
+   /*****FIXME****** improve error handling to stop only on 
+    * really fatal problems, or the number of errors is too
+    * large.
+    */
+       long file_index;
+       int stream, len;
+       char *attr, buf[MAXSTRING];
+       char Opts[MAXSTRING];         /* either Verify opts or MD5 signature */
+
+       /* ***FIXME*** check fname length */
+       if ((len = sscanf(fd->msg, "%ld %d %s %s", &file_index, &stream, 
+            Opts, jcr->fname)) != 4) {
+          Jmsg(jcr, M_FATAL, 0, _("<filed: bad attributes, expected 4 fields got %d\n\
+msglen=%d msg=%s\n"), len, fd->msglen, fd->msg);
+         jcr->JobStatus = JS_ErrorTerminated;
+         return 0;
+       }
+
+       if (stream == STREAM_UNIX_ATTRIBUTES) {
+         len = strlen(fd->msg);      /* length before attributes */
+         ar.attr = &fd->msg[len+1];
+         ar.fname = jcr->fname;
+         ar.FileIndex = 0;           /* used as mark field during compare */
+         ar.Stream = stream;
+         ar.link = NULL;
+         ar.JobId = jcr->JobId;
+         ar.ClientId = jcr->ClientId;
+         ar.PathId = 0;
+         ar.FilenameId = 0;
+
+          Dmsg2(11, "dird<filed: stream=%d %s\n", stream, jcr->fname);
+          Dmsg1(20, "dird<filed: attr=%s\n", attr);
+
+         /* ***FIXME*** fix link field */
+         if (!db_create_file_attributes_record(jcr->db, &ar)) {
+             Jmsg1(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+            jcr->JobStatus = JS_ErrorTerminated;
+            /* This probably should not really be fatal *****FIXME****** */
+            return 0;
+         }
+         jcr->FileIndex = file_index;
+         jcr->FileId = ar.FileId;
+       } else if (stream == STREAM_MD5_SIGNATURE) {
+         if (jcr->FileIndex != (uint32_t)file_index) {
+             Jmsg0(jcr, M_FATAL, 0, _("Got MD5 but not same block as attributes\n"));
+            jcr->JobStatus = JS_ErrorTerminated;
+            return 0;
+         }
+         db_escape_string(buf, Opts, strlen(Opts));
+          Dmsg2(20, "MD5len=%d MD5=%s\n", strlen(buf), buf);
+         if (!db_add_MD5_to_file_record(jcr->db, jcr->FileId, buf)) {
+             Jmsg1(jcr, M_WARNING, 0, "%s", db_strerror(jcr->db));
+         }
+       }
+       jcr->jr.JobFiles = file_index;
+       jcr->jr.LastIndex = file_index;
+   } 
+   if (n < 0) {
+      Jmsg1(jcr, M_FATAL, 0, _("<filed: Network error getting attributes. ERR=%s\n"),
+                       bnet_strerror(fd));
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+
+   jcr->JobStatus = JS_Terminated;
+   return 1;
+}
diff --git a/bacula/src/dird/getmsg.c b/bacula/src/dird/getmsg.c
new file mode 100644 (file)
index 0000000..b37abe2
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ *
+ *   Bacula Director -- routines to receive network data and
+ *    handle network signals. These routines handle the connections
+ *    to the Storage daemon and the File daemon.
+ *
+ *     Kern Sibbald, August MM
+ *
+ *    This routine runs as a thread and must be thread reentrant.
+ *
+ *  Basic tasks done here:
+ *    Handle  network signals (signals).  
+ *      Signals always have return status 0 from bnet_recv() and
+ *      a zero or negative message length.
+ *    Pass appropriate messages back to the caller (responses).  
+ *      Responses always have a digit as the first character.
+ *    Handle requests for message and catalog services (requests).  
+ *      Requests are any message that does not begin with a digit.
+ *      In affect, they are commands.
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Forward referenced functions */
+static char *find_msg_start(char *msg);
+
+static char OK_msg[] = "1000 OK\n";
+
+/*
+ * Get a message
+ *  Call appropriate processing routine
+ *  If it is not a Jmsg or a ReqCat message,
+ *   return it to the caller.
+ *
+ *  This routine is called to get the next message from
+ *  another daemon. If the message is in canonical message
+ *  format and the type is known, it will be dispatched
+ *  to the appropriate handler.  If the message is
+ *  in any other format, it will be returned. 
+ *
+ */
+int32_t bget_msg(BSOCK *bs, int rtn)
+{
+   int32_t n;
+   char Job[MAX_NAME_LENGTH];
+   char MsgType[20];
+   int type, level;
+   JCR *jcr;
+   char *msg;
+
+   for (;;) {
+      n = bnet_recv(bs);
+      Dmsg2(120, "bget_msg %d: %s\n", n, bs->msg);
+
+      if (n < 0) {
+        return n;                    /* error return */
+      }
+      if (n == 0) {                  /* handle signal */
+        /* 0 return from bnet_recv() => network signal */
+        switch (bs->msglen) {
+           case BNET_EOF:               /* deprecated */
+           case BNET_EOD:               /* end of data */
+              return 0;
+           case BNET_EOD_POLL:
+              bnet_fsend(bs, OK_msg);   /* send response */
+              return 0;                 /* end of data */
+           case BNET_TERMINATE:
+              bs->terminated = 1;
+              return 0;
+           case BNET_POLL:
+              bnet_fsend(bs, OK_msg);   /* send response */
+              break;
+           case BNET_HEARTBEAT:
+              bnet_sig(bs, BNET_HB_RESPONSE);
+              break;
+           case BNET_STATUS:
+              /* *****FIXME***** Implement */
+               bnet_fsend(bs, "Status OK\n");
+              bnet_sig(bs, BNET_EOD);
+              break;
+           default:
+               Emsg1(M_WARNING, 0, _("bget_msg: unknown signal %d\n"), bs->msglen);
+              return 0;
+        }
+        continue;
+      }
+     
+      /* Handle normal data */
+
+      if (ISDIGIT(bs->msg[0])) {      /* response? */
+        return n;                    /* yes, return it */
+      }
+       
+      /*
+       * If we get here, it must be a request. Either
+       *  a message to dispatch, or a catalog request.
+       *  Try to fulfill it.
+       */
+      if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
+         Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+        continue;
+      }
+      if (!(jcr=get_jcr_by_full_name(Job))) {
+         Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg);
+        continue;
+      }
+
+      /* Skip past "Jmsg Job=nnn" */
+      if (!(msg=find_msg_start(bs->msg))) {
+         Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+        free_jcr(jcr);
+        continue;
+      }
+
+      /* 
+       * Here we are expecting a message of the following format:
+       *   Jmsg Job=nnn type=nnn level=nnn Message-string
+       */
+      if (bs->msg[0] == 'J') {           /* Job message */
+         if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%d", 
+                   Job, &type, &level) != 3) {
+            Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+           free_jcr(jcr);
+           continue;
+        }
+         Dmsg1(120, "Got msg: %s\n", bs->msg);
+        skip_spaces(&msg);
+        skip_nonspaces(&msg);        /* skip type=nnn */
+        skip_spaces(&msg);
+        skip_nonspaces(&msg);        /* skip level=nnn */
+         if (*msg == ' ') {
+           msg++;                    /* skip leading space */
+        }
+         Dmsg1(120, "Dispatch msg: %s", msg);
+        dispatch_message(jcr, type, level, msg);
+        free_jcr(jcr);
+        continue;
+      }
+      /* 
+       * Here we expact a CatReq message
+       *   CatReq Job=nn Catalog-Request-Message
+       */
+      if (bs->msg[0] == 'C') {        /* Catalog request */
+         Dmsg1(120, "Catalog req: %s", bs->msg);
+        catalog_request(jcr, bs, msg);
+        free_jcr(jcr);
+        continue;
+      }
+      if (bs->msg[0] == 'U') {        /* Catalog update */
+        catalog_update(jcr, bs, msg);
+        free_jcr(jcr);
+        continue;
+      }
+      if (bs->msg[0] == 'M') {        /* Mount request */
+         Dmsg1(120, "Mount req: %s", bs->msg);
+        mount_request(jcr, bs, msg);
+        free_jcr(jcr);
+        continue;
+      }
+      return n;
+   }
+}
+
+static char *find_msg_start(char *msg)
+{
+   char *p = msg;
+
+   skip_nonspaces(&p);               /* skip message type */
+   skip_spaces(&p);
+   skip_nonspaces(&p);               /* skip Job */
+   skip_spaces(&p);                  /* after spaces come the message */
+   return p;
+}
+
+/*
+ * Get response from File daemon to a command we
+ * sent. Check that the response agrees with what we expect.
+ *
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int response(BSOCK *fd, char *resp, char *cmd)
+{
+   int n;
+
+   if (fd->errors) {
+      return 0;
+   }
+   if ((n = bget_msg(fd, 0)) > 0) {
+      Dmsg0(10, fd->msg);
+      if (strcmp(fd->msg, resp) == 0) {
+        return 1;
+      }
+      Emsg3(M_FATAL, 0, _("<filed: bad response to %s command: wanted %s got: %s\n"),
+        cmd, resp, fd->msg);
+      return 0;
+   } 
+   Emsg2(M_FATAL, 0, _("<filed: Socket error from Filed on %s command: ERR=%s\n"),
+        cmd, bnet_strerror(fd));
+   return 0;
+}
diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c
new file mode 100644 (file)
index 0000000..9200cca
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ *
+ *   Bacula Director Job processing routines
+ *
+ *     Kern Sibbald, October MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Forward referenced subroutines */
+static void job_thread(void *arg);
+
+/* Exported subroutines */
+void run_job(JCR *jcr);
+void init_job_server(int max_workers);
+
+
+/* Imported subroutines */
+extern void term_scheduler();
+extern void term_ua_server();
+extern int do_backup(JCR *jcr);
+extern int do_restore(JCR *jcr);
+extern int do_verify(JCR *jcr);
+extern void backup_cleanup(void);
+extern void start_UA_server(int port);
+
+/* Queue of jobs to be run */
+static workq_t job_wq;               /* our job work queue */
+
+
+void init_job_server(int max_workers)
+{
+   int stat;
+
+   if ((stat = workq_init(&job_wq, max_workers, job_thread)) != 0) {
+      Emsg1(M_ABORT, 0, _("Could not init job work queue: ERR=%s\n"), strerror(stat));
+   }
+   return;
+}
+
+/*
+ * Run a job
+ *
+ */
+void run_job(JCR *jcr)
+{
+   int stat, errstat;
+
+   create_unique_job_name(jcr, jcr->job->hdr.name);
+   jcr->jr.SchedTime = jcr->sched_time;
+   jcr->jr.StartTime = jcr->start_time;
+   jcr->jr.Type = jcr->JobType;
+   jcr->jr.Level = jcr->level;
+   strcpy(jcr->jr.Name, jcr->job->hdr.name);
+   strcpy(jcr->jr.Job, jcr->Job);
+
+   /* Initialize termination condition variable */
+   if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
+      Emsg1(M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat));
+      jcr->JobStatus = JS_ErrorTerminated;
+      free_jcr(jcr);
+      return;
+   }
+
+   /*
+    * Open database
+    */
+   Dmsg0(50, "Open database\n");
+   jcr->db=db_init_database(jcr->catalog->db_name, jcr->catalog->db_user,
+                           jcr->catalog->db_password);
+   if (!db_open_database(jcr->db)) {
+      Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+      db_close_database(jcr->db);
+      jcr->JobStatus = JS_ErrorTerminated;
+      free_jcr(jcr);
+      return;
+   }
+   Dmsg0(50, "DB opened\n");
+
+
+   /*
+    * Create Job record  
+    */
+   jcr->jr.JobStatus = jcr->JobStatus;
+   if (!db_create_job_record(jcr->db, &jcr->jr)) {
+      Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+      db_close_database(jcr->db);
+      jcr->JobStatus = JS_ErrorTerminated;
+      free_jcr(jcr);
+      return;
+   }
+   jcr->JobId = jcr->jr.JobId;
+   ASSERT(jcr->jr.JobId > 0);
+
+   Dmsg4(30, "Created job record JobId=%d Name=%s Type=%c Level=%c\n", 
+       jcr->JobId, jcr->Job, jcr->jr.Type, jcr->jr.Level);
+   Dmsg0(200, "Add jrc to work queue\n");
+
+
+   /* Queue the job to be run */
+   if ((stat = workq_add(&job_wq, (void *)jcr)) != 0) {
+      Emsg1(M_ABORT, 0, _("Could not add job to work queue: ERR=%s\n"), strerror(stat));
+   }
+   Dmsg0(200, "Done run_job()\n");
+}
+
+/* This is the engine called by workq_add() */
+static void job_thread(void *arg)
+{
+   time_t now;
+   JCR *jcr = (JCR *)arg;
+
+   time(&now);
+
+   Dmsg0(100, "=====Start Job=========\n");
+   jcr->start_time = now;            /* set the real start time */
+   if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
+       (jcr->start_time - jcr->sched_time)) {
+      Jmsg(jcr, M_FATAL, 0, _("Job cancelled because max delay time exceeded.\n"));
+      free_jcr(jcr);
+   }
+   jcr->JobStatus = JS_Running;
+
+   switch (jcr->JobType) {
+      case JT_BACKUP:
+        do_backup(jcr);
+        break;
+      case JT_VERIFY:
+        do_verify(jcr);
+        break;
+      case JT_RESTORE:
+        do_restore(jcr);
+        break;
+      default:
+         Dmsg1(0, "Unimplemented job type: %d\n", jcr->JobType);
+        break;
+   }
+   Dmsg0(50, "Before free jcr\n");
+   free_jcr(jcr);
+   Dmsg0(50, "======== End Job ==========\n");
+}
+
+/*
+ * Takes base_name and appends (unique) current
+ *   date and time to form unique job name.
+ *
+ *  Returns: unique job name in jcr->Job
+ *    date/time in jcr->start_time
+ */
+void create_unique_job_name(JCR *jcr, char *base_name)
+{
+   /* Job start mutex */
+   static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+   static time_t last_start_time = 0;
+   time_t now;
+   struct tm tm;
+   char dt[MAX_TIME_LENGTH];
+   char name[MAX_NAME_LENGTH];
+   char *p;
+
+   /* Guarantee unique start time -- maximum one per second, and
+    * thus unique Job Name 
+    */
+   P(mutex);                         /* lock creation of jobs */
+   time(&now);
+   while (now == last_start_time) {
+      sleep(1);
+      time(&now);
+   }
+   last_start_time = now;
+   V(mutex);                         /* allow creation of jobs */
+   jcr->start_time = now;
+   /* Form Unique JobName */
+   localtime_r(&now, &tm);
+   strftime(dt, sizeof(dt), "%Y-%m-%d.%H:%M:%S", &tm); 
+   strncpy(name, base_name, sizeof(name));
+   name[sizeof(name)-22] = 0;         /* truncate if too long */
+   sprintf(jcr->Job, "%s.%s", name, dt); /* add date & time */
+   /* Convert spaces into underscores */
+   for (p=jcr->Job; *p; p++) {
+      if (*p == ' ') {
+         *p = '_';
+      }
+   }
+}
+
+/*
+ * Free the Job Control Record if no one is still using it.
+ *  Called from main free_jcr() routine in src/lib/jcr.c so
+ *  that we can do our Director specific cleanup of the jcr.
+ */
+void dird_free_jcr(JCR *jcr)
+{
+   Dmsg0(200, "Start dird free_jcr\n");
+
+   if (jcr->file_bsock) {
+      Dmsg0(200, "Close File bsock\n");
+      bnet_close(jcr->file_bsock);
+   }
+   if (jcr->store_bsock) {
+      Dmsg0(200, "Close Store bsock\n");
+      bnet_close(jcr->store_bsock);
+   }
+   if (jcr->fname) {  
+      Dmsg0(200, "Free JCR fname\n");
+      free_pool_memory(jcr->fname);
+   }
+   if (jcr->stime) {
+      Dmsg0(200, "Free JCR stime\n");
+      free_pool_memory(jcr->stime);
+   }
+   if (jcr->db) {
+      Dmsg0(200, "Close DB\n");
+      db_close_database(jcr->db);
+   }
+   if (jcr->RestoreWhere) {
+      free(jcr->RestoreWhere);
+   }
+   Dmsg0(200, "End dird free_jcr\n");
+}
+
+/*
+ * Set some defaults in the JCR necessary to
+ * run. These items are pulled from the job
+ * definition as defaults, but can be overridden
+ * later.
+ */
+void set_jcr_defaults(JCR *jcr, JOB *job)
+{
+   jcr->job = job;
+   jcr->JobType = job->JobType;
+   jcr->level = job->level;
+   jcr->store = job->storage;
+   jcr->client = job->client;
+   if (jcr->client_name) {
+      free(jcr->client_name);
+   }
+   jcr->client_name = bstrdup(job->client->hdr.name);
+   jcr->pool = job->pool;
+   jcr->catalog = job->client->catalog;
+   jcr->fileset = job->fs;
+   /* If no default level given, set one */
+   if (jcr->level == 0) {
+      switch (jcr->JobType) {
+      case JT_VERIFY:
+        jcr->level = L_VERIFY_CATALOG;
+        break;
+      case JT_BACKUP:
+        jcr->level = L_INCREMENTAL;
+        break;
+      default:
+        break;
+      }
+   }
+}
diff --git a/bacula/src/dird/mountreq.c b/bacula/src/dird/mountreq.c
new file mode 100644 (file)
index 0000000..68dc820
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *
+ *   Bacula Director -- mountreq.c -- handles the message channel
+ *    Mount request from the Storage daemon.
+ *
+ *     Kern Sibbald, March MMI
+ *
+ *    This routine runs as a thread and must be thread reentrant.
+ *
+ *  Basic tasks done here:
+ *     Handle Mount services.
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/*
+ * Handle mount request
+ *  For now, we put the bsock in the UA's queue
+ */
+
+/* Requests from the Storage daemon */
+
+
+/* Responses  sent to Storage daemon */
+#ifdef xxx
+static char OK_mount[]  = "1000 OK MountVolume\n";
+#endif
+
+static BQUEUE mountq = {&mountq, &mountq};
+static int num_reqs = 0;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+typedef struct mnt_req_s {
+   BQUEUE bq;
+   BSOCK *bs;
+   JCR *jcr;
+} MNT_REQ;
+
+
+void mount_request(JCR *jcr, BSOCK *bs, char *buf)
+{
+   MNT_REQ *mr;
+
+   mr = (MNT_REQ *) malloc(sizeof(MNT_REQ));
+   memset(mr, 0, sizeof(MNT_REQ));
+   mr->jcr = jcr;
+   mr->bs = bs;
+   P(mutex);
+   num_reqs++;
+   qinsert(&mountq, &mr->bq);
+   V(mutex);
+   return;
+}
diff --git a/bacula/src/dird/msgchan.c b/bacula/src/dird/msgchan.c
new file mode 100644 (file)
index 0000000..b59fcb1
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ *
+ *   Bacula Director -- msgchan.c -- handles the message channel
+ *    to the Storage daemon and the File daemon.
+ *
+ *     Kern Sibbald, August MM
+ *
+ *    This routine runs as a thread and must be thread reentrant.
+ *
+ *  Basic tasks done here:
+ *    Open a message channel with the Storage daemon
+ *     to authenticate ourself and to pass the JobId.
+ *    Create a thread to interact with the Storage daemon
+ *     who returns a job status and requests Catalog services, etc.
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Commands sent to Storage daemon */
+static char jobcmd[]     = "JobId=%d job=%s job_name=%s client_name=%s Allow=%s Session=%s\n";
+static char use_device[] = "use device=%s media_type=%s pool_name=%s pool_type=%s\n";
+
+/* Response from Storage daemon */
+static char OKjob[]      = "3000 OK Job SDid=%d SDtime=%d Authorization=%100s\n";
+static char OK_device[]  = "3000 OK use device\n";
+
+/* Storage Daemon requests */
+static char Job_start[]  = "3010 Job %127s start\n";
+static char Job_end[]   = 
+   "3099 Job %127s end JobStatus=%d JobFiles=%d JobBytes=%" lld "\n";
+static char Job_status[] = "3012 Job %127s jobstatus %d\n";
+
+/* Forward referenced functions */
+static void *msg_thread(void *arg);
+
+/*
+ * Establish a message channel connection with the Storage daemon
+ * and perform authentication. 
+ */
+int connect_to_storage_daemon(JCR *jcr, int retry_interval,    
+                             int max_retry_time, int verbose)
+{
+   BSOCK *sd;
+
+   /*
+    *  Open message channel with the Storage daemon   
+    */
+   Dmsg2(200, "bnet_connect to Storage daemon %s:%d\n", jcr->store->address,
+      jcr->store->SDport);
+   sd = bnet_connect(jcr, retry_interval, max_retry_time,
+          _("Storage daemon"), jcr->store->address, 
+         NULL, jcr->store->SDport, verbose);
+   if (sd == NULL) {
+      return 0;
+   }
+   sd->res = (RES *)jcr->store;        /* save pointer to other end */
+   jcr->store_bsock = sd;
+
+   if (!authenticate_storage_daemon(jcr)) {
+      return 0;
+   }
+   return 1;
+}
+
+/*
+ * Start a job with the Storage daemon
+ */
+int start_storage_daemon_job(JCR *jcr)
+{
+   int status;
+   STORE *storage;
+   BSOCK *sd;
+   char auth_key[100];               /* max 17 chars */
+   char *device_name, *pool_name, *pool_type, *media_type;
+   int device_name_len, pool_name_len, pool_type_len, media_type_len;
+
+   storage = jcr->store;
+   sd = jcr->store_bsock;
+   /*
+    * Now send JobId and permissions, and get back the authorization key.
+    */
+   bash_spaces(jcr->job->hdr.name);
+   bash_spaces(jcr->client->hdr.name);
+   bnet_fsend(sd, jobcmd, jcr->JobId, jcr->Job, jcr->job->hdr.name, 
+              jcr->client->hdr.name, "append", "*");
+   unbash_spaces(jcr->job->hdr.name);
+   unbash_spaces(jcr->client->hdr.name);
+   if (bnet_recv(sd) > 0) {
+       Dmsg1(10, "<stored: %s", sd->msg);
+       if (sscanf(sd->msg, OKjob, &jcr->VolSessionId, 
+                 &jcr->VolSessionTime, &auth_key) != 3) {
+          Jmsg(jcr, M_FATAL, 0, _("Storage daemon rejected Job command: %s\n"), sd->msg);
+         return 0;
+       } else {
+         jcr->sd_auth_key = bstrdup(auth_key);
+          Dmsg1(50, "sd_auth_key=%s\n", jcr->sd_auth_key);
+       }
+   } else {
+      Jmsg(jcr, M_FATAL, 0, _("<stored: bad response to Job command: %s\n"),
+        bnet_strerror(sd));
+      return 0;
+   }
+
+   /*
+    * Send use device = xxx media = yyy pool = zzz
+    */
+   device_name_len = strlen(storage->dev_name) + 1;
+   media_type_len = strlen(storage->media_type) + 1;
+   pool_type_len = strlen(jcr->pool->pool_type) + 1;
+   pool_name_len = strlen(jcr->pool->hdr.name) + 1;
+   device_name = (char *) get_memory(device_name_len);
+   pool_name = (char *) get_memory(pool_name_len);
+   pool_type = (char *) get_memory(pool_type_len);
+   media_type = (char *) get_memory(media_type_len);
+   memcpy(device_name, storage->dev_name, device_name_len);
+   memcpy(media_type, storage->media_type, media_type_len);
+   memcpy(pool_type, jcr->pool->pool_type, pool_type_len);
+   memcpy(pool_name, jcr->pool->hdr.name, pool_name_len);
+   bash_spaces(device_name);
+   bash_spaces(media_type);
+   bash_spaces(pool_type);
+   bash_spaces(pool_name);
+   sd->msg = (char *) check_pool_memory_size(sd->msg, sizeof(device_name) +
+      device_name_len + media_type_len + pool_type_len + pool_name_len);
+   bnet_fsend(sd, use_device, device_name, media_type, pool_name, pool_type);
+   Dmsg1(10, ">stored: %s", sd->msg);
+   status = response(sd, OK_device, "Use Device");
+
+   free_memory(device_name);
+   free_memory(media_type);
+   free_memory(pool_name);
+   free_memory(pool_type);
+
+   return status;
+}
+
+/* 
+ * Start a thread to handle Storage daemon messages and
+ *  Catalog requests.
+ */
+int start_storage_daemon_message_thread(JCR *jcr)
+{
+   int status;
+   pthread_t thid;
+
+   P(jcr->mutex);
+   jcr->use_count++;                 /* mark in use by msg thread */
+   V(jcr->mutex);
+   set_thread_concurrency(4);
+   if ((status=pthread_create(&thid, NULL, msg_thread, (void *)jcr)) != 0) {
+      Emsg1(M_ABORT, 0, _("Cannot create message thread: %s\n"), strerror(status));
+   }        
+   jcr->SD_msg_chan = thid;
+   return 1;
+}
+
+static void msg_thread_cleanup(void *arg)
+{
+   JCR *jcr = (JCR *)arg;
+   Dmsg0(200, "End msg_thread\n");
+   P(jcr->mutex);
+   jcr->msg_thread_done = TRUE;
+   pthread_cond_broadcast(&jcr->term_wait); /* wakeup any waiting threads */
+   V(jcr->mutex);
+   free_jcr(jcr);                    /* release jcr */
+}
+
+/*
+ * Handle the message channel (i.e. requests from the
+ *  Storage daemon).
+ * Note, we are running in a separate thread.
+ */
+static void *msg_thread(void *arg)
+{
+   JCR *jcr = (JCR *)arg;
+   BSOCK *sd;
+   int JobStatus;
+   char Job[MAX_NAME_LENGTH];
+   uint32_t JobFiles;
+   uint64_t JobBytes;
+   int stat;
+
+   pthread_cleanup_push(msg_thread_cleanup, arg);
+   Dmsg0(200, "msg_thread\n");
+   sd = jcr->store_bsock;
+   pthread_detach(pthread_self());
+
+   /* Read the Storage daemon's output.
+    */
+   Dmsg0(200, "Start msg_thread loop\n");
+   while ((stat=bget_msg(sd, 0)) > 0) {
+      Dmsg1(200, "<stored: %s", sd->msg);
+      if (sscanf(sd->msg, Job_start, &Job) == 1) {
+        continue;
+      }
+      if (sscanf(sd->msg, Job_end, &Job, &JobStatus, &JobFiles,
+                &JobBytes) == 4) {
+        jcr->SDJobStatus = JobStatus; /* termination status */
+        jcr->JobFiles = JobFiles;
+        jcr->JobBytes = JobBytes;
+        break;
+      }     
+      if (sscanf(sd->msg, Job_status, &Job, &JobStatus) == 2) {
+        jcr->SDJobStatus = JobStatus; /* current status */
+        continue;
+      }
+   }
+   if (stat < 0) {                  
+      jcr->SDJobStatus = JS_ErrorTerminated;
+   }
+   pthread_cleanup_pop(1);
+   return NULL;
+}
diff --git a/bacula/src/dird/newvol.c b/bacula/src/dird/newvol.c
new file mode 100644 (file)
index 0000000..1f7dda1
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *
+ *   Bacula Director -- newvol.c -- creates new Volumes in
+ *    catalog Media table from the LabelFormat specification.
+ *
+ *     Kern Sibbald, May MMI
+ *
+ *    This routine runs as a thread and must be thread reentrant.
+ *
+ *  Basic tasks done here:
+ *     If possible create a new Media entry
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/*
+ * Really crude automatic Volume name creation using
+ *  LabelFormat
+ */
+int newVolume(JCR *jcr)
+{
+   MEDIA_DBR mr; 
+   POOL_DBR pr;
+   char name[MAXSTRING];
+
+   memset(&mr, 0, sizeof(mr));
+   memset(&pr, 0, sizeof(pr));
+
+   /* See if we can create a new Volume */
+   pr.PoolId = jcr->PoolId;
+   if (db_get_pool_record(jcr->db, &pr) && pr.LabelFormat[0] &&
+       pr.LabelFormat[0] != '*') {
+      if (pr.MaxVols == 0 || pr.NumVols < pr.MaxVols) {
+        memset(&mr, 0, sizeof(mr));
+        mr.PoolId = jcr->PoolId;
+        strcpy(mr.MediaType, jcr->store->media_type);
+        strcpy(name, pr.LabelFormat);   
+         strcat(name, "%04d");
+        sprintf(mr.VolumeName, name, ++pr.NumVols);
+         strcpy(mr.VolStatus, "Append");
+         strcpy(mr.Recycle, "No");
+        if (db_create_media_record(jcr->db, &mr) &&
+           db_update_pool_record(jcr->db, &pr) == 1) {
+            Dmsg1(90, "Created new Volume=%s\n", mr.VolumeName);
+           return 1;
+        } else {
+            Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
+        }
+      }
+   }
+   return 0;   
+}
diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h
new file mode 100644 (file)
index 0000000..0c693d8
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Director external function prototypes
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* authenticate.c */
+extern int authenticate_storage_daemon(JCR *jcr);
+extern int authenticate_file_daemon(JCR *jcr);
+extern int authenticate_user_agent(BSOCK *ua);
+
+/* catreq.c */
+extern void catalog_request(JCR *jcr, BSOCK *bs, char *buf);
+extern void catalog_update(JCR *jcr, BSOCK *bs, char *buf);
+
+/* dird_conf.c */
+extern char *level_to_str(int level);
+
+/* fd_cmds.c */
+extern int connect_to_file_daemon(JCR *jcr, int retry_interval,
+                                  int max_retry_time, int verbose);
+extern int send_include_list(JCR *jcr);
+extern int send_exclude_list(JCR *jcr);
+extern int get_attributes_and_put_in_catalog(JCR *jcr);
+extern int get_attributes_and_compare_to_catalog(JCR *jcr, int last_full_id);
+extern int put_file_into_catalog(JCR *jcr, long file_index, char *fname, 
+                          char *link, char *attr, int stream);
+
+/* job.c */
+extern void free_jcr(JCR *jcr);
+extern void set_jcr_defaults(JCR *jcr, JOB *job);
+extern void create_unique_job_name(JCR *jcr, char *base_name);
+
+/* mountreq.c */
+extern void mount_request(JCR *jcr, BSOCK *bs, char *buf);
+
+/* msgchan.c */
+extern int connect_to_storage_daemon(JCR *jcr, int retry_interval,    
+                              int max_retry_time, int verbose);
+extern int start_storage_daemon_job(JCR *jcr);
+extern int start_storage_daemon_message_thread(JCR *jcr);
+extern int32_t bget_msg(BSOCK *bs, int type);
+extern int response(BSOCK *fd, char *resp, char *cmd);
+
+/* newvol.c */
+extern int newVolume(JCR *jcr);
+
+/* ua_cmds.c */
+extern int create_pool(B_DB *db, POOL *pool);
diff --git a/bacula/src/dird/query.sql b/bacula/src/dird/query.sql
new file mode 100644 (file)
index 0000000..8238854
--- /dev/null
@@ -0,0 +1,79 @@
+:List Job totals:
+SELECT  count(*) AS Jobs, sum(JobFiles) AS Files, 
+ sum(JobBytes) AS Bytes, Name AS Job FROM Job GROUP BY Name;
+SELECT max(JobId) AS Jobs,sum(JobFiles) AS Files,
+ sum(JobBytes) As Bytes FROM Job
+#
+:List where a file is saved:
+*Enter path with trailing slash:
+*Enter filename:
+*Enter Client name:
+SELECT Job.JobId, StartTime AS JobStartTime, VolumeName, Client.Name AS ClientName
+ FROM Job,File,Path,Filename,Media,JobMedia,Client
+ WHERE File.JobId=Job.JobId
+ AND Path.Path="%1"
+ AND Filename.Name="%2"
+ AND Client.Name="%3"
+ AND Path.PathId=File.PathId
+ AND Filename.FilenameId=File.FilenameId
+ AND JobMedia.JobId=Job.JobId
+ AND JobMedia.MediaId=Media.MediaId
+ AND Client.ClientId=Job.ClientId
+ GROUP BY Job.JobId;
+#
+:List where the most recent copies of a file are saved:
+*Enter path with trailing slash:
+*Enter filename:
+*Enter Client name:
+SELECT Job.JobId, StartTime AS JobStartTime, VolumeName, Client.Name AS ClientName
+ FROM Job,File,Path,Filename,Media,JobMedia,Client
+ WHERE File.JobId=Job.JobId
+ AND Path.Path="%1"
+ AND Filename.Name="%2"
+ AND Client.Name="%3"
+ AND Path.PathId=File.PathId
+ AND Filename.FilenameId=File.FilenameId
+ AND JobMedia.JobId=Job.JobId
+ AND JobMedia.MediaId=Media.MediaId
+ AND Client.ClientId=Job.ClientId
+ ORDER BY Job.StartTime DESC LIMIT 5;
+#
+:List total files/bytes by Job:
+SELECT count(*) AS Jobs, sum(JobFiles) AS Files,
+ sum(JobBytes) AS Bytes, Name AS Job
+ FROM Job GROUP by Name
+#
+:List total files/bytes by Volume:
+SELECT count(*) AS Jobs, sum(JobFiles) AS Files,
+ sum(JobBytes) AS Bytes, VolumeName
+ FROM Job,JobMedia,Media
+ WHERE JobMedia.JobId=Job.JobId
+ AND JobMedia.MediaId=Media.MediaId
+ GROUP by VolumeName;  
+#
+# create list of files to be deleted
+#
+:List files older than n days to be dropped:
+*Enter retention period:
+# First cleanup
+drop table if exists retension;
+# First create table with all files older than n days
+create temporary table retension
+  select Job.JobId,File.FileId,Path.PathId,Filename.FilenameId
+  from Filename,File,Path,JobMedia,Media,Job
+  where JobMedia.JobId=File.JobId 
+  and Job.JobId=File.JobId
+  and Media.MediaId=JobMedia.MediaId 
+  and Filename.FilenameId=File.FilenameId
+  and Path.PathId=File.PathId
+  and (to_days(current_date) - to_days(EndTime)) > %1;
+# Now select entries that have a more recent backup
+select retension.JobId,retension.FileId,Path.Path,Filename.Name
+  from retension,Filename,File,Path,Job
+  where Job.JobId!=retension.JobId
+  and (to_days(current_date) - to_days(Job.EndTime)) <= %1
+  and Job.JobId=File.JobId
+  and Filename.FilenameId=File.FilenameId
+  and Path.PathId=File.PathId
+  and retension.PathId=File.PathId
+  and retension.FilenameId=File.FilenameId;
diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c
new file mode 100644 (file)
index 0000000..35accb5
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ *
+ *   Bacula Director -- restore.c -- responsible for restoring files
+ *
+ *     Kern Sibbald, November MM
+ *
+ *    This routine is run as a separate thread.  There may be more
+ *    work to be done to make it totally reentrant!!!!
+ * 
+ * Current implementation is Catalog verification only (i.e. no
+ *  verification versus tape).
+ *
+ *  Basic tasks done here:
+ *     Open DB
+ *     Open Message Channel with Storage daemon to tell him a job will be starting.
+ *     Open connection with File daemon and pass him commands
+ *      to do the restore.
+ *     Update the DB according to what files where restored????
+ *
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Commands sent to File daemon */
+static char restorecmd[]   = "restore where=%s\n";
+static char storaddr[]     = "storage address=%s port=%d\n";
+static char sessioncmd[]   = "session %s %ld %ld %ld %ld %ld %ld\n";  
+
+/* Responses received from File daemon */
+static char OKrestore[]   = "2000 OK restore\n";
+static char OKstore[]     = "2000 OK storage\n";
+static char OKsession[]   = "2000 OK session\n";
+
+/* Forward referenced functions */
+static void restore_cleanup(JCR *jcr, int status);
+
+/* External functions */
+
+/* 
+ * Do a restore of the specified files
+ *    
+ *  Returns:  0 on failure
+ *           1 on success
+ */
+int do_restore(JCR *jcr) 
+{
+   char dt[MAX_TIME_LENGTH];
+   BSOCK   *fd;
+   JOB_DBR rjr;                      /* restore job record */
+   CLIENT_DBR cr;
+
+   /*
+    * Get or Create a client record
+    */
+   memset(&cr, 0, sizeof(cr));
+   strcpy(cr.Name, jcr->client->hdr.name);
+   if (jcr->client_name) {
+      free(jcr->client_name);
+   }
+   jcr->client_name = bstrdup(jcr->client->hdr.name);
+   if (!db_create_client_record(jcr->db, &cr)) {
+      Jmsg(jcr, M_ERROR, 0, _("Could not create Client record. %s"), 
+        db_strerror(jcr->db));
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+   jcr->jr.ClientId = cr.ClientId;
+
+   memset(&rjr, 0, sizeof(rjr));
+   jcr->jr.Level = 'F';            /* Full restore */
+   jcr->jr.StartTime = jcr->start_time;
+   if (!db_update_job_start_record(jcr->db, &jcr->jr)) {
+      Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+   Dmsg0(20, "Updated job start record\n");
+   jcr->fname = (char *) get_pool_memory(PM_FNAME);
+
+   Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
+
+   /*
+    * Find Job Record for Files to be restored
+    */
+   if (jcr->RestoreJobId != 0) {
+      rjr.JobId = jcr->RestoreJobId;    /* specified by UA */
+   } else {
+      rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */
+   }
+   if (!db_get_job_record(jcr->db, &rjr)) {
+      Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId,
+        db_strerror(jcr->db));
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+   Dmsg3(20, "Got JobId=%d VolSessId=%ld, VolSesTime=%ld\n", 
+            rjr.JobId, rjr.VolSessionId, rjr.VolSessionTime);
+   Dmsg4(20, "StartFile=%ld, EndFile=%ld StartBlock=%ld EndBlock=%ld\n", 
+            rjr.StartFile, rjr.EndFile, rjr.StartBlock, rjr.EndBlock);
+
+   /*
+    * Now find the Volumes we will need for the Restore
+    */
+   jcr->VolumeName[0] = 0;
+   if (!db_get_job_volume_names(jcr->db, rjr.JobId, jcr->VolumeName) ||
+       jcr->VolumeName[0] == 0) {
+      Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"), 
+        rjr.JobId, db_strerror(jcr->db));
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+   Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName);
+      
+
+   /* Print Job Start message */
+   bstrftime(dt, sizeof(dt), jcr->start_time);
+   Jmsg(jcr, M_INFO, 0, _("%s Start Restore Job %s Name=%s, Client=%s, FileSet=%s\n"), 
+      dt, jcr->Job, jcr->job->hdr.name, jcr->client->hdr.name, 
+      jcr->fileset->hdr.name);
+
+   /*
+    * Open a message channel connection with the Storage
+    * daemon. This is to let him know that our client
+    * will be contacting him for a backup  session.
+    *
+    */
+   Dmsg0(10, "Open connection with storage daemon\n");
+   jcr->JobStatus = JS_Blocked;
+   /*
+    * Start conversation with Storage daemon  
+    */
+   if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+   /*
+    * Now start a job with the Storage daemon
+    */
+   if (!start_storage_daemon_job(jcr)) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+   /*
+    * Now start a Storage daemon message thread
+    */
+   if (!start_storage_daemon_message_thread(jcr)) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+   Dmsg0(50, "Storage daemon connection OK\n");
+
+   /* 
+    * Start conversation with File daemon  
+    */
+   if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+
+   fd = jcr->file_bsock;
+   jcr->JobStatus = JS_Running;
+
+   if (!send_include_list(jcr)) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+
+   if (!send_exclude_list(jcr)) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+
+   /* 
+    * send Storage daemon address to the File daemon,
+    *  then wait for File daemon to make connection
+    *  with Storage daemon.
+    */
+   jcr->JobStatus = JS_Blocked;
+   if (jcr->store->SDDport == 0) {
+      jcr->store->SDDport = jcr->store->SDport;
+   }
+   bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
+   Dmsg1(6, "dird>filed: %s\n", fd->msg);
+   if (!response(fd, OKstore, "Storage")) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+   jcr->JobStatus = JS_Running;
+
+   /*
+    * Pass the VolSessionId, VolSessionTime, Start and
+    * end File and Blocks on the session command.
+    */
+   bnet_fsend(fd, sessioncmd, 
+            jcr->VolumeName,
+            rjr.VolSessionId, rjr.VolSessionTime, 
+            rjr.StartFile, rjr.EndFile, rjr.StartBlock, 
+            rjr.EndBlock);
+   if (!response(fd, OKsession, "Session")) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+
+   /* Send restore command */
+   if (jcr->RestoreWhere) {
+      bnet_fsend(fd, restorecmd, jcr->RestoreWhere);
+   } else {
+      bnet_fsend(fd, restorecmd,                              
+         jcr->job->RestoreWhere==NULL ? "" : jcr->job->RestoreWhere);
+   }
+   if (!response(fd, OKrestore, "Restore")) {
+      restore_cleanup(jcr, JS_ErrorTerminated);
+      return 0;
+   }
+
+   /* Wait for Job Termination */
+   /*** ****FIXME**** get job termination data */
+   Dmsg0(20, "wait for job termination\n");
+   while (bget_msg(fd, 0) >  0) {
+      Dmsg1(0, "dird<filed: %s\n", fd->msg);
+   }
+
+   restore_cleanup(jcr, JS_Terminated);
+
+   return 1;
+}
+
+/*
+ * Release resources allocated during restore.
+ *
+ */
+static void restore_cleanup(JCR *jcr, int status) 
+{
+   char dt[MAX_TIME_LENGTH];
+
+   Dmsg0(20, "In restore_cleanup\n");
+   if (jcr->jr.EndTime == 0) {
+      jcr->jr.EndTime = time(NULL);
+   }
+   jcr->jr.JobStatus = jcr->JobStatus = status;
+   if (!db_update_job_end_record(jcr->db, &jcr->jr)) {
+      Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"), 
+        db_strerror(jcr->db));
+   }
+
+   bstrftime(dt, sizeof(dt), jcr->jr.EndTime);
+   Jmsg(jcr, M_INFO, 0, _("%s End Restore Job %s.\n"),
+      dt, jcr->Job);
+
+   Dmsg0(20, "Leaving restore_cleanup\n");
+}
diff --git a/bacula/src/dird/run_conf.c b/bacula/src/dird/run_conf.c
new file mode 100644 (file)
index 0000000..c58a713
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ *
+ *  Configuration parser for Director Run Configuration
+ *   directives, which are part of the Schedule Resource
+ *
+ *     Kern Sibbald, May MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+extern URES res_all;
+extern struct s_jl joblevels[];
+
+/* Forward referenced subroutines */
+
+enum e_state {
+   s_none = 0,
+   s_range,
+   s_mday,
+   s_month,
+   s_time,
+   s_at,
+   s_wday,
+   s_daily,
+   s_weekly,
+   s_monthly,
+   s_hourly,
+};  
+
+struct s_keyw {
+  char *name;                        /* keyword */
+  enum e_state state;                /* parser state */
+  int code;                          /* state value */
+};
+
+/* Keywords understood by parser */
+static struct s_keyw keyw[] = {
+  {N_("on"),         s_none,    0},
+  {N_("at"),         s_at,      0},
+
+  {N_("sun"),        s_wday,    0},
+  {N_("mon"),        s_wday,    1},
+  {N_("tue"),        s_wday,    2},
+  {N_("wed"),        s_wday,    3},
+  {N_("thu"),        s_wday,    4},
+  {N_("fri"),        s_wday,    5},
+  {N_("sat"),        s_wday,    6},
+  {N_("jan"),        s_month,   0},
+  {N_("feb"),        s_month,   1},
+  {N_("mar"),        s_month,   2},
+  {N_("apr"),        s_month,   3},
+  {N_("may"),        s_month,   4},
+  {N_("jun"),        s_month,   5},
+  {N_("jul"),        s_month,   6},
+  {N_("aug"),        s_month,   7},
+  {N_("sep"),        s_month,   8},
+  {N_("oct"),        s_month,   9},
+  {N_("nov"),        s_month,  10},
+  {N_("dec"),        s_month,  11},
+
+  {N_("sunday"),     s_wday,    0},
+  {N_("monday"),     s_wday,    1},
+  {N_("tuesday"),    s_wday,    2},
+  {N_("wednesday"),  s_wday,    3},
+  {N_("thursday"),   s_wday,    4},
+  {N_("friday"),     s_wday,    5},
+  {N_("saturday"),   s_wday,    6},
+  {N_("january"),    s_month,   0},
+  {N_("february"),   s_month,   1},
+  {N_("march"),      s_month,   2},
+  {N_("april"),      s_month,   3},
+  {N_("june"),       s_month,   5},
+  {N_("july"),       s_month,   6},
+  {N_("august"),     s_month,   7},
+  {N_("september"),  s_month,   8},
+  {N_("october"),    s_month,   9},
+  {N_("november"),   s_month,  10},
+  {N_("december"),   s_month,  11},
+
+  {N_("daily"),      s_daily,   0},
+  {N_("weekly"),     s_weekly,  0},
+  {N_("monthly"),    s_monthly, 0},
+  {N_("hourly"),     s_hourly,  0},
+  {NULL,        s_none,    0}
+};
+
+static int have_hour, have_mday, have_wday, have_month;
+static int have_at;
+static RUN lrun;
+
+static void clear_defaults()
+{
+   have_hour = have_mday = have_wday = have_month = TRUE;
+   clear_bit(0,lrun.hour);
+   clear_bits(0, 30, lrun.mday);
+   clear_bits(0, 6, lrun.wday);
+   clear_bits(0, 11, lrun.month);
+}
+
+static void set_defaults()
+{
+   have_hour = have_mday = have_wday = have_month = FALSE;
+   have_at = FALSE;
+   set_bit(0,lrun.hour);
+   set_bits(0, 30, lrun.mday);
+   set_bits(0, 6, lrun.wday);
+   set_bits(0, 11, lrun.month);
+}
+
+
+/* Check if string is a number */
+static int is_num(char *num)
+{
+   char *p = num;
+   int ch;
+   while ((ch = *p++)) {
+      if (ch < '0' || ch > '9') {
+        return FALSE;
+      }
+   }
+   return TRUE;
+}
+
+
+/* 
+ * Store Schedule Run information   
+ * 
+ * Parse Run statement:
+ *
+ *  Run <full|incremental|...> [on] 2 january at 23:45
+ *
+ *   Default Run time is daily at 0:0
+ *  
+ *   There can be multiple run statements, they are simply chained
+ *   together.
+ *
+ */
+void store_run(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token, state, state2, i, code, code2;
+   int options = lc->options;
+   RUN **run = (RUN **)(item->value);  
+   RUN *trun;
+   char *p;
+
+
+   lc->options |= LOPT_NO_IDENT;      /* want only "strings" */
+
+   /* clear local copy of run record */
+   memset(&lrun, 0, sizeof(RUN));
+
+   /* scan for Job level "full", "incremental", ... */
+   token = lex_get_token(lc);
+   if (token != T_STRING) {
+      scan_err1(lc, _("Expected a Job level identifier, got: %s"), lc->str);
+   } else {
+      lcase(lc->str);
+      for (i=0; joblevels[i].level_name; i++) {
+        if (strcmp(lc->str, joblevels[i].level_name) == 0) {
+           lrun.level = joblevels[i].level;
+           lrun.job_class = joblevels[i].job_class;
+           i = 0;
+           break;
+        }
+      }
+      if (i != 0) {
+         scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
+      }
+   }
+
+   /*
+    * Scan schedule times.
+    * Default is: daily at 0:0
+    */
+   state = s_none;
+   set_defaults();
+
+   while ((token = lex_get_token(lc)) != T_EOL) {
+      int len, pm;
+      switch (token) {
+        case T_NUMBER:
+           state = s_mday;
+           code = atoi(lc->str) - 1;
+           if (code < 0 || code > 30) {
+               scan_err0(lc, _("Day number out of range (1-31)"));
+           }
+           break;
+        case T_STRING:
+            if (strchr(lc->str, (int)'-')) {
+              state = s_range;
+              break;
+           }
+            if (strchr(lc->str, (int)':')) {
+              state = s_time;
+              break;
+           }
+           /* everything else must be a keyword */
+           lcase(lc->str);
+           for (i=0; keyw[i].name; i++) {
+              if (strcmp(lc->str, keyw[i].name) == 0) {
+                 state = keyw[i].state;
+                 code   = keyw[i].code;
+                 i = 0;
+                 break;
+              }
+           }
+           if (i != 0) {
+               scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
+           }
+           break;
+        case T_COMMA:
+           continue;
+        default:
+            scan_err1(lc, _("Unexpected token: %s"), lc->str);
+           break;
+      }
+      switch (state) {
+        case s_none:
+           continue;
+        case s_mday:                 /* day of month */
+           if (!have_mday) {
+              clear_bits(0, 30, lrun.mday);
+              clear_bits(0, 6, lrun.wday);
+              have_mday = TRUE;
+           }
+           set_bit(code, lrun.mday);
+           break;
+        case s_month:                /* month of year */
+           if (!have_month) {
+              clear_bits(0, 11, lrun.month);
+              have_month = TRUE;
+           }
+           set_bit(code, lrun.month);
+           break;
+        case s_wday:                 /* week day */
+           if (!have_wday) {
+              clear_bits(0, 6, lrun.wday);
+              clear_bits(0, 30, lrun.mday);
+              have_wday = TRUE;
+           }
+           set_bit(code, lrun.wday);
+           break;
+        case s_time:                 /* time */
+           if (!have_at) {
+               scan_err0(lc, _("Time must be preceded by keyword AT."));
+           }
+           if (!have_hour) {
+              clear_bit(0, lrun.hour);
+              have_hour = TRUE;
+           }
+            p = strchr(lc->str, ':');
+           if (!p)  {
+               scan_err0(lc, _("Time logic error.\n"));
+           }
+           *p++ = 0;                 /* separate two halves */
+           code = atoi(lc->str);
+           len = strlen(p);
+            if (len > 2 && p[len-1] == 'm') {
+               if (p[len-2] == 'a') {
+                 pm = 0;
+               } else if (p[len-2] == 'p') {
+                 pm = 1;
+              } else {
+                  scan_err0(lc, _("Bad time specification."));
+              }
+           } else {
+              pm = 0;
+           }
+           code2 = atoi(p);
+           if (pm) {
+              code += 12;
+           }
+           if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
+               scan_err0(lc, _("Bad time specification."));
+           }
+           set_bit(code, lrun.hour);
+           lrun.minute = code2;
+           break;
+        case s_at:
+           have_at = TRUE;
+           break;
+        case s_range:
+            p = strchr(lc->str, '-');
+           if (!p) {
+               scan_err0(lc, _("Range logic error.\n"));
+           }
+           *p++ = 0;                 /* separate two halves */
+
+           /* Check for day range */
+           if (is_num(lc->str) && is_num(p)) {
+              code = atoi(lc->str) - 1;
+              code2 = atoi(p) - 1;
+              if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
+                  scan_err0(lc, _("Bad day range specification."));
+              }
+              if (!have_mday) {
+                 clear_bits(0, 30, lrun.mday);
+                 clear_bits(0, 6, lrun.wday);
+                 have_mday = TRUE;
+              }
+              if (code < code2) {
+                 set_bits(code, code2, lrun.mday);
+              } else {
+                 set_bits(code, 30, lrun.mday);
+                 set_bits(0, code2, lrun.mday);
+              }
+              break;
+           }
+
+           /* lookup first half of keyword range (week days or months) */
+           lcase(lc->str);
+           for (i=0; keyw[i].name; i++) {
+              if (strcmp(lc->str, keyw[i].name) == 0) {
+                 state = keyw[i].state;
+                 code   = keyw[i].code;
+                 i = 0;
+                 break;
+              }
+           }
+           if (i != 0 || (state != s_month && state != s_wday)) {
+               scan_err0(lc, _("Invalid month or week day range"));
+           }
+
+           /* Lookup end of range */
+           lcase(p);
+           for (i=0; keyw[i].name; i++) {
+              if (strcmp(p, keyw[i].name) == 0) {
+                 state2  = keyw[i].state;
+                 code2   = keyw[i].code;
+                 i = 0;
+                 break;
+              }
+           }
+           if (i != 0 || state != state2 || 
+              (state2 != s_month && state2 != s_wday) || code == code2) {
+               scan_err0(lc, _("Invalid month or weekday range"));
+           }
+           if (state == s_wday) {
+              if (!have_wday) {
+                 clear_bits(0, 6, lrun.wday);
+                 clear_bits(0, 30, lrun.mday);
+                 have_wday = TRUE;
+              }
+              if (code < code2) {
+                 set_bits(code, code2, lrun.wday);
+              } else {
+                 set_bits(code, 6, lrun.wday);
+                 set_bits(0, code2, lrun.wday);
+              }
+           } else {
+              /* must be s_month */
+              if (!have_month) {
+                 clear_bits(0, 30, lrun.month);
+                 have_month = TRUE;
+              }
+              if (code < code2) {
+                 set_bits(code, code2, lrun.month);
+              } else {
+                 /* this is a bit odd, but we accept it anyway */
+                 set_bits(code, 30, lrun.month);
+                 set_bits(0, code2, lrun.month);
+              }
+           }
+           break;
+        case s_hourly:
+           clear_defaults();
+           set_bits(0, 23, lrun.hour);
+           set_bits(0, 30, lrun.mday);
+           set_bits(0, 11, lrun.month);
+           break;
+        case s_weekly:
+           clear_defaults();
+           set_bit(0, lrun.wday);
+           set_bits(0, 11, lrun.month);
+           break;
+        case s_daily:
+           clear_defaults();
+           set_bits(0, 30, lrun.mday);
+           set_bits(0, 11, lrun.month);
+           break;
+        case s_monthly:
+           clear_defaults();
+           set_bit(0, lrun.mday);
+           set_bits(0, 11, lrun.month);
+           break;
+        default:
+            scan_err0(lc, _("Unexpected run state\n"));
+           break;
+      }
+   }
+
+   /* Allocate run record, copy new stuff into it,
+    * and link it into the list of run records 
+    * in the schedule resource.
+    */
+   if (pass == 1) {
+      trun = (RUN *) malloc(sizeof(RUN));
+      memcpy(trun, &lrun, sizeof(RUN));
+      if (*run) {
+        trun->next = *run;
+      }
+      *run = trun;
+   }
+
+   lc->options = options;            /* restore scanner options */
+   set_bit(index, res_all.res_sch.hdr.item_present);
+}
diff --git a/bacula/src/dird/scheduler.c b/bacula/src/dird/scheduler.c
new file mode 100644 (file)
index 0000000..e65f12b
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *
+ *   Bacula scheduler
+ *     It looks at what jobs are to be run and when
+ *     and waits around until it is time to 
+ *     fire them up.
+ *
+ *     Kern Sibbald, May MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+
+/* Forward referenced subroutines */
+static void find_runs();
+
+/* Imported subroutines */
+
+/* Imported variables */
+
+/* Local variables */
+typedef struct {
+   RUN *run;
+   JOB *job;
+   time_t runtime;
+} RUNJOB;
+
+static int num_runjobs;              /* total jobs found by find_runs() */
+static int rem_runjobs;              /* jobs remaining to be processed */
+static int max_runjobs;              /* max jobs in runjobs array */
+static RUNJOB *runjobs;              /* array of jobs to be run */
+
+
+/*********************************************************************
+ *
+ *        Main Bacula Scheduler
+ *
+ */
+JCR *wait_for_next_job(char *job_to_run)
+{
+   JCR *jcr;
+   JOB *job;
+   RUN *run;
+   time_t now, runtime, nexttime;
+   int jobindex, i;
+   static int first = TRUE;
+
+   Dmsg0(200, "Enter wait_for_next_job\n");
+   if (first) {
+      first = FALSE;
+      max_runjobs = 10;
+      runjobs = (RUNJOB *) malloc(sizeof(RUNJOB) * max_runjobs);
+      num_runjobs = 0;
+      if (job_to_run) {              /* one shot */
+        job = (JOB *)GetResWithName(R_JOB, job_to_run);
+        if (!job) {
+            Emsg1(M_ERROR, 0, _("Job %s not found\n"), job_to_run);
+        }
+         Dmsg1(5, "Found job_to_run %s\n", job_to_run);
+        jcr = new_jcr(sizeof(JCR), dird_free_jcr);
+        set_jcr_defaults(jcr, job);
+        return jcr;
+      }
+      find_runs();
+   }
+   /* Wait until we have something in the
+    * next hour or so.
+    */
+   while (num_runjobs == 0 || rem_runjobs == 0) {
+      sleep(60);
+      find_runs();
+   }
+   /* 
+    * Sort through what is to be run in the next
+    * two hours to find the first job to be run,
+    * then wait around until it is time.
+    *
+    */
+   time(&now);
+   nexttime = now + 60 * 60 * 24;     /* a much later time */
+   jobindex = -1;
+   for (i=0; i<num_runjobs; i++) {
+      runtime = runjobs[i].runtime;
+      if (runtime > 0 && runtime < nexttime) { /* find minimum time job */
+        nexttime = runtime;
+        jobindex = i;
+      }
+   }
+   if (jobindex < 0) {               /* we really should have something now */
+      Emsg0(M_ABORT, 0, _("Scheduler logic error\n"));
+   }
+
+   /* Now wait for the time to run the job */
+   for (;;) {
+      int twait;
+      time(&now);
+      twait = nexttime - now;
+      if (twait <= 0)                /* time to run it */
+        break;
+      if (twait > 20)                /* sleep max 20 seconds */
+        twait = 20;
+      sleep(twait);
+   }
+   run = runjobs[jobindex].run;
+   job = runjobs[jobindex].job;
+   runjobs[jobindex].runtime = 0;     /* remove from list */
+   run->last_run = now;              /* mark as run */
+   rem_runjobs--;                    /* decrement count of remaining jobs */
+   jcr = new_jcr(sizeof(JCR), dird_free_jcr);
+   set_jcr_defaults(jcr, job);
+   jcr->level = run->level;          /* override run level */
+   Dmsg0(200, "Leave wait_for_next_job()\n");
+   return jcr;
+}
+
+
+/*
+ * Shutdown the scheduler  
+ */
+void term_scheduler()
+{
+   if (runjobs) {                    /* free allocated memory */
+      free(runjobs);
+      runjobs = NULL;
+      max_runjobs = 0;
+   }
+}
+
+
+/*         
+ * Find all jobs to be run this hour
+ * and the next hour.
+ */
+static void find_runs()
+{
+   time_t now, runtime;
+   RUN *run;
+   JOB *job;
+   SCHED *sched;
+   struct tm tm;
+   int hour, next_hour, minute, mday, wday, month;
+
+   Dmsg0(200, "enter find_runs()\n");
+   num_runjobs = 0;
+
+   now = time(NULL);
+   localtime_r(&now, &tm);
+   
+   hour = tm.tm_hour;
+   next_hour = hour + 1;
+   if (next_hour > 23)
+      next_hour -= 24;
+   minute = tm.tm_min;
+   mday = tm.tm_mday - 1;
+   wday = tm.tm_wday;
+   month = tm.tm_mon;
+
+   /* Loop through all jobs */
+   LockRes();
+   for (job=NULL; (job=(JOB *)GetNextRes(R_JOB, (RES *)job)); ) {
+      sched = job->schedule;
+      if (sched == NULL) {           /* scheduled? */
+        continue;                    /* no, skip this job */
+      }
+      for (run=sched->run; run; run=run->next) {
+
+        if (now - run->last_run < 60 * 20)
+           continue;                 /* wait at least 20 minutes */
+
+        /* Find runs scheduled in this our or in the
+         * next hour (we may be one second before the next hour).
+         */
+        if ((bit_is_set(hour, run->hour) || bit_is_set(next_hour, run->hour)) &&
+            (bit_is_set(mday, run->mday) || bit_is_set(wday, run->wday)) && 
+            bit_is_set(month, run->month)) {
+
+           /* find time (time_t) job is to be run */
+           localtime_r(&now, &tm);
+           if (bit_is_set(next_hour, run->hour))
+              tm.tm_hour++;
+           if (tm.tm_hour > 23)
+              tm.tm_hour = 0;
+           tm.tm_min = run->minute;
+           tm.tm_sec = 0;
+           runtime = mktime(&tm);
+           if (runtime < (now - 5 * 60)) /* give 5 min grace to pickup straglers */
+              continue;
+           /* Make sure array is big enough */
+           if (num_runjobs == max_runjobs) {
+              max_runjobs += 10;
+              runjobs = (RUNJOB *) realloc(runjobs, sizeof(RUNJOB) * max_runjobs);
+              if (!runjobs)
+                  Emsg0(M_ABORT, 0, _("Out of memory\n"));
+           }
+           /* accept to run this job */
+           runjobs[num_runjobs].run = run;
+           runjobs[num_runjobs].job = job;
+           runjobs[num_runjobs++].runtime = runtime; /* when to run it */
+
+        }
+      }  
+   }
+
+   UnlockRes();
+   rem_runjobs = num_runjobs;
+   Dmsg0(200, "Leave find_runs()\n");
+}
diff --git a/bacula/src/dird/ua.h b/bacula/src/dird/ua.h
new file mode 100644 (file)
index 0000000..d9f4120
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Includes specific to the Director User Agent Server
+ *
+ *     Kern Sibbald, August MMI
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#define MAX_ARGS 20
+
+typedef struct s_ua_context {
+   BSOCK *UA_sock;
+   BSOCK *sd;
+   JCR *jcr;
+   B_DB *db;
+   CAT *catalog;
+   char *cmd;                         /* return command/name buffer */
+   char *args;                        /* command line arguments */
+   char *argk[MAX_ARGS];              /* argument keywords */
+   char *argv[MAX_ARGS];              /* argument values */
+   int argc;                          /* number of arguments */
+   char **prompt;                     /* list of prompts */
+   int max_prompts;                   /* max size of list */
+   int num_prompts;                   /* current number in list */
+   int auto_display_messages;         /* if set, display messages */
+   int user_notified_msg_pending;     /* set when user notified */
+   int automount;                     /* if set, mount after label */
+} UAContext;
+
+/* ua_cmds.c */
+int do_a_command(UAContext *ua, char *cmd);
+int do_a_dot_command(UAContext *ua, char *cmd);
+int qmessagescmd(UAContext *ua, char *cmd);
+int open_db(UAContext *ua);
+void close_db(UAContext *ua);
+
+/* ua_input.c */
+char *next_arg(char **s);
+int get_cmd(UAContext *ua, char *prompt);
+void parse_command_args(UAContext *ua);
+
+/* ua_output.c */
+void prtit(void *ctx, char *msg);
+
+/* ua_server.c */
+void bsendmsg(void *sock, char *fmt, ...);
+
+/* ua_select.c */
+STORE *select_storage_resource(UAContext *ua);
+JOB   *select_job_resource(UAContext *ua);
+int    select_pool_dbr(UAContext *ua, POOL_DBR *pr);
+CLIENT *select_client_resource(UAContext *ua);
+FILESET *select_fs_resource(UAContext *ua);
+
+void   start_prompt(UAContext *ua, char *msg);
+void   add_prompt(UAContext *ua, char *prompt);
+int    do_prompt(UAContext *ua, char *msg, char *prompt);
+CAT   *get_catalog_resource(UAContext *ua);           
+STORE *get_storage_resource(UAContext *ua, char *cmd);
+int    get_media_type(UAContext *ua, char *MediaType);
+int    get_pool_dbr(UAContext *ua, POOL_DBR *pr);
+POOL  *get_pool_resource(UAContext *ua);
+CLIENT *get_client_resource(UAContext *ua);
+
+int find_arg_keyword(UAContext *ua, char **list);
+int do_keyword_prompt(UAContext *ua, char *msg, char **list);
diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c
new file mode 100644 (file)
index 0000000..791ca47
--- /dev/null
@@ -0,0 +1,1267 @@
+/*
+ *
+ *   Bacula Director -- User Agent Commands
+ *
+ *     Kern Sibbald, September MM
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+#include "ua.h"
+
+/* Imported subroutines */
+extern void run_job(JCR *jcr);
+
+/* Imported variables */
+extern struct s_jl joblevels[];
+extern int r_first;
+extern int r_last;
+extern struct s_res resources[];
+extern int console_msg_pending;
+extern FILE *con_fd;
+extern char my_name[];
+
+/* Imported functions */
+extern int statuscmd(UAContext *ua, char *cmd);
+extern int listcmd(UAContext *ua, char *cmd);
+extern int showcmd(UAContext *ua, char *cmd);
+extern int messagescmd(UAContext *ua, char *cmd);
+extern int autodisplaycmd(UAContext *ua, char *cmd);
+extern int sqlquerycmd(UAContext *ua, char *cmd);
+extern int querycmd(UAContext *ua, char *cmd);
+extern int runcmd(UAContext *ua, char *cmd);
+extern int retentioncmd(UAContext *ua, char *cmd);
+
+/* Forward referenced functions */
+static int addcmd(UAContext *ua, char *cmd),  createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd);
+static int setdebugcmd(UAContext *ua, char *cmd);
+static int helpcmd(UAContext *ua, char *cmd);
+static int deletecmd(UAContext *ua, char *cmd);
+static int usecmd(UAContext *ua, char *cmd),  unmountcmd(UAContext *ua, char *cmd);
+static int labelcmd(UAContext *ua, char *cmd), mountcmd(UAContext *ua, char *cmd), updatecmd(UAContext *ua, char *cmd);
+static int versioncmd(UAContext *ua, char *cmd), automountcmd(UAContext *ua, char *cmd);
+static int update_media(UAContext *ua);
+static int update_pool(UAContext *ua);
+static int delete_media(UAContext *ua);
+static int delete_pool(UAContext *ua);
+
+int quitcmd(UAContext *ua, char *cmd);
+
+
+struct cmdstruct { char *key; int (*func)(UAContext *ua, char *cmd); char *help; }; 
+static struct cmdstruct commands[] = {
+ { N_("add"),        addcmd,       _("add media to a pool")},
+ { N_("autodisplay"), autodisplaycmd, _("autodisplay [on/off] -- console messages")},
+ { N_("automount"),   automountcmd,   _("automount [on/off] -- after label")},
+ { N_("cancel"),     cancelcmd,    _("cancel job=nnn -- cancel a job")},
+ { N_("create"),     createcmd,    _("create DB Pool from resource")},  
+ { N_("delete"),     deletecmd,    _("delete [pool=<pool-name> | media volume=<volume-name>]")},    
+ { N_("help"),       helpcmd,      _("print this command")},
+ { N_("label"),      labelcmd,     _("label a tape")},
+ { N_("list"),       listcmd,      _("list [pools | jobs | jobtotals | media <pool> | files job=<nn>]; from catalog")},
+ { N_("messages"),   messagescmd,  _("messages")},
+ { N_("mount"),      mountcmd,     _("mount <storage-name>")},
+ { N_("retention"),  retentioncmd, _("retention")},
+ { N_("run"),        runcmd,       _("run <job-name>")},
+ { N_("setdebug"),   setdebugcmd,  _("sets debug level")},
+ { N_("show"),       showcmd,      _("show (resource records) [jobs | pools | ... | all]")},
+ { N_("sqlquery"),   sqlquerycmd,  _("use SQL to query catalog")}, 
+ { N_("status"),     statuscmd,    _("status [storage | client]=<name>")},
+ { N_("unmount"),    unmountcmd,   _("unmount <storage-name>")},
+ { N_("update"),     updatecmd,    _("update DB Pool from resource")},
+ { N_("use"),        usecmd,       _("use catalog xxx")},
+ { N_("version"),    versioncmd,   _("print Director version")},
+ { N_("quit"),       quitcmd,      _("quit")},
+ { N_("query"),      querycmd,     _("query catalog")},
+ { N_("exit"),       quitcmd,      _("exit = quit")},
+            };
+#define comsize (sizeof(commands)/sizeof(struct cmdstruct))
+
+/*
+ * Execute a command from the UA
+ */
+int do_a_command(UAContext *ua, char *cmd)
+{
+   unsigned int i;
+   int len, stat;
+   int found;
+
+   found = 0;
+   stat = 1;
+
+   Dmsg1(20, "Command: %s\n", ua->UA_sock->msg);
+   if (ua->argc == 0) {
+      return 1;
+   }
+
+   len = strlen(ua->argk[0]);
+   for (i=0; i<comsize; i++)      /* search for command */
+      if (strncasecmp(ua->argk[0],  _(commands[i].key), len) == 0) {
+        stat = (*commands[i].func)(ua, cmd);   /* go execute command */
+        found = 1;
+        break;
+      }
+   if (!found) {
+      strcat(ua->UA_sock->msg, _(": is an illegal command\n"));
+      ua->UA_sock->msglen = strlen(ua->UA_sock->msg);
+      bnet_send(ua->UA_sock);
+   }
+   return stat;
+}
+
+
+/*
+ *  Add Volumes to an existing Pool
+ *
+ */
+static int addcmd(UAContext *ua, char *cmd) 
+{
+   POOL_DBR pr;
+   MEDIA_DBR mr;
+   int num, i, max, startnum;
+   int first_id = 0;
+   char name[MAX_NAME_LENGTH];
+
+   bsendmsg(ua, _(
+"You probably don't want to be using this command since it\n"
+"creates database records without labeling the Volumes.\n"
+"You probably want to use the label command.\n\n"));
+
+   if (!open_db(ua)) {
+      return 1;
+   }
+
+   memset(&pr, 0, sizeof(pr));
+   memset(&mr, 0, sizeof(mr));
+
+   if (!get_pool_dbr(ua, &pr)) {
+      return 1;
+   }
+
+   Dmsg4(20, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
+      pr.MaxVols, pr.PoolType);
+
+   while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
+      bsendmsg(ua, _("Pool already has maximum volumes = %d\n"), pr.MaxVols);
+      for (;;) {
+         if (!get_cmd(ua, _("Enter new maximum (zero for unlimited): "))) {
+           return 1;
+        }
+        pr.MaxVols = atoi(ua->cmd);
+        if (pr.MaxVols < 0) {
+            bsendmsg(ua, _("Max vols must be zero or greater.\n"));
+           continue;
+        }
+        break;
+      }
+   }
+
+   if (!get_media_type(ua, mr.MediaType)) {
+      return 1;
+   }
+
+   if (pr.MaxVols == 0) {
+      max = 1000;
+   } else {
+      max = pr.MaxVols - pr.NumVols;
+   }
+   for (;;) {
+      char buf[100]; 
+      sprintf(buf, _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
+      if (!get_cmd(ua, buf)) {
+        return 1;
+      }
+      num = atoi(ua->cmd);
+      if (num < 0 || num > max) {
+         bsendmsg(ua, _("The number must be between 0 and %d\n"), max);
+        continue;
+      }
+      break;
+   }
+getVolName:
+   if (num == 0) {
+      if (!get_cmd(ua, _("Enter Volume name: "))) {
+        return 1;
+      }
+   } else {
+      if (!get_cmd(ua, _("Enter base volume name: "))) {
+        return 1;
+      }
+   }
+   if (strchr(ua->cmd, '|')) {
+      bsendmsg(ua, _("Illegal character | in a volume name.\n"));
+      goto getVolName;
+   }
+   if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
+      bsendmsg(ua, _("Volume name too long.\n"));
+      goto getVolName;
+   }
+
+   strcpy(name, ua->cmd);
+   if (num > 0) {
+      strcat(name, "%04d");
+
+      for (;;) {
+         if (!get_cmd(ua, _("Enter the starting number: "))) {
+           return 1;
+        }
+        startnum = atoi(ua->cmd);
+        if (startnum < 1) {
+            bsendmsg(ua, _("Start number must be greater than zero.\n"));
+           continue;
+        }
+        break;
+      }
+   } else {
+      startnum = 1;
+      num = 1;
+   }
+          
+   mr.PoolId = pr.PoolId;
+   strcpy(mr.VolStatus, "Append");
+   strcpy(mr.Recycle, "No");
+   for (i=startnum; i < num+startnum; i++) { 
+      sprintf(mr.VolumeName, name, i);
+      Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
+      if (!db_create_media_record(ua->db, &mr)) {
+        bsendmsg(ua, db_strerror(ua->db));
+        return 1;
+      }
+      if (i == startnum) {
+        first_id = mr.PoolId;
+      }
+   }
+   pr.NumVols += num;
+   Dmsg0(200, "Update pool record.\n"); 
+   if (db_update_pool_record(ua->db, &pr) != 1) {
+      bsendmsg(ua, db_strerror(ua->db));
+      return 1;
+   }
+   bsendmsg(ua, _("%d Volumes created in pool %s\n"), num, pr.Name);
+
+   return 1;
+}
+
+/*
+ * Turn auto mount on/off  
+ * 
+ *  automount on 
+ *  automount off
+ */
+int automountcmd(UAContext *ua, char *cmd)
+{
+   char *onoff;
+
+   if (ua->argc != 2) {
+      if (!get_cmd(ua, _("Turn on or off? "))) {
+           return 1;
+      }
+      onoff = ua->cmd;
+   } else {
+      onoff = ua->argk[1];
+   }
+
+   ua->automount = (strcasecmp(onoff, _("off")) == 0) ? 0 : 1;
+   return 1; 
+}
+
+
+/*
+ * Cancel a job
+ */
+static int cancelcmd(UAContext *ua, char *cmd)
+{
+   int i;
+   int njobs = 0;
+   BSOCK *sd, *fd;
+   JCR *jcr = NULL;
+   char JobName[MAX_NAME_LENGTH];
+
+   if (!open_db(ua)) {
+      return 1;
+   }
+
+   for (i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
+        if (!ua->argv[i]) {
+           break;
+        }
+        if (!(jcr=get_jcr_by_id(atoi(ua->argv[i])))) {
+            bsendmsg(ua, _("JobId %d is not running.\n"), atoi(ua->argv[i]));
+           return 1;
+        }
+        break;
+      } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
+        if (!ua->argv[i]) {
+           break;
+        }
+        if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
+            bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
+           return 1;
+        }
+        break;
+      }
+   }
+   /* If we still do not have a jcr,
+    *  throw up a list and ask the user to select one.
+    */
+   if (!jcr) {
+      /* Count Jobs running */
+      lock_jcr_chain();
+      for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
+        if (jcr->JobId == 0) {      /* this is us */
+           free_locked_jcr(jcr);
+           njobs--;
+           continue;
+        }
+        free_locked_jcr(jcr);
+      }
+      unlock_jcr_chain();
+      if (njobs == 0) {
+         bsendmsg(ua, _("No Jobs running.\n"));
+        return 1;
+      }
+      start_prompt(ua, _("Select Job:\n"));
+      lock_jcr_chain();
+      for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
+        if (jcr->JobId == 0) {      /* this is us */
+           free_locked_jcr(jcr);
+           continue;
+        }
+        add_prompt(ua, jcr->Job);
+        free_locked_jcr(jcr);
+      }
+      unlock_jcr_chain();
+      if (do_prompt(ua, _("Choose Job to cancel"), JobName) < 0) {
+        return 1;
+      }
+      if (njobs == 1) {
+         if (!get_cmd(ua, _("Confirm cancel (yes/no): "))) {
+           return 1;
+        }
+         if (strcasecmp(ua->cmd, _("yes")) != 0) {
+           return 1;
+        }
+      }
+      jcr = get_jcr_by_full_name(JobName);
+      if (!jcr) {
+         bsendmsg(ua, _("Job %s not found.\n"), JobName);
+        return 1;
+      }
+   }
+     
+   switch (jcr->JobStatus) {
+   case JS_Created:
+      jcr->JobStatus = JS_Cancelled;
+      bsendmsg(ua, _("JobId %d, Job %s marked to be cancelled.\n"),
+             jcr->JobId, jcr->Job);
+      free_jcr(jcr);
+      return 1;
+        
+   case JS_Running:
+   case JS_WaitSD:
+   case JS_WaitFD:
+   case JS_WaitMedia:
+   case JS_WaitMount:
+   case JS_Blocked:
+
+      jcr->JobStatus = JS_Cancelled;
+      /* Cancel File daemon */
+      ua->jcr->client = jcr->client;
+      if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
+         bsendmsg(ua, _("Failed to connect to File daemon.\n"));
+        free_jcr(jcr);
+        return 1;
+      }
+      Dmsg0(200, "Connected to file daemon\n");
+      fd = ua->jcr->file_bsock;
+      bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
+      while (bnet_recv(fd) > 0) {
+         bsendmsg(ua, "%s", fd->msg);
+      }
+      bnet_sig(fd, BNET_TERMINATE);
+      bnet_close(fd);
+      ua->jcr->file_bsock = NULL;
+
+      /* Cancel Storage daemon */
+      ua->jcr->store = jcr->store;
+      if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
+         bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
+        free_jcr(jcr);
+        return 1;
+      }
+      Dmsg0(200, "Connected to storage daemon\n");
+      sd = ua->jcr->store_bsock;
+      bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
+      while (bnet_recv(sd) > 0) {
+         bsendmsg(ua, "%s", sd->msg);
+      }
+      bnet_sig(sd, BNET_TERMINATE);
+      bnet_close(sd);
+      ua->jcr->store_bsock = NULL;
+
+   default:
+      bsendmsg(ua, _("JobId %d Job %s Status=%c cannot be cancelled.\n"), 
+         jcr->JobId, jcr->Job, jcr->JobStatus);
+   }
+   free_jcr(jcr);
+
+   return 1; 
+}
+
+/*
+ * Create a pool record from a given Pool resource
+ *   Also called from backup.c
+ * Returns: -1 on error
+ *          0  record already exists
+ *          1  record created
+ */
+
+int create_pool(B_DB *db, POOL *pool)
+{
+   POOL_DBR  pr;
+
+   memset(&pr, 0, sizeof(POOL_DBR));
+
+   strcpy(pr.Name, pool->hdr.name);
+
+   if (db_get_pool_record(db, &pr)) {
+      return 0;                      /* exists */
+   }
+
+   strcpy(pr.PoolType, pool->pool_type);
+   pr.MaxVols = pool->max_volumes;
+   pr.NumVols = 0;
+   pr.UseOnce = pool->use_volume_once;
+   pr.UseCatalog = pool->use_catalog;
+   pr.AcceptAnyVolume = pool->accept_any_volume;
+   if (pool->label_format) {
+      strcpy(pr.LabelFormat, pool->label_format);
+   } else {
+      strcpy(pr.LabelFormat, "*");    /* none */
+   }
+
+   if (!db_create_pool_record(db, &pr)) {
+      return -1;                     /* error */
+   }
+   return 1;
+}
+
+
+
+/*
+ * Create a Pool Record in the database.
+ *  It is always created from the Resource record.
+ */
+static int createcmd(UAContext *ua, char *cmd) 
+{
+   POOL *pool;
+
+   if (!open_db(ua)) {
+      return 1;
+   }
+
+   pool = get_pool_resource(ua);
+   if (!pool) {
+      return 1;
+   }
+
+   switch (create_pool(ua->db, pool)) {
+   case 0:
+      bsendmsg(ua, _("Error: Pool %s already exists.\n\
+Use update to change it.\n"), pool->hdr.name);
+      break;
+
+   case -1:
+      bsendmsg(ua, db_strerror(ua->db));
+      break;
+
+   default:
+     break;
+   }
+   return 1;
+}
+
+
+
+
+/*
+ * Update a Pool Record in the database.
+ *  It is always updated from the Resource record.
+ *
+ *    update pool=<pool-name>
+ *        updates pool from Pool resource
+ *    update media pool=<pool-name> volume=<volume-name>
+ *        changes pool info for volume
+ */
+static int updatecmd(UAContext *ua, char *cmd) 
+{
+   static char *kw[] = {
+      N_("media"),
+      N_("volume"),
+      N_("pool"),
+      NULL};
+
+   if (!open_db(ua)) {
+      return 1;
+   }
+
+   switch (find_arg_keyword(ua, kw)) {
+      case 0:
+      case 1:
+        update_media(ua);
+        return 1;
+      case 2:
+        update_pool(ua);
+        return 1;
+      default:
+        break;
+   }
+    
+   start_prompt(ua, _("Update choice:\n"));
+   add_prompt(ua, _("pool"));
+   add_prompt(ua, _("media"));
+   switch (do_prompt(ua, _("Choose catalog item to update"), NULL)) {
+      case 0:
+        update_pool(ua);
+        break;
+      case 1:
+        update_media(ua);
+        break;
+      default:
+        break;
+   }
+   return 1;
+}
+
+/*
+ * Update a media record -- allows you to change the
+ *  Volume status. E.g. if you want Bacula to stop
+ *  writing on the volume, set it to anything other
+ *  than Append.
+ */             
+static int update_media(UAContext *ua)
+{
+   POOL_DBR pr;
+   MEDIA_DBR mr;
+   int i;
+   static char *kw[] = {
+      "volume",
+      NULL};
+
+   memset(&pr, 0, sizeof(pr));
+   memset(&mr, 0, sizeof(mr));
+   if (!get_pool_dbr(ua, &pr)) {
+      return 1;
+   }
+   mr.PoolId = pr.PoolId;
+   mr.VolumeName[0] = 0;
+
+   i = find_arg_keyword(ua, kw);
+   if (i == 0 && ua->argv[i]) {
+      strcpy(mr.VolumeName, ua->argv[i]);
+   }
+   if (mr.VolumeName[0] == 0) {
+      db_list_media_records(ua->db, &mr, prtit, ua);
+      if (!get_cmd(ua, _("Enter Volume name to update: "))) {
+        return 1;
+      }
+      strcpy(mr.VolumeName, ua->cmd);
+   }
+   mr.MediaId = 0;
+   if (!db_get_media_record(ua->db, &mr)) {
+      bsendmsg(ua, _("Media record for %s not found.\n"), mr.VolumeName);
+      return 1;
+   }
+   start_prompt(ua, _("Volume Status Values:\n"));
+   add_prompt(ua, "Append");
+   add_prompt(ua, "Archive");
+   add_prompt(ua, "Disabled");
+   add_prompt(ua, "Full");
+   add_prompt(ua, "Recycle");
+   add_prompt(ua, "Read-Only");
+   if (do_prompt(ua, _("Choose new Volume Status"), ua->cmd) < 0) {
+      return 1;
+   }
+   strcpy(mr.VolStatus, ua->cmd);
+   db_update_media_record(ua->db, &mr);
+   return 1;
+}
+
+/* 
+ * Update pool record -- pull info from current POOL resource
+ */
+static int update_pool(UAContext *ua)
+{
+   POOL_DBR  pr;
+   int id;
+   POOL *pool;
+   
+   memset(&pr, 0, sizeof(pr));
+   if (!get_pool_dbr(ua, &pr)) {
+      return 1;
+   }
+
+   strcpy(pr.PoolType, pool->pool_type);
+   if (pr.MaxVols != (uint32_t) (pool->max_volumes)) {
+      pr.MaxVols = pool->max_volumes;
+   }
+   if (pr.MaxVols != 0 && pr.MaxVols < pr.NumVols) {
+      pr.MaxVols = pr.NumVols;
+   }
+   pr.UseOnce = pool->use_volume_once;
+   pr.UseCatalog = pool->use_catalog;
+   pr.AcceptAnyVolume = pool->accept_any_volume;
+   if (pool->label_format) {
+      strcpy(pr.LabelFormat, pool->label_format);
+   } else {
+      strcpy(pr.LabelFormat, "*");    /* none */
+   }
+   id = db_update_pool_record(ua->db, &pr);
+   if (id <= 0) {
+      bsendmsg(ua, "Error: db_update_pool_record returned %d\n", id);
+   }
+   return 1;
+}
+
+
+static void do_storage_setdebug(UAContext *ua, STORE *store, int level)
+{
+   BSOCK *sd;
+
+   ua->jcr->store = store;
+   /* Try connecting for up to 15 seconds */
+   bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"), 
+      store->hdr.name, store->address, store->SDport);
+   if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
+      bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
+      return;
+   }
+   Dmsg0(20, _("Connected to storage daemon\n"));
+   sd = ua->jcr->store_bsock;
+   bnet_fsend(sd, "setdebug=%d\n", level);
+   if (bnet_recv(sd) > 0) {
+      bsendmsg(ua, "%s", sd->msg);
+   }
+   bnet_sig(sd, BNET_TERMINATE);
+   bnet_close(sd);
+   ua->jcr->store_bsock = NULL;
+   return;  
+}
+   
+static void do_client_setdebug(UAContext *ua, CLIENT *client, int level)
+{
+   BSOCK *fd;
+
+   /* Connect to File daemon */
+
+   ua->jcr->client = client;
+   /* Try to connect for 15 seconds */
+   bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), 
+      client->hdr.name, client->address, client->FDport);
+   if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
+      bsendmsg(ua, _("Failed to connect to Client.\n"));
+      return;
+   }
+   Dmsg0(20, "Connected to file daemon\n");
+   fd = ua->jcr->file_bsock;
+   bnet_fsend(fd, "setdebug=%d\n", level);
+   if (bnet_recv(fd) > 0) {
+      bsendmsg(ua, "%s", fd->msg);
+   }
+   bnet_sig(fd, BNET_TERMINATE);
+   bnet_close(fd);
+   ua->jcr->file_bsock = NULL;
+
+   return;  
+}
+
+
+static void do_all_setdebug(UAContext *ua, int level)
+{
+   STORE *store, **unique_store;
+   CLIENT *client, **unique_client;
+   int i, j, found;
+
+   /* Director */
+   debug_level = level;
+
+   /* Count Storage items */
+   LockRes();
+   store = NULL;
+   for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
+      { }
+   unique_store = (STORE **) malloc(i * sizeof(STORE));
+   /* Find Unique Storage address/port */        
+   store = (STORE *)GetNextRes(R_STORAGE, NULL);
+   i = 0;
+   unique_store[i++] = store;
+   while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
+      found = 0;
+      for (j=0; j<i; j++) {
+        if (strcmp(unique_store[j]->address, store->address) == 0 &&
+            unique_store[j]->SDport == store->SDport) {
+           found = 1;
+           break;
+        }
+      }
+      if (!found) {
+        unique_store[i++] = store;
+         Dmsg2(40, "Stuffing: %s:%d\n", store->address, store->SDport);
+      }
+   }
+   UnlockRes();
+
+   /* Call each unique Storage daemon */
+   for (j=0; j<i; j++) {
+      do_storage_setdebug(ua, unique_store[j], level);
+   }
+   free(unique_store);
+
+   /* Count Client items */
+   LockRes();
+   client = NULL;
+   for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
+      { }
+   unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
+   /* Find Unique Client address/port */        
+   client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
+   i = 0;
+   unique_client[i++] = client;
+   while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
+      found = 0;
+      for (j=0; j<i; j++) {
+        if (strcmp(unique_client[j]->address, client->address) == 0 &&
+            unique_client[j]->FDport == client->FDport) {
+           found = 1;
+           break;
+        }
+      }
+      if (!found) {
+        unique_client[i++] = client;
+         Dmsg2(40, "Stuffing: %s:%d\n", client->address, client->FDport);
+      }
+   }
+   UnlockRes();
+
+   /* Call each unique File daemon */
+   for (j=0; j<i; j++) {
+      do_client_setdebug(ua, unique_client[j], level);
+   }
+   free(unique_client);
+}
+
+/*
+ * setdebug level=nn all
+ */
+static int setdebugcmd(UAContext *ua, char *cmd)
+{
+   STORE *store;
+   CLIENT *client;
+   int level;
+   int i;
+
+   if (!open_db(ua)) {
+      return 1;
+   }
+   Dmsg1(20, "setdebug:%s:\n", cmd);
+
+   level = -1;
+   for (i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], _("level")) == 0 && ua->argv[i]) {
+        level = atoi(ua->argv[i]);
+        break;
+      }
+   }
+   if (level < 0) {
+      if (!get_cmd(ua, _("Enter new debug level: "))) {
+        return 1;
+      }
+      level = atoi(ua->cmd);
+   }
+   if (level < 0) {
+      bsendmsg(ua, _("level cannot be negative.\n"));
+      return 1;
+   }
+
+   /* General debug? */
+   for (i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], _("all")) == 0) {
+        do_all_setdebug(ua, level);
+        return 1;
+      }
+      if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
+          strcasecmp(ua->argk[i], _("director")) == 0) {
+        debug_level = level;
+        return 1;
+      }
+      if (strcasecmp(ua->argk[i], _("client")) == 0) {
+        client = NULL;
+        if (ua->argv[i]) {
+           client = (CLIENT *) GetResWithName(R_CLIENT, ua->argv[i]);
+           if (client) {
+              do_client_setdebug(ua, client, level);
+              return 1;
+           }
+        }
+        client = select_client_resource(ua);   
+        if (client) {
+           do_client_setdebug(ua, client, level);
+           return 1;
+        }
+
+        store = get_storage_resource(ua, cmd);
+        if (store) {
+           do_storage_setdebug(ua, store, level);
+           return 1;
+        }
+      }
+   } 
+   /*
+    * We didn't find an appropriate keyword above, so
+    * prompt the user.
+    */
+   start_prompt(ua, _("Available daemons are: \n"));
+   add_prompt(ua, _("Director"));
+   add_prompt(ua, _("Storage"));
+   add_prompt(ua, _("Client"));
+   add_prompt(ua, _("All"));
+   switch(do_prompt(ua, _("Select daemon type to set debug level"), NULL)) {
+      case 0:                        /* Director */
+        debug_level = level;
+        break;
+      case 1:
+        store = get_storage_resource(ua, cmd);
+        if (store) {
+           do_storage_setdebug(ua, store, level);
+        }
+        break;
+      case 2:
+        client = select_client_resource(ua);
+        if (client) {
+           do_client_setdebug(ua, client, level);
+        }
+        break;
+      case 3:
+        do_all_setdebug(ua, level);
+        break;
+      default:
+        break;
+   }
+   return 1;
+}
+
+
+
+/*
+ * Delete Pool records (should purge Media with it).
+ *
+ *  delete pool=<pool-name>
+ *  delete media pool=<pool-name> volume=<name>
+ */
+static int deletecmd(UAContext *ua, char *cmd)
+{
+   static char *keywords[] = {
+      N_("media"),
+      N_("pool"),
+      NULL};
+
+   if (!open_db(ua)) {
+      return 1;
+   }
+
+   bsendmsg(ua, _(
+"In general it is not a good idea to delete either a\n"
+"Pool or Media since in both cases, you may delete Media\n"
+"that contain data.\n\n"));
+     
+   switch (find_arg_keyword(ua, keywords)) {
+      case 0:
+        delete_media(ua);     
+        return 1;
+      case 1:
+        delete_pool(ua);
+        return 1;
+      default:
+        break;
+   }
+   switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
+      case 0:
+        delete_media(ua);
+        break;
+      case 1:
+        delete_pool(ua);
+        break;
+      default:
+         bsendmsg(ua, _("Nothing done.\n"));
+        break;
+   }
+   return 1;
+}
+
+/*
+ * Delete media records from database -- dangerous 
+ */
+static int delete_media(UAContext *ua)
+{
+   POOL_DBR pr;
+   MEDIA_DBR mr;
+   int found = FALSE;
+   int i;
+
+   memset(&pr, 0, sizeof(pr));
+   memset(&mr, 0, sizeof(mr));
+
+   /* Get the pool, possibly from pool=<pool-name> */
+   if (!get_pool_dbr(ua, &pr)) {
+      return 1;
+   }
+   mr.PoolId = pr.PoolId;
+
+   /* See if a volume name is specified as an argument */
+   for (i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], _("volume")) == 0 && ua->argv[i]) {
+        found = TRUE;
+        break;
+      }
+   }
+   if (found) {
+      strcpy(mr.VolumeName, ua->argv[i]);
+   } else {
+      db_list_media_records(ua->db, &mr, prtit, ua);
+      if (!get_cmd(ua, _("Enter the Volume name to delete: "))) {
+        return 1;
+      }
+   }
+   mr.MediaId = 0;
+   strcpy(mr.VolumeName, ua->cmd);
+   if (!get_cmd(ua, _("If you want to continue enter pretty please: "))) {
+      return 1;
+   }
+   if (strcmp(ua->cmd, _("pretty please")) == 0) {
+      db_delete_media_record(ua->db, &mr);
+   }
+   return 1;
+}
+
+/*
+ * Delete a pool record from the database -- dangerous  
+ */
+static int delete_pool(UAContext *ua)
+{
+   POOL_DBR  pr;
+   
+   memset(&pr, 0, sizeof(pr));
+
+   if (!get_pool_dbr(ua, &pr)) {
+      return 1;
+   }
+   if (!get_cmd(ua, _("If you want to continue enter pretty please: "))) {
+      return 1;
+   }
+   if (strcmp(ua->cmd, _("pretty please")) == 0) {
+      db_delete_pool_record(ua->db, &pr);
+   }
+   return 1;
+}
+
+
+/*
+ * Label a tape 
+ *  
+ *   label storage=xxx volume=vvv
+ */
+static int labelcmd(UAContext *ua, char *cmd)
+{
+   STORE *store;
+   BSOCK *sd;
+   char dev_name[MAX_NAME_LENGTH];
+   MEDIA_DBR mr;
+   POOL_DBR pr;
+   int ok = FALSE;
+   int mounted = FALSE;
+   int i;
+   static char *keyword[] = {
+      "volume",
+      NULL};
+
+   if (!open_db(ua)) {
+      return 1;
+   }
+   store = get_storage_resource(ua, cmd);
+   if (!store) {
+      return 1;
+   }
+
+   i = find_arg_keyword(ua, keyword);
+   if (i >=0 && ua->argv[i]) {
+      strcpy(ua->cmd, ua->argv[i]);
+      goto gotVol;
+   }
+
+getVol:
+   if (!get_cmd(ua, _("Enter new Volume name: "))) {
+      return 1;
+   }
+gotVol:
+   if (strchr(ua->cmd, '|')) {
+      bsendmsg(ua, _("Illegal character | in a volume name.\n"));
+      goto getVol;
+   }
+   if (strlen(ua->cmd) >= MAX_NAME_LENGTH) {
+      bsendmsg(ua, _("Volume name too long.\n"));
+      goto getVol;
+   }
+
+   memset(&mr, 0, sizeof(mr));
+   strcpy(mr.VolumeName, ua->cmd);
+   if (db_get_media_record(ua->db, &mr)) {
+       bsendmsg(ua, _("Media record for Volume %s already exists.\n"), 
+         mr.VolumeName);
+       return 1;
+   }
+   strcpy(mr.MediaType, store->media_type);
+
+   memset(&pr, 0, sizeof(pr));
+   if (!select_pool_dbr(ua, &pr)) {
+      return 1;
+   }
+   mr.PoolId = pr.PoolId;
+   strcpy(mr.Recycle, "Yes");
+   strcpy(mr.VolStatus, "Append");
+
+   ua->jcr->store = store;
+   bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
+      store->hdr.name, store->address, store->SDport);
+   if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
+      bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
+      return 1;   
+   }
+   sd = ua->jcr->store_bsock;
+   strcpy(dev_name, store->dev_name);
+   bash_spaces(dev_name);
+   bash_spaces(mr.VolumeName);
+   bash_spaces(mr.MediaType);
+   bash_spaces(pr.Name);
+   bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s"), 
+      dev_name, mr.VolumeName, pr.Name, mr.MediaType);
+   bsendmsg(ua, "Sending label command ...\n");
+   while (bnet_recv(sd) > 0) {
+      bsendmsg(ua, "%s", sd->msg);
+      if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
+        ok = TRUE;
+      }
+   }
+   ua->jcr->store_bsock = NULL;
+   unbash_spaces(dev_name);
+   unbash_spaces(mr.VolumeName);
+   unbash_spaces(mr.MediaType);
+   unbash_spaces(pr.Name);
+   if (ok) {
+      if (db_create_media_record(ua->db, &mr)) {
+         bsendmsg(ua, _("Media record for Volume=%s successfully created.\n"),
+           mr.VolumeName);
+        if (ua->automount) {
+            bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
+            bnet_fsend(sd, "mount %s", dev_name);
+           while (bnet_recv(sd) > 0) {
+               bsendmsg(ua, "%s", sd->msg);
+              /* Here we can get
+               *  3001 OK mount. Device=xxx      or
+               *  3001 Mounted Volume vvvv
+               */
+               if (strncmp(sd->msg, "3001 ", 5) == 0) {
+                 mounted = TRUE;
+                 /***** ****FIXME***** find job waiting for  
+                  ***** mount, and change to waiting for SD  
+                  */
+              }
+           }
+        }
+      } else {
+         bsendmsg(ua, "%s", db_strerror(ua->db));
+      }
+   }
+   if (!mounted) {
+      bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
+   }
+   bnet_sig(sd, BNET_TERMINATE);
+   bnet_close(sd);
+   return 1;
+}
+
+static void do_mount_cmd(int mount, UAContext *ua, char *cmd)
+{
+   STORE *store;
+   BSOCK *sd;
+   char dev_name[MAX_NAME_LENGTH];
+
+
+   if (!open_db(ua)) {
+      return;
+   }
+   Dmsg1(20, "mount: %s\n", ua->UA_sock->msg);
+
+   store = get_storage_resource(ua, cmd);
+   if (!store) {
+      return;
+   }
+
+   Dmsg2(20, "Found storage, MediaType=%s DevName=%s\n",
+      store->media_type, store->dev_name);
+
+   ua->jcr->store = store;
+   if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
+      bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
+      return;
+   }
+   sd = ua->jcr->store_bsock;
+   strcpy(dev_name, store->dev_name);
+   bash_spaces(dev_name);
+   if (mount) {
+      bnet_fsend(sd, "mount %s", dev_name);
+   } else {
+      bnet_fsend(sd, "unmount %s", dev_name);
+   }
+   while (bnet_recv(sd) > 0) {
+      bsendmsg(ua, "%s", sd->msg);
+      if (strncmp(sd->msg, "3001 OK mount.", 14) == 0) {
+         /***** ****FIXME**** fix JobStatus */
+      }
+   }
+   bnet_sig(sd, BNET_TERMINATE);
+   bnet_close(sd);
+   ua->jcr->store_bsock = NULL;
+}
+
+/*
+ * mount [storage | device] <name>
+ */
+static int mountcmd(UAContext *ua, char *cmd)
+{
+   do_mount_cmd(1, ua, cmd);         /* mount */
+   return 1;
+}
+
+
+/*
+ * unmount [storage | device] <name>
+ */
+static int unmountcmd(UAContext *ua, char *cmd)
+{
+   do_mount_cmd(0, ua, cmd);         /* unmount */
+   return 1;
+}
+
+
+/*
+ * Switch databases
+ *   use catalog=<name>
+ */
+static int usecmd(UAContext *ua, char *cmd)
+{
+   CAT *oldcatalog, *catalog;
+
+
+   close_db(ua);                     /* close any previously open db */
+   oldcatalog = ua->catalog;
+
+   if (!(catalog = get_catalog_resource(ua))) {
+      ua->catalog = oldcatalog;
+   } else {
+      ua->catalog = catalog;
+   }
+   if (open_db(ua)) {
+      bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
+        ua->catalog->hdr.name, ua->catalog->db_name);
+   }
+   return 1;
+}
+
+int quitcmd(UAContext *ua, char *cmd) 
+{
+   return 0;
+}
+
+static int helpcmd(UAContext *ua, char *cmd)
+{
+   unsigned int i;
+
+/* usage(); */
+   bnet_fsend(ua->UA_sock, _("  Command    Description\n  =======    ===========\n"));
+   for (i=0; i<comsize; i++) {
+      bnet_fsend(ua->UA_sock, _("  %-10s %s\n"), _(commands[i].key), _(commands[i].help));
+   }
+   bnet_fsend(ua->UA_sock, "\n");
+   return 1;
+}
+
+static int versioncmd(UAContext *ua, char *cmd)
+{
+   bsendmsg(ua, "%s Version: " VERSION " (" DATE ")\n", my_name);
+   return 1;
+}
+
+
+/* A bit brain damaged in that if the user has not done
+ * a "use catalog xxx" command, we simply find the first
+ * catalog resource and open it.
+ */
+int open_db(UAContext *ua)
+{
+   if (ua->db) {
+      return 1;
+   }
+   if (!ua->catalog) {
+      LockRes();
+      ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
+      UnlockRes();
+      if (!ua->catalog) {    
+         bnet_fsend(ua->UA_sock, _("Could not find a Catalog resource\n"));
+        return 0;
+      } else {
+         bnet_fsend(ua->UA_sock, _("Using default Catalog name=%s DB=%s\n"), 
+           ua->catalog->hdr.name, ua->catalog->db_name);
+      }
+   }
+
+   Dmsg0(50, "Open database\n");
+   ua->db = db_init_database(ua->catalog->db_name, ua->catalog->db_user,
+                            ua->catalog->db_password);
+   if (!db_open_database(ua->db)) {
+      bnet_fsend(ua->UA_sock, _("Could not open DB %s: ERR=%s"), 
+        ua->catalog->db_name, db_strerror(ua->db));
+      close_db(ua);
+      return 0;
+   }
+   Dmsg1(50, "DB %s opened\n", ua->catalog->db_name);
+   return 1;
+}
+
+void close_db(UAContext *ua)
+{
+   if (ua->db) {
+      db_close_database(ua->db);
+   }
+   ua->db = NULL;
+}
diff --git a/bacula/src/dird/ua_dotcmds.c b/bacula/src/dird/ua_dotcmds.c
new file mode 100644 (file)
index 0000000..12aa6f7
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *
+ *   Bacula Director -- User Agent Commands
+ *     These are "dot" commands, i.e. commands preceded
+ *       by a period. These commands are meant to be used
+ *       by a program, so there is no prompting, and the
+ *       returned results are (supposed to be) predictable.
+ *
+ *     Kern Sibbald, April MMII
+ */
+
+/*
+   Copyright (C) 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+#include "ua.h"
+
+/* Imported variables */
+extern struct s_jl joblevels[];
+extern int r_first;
+extern int r_last;
+extern struct s_res resources[];
+extern int console_msg_pending;
+extern FILE *con_fd;
+extern char my_name[];
+
+/* Imported functions */
+extern int qmessagescmd(UAContext *ua, char *cmd);
+extern int quitcmd(UAContext *ua, char *cmd);
+
+/* Forward referenced functions */
+static int diecmd(UAContext *ua, char *cmd);
+static int jobscmd(UAContext *ua, char *cmd);
+static int filesetscmd(UAContext *ua, char *cmd);
+static int clientscmd(UAContext *ua, char *cmd);
+static int msgscmd(UAContext *ua, char *cmd);
+
+struct cmdstruct { char *key; int (*func)(UAContext *ua, char *cmd); char *help; }; 
+static struct cmdstruct commands[] = {
+ { N_(".die"),        diecmd,       NULL},
+ { N_(".jobs"),       jobscmd,      NULL},
+ { N_(".filesets"),   filesetscmd,  NULL},
+ { N_(".clients"),    clientscmd,   NULL},
+ { N_(".msgs"),       msgscmd,      NULL},
+ { N_(".messages"),   qmessagescmd, NULL},
+ { N_(".quit"),       quitcmd,      NULL},
+ { N_(".exit"),       quitcmd,      NULL} 
+            };
+#define comsize (sizeof(commands)/sizeof(struct cmdstruct))
+
+/*
+ * Execute a command from the UA
+ */
+int do_a_dot_command(UAContext *ua, char *cmd)
+{
+   unsigned int i;
+   int len, stat;  
+   int found;
+
+   found = 0;
+   stat = 1;
+
+   Dmsg1(200, "Dot command: %s\n", ua->UA_sock->msg);
+   if (ua->argc == 0) {
+      return 1;
+   }
+
+   len = strlen(ua->argk[0]);
+   if (len == 1) {
+      return 1;                      /* no op */
+   }
+   for (i=0; i<comsize; i++) {    /* search for command */
+      if (strncasecmp(ua->argk[0],  _(commands[i].key), len) == 0) {
+        stat = (*commands[i].func)(ua, cmd);   /* go execute command */
+        found = 1;
+        break;
+      }
+   }
+   if (!found) {
+      strcat(ua->UA_sock->msg, _(": is an illegal command\n"));
+      ua->UA_sock->msglen = strlen(ua->UA_sock->msg);
+      bnet_send(ua->UA_sock);
+   }
+   return stat;
+}
+
+/*
+ * Create segmentation fault 
+ */
+static int diecmd(UAContext *ua, char *cmd)
+{
+   JCR *jcr = NULL;
+   int a;
+   
+   a = jcr->JobId; /* ref NULL pointer */
+   return 0;
+}
+
+static int jobscmd(UAContext *ua, char *cmd)
+{
+   JOB *job = NULL;
+   LockRes();
+   while ( (job = (JOB *)GetNextRes(R_JOB, (RES *)job)) ) {
+      bsendmsg(ua, "%s\n", job->hdr.name);
+   }
+   UnlockRes();
+   return 1;
+}
+
+static int filesetscmd(UAContext *ua, char *cmd)
+{
+   FILESET *fs = NULL;
+   LockRes();
+   while ( (fs = (FILESET *)GetNextRes(R_FILESET, (RES *)fs)) ) {
+      bsendmsg(ua, "%s\n", fs->hdr.name);
+   }
+   UnlockRes();
+   return 1;
+}
+
+static int clientscmd(UAContext *ua, char *cmd)
+{
+   CLIENT *client = NULL;
+   LockRes();
+   while ( (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)) ) {
+      bsendmsg(ua, "%s\n", client->hdr.name);
+   }
+   UnlockRes();
+   return 1;
+}
+
+static int msgscmd(UAContext *ua, char *cmd)
+{
+   MSGS *msgs = NULL;
+   LockRes();
+   while ( (msgs = (MSGS *)GetNextRes(R_MSGS, (RES *)msgs)) ) {
+      bsendmsg(ua, "%s\n", msgs->hdr.name);
+   }
+   UnlockRes();
+   return 1;
+}
diff --git a/bacula/src/dird/ua_input.c b/bacula/src/dird/ua_input.c
new file mode 100644 (file)
index 0000000..53250db
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *
+ *   Bacula Director -- User Agent Input and scanning code
+ *
+ *     Kern Sibbald, October MMI
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+#include "ua.h"
+
+
+/* Imported variables */
+
+
+/* Exported functions */
+
+int get_cmd(UAContext *ua, char *prompt)
+{
+   BSOCK *sock = ua->UA_sock;
+
+   ua->cmd[0] = 0;
+   bnet_fsend(sock, "%s", prompt);
+   bnet_sig(sock, BNET_PROMPT);       /* request more input */
+   if (bnet_recv(sock) < 0) {
+      return 0;
+   }
+   ua->cmd = (char *) check_pool_memory_size(ua->cmd, sock->msglen+1);
+   strcpy(ua->cmd, sock->msg);
+   ua->cmd[sock->msglen] = 0;
+   strip_trailing_junk(ua->cmd);
+   return 1;
+}
+
+/* 
+ * Return next argument from command line.  Note, this
+ * routine is destructive.
+ */
+char *next_arg(char **s)
+{
+   char *p, *n;
+
+   /* skip past spaces to next arg */
+   for (p=*s; *p && *p == ' '; p++)
+      {}
+   /* Determine start of argument */
+   if (*p == '"') {
+      n = p+1;                       /* skip leading quote */
+   } else {
+      n = p;
+   }
+   /* Scan argment and terminate it */
+   for ( ; *p && *p != ' '; p++) {
+      if (*p == '"') {
+         for (p++; *p && *p != '"'; p++) {
+           *(p-1) = *p;
+           *p = 0;
+        }
+        break;
+      }
+   }
+   if (*p) {                         /* if more arguments */
+      *p++ = 0;                      /* terminate this one */
+   }
+   *s = p;
+   return n;
+}   
+
+/*
+ * This routine parses the input command line.
+ * It makes a copy in args, then builds an
+ *  argc, argv like list where
+ *    
+ *  argc = count of arguments
+ *  argk[i] = argument keyword (part preceding =)
+ *  argv[i] = argument value (part after =)
+ *
+ *  example:  arg1 arg2=abc arg3=
+ *
+ *  argc = c
+ *  argk[0] = arg1
+ *  argv[0] = NULL
+ *  argk[1] = arg2
+ *  argv[1] = abc
+ *  argk[2] = arg3
+ *  argv[2] = 
+ */
+
+void parse_command_args(UAContext *ua)
+{
+   BSOCK *sock = ua->UA_sock;
+   char *p, *n;
+   int i;
+
+   ua->args = (char *) check_pool_memory_size(ua->args, sock->msglen+1);
+   strcpy(ua->args, sock->msg);
+   ua->args[sock->msglen] = 0;
+   strip_trailing_junk(ua->args);
+   ua->argc = 0;
+   p = ua->args;
+   /* Pick up all arguments */
+   while (ua->argc < MAX_ARGS) {
+      n = next_arg(&p);   
+      if (*n) {
+        ua->argk[ua->argc++] = n;
+      } else {
+        break;
+      }
+   }
+   /* Separate keyword and value */
+   for (i=0; i<ua->argc; i++) {
+      p = strchr(ua->argk[i], '=');
+      if (p) {
+        *p++ = 0;                    /* terminate keyword and point to value */
+        if (strlen(p) > MAX_NAME_LENGTH-1) {
+           p[MAX_NAME_LENGTH-1] = 0; /* truncate to max len */
+        }
+      }
+      ua->argv[i] = p;               /* save ptr to value or NULL */
+   }
+#ifdef xxxxxxxxx
+   for (i=0; i<ua->argc; i++) {
+      Dmsg3(000, "Arg %d: kw=%s val=%s\n", i, 
+         ua->argk[i], ua->argv[i]?ua->argv[i]:"NULL");
+   }
+#endif
+}
diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c
new file mode 100644 (file)
index 0000000..e77673c
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ *
+ *   Bacula Director -- User Agent Output Commands
+ *     I.e. messages, listing database, showing resources, ...
+ *
+ *     Kern Sibbald, September MM
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+#include "ua.h"
+
+/* Imported subroutines */
+extern void run_job(JCR *jcr);
+
+/* Imported variables */
+extern struct s_jl joblevels[];
+extern int r_first;
+extern int r_last;
+extern struct s_res resources[];
+extern int console_msg_pending;
+extern FILE *con_fd;
+
+
+/* Imported functions */
+
+/* Forward referenced functions */
+
+
+/*
+ * Turn auto display of console messages on/off
+ */
+int autodisplaycmd(UAContext *ua, char *cmd)
+{
+   static char *kw[] = {
+      N_("on"), 
+      N_("off"),
+      NULL};
+
+   switch (find_arg_keyword(ua, kw)) {
+      case 0:
+        ua->auto_display_messages = 1;
+        break;
+      case 1:
+        ua->auto_display_messages = 0;
+        break;
+      default:
+         bsendmsg(ua, _("ON or OFF keyword missing.\n"));
+        break;
+   }
+   return 1; 
+}
+
+
+struct showstruct {char *res_name; int type;};
+static struct showstruct reses[] = {
+   {N_("directors"),  R_DIRECTOR},
+   {N_("clients"),    R_CLIENT},
+   {N_("jobs"),       R_JOB},
+   {N_("storages"),   R_STORAGE},
+   {N_("catalogs"),   R_CATALOG},
+   {N_("schedules"),  R_SCHEDULE},
+   {N_("filesets"),   R_FILESET},
+   {N_("groups"),     R_GROUP},
+   {N_("pools"),      R_POOL},
+   {N_("messages"),   R_MSGS},
+   {N_("all"),        -1},
+   {N_("help"),       -2},
+   {NULL,          0}
+};
+
+
+/*
+ *  Displays Resources
+ *
+ *  show all
+ *  show <resource-keyword-name>  e.g. show directors
+ *  show <resource-keyword-name>=<name> e.g. show director=HeadMan
+ *
+ */
+int showcmd(UAContext *ua, char *cmd)
+{
+   int i, j, type, len; 
+   int recurse;
+   char *res_name;
+   RES *res;
+
+   Dmsg1(20, "show: %s\n", ua->UA_sock->msg);
+
+
+   for (i=1; i<ua->argc; i++) {
+      type = 0;
+      res_name = ua->argk[i]; 
+      if (!ua->argv[i]) {            /* was a name given? */
+        /* No name, dump all resources of specified type */
+        recurse = 1;
+        len = strlen(res_name);
+        for (j=0; reses[j].res_name; j++) {
+           if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
+              type = reses[j].type;
+              if (type > 0) {
+                 res = resources[type-r_first].res_head;
+              } else {
+                 res = NULL;
+              }
+              break;
+           }
+        }
+      } else {
+        /* Dump a single resource with specified name */
+        recurse = 0;
+        len = strlen(res_name);
+        for (j=0; reses[j].res_name; j++) {
+           if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
+              type = reses[j].type;
+              res = (RES *)GetResWithName(type, ua->argv[i]);
+              if (!res) {
+                 type = -3;
+              }
+              break;
+           }
+        }
+      }
+
+      switch (type) {
+      case -1:                          /* all */
+        for (j=r_first; j<=r_last; j++) {
+           dump_resource(j, resources[j-r_first].res_head, bsendmsg, ua);     
+        }
+        break;
+      case -2:
+         bsendmsg(ua, _("Keywords for the show command are:\n"));
+        for (j=0; reses[j].res_name; j++) {
+            bsendmsg(ua, "%s\n", _(reses[j].res_name));
+        }
+        return 1;
+      case -3:
+         bsendmsg(ua, _("%s resource %s not found.\n"), res_name, ua->argv[i]);
+        return 1;
+      case 0:
+         bsendmsg(ua, _("Resource %s not found\n"), res_name);
+        return 1;
+      default:
+        dump_resource(recurse?type:-type, res, bsendmsg, ua);
+        break;
+      }
+   }
+   return 1;
+}
+
+
+/*
+ * Callback routine for "printing" database file listing
+ */
+void prtit(void *ctx, char *msg)
+{
+   UAContext *ua = (UAContext *)ctx;
+   bnet_fsend(ua->UA_sock, "%s", msg);
+}
+
+/* Format message and send to other end */
+void bsendmsg(void *ctx, char *fmt, ...)
+{
+   va_list arg_ptr;
+   UAContext *ua = (UAContext *)ctx;
+   BSOCK *bs = ua->UA_sock;
+   int maxlen;
+
+again:
+   maxlen = sizeof_pool_memory(bs->msg) - 1;
+   va_start(arg_ptr, fmt);
+   bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
+   va_end(arg_ptr);
+   if (bs->msglen < 0 || bs->msglen >= maxlen) {
+      bs->msg = (char *) realloc_pool_memory(bs->msg, maxlen + 200);
+      goto again;
+   }
+   bnet_send(bs);
+}
+
+
+/*
+ *  List contents of database
+ *
+ *  list jobs          - lists all jobs run
+ *  list jobid=nnn     - list job data for jobid
+ *  list job=name      - list job data for job
+ *  list jobmedia jobid=<nn>
+ *  list jobmedia job=name
+ *  list files jobid=<nn> - list files saved for job nn
+ *  list files job=name
+ *  list pools         - list pool records
+ *  list jobtotals     - list totals for all jobs
+ *  list media         - list media for given pool
+ *
+ */
+int listcmd(UAContext *ua, char *cmd) 
+{
+   char *VolumeName;
+   int jobid, n;
+   int i, j;
+   JOB_DBR jr;
+   POOL_DBR pr;
+   MEDIA_DBR mr;
+
+   if (!open_db(ua))
+      return 1;
+
+   memset(&jr, 0, sizeof(jr));
+   memset(&pr, 0, sizeof(pr));
+   memset(&mr, 0, sizeof(mr));
+
+   Dmsg1(20, "list: %s\n", cmd);
+
+   if (!ua->db) {
+      bsendmsg(ua, _("Hey! DB is NULL\n"));
+   }
+
+   /* Scan arguments looking for things to do */
+   for (i=1; i<ua->argc; i++) {
+      /* List JOBS */
+      if (strcasecmp(ua->argk[i], _("jobs")) == 0) {
+        db_list_job_records(ua->db, &jr, prtit, ua);
+
+        /* List JOBTOTALS */
+      } else if (strcasecmp(ua->argk[i], _("jobtotals")) == 0) {
+        db_list_job_totals(ua->db, &jr, prtit, ua);
+
+      /* List JOBID */
+      } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
+        if (ua->argv[i]) {
+           jobid = atoi(ua->argv[i]);
+           if (jobid > 0) {
+              jr.JobId = jobid;
+              db_list_job_records(ua->db, &jr, prtit, ua);
+           }
+        }
+
+      /* List JOB */
+      } else if (strcasecmp(ua->argk[i], _("job")) == 0 && ua->argv[i]) {
+        strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
+        jr.Job[MAX_NAME_LENGTH-1] = 0;
+        jr.JobId = 0;
+        db_list_job_records(ua->db, &jr, prtit, ua);
+
+      /* List FILES */
+      } else if (strcasecmp(ua->argk[i], _("files")) == 0) {
+
+        for (j=i+1; j<ua->argc; j++) {
+            if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
+              strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
+              jr.Job[MAX_NAME_LENGTH-1] = 0;
+              jr.JobId = 0;
+              db_get_job_record(ua->db, &jr);
+              jobid = jr.JobId;
+            } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
+              jobid = atoi(ua->argv[j]);
+           } else {
+              continue;
+           }
+           if (jobid > 0) {
+              db_list_files_for_job(ua->db, jobid, prtit, ua);
+           }
+        }
+      
+      /* List JOBMEDIA */
+      } else if (strcasecmp(ua->argk[i], _("jobmedia")) == 0) {
+        int done = FALSE;
+        for (j=i+1; j<ua->argc; j++) {
+            if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
+              strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
+              jr.Job[MAX_NAME_LENGTH-1] = 0;
+              jr.JobId = 0;
+              db_get_job_record(ua->db, &jr);
+              jobid = jr.JobId;
+            } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
+              jobid = atoi(ua->argv[j]);
+           } else {
+              continue;
+           }
+           db_list_jobmedia_records(ua->db, jobid, prtit, ua);
+           done = TRUE;
+        }
+        if (!done) {
+           /* List for all jobs (jobid=0) */
+           db_list_jobmedia_records(ua->db, 0, prtit, ua);
+        }
+
+      /* List POOLS */
+      } else if (strcasecmp(ua->argk[i], _("pools")) == 0) {
+        db_list_pool_records(ua->db, prtit, ua);
+
+      /* List MEDIA */
+      } else if (strcasecmp(ua->argk[i], _("media")) == 0) {
+        int done = FALSE;
+        for (j=i+1; j<ua->argc; j++) {
+            if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
+              strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
+              jr.Job[MAX_NAME_LENGTH-1] = 0;
+              jr.JobId = 0;
+              db_get_job_record(ua->db, &jr);
+              jobid = jr.JobId;
+            } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
+              jobid = atoi(ua->argv[j]);
+           } else {
+              continue;
+           }
+           VolumeName = (char *) get_pool_memory(PM_FNAME);
+           n = db_get_job_volume_names(ua->db, jobid, VolumeName);
+            bsendmsg(ua, _("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName);
+           free_memory(VolumeName);
+           done = TRUE;
+        }
+        /* if no job or jobid keyword found, then we list all media */
+        if (!done) {
+           if (!get_pool_dbr(ua, &pr)) {
+              return 1;
+           }
+           mr.PoolId = pr.PoolId;
+           db_list_media_records(ua->db, &mr, prtit, ua);
+        }
+      } else {
+         bsendmsg(ua, _("Unknown list keyword: %s\n"), ua->argk[i]);
+      }
+   }
+   return 1;
+}
+
+void do_messages(UAContext *ua, char *cmd)
+{
+   char msg[2000];
+   int mlen; 
+
+   fcntl(fileno(con_fd), F_SETLKW);
+   rewind(con_fd);
+   while (fgets(msg, sizeof(msg), con_fd)) {
+      mlen = strlen(msg);
+      ua->UA_sock->msg = (char *) check_pool_memory_size(
+        ua->UA_sock->msg, mlen+1);
+      strcpy(ua->UA_sock->msg, msg);
+      ua->UA_sock->msglen = mlen;
+      bnet_send(ua->UA_sock);
+   }
+   ftruncate(fileno(con_fd), 0L);
+   console_msg_pending = FALSE;
+   fcntl(fileno(con_fd), F_UNLCK);
+   ua->user_notified_msg_pending = FALSE;
+}
+
+
+int qmessagescmd(UAContext *ua, char *cmd)
+{
+   if (console_msg_pending && ua->auto_display_messages) {
+      do_messages(ua, cmd);
+   }
+   return 1;
+}
+
+int messagescmd(UAContext *ua, char *cmd)
+{
+   if (console_msg_pending) {
+      do_messages(ua, cmd);
+   } else {
+      bnet_fsend(ua->UA_sock, _("You have no messages.\n"));
+   }
+   return 1;
+}
diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c
new file mode 100644 (file)
index 0000000..8a5c90b
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ *
+ *   Bacula Director -- Run Command
+ *
+ *     Kern Sibbald, December MMI
+ */
+
+/*
+   Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+#include "ua.h"
+
+/* Imported subroutines */
+extern void run_job(JCR *jcr);
+
+/* Imported variables */
+extern struct s_jl joblevels[];
+
+/*
+ * For Backup and Verify Jobs
+ *     run [job=]<job-name> level=<level-name>
+ *
+ * For Restore Jobs
+ *     run <job-name> jobid=nn
+ *
+ */
+int runcmd(UAContext *ua, char *cmd)
+{
+   JOB *job;
+   JCR *jcr;
+   char *job_name, *level_name, *jid, *store_name;
+   char *where, *fileset_name, *client_name;
+   int i, j, found;
+   STORE *store;
+   CLIENT *client;
+   FILESET *fileset;
+   static char *kw[] = {
+      N_("job"),
+      N_("jobid"),
+      N_("client"),
+      N_("fileset"),
+      N_("level"),
+      N_("storage"),
+      N_("where"),
+      NULL};
+
+   if (!open_db(ua)) {
+      return 1;
+   }
+
+   job_name = NULL;
+   level_name = NULL;
+   jid = NULL;
+   store_name = NULL;
+   where = NULL;
+   client_name = NULL;
+   fileset_name = NULL;
+
+   Dmsg1(20, "run: %s\n", ua->UA_sock->msg);
+
+   for (i=1; i<ua->argc; i++) {
+      found = False;
+      Dmsg2(200, "Doing arg %d = %s\n", i, ua->argk[i]);
+      for (j=0; kw[j]; j++) {
+        if (strcasecmp(ua->argk[i], _(kw[j])) == 0) {
+           if (!ua->argv[i]) {
+               bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]);
+              return 1;
+           }
+            Dmsg1(200, "Got keyword=%s\n", kw[j]);
+           switch (j) {
+              case 0: /* job */
+                 if (job_name) {
+                     bsendmsg(ua, _("Job name specified twice.\n"));
+                    return 1;
+                 }
+                 job_name = ua->argv[i];
+                 found = True;
+                 break;
+              case 1: /* JobId */
+                 if (jid) {
+                     bsendmsg(ua, _("JobId specified twice.\n"));
+                    return 1;
+                 }
+                 jid = ua->argv[i];
+                 found = True;
+                 break;
+              case 2: /* client */
+                 if (client_name) {
+                     bsendmsg(ua, _("Client specified twice.\n"));
+                    return 1;
+                 }
+                 client_name = ua->argv[i];
+                 found = True;
+                 break;
+              case 3: /* fileset */
+                 if (fileset_name) {
+                     bsendmsg(ua, _("FileSet specified twice.\n"));
+                    return 1;
+                 }
+                 fileset_name = ua->argv[i];
+                 found = True;
+                 break;
+              case 4: /* level */
+                 if (level_name) {
+                     bsendmsg(ua, _("Level specified twice.\n"));
+                    return 1;
+                 }
+                 level_name = ua->argv[i];
+                 found = True;
+                 break;
+              case 5: /* storage */
+                 if (store_name) {
+                     bsendmsg(ua, _("Storage specified twice.\n"));
+                    return 1;
+                 }
+                 store_name = ua->argv[i];
+                 found = True;
+                 break;
+              case 6: /* where */
+                 if (where) {
+                     bsendmsg(ua, _("Where specified twice.\n"));
+                    return 1;
+                 }
+                 where = ua->argv[i];
+                 break;
+                 found = True;
+              default:
+                 break;
+           }
+        }
+      } /* end keyword loop */
+      if (!found) {
+         Dmsg1(200, "%s not found\n", ua->argk[i]);
+        /*
+         * Special case for Job Name, it can be the first
+         * keyword that has no value.
+         */
+        if (!job_name && !ua->argv[i]) {
+           job_name = ua->argk[i];   /* use keyword as job name */
+            Dmsg1(200, "Set jobname=%s\n", job_name);
+        } else {
+            bsendmsg(ua, _("Invalid keyword %s\n"), ua->argk[i]);
+           return 1;
+        }
+      }
+   } /* end argc loop */
+            
+   Dmsg0(20, "Done scan.\n");
+   if (job_name) {
+      /* Find Job */
+      job = (JOB *)GetResWithName(R_JOB, job_name);
+      if (!job) {
+         bsendmsg(ua, _("Job %s: not found\n"), job_name);
+        job = select_job_resource(ua);
+      } else {
+         Dmsg1(20, "Found job=%s\n", job_name);
+      }
+   } else {
+      bsendmsg(ua, _("A job name must be specified.\n"));
+      job = select_job_resource(ua);
+   }
+   if (!job) {
+      return 1;
+   }
+
+   if (store_name) {
+      store = (STORE *)GetResWithName(R_STORAGE, store_name);
+      if (!store) {
+         bsendmsg(ua, _("Storage %s not found.\n"), store_name);
+        store = select_storage_resource(ua);
+      }
+   } else {
+      store = job->storage;          /* use default */
+   }
+   if (!store) {
+      return 1;
+   }
+
+   jcr = new_jcr(sizeof(JCR), dird_free_jcr);
+   set_jcr_defaults(jcr, job);
+   jcr->store = store;               /* set possible new Storage */
+
+try_again:
+   Dmsg1(20, "JobType=%c\n", jcr->JobType);
+   switch (jcr->JobType) {
+      case JT_BACKUP:
+      case JT_VERIFY:
+        if (level_name) {
+           /* Look up level name and pull code */
+           lcase(level_name);
+           found = 0;
+           for (i=0; joblevels[i].level_name; i++) {
+              if (strcasecmp(level_name, _(joblevels[i].level_name)) == 0) {
+                 jcr->level = joblevels[i].level;
+                 found = 1;
+                 break;
+              }
+           }
+           if (!found) { 
+               bsendmsg(ua, _("Level %s not valid.\n"), level_name);
+              free_jcr(jcr);
+              return 1;
+           }
+        }
+        level_name = NULL;
+         bsendmsg(ua, _("Run %s job\n\
+JobName:  %s\n\
+FileSet:  %s\n\
+Level:    %s\n\
+Client:   %s\n\
+Storage:  %s\n"),
+                 jcr->JobType==JT_BACKUP?_("Backup"):_("Verify"),
+                job->hdr.name,
+                jcr->fileset->hdr.name,
+                level_to_str(jcr->level),
+                jcr->client->hdr.name,
+                jcr->store->hdr.name);
+        break;
+      case JT_RESTORE:
+        if (jcr->RestoreJobId == 0) {
+           if (jid) {
+              jcr->RestoreJobId = atoi(jid);
+           } else {
+               if (!get_cmd(ua, _("Please enter a JobId for restore: "))) {
+                 free_jcr(jcr);
+                 return 1;
+              }  
+              jcr->RestoreJobId = atoi(ua->cmd);
+           }
+        }
+         jcr->level = 'F';            /* ***FIXME*** */
+         Dmsg1(20, "JobId to restore=%d\n", jcr->RestoreJobId);
+         bsendmsg(ua, _("Run Restore job\n\
+JobName:    %s\n\
+Where:      %s\n\
+RestoreId:  %d\n\
+Level:      %s\n\
+FileSet:    %s\n\
+Client:     %s\n\
+Storage:    %s\n"),
+                job->hdr.name,
+                jcr->RestoreWhere?jcr->RestoreWhere:job->RestoreWhere,
+                jcr->RestoreJobId,
+                level_to_str(jcr->level),
+                jcr->fileset->hdr.name,
+                jcr->client->hdr.name,
+                jcr->store->hdr.name);
+        break;
+      default:
+         bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
+        free_jcr(jcr);
+        return 1;
+   }
+   if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
+      free_jcr(jcr);
+      return 1;
+   }
+   if (strcasecmp(ua->cmd, _("mod")) == 0) {
+      start_prompt(ua, _("Parameters to modify:\n"));
+      add_prompt(ua, _("Job"));
+      add_prompt(ua, _("Level"));
+      add_prompt(ua, _("FileSet"));
+      add_prompt(ua, _("Client"));
+      add_prompt(ua, _("Storage"));
+      if (jcr->JobType == JT_RESTORE) {
+         add_prompt(ua, _("Where"));
+         add_prompt(ua, _("JobId"));
+      }
+      switch (do_prompt(ua, _("Select parameter to modify"), NULL)) {
+      case 0:
+        /* Job */
+        job = select_job_resource(ua);
+        if (job) {
+           jcr->job = job;
+           set_jcr_defaults(jcr, job);
+           goto try_again;
+        }
+        break;
+      case 1:
+        /* Level */
+        if (jcr->JobType == JT_BACKUP) {
+            start_prompt(ua, _("Levels:\n"));
+            add_prompt(ua, _("Full"));
+            add_prompt(ua, _("Incremental"));
+            add_prompt(ua, _("Differential"));
+            add_prompt(ua, _("Level"));
+            add_prompt(ua, _("Since"));
+            switch (do_prompt(ua, _("Select level"), NULL)) {
+           case 0:
+              jcr->level = L_FULL;
+              break;
+           case 1:
+              jcr->level = L_INCREMENTAL;
+              break;
+           case 2:
+              jcr->level = L_DIFFERENTIAL;
+              break;
+           case 3:
+              jcr->level = L_LEVEL;
+              break;
+           case 4:
+              jcr->level = L_SINCE;
+              break;
+           default:
+              break;
+           }
+           goto try_again;
+        } else if (jcr->JobType == JT_VERIFY) {
+            start_prompt(ua, _("Levels:\n"));
+            add_prompt(ua, _("Verify from Catalog"));
+            add_prompt(ua, _("Initialize Catalog"));
+            add_prompt(ua, _("Verify Volume"));
+            add_prompt(ua, _("Verify Volume Data"));
+            switch (do_prompt(ua, _("Select level"), NULL)) {
+           case 0:
+              jcr->level = L_VERIFY_CATALOG;
+              break;
+           case 1:
+              jcr->level = L_VERIFY_INIT;
+              break;
+           case 2:
+              jcr->level = L_VERIFY_VOLUME;
+              break;
+           case 3:
+              jcr->level = L_VERIFY_DATA;
+              break;
+           default:
+              break;
+           }
+           goto try_again;
+        }
+        goto try_again;
+      case 2:
+        /* FileSet */
+        fileset = select_fs_resource(ua);
+        if (fileset) {
+           jcr->fileset = fileset;
+           goto try_again;
+        }      
+        break;
+      case 3:
+        client = select_client_resource(ua);
+        if (client) {
+           jcr->client = client;
+           goto try_again;
+        }
+        break;
+      case 4:
+        store = select_storage_resource(ua);
+        if (store) {
+           jcr->store = store;
+           goto try_again;
+        }
+        break;
+      case 5:
+        /* Where */
+         if (!get_cmd(ua, _("Please enter path prefix (where) for restore: "))) {
+           break;
+        }
+         if (ua->cmd[0] != '/') {
+            bsendmsg(ua, _("Prefix must begin with a /\n"));
+        } else {
+           if (jcr->RestoreWhere) {
+              free(jcr->RestoreWhere);
+           }
+           jcr->RestoreWhere = bstrdup(ua->cmd);
+        }  
+        goto try_again;
+      case 6:
+        /* JobId */
+        jid = NULL;                  /* force reprompt */
+        jcr->RestoreJobId = 0;
+        goto try_again;
+      default: 
+        goto try_again;
+      }
+      bsendmsg(ua, _("Job not run.\n"));
+      free_jcr(jcr);
+      return 1;
+   }
+   if (strcasecmp(ua->cmd, _("yes")) != 0) {
+      bsendmsg(ua, _("Job not run.\n"));
+      free_jcr(jcr);
+      return 1;
+   }
+
+   Dmsg1(200, "Calling run_job job=%x\n", jcr->job);
+   run_job(jcr);
+   return 1;
+}
diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c
new file mode 100644 (file)
index 0000000..d0ac1a4
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ *
+ *   Bacula Director -- User Agent Prompt and Selection code
+ *
+ *     Kern Sibbald, October MMI
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+#include "ua.h"
+
+
+/* Imported variables */
+
+
+/* Exported functions */
+
+int do_prompt(UAContext *ua, char *msg, char *prompt);
+void add_prompt(UAContext *ua, char *prompt);
+void start_prompt(UAContext *ua, char *msg);
+STORE *select_storage_resource(UAContext *ua);
+JOB *select_job_resource(UAContext *ua);
+
+/* 
+ * Given a list of keywords, find the first one
+ *  that is in the argument list.
+ * Returns: -1 if not found
+ *         index into list (base 0) on success
+ */
+int find_arg_keyword(UAContext *ua, char **list)
+{
+   int i, j;
+   for (i=1; i<ua->argc; i++) {
+      for(j=0; list[j]; j++) {
+        if (strcasecmp(_(list[j]), ua->argk[i]) == 0) {
+           return j;
+        }
+      }
+   }
+   return -1;
+}
+
+/* 
+ * Given a list of keywords, prompt the user 
+ * to choose one.
+ *
+ * Returns: -1 on failure
+ *         index into list (base 0) on success
+ */
+int do_keyword_prompt(UAContext *ua, char *msg, char **list)
+{
+   int i;
+   start_prompt(ua, _("You have the following choices:\n"));
+   for (i=0; list[i]; i++) {
+      add_prompt(ua, list[i]);
+   }
+   return do_prompt(ua, msg, NULL);
+}
+
+
+/* 
+ * Select a Storage resource from prompt list
+ */
+STORE *select_storage_resource(UAContext *ua)
+{
+   char name[MAX_NAME_LENGTH];   
+   STORE *store = NULL;
+
+   start_prompt(ua, _("The defined Storage resources are:\n"));
+   LockRes();
+   while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
+      add_prompt(ua, store->hdr.name);
+   }
+   UnlockRes();
+   do_prompt(ua, _("Select Storage resource"), name);
+   store = (STORE *)GetResWithName(R_STORAGE, name);
+   return store;
+}
+
+/* 
+ * Select a FileSet resource from prompt list
+ */
+FILESET *select_fs_resource(UAContext *ua)
+{
+   char name[MAX_NAME_LENGTH];   
+   FILESET *fs = NULL;
+
+   start_prompt(ua, _("The defined FileSet resources are:\n"));
+   LockRes();
+   while ((fs = (FILESET *)GetNextRes(R_FILESET, (RES *)fs))) {
+      add_prompt(ua, fs->hdr.name);
+   }
+   UnlockRes();
+   do_prompt(ua, _("Select FileSet resource"), name);
+   fs = (FILESET *)GetResWithName(R_FILESET, name);
+   return fs;
+}
+
+
+/* 
+ * Get a catalog resource from prompt list
+ */
+CAT *get_catalog_resource(UAContext *ua)
+{
+   char name[MAX_NAME_LENGTH];   
+   CAT *catalog = NULL;
+   int i;
+
+   for (i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], _("catalog")) == 0 && ua->argv[i]) {
+        catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
+        break;
+      }
+   }
+   if (!catalog) {
+      start_prompt(ua, _("The defined Catalog resources are:\n"));
+      LockRes();
+      while ((catalog = (CAT *)GetNextRes(R_CATALOG, (RES *)catalog))) {
+        add_prompt(ua, catalog->hdr.name);
+      }
+      UnlockRes();
+      do_prompt(ua, _("Select Catalog resource"), name);
+      catalog = (CAT *)GetResWithName(R_CATALOG, name);
+   }
+   return catalog;
+}
+
+
+/* 
+ * Select a Job resource from prompt list
+ */
+JOB *select_job_resource(UAContext *ua)
+{
+   char name[MAX_NAME_LENGTH];   
+   JOB *job = NULL;
+
+   start_prompt(ua, _("The defined Job resources are:\n"));
+   LockRes();
+   while ( (job = (JOB *)GetNextRes(R_JOB, (RES *)job)) ) {
+      add_prompt(ua, job->hdr.name);
+   }
+   UnlockRes();
+   do_prompt(ua, _("Select Job resource"), name);
+   job = (JOB *)GetResWithName(R_JOB, name);
+   return job;
+}
+
+
+/* 
+ * Select a client resource from prompt list
+ */
+CLIENT *select_client_resource(UAContext *ua)
+{
+   char name[MAX_NAME_LENGTH];   
+   CLIENT *client = NULL;
+
+   start_prompt(ua, _("The defined Client resources are:\n"));
+   LockRes();
+   while ( (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)) ) {
+      add_prompt(ua, client->hdr.name);
+   }
+   UnlockRes();
+   do_prompt(ua, _("Select Client (File daemon) resource"), name);
+   client = (CLIENT *)GetResWithName(R_CLIENT, name);
+   return client;
+}
+
+/*
+ *  Get client resource, start by looking for
+ *   client=<client-name>
+ *  if we don't find the keyword, we prompt the user.
+ */
+CLIENT *get_client_resource(UAContext *ua)
+{
+   CLIENT *client = NULL;
+   int i;
+   
+   for (i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], _("client")) == 0 && ua->argv[i]) {
+        client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
+        if (client) {
+           return client;
+        }
+         bsendmsg(ua, _("Error: Client resource %s does not exist.\n"), ua->argv[i]);
+        break;
+      }
+   }
+   return select_client_resource(ua);
+}
+
+
+
+
+/* Scan what the user has entered looking for:
+ * 
+ *  pool=<pool-name>   
+ *
+ *  if error or not found, put up a list of pool DBRs
+ *  to choose from.
+ *
+ *   returns: 0 on error
+ *           poolid on success and fills in POOL_DBR
+ */
+int get_pool_dbr(UAContext *ua, POOL_DBR *pr)
+{
+   int i;
+
+   for (i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], _("pool")) == 0 && ua->argv[i]) {
+        strcpy(pr->Name, ua->argv[i]);
+        if (!db_get_pool_record(ua->db, pr)) {
+            bsendmsg(ua, _("Could not find Pool %s: ERR=%s"), ua->argv[i],
+                    db_strerror(ua->db));
+           pr->PoolId = 0;
+           break;
+        }
+        return pr->PoolId;
+      }
+   }
+   if (!select_pool_dbr(ua, pr)) {  /* try once more */
+      return 0;
+   }
+   return pr->PoolId;
+}
+
+/*
+ * Select a Pool record from the catalog
+ */
+int select_pool_dbr(UAContext *ua, POOL_DBR *pr)
+{
+   POOL_DBR opr;
+   char name[MAX_NAME_LENGTH];
+   int num_pools, i;
+   uint32_t *ids; 
+
+
+   pr->PoolId = 0;
+   if (!db_get_pool_ids(ua->db, &num_pools, &ids)) {
+      bsendmsg(ua, _("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
+      return 0;
+   }
+   if (num_pools <= 0) {
+      bsendmsg(ua, _("No pools defined.\n"));
+      return 0;
+   }
+     
+   start_prompt(ua, _("Defined Pools:\n"));
+   for (i=0; i < num_pools; i++) {
+      opr.PoolId = ids[i];
+      if (!db_get_pool_record(ua->db, &opr)) {
+        continue;
+      }
+      add_prompt(ua, opr.Name);
+   }
+   free(ids);
+   if (do_prompt(ua, _("Select the Pool"), name) < 0) {
+      return 0;
+   }
+   memset(&opr, 0, sizeof(pr));
+   strcpy(opr.Name, name);
+
+   if (!db_get_pool_record(ua->db, &opr)) {
+      bsendmsg(ua, _("Could not find Pool %s: ERR=%s"), name, db_strerror(ua->db));
+      return 0;
+   }
+   memcpy(pr, &opr, sizeof(opr));
+   return opr.PoolId;
+}
+
+
+/*
+ *  This routine is ONLY used in the create command.
+ *  If you are thinking about using it, you
+ *  probably want to use select_pool_dbr() 
+ *  or get_pool_dbr() above.
+ */
+POOL *get_pool_resource(UAContext *ua)
+{
+   POOL *pool = NULL;
+   char name[MAX_NAME_LENGTH];
+   int i;
+   
+   for (i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], _("pool")) == 0 && ua->argv[i]) {
+        pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
+        if (pool) {
+           return pool;
+        }
+         bsendmsg(ua, _("Error: Pool resource %s does not exist.\n"), ua->argv[i]);
+        break;
+      }
+   }
+   start_prompt(ua, _("The defined Pool resources are:\n"));
+   LockRes();
+   while ((pool = (POOL *)GetNextRes(R_POOL, (RES *)pool))) {
+      add_prompt(ua, pool->hdr.name);
+   }
+   UnlockRes();
+   do_prompt(ua, _("Select Pool resource"), name);
+   pool = (POOL *)GetResWithName(R_POOL, name);
+   return pool;
+}
+
+
+
+
+/*
+ * Implement unique set of prompts 
+ */
+void start_prompt(UAContext *ua, char *msg)
+{
+  if (ua->max_prompts == 0) {
+     ua->max_prompts = 10;
+     ua->prompt = (char **) bmalloc(sizeof(char *) * ua->max_prompts);
+  }
+  ua->num_prompts = 1;
+  ua->prompt[0] = bstrdup(msg);
+}
+
+/*
+ * Add to prompts -- keeping them unique 
+ */
+void add_prompt(UAContext *ua, char *prompt)
+{
+   int i;
+   if (ua->num_prompts == ua->max_prompts) {
+      ua->max_prompts *= 2;
+      ua->prompt = (char **) brealloc(ua->prompt, sizeof(char *) *
+        ua->max_prompts);
+    }
+    for (i=1; i < ua->num_prompts; i++) {
+       if (strcmp(ua->prompt[i], prompt) == 0) {
+         return;
+       }
+    }
+    ua->prompt[ua->num_prompts++] = bstrdup(prompt);
+}
+
+/*
+ * Display prompts and get user's choice
+ *
+ *  Returns: -1 on error
+ *           index base 0 on success, and choice
+ *              is copied to prompt if not NULL
+ */
+int do_prompt(UAContext *ua, char *msg, char *prompt)
+{
+   int i, item;
+   char pmsg[MAXSTRING];
+
+   bsendmsg(ua, ua->prompt[0]);
+   for (i=1; i < ua->num_prompts; i++) {
+      bsendmsg(ua, "%6d: %s\n", i, ua->prompt[i]);
+   }
+
+   if (prompt) {
+      *prompt = 0;
+   }
+
+   for ( ;; ) {
+      if (ua->num_prompts == 2) {
+        item = 1;
+         bsendmsg(ua, _("Item 1 selected automatically.\n"));
+        if (prompt) {
+           strcpy(prompt, ua->prompt[1]);
+        }
+        break;
+      } else {
+         sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
+      }
+      if (!get_cmd(ua, pmsg) || *ua->cmd == '.') {
+        item = -1;                   /* error */
+        break;
+      }
+      item = atoi(ua->cmd);
+      if (item < 1 || item >= ua->num_prompts) {
+         bsendmsg(ua, _("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
+        continue;
+      }
+      if (prompt) {
+        strcpy(prompt, ua->prompt[item]);
+      }
+      break;
+   }
+                             
+   for (i=0; i < ua->num_prompts; i++) {
+      free(ua->prompt[i]);
+   }
+   ua->num_prompts = 0;
+   return item - 1;
+}
+
+
+/*
+ * We scan what the user has entered looking for
+ *    <storage-resource>
+ *    device=<device-name>     ???? does this work ????
+ *    storage=<storage-resource>
+ *    job=<job_name>
+ *    jobid=<jobid>
+ *    ?             (prompt him with storage list)
+ *    <some-error>   (prompt him with storage list)
+ */
+STORE *get_storage_resource(UAContext *ua, char *cmd)
+{
+   char *store_name, *device_name;
+   STORE *store;
+   int jobid;
+   JCR *jcr;
+   int i;
+      
+   if (ua->argc == 1) {
+      return select_storage_resource(ua);
+   }
+   
+   device_name = NULL;
+   store_name = NULL;
+
+   for (i=1; i<ua->argc; i++) {
+      if (!ua->argv[i]) {
+        /* Default argument is storage */
+        if (store_name) {
+            bsendmsg(ua, _("Storage name given twice.\n"));
+           return NULL;
+        }
+        store_name = ua->argk[i];
+         if (*store_name == '?') {
+           return select_storage_resource(ua);
+        }
+      } else {
+         if (strcasecmp(ua->argk[i], _("device")) == 0) {
+           device_name = ua->argv[i];
+
+         } else if (strcasecmp(ua->argk[i], _("storage")) == 0) {
+           store_name = ua->argv[i];
+
+         } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
+           jobid = atoi(ua->argv[i]);
+           if (jobid <= 0) {
+               bsendmsg(ua, _("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
+              return NULL;
+           }
+           if (!(jcr=get_jcr_by_id(jobid))) {
+               bsendmsg(ua, _("JobId %d is not running.\n"), jobid);
+              return NULL;
+           }
+           store = jcr->store;
+           free_jcr(jcr);
+           return store;
+
+         } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
+           if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
+               bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
+              return NULL;
+           }
+           store = jcr->store;
+           free_jcr(jcr);
+           return store;
+
+        } else {
+            bsendmsg(ua, _("Unknown keyword: %s\n"), ua->argk[i]);
+           return NULL;
+        }
+      }
+   }
+
+   if (!store_name) {
+     bsendmsg(ua, _("A storage device name must be given.\n"));
+     store = NULL;
+   } else {
+      store = (STORE *)GetResWithName(R_STORAGE, store_name);
+      if (!store) {
+         bsendmsg(ua, "Storage resource %s: not found\n", store_name);
+      }
+   }
+   if (!store) {
+      store = select_storage_resource(ua);
+   }
+   return store;
+}
+
+
+/*
+ * Scan looking for mediatype= 
+ *
+ *  if not found or error, put up selection list
+ *
+ *  Returns: 0 on error
+ *          1 on success, MediaType is set
+ */
+int get_media_type(UAContext *ua, char *MediaType)
+{
+   STORE *store;
+   int i;
+   static char *keyword[] = {
+      "mediatype",
+      NULL};
+
+   i = find_arg_keyword(ua, keyword);
+   if (i >= 0 && ua->argv[i]) {
+      strcpy(MediaType, ua->argv[i]);
+      return 1;
+   }
+
+   start_prompt(ua, _("Media Types defined in conf file:\n"));
+   LockRes();
+   for (store = NULL; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); ) {
+      add_prompt(ua, store->media_type);
+   }
+   UnlockRes();
+   return (do_prompt(ua, _("Select the Media Type"), MediaType) < 0) ? 0 : 1;
+}
diff --git a/bacula/src/dird/ua_server.c b/bacula/src/dird/ua_server.c
new file mode 100644 (file)
index 0000000..1ce7260
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ *
+ *   Bacula Director -- User Agent Server
+ *
+ *     Kern Sibbald, September MM
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+#include "ua.h"
+
+/* Imported subroutines */
+extern void run_job(JCR *jcr);
+
+/* Imported variables */
+extern struct s_jl joblevels[];
+extern int r_first;
+extern int r_last;
+extern struct s_res resources[];
+extern int console_msg_pending;
+extern FILE *con_fd;
+extern char my_name[];
+
+/* Static variables */
+
+/* Exported variables */
+int quit_cmd_thread = 0;
+
+/* Imported functions */
+
+/* Forward referenced functions */
+
+static void *connect_thread(void *arg);
+static void handle_UA_client_request(void *arg);
+
+
+/* Global variables */
+static int started = FALSE;
+static workq_t ua_workq;
+
+/* Called here by Director daemon to start UA (user agent)
+ * command thread. This routine creates the thread and then
+ * returns.
+ */
+void start_UA_server(int UA_port)
+{
+   pthread_t thid;
+   int status;
+
+   set_thread_concurrency(4);
+   if ((status=pthread_create(&thid, NULL, connect_thread, (void *)UA_port)) != 0) {
+      Emsg1(M_ABORT, 0, _("Cannot create UA thread: %s\n"), strerror(status));
+   }
+   started = TRUE;
+   return;
+}
+
+static void *connect_thread(void *arg)
+{
+   int UA_port = (int)arg;
+
+   pthread_detach(pthread_self());
+
+   bnet_thread_server(UA_port, 5, &ua_workq, handle_UA_client_request);
+   return NULL;
+}
+
+/*
+ * Handle Director User Agent commands  
+ *
+ */
+static void handle_UA_client_request(void *arg)
+{
+   int quit, stat;
+   static char cmd[1000];
+   UAContext ua;
+   BSOCK *UA_sock = (BSOCK *) arg;
+
+   pthread_detach(pthread_self());
+
+   memset(&ua, 0, sizeof(ua));
+   ua.automount = TRUE;
+   ua.jcr = new_jcr(sizeof(JCR), dird_free_jcr);
+   close_msg(ua.jcr);                 /* we don't handle messages */
+   ua.jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */
+   ua.UA_sock = UA_sock;
+   ua.cmd = (char *) get_pool_memory(PM_FNAME);
+   ua.args = (char *) get_pool_memory(PM_FNAME);
+
+   create_unique_job_name(ua.jcr, "*Console*");
+   ua.jcr->sched_time = ua.jcr->start_time;
+   ua.jcr->JobType = JT_CONSOLE;
+
+   bnet_recv(ua.UA_sock);         /* Get first message */
+   if (!authenticate_user_agent(ua.UA_sock)) {
+      goto getout;
+   }
+
+   quit = FALSE;
+   while (!quit) {
+      stat = bnet_recv(ua.UA_sock);
+      if (stat > 0) {
+        strncpy(cmd, ua.UA_sock->msg, sizeof(cmd));
+        cmd[sizeof(cmd)-1] = 0;       /* ensure it is terminated/trucated */
+        parse_command_args(&ua);
+         if (ua.argc > 0 && ua.argk[0][0] == '.') {
+           quit = !do_a_dot_command(&ua, cmd);
+        } else {
+           quit = !do_a_command(&ua, cmd);
+        }
+        if (!quit) {
+           if (ua.auto_display_messages) {
+               strcpy(cmd, "messages");
+              qmessagescmd(&ua, cmd);
+              ua.user_notified_msg_pending = FALSE;
+           } else if (!ua.user_notified_msg_pending && console_msg_pending) {
+               bsendmsg(&ua, _("You have messages.\n"));
+              ua.user_notified_msg_pending = TRUE;
+           }
+           bnet_sig(ua.UA_sock, BNET_EOD); /* send end of command */
+        }
+      } else if (stat == 0) {
+        if (ua.UA_sock->msglen == BNET_TERMINATE) {
+           break;
+        }
+        bnet_sig(ua.UA_sock, BNET_POLL);
+      } else {
+        break;                    /* error, exit */
+      }
+   }
+
+getout:
+   if (ua.UA_sock) {
+      bnet_close(ua.UA_sock);
+      ua.UA_sock = NULL;
+   }
+
+   if (ua.jcr) {
+      free_jcr(ua.jcr);
+      ua.jcr = NULL;
+   }
+   close_db(&ua);
+   if (ua.prompt) {
+      free(ua.prompt);
+   }
+   if (ua.cmd) {
+      free_pool_memory(ua.cmd);
+   }
+   if (ua.args) {
+      free_pool_memory(ua.args);
+   }
+   return;
+}
+
+/*
+ * Called from main Bacula thread 
+ */
+void term_ua_server()
+{
+   if (!started) {
+      return;
+   }
+   quit_cmd_thread = TRUE;
+}
diff --git a/bacula/src/dird/ua_status.c b/bacula/src/dird/ua_status.c
new file mode 100644 (file)
index 0000000..a05ee54
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ *
+ *   Bacula Director -- User Agent Status Command
+ *
+ *     Kern Sibbald, August MMI
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+#include "ua.h"
+
+extern char my_name[];
+extern time_t daemon_start_time;
+extern struct s_last_job last_job;
+
+static void print_jobs_scheduled(UAContext *ua);
+static void do_storage_status(UAContext *ua, STORE *store);
+static void do_client_status(UAContext *ua, CLIENT *client);
+static void do_director_status(UAContext *ua, char *cmd);
+static void do_all_status(UAContext *ua, char *cmd);
+
+/*
+ * status command
+ */
+int statuscmd(UAContext *ua, char *cmd)
+{
+   STORE *store;
+   CLIENT *client;
+   int item, i;
+
+   if (!open_db(ua)) {
+      return 1;
+   }
+   Dmsg1(20, "status:%s:\n", cmd);
+
+   for (i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], _("all")) == 0) {
+        do_all_status(ua, cmd);
+        return 1;
+      } else if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
+                 strcasecmp(ua->argk[i], _("director")) == 0) {
+        do_director_status(ua, cmd);
+        return 1;
+      } else if (strcasecmp(ua->argk[i], _("client")) == 0) {
+        client = get_client_resource(ua);
+        if (client) {
+           do_client_status(ua, client);
+        }
+        return 1;
+      } else {
+        store = get_storage_resource(ua, cmd);
+        if (store) {
+           do_storage_status(ua, store);
+        }
+        return 1;
+      }
+   }
+   /* If no args, ask for status type */
+   if (ua->argc == 1) {                                   
+      start_prompt(ua, _("Status available for:\n"));
+      add_prompt(ua, _("Director"));
+      add_prompt(ua, _("Storage"));
+      add_prompt(ua, _("Client"));
+      add_prompt(ua, _("All"));
+      Dmsg0(20, "do_prompt: select daemon\n");
+      if ((item=do_prompt(ua, _("Select daemon type for status"), cmd)) < 0) {
+        return 1;
+      }
+      Dmsg1(20, "item=%d\n", item);
+      switch (item) { 
+      case 0:                        /* Director */
+        do_director_status(ua, cmd);
+        break;
+      case 1:
+        store = select_storage_resource(ua);
+        if (store) {
+           do_storage_status(ua, store);
+        }
+        break;
+      case 2:
+        client = select_client_resource(ua);
+        if (client) {
+           do_client_status(ua, client);
+        }
+        break;
+      case 3:
+        do_all_status(ua, cmd);
+        break;
+      default:
+        break;
+      }
+   }
+   return 1;
+}
+
+static void do_all_status(UAContext *ua, char *cmd)
+{
+   STORE *store, **unique_store;
+   CLIENT *client, **unique_client;
+   int i, j, found;
+
+   do_director_status(ua, cmd);
+
+   /* Count Storage items */
+   LockRes();
+   store = NULL;
+   for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
+      { }
+   unique_store = (STORE **) malloc(i * sizeof(STORE));
+   /* Find Unique Storage address/port */        
+   store = (STORE *)GetNextRes(R_STORAGE, NULL);
+   i = 0;
+   unique_store[i++] = store;
+   while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
+      found = 0;
+      for (j=0; j<i; j++) {
+        if (strcmp(unique_store[j]->address, store->address) == 0 &&
+            unique_store[j]->SDport == store->SDport) {
+           found = 1;
+           break;
+        }
+      }
+      if (!found) {
+        unique_store[i++] = store;
+         Dmsg2(40, "Stuffing: %s:%d\n", store->address, store->SDport);
+      }
+   }
+   UnlockRes();
+
+   /* Call each unique Storage daemon */
+   for (j=0; j<i; j++) {
+      do_storage_status(ua, unique_store[j]);
+   }
+   free(unique_store);
+
+   /* Count Client items */
+   LockRes();
+   client = NULL;
+   for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
+      { }
+   unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
+   /* Find Unique Client address/port */        
+   client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
+   i = 0;
+   unique_client[i++] = client;
+   while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
+      found = 0;
+      for (j=0; j<i; j++) {
+        if (strcmp(unique_client[j]->address, client->address) == 0 &&
+            unique_client[j]->FDport == client->FDport) {
+           found = 1;
+           break;
+        }
+      }
+      if (!found) {
+        unique_client[i++] = client;
+         Dmsg2(40, "Stuffing: %s:%d\n", client->address, client->FDport);
+      }
+   }
+   UnlockRes();
+
+   /* Call each unique File daemon */
+   for (j=0; j<i; j++) {
+      do_client_status(ua, unique_client[j]);
+   }
+   free(unique_client);
+   
+}
+
+static void do_director_status(UAContext *ua, char *cmd)
+{
+   JCR *jcr;
+   int njobs = 0;
+   char *msg;
+   char dt[MAX_TIME_LENGTH], b1[30], b2[30];
+   int pool_mem = FALSE;
+
+   Dmsg0(200, "Doing status\n");
+   bsendmsg(ua, "%s Version: " VERSION " (" DATE ")\n", my_name);
+   bstrftime(dt, sizeof(dt), daemon_start_time);
+   bsendmsg(ua, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs,
+        last_job.NumJobs == 1 ? "" : "s");
+   if (last_job.NumJobs > 0) {
+      char *termstat, jstat[2];
+
+      bstrftime(dt, sizeof(dt), last_job.end_time);
+      bsendmsg(ua, _("Last Job %s finished at %s\n"), last_job.Job, dt);
+      switch (last_job.JobStatus) {
+        case JS_Terminated:
+            termstat = _("OK");
+           break;
+       case JS_ErrorTerminated:
+            termstat = _("Error");
+           break;
+       default:
+           jstat[0] = last_job.JobStatus;
+           jstat[1] = 0;
+           termstat = jstat;
+           break;
+      }
+          
+      bsendmsg(ua, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
+          edit_uint_with_commas(last_job.JobFiles, b1),
+          edit_uint_with_commas(last_job.JobBytes, b2),
+          termstat);
+   }
+   lock_jcr_chain();
+   for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
+      if (jcr->JobId == 0) {     /* this is us */
+        bstrftime(dt, sizeof(dt), jcr->start_time);
+         bsendmsg(ua, _("Console connected at %s\n"), dt);
+        free_locked_jcr(jcr);
+        njobs--;
+        continue;
+      }
+      switch (jcr->JobStatus) {
+        case JS_Created:
+            msg = _("is waiting execution");
+           break;
+        case JS_Running:
+            msg = _("is running");
+           break;
+        case JS_Blocked:
+            msg = _("is blocked");
+           break;
+        case JS_Terminated:
+            msg = _("has terminated");
+           break;
+        case JS_ErrorTerminated:
+            msg = _("has erred");
+           break;
+        case JS_Cancelled:
+            msg = _("has been canceled");
+           break;
+        case JS_WaitFD:
+           msg = (char *) get_pool_memory(PM_FNAME);
+            Mmsg(&msg, _("is waiting on Client %s"), jcr->client->hdr.name);
+           pool_mem = TRUE;
+           break;
+        case JS_WaitSD:
+           msg = (char *) get_pool_memory(PM_FNAME);
+            Mmsg(&msg, _("is waiting on Storage %s"), jcr->store->hdr.name);
+           pool_mem = TRUE;
+           break;
+        default:
+           msg = (char *) get_pool_memory(PM_FNAME);
+            Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus);
+           pool_mem = TRUE;
+           break;
+      }
+      switch (jcr->SDJobStatus) {
+        case JS_WaitMount:
+           if (pool_mem) {
+              free_pool_memory(msg);
+              pool_mem = FALSE;
+           }
+            msg = _("is waiting for a mount request");
+           break;
+        case JS_WaitMedia:
+           if (pool_mem) {
+              free_pool_memory(msg);
+              pool_mem = FALSE;
+           }
+            msg = _("is waiting for an appendable Volume");
+           break;
+        case JS_WaitFD:
+           if (!pool_mem) {
+              msg = (char *) get_pool_memory(PM_FNAME);
+              pool_mem = TRUE;
+           }
+            Mmsg(&msg, _("is waiting for Client %s to connect to Storage %s"),
+                jcr->client->hdr.name, jcr->store->hdr.name);
+           break;
+
+      }
+      bsendmsg(ua, _("JobId %d Job %s %s.\n"), jcr->JobId, jcr->Job, msg);
+      if (pool_mem) {
+        free_pool_memory(msg);
+        pool_mem = FALSE;
+      }
+      free_locked_jcr(jcr);
+   }
+   unlock_jcr_chain();
+
+   if (njobs == 0) {
+      bsendmsg(ua, _("No jobs are running.\n"));
+   }
+   print_jobs_scheduled(ua);
+   bsendmsg(ua, "====\n");
+}
+
+static void do_storage_status(UAContext *ua, STORE *store)
+{
+   BSOCK *sd;
+
+   ua->jcr->store = store;
+   /* Try connecting for up to 15 seconds */
+   bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"), 
+      store->hdr.name, store->address, store->SDport);
+   if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
+      bsendmsg(ua, _("\nFailed to connect to Storage daemon %s.\n====\n"),
+        store->hdr.name);
+      return;
+   }
+   Dmsg0(20, _("Connected to storage daemon\n"));
+   sd = ua->jcr->store_bsock;
+   bnet_fsend(sd, "status");
+   while (bnet_recv(sd) > 0) {
+      bsendmsg(ua, "%s", sd->msg);
+   }
+   bnet_sig(sd, BNET_TERMINATE);
+   bnet_close(sd);
+   ua->jcr->store_bsock = NULL;
+   return;  
+}
+   
+static void do_client_status(UAContext *ua, CLIENT *client)
+{
+   BSOCK *fd;
+
+   /* Connect to File daemon */
+
+   ua->jcr->client = client;
+   /* Try to connect for 15 seconds */
+   bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), 
+      client->hdr.name, client->address, client->FDport);
+   if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
+      bsendmsg(ua, _("Failed to connect to Client %s.\n====\n"),
+        client->hdr.name);
+      return;
+   }
+   Dmsg0(20, _("Connected to file daemon\n"));
+   fd = ua->jcr->file_bsock;
+   bnet_fsend(fd, "status");
+   while (bnet_recv(fd) > 0) {
+      bsendmsg(ua, "%s", fd->msg);
+   }
+   bnet_sig(fd, BNET_TERMINATE);
+   bnet_close(fd);
+   ua->jcr->file_bsock = NULL;
+
+   return;  
+}
+
+static void prt_runtime(UAContext *ua, JOB *job, time_t runtime)
+{
+   char dt[MAX_TIME_LENGTH], *type;
+
+   bstrftime(dt, sizeof(dt), runtime);
+   switch (job->JobType) {
+      case JT_BACKUP:
+         type = _("Backup");
+        break;
+      case JT_VERIFY:
+         type = _("Verify");
+        break;
+      case JT_RESTORE:
+         type = _("Restore");
+        break;
+      default:
+         type = _("Unknown type of");
+        break;
+   }
+   bsendmsg(ua, _("%s job \"%s\" scheduled for %s\n"), type, job->hdr.name, dt);
+}
+
+/*         
+ * Find all jobs to be run this hour
+ * and the next hour.
+ */
+static void print_jobs_scheduled(UAContext *ua)
+{
+   time_t now, runtime, tomorrow;
+   RUN *run;
+   JOB *job;
+   SCHED *sched;
+   struct tm tm;
+   int mday, wday, month, tmday, twday, tmonth, i, hour;
+   int tod, tom;
+   int found;
+
+   Dmsg0(200, "enter find_runs()\n");
+
+   now = time(NULL);
+   localtime_r(&now, &tm);
+   mday = tm.tm_mday - 1;
+   wday = tm.tm_wday;
+   month = tm.tm_mon;
+
+   tomorrow = now + 60 * 60 * 24;
+   localtime_r(&tomorrow, &tm);
+   tmday = tm.tm_mday - 1;
+   twday = tm.tm_wday;
+   tmonth = tm.tm_mon;
+
+   /* Loop through all jobs */
+   LockRes();
+   for (job=NULL; (job=(JOB *)GetNextRes(R_JOB, (RES *)job)); ) {
+      sched = job->schedule;
+      if (sched == NULL) {           /* scheduled? */
+        continue;                    /* no, skip this job */
+      }
+      for (run=sched->run; run; run=run->next) {
+        /* 
+         * Find runs in next 24 hours
+         */
+        tod = (bit_is_set(mday, run->mday) || bit_is_set(wday, run->wday)) && 
+               bit_is_set(month, run->month);
+
+        tom = (bit_is_set(tmday, run->mday) || bit_is_set(twday, run->wday)) &&
+               bit_is_set(tmonth, run->month);
+
+         Dmsg2(200, "tod=%d tom=%d\n", tod, tom);
+        found = FALSE;
+        if (tod) {
+           /* find time (time_t) job is to be run */
+           localtime_r(&now, &tm);
+           hour = 0;
+           for (i=tm.tm_hour; i < 24; i++) {
+              if (bit_is_set(i, run->hour)) {
+                 tm.tm_hour = i;
+                 tm.tm_min = run->minute;
+                 tm.tm_sec = 0;
+                 runtime = mktime(&tm);
+                 if (runtime > now) {
+                    prt_runtime(ua, job, runtime);
+                    found = TRUE;
+                    break;
+                 }
+              }
+           }
+        }
+
+        Dmsg2(200, "runtime=%d now=%d\n", runtime, now);
+       if (!found && tom) {
+           localtime_r(&tomorrow, &tm);
+           hour = 0;
+           for (i=0; i < 24; i++) {
+              if (bit_is_set(i, run->hour)) {
+                 hour = i;
+                 break;
+              }
+           }
+           tm.tm_hour = hour;
+           tm.tm_min = run->minute;
+           tm.tm_sec = 0;
+           runtime = mktime(&tm);
+            Dmsg2(200, "truntime=%d now=%d\n", runtime, now);
+           if (runtime < tomorrow) {
+              prt_runtime(ua, job, runtime);
+           }
+        }
+      }  
+   }
+   UnlockRes();
+   Dmsg0(200, "Leave find_runs()\n");
+}
diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c
new file mode 100644 (file)
index 0000000..57d97e4
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ *
+ *   Bacula Director -- verify.c -- responsible for running file verification
+ *
+ *     Kern Sibbald, October MM
+ *
+ *    This routine is run as a separate thread.  There may be more
+ *    work to be done to make it totally reentrant!!!!
+ * 
+ * Current implementation is Catalog verification only (i.e. no
+ *  verification versus tape).
+ *
+ *  Basic tasks done here:
+ *     Open DB
+ *     Open connection with File daemon and pass him commands
+ *      to do the verify.
+ *     When the File daemon sends the attributes, compare them to
+ *      what is in the DB.
+ *
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Imported Global Variables */
+extern int debug_level;
+
+/* Commands sent to File daemon */
+static char verifycmd[]   = "verify";
+static char levelcmd[]    = "level = %s%s\n";
+
+/* Responses received from File daemon */
+static char OKverify[]   = "2000 OK verify\n";
+static char OKlevel[]    = "2000 OK level\n";
+
+/* Forward referenced functions */
+static void verify_cleanup(JCR *jcr);
+static void prt_fname(JCR *jcr);
+static int missing_handler(void *ctx, int num_fields, char **row);
+
+/* 
+ * Do a verification of the specified files
+ *    
+ *  Returns:  0 on failure
+ *           1 on success
+ */
+int do_verify(JCR *jcr) 
+{
+   char *level;
+   BSOCK   *fd;
+   JOB_DBR jr;
+   int last_full_id;
+   CLIENT_DBR cr;
+
+   memset(&cr, 0, sizeof(cr));
+   strcpy(cr.Name, jcr->client->hdr.name);
+   if (jcr->client_name) {
+      free(jcr->client_name);
+   }
+   jcr->client_name = bstrdup(jcr->client->hdr.name);
+   if (!db_create_client_record(jcr->db, &cr)) {
+      Jmsg(jcr, M_ERROR, 0, _("Could not create Client record. %s"), 
+        db_strerror(jcr->db));
+      jcr->JobStatus = JS_ErrorTerminated;
+      verify_cleanup(jcr);                   
+      return 0;
+   }
+   jcr->jr.ClientId = cr.ClientId;
+
+   Dmsg1(9, "bdird: created client %s record\n", jcr->client->hdr.name);
+
+   /* If we are doing a verify from the catalog,
+    * we must look up the time and date of the
+    * last full verify.
+    */
+   if (jcr->level == L_VERIFY_CATALOG) {
+      memcpy(&jr, &(jcr->jr), sizeof(jr));
+      if (!db_find_last_full_verify(jcr->db, &jr)) {
+         Jmsg(jcr, M_FATAL, 0, _("Unable to find last full verify. %s"),
+           db_strerror(jcr->db));
+        jcr->JobStatus = JS_ErrorTerminated;
+        verify_cleanup(jcr);
+        return 0;
+      }
+      last_full_id = jr.JobId;
+      Dmsg1(20, "Last full id=%d\n", last_full_id);
+   }
+
+   jcr->jr.JobId = jcr->JobId;
+   jcr->jr.StartTime = jcr->start_time;
+   jcr->jr.Level = jcr->level;
+   if (!db_update_job_start_record(jcr->db, &jcr->jr)) {
+      Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
+      jcr->JobStatus = JS_ErrorTerminated;
+      verify_cleanup(jcr);
+      return 0;
+   }
+
+   jcr->fname = (char *) get_pool_memory(PM_FNAME);
+
+   jcr->jr.JobId = last_full_id;      /* save last full id */
+
+   /* Print Job Start message */
+   Jmsg(jcr, M_INFO, 0, _("Start Verify JobId %d Job=%s\n"),
+      jcr->JobId, jcr->Job);
+
+   if (jcr->level == L_VERIFY_CATALOG) {
+      memset(&jr, 0, sizeof(jr));
+      jr.JobId = last_full_id;
+      if (!db_get_job_record(jcr->db, &jr)) {
+         Jmsg(jcr, M_ERROR, 0, _("Could not get job record. %s"), db_strerror(jcr->db));
+        jcr->JobStatus = JS_ErrorTerminated;
+        verify_cleanup(jcr);
+        return 0;
+      }
+      Jmsg(jcr, M_INFO, 0, _("Verifying against Init JobId %d run %s\n"),
+        last_full_id, jr.cStartTime); 
+   }
+
+   /*
+    * OK, now connect to the File daemon
+    *  and ask him for the files.
+    */
+   jcr->sd_auth_key = bstrdup("dummy");    /* dummy Storage daemon key */
+   if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      verify_cleanup(jcr);
+      return 0;
+   }
+
+   fd = jcr->file_bsock;
+
+   Dmsg0(30, ">filed: Send include list\n");
+   if (!send_include_list(jcr)) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      verify_cleanup(jcr);
+      return 0;
+   }
+
+   Dmsg0(30, ">filed: Send exclude list\n");
+   if (!send_exclude_list(jcr)) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      verify_cleanup(jcr);
+      return 0;
+   }
+
+   /* 
+    * Send Level command to File daemon
+    *
+    */
+   switch (jcr->level) {
+      case L_VERIFY_INIT:
+         level = "init";
+        break;
+      case L_VERIFY_CATALOG:
+         level = "catalog";
+        break;
+      case L_VERIFY_VOLUME:
+         level = "volume";
+        break;
+      case L_VERIFY_DATA:
+         level = "data";
+        break;
+      default:
+         Emsg1(M_FATAL, 0, _("Unimplemented save level %d\n"), jcr->level);
+        jcr->JobStatus = JS_ErrorTerminated;
+        verify_cleanup(jcr);
+        return 0;
+   }
+   Dmsg1(20, ">filed: %s", fd->msg);
+   bnet_fsend(fd, levelcmd, level, " ");
+   if (!response(fd, OKlevel, "Level")) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      verify_cleanup(jcr);
+      return 0;
+   }
+
+   /* 
+    * Send verify command to File daemon
+    */
+   bnet_fsend(fd, verifycmd);
+   if (!response(fd, OKverify, "Verify")) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      verify_cleanup(jcr);
+      return 0;
+   }
+
+   /*
+    * Now get data back from File daemon and
+    *  compare it to the catalog or store it in the
+    *  catalog depending on the run type.
+    */
+   /* Compare to catalog */
+   if (jcr->level == L_VERIFY_CATALOG) {
+      Dmsg0(10, "Verify level=catalog\n");
+      get_attributes_and_compare_to_catalog(jcr, last_full_id);
+
+   /* Build catalog */
+   } else if (jcr->level == L_VERIFY_INIT) {
+      Dmsg0(10, "Verify level=init\n");
+      get_attributes_and_put_in_catalog(jcr);
+
+   } else {
+      Emsg1(M_FATAL, 0, _("Unimplemented save level %d\n"), jcr->level);
+      jcr->JobStatus = JS_ErrorTerminated;
+      verify_cleanup(jcr);
+      return 0;
+   }
+
+   verify_cleanup(jcr);
+   return 1;
+}
+
+/*
+ * Release resources allocated during backup.
+ *
+ */
+static void verify_cleanup(JCR *jcr)
+{
+   char sdt[50], edt[50];
+   char ec1[30];
+   char term_code[100];
+   char *term_msg;
+   int msg_type;
+   int TermCode;
+   int last_full_id;
+
+   Dmsg0(100, "Enter verify_cleanup()\n");
+
+   last_full_id = jcr->jr.JobId;
+
+
+   if (jcr->jr.EndTime == 0) {
+      jcr->jr.EndTime = time(NULL);
+   }
+   jcr->end_time = jcr->jr.EndTime;
+   jcr->jr.JobId = jcr->JobId;
+   jcr->jr.JobStatus = jcr->JobStatus;
+   TermCode = jcr->JobStatus;
+
+   if (!db_update_job_end_record(jcr->db, &jcr->jr)) {
+      Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"), 
+        db_strerror(jcr->db));
+   }
+
+   msg_type = M_INFO;                /* by default INFO message */
+   switch (TermCode) {
+      case JS_Terminated:
+         term_msg = _("Verify OK");
+        break;
+      case JS_Errored:
+         term_msg = _("*** Verify Error ***"); 
+        msg_type = M_ERROR;          /* Generate error message */
+        break;
+      case JS_Cancelled:
+         term_msg = _("Verify Cancelled");
+        break;
+      case JS_Differences:
+         term_msg = _("Verify Differences");
+        break;
+      default:
+        term_msg = term_code;
+         sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
+        break;
+   }
+   bstrftime(sdt, sizeof(sdt), jcr->jr.StartTime);
+   bstrftime(edt, sizeof(edt), jcr->jr.EndTime);
+
+   Jmsg(jcr, msg_type, 0, _("%s\n\
+JobId:                  %d\n\
+Job:                    %s\n\
+FileSet:                %s\n\
+Verify Level:           %s\n\
+Client:                 %s\n\
+Start time:             %s\n\
+End time:               %s\n\
+Files Examined:         %s\n\
+Termination:            %s\n"),
+       edt,
+       jcr->jr.JobId,
+       jcr->jr.Job,
+       jcr->fileset->hdr.name,
+       level_to_str(jcr->level),
+       jcr->client->hdr.name,
+       sdt,
+       edt,
+       edit_uint_with_commas(jcr->jr.JobFiles, ec1),
+       term_msg);
+
+   Dmsg0(100, "Leave verify_cleanup()\n");
+
+}
+
+/*
+ * This routine is called only during a Verify
+ */
+int get_attributes_and_compare_to_catalog(JCR *jcr, int last_full_id)
+{
+   BSOCK   *fd;
+   int n, len;
+   FILE_DBR fdbr;
+   struct stat statf;                /* file stat */
+   struct stat statc;                /* catalog stat */
+   int stat = JS_Terminated;
+   char buf[MAXSTRING];
+
+   memset(&fdbr, 0, sizeof(FILE_DBR));
+   fd = jcr->file_bsock;
+   fdbr.JobId = last_full_id;
+   
+   Dmsg0(20, "bdird: waiting to receive file attributes\n");
+   /*
+    * Get Attributes and MD5 Signature from File daemon
+    */
+   while ((n=bget_msg(fd, 0)) > 0) {
+       long file_index, attr_file_index;
+       int stream;
+       char *attr, *p;
+       char Opts[MAXSTRING];         /* Verify Opts or MD5 signature */
+       int do_MD5;
+
+       Dmsg1(50, "Atts+MD5=%s\n", fd->msg);
+       if ((len = sscanf(fd->msg, "%ld %d %s %s", &file_index, &stream, 
+            Opts, jcr->fname)) != 4) {
+          Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 4 fields got %d\n\
+msglen=%d msg=%s\n"), len, fd->msglen, fd->msg);
+         jcr->JobStatus = JS_ErrorTerminated;
+         return 0;
+       }
+       /*
+       * Got attributes stream, decode it
+       */
+       if (stream == STREAM_UNIX_ATTRIBUTES) {
+         attr_file_index = file_index;    /* remember attribute file_index */
+         len = strlen(fd->msg);
+         attr = &fd->msg[len+1];
+         decode_stat(attr, &statf);  /* decode file stat packet */
+         do_MD5 = FALSE;
+         jcr->fn_printed = FALSE;
+
+          Dmsg2(11, "dird<filed: stream=%d %s\n", stream, jcr->fname);
+          Dmsg1(20, "dird<filed: attr=%s\n", attr);
+
+         /* 
+          * Find equivalent record in the database 
+          */
+         fdbr.FileId = 0;
+         db_get_file_attributes_record(jcr->db, jcr->fname, &fdbr);
+
+         if (fdbr.FileId == 0) {
+             Jmsg(jcr, M_INFO, 0, _("New file: %s\n"), jcr->fname);
+             Dmsg1(20, _("File not in catalog: %s\n"), jcr->fname);
+            stat = JS_Differences;
+            continue;
+         } else {
+            /* 
+             * mark file record as visited by stuffing the
+             * current JobId, which is unique, into the FileIndex
+             */
+            db_mark_file_record(jcr->db, fdbr.FileId, jcr->JobId);
+         }
+
+          Dmsg2(20, "Found %s in catalog. Opts=%s\n", jcr->fname, Opts);
+         decode_stat(fdbr.LStat, &statc); /* decode catalog stat */
+         strip_trailing_junk(jcr->fname);
+         /*
+          * Loop over options supplied by user and verify the
+          * fields he requests.
+          */
+         for (p=Opts; *p; p++) {
+            switch (*p) {
+             case 'i':                /* compare INODEs */
+               if (statc.st_ino != statf.st_ino) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_ino   differ. Cat: %x File: %x\n"), 
+                     statc.st_ino, statf.st_ino);
+                  stat = JS_Differences;
+               }
+               break;
+             case 'p':                /* permissions bits */
+               if (statc.st_mode != statf.st_mode) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_mode  differ. Cat: %x File: %x\n"), 
+                     statc.st_mode, statf.st_mode);
+                  stat = JS_Differences;
+               }
+               break;
+             case 'n':                /* number of links */
+               if (statc.st_nlink != statf.st_nlink) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_nlink differ. Cat: %d File: %d\n"), 
+                     statc.st_nlink, statf.st_nlink);
+                  stat = JS_Differences;
+               }
+               break;
+             case 'u':                /* user id */
+               if (statc.st_uid != statf.st_uid) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_uid   differ. Cat: %d File: %d\n"), 
+                     statc.st_uid, statf.st_uid);
+                  stat = JS_Differences;
+               }
+               break;
+             case 'g':                /* group id */
+               if (statc.st_gid != statf.st_gid) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_gid   differ. Cat: %d File: %d\n"), 
+                     statc.st_gid, statf.st_gid);
+                  stat = JS_Differences;
+               }
+               break;
+             case 's':                /* size */
+               if (statc.st_size != statf.st_size) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_size  differ. Cat: %d File: %d\n"), 
+                     statc.st_size, statf.st_size);
+                  stat = JS_Differences;
+               }
+               break;
+             case 'a':                /* access time */
+               if (statc.st_atime != statf.st_atime) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_atime differs\n"));
+                  stat = JS_Differences;
+               }
+               break;
+             case 'm':
+               if (statc.st_mtime != statf.st_mtime) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_mtime differs\n"));
+                  stat = JS_Differences;
+               }
+               break;
+             case 'c':                /* ctime */
+               if (statc.st_ctime != statf.st_ctime) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_ctime differs\n"));
+                  stat = JS_Differences;
+               }
+               break;
+             case 'd':                /* file size decrease */
+               if (statc.st_size > statf.st_size) {
+                  prt_fname(jcr);
+                   Jmsg(jcr, M_INFO, 0, _("      st_size  decrease. Cat: %d File: %d\n"), 
+                     statc.st_size, statf.st_size);
+                  stat = JS_Differences;
+               }
+               break;
+             case '5':                /* compare MD5 */
+               do_MD5 = TRUE;
+               break;
+             case ':':
+             case 'V':
+            default:
+               break;
+            }
+         }
+       /*
+       * Got MD5 Signature from Storage daemon
+       *  It came across in the Opts field.
+       */
+       } else if (stream == STREAM_MD5_SIGNATURE) {
+         if (attr_file_index != file_index) {
+             Jmsg2(jcr, M_FATAL, 0, _("MD5 index %d not same as attributes %d\n"),
+               file_index, attr_file_index);
+            jcr->JobStatus = JS_ErrorTerminated;
+            return 0;
+         }
+         if (do_MD5) {
+            db_escape_string(buf, Opts, strlen(Opts));
+            if (strcmp(buf, fdbr.MD5) != 0) {
+               /***FIXME**** fname may not be valid */
+               prt_fname(jcr);
+               if (debug_level >= 10) {
+                   Jmsg(jcr, M_INFO, 0, _("      MD5 not same. File=%s Cat=%s\n"), buf, fdbr.MD5);
+               } else {
+                   Jmsg(jcr, M_INFO, 0, _("      MD5 differs.\n"));
+               }
+               stat = JS_Differences;
+            }
+         }
+       }
+       jcr->jr.JobFiles = file_index;
+
+   } 
+   if (n < 0) {
+      Jmsg2(jcr, M_FATAL, 0, _("bdird<filed: bad attributes from filed n=%d : %s\n"),
+                       n, strerror(errno));
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+   /* Now find all the files that are missing -- i.e. all files in
+    *  the database where the FileIndex != current JobId
+    */
+   jcr->fn_printed = FALSE;
+   sprintf(buf, 
+"SELECT Path.Path,Filename.Name FROM File,Path,Filename "
+"WHERE File.JobId=%d "
+"AND File.FileIndex!=%d AND File.PathId=Path.PathId "
+"AND File.FilenameId=Filename.FilenameId", 
+      last_full_id, jcr->JobId);
+   db_sql_query(jcr->db, buf, missing_handler, (void *)jcr);
+   if (jcr->fn_printed) {
+      stat = JS_Differences;
+   }
+   jcr->JobStatus = stat;
+   return 1;
+}
+
+/*
+ * We are called here for each record that matches the above
+ *  SQL query -- that is for each file contained in the Catalog
+ *  that was not marked earlier. This means that the file in
+ *  question is a missing file (in the Catalog but on on Disk).
+ */
+static int missing_handler(void *ctx, int num_fields, char **row)
+{
+   JCR *jcr = (JCR *)ctx;
+
+   if (!jcr->fn_printed) {
+      Jmsg(jcr, M_INFO, 0, "\n");
+      Jmsg(jcr, M_INFO, 0, _("The following files are missing:\n"));
+      jcr->fn_printed = TRUE;
+   }
+   Jmsg(jcr, M_INFO, 0, "      %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
+   return 0;
+}
+
+
+/* 
+ * Print filename for verify
+ */
+static void prt_fname(JCR *jcr)
+{
+   if (!jcr->fn_printed) {
+      Jmsg(jcr, M_INFO, 0, _("File: %s\n"), jcr->fname);
+      jcr->fn_printed = TRUE;
+   }
+}
diff --git a/bacula/src/filed/Makefile.in b/bacula/src/filed/Makefile.in
new file mode 100755 (executable)
index 0000000..dcc7032
--- /dev/null
@@ -0,0 +1,127 @@
+@MCOMMON@
+
+srcdir =       .
+VPATH =        .
+.PATH:         .
+
+# one up
+basedir = ..
+# top dir
+topdir = ../..
+# this dir relative to top dir
+thisdir = src/filed
+
+DEBUG=@DEBUG@
+
+first_rule: all
+dummy:
+
+#
+SVRSRCS = filed.c authenticate.c backup.c estimate.c \
+         filed_conf.c job.c \
+         restore.c status.c verify.c
+SVROBJS = filed.o authenticate.o backup.o estimate.o \
+         filed_conf.o job.o \
+         restore.o status.o verify.o
+
+# these are the objects that are changed by the .configure process
+EXTRAOBJS = @OBJLIST@
+
+FDLIBS = @FDLIBS@                # extra libs for File daemon
+
+# extra items for linking on Win32
+WIN32OBJS = win32/winmain.o win32/winlib.a win32/winres.res
+win32 = $(WIN32OBJS) -luser32 -lgdi32
+
+WIN32LIBS = $(@WIN32@)
+
+.SUFFIXES:     .c .o
+.PHONY:
+.DONTCARE:
+
+# inference rules
+.c.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
+#-------------------------------------------------------------------------
+all: Makefile @WIN32@ bacula-fd       
+       @echo "==== Make of filed is good ===="
+       @echo " "
+
+win32/winlib.a:
+       (cd win32; $(MAKE))
+       @rm -f bacula-fd.exe
+
+win32/winmain.o:
+       (cd win32; $(MAKE))
+       @rm -f bacula-fd.exe
+
+win32/winres.res:
+       (cd win32; $(MAKE))
+       @rm -f bacula-fd.exe
+
+# win32 libraries if needed
+win32: $(WIN32OBJS)
+       (cd win32; $(MAKE))
+       @rm -f bacula-fd.exe
+
+bacula-fd:  $(SVROBJS) ../findlib/libfind.a ../lib/libbac.a @WIN32@
+       $(CXX) $(LDFLAGS) -L../lib -L../findlib -o $@ $(SVROBJS) \
+         $(WIN32LIBS) $(FDLIBS) $(LIBS) $(DLIB) -lfind -lbac -lm
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+clean:
+       @$(RMF) bacula-fd filed core core.* a.out *.o *.bak *~ *.intpro *.extpro 1 2 3
+       if test -f win32/Makefile; then \
+          (cd win32; $(MAKE) clean); \
+       fi
+
+realclean: clean
+       @$(RMF) tags bacula-fd.conf
+
+distclean: realclean
+       if test $(srcdir) = .; then $(MAKE) realclean; fi
+       (cd $(srcdir); $(RMF) Makefile)
+       if test -f win32/Makefile; then \
+          (cd win32; $(MAKE) distclean); \
+       fi
+
+install: all
+       $(INSTALL_PROGRAM) bacula-fd $(DESTDIR)$(sbindir)/bacula-fd 
+       @srcconf=bacula-fd.conf; \
+       if  test -f ${DESTDIR}${sysconfdir}/$$srcconf; then \
+          destconf=$$srcconf.new; \
+          echo "  ==> Found existing $$srcconf, installing new conf file as $$destconf"; \
+       else \
+          destconf=$$srcconf; \
+       fi; \
+       echo "${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf"; \
+       ${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf
+
+uninstall:
+       (cd $(DESTDIR)$(sbindir); $(RMF) bacula-fd)
+       (cd $(DESTDIR)$(sbindir); $(RMF) bacula-fd.conf)
+
+
+
+# Semi-automatic generation of dependencies:
+# Use gcc -MM because X11 `makedepend' doesn't work on all systems
+# and it also includes system headers.
+# `semi'-automatic since dependencies are generated at distribution time.
+
+depend:
+       @$(MV) Makefile Makefile.bak
+       @$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile
+       @$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile
+       @$(CC) -S -M $(CPPFLAGS) $(XINC) -I$(srcdir) -I$(basedir) $(SQL_INC) *.c >> Makefile
+       @if test -f Makefile ; then \
+           $(RMF) Makefile.bak; \
+       else \
+          $(MV) Makefile.bak Makefile; \
+          echo -e "Something went wrong\n\a"; \
+       fi
+
+# -----------------------------------------------------------------------
+# DO NOT DELETE: nice dependency list follows
diff --git a/bacula/src/filed/authenticate.c b/bacula/src/filed/authenticate.c
new file mode 100644 (file)
index 0000000..cecf3e5
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Authenticate Director who is attempting to connect.
+ *
+ *   Kern Sibbald, October 2000
+ * 
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+  
+#include "bacula.h"
+#include "filed.h"
+
+static char OK_hello[]  = "2000 OK Hello\n";
+static char Dir_sorry[] = "2999 No go\n";
+
+
+/********************************************************************* 
+ *
+ */
+static int authenticate(int rcode, BSOCK *bs)
+{
+   char *name;
+   DIRRES *director;
+
+   if (rcode != R_DIRECTOR) {
+      Emsg1(M_FATAL, 0, _("I only authenticate directors, not %d\n"), rcode);
+      return 0;
+   }
+   name = (char *) get_pool_memory(PM_MESSAGE);
+   name = (char *) check_pool_memory_size(name, bs->msglen);
+
+   if (sscanf(bs->msg, "Hello Director %s calling\n", name) != 1) {
+      free_pool_memory(name);
+      Emsg1(M_FATAL, 0, _("Authentication failure: %s"), bs->msg);
+      return 0;
+   }
+   director = NULL;
+   LockRes();
+   while ((director=(DIRRES *)GetNextRes(rcode, (RES *)director))) {
+      if (strcmp(director->hdr.name, name) == 0)
+        break;
+   }
+   UnlockRes();
+   if (director && (!cram_md5_auth(bs, director->password) ||
+       !cram_md5_get_auth(bs, director->password))) {
+      director = NULL;
+   }
+   free_pool_memory(name);
+   return (director != NULL);
+}
+
+/*
+ * Inititiate the communications with the Director.
+ * He has made a connection to our server.
+ * 
+ * Basic tasks done here:
+ *   We read Director's initial message and authorize him.
+ *
+ */
+int authenticate_director(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+
+   if (!authenticate(R_DIRECTOR, dir)) {
+      bnet_fsend(dir, "%s", Dir_sorry);
+      Emsg0(M_ERROR, 0, _("Unable to authenticate Director\n"));
+      return 0;
+   }
+   return bnet_fsend(dir, "%s", OK_hello);
+}
+
+/*
+ * First prove our identity to the Storage daemon, then
+ * make him prove his identity.
+ */
+int authenticate_storagedaemon(JCR *jcr)
+{
+   BSOCK *sd = jcr->store_bsock;
+
+   return cram_md5_get_auth(sd, jcr->sd_auth_key) &&
+         cram_md5_auth(sd, jcr->sd_auth_key);
+}
diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c
new file mode 100644 (file)
index 0000000..7374fe3
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ *  Bacula File Daemon backup.c  send file attributes and data
+ *   to the Storage daemon.
+ *
+ *    Kern Sibbald, March MM
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "filed.h"
+
+static int save_file(FF_PKT *ff_pkt, void *pkt);
+
+/* 
+ * Find all the requested files and send them
+ * to the Storage daemon.
+ * 
+ */
+int blast_data_to_storage_daemon(JCR *jcr, char *addr, int port)
+{
+   BSOCK *sd;
+   int stat = 1;
+
+   sd = jcr->store_bsock;
+
+   jcr->JobStatus = JS_Running;
+
+   Dmsg1(10, "bfiled: opened data connection %d to stored\n", sd->fd);
+
+   if (!bnet_set_buffer_size(sd, MAX_NETWORK_BUFFER_SIZE, BNET_SETBUF_WRITE)) {
+      return 0;
+   }
+   jcr->buf_size = sd->msglen;            
+
+   jcr->compress_buf = (char *) bmalloc(jcr->buf_size);
+
+   Dmsg1(100, "set_find_options ff=%p\n", jcr->ff);
+   set_find_options(jcr->ff, jcr->incremental, jcr->mtime);
+   Dmsg0(10, "start find files\n");
+
+   /* Subroutine save_file() is called for each file */
+   /* ***FIXME**** add FSM code */
+   if (!find_files(jcr->ff, save_file, (void *)jcr)) {
+      stat = 0;                      /* error */
+   }
+
+   bnet_sig(sd, BNET_EOF);           /* terminate data connection */
+
+   if (jcr->big_buf) {
+      free(jcr->big_buf);
+      jcr->big_buf = NULL;
+   }
+   if (jcr->compress_buf) {
+      free(jcr->compress_buf);
+      jcr->compress_buf = NULL;
+   }
+   return stat;
+}         
+
+/* 
+ * Called here by find() for each file included.
+ *
+ *  *****FIXME*****   add FSMs File System Modules
+ *
+ *  Send the file and its data to the Storage daemon.
+ */
+static int save_file(FF_PKT *ff_pkt, void *ijcr)
+{
+   char attribs[MAXSTRING];
+   int fid, stat, stream;
+   size_t read_size;
+   struct MD5Context md5c;
+   int gotMD5 = 0;
+   unsigned char signature[16];
+   BSOCK *sd, *dir;
+   JCR *jcr = (JCR *)ijcr;
+   char *msgsave;
+
+   sd = jcr->store_bsock;
+   dir = jcr->dir_bsock;
+   jcr->num_files_examined++;        /* bump total file count */
+
+   switch (ff_pkt->type) {
+   case FT_LNKSAVED:                 /* Hard linked, file already saved */
+      break;
+   case FT_REGE:
+      Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
+      break;
+   case FT_REG:
+      Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
+      break;
+   case FT_LNK:
+      Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
+      break;
+   case FT_DIR:
+      Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->link);
+      break;
+   case FT_SPEC:
+      Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
+      break;
+   case FT_NOACCESS:
+      Jmsg(jcr, M_NOTSAVED, -1, _("     Could not access %s: ERR=%s"), ff_pkt->fname, 
+        strerror(ff_pkt->ff_errno));
+      return 1;
+   case FT_NOFOLLOW:
+      Jmsg(jcr, M_NOTSAVED, -1, _("     Could not follow link %s: ERR=%s\n"), ff_pkt->fname, 
+        strerror(ff_pkt->ff_errno));
+      return 1;
+   case FT_NOSTAT:
+      Jmsg(jcr, M_NOTSAVED, -1, _("     Could not stat %s: ERR=%s\n"), ff_pkt->fname, 
+        strerror(ff_pkt->ff_errno));
+      return 1;
+   case FT_DIRNOCHG:
+   case FT_NOCHG:
+      Jmsg(jcr, M_SKIPPED, -1,  _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
+      return 1;
+   case FT_ISARCH:
+      Jmsg(jcr, M_NOTSAVED, -1, _("     Archive file not saved: %s\n"), ff_pkt->fname);
+      return 1;
+   case FT_NORECURSE:
+      Jmsg(jcr, M_SKIPPED, -1,  _("     Recursion turned off. Directory skipped: %s\n"), 
+        ff_pkt->fname);
+      return 1;
+   case FT_NOFSCHG:
+      Jmsg(jcr, M_SKIPPED, -1,  _("     File system change prohibited. Directory skipped. %s\n"), 
+        ff_pkt->fname);
+      return 1;
+   case FT_NOOPEN:
+      Jmsg(jcr, M_NOTSAVED, -1, _("     Could not open directory %s: ERR=%s\n"), ff_pkt->fname, 
+        strerror(ff_pkt->ff_errno));
+      return 1;
+   default:
+      Jmsg(jcr, M_ERROR, 0, _("Unknown file type %d; not saved: %s\n"), ff_pkt->type, ff_pkt->fname);
+      return 1;
+   }
+
+   if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode) && 
+        ff_pkt->statp.st_size > 0) {
+      if ((fid = open(ff_pkt->fname, O_RDONLY | O_BINARY)) < 0) {
+        ff_pkt->ff_errno = errno;
+         Jmsg(jcr, M_NOTSAVED, -1, _("Cannot open %s: ERR=%s.\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno));
+        return 1;
+      }
+   } else {
+      fid = -1;
+   }
+
+   Dmsg1(30, "bfiled: sending %s to stored\n", ff_pkt->fname);
+   encode_stat(attribs, &ff_pkt->statp);
+     
+   jcr->JobFiles++;                   /* increment number of files sent */
+   jcr->last_fname = (char *) check_pool_memory_size(jcr->last_fname, strlen(ff_pkt->fname) + 1);
+   strcpy(jcr->last_fname, ff_pkt->fname);
+    
+   /*
+    * Send Attributes header to Storage daemon
+    *   <file-index> <stream> <info>
+    */
+   if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES)) {
+      if (fid >= 0) {
+        close(fid);
+      }
+      return 0;
+   }
+   Dmsg1(10, ">stored: attrhdr %s\n", sd->msg);
+
+   /* 
+    * Send file attributes to Storage daemon   
+    *  File_index
+    *  File type
+    *  Filename (full path)
+    *  Encoded attributes
+    *  Link name (if type==FT_LNK)
+    * For a directory, link is the same as fname, but with trailing
+    * slash. For a linked file, link is the link.
+    */
+   if (ff_pkt->type == FT_LNK) {
+      stat = bnet_fsend(sd, "%ld %d %s%c%s%c%s%c", jcr->JobFiles, 
+              ff_pkt->type, ff_pkt->fname, 0, attribs, 0, ff_pkt->link, 0);
+   } else if (ff_pkt->type == FT_DIR) {
+      stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c", jcr->JobFiles, 
+              ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0);
+   } else {
+      stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c", jcr->JobFiles, 
+              ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0);
+   }
+
+   Dmsg2(20, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
+   if (!stat) {
+      if (fid >= 0) {
+        close(fid);
+      }
+      return 0;
+   }
+   /* send data termination sentinel */
+   bnet_sig(sd, BNET_EOD);
+
+   /* 
+    * If the file has data, read it and send to the Storage daemon
+    *
+    */
+   if (fid >= 0) {
+
+      Dmsg1(60, "Saving data, type=%d\n", ff_pkt->type);
+      /*
+       * Send Data header to Storage daemon
+       *    <file-index> <stream> <info>
+       */
+      if (ff_pkt->flags & FO_GZIP) {
+        stream = STREAM_GZIP_DATA;
+        /* Adjust for compression so that output buffer is
+         * 12 bytes + 0.1% larger than input buffer
+         */
+        read_size = jcr->buf_size - 12 - (jcr->buf_size / 1000) - 1;
+      } else {
+        stream = STREAM_FILE_DATA;
+        read_size = jcr->buf_size;
+      }
+      if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) {
+        close(fid);
+        return 0;
+      }
+      Dmsg1(10, ">stored: datahdr %s\n", sd->msg);
+
+      if (ff_pkt->flags & FO_MD5) {
+        MD5Init(&md5c);
+      }
+
+      msgsave = sd->msg;
+      while ((sd->msglen=read(fid, sd->msg, read_size)) > 0) {
+#ifdef HAVE_LIBZ
+        uLongf compress_len;
+#endif
+
+        if (ff_pkt->flags & FO_MD5) {
+           MD5Update(&md5c, (unsigned char *) (sd->msg), sd->msglen);
+           gotMD5 = 1;
+        }
+        /* ***FIXME*** add compression level options */
+#ifdef HAVE_LIBZ
+        if (ff_pkt->flags & FO_GZIP) {
+           if (compress((Bytef *)jcr->compress_buf, &compress_len, 
+                 (const Bytef *)sd->msg, (uLong)sd->msglen) != Z_OK) {
+               Jmsg(jcr, M_ERROR, 0, _("Compression error\n"));
+              sd->msg = msgsave;
+              sd->msglen = 0;
+              close(fid);
+              return 0;
+           }
+           sd->msg = jcr->compress_buf;
+           sd->msglen = compress_len;
+        }
+#endif
+        if (!bnet_send(sd)) {
+           sd->msg = msgsave;
+           sd->msglen = 0;
+           close(fid);
+           return 0;
+        }
+         Dmsg1(30, "Send data to FD len=%d\n", sd->msglen);
+        jcr->JobBytes += sd->msglen;
+      }
+      if (sd->msglen < 0) {
+         Jmsg(jcr, M_ERROR, 0, _("Error during save reading ERR=%s\n"), ff_pkt->fname, 
+           strerror(ff_pkt->ff_errno));
+      }
+      sd->msg = msgsave;
+
+      /* Send data termination poll signal to Storage daemon.
+       *  NOTE possibly put this poll on a counter as specified
+       *  by the user to improve efficiency (i.e. poll every
+       *  other file, every third file, ... 
+       */
+      bnet_sig(sd, BNET_EOD_POLL);
+      Dmsg0(30, "Send EndData_Poll\n");
+      /* ***FIXME**** change to use bget_msg() */
+      if (bnet_recv(sd) <= 0) {
+        close(fid);
+        return 0;
+      } else {
+         if (strcmp(sd->msg, "3000 OK\n") != 0) {
+           Jmsg1(jcr, M_ERROR, 0, _("Job aborted by Storage daemon: %s\n"), sd->msg);
+          close(fid);
+          return 0;
+        }
+      }
+      close(fid);                       /* close file */
+   }
+
+
+   /* Terminate any MD5 signature and send it to Storage daemon and the Director */
+   if (gotMD5 && ff_pkt->flags & FO_MD5) {
+#ifdef really_needed
+      char MD5buf[50];               /* 24 bytes should do */
+#endif
+
+      MD5Final(signature, &md5c);
+
+      /* First do Storage daemon */
+      bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_MD5_SIGNATURE);
+      Dmsg1(10, "bfiled>stored:header %s\n", sd->msg);
+      memcpy(sd->msg, signature, 16);
+      sd->msglen = 16;
+      bnet_send(sd);
+      bnet_sig(sd, BNET_EOD);        /* end of MD5 */
+
+#ifdef really_needed
+      /* Now do Director (single record) */
+      bin_to_base64(MD5buf, (char *)signature, 16); /* encode 16 bytes */
+      bnet_fsend(dir, "%ld %d %s X", jcr->JobFiles, STREAM_MD5_SIGNATURE, 
+                MD5buf);
+#endif
+      gotMD5 = 0;
+   }
+#ifdef really_needed
+   if (ff_pkt->type == FT_DIR) {
+      Jmsg(jcr, M_SAVED, -1, _("     Directory saved normally: %s\n"), ff_pkt->link);
+   } else {
+      Jmsg(jcr, M_SAVED, -1, _("     File saved normally: %s\n"), ff_pkt->fname);
+   }
+#endif
+   return 1;
+}
diff --git a/bacula/src/filed/bacula-fd.conf.in b/bacula/src/filed/bacula-fd.conf.in
new file mode 100644 (file)
index 0000000..549f20c
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# Default  Bacula File Daemon Configuration file
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@ @DISTVER@
+#
+# There is not much to change here except perhaps the
+# File daemon Name to
+#
+
+#
+# List Directors who are permitted to contact this File daemon
+#
+Director {
+  Name = @hostname@-dir
+  Password = "@fd_password@"
+}
+
+#
+# "Global" File daemon configuration specifications
+#
+FileDaemon {                          # this is me
+  Name = @hostname@-fd
+  FDport = @fd_port@                  # where we listen for the director
+  WorkingDirectory = @working_dir@
+  Pid Directory = @piddir@
+  SubSys Directory = @subsysdir@
+}
+
+# Send all messages except skipped files back to Director
+Messages {
+  Name = Standard
+  director = @hostname@-dir = all, !skipped
+}
diff --git a/bacula/src/filed/estimate.c b/bacula/src/filed/estimate.c
new file mode 100644 (file)
index 0000000..fa020ff
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  Bacula File Daemon estimate.c                  
+ *   Make and estimate of the number of files and size to be saved.
+ *
+ *    Kern Sibbald, September MMI
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "filed.h"
+
+static int tally_file(FF_PKT *ff_pkt, void *pkt);
+
+/* 
+ * Find all the requested files and count them.
+ */
+int make_estimate(JCR *jcr)
+{
+   int stat;
+
+   jcr->JobStatus = JS_Running;
+
+   set_find_options(jcr->ff, jcr->incremental, jcr->mtime);
+
+   stat = find_files(jcr->ff, tally_file, (void *)jcr);
+
+   return stat;
+}         
+
+/* 
+ * Called here by find() for each file included.
+ *
+ *  *****FIXME*****   add FSMs File System Modules
+ *
+ */
+static int tally_file(FF_PKT *ff_pkt, void *ijcr)
+{
+   JCR *jcr = (JCR *) ijcr;
+
+   switch (ff_pkt->type) {
+   case FT_LNKSAVED:                 /* Hard linked, file already saved */
+      break;
+   case FT_REGE:
+   case FT_REG:
+   case FT_LNK:
+   case FT_DIR:
+   case FT_SPEC:
+      break;
+   case FT_NOACCESS:
+   case FT_NOFOLLOW:
+   case FT_NOSTAT:
+   case FT_DIRNOCHG:
+   case FT_NOCHG:
+   case FT_ISARCH:
+   case FT_NORECURSE:
+   case FT_NOFSCHG:
+   case FT_NOOPEN:
+   default:
+      return 1;
+   }
+
+   if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode) && 
+        ff_pkt->statp.st_size > 0) {
+      jcr->JobBytes += ff_pkt->statp.st_size;
+   }
+
+   jcr->JobFiles++;                 /* increment number of files sent */
+   return 1;
+}
diff --git a/bacula/src/filed/filed.c b/bacula/src/filed/filed.c
new file mode 100644 (file)
index 0000000..7e7ee3b
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ *  Bacula File Daemon
+ *
+ *    Kern Sibbald, March MM
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "filed.h"
+
+/* Imported Functions */
+extern void handle_client_request(void *dir_sock);
+
+/* Forward referenced functions */
+void terminate_filed(int sig);
+
+/* Exported variables */
+
+
+#ifdef HAVE_CYGWIN
+int win32_client = 1;
+#else
+int win32_client = 0;
+#endif
+
+
+#define CONFIG_FILE "./bacula-fd.conf" /* default config file */
+
+static char *configfile = NULL;
+static int foreground = 0;
+static workq_t dir_workq;            /* queue of work from Director */
+
+static void usage()
+{
+   fprintf(stderr, _(
+"\nVersion: " VERSION " (" DATE ")\n\n"
+"Usage: filed [-f -s] [-c config_file] [-d debug_level] [config_file]\n"  
+"        -c <file>   use <file> as configuration file\n"
+"        -dnn        set debug level to nn\n"
+"        -f          run in foreground (for debugging)\n"
+"        -s          no signals (for debugging)\n"
+"        -t          test configuration file and exit\n"
+"        -?          print this message.\n"
+"\n"));         
+   exit(1);
+}
+
+
+/********************************************************************* 
+ *
+ *  Main Bacula Unix Client Program                       
+ *
+ */
+#ifdef HAVE_CYGWIN
+#define main BaculaMain
+#endif
+int main (int argc, char *argv[])
+{
+   int ch;
+   int no_signals = FALSE;
+   int test_config = FALSE;
+   CLIENT *me;                       /* my resource */
+   DIRRES *director;
+
+   init_stack_dump();
+   my_name_is(argc, argv, "filed");
+   daemon_start_time = time(NULL);
+
+   memset(&last_job, 0, sizeof(last_job));
+
+   while ((ch = getopt(argc, argv, "c:d:fst?")) != -1) {
+      switch (ch) {
+         case 'c':                    /* configuration file */
+           if (configfile != NULL) {
+              free(configfile);
+           }
+           configfile = bstrdup(optarg);
+           break;
+
+         case 'd':                    /* debug level */
+           debug_level = atoi(optarg);
+           if (debug_level <= 0) {
+              debug_level = 1; 
+           }
+           break;
+
+         case 'f':                    /* run in foreground */
+           foreground = TRUE;
+           break;
+
+         case 's':
+           no_signals = TRUE;
+           break;
+
+         case 't':
+           test_config = TRUE;
+           break;
+
+         case '?':
+        default:
+           usage();
+
+      }  
+   }
+   argc -= optind;
+   argv += optind;
+
+   if (argc) {
+      if (configfile != NULL)
+        free(configfile);
+      configfile = bstrdup(*argv);
+      argc--; 
+      argv++;
+   }
+   if (argc) {
+      usage();
+   }
+
+   if (!no_signals) {
+      init_signals(terminate_filed);
+   }
+
+   if (configfile == NULL) {
+      configfile = bstrdup(CONFIG_FILE);
+   }
+
+
+   init_msg(NULL);
+   parse_config(configfile);
+
+   LockRes();
+   director = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
+   UnlockRes();
+   if (!director) {
+      Emsg1(M_ABORT, 0, _("No Director resource defined in %s\n"),
+        configfile);
+   }
+
+   LockRes();
+   me = (CLIENT *)GetNextRes(R_CLIENT, NULL);
+   UnlockRes();
+   if (!me) {
+      Emsg1(M_ABORT, 0, _("No File daemon resource defined in %s\n\
+Without that I don't know who I am :-(\n"), configfile);
+   } else {
+      my_name_is(0, (char **)NULL, me->hdr.name);
+   }
+   working_directory = me->working_directory;
+
+   if (test_config) {
+      terminate_filed(0);
+   }
+
+   if (!foreground) {
+      daemon_start();
+      init_stack_dump();             /* set new pid */
+   }
+
+#ifdef BOMB
+   me += 1000000;
+#endif
+
+   init_watchdog();                  /* start watchdog thread */
+
+   /* Become server, and handle requests */
+   Dmsg1(10, "filed: listening on port %d\n", me->FDport);
+   bnet_thread_server(me->FDport, 10, &dir_workq, handle_client_request);
+
+   exit(0);                          /* should never get here */
+}
+
+void terminate_filed(int sig)
+{
+   term_watchdog();
+
+   if (configfile != NULL) {
+      free(configfile);
+   }
+   if (debug_level > 5) {
+      print_memory_pool_stats(); 
+   }
+   free_config_resources();
+   close_memory_pool();              /* free memory in pool */
+   term_msg();
+   sm_dump(False);                   /* dump orphaned buffers */
+   exit(1);
+}
diff --git a/bacula/src/filed/filed.h b/bacula/src/filed/filed.h
new file mode 100644 (file)
index 0000000..e376722
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Bacula File Daemon specific configuration and defines
+ *
+ *     Kern Sibbald, Jan MMI 
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "findlib/find.h"
+#include "lib/save-cwd.h"
+#define FILE_DAEMON 1
+#include "jcr.h"
+#include "protos.h"                   /* file daemon prototypes */
+#include "filed_conf.h"
+#ifdef HAVE_LIBZ
+#include <zlib.h>                     /* compression headers */
+#else
+#define uLongf uint32_t
+#endif
+
+extern int win32_client;              /* Are we running on Windows? */
diff --git a/bacula/src/filed/filed_conf.c b/bacula/src/filed/filed_conf.c
new file mode 100644 (file)
index 0000000..708fafb
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ *   Main configuration file parser for Bacula File Daemon (Client)
+ *    some parts may be split into separate files such as
+ *    the schedule configuration (sch_config.c).
+ *
+ *   Note, the configuration file parser consists of three parts
+ *
+ *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
+ *
+ *   2. The generic config  scanner in lib/parse_config.c and 
+ *     lib/parse_config.h.
+ *     These files contain the parser code, some utility
+ *     routines, and the common store routines (name, int,
+ *     string).
+ *
+ *   3. The daemon specific file, which contains the Resource
+ *     definitions as well as any specific store routines
+ *     for the resource records.
+ *
+ *     Kern Sibbald, September MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+#include "filed.h"
+
+/* Define the first and last resource ID record
+ * types. Note, these should be unique for each
+ * daemon though not a requirement.
+ */
+int r_first = R_FIRST;
+int r_last  = R_LAST;
+pthread_mutex_t res_mutex =  PTHREAD_MUTEX_INITIALIZER;
+
+/* Forward referenced subroutines */
+
+
+/* We build the current resource here as we are
+ * scanning the resource configuration definition,
+ * then move it to allocated memory when the resource
+ * scan is complete.
+ */
+URES res_all;
+int  res_all_size = sizeof(res_all);
+
+/* Definition of records permitted within each
+ * resource with the routine to process the record 
+ * information.
+ */ 
+
+/* Client or File daemon "Global" resources */
+static struct res_items cli_items[] = {
+   {"name",     store_name,     ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str,   ITEM(res_client.hdr.desc), 0, 0, 0},
+   {"fdport",   store_pint,     ITEM(res_client.FDport),  0, ITEM_REQUIRED, 0},
+   {"workingdirectory",  store_dir,  ITEM(res_client.working_directory), 0, ITEM_REQUIRED, 0}, 
+   {"piddirectory",  store_dir,  ITEM(res_client.pid_directory), 0, ITEM_REQUIRED, 0}, 
+   {"subsysdirectory",  store_dir,  ITEM(res_client.subsys_directory), 0, ITEM_REQUIRED, 0}, 
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* Directors that can use our services */
+static struct res_items dir_items[] = {
+   {"name",        store_name,     ITEM(res_dir.hdr.name),  0, ITEM_REQUIRED, 0},
+   {"description", store_str,      ITEM(res_dir.hdr.desc),  0, 0, 0},
+   {"password",    store_password, ITEM(res_dir.password),  0, ITEM_REQUIRED, 0},
+   {"address",     store_str,      ITEM(res_dir.address),   0, 0, 0},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+/* Message resource */
+extern struct res_items msgs_items[];
+
+/* 
+ * This is the master resource definition.  
+ * It must have one item for each of the resources.
+ */
+struct s_res resources[] = {
+   {"director",      dir_items,   R_DIRECTOR,  NULL},
+   {"filedaemon",    cli_items,   R_CLIENT,    NULL},
+   {"client",        cli_items,   R_CLIENT,    NULL}, /* alias for filedaemon */
+   {"messages",      msgs_items,  R_MSGS,      NULL},
+   {NULL,           NULL,        0,           NULL}
+};
+
+
+/* Dump contents of resource */
+void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...), void *sock)
+{
+   URES *res = (URES *)reshdr;
+   int recurse = 1;
+
+   if (res == NULL) {
+      sendit(sock, "No record for %d %s\n", type, res_to_str(type));
+      return;
+   }
+   if (type < 0) {                   /* no recursion */
+      type = - type;
+      recurse = 0;
+   }
+   switch (type) {
+      case R_DIRECTOR:
+         sendit(sock, "Director: name=%s password=%s\n", reshdr->name, 
+                res->res_dir.password);
+        break;
+      case R_CLIENT:
+         sendit(sock, "Client: name=%s FDport=%d\n", reshdr->name,
+                res->res_client.FDport);
+        break;
+      case R_MSGS:
+         sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
+        break;
+      default:
+         sendit(sock, "Unknown resource type %d\n", type);
+   }
+   if (recurse && res->res_dir.hdr.next)
+      dump_resource(type, res->res_dir.hdr.next, sendit, sock);
+}
+
+/* 
+ * Free memory of resource.  
+ * NB, we don't need to worry about freeing any references
+ * to other resources as they will be freed when that 
+ * resource chain is traversed.  Mainly we worry about freeing
+ * allocated strings (names).
+ */
+void free_resource(int type)
+{
+   URES *res;
+   RES *nres;
+   int rindex = type - r_first;
+
+   res = (URES *)resources[rindex].res_head;
+
+   if (res == NULL) {
+      return;
+   }
+
+   /* common stuff -- free the resource name */
+   nres = (RES *)res->res_dir.hdr.next;
+   if (res->res_dir.hdr.name)
+      free(res->res_dir.hdr.name);
+   if (res->res_dir.hdr.desc)
+      free(res->res_dir.hdr.desc);
+
+   switch (type) {
+      case R_DIRECTOR:
+        if (res->res_dir.password)
+           free(res->res_dir.password);
+        if (res->res_dir.address)
+           free(res->res_dir.address);
+        break;
+      case R_CLIENT:
+        if (res->res_client.working_directory)
+           free(res->res_client.working_directory);
+        if (res->res_client.pid_directory)
+           free(res->res_client.pid_directory);
+        if (res->res_client.subsys_directory)
+           free(res->res_client.subsys_directory);
+        break;
+      case R_MSGS:
+        if (res->res_msgs.mail_cmd)
+           free(res->res_msgs.mail_cmd);
+        if (res->res_msgs.operator_cmd)
+           free(res->res_msgs.operator_cmd);
+        break;
+      default:
+         printf("Unknown resource type %d\n", type);
+   }
+   /* Common stuff again -- free the resource, recurse to next one */
+   free(res);
+   resources[rindex].res_head = nres;
+   if (nres) {
+      free_resource(type);
+   }
+}
+
+/* Save the new resource by chaining it into the head list for
+ * the resource. If this is pass 2, we update any resource
+ * pointers (currently only in the Job resource).
+ */
+void save_resource(int type, struct res_items *items, int pass)
+{
+   URES *res;
+   int rindex = type - r_first;
+   int i, size;
+   int error = 0;
+
+   /* 
+    * Ensure that all required items are present
+    */
+   for (i=0; items[i].name; i++) {
+      if (items[i].flags & ITEM_REQUIRED) {
+           if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {  
+               Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"),
+                items[i].name, resources[rindex]);
+            }
+      }
+   }
+
+   /* During pass 2, we looked up pointers to all the resources
+    * referrenced in the current resource, , now we
+    * must copy their address from the static record to the allocated
+    * record.
+    */
+   if (pass == 2) {
+      switch (type) {
+        /* Resources not containing a resource */
+        case R_MSGS:
+        case R_DIRECTOR:
+        case R_CLIENT:
+           break;
+
+        default:
+            Emsg1(M_ERROR, 0, _("Unknown resource type %d\n"), type);
+           error = 1;
+           break;
+      }
+      /* Note, the resoure name was already saved during pass 1,
+       * so here, we can just release it.
+       */
+      if (res_all.res_dir.hdr.name) {
+        free(res_all.res_dir.hdr.name);
+        res_all.res_dir.hdr.name = NULL;
+      }
+      if (res_all.res_dir.hdr.desc) {
+        free(res_all.res_dir.hdr.desc);
+        res_all.res_dir.hdr.desc = NULL;
+      }
+      return;
+   }
+
+   switch (type) {
+      case R_DIRECTOR:
+        size = sizeof(DIRRES);
+        break;
+      case R_CLIENT:
+        size = sizeof(CLIENT);
+        break;
+      case R_MSGS:
+        size = sizeof(MSGS);
+        break;
+      default:
+         printf(_("Unknown resource type %d\n"), type);
+        error = 1;
+        break;
+   }
+   /* Common */
+   if (!error) {
+      res = (URES *) malloc(size);
+      memcpy(res, &res_all, size);
+      res->res_dir.hdr.next = resources[rindex].res_head;
+      resources[rindex].res_head = (RES *)res;
+      Dmsg1(90, "dir_conf: inserting res: %s\n", res->res_dir.hdr.name);
+   }
+
+}
diff --git a/bacula/src/filed/filed_conf.h b/bacula/src/filed/filed_conf.h
new file mode 100644 (file)
index 0000000..3edffcc
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Bacula File Daemon specific configuration
+ *
+ *     Kern Sibbald, Sep MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/*
+ * Resource codes -- they must be sequential for indexing   
+ */
+#define R_FIRST                      1001
+
+#define R_DIRECTOR                   1001
+#define R_CLIENT                     1002
+#define R_MSGS                       1003
+
+#define R_LAST                       R_MSGS
+
+/*
+ * Some resource attributes
+ */
+#define R_NAME                       1020
+#define R_ADDRESS                    1021
+#define R_PASSWORD                   1022
+#define R_TYPE                       1023
+
+
+/* Definition of the contents of each Resource */
+struct s_res_dir {
+   RES  hdr;
+   char *password;                   /* Director password */
+   char *address;                    /* Director address or zero */
+};
+typedef struct s_res_dir DIRRES;
+
+struct s_res_client {
+   RES  hdr;
+   int  FDport;                      /* where we listen for Directors */ 
+   char *working_directory;
+   char *pid_directory;
+   char *subsys_directory;
+};
+typedef struct s_res_client CLIENT;
+
+
+
+/* Define the Union of all the above
+ * resource structure definitions.
+ */
+union u_res {
+   struct s_res_dir    res_dir;
+   struct s_res_client res_client;
+   struct s_res_msgs   res_msgs;
+   RES hdr;
+};
+
+typedef union u_res URES;
diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c
new file mode 100644 (file)
index 0000000..419f9e9
--- /dev/null
@@ -0,0 +1,711 @@
+/*
+ *  Bacula File Daemon Job processing
+ *
+ *    Kern Sibbald, October MM
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "filed.h"
+
+extern char my_name[];
+                       
+/* Imported functions */
+extern int status_cmd(JCR *jcr);
+                                  
+/* Forward referenced functions */
+static int backup_cmd(JCR *jcr);
+static int cancel_cmd(JCR *jcr);
+static int setdebug_cmd(JCR *jcr);
+static int estimate_cmd(JCR *jcr);
+static int exclude_cmd(JCR *jcr);
+static int hello_cmd(JCR *jcr);
+static int job_cmd(JCR *jcr);
+static int include_cmd(JCR *jcr);
+static int level_cmd(JCR *jcr);
+static int verify_cmd(JCR *jcr);
+static int restore_cmd(JCR *jcr);
+static int storage_cmd(JCR *jcr);
+static int session_cmd(JCR *jcr);
+static int response(BSOCK *sd, char *resp, char *cmd);
+static void filed_free_jcr(JCR *jcr);
+
+
+
+/* Exported functions */
+
+struct s_cmds {
+   char *cmd;
+   int (*func)(JCR *);
+};
+
+/*  
+ * The following are the recognized commands from the Director. 
+ */
+static struct s_cmds cmds[] = {
+   {"backup",   backup_cmd},
+   {"cancel",   cancel_cmd},
+   {"setdebug=", setdebug_cmd},
+   {"estimate", estimate_cmd},
+   {"exclude",  exclude_cmd},
+   {"Hello",    hello_cmd},
+   {"include",  include_cmd},
+   {"JobId=",   job_cmd},
+   {"level = ", level_cmd},
+   {"restore",  restore_cmd},
+   {"session",  session_cmd},
+   {"status",   status_cmd},
+   {"storage ", storage_cmd},
+   {"verify",   verify_cmd},
+   {NULL,      NULL}                  /* list terminator */
+};
+
+/* Commands received from director that need scanning */
+static char jobcmd[]     = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
+static char storaddr[]   = "storage address=%s port=%d\n";
+static char sessioncmd[] = "session %s %ld %ld %ld %ld %ld %ld\n";
+static char restorecmd[] = "restore where=%s\n";
+
+/* Responses sent to Director */
+static char errmsg[]       = "2999 Invalid command\n";
+static char no_auth[]      = "2998 No Authorization\n";
+static char OKinc[]        = "2000 OK include\n";
+static char OKest[]        = "2000 OK estimate files=%ld bytes=%ld\n";
+static char OKexc[]        = "2000 OK exclude\n";
+static char OKlevel[]      = "2000 OK level\n";
+static char OKbackup[]     = "2000 OK backup\n";
+static char OKverify[]     = "2000 OK verify\n";
+static char OKrestore[]    = "2000 OK restore\n";
+static char OKsession[]    = "2000 OK session\n";
+static char OKstore[]      = "2000 OK storage\n";
+static char OKjob[]        = "2000 OK Job\n";
+static char OKsetdebug[]   = "2000 OK setdebug=%d\n";
+static char BADjob[]       = "2901 Bad Job\n";
+
+/* Responses received from Storage Daemon */
+static char OK_end[]       = "3000 OK end\n";
+static char OK_open[]      = "3000 OK open ticket = %d\n";
+static char OK_data[]      = "3000 OK data\n";
+static char OK_append[]    = "3000 OK append data\n";
+
+
+/* Commands sent to Storage Daemon */
+static char append_open[]  = "append open session\n";
+static char append_data[]  = "append data %d\n";
+static char append_end[]   = "append end session %d\n";
+static char append_close[] = "append close session %d\n";
+static char read_open[]    = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
+static char read_data[]    = "read data %d\n";
+static char read_close[]   = "read close session %d\n";
+
+/* 
+ * Accept requests from a Director
+ *
+ * NOTE! We are running as a separate thread
+ *
+ * Send output one line
+ * at a time followed by a zero length transmission.
+ *
+ * Return when the connection is terminated or there
+ * is an error.
+ *
+ * Basic task here is:
+ *   Authenticate Director (during Hello command).
+ *   Accept commands one at a time from the Director
+ *     and execute them.
+ *
+ */
+void *handle_client_request(void *dirp)
+{
+   int i, found, quit;
+   JCR *jcr;
+   BSOCK *dir = (BSOCK *) dirp;
+
+   jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
+   jcr->dir_bsock = dir;
+   jcr->ff = init_find_files();
+   jcr->start_time = time(NULL);
+   jcr->last_fname = (char *) get_pool_memory(PM_FNAME);
+   jcr->client_name = bstrdup(my_name);
+
+   /**********FIXME******* add command handler error code */
+
+   for (quit=0; !quit;) {
+
+      /* Read command */
+      if (bnet_recv(dir) <= 0) {
+        break;                       /* connection terminated */
+      }
+      dir->msg[dir->msglen] = 0;
+      Dmsg1(9, "<dird: %s", dir->msg);
+      found = FALSE;
+      for (i=0; cmds[i].cmd; i++) {
+        if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
+           if (!jcr->authenticated && cmds[i].func != hello_cmd) {
+              bnet_fsend(dir, no_auth);
+              break;
+           }
+           if (!cmds[i].func(jcr)) {    /* do command */
+              quit = TRUE;              /* error, get out */
+               Dmsg0(20, "Command error\n");
+           }
+           found = TRUE;            /* indicate command found */
+           break;
+        }
+      }
+      if (!found) {                  /* command not found */
+        bnet_fsend(dir, errmsg);
+        quit = TRUE;
+        break;
+      }
+   }
+   Dmsg0(20, "Calling term_find_files\n");
+   term_find_files(jcr->ff);
+   Dmsg0(20, "Done with term_find_files\n");
+   free_jcr(jcr);                    /* destroy JCR record */
+   Dmsg0(20, "Done with free_jcr\n");
+   return NULL;
+}
+
+/*
+ * Hello from Director he must identify himself and provide his 
+ *  password.
+ */
+static int hello_cmd(JCR *jcr)
+{
+   Dmsg0(20, "Calling Authenticate\n");
+   if (!authenticate_director(jcr)) {
+      return 0;
+   }
+   Dmsg0(20, "OK Authenticate\n");
+   jcr->authenticated = TRUE;
+   return 1;
+}
+
+/*
+ * Cancel a Job
+ */
+static int cancel_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   char Job[MAX_NAME_LENGTH];
+   JCR *cjcr;
+
+   if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
+      if (!(cjcr=get_jcr_by_full_name(Job))) {
+         bnet_fsend(dir, "2901 Job %s not found.\n", Job);
+      } else {
+        cjcr->JobStatus = JS_Cancelled;
+        free_jcr(cjcr);
+         bnet_fsend(dir, "2001 Job %s marked to be cancelled.\n", Job);
+      }
+   } else {
+      bnet_fsend(dir, "2902 Error scanning cancel command.\n");
+   }
+   bnet_sig(dir, BNET_EOF);
+   return 1;
+}
+
+
+/*
+ * Set debug level as requested by the Director
+ *
+ */
+static int setdebug_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   int level;
+
+   Dmsg1(10, "setdebug_cmd: %s", dir->msg);
+   if (sscanf(dir->msg, "setdebug=%d", &level) != 1 || level < 0) {
+      bnet_fsend(dir, "2991 Bad setdebug command: %s\n", dir->msg);
+      return 0;
+   }
+   debug_level = level;
+   return bnet_fsend(dir, OKsetdebug, level);
+}
+
+
+static int estimate_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   make_estimate(jcr);
+   return bnet_fsend(dir, OKest, jcr->JobFiles, jcr->JobBytes);
+}
+
+/*
+ * Get JobId and Storage Daemon Authorization key from Director
+ */
+static int job_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   char *sd_auth_key;
+
+   sd_auth_key = (char *) get_memory(dir->msglen);
+   if (sscanf(dir->msg, jobcmd,  &jcr->JobId, jcr->Job,  
+             &jcr->VolSessionId, &jcr->VolSessionTime,
+             sd_auth_key) != 5) {
+      bnet_fsend(dir, BADjob);
+      Emsg1(M_FATAL, 0, _("Bad Job Command: %s\n"), dir->msg);
+      free_pool_memory(sd_auth_key);
+      return 0;
+   }
+   jcr->sd_auth_key = bstrdup(sd_auth_key);
+   free_pool_memory(sd_auth_key);
+   Dmsg2(20, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
+   return bnet_fsend(dir, OKjob);
+}
+
+/* 
+ * 
+ * Get list of files/directories to include from Director
+ *
+ */
+static int include_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+
+   while (bnet_recv(dir) > 0) {
+       dir->msg[dir->msglen] = 0;
+       strip_trailing_junk(dir->msg);
+       Dmsg1(10, "filed<dird: include file %s\n", dir->msg);
+       add_fname_to_include_list(jcr->ff, 1, dir->msg);
+   }
+
+   return bnet_fsend(dir, OKinc);
+}
+
+/*
+ * Get list of files to exclude from Director
+ *
+ */
+static int exclude_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   char *p;  
+
+   while (bnet_recv(dir) > 0) {
+       dir->msg[dir->msglen] = 0;
+       strip_trailing_junk(dir->msg);
+       /* Skip leading options */
+       for (p=dir->msg; *p && *p != ' '; p++)
+         { }
+       /* Skip spaces */
+       for ( ; *p && *p == ' '; p++)
+         { }
+       add_fname_to_exclude_list(jcr->ff, p);
+       Dmsg1(10, "<dird: exclude file %s\n", dir->msg);
+   }
+
+   return bnet_fsend(dir, OKexc);
+}
+
+/*
+ * Get backup level from Director
+ *
+ */
+static int level_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   char *level;
+   struct tm tm;
+   time_t mtime;
+
+   level = (char *) get_memory(dir->msglen);
+   Dmsg1(10, "level_cmd: %s", dir->msg);
+   if (sscanf(dir->msg, "level = %s ", level) != 1) {
+      Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), dir->msg);
+      free_memory(level);
+      return 0;
+   }
+   /*
+    * Full backup requested
+    */
+   if (strcmp(level, "full") == 0) {
+      jcr->save_level = L_FULL;
+   /* 
+    * Backup requested since <date> <time>
+    *  This form is also used for incremental and differential
+    */
+   } else if (strcmp(level, "since") == 0) {
+      jcr->save_level = L_SINCE;
+      if (sscanf(dir->msg, "level = since %d-%d-%d %d:%d:%d", 
+                &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+                &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+         Jmsg1(jcr, M_FATAL, 0, "Bad scan of date/time: %s\n", dir->msg);
+        free_memory(level);
+        return 0;
+      }
+      tm.tm_year -= 1900;
+      tm.tm_mon  -= 1;
+      tm.tm_wday = tm.tm_yday = 0;             
+      tm.tm_isdst = -1;
+      mtime = mktime(&tm);
+      Dmsg1(90, "Got since time: %s", ctime(&mtime));
+      jcr->incremental = 1;
+      jcr->mtime = mtime;
+   } else if (strcmp(level, "catalog") == 0) {
+      /* nothing for now */
+   } else if (strcmp(level, "init") == 0) {
+      /* nothing for now */
+   } else {
+      Jmsg1(jcr, M_FATAL, 0, "Unknown backup level: %s\n", level);
+      free_memory(level);
+      return 0;
+   }
+   free_memory(level);
+   return bnet_fsend(dir, OKlevel);
+}
+
+/*
+ * Get session parameters from Director -- this is for a Restore command
+ */
+static int session_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+
+   if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
+             &jcr->VolSessionId, &jcr->VolSessionTime,
+             &jcr->StartFile, &jcr->EndFile, 
+             &jcr->StartBlock, &jcr->EndBlock) != 7) {
+      Emsg1(M_FATAL, 0, "Bad session command: %s", dir->msg);
+      return 0;
+   }
+
+   return bnet_fsend(dir, OKsession);
+}
+
+/*
+ * Get address of storage daemon from Director
+ *
+ */
+static int storage_cmd(JCR *jcr)
+{
+   int stored_port;               /* storage daemon port */
+   BSOCK *dir = jcr->dir_bsock;
+   BSOCK *sd;                        /* storage daemon bsock */
+
+   if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port) != 2) {
+      Emsg1(M_FATAL, 0, _("Bad storage command: %s\n"), dir->msg);
+      return 0;
+   }
+   Dmsg2(30, "Got storage: %s:%d\n", jcr->stored_addr, stored_port);
+   /* Open command communications with Storage daemon */
+   /* Try to connect for 1 hour at 10 second intervals */
+   sd = bnet_connect(jcr, 10, 3600, _("Storage daemon"), 
+                    jcr->stored_addr, NULL, stored_port, 1);
+   if (sd == NULL) {
+      Jmsg2(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
+         jcr->stored_addr, stored_port);
+      return 0;
+   }
+
+   jcr->store_bsock = sd;
+
+   bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
+   if (!authenticate_storagedaemon(jcr)) {
+      Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
+      return 0;
+   }
+
+   /* Send OK to Director */
+   return bnet_fsend(dir, OKstore);
+}
+
+
+/*  
+ * Do a backup. For now, we handle only Full and Incremental.
+ */
+static int backup_cmd(JCR *jcr)
+{ 
+   int data_port;
+   BSOCK *dir = jcr->dir_bsock;
+   BSOCK *sd = jcr->store_bsock;
+   int len;
+
+   jcr->JobStatus = JS_Blocked;
+   jcr->JobType = JT_BACKUP;
+   Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
+
+   if (sd == NULL) {
+      Emsg0(M_FATAL, 0, _("Cannot contact Storage daemon\n"));
+      jcr->JobStatus = JS_ErrorTerminated;
+      goto cleanup;
+   }
+
+   bnet_fsend(dir, OKbackup);
+   Dmsg1(10, "bfiled>dird: %s", dir->msg);
+
+   /* 
+    * Send Append Open Session to Storage daemon
+    */
+   bnet_fsend(sd, append_open);
+   Dmsg1(10, ">stored: %s", sd->msg);
+   /* 
+    * Expect to receive back the Ticket number
+    */
+   if (bnet_recv(sd) > 0) {
+      Dmsg1(10, "<stored: %s", sd->msg);
+      if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
+         Emsg1(M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
+        jcr->JobStatus = JS_ErrorTerminated;
+        goto cleanup;
+      }
+      Dmsg1(10, "Got Ticket=%d\n", jcr->Ticket);
+   } else {
+      Emsg0(M_FATAL, 0, _("Bad response from stored to open command\n"));
+      jcr->JobStatus = JS_ErrorTerminated;
+      goto cleanup;
+   }
+
+   /* 
+    * Send Append data command to Storage daemon
+    */
+   bnet_fsend(sd, append_data, jcr->Ticket);
+   Dmsg1(10, ">stored: %s", sd->msg);
+
+   /* 
+    * Expect to get OK data 
+    */
+   Dmsg1(10, "<stored: %s", sd->msg);
+   if (!response(sd, OK_data, "Append Data")) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      goto cleanup;
+   }
+      
+   /*
+    * Send Files to Storage daemon
+    */
+   Dmsg1(100, "begin blast ff=%p\n", jcr->ff);
+   if (!blast_data_to_storage_daemon(jcr, NULL, data_port)) {
+      jcr->JobStatus = JS_ErrorTerminated;
+   } else {
+      jcr->JobStatus = JS_Terminated;
+      /* 
+       * Expect to get response to append_data from Storage daemon
+       */
+      if (!response(sd, OK_append, "Append Data")) {
+        jcr->JobStatus = JS_ErrorTerminated;
+        goto cleanup;
+      }
+     
+      /* 
+       * Send Append End Data to Storage daemon
+       */
+      bnet_fsend(sd, append_end, jcr->Ticket);
+      /* Get end OK */
+      if (!response(sd, OK_end, "Append End")) {
+        jcr->JobStatus = JS_ErrorTerminated;
+        goto cleanup;
+      }
+
+      /*
+       * Send Append Close to Storage daemon
+       */
+      bnet_fsend(sd, append_close, jcr->Ticket);
+      while ((len = bnet_recv(sd)) > 0) {
+         /* discard anything else returned from SD */
+      }
+      if (len < 0) {
+         Emsg2(M_FATAL, 0, _("<stored: net_recv len=%d: ERR=%s\n"), len, bnet_strerror(sd));
+        jcr->JobStatus = JS_ErrorTerminated;
+      }
+   }
+
+cleanup:
+
+   /* Inform Storage daemon that we are done */
+   if (sd) {
+      bnet_sig(sd, BNET_EOF);
+   }
+
+   /* Inform Director that we are done */
+   bnet_sig(dir, BNET_EOF);
+
+   return jcr->JobStatus == JS_Terminated;
+}
+
+/*  
+ * Do a Verify for Director
+ *
+ */
+static int verify_cmd(JCR *jcr)
+{ 
+   BSOCK *dir = jcr->dir_bsock;
+
+   jcr->JobType = JT_VERIFY;
+   bnet_fsend(dir, OKverify);
+   Dmsg1(10, "bfiled>dird: %s", dir->msg);
+
+   do_verify(jcr);
+
+   /* Inform Director that we are done */
+   return bnet_sig(dir, BNET_EOF);
+}
+
+/*  
+ * Do a Restore for Director
+ *
+ */
+static int restore_cmd(JCR *jcr)
+{ 
+   int len;
+   char *ip_addr;         
+   int data_port;
+   BSOCK *dir = jcr->dir_bsock;
+   BSOCK *sd = jcr->store_bsock;
+   char *where;
+
+   /*
+    * Scan WHERE (base directory for restore) from command
+    */
+   Dmsg0(50, "restore command\n");
+   /* Pickup where string */
+   where = (char *) get_memory(dir->msglen+1);
+   *where = 0;
+   sscanf(dir->msg, restorecmd, where);
+   Dmsg1(50, "Got where=%s\n", where);
+   jcr->where = where;
+
+   bnet_fsend(dir, OKrestore);
+   Dmsg1(10, "bfiled>dird: %s", dir->msg);
+
+   jcr->JobType = JT_RESTORE;
+   jcr->JobStatus = JS_Blocked;
+   ip_addr = (char *) get_pool_memory(PM_FNAME);
+
+   Dmsg4(20, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
+      jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
+   Dmsg2(20, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
+        
+   /* 
+    * Open Read Session with Storage daemon
+    */
+   bnet_fsend(sd, read_open, jcr->VolumeName,
+      jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile, 
+      jcr->StartBlock, jcr->EndBlock);
+   Dmsg1(10, ">stored: %s", sd->msg);
+
+   /* 
+    * Get ticket number
+    */
+   if ((len = bnet_recv(sd)) > 0) {
+      Dmsg1(10, "bfiled<stored: %s", sd->msg);
+      if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
+         Emsg1(M_FATAL, 0, _("Bad response to read open: %s\n"), sd->msg);
+        return 0;
+      }
+      Dmsg1(10, "bfiled: got Ticket=%d\n", jcr->Ticket);
+   } else {
+      Emsg0(M_FATAL, 0, _("Bad response from stored to read open command\n"));
+      return 0;
+   }
+
+   /* 
+    * Start read of data with Storage daemon
+    */
+   bnet_fsend(sd, read_data, jcr->Ticket);
+   Dmsg1(10, ">stored: %s", sd->msg);
+
+   /* 
+    * Get OK data
+    */
+   if (!response(sd, OK_data, "Read Data")) {
+      return 0;
+   }
+
+   /* 
+    * Do restore of files and data
+    */
+   do_restore(jcr, ip_addr, data_port);
+
+   /* 
+    * Send Close session command to Storage daemon
+    */
+   bnet_fsend(sd, read_close, jcr->Ticket);
+   Dmsg1(30, "bfiled>stored: %s", sd->msg);
+
+   /* ****FIXME**** check response */
+   bnet_recv(sd);                    /* get OK */
+
+   /* Inform Storage daemon that we are done */
+   bnet_sig(sd, BNET_EOF);
+
+   /* Inform Director that we are done */
+   bnet_sig(dir, BNET_EOF);
+
+   /* Clean up */
+   free_pool_memory(ip_addr);
+   Dmsg0(30, "Done in job.c\n");
+   return 1;
+}
+
+
+
+/* 
+ * Destroy the Job Control Record and associated
+ * resources (sockets).
+ */
+static void filed_free_jcr(JCR *jcr) 
+{
+   if (jcr->store_bsock) {
+      bnet_close(jcr->store_bsock);
+   }
+   if (jcr->where) {
+      free_pool_memory(jcr->where);
+   }
+   if (jcr->last_fname) {
+      free_pool_memory(jcr->last_fname);
+   }
+   return;
+}
+
+/*
+ * Get response from Storage daemon to a command we
+ * sent. Check that the response is OK.
+ *
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int response(BSOCK *sd, char *resp, char *cmd)
+{
+   int n;
+
+   if (sd->errors) {
+      return 0;
+   }
+   if ((n = bnet_recv(sd)) > 0) {
+      Dmsg0(10, sd->msg);
+      if (strcmp(sd->msg, resp) == 0) {
+        return 1;
+      }
+   } 
+   /* ********FIXME******** segfault if the following is executed */
+   if (n > 0) {
+      Emsg3(M_FATAL, 0, _("<stored: bad response to %s: wanted: %s, got: %s\n"),
+        cmd, resp, sd->msg);
+   } else {
+      Emsg2(M_FATAL, 0, _("<stored: bad response to %s command: ERR=%s\n"),
+        cmd, bnet_strerror(sd));
+   }
+   return 0;
+}
diff --git a/bacula/src/filed/protos.h b/bacula/src/filed/protos.h
new file mode 100644 (file)
index 0000000..af93c8a
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+extern int blast_data_to_storage_daemon(JCR *jcr, char *addr, int port);
+extern void do_verify(JCR *jcr);
+extern void do_restore(JCR *jcr, char *addr, int port);
+extern int authenticate_director(JCR *jcr);
+extern int authenticate_storagedaemon(JCR *jcr);
+extern int make_estimate(JCR *jcr);
+
diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c
new file mode 100644 (file)
index 0000000..7e3da87
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ *  Bacula File Daemon restore.c Restorefiles.
+ *
+ *    Kern Sibbald, November MM
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "filed.h"
+
+/* Data received from Storage Daemon */
+static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
+
+/* Forward referenced functions */
+static void print_ls_output(JCR *jcr, char *fname, char *lname, int type, struct stat *statp);
+
+#define RETRY 10                     /* retry wait time */
+
+/* 
+ * Restore the requested files.
+ * 
+ */
+void do_restore(JCR *jcr, char *addr, int port)
+{
+   int wherelen;
+   BSOCK *sd;
+   char *fname;                      /* original file name */
+   char *ofile;                      /* output name with possible prefix */
+   char *lname;                      /* link name */
+   int32_t stream;
+   uint32_t size;
+   uint32_t VolSessionId, VolSessionTime, file_index;
+   uint32_t record_file_index;
+   struct stat statp;
+   int extract = FALSE;
+   int ofd = -1;
+   int type;
+   uint32_t total = 0;
+   
+   wherelen = strlen(jcr->where);
+
+   sd = jcr->store_bsock;
+   jcr->JobStatus = JS_Running;
+
+   if (!bnet_set_buffer_size(sd, MAX_NETWORK_BUFFER_SIZE, BNET_SETBUF_READ)) {
+      return;
+   }
+
+   fname = (char *) get_pool_memory(PM_FNAME);
+   ofile = (char *) get_pool_memory(PM_FNAME);
+   lname = (char *) get_pool_memory(PM_FNAME);
+
+   /* 
+    * Get a record from the Storage daemon
+    */
+   while (bnet_recv(sd) > 0) {
+      /*
+       * First we expect a Stream Record Header 
+       */
+      if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index,
+         &stream, &size) != 5) {
+         Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
+        free_pool_memory(fname);
+        free_pool_memory(ofile);
+        free_pool_memory(lname);
+        return;
+      }
+      Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream);
+
+      /* 
+       * Now we expect the Stream Data
+       */
+      if (bnet_recv(sd) < 0) {
+         Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd));
+      }
+      if (size != ((uint32_t) sd->msglen)) {
+         Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size);
+        free_pool_memory(fname);
+        free_pool_memory(ofile);
+        free_pool_memory(lname);
+        return;
+      }
+      Dmsg1(30, "Got stream data, len=%d\n", sd->msglen);
+
+      /* File Attributes stream */
+      if (stream == STREAM_UNIX_ATTRIBUTES) {
+        char *ap, *lp;
+
+         Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
+        /* If extracting, it was from previous stream, so
+         * close the output file.
+         */
+        if (extract) {
+           if (ofd < 0) {
+               Emsg0(M_ABORT, 0, _("Logic error output file should be open\n"));
+           }
+           close(ofd);
+           ofd = -1;
+           extract = FALSE;
+           set_statp(jcr, fname, ofile, lname, type, &statp);
+            Dmsg0(30, "Stop extracting.\n");
+        }
+
+        if ((int)sizeof_pool_memory(fname) <  sd->msglen) {
+           fname = (char *) realloc_pool_memory(fname, sd->msglen + 1);
+        }
+        if (sizeof_pool_memory(ofile) < sizeof_pool_memory(fname) + wherelen + 1) {
+           ofile = (char *) realloc_pool_memory(ofile, sizeof_pool_memory(fname) + wherelen + 1);
+        }
+        if ((int)sizeof_pool_memory(lname) < sd->msglen) {
+           ofile = (char *) realloc_pool_memory(ofile, sd->msglen + 1);
+        }
+        *fname = 0;
+        *lname = 0;
+
+        /*              
+         * An Attributes record consists of:
+         *    File_index
+         *    Type   (FT_types)
+         *    Filename
+         *    Attributes
+         *    Link name (if file linked i.e. FT_LNK)
+         *
+         */
+         if (sscanf(sd->msg, "%d %d %s", &record_file_index, &type, fname) != 3) {
+            Emsg1(M_FATAL, 0, _("Error scanning record header: %s\n"), sd->msg);
+           /** ****FIXME**** need to cleanup */
+            Dmsg0(0, "\nError scanning header\n");
+           return;  
+        }
+         Dmsg3(30, "Got Attr: FilInx=%d type=%d fname=%s\n", record_file_index,
+           type, fname);
+        if (record_file_index != file_index) {
+            Emsg2(M_ABORT, 0, _("Record header file index %ld not equal record index %ld\n"),
+              file_index, record_file_index);
+            Dmsg0(0, "File index error\n");
+        }
+        ap = sd->msg;
+        /* Skip to attributes */
+        while (*ap++ != 0) {
+           ;
+        }
+        /* Skip to Link name */
+        if (type == FT_LNK) {
+           lp = ap;
+           while (*lp++ != 0) {
+              ;
+           }
+            strcat(lname, lp);        /* "save" link name */
+        } else {
+           *lname = 0;
+        }
+
+        decode_stat(ap, &statp);
+        /*
+         * Prepend the where directory so that the
+         * files are put where the user wants.
+         *
+         * We do a little jig here to handle Win32 files with
+         * a drive letter.  
+         *   If where is null and we are running on a win32 client,
+         *      change nothing.
+         *   Otherwise, if the second character of the filename is a
+         *   colon (:), change it into a slash (/) -- this creates
+         *   a reasonable pathname on most systems.
+         */
+        if (jcr->where[0] == 0 && win32_client) {
+           strcpy(ofile, fname);
+        } else {
+           strcpy(ofile, jcr->where);
+            if (fname[1] == ':') {
+               fname[1] = '/';
+              strcat(ofile, fname);
+               fname[1] = ':';
+           } else {
+              strcat(ofile, fname);
+           }
+        }
+
+         Dmsg1(30, "Outfile=%s\n", ofile);
+        print_ls_output(jcr, ofile, lname, type, &statp);
+
+        extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd);
+         Dmsg1(40, "Extract=%d\n", extract);
+        if (extract) {
+           jcr->JobFiles++;
+        }
+        jcr->num_files_examined++;
+
+      /* Data stream */
+      } else if (stream == STREAM_FILE_DATA) {
+        if (extract) {
+            Dmsg2(30, "Write %d bytes, total before write=%d\n", sd->msglen, total);
+           if (write(ofd, sd->msg, sd->msglen) != sd->msglen) {
+               Dmsg0(0, "===Write error===\n");
+               Jmsg2(jcr, M_ERROR, 0, "Write error on %s: %s\n", ofile, strerror(errno));
+              free_pool_memory(fname);
+              free_pool_memory(ofile);
+              free_pool_memory(lname);
+              return;
+           }
+           total += sd->msglen;
+           jcr->JobBytes += sd->msglen;
+        }
+
+      /* If extracting, wierd stream (not 1 or 2), close output file anyway */
+      } else if (extract) {
+         Dmsg1(30, "Found wierd stream %d\n", stream);
+        if (ofd < 0) {
+            Emsg0(M_ABORT, 0, _("Logic error output file should be open\n"));
+        }
+        close(ofd);
+        ofd = -1;
+        extract = FALSE;
+        set_statp(jcr, fname, ofile, lname, type, &statp);
+      } else if (stream != STREAM_MD5_SIGNATURE) {
+         Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
+      }
+   }
+
+   /* If output file is still open, it was the last one in the
+    * archive since we just hit an end of file, so close the file. 
+    */
+   if (ofd >= 0) {
+      close(ofd);
+      set_statp(jcr, fname, ofile, lname, type, &statp);
+   }
+
+   free_pool_memory(fname);
+   free_pool_memory(ofile);
+   free_pool_memory(lname);
+   Dmsg2(10, "End Do Restore. Files=%d Bytes=%" lld "\n", jcr->JobFiles,
+      jcr->JobBytes);
+}         
+
+extern char *getuser(uid_t uid);
+extern char *getgroup(gid_t gid);
+
+/*
+ * Print an ls style message, also send INFO
+ */
+static void print_ls_output(JCR *jcr, char *fname, char *lname, int type, struct stat *statp)
+{
+   /* ********FIXME******** make memory pool */
+   char buf[1000]; 
+   char *p, *f;
+   int n;
+
+   p = encode_mode(statp->st_mode, buf);
+   n = sprintf(p, "  %2d ", (uint32_t)statp->st_nlink);
+   p += n;
+   n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid));
+   p += n;
+   n = sprintf(p, "%8" lld " ", (uint64_t)statp->st_size);
+   p += n;
+   p = encode_time(statp->st_ctime, p);
+   *p++ = ' ';
+   *p++ = ' ';
+   for (f=fname; *f; )
+      *p++ = *f++;
+   if (type == FT_LNK) {
+      *p++ = ' ';
+      *p++ = '-';
+      *p++ = '>';
+      *p++ = ' ';
+      /* Copy link name */
+      for (f=lname; *f; )
+        *p++ = *f++;
+   }
+   *p++ = '\n';
+   *p = 0;
+   Dmsg0(20, buf);
+   Jmsg(jcr, M_INFO, 0, buf);
+}
diff --git a/bacula/src/filed/status.c b/bacula/src/filed/status.c
new file mode 100755 (executable)
index 0000000..da15c6f
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *  Bacula File Daemon Status routines
+ *
+ *    Kern Sibbald, August MMI
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "filed.h"
+
+extern char my_name[];
+extern struct s_last_job last_job;
+extern time_t daemon_start_time;
+
+/*
+ * General status generator
+ */
+static void do_status(void sendit(char *msg, int len, void *sarg), void *arg) 
+{
+   int sec, bps;
+   char *msg, b1[32], b2[32], b3[32];
+   int found, len;
+   JCR *njcr;
+   char dt[MAX_TIME_LENGTH];
+
+   msg = (char *)get_pool_memory(PM_MESSAGE);
+   found = 0;
+   len = Mmsg(&msg, "%s Version: " VERSION " (" DATE ")\n", my_name);
+   sendit(msg, len, arg);
+   bstrftime(dt, sizeof(dt), daemon_start_time);
+   len = Mmsg(&msg, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs,
+        last_job.NumJobs == 1 ? "" : "s");
+   sendit(msg, len, arg);
+   if (last_job.NumJobs > 0) {
+      char *termstat, jstat[2];
+
+      bstrftime(dt, sizeof(dt), last_job.end_time);
+      len = Mmsg(&msg, _("Last Job %s finished at %s\n"), last_job.Job, dt);
+      sendit(msg, len, arg);
+      switch (last_job.JobStatus) {
+        case JS_Terminated:
+            termstat = "OK";
+           break;
+       case JS_ErrorTerminated:
+            termstat = "Error";
+           break;
+       default:
+           jstat[0] = last_job.JobStatus;
+           jstat[1] = 0;
+           termstat = jstat;
+           break;
+      }
+          
+      len = Mmsg(&msg, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
+          edit_uint_with_commas(last_job.JobFiles, b1),
+          edit_uint_with_commas(last_job.JobBytes, b2),
+          termstat);
+      sendit(msg, len, arg);
+   }
+   lock_jcr_chain();
+   for (njcr=NULL; (njcr=get_next_jcr(njcr)); ) {
+      bstrftime(dt, sizeof(dt), njcr->start_time);
+      if (njcr->JobId == 0) {
+         len = Mmsg(&msg, _("Director connected at: %s\n"), dt);
+      } else {
+         len = Mmsg(&msg, _("JobId %d Job %s is running. Started: %s\n"), 
+            njcr->JobId, njcr->Job, dt);
+      }
+      sendit(msg, len, arg);
+      if (njcr->JobId == 0) {
+        free_locked_jcr(njcr);
+        continue;
+      }
+      sec = time(NULL) - njcr->start_time;
+      if (sec <= 0) {
+        sec = 1;
+      }
+      bps = njcr->JobBytes / sec;
+      len = Mmsg(&msg,  _("    Files=%s Bytes=%s Bytes/sec=%s\n"), 
+          edit_uint_with_commas(njcr->JobFiles, b1),
+          edit_uint_with_commas(njcr->JobBytes, b2),
+          edit_uint_with_commas(bps, b3));
+      sendit(msg, len, arg);
+      len = Mmsg(&msg, _("    Files Examined=%s\n"), 
+          edit_uint_with_commas(njcr->num_files_examined, b1));
+      sendit(msg, len, arg);
+      if (njcr->JobFiles > 0) {
+         len = Mmsg(&msg, _("    Processing file: %s\n"), njcr->last_fname);
+        sendit(msg, len, arg);
+      }
+
+      found = 1;
+      if (njcr->store_bsock) {
+         len = Mmsg(&msg, "    SDReadSeqNo=%" lld " fd=%d\n",
+            njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
+        sendit(msg, len, arg);
+      } else {
+         len = Mmsg(&msg, _("    SDSocket closed.\n"));
+        sendit(msg, len, arg);
+      }
+      free_locked_jcr(njcr);
+   }
+   unlock_jcr_chain();
+   if (!found) {
+      len = Mmsg(&msg, _("No jobs running.\n"));
+      sendit(msg, len, arg);
+   }
+   free_pool_memory(msg);
+}
+
+/*
+ * Send to Director 
+ */
+static void sendit(char *msg, int len, void *arg)
+{
+   BSOCK *user = (BSOCK *)arg;
+
+   memcpy(user->msg, msg, len+1);
+   user->msglen = len+1;
+   bnet_send(user);
+}
+                                  
+/*
+ * Status command from Director
+ */
+int status_cmd(JCR *jcr)
+{
+   BSOCK *user = jcr->dir_bsock;
+
+   bnet_fsend(user, "\n");
+   do_status(sendit, (void *)user);
+   bnet_fsend(user, "====\n");
+
+   bnet_sig(user, BNET_EOF);
+   return 1;
+}
+
+
+#ifdef HAVE_CYGWIN
+#include <windows.h>
+
+static char buf[100];
+int bacstat = 0;
+
+struct s_win32_arg {
+   HWND hwnd;
+   int idlist;
+};
+
+/*
+ * Put message in Window List Box
+ */
+static void win32_sendit(char *msg, int len, void *marg)
+{
+   struct s_win32_arg *arg = (struct s_win32_arg *)marg;
+
+   if (len > 0) {
+      msg[len-1] = 0;                /* eliminate newline */
+   }
+   SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
+   
+}
+
+void FillStatusBox(HWND hwnd, int idlist)
+{
+   struct s_win32_arg arg;
+
+   arg.hwnd = hwnd;
+   arg.idlist = idlist;
+
+   /* Empty box */
+   for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
+      { }
+   do_status(win32_sendit, (void *)&arg);
+}
+
+char *bac_status(int stat)
+{
+   JCR *njcr;
+   char *termstat = _("Bacula Idle");
+
+   bacstat = 0;
+   if (last_job.NumJobs > 0) {
+      switch (last_job.JobStatus) {
+       case JS_ErrorTerminated:
+           bacstat = -1;
+            termstat = _("Last Job Erred");
+           break;
+       default:
+           break;
+      }
+   }
+   lock_jcr_chain();
+   for (njcr=NULL; (njcr=get_next_jcr(njcr)); ) {
+      if (njcr->JobId != 0) {
+        bacstat = 1;
+         termstat = _("Bacula Running");
+        free_locked_jcr(njcr);
+        break;
+      }
+      free_locked_jcr(njcr);
+   }
+   unlock_jcr_chain();
+   strcpy(buf, termstat);
+   return buf;
+}
+
+#endif /* HAVE_CYGWIN */
diff --git a/bacula/src/filed/verify.c b/bacula/src/filed/verify.c
new file mode 100644 (file)
index 0000000..67eab1f
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ *  Bacula File Daemon verify.c  Verify files.
+ *
+ *    Kern Sibbald, October MM
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "filed.h"
+
+static int verify_file(FF_PKT *ff_pkt, void *my_pkt);
+
+/* 
+ * Find all the requested files and send attributes
+ * to the Director.
+ * 
+ */
+void do_verify(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   
+   jcr->buf_size = MAX_NETWORK_BUFFER_SIZE;
+   if ((jcr->big_buf = (char *) malloc(jcr->buf_size)) == NULL) {
+      Emsg1(M_ABORT, 0, _("Cannot malloc %d network read buffer\n"), MAX_NETWORK_BUFFER_SIZE);
+   }
+   set_find_options(jcr->ff, jcr->incremental, jcr->mtime);
+   Dmsg0(10, "Start find files\n");
+   /* Subroutine verify_file() is called for each file */
+   if (!find_files(jcr->ff, verify_file, (void *)jcr)) {
+      /****FIXME**** error termination */
+      Dmsg0(0, "========= Error return from find_files\n");
+   }
+   Dmsg0(10, "End find files\n");
+
+   dir->msglen = 0;
+   bnet_send(dir);                   /* signal end attributes to director */
+   if (jcr->big_buf) {
+      free(jcr->big_buf);
+      jcr->big_buf = NULL;
+   }
+}         
+
+/* 
+ * Called here by find() for each file.
+
+    *****FIXME*****   add FSMs File System Modules
+ *
+ *  Find the file, compute the MD5 and send it back to the Director
+ */
+static int verify_file(FF_PKT *ff_pkt, void *pkt) 
+{
+   char attribs[MAXSTRING];
+   int32_t n;
+   int fid;
+   struct MD5Context md5c;
+   unsigned char signature[16];
+   BSOCK *sd, *dir;
+   JCR *jcr = (JCR *)pkt;
+
+   sd = jcr->store_bsock;
+   dir = jcr->dir_bsock;
+
+   switch (ff_pkt->type) {
+   case FT_LNKSAVED:                 /* Hard linked, file already saved */
+      break;
+   case FT_REGE:
+      Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
+      break;
+   case FT_REG:
+      Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
+      break;
+   case FT_LNK:
+      Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
+      break;
+   case FT_DIR:
+      Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
+      break;
+   case FT_SPEC:
+      Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
+      break;
+   case FT_NOACCESS:
+      Jmsg(jcr, M_ERROR, -1, _("     Could not access %s: ERR=%s\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno));
+      return 1;
+   case FT_NOFOLLOW:
+      Jmsg(jcr, M_ERROR, -1, _("     Could not follow link %s: ERR=%s\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno));
+      return 1;
+   case FT_NOSTAT:
+      Jmsg(jcr, M_ERROR, -1, _("      Could not stat %s: ERR=%s\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno));
+      return 1;
+   case FT_DIRNOCHG:
+   case FT_NOCHG:
+      Jmsg(jcr, M_INFO, -1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
+      return 1;
+   case FT_ISARCH:
+      Jmsg(jcr, M_SKIPPED, -1, _("     Archive file skipped: %s\n"), ff_pkt->fname);
+      return 1;
+   case FT_NORECURSE:
+      Jmsg(jcr, M_SKIPPED, -1, _("     Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
+      return 1;
+   case FT_NOFSCHG:
+      Jmsg(jcr, M_SKIPPED, -1, _("     File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
+      return 1;
+   case FT_NOOPEN:
+      Jmsg(jcr, M_ERROR, -1, _("     Could not open directory %s: ERR=%s\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno));
+      return 1;
+   default:
+      Jmsg(jcr, M_ERROR, 0, _("Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
+      return 1;
+   }
+
+   if ((fid = open(ff_pkt->fname, O_RDONLY | O_BINARY)) < 0) {
+      ff_pkt->ff_errno = errno;
+      Jmsg(jcr, M_ERROR, -1, _("  Cannot open %s: ERR=%s.\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno));
+      return 1;
+   }
+
+   Dmsg2(50, "opened %s fid=%d\n", ff_pkt->fname, fid);
+   Dmsg1(10, "bfiled: sending %s to Director\n", ff_pkt->fname);
+   encode_stat(attribs, &ff_pkt->statp);
+     
+   jcr->JobFiles++;                 /* increment number of files sent */
+    
+   if (ff_pkt->VerifyOpts[0] == 0) {
+      ff_pkt->VerifyOpts[0] = 'V';
+      ff_pkt->VerifyOpts[1] = 0;
+   }
+   /* Send file attributes to Director (note different format than for Storage) */
+   if (ff_pkt->type == FT_LNK) {
+      dir->msglen = sprintf(dir->msg,"%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
+                   STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, 
+                   0, attribs, 0, ff_pkt->link, 0);
+   } else {
+      dir->msglen = sprintf(dir->msg,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
+                   STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, 
+                   0, attribs, 0, 0);
+   }
+   Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
+   bnet_send(dir);           /* send to Director */
+
+
+   /* 
+    * If MD5 is requested, read the file and compute the MD5   
+    *
+    */
+   if (ff_pkt->flags & FO_MD5) {
+      char MD5buf[50];               /* 24 should do */
+
+      MD5Init(&md5c);
+
+      if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode) && 
+           ff_pkt->statp.st_size > 0) {
+        while ((n=read(fid, jcr->big_buf, jcr->buf_size)) > 0) {
+           MD5Update(&md5c, ((unsigned char *) jcr->big_buf), n);
+           jcr->JobBytes += n;
+        }
+        if (n < 0) {
+            Jmsg(jcr, M_ERROR, -1, _("  Error reading %s: ERR=%s\n"), ff_pkt->fname, strerror(ff_pkt->ff_errno));
+        }
+      }
+
+      MD5Final(signature, &md5c);
+
+      bin_to_base64(MD5buf, (char *)signature, 16); /* encode 16 bytes */
+      dir->msglen = sprintf(dir->msg, "%d %d %s X", jcr->JobFiles, 
+        STREAM_MD5_SIGNATURE, MD5buf);
+      Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg);
+      bnet_send(dir);               /* send MD5 signature to Director */
+   }
+   close(fid);
+   return 1;
+}
diff --git a/bacula/src/filed/win32/Makefile.in b/bacula/src/filed/win32/Makefile.in
new file mode 100755 (executable)
index 0000000..d0426e8
--- /dev/null
@@ -0,0 +1,112 @@
+#
+# makefile to build Windows specific pieces of the Bacula File daemon
+#
+CFLAGS=@CFLAGS@
+CC = @CC@
+RANLIB = @RANLIB@
+SHELL = /bin/sh
+
+# Program to install `make'.
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+# Program to install the man page.
+INSTALL_DATA = @INSTALL_DATA@
+# Generic install program.
+INSTALL = @INSTALL@
+
+VERSION = @VERSION@
+
+
+# this dir
+srcdir = .
+# main dir
+topdir = ../../..
+# this dir relative to top dir
+thisdir = src/filed/win32
+
+# Common prefix for machine-independent installed files.
+prefix = @prefix@
+sysconfdir = @sysconfdir@
+sbindir = @sbindir@
+piddir = @piddir@
+
+SRCS = shutdown.c
+
+OBJS = shutdown.o
+
+BACOBJS = winabout.o winevents.o winservice.o winstat.o wintray.o winmain.o
+
+all: winlib.a winres.res 
+
+win32: winlib.a
+
+winlib.a: $(BACOBJS) winres.res
+       ar rc $@ $(BACOBJS)
+       $(RANLIB) $@
+
+winres.res: winres.rc bacula.ico winres.h idle.ico running.ico error.ico
+       windres $< -O coff -o $@
+
+winmain.o: winmain.cpp winbacula.h
+       $(CC) -c $(CFLAGS) $<
+
+email.o: email.c
+       $(CC) -c ${CFLAGS} $<
+
+email.exe: email.o libmymapi32.a
+       $(CC) ${CFLAGS} -L. -o email email.o -luser32 -lgdi32 -lmymapi32
+
+libmymapi32.a: mymapi32.def
+       dlltool --as=as -k --output-lib $@ --def $<
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+clean:
+       rm -f *.exe *.o *.res *.a 1 2 3
+       rm -f bin/bacula-fd.exe bin/smtp.exe
+
+distclean: clean
+       rm -f Makefile
+
+install:
+       @mkdir -p $(sbindir) /tmp $(sbindir)/../working
+       @echo "Installing system binary files ..."
+       @strip ../bacula-fd.exe
+       @strip ../../lib/smtp.exe
+       @cp -f ../bacula-fd.exe bin/
+       @cp -f ../../lib/smtp.exe bin/
+       @cp -f bin/* $(sbindir)
+
+# Make a Win32 binary release 
+binary-release:
+       @rm -rf wr
+       @mkdir -p wr
+       @mkdir -p wr/$(prefix) wr/$(sbindir) wr/$(sbindir)/../working wr/$(sysconfdir) wr/tmp
+       @echo "Copying system binary files ..."
+       @cp bin/* wr/$(sbindir)
+       @strip ../bacula-fd.exe
+       @strip ../../lib/smtp.exe
+       @echo "Copying executables ..."
+       @cp -f ../bacula-fd.exe wr/$(sbindir)/bacula-fd.exe 
+       @cp -f ../../lib/smtp.exe wr/$(sbindir)/smtp.exe 
+       @echo "Copying bacula-fd.conf..."
+       @cp -f ../bacula-fd.conf wr/$(sysconfdir)/bacula-fd.conf
+# the two dummy files are necessary to insure that WinZip
+# actually creates the directories.
+       @echo "dummy" >wr/tmp/dummy.txt
+       @echo "dummy" >wr/$(sbindir)/../working/dummy.txt
+       @echo "Making tar file ..."
+       @tar cfz winbacula-${VERSION}.tar.gz -C wr bacula tmp
+       @mv -f winbacula-${VERSION}.tar.gz $(topdir)/..
+       @rm -rf wr
+       @(cd $(topdir)/..; \
+          echo "Tar file in: `pwd`/winbacula-${VERSION}.tar.gz")
+
+dummy:
+
+.c.o:
+       $(CC) -c $(CFLAGS) $<
+
+.cpp.o:
+       $(CC) -c $(CFLAGS) $<
diff --git a/bacula/src/filed/win32/bacula.bmp b/bacula/src/filed/win32/bacula.bmp
new file mode 100644 (file)
index 0000000..9db8e64
Binary files /dev/null and b/bacula/src/filed/win32/bacula.bmp differ
diff --git a/bacula/src/filed/win32/bacula.ico b/bacula/src/filed/win32/bacula.ico
new file mode 100644 (file)
index 0000000..f6d50bf
Binary files /dev/null and b/bacula/src/filed/win32/bacula.ico differ
diff --git a/bacula/src/filed/win32/bacula.rc b/bacula/src/filed/win32/bacula.rc
new file mode 100644 (file)
index 0000000..5849beb
--- /dev/null
@@ -0,0 +1 @@
+1 ICON  "apcupsd.ico"
diff --git a/bacula/src/filed/win32/bin/Install.bat b/bacula/src/filed/win32/bin/Install.bat
new file mode 100755 (executable)
index 0000000..cc4ccf5
--- /dev/null
@@ -0,0 +1,2 @@
+cd c:\bacula\bin
+c:\bacula\bin\bacula-fd.exe /install -c c:\bacula\bin\bacula-fd.conf
diff --git a/bacula/src/filed/win32/bin/Start.bat b/bacula/src/filed/win32/bin/Start.bat
new file mode 100755 (executable)
index 0000000..1adb6c2
--- /dev/null
@@ -0,0 +1,2 @@
+cd c:\bacula\bin
+c:\bacula\bin\bacula-fd.exe /service -c c:\bacula\bin\bacula-fd.conf
diff --git a/bacula/src/filed/win32/bin/Stop.bat b/bacula/src/filed/win32/bin/Stop.bat
new file mode 100755 (executable)
index 0000000..d668499
--- /dev/null
@@ -0,0 +1,2 @@
+cd c:\bacula\bin
+c:\bacula\bin\bacula-fd.exe /kill
diff --git a/bacula/src/filed/win32/bin/Uninstall.bat b/bacula/src/filed/win32/bin/Uninstall.bat
new file mode 100755 (executable)
index 0000000..4a7db53
--- /dev/null
@@ -0,0 +1,2 @@
+cd c:\bacula\bin
+c:\bacula\bin\bacula-fd.exe /remove
diff --git a/bacula/src/filed/win32/bin/btraceback b/bacula/src/filed/win32/bin/btraceback
new file mode 100755 (executable)
index 0000000..6f91c8d
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+# 
+# Script to do a stackdump of a Bacula daemon/program.
+#
+# We attempt to attach to running program
+#
+# Arguments to this script are
+#  $1 = path to executable
+#  $2 = main pid of running program to be traced back.
+#
+
+gdb -quiet -batch -x /bacula/bin/btraceback.gdb $1 $2 2>&1 | mail -s "Bacula traceback" root
+
+# Below is some old code that did the traceback from a core
+#  dump. However, for some odd reason, core dumps are not
+#  always produced.
+#i=0
+#core=
+#echo "In modified btraceback"
+#echo "$1 $2"
+#pwd
+#while [ "$i" -lt 60 ] ; do
+#  if [ -f core ] ; then
+#     break;
+#  fi
+#  if [ -f core.$2 ] ; then
+#     core=core.$2
+#     break 
+#  fi 
+#  sleep 1
+#  i=`expr $i + 1`
+#done
+
+#if test x$core != x; then
+#   gdb -quiet -batch -x /home/kern/bacula/bin/btraceback.gdb $1 $core 2>&1 | mail -s "Bacula traceback" kern@sibbald.com
+#else
+#   gdb -quiet -batch -x /home/kern/bacula/bin/btraceback.gdb $1 $2 2>&1 | mail -s "Bacula traceback" kern@sibbald.com
+#fi
diff --git a/bacula/src/filed/win32/bin/btraceback.gdb b/bacula/src/filed/win32/bin/btraceback.gdb
new file mode 100755 (executable)
index 0000000..74e1f23
--- /dev/null
@@ -0,0 +1,23 @@
+print my_name
+print exename
+print exepath
+bt
+thread apply all bt
+f 0
+info locals
+f 1
+info locals
+f 2
+info locals
+f 3
+info locals
+f 4
+info locals
+f 5 
+info locals
+f 6
+info locals
+f 7
+info locals
+detach
+quit
diff --git a/bacula/src/filed/win32/bin/cygwin1.dll b/bacula/src/filed/win32/bin/cygwin1.dll
new file mode 100755 (executable)
index 0000000..110da8c
Binary files /dev/null and b/bacula/src/filed/win32/bin/cygwin1.dll differ
diff --git a/bacula/src/filed/win32/bin/setup.bat b/bacula/src/filed/win32/bin/setup.bat
new file mode 100755 (executable)
index 0000000..86d0f0e
--- /dev/null
@@ -0,0 +1,11 @@
+rem 
+rem  perform installation of bacula on Win32 systems
+rem
+c:
+cd \
+mkdir tmp
+cd c:\bacula\bin
+path=c:\bacula\bin
+umount --remove-all-mounts
+mount -f c:\ /
+c:\bacula\bin\bacula-fd.exe /install -c c:\bacula\bin\bacula-fd.conf
diff --git a/bacula/src/filed/win32/error.ico b/bacula/src/filed/win32/error.ico
new file mode 100644 (file)
index 0000000..a8f85f1
Binary files /dev/null and b/bacula/src/filed/win32/error.ico differ
diff --git a/bacula/src/filed/win32/idle.ico b/bacula/src/filed/win32/idle.ico
new file mode 100644 (file)
index 0000000..ce5315f
Binary files /dev/null and b/bacula/src/filed/win32/idle.ico differ
diff --git a/bacula/src/filed/win32/mymapi32.def b/bacula/src/filed/win32/mymapi32.def
new file mode 100644 (file)
index 0000000..42f0bfe
--- /dev/null
@@ -0,0 +1,151 @@
+LIBRARY MAPI32.DLL
+EXPORTS
+MAPISendMail@20
+BuildDisplayTable@40
+CbOfEncoded@4
+CchOfEncoding@4
+ChangeIdleRoutine@28
+CloseIMsgSession@4
+CreateIProp@24
+CreateTable@36
+DeinitMapiUtil@0
+DeregisterIdleRoutine@4
+EnableIdleRoutine@8
+EncodeID@12
+FBadColumnSet@4
+FBadEntryList@4
+FBadProp@4
+FBadPropTag@4
+FBadRestriction@4
+FBadRglpNameID@8
+FBadRglpszA@8
+FBadRglpszW@8
+FBadRow@4
+FBadRowSet@4
+FBadSortOrderSet@4
+FBinFromHex@8
+FDecodeID@12
+FEqualNames@8
+FPropCompareProp@12
+FPropContainsProp@12
+FPropExists@8
+FreePadrlist@4
+FreeProws@4
+FtAdcFt@20
+FtAddFt@16
+FtDivFtBogus@20
+FtMulDw@12
+FtMulDwDw@8
+FtNegFt@8
+FtSubFt@16
+FtgRegisterIdleRoutine@20
+GetAttribIMsgOnIStg@12
+GetTnefStreamCodepage
+GetTnefStreamCodepage@12
+HexFromBin@12
+HrAddColumns@16
+HrAddColumnsEx@20
+HrAllocAdviseSink@12
+HrComposeEID@28
+HrComposeMsgID@24
+HrDecomposeEID@28
+HrDecomposeMsgID@24
+HrDispatchNotifications@4
+HrEntryIDFromSz@12
+HrGetOneProp@12
+HrIStorageFromStream@16
+HrQueryAllRows@24
+HrSetOneProp@8
+HrSzFromEntryID@12
+HrThisThreadAdviseSink@8
+HrValidateIPMSubtree@20
+HrValidateParameters@8
+InstallFilterHook@4
+IsBadBoundedStringPtr@8
+LAUNCHWIZARD
+LPropCompareProp@8
+LaunchWizard@20
+LpValFindProp@12
+MAPIAdminProfiles
+MAPIAdminProfiles@8
+MAPIAllocateBuffer
+MAPIAllocateBuffer@8
+MAPIAllocateMore
+MAPIAllocateMore@12
+MAPIDeinitIdle@0
+MAPIFreeBuffer
+MAPIFreeBuffer@4
+MAPIGetDefaultMalloc@0
+MAPIInitIdle@4
+MAPIInitialize
+MAPIInitialize@4
+MAPILogonEx
+MAPILogonEx@20
+MAPIOpenFormMgr
+MAPIOpenFormMgr@8
+MAPIOpenLocalFormContainer
+MAPIOpenLocalFormContainer@4
+MAPIUninitialize
+MAPIUninitialize@0
+MNLS_CompareStringW@24
+MNLS_IsBadStringPtrW@8
+MNLS_MultiByteToWideChar@24
+MNLS_WideCharToMultiByte@32
+MNLS_lstrcmpW@8
+MNLS_lstrcpyW@8
+MNLS_lstrlenW@4
+MapStorageSCode@4
+OpenIMsgOnIStg@44
+OpenIMsgSession@12
+OpenStreamOnFile
+OpenStreamOnFile@24
+OpenTnefStream
+OpenTnefStream@28
+OpenTnefStreamEx
+OpenTnefStreamEx@32
+PRProviderInit
+PpropFindProp@12
+PropCopyMore@16
+RTFSync
+RTFSync@12
+ScBinFromHexBounded@12
+ScCopyNotifications@16
+ScCopyProps@16
+ScCountNotifications@12
+ScCountProps@12
+ScCreateConversationIndex@16
+ScDupPropset@16
+ScGenerateMuid@4
+ScInitMapiUtil@4
+ScLocalPathFromUNC@12
+ScMAPIXFromCMC
+ScMAPIXFromSMAPI
+ScRelocNotifications@20
+ScRelocProps@20
+ScSplEntry
+ScUNCFromLocalPath@12
+SetAttribIMsgOnIStg@16
+SwapPlong@8
+SwapPword@8
+SzFindCh@8
+SzFindLastCh@8
+SzFindSz@8
+UFromSz@4
+UNKOBJ_COFree@8
+UNKOBJ_Free@8
+UNKOBJ_FreeRows@8
+UNKOBJ_ScAllocate@12
+UNKOBJ_ScAllocateMore@16
+UNKOBJ_ScCOAllocate@12
+UNKOBJ_ScCOReallocate@12
+UNKOBJ_ScSzFromIdsAlloc@20
+UlAddRef@4
+UlFromSzHex@4
+UlPropSize@4
+UlRelease@4
+WrapCompressedRTFStream
+WrapCompressedRTFStream@12
+WrapProgress@20
+WrapStoreEntryID@24
+__CPPValidateParameters@8
+__ValidateParameters@8
diff --git a/bacula/src/filed/win32/popup.c b/bacula/src/filed/win32/popup.c
new file mode 100644 (file)
index 0000000..c556fa8
--- /dev/null
@@ -0,0 +1,47 @@
+/* 
+ * Dumb Windows program to put up a message box
+ * containing the command line.  Any leading and
+ * trailing quotes are stripped.
+ * 
+ *  Kern E. Sibbald
+ *   July MM  
+ */
+#include "windows.h"
+
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
+                  PSTR szCmdLine, int iCmdShow)
+{
+   int len = strlen(szCmdLine);
+   char *msg, *wordPtr;
+
+   // Funny things happen with the command line if the
+   // execution comes from c:/Program Files/apcupsd/apcupsd.exe
+   // We get a command line like: Files/apcupsd/apcupsd.exe" options
+   // I.e. someone stops scanning command line on a space, not
+   // realizing that the filename is quoted!!!!!!!!!!
+   // So if first character is not a double quote and
+   // the last character before first space is a double
+   // quote, we throw away the junk.
+   wordPtr = szCmdLine;
+   while (*wordPtr && *wordPtr != ' ')
+      wordPtr++;
+   if (wordPtr > szCmdLine)     // backup to char before space
+      wordPtr--;
+   // if first character is not a quote and last is, junk it
+   if (*szCmdLine != '"' && *wordPtr == '"') {
+      wordPtr++;
+      while (*wordPtr && *wordPtr == ' ')
+        wordPtr++;              /* strip leading spaces */
+      szCmdLine = wordPtr;
+      len = strlen(szCmdLine);
+   }
+
+   msg = szCmdLine;
+   if (*szCmdLine == '"' && len > 0 && szCmdLine[len-1] == '"') {
+      msg = szCmdLine + 1;
+      szCmdLine[len-1] = 0;
+   }
+   MessageBox(NULL, msg, "Apcupsd message", MB_OK);
+   return 0;
+}
diff --git a/bacula/src/filed/win32/running.ico b/bacula/src/filed/win32/running.ico
new file mode 100644 (file)
index 0000000..32dc42c
Binary files /dev/null and b/bacula/src/filed/win32/running.ico differ
diff --git a/bacula/src/filed/win32/saving.ico b/bacula/src/filed/win32/saving.ico
new file mode 100644 (file)
index 0000000..f6d50bf
Binary files /dev/null and b/bacula/src/filed/win32/saving.ico differ
diff --git a/bacula/src/filed/win32/winabout.cpp b/bacula/src/filed/win32/winabout.cpp
new file mode 100755 (executable)
index 0000000..6b1095e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+   This file is patterned after the VNC Win32 code by ATT
+  
+   Copyright (2000) Kern E. Sibbald
+*/
+
+#include "winbacula.h"
+#include "winabout.h"
+
+bacAbout::bacAbout()
+{
+   visible = FALSE;
+}
+
+bacAbout::~bacAbout()
+{
+}
+
+void bacAbout::Show(BOOL show)
+{
+   if (show && !visible) {
+      DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_ABOUT), NULL,
+         (DLGPROC)DialogProc, (LONG)this);
+   }
+}
+
+BOOL CALLBACK
+bacAbout::DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+   /* The dialog-box this pointer is in USERDATA */
+   bacAbout *_this = (bacAbout *)GetWindowLong(hwnd, GWL_USERDATA);
+
+   switch (uMsg) {
+   case WM_INITDIALOG:
+      /* Retrieve the Dialog box parameter */
+      SetWindowLong(hwnd, GWL_USERDATA, lParam);
+      _this = (bacAbout *)lParam;
+
+      /* Show the dialog */
+      SetForegroundWindow(hwnd);
+      _this->visible = TRUE;
+      return TRUE;
+
+   case WM_COMMAND:
+      switch (LOWORD(wParam)) {
+      case IDCANCEL:
+      case IDOK:
+         EndDialog(hwnd, TRUE);
+         _this->visible = FALSE;
+         return TRUE;
+      }
+      break;
+
+   case WM_DESTROY:
+      EndDialog(hwnd, FALSE);
+      _this->visible = FALSE;
+      return TRUE;
+   }
+   return 0;
+}
diff --git a/bacula/src/filed/win32/winabout.h b/bacula/src/filed/win32/winabout.h
new file mode 100755 (executable)
index 0000000..9d4d086
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+   This file was inspired by the VNC Win32 code by ATT
+  
+   Copyright (2000) Kern E. Sibbald
+*/
+
+
+/* Object implementing the About dialog for Bacula */
+
+class bacAbout;
+
+#ifndef _WINABOUT_H_
+#define _WINABOUT_H_ 1
+
+/* Define the bacAbout class */
+class bacAbout
+{
+public:
+   bacAbout();
+   ~bacAbout();
+
+   /* The dialog box window proc */
+   static BOOL CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+   void Show(BOOL show);
+
+   /* Object local storage */
+   BOOL visible;
+};
+
+#endif
diff --git a/bacula/src/filed/win32/winbacula.h b/bacula/src/filed/win32/winbacula.h
new file mode 100755 (executable)
index 0000000..f57cf1b
--- /dev/null
@@ -0,0 +1,83 @@
+//  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+//  This file was part of the VNC system.
+//
+//  The VNC system 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.
+//
+// If the source code for the VNC system is not available from the place 
+// whence you received this file, check http://www.uk.research.att.com/vnc or contact
+// the authors on vnc@uk.research.att.com for information on obtaining it.
+//
+// This file has been adapted to the Win32 version of Bacula
+// by Kern E. Sibbald.  Many thanks to ATT and James Weatherall,
+// the original author, for providing an excellent template.
+//
+// Copyright (2000) Kern E. Sibbald
+//
+
+
+// WinUPS header file
+
+#define STRICT
+#include <windows.h>
+#include <stdio.h>
+#include <process.h>
+#include "winres.h"
+
+// Application specific messages
+
+// Message used for system tray notifications
+#define WM_TRAYNOTIFY                           WM_USER+1
+
+// Messages used for the server object to notify windows of things
+#define WM_SRV_CLIENT_CONNECT           WM_USER+2
+#define WM_SRV_CLIENT_AUTHENTICATED     WM_USER+3
+#define WM_SRV_CLIENT_DISCONNECT        WM_USER+4
+
+// Export the application details
+extern HINSTANCE        hAppInstance;
+extern const char       *szAppName;
+extern DWORD            mainthreadId;
+
+// Main UPS server routine
+extern int BaculaAppMain();
+
+// Standard command-line flag definitions
+const char BaculaRunService[]            = "/service";
+const char BaculaRunServiceHelper[]      = "/servicehelper";
+const char BaculaRunAsUserApp[]          = "/run";
+
+const char BaculaInstallService[]        = "/install";
+const char BaculaRemoveService[]         = "/remove";
+
+#ifdef properties_implemented
+const char BaculaShowProperties[]        = "/settings";
+const char BaculaShowDefaultProperties[] = "/defaultsettings";
+#endif
+
+const char BaculaShowAbout[]             = "/about";
+const char BaculaShowStatus[]            = "/status";
+const char BaculaShowEvents[]            = "/events";
+const char BaculaKillRunningCopy[]       = "/kill";
+
+const char BaculaShowHelp[]              = "/help";
+
+// Usage string
+#ifdef properties_implemented
+const char BaculaUsageText[] = "Bacula [/run] [/kill] [/install] [/remove] [/settings] [/defaultsettings] [/about] [/status] [/evetns]\n";
+#else
+const char BaculaUsageText[] = "Bacula [/run] [/kill] [/install] [/remove] [/about] [/status] [/events]\n";
+#endif
diff --git a/bacula/src/filed/win32/winevents.cpp b/bacula/src/filed/win32/winevents.cpp
new file mode 100755 (executable)
index 0000000..6853b1a
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+   This file is patterned after the VNC Win32 code by ATT
+  
+   Copyright (2000) Kern E. Sibbald
+*/
+
+
+/* Code for the Events dialogue */
+
+#include "winbacula.h"
+#include "winevents.h"
+
+extern "C" void FillEventsBox(HWND hwnd, int id_list);
+
+bacEvents::bacEvents()
+{
+   visible = FALSE;
+}
+
+bacEvents::~bacEvents()
+{
+}
+
+/* Show the dialogue box */
+void
+bacEvents::Show(BOOL show)
+{
+   if (show && !visible) {
+      DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_EVENTS), NULL,
+         (DLGPROC)DialogProc, (LONG)this);
+   }
+}
+
+
+BOOL CALLBACK
+bacEvents::DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+   /* The dialog-box this pointer is in USERDATA */
+   bacEvents *_this = (bacEvents *)GetWindowLong(hwnd, GWL_USERDATA);
+
+   switch (uMsg) {
+   case WM_INITDIALOG:
+      /* Retrieve the Dialog box parameter */
+      SetWindowLong(hwnd, GWL_USERDATA, lParam);
+      _this = (bacEvents *)lParam;
+
+      /* Show the dialog */
+      SetForegroundWindow(hwnd);
+      _this->visible = TRUE;
+      return TRUE;
+
+   case WM_COMMAND:
+      switch (LOWORD(wParam)) {
+      case IDCANCEL:
+      case IDOK:
+         EndDialog(hwnd, TRUE);
+         _this->visible = FALSE;
+         return TRUE;
+      }
+      break;
+
+   case WM_DESTROY:
+      EndDialog(hwnd, FALSE);
+      _this->visible = FALSE;
+      return TRUE;
+   }
+   return 0;
+}
diff --git a/bacula/src/filed/win32/winevents.h b/bacula/src/filed/win32/winevents.h
new file mode 100755 (executable)
index 0000000..466760b
--- /dev/null
@@ -0,0 +1,43 @@
+/* Object implementing the Events dialog for Bacula */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+ */
+
+
+class bacEvents;
+
+#ifndef _win_bacEVENTS
+#define _win_bacEVENTS 1
+
+/* Define the bacEvents class */
+class bacEvents
+{
+public:
+   bacEvents();
+   ~bacEvents();
+
+   /* The dialog box window proc */
+   static BOOL CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+   void Show(BOOL show);
+
+   /* Object local storage */
+   BOOL visible;
+};
+
+#endif
diff --git a/bacula/src/filed/win32/winmain.cpp b/bacula/src/filed/win32/winmain.cpp
new file mode 100755 (executable)
index 0000000..7c54033
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+   This file is patterned after the VNC Win32 code by ATT
+  
+   Copyright (2000) Kern E. Sibbald
+*/
+
+#include <lmcons.h>
+#include <ctype.h>
+#include "winbacula.h"
+#include "wintray.h"
+#include "winservice.h"
+#include <signal.h>
+
+extern int BaculaMain(int argc, char **argv);
+extern int terminate_filed(int sig);
+extern DWORD g_error;
+extern BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
+
+
+HINSTANCE       hAppInstance;
+const char      *szAppName = "Bacula";
+DWORD           mainthreadId;
+
+/* Imported variables */
+extern DWORD    g_servicethread;
+
+#define MAX_COMMAND_ARGS 100
+static char *command_args[MAX_COMMAND_ARGS] = {"bacula-fd", NULL};
+static int num_command_args = 1;
+static pid_t main_pid;
+
+/*
+ * WinMain parses the command line and either calls the main App
+ * routine or, under NT, the main service routine.
+ */
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
+                   PSTR CmdLine, int iCmdShow)
+{
+   char *szCmdLine = CmdLine;
+   char *wordPtr,*tempPtr;
+   int i,quote;
+
+   /* Save the application instance and main thread id */
+   hAppInstance = hInstance;
+   mainthreadId = GetCurrentThreadId();
+
+   main_pid = getpid();
+
+   /*
+    * Funny things happen with the command line if the
+    * execution comes from c:/Program Files/bacula/bacula.exe
+    * We get a command line like: Files/bacula/bacula.exe" options
+    * I.e. someone stops scanning command line on a space, not
+    * realizing that the filename is quoted!!!!!!!!!!
+    * So if first character is not a double quote and
+    * the last character before first space is a double
+    * quote, we throw away the junk.
+    */
+   wordPtr = szCmdLine;
+   while (*wordPtr && *wordPtr != ' ')
+      wordPtr++;
+   if (wordPtr > szCmdLine)      /* backup to char before space */
+      wordPtr--;
+   /* if first character is not a quote and last is, junk it */
+   if (*szCmdLine != '"' && *wordPtr == '"')
+      szCmdLine = wordPtr + 1;
+   //      MessageBox(NULL, szCmdLine, "Cmdline", MB_OK);
+
+   /* Build Unix style argc *argv[] */      
+
+   /* Don't NULL command_args[0] !!! */
+   for (i=1;i<MAX_COMMAND_ARGS;i++)
+      command_args[i] = NULL;
+
+   wordPtr = szCmdLine;
+   quote = 0;
+   while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
+      wordPtr++;
+   if (*wordPtr == '\"') {
+      quote = 1;
+      wordPtr++;
+   } else if (*wordPtr == '/') {
+      /* Skip Windows options */
+      while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
+         wordPtr++;
+      while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
+         wordPtr++;
+   }
+   if (*wordPtr) {
+      while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
+         tempPtr = wordPtr;
+         if (quote) {
+            while (*tempPtr && *tempPtr != '\"')
+            tempPtr++;
+            quote = 0;
+         } else {
+            while (*tempPtr && *tempPtr != ' ')
+            tempPtr++;
+         }
+         if (*tempPtr)
+            *(tempPtr++) = '\0';
+         command_args[num_command_args++] = wordPtr;
+         wordPtr = tempPtr;
+         while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
+            wordPtr++;
+         if (*wordPtr == '\"') {
+            quote = 1;
+            wordPtr++;
+         }
+      }
+   }
+
+   /*
+    * Now process Windows command line options
+    *   as defined by ATT
+    *
+    * Make the command-line lowercase and parse it
+    */
+   for (i = 0; i < (int)strlen(szCmdLine); i++) {
+      szCmdLine[i] = tolower(szCmdLine[i]);
+   }
+
+   BOOL argfound = FALSE;
+   for (i = 0; i < (int)strlen(szCmdLine); i++) {
+      if (szCmdLine[i] <= ' ')
+              continue;
+
+      if (szCmdLine[i] == '-') {
+         while (szCmdLine[i] && szCmdLine[i] != ' ')
+            i++;
+         continue;
+      }
+
+      argfound = TRUE;
+
+      // Now check for command-line arguments
+
+      // /servicehelper
+      //  Used on NT to connect to Bacula
+      if (strncmp(&szCmdLine[i], BaculaRunServiceHelper, strlen(BaculaRunServiceHelper)) == 0) {
+              // NB : This flag MUST be parsed BEFORE "-service", otherwise it will match
+              // the wrong option!  (This code should really be replaced with a simple
+              // parser machine and parse-table...)
+
+              // Run the Bacula Service Helper app
+              bacService::PostUserHelperMessage();
+              return 0;
+      }
+      // /service
+      if (strncmp(&szCmdLine[i], BaculaRunService, strlen(BaculaRunService)) == 0) {
+              // Run Bacula as a service
+              return bacService::BaculaServiceMain();
+      }
+      // /run  (this is the default if no command line arguments)
+      if (strncmp(&szCmdLine[i], BaculaRunAsUserApp, strlen(BaculaRunAsUserApp)) == 0) {
+              // Bacula is being run as a user-level program
+              return BaculaAppMain();
+      }
+      // /install
+      if (strncmp(&szCmdLine[i], BaculaInstallService, strlen(BaculaInstallService)) == 0) {
+              // Install Bacula as a service
+              bacService::InstallService();
+              i+=strlen(BaculaInstallService);
+              continue;
+      }
+      // /remove
+      if (strncmp(&szCmdLine[i], BaculaRemoveService, strlen(BaculaRemoveService)) == 0) {
+              // Remove the Bacula service
+              bacService::RemoveService();
+              i+=strlen(BaculaRemoveService);
+              continue;
+      }
+
+      // /about
+      if (strncmp(&szCmdLine[i], BaculaShowAbout, strlen(BaculaShowAbout)) == 0) {
+              // Show the About dialog of an existing instance of Bacula
+              bacService::ShowAboutBox();
+              i+=strlen(BaculaShowAbout);
+              continue;
+      }
+
+      // /status
+      if (strncmp(&szCmdLine[i], BaculaShowStatus, strlen(BaculaShowStatus)) == 0) {
+              // Show the Status dialog of an existing instance of Bacula
+              bacService::ShowStatus();
+              i+=strlen(BaculaShowStatus);
+              continue;
+      }
+
+      // /events
+      if (strncmp(&szCmdLine[i], BaculaShowEvents, strlen(BaculaShowEvents)) == 0) {
+              // Show the Events dialog of an existing instance of Bacula
+              bacService::ShowEvents();
+              i+=strlen(BaculaShowEvents);
+              continue;
+      }
+
+
+      // /kill
+      if (strncmp(&szCmdLine[i], BaculaKillRunningCopy, strlen(BaculaKillRunningCopy)) == 0) {
+              // Kill any already running copy of Bacula
+              bacService::KillRunningCopy();
+              i+=strlen(BaculaKillRunningCopy);
+              continue;
+      }
+
+      // /help
+      if (strncmp(&szCmdLine[i], BaculaShowHelp, strlen(BaculaShowHelp)) == 0) {
+         MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK | MB_ICONINFORMATION);
+         i+=strlen(BaculaShowHelp);
+         continue;
+      }
+      
+      MessageBox(NULL, szCmdLine, "Bad Command Line Options", MB_OK);
+
+      // Show the usage dialog
+      MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK | MB_ICONINFORMATION);
+      break;
+   }
+
+   // If no arguments were given then just run
+   if (!argfound) {
+      BaculaAppMain();
+   }
+   return 0;
+}
+
+
+/*
+ * Called as a thread from BaculaAppMain()
+ * Here we handle the Windows messages
+ */
+DWORD WINAPI Main_Msg_Loop(LPVOID lpwThreadParam)
+{
+   DWORD old_servicethread = g_servicethread;
+
+   /* Since we are the only thread with a message loop
+    * mark ourselves as the service thread so that
+    * we can receive all the window events.
+    */
+   g_servicethread = GetCurrentThreadId();
+
+   // Create tray icon & menu if we're running as an app
+   bacMenu *menu = new bacMenu();
+   if (menu == NULL) {
+      PostQuitMessage(0);
+   }
+
+
+   // Now enter the message handling loop until told to quit!
+   MSG msg;
+   while (GetMessage(&msg, NULL, 0,0) ) {
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+   }
+
+   if (menu != NULL)
+      delete menu;
+
+   if (old_servicethread != 0) { /* started as NT service */
+      // Mark that we're no longer running
+      g_servicethread = 0;
+
+      // Tell the service manager that we've stopped.
+      ReportStatus(SERVICE_STOPPED, g_error, 0);
+   }   
+   kill(main_pid, SIGTERM);
+   _exit(0);
+}
+
+/*
+ * This is the main routine for Bacula when running as an application
+ * (under Windows 95 or Windows NT)
+ * Under NT, Bacula can also run as a service.  The BaculaServerMain routine,
+ * defined in the bacService header, is used instead when running as a service.
+ */
+int BaculaAppMain()
+{
+   DWORD dwThreadID;
+
+   // Set this process to be the last application to be shut down.
+   SetProcessShutdownParameters(0x100, 0);
+
+   HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
+   if (hservwnd != NULL) {
+      // We don't allow multiple instances!
+      MessageBox(NULL, "Another instance of Bacula is already running", szAppName, MB_OK);
+      _exit(0);
+   }
+
+   // Create a thread to handle the Windows messages
+   (void)CreateThread(NULL, 0, Main_Msg_Loop, NULL, 0, &dwThreadID);
+
+   // Call the "real" Bacula
+   BaculaMain(num_command_args, command_args);
+   PostQuitMessage(0);
+   _exit(0);
+}
diff --git a/bacula/src/filed/win32/winres.h b/bacula/src/filed/win32/winres.h
new file mode 100755 (executable)
index 0000000..a1f52e9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Included by bacula.rc
+ */
+
+/* Icon definitions */
+#define IDI_BACULA                      100
+#define IDI_IDLE                        101
+#define IDI_RUNNING                     102
+#define IDI_JOB_ERROR                   103
+#define IDR_TRAYMENU                    104
+
+#define IDC_LIST                        1000
+#define IDC_NONYET_LABEL                1006
+#define IDC_UPDATE_BORDER               1010
+#define IDC_APCUPSDBMP                  1016
+#define IDC_VERSION                     1017
+#define IDC_NAME                        1018
+#define IDC_EMAIL                       1019
+#define IDC_WWW                         1022
+#define IDC_COPYRIGHT                   1023
+#define IDACCEPT                        1030
+#define IDREJECT                        1031
+#define IDC_STATIC_TEXT1                1032
+#define IDC_ACCEPT_IP                   1033
+#define IDC_STATIC_TEXT                 1034
+#define IDC_ACCEPT_TIMEOUT              1035
+#define IDC_TRADEMARK                   1036
+
+
+#define ID_PROPERTIES                   40001
+#define ID_CLOSE                        40002
+#define ID_KILLCLIENTS                  40003
+#define ID_ABOUT                        40004
+#define ID_STATUS                       40005
+#define ID_DEFAULT_PROPERTIES           40006
+#define ID_EVENTS                       40007
+
+/* Dialog definitions */
+#define IDD_PROPERTIES                  200
+#define IDD_ABOUT                       201
+#define IDD_STATUS                      202
+#define IDD_EVENTS                      203
+
+
+#define IDB_BACULABMP                   106
diff --git a/bacula/src/filed/win32/winres.rc b/bacula/src/filed/win32/winres.rc
new file mode 100644 (file)
index 0000000..4638580
--- /dev/null
@@ -0,0 +1,176 @@
+#include <winuser.h>
+#include <winver.h>
+#include "winres.h"
+#include "../../version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icons
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_BACULA              ICON    DISCARDABLE     "bacula.ico"
+IDI_IDLE                ICON    DISCARDABLE     "idle.ico"
+IDI_RUNNING             ICON    DISCARDABLE     "running.ico"
+IDI_JOB_ERROR           ICON    DISCARDABLE     "error.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TRAYMENU MENU DISCARDABLE 
+BEGIN
+    POPUP "tray"
+    BEGIN
+        MENUITEM "&Status",                     ID_STATUS
+        MENUITEM "&Events",                     ID_EVENTS
+#ifdef properties_implemented
+        MENUITEM "&Properties",                 ID_PROPERTIES
+#endif
+        MENUITEM SEPARATOR
+        MENUITEM "&About Bacula",               ID_ABOUT
+        MENUITEM SEPARATOR
+        MENUITEM "&Close Bacula",               ID_CLOSE
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,1,0,0
+ PRODUCTVERSION 1,1,0,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0 //
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904E0" // Lang=US English, CharSet=Windows Multiligual
+        BEGIN
+            VALUE "Comments", "by Kern Sibbald\0"
+            VALUE "CompanyName", "            \0"
+            VALUE "FileDescription", "Bacula File daemon for Win32\0"
+            VALUE "FileVersion", VERSION "\0"
+            VALUE "InternalName", "Bacula\0"
+            VALUE "LegalCopyright", "Copyright Kern Sibbald, 2002\0"
+            VALUE "LegalTrademarks", "Licensed under GNU GPL 2.0\0"
+            VALUE "OriginalFilename", "filed.exe\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "Bacula - Win32 Version\0"
+            VALUE "ProductVersion", VERSION
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252 // US English, Multilingual
+    END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_BACULABMP           BITMAP  DISCARDABLE     "bacula.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDI_BACULA              "Bacula"
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Properties Dialog
+//
+#ifdef properties_implemented
+
+IDD_PROPERTIES DIALOG DISCARDABLE  0, 0, 221, 204
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | 
+    WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Bacula Properties"
+FONT 8, "MS Sans Serif"
+BEGIN
+    PUSHBUTTON      "&Cancel",IDCANCEL,165,25,51,15
+    DEFPUSHBUTTON   "&OK",IDOK,165,5,51,15
+    LTEXT           "No Properites yet",IDC_NONYET_LABEL,19,30,56,15,
+                    SS_CENTERIMAGE
+END
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// About Dialog
+//
+
+IDD_ABOUT DIALOG DISCARDABLE  0, 0, 250, 145
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Bacula"
+FONT 8, "MS Sans Serif"
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,190,120,50,15
+//  CONTROL         "\3", IDC_BACULABMP,"Static",SS_ICON | SS_CENTERIMAGE |
+//                  SS_SUNKEN,7,5,73,65
+    CONTROL         "a", IDB_BACULABMP,"Static",SS_BITMAP|SS_SUNKEN,7,5,73,65
+    LTEXT           "Bacula Version " VERSION " (" DATE ")", IDC_VERSION,90,10,239,10
+    LTEXT           "      by Kern Sibbald",IDC_NAME,90,20,239,10
+    LTEXT           "For more information, see:",
+                    IDC_WWW,90,40,239,10
+    LTEXT           "         www.sibbald.com/bacula",
+                    IDC_WWW,90,50,239,10
+    LTEXT           "                                               ",
+                    IDC_WWW,90,60,239,10
+    LTEXT           "                                    ",
+                    IDC_WWW,90,70,239,10
+    LTEXT           "Copyright (C) 1999-2002, Kern Sibbald",
+                    IDC_COPYRIGHT,7,120,175,10
+    LTEXT           "Licensed under GNU GPL 2.0.",
+                    IDC_TRADEMARK,7,130,175,10
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Status Dialog
+//
+
+IDD_STATUS DIALOG DISCARDABLE  0, 0, 411, 244
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | 
+    WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Bacula Status"
+FONT 8, "Courier New"
+BEGIN
+    DEFPUSHBUTTON   "&OK",IDOK,355,5,51,15
+    LISTBOX         IDC_LIST, 2, 2, 350, 240, WS_VSCROLL | WS_HSCROLL | WS_BORDER
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Events Dialog
+//
+
+IDD_EVENTS DIALOG DISCARDABLE  0, 0, 411, 204
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | 
+    WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Bacula Events"
+FONT 8, "Courier New"
+BEGIN
+    DEFPUSHBUTTON   "&OK",IDOK,355,5,51,15
+    LISTBOX         IDC_LIST, 2, 2, 350, 200, WS_VSCROLL | WS_HSCROLL | WS_BORDER
+END
diff --git a/bacula/src/filed/win32/winservice.cpp b/bacula/src/filed/win32/winservice.cpp
new file mode 100755 (executable)
index 0000000..8190ff8
--- /dev/null
@@ -0,0 +1,908 @@
+//  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+//  This file is part of the VNC system.
+//
+//  The VNC system 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.
+//
+// If the source code for the VNC system is not available from the place 
+// whence you received this file, check http://www.uk.research.att.com/vnc or contact
+// the authors on vnc@uk.research.att.com for information on obtaining it.
+//
+// This file has been adapted to the Win32 version of Bacula
+// by Kern E. Sibbald.  Many thanks to ATT and James Weatherall,
+// the original author, for providing an excellent template.
+//
+// Copyright (2000) Kern E. Sibbald
+//
+
+
+// winService
+
+// Implementation of service-oriented functionality of Bacula
+// I.e. command line options that contact a running version of
+// Bacula and ask it to do something (show about, show status,
+// show events, ...)
+
+
+#include <lmcons.h>
+#include "winbacula.h"
+#include "winservice.h"
+#include "wintray.h"
+
+// Error message logging
+void LogErrorMsg(char *message);
+
+// OS-SPECIFIC ROUTINES
+
+// Create an instance of the bacService class to cause the static fields to be
+// initialised properly
+
+bacService init;
+
+DWORD   g_platform_id;
+BOOL    g_impersonating_user = 0;
+
+bacService::bacService()
+{
+    OSVERSIONINFO osversioninfo;
+    osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
+
+    // Get the current OS version
+    if (!GetVersionEx(&osversioninfo))
+            g_platform_id = 0;
+    else
+            g_platform_id = osversioninfo.dwPlatformId;
+}
+
+// CurrentUser - fills a buffer with the name of the current user!
+BOOL
+bacService::CurrentUser(char *buffer, UINT size)
+{
+   // How to obtain the name of the current user depends upon the OS being used
+   if ((g_platform_id == VER_PLATFORM_WIN32_NT) && bacService::RunningAsService()) {
+      // Windows NT, service-mode
+
+      // -=- FIRSTLY - verify that a user is logged on
+
+      // Get the current Window station
+      HWINSTA station = GetProcessWindowStation();
+      if (station == NULL)
+              return FALSE;
+
+      // Get the current user SID size
+      DWORD usersize;
+      GetUserObjectInformation(station,
+              UOI_USER_SID, NULL, 0, &usersize);
+
+      // Check the required buffer size isn't zero
+      if (usersize == 0) {
+         // No user is logged in - ensure we're not impersonating anyone
+         RevertToSelf();
+         g_impersonating_user = FALSE;
+
+         // Return "" as the name...
+         if (strlen("") >= size)
+                 return FALSE;
+         strcpy(buffer, "");
+
+         return TRUE;
+      }
+
+      // -=- SECONDLY - a user is logged on but if we're not impersonating
+      //     them then we can't continue!
+      if (!g_impersonating_user) {
+         // Return "" as the name...
+         if (strlen("") >= size)
+                 return FALSE;
+         strcpy(buffer, "");
+         return TRUE;
+      }
+   }
+           
+   // -=- When we reach here, we're either running under Win9x, or we're running
+   //     under NT as an application or as a service impersonating a user
+   // Either way, we should find a suitable user name.
+
+   switch (g_platform_id) {
+
+   case VER_PLATFORM_WIN32_WINDOWS:
+   case VER_PLATFORM_WIN32_NT:
+      // Just call GetCurrentUser
+      DWORD length = size;
+
+      if (GetUserName(buffer, &length) == 0)
+      {
+              UINT error = GetLastError();
+
+              if (error == ERROR_NOT_LOGGED_ON)
+              {
+                      // No user logged on
+                      if (strlen("") >= size)
+                              return FALSE;
+                      strcpy(buffer, "");
+                      return TRUE;
+              }
+              else
+              {
+                      // Genuine error...
+                      return FALSE;
+              }
+      }
+      return TRUE;
+   }
+
+   // OS was not recognised!
+   return FALSE;
+}
+
+// IsWin95 - returns a BOOL indicating whether the current OS is Win95
+BOOL
+bacService::IsWin95()
+{
+   return (g_platform_id == VER_PLATFORM_WIN32_WINDOWS);
+}
+
+// IsWinNT - returns a bool indicating whether the current OS is WinNT
+BOOL
+bacService::IsWinNT()
+{
+   return (g_platform_id == VER_PLATFORM_WIN32_NT);
+}
+
+// Internal routine to find the  Bacula menu class window and
+// post a message to it!
+
+BOOL
+PostToBacula(UINT message, WPARAM wParam, LPARAM lParam)
+{
+   // Locate the hidden Bacula menu window
+   HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
+   if (hservwnd == NULL)
+           return FALSE;
+
+   // Post the message to Bacula
+   PostMessage(hservwnd, message, wParam, lParam);
+   return TRUE;
+}
+
+
+// Static routine to show the Properties dialog for a currently-running
+// copy of Bacula, (usually a servicified version.)
+
+BOOL
+bacService::ShowProperties()
+{
+#ifdef properties_implemented
+   // Post to the Bacula menu window
+   if (!PostToBacula(MENU_PROPERTIES_SHOW, 0, 0)) {
+      MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
+      return FALSE;
+   }
+#endif
+   return TRUE;
+}
+
+// Static routine to show the Default Properties dialog for a currently-running
+// copy of Bacula, (usually a servicified version.)
+
+BOOL
+bacService::ShowDefaultProperties()
+{
+#ifdef properties_implemented
+   // Post to the Bacula menu window
+   if (!PostToBacula(MENU_DEFAULT_PROPERTIES_SHOW, 0, 0)) {
+      MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
+      return FALSE;
+   }
+
+#endif
+   return TRUE;
+}
+
+// Static routine to show the About dialog for a currently-running
+// copy of Bacula, (usually a servicified version.)
+
+BOOL
+bacService::ShowAboutBox()
+{
+   // Post to the Bacula menu window
+   if (!PostToBacula(MENU_ABOUTBOX_SHOW, 0, 0)) {
+      MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
+      return FALSE;
+   }
+   return TRUE;
+}
+
+// Static routine to show the Status dialog for a currently-running
+// copy of Bacula, (usually a servicified version.)
+
+BOOL
+bacService::ShowStatus()
+{
+   // Post to the Bacula menu window
+   if (!PostToBacula(MENU_STATUS_SHOW, 0, 0)) {
+      MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
+      return FALSE;
+   }
+   return TRUE;
+}
+
+// Static routine to show the Events dialog for a currently-running
+// copy of Bacula, (usually a servicified version.)
+
+BOOL
+bacService::ShowEvents()
+{
+   // Post to the Bacula menu window
+   if (!PostToBacula(MENU_EVENTS_SHOW, 0, 0)) {
+      MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
+      return FALSE;
+   }
+   return TRUE;
+}
+
+
+// Static routine to tell a locally-running instance of the server
+// to connect out to a new client
+
+BOOL
+bacService::PostAddNewClient(unsigned long ipaddress)
+{
+   // Post to the Bacula menu window
+   if (!PostToBacula(MENU_ADD_CLIENT_MSG, 0, ipaddress)) {
+      MessageBox(NULL, "No existing instance of Bacula could be contacted", szAppName, MB_ICONEXCLAMATION | MB_OK);
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+// SERVICE-MODE ROUTINES
+
+// Service-mode defines:
+
+// Executable name
+#define BAC_APPNAME            "bacula"
+
+// Internal service name
+#define BAC_SERVICENAME        "Bacula"
+
+// Displayed service name
+#define BAC_SERVICEDISPLAYNAME "Bacula File Server"
+
+// List of other required services ("dependency 1\0dependency 2\0\0")
+// *** These need filling in properly
+#define BAC_DEPENDENCIES       ""
+
+// Internal service state
+SERVICE_STATUS          g_srvstatus;       // current status of the service
+SERVICE_STATUS_HANDLE   g_hstatus;
+DWORD                   g_error = 0;
+DWORD                   g_servicethread = 0;
+char*                   g_errortext[256];
+
+// Forward defines of internal service functions
+void WINAPI ServiceMain(DWORD argc, char **argv);
+
+DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam);
+void ServiceStop();
+void WINAPI ServiceCtrl(DWORD ctrlcode);
+
+bool WINAPI CtrlHandler (DWORD ctrltype);
+
+BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
+
+// ROUTINE TO QUERY WHETHER THIS PROCESS IS RUNNING AS A SERVICE OR NOT
+
+BOOL    g_servicemode = FALSE;
+
+BOOL
+bacService::RunningAsService()
+{
+   return g_servicemode;
+}
+
+BOOL
+bacService::KillRunningCopy()
+{
+   while (PostToBacula(WM_CLOSE, 0, 0)) {
+   }
+   return TRUE;
+}
+
+
+// ROUTINE TO POST THE HANDLE OF THE CURRENT USER TO THE RUNNING Bacula, IN ORDER
+// THAT IT CAN LOAD THE APPROPRIATE SETTINGS.  THIS IS USED ONLY BY THE SVCHELPER
+// OPTION, WHEN RUNNING UNDER NT
+BOOL
+bacService::PostUserHelperMessage()
+{
+   // - Check the platform type
+   if (!IsWinNT())
+           return TRUE;
+
+   // - Get the current process ID
+   DWORD processId = GetCurrentProcessId();
+
+   // - Post it to the existing Bacula
+   if (!PostToBacula(MENU_SERVICEHELPER_MSG, 0, (LPARAM)processId))
+           return FALSE;
+
+   // - Wait until it's been used
+   return TRUE;
+}
+
+// ROUTINE TO PROCESS AN INCOMING INSTANCE OF THE ABOVE MESSAGE
+BOOL
+bacService::ProcessUserHelperMessage(WPARAM wParam, LPARAM lParam) {
+   // - Check the platform type
+   if (!IsWinNT() || !bacService::RunningAsService())
+           return TRUE;
+
+   // - Close the HKEY_CURRENT_USER key, to force NT to reload it for the new user
+   // NB: Note that this is _really_ dodgy if ANY other thread is accessing the key!
+   if (RegCloseKey(HKEY_CURRENT_USER) != ERROR_SUCCESS) {
+           return FALSE;
+   }
+
+   // - Revert to our own identity
+   RevertToSelf();
+   g_impersonating_user = FALSE;
+
+   // - Open the specified process
+   HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)lParam);
+   if (processHandle == NULL) {
+           return FALSE;
+   }
+
+   // - Get the token for the given process
+   HANDLE userToken = NULL;
+   if (!OpenProcessToken(processHandle, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &userToken)) {
+           CloseHandle(processHandle);
+           return FALSE;
+   }
+   CloseHandle(processHandle);
+
+   // - Set this thread to impersonate them
+   if (!ImpersonateLoggedOnUser(userToken)) {
+           CloseHandle(userToken);
+           return FALSE;
+   }
+   CloseHandle(userToken);
+
+   g_impersonating_user = TRUE;
+   return TRUE;
+}
+
+// SERVICE MAIN ROUTINE
+int
+bacService::BaculaServiceMain()
+{
+   // Mark that we are a service
+   g_servicemode = TRUE;
+
+   // How to run as a service depends upon the OS being used
+   switch (g_platform_id) {
+
+           // Windows 95/98
+   case VER_PLATFORM_WIN32_WINDOWS:
+      {
+      // Obtain a handle to the kernel library
+      HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
+      if (kerneldll == NULL) {
+         MessageBox(NULL, "KERNEL32.DLL not found: Bacula service not started", 
+             "Bacula Service", MB_OK);
+         break;
+      }
+
+      // And find the RegisterServiceProcess function
+      DWORD (*RegisterService)(DWORD, DWORD);
+      RegisterService = (DWORD (*)(DWORD, DWORD))
+              GetProcAddress(kerneldll, "RegisterServiceProcess");
+      if (RegisterService == NULL) {
+         MessageBox(NULL, "Registry service not fond: Bacula service not started",
+            "Bacula Service", MB_OK);
+         break;
+      }
+      
+      // Register this process with the OS as a service!
+      RegisterService(0, 1);
+
+      // Run the service itself
+      BaculaAppMain();
+
+      // Then remove the service from the system service table
+      RegisterService(0, 0);
+
+      // Free the kernel library
+      FreeLibrary(kerneldll);
+
+      // *** If we don't kill the process directly here, then 
+      // for some reason, Bacula crashes...
+ //         ExitProcess(0);
+      break;
+      }
+           // Windows NT
+   case VER_PLATFORM_WIN32_NT:
+      {
+      // Create a service entry table
+      SERVICE_TABLE_ENTRY dispatchTable[] = {
+              {BAC_SERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
+              {NULL, NULL}
+      };
+
+      // Call the service control dispatcher with our entry table
+      if (!StartServiceCtrlDispatcher(dispatchTable))
+              LogErrorMsg("StartServiceCtrlDispatcher failed.");
+      break;
+      }
+   }
+   return 0;
+}
+
+// SERVICE MAIN ROUTINE - NT ONLY !!!
+// NT ONLY !!!
+void WINAPI ServiceMain(DWORD argc, char **argv)
+{
+    DWORD dwThreadID;
+
+        // Register the service control handler
+    g_hstatus = RegisterServiceCtrlHandler(BAC_SERVICENAME, ServiceCtrl);
+
+    if (g_hstatus == 0) {
+       MessageBox(NULL, "Contact Register Service Handler failure",
+          "Bacula service", MB_OK);
+       return;
+    }
+
+        // Set up some standard service state values
+    g_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS;
+    g_srvstatus.dwServiceSpecificExitCode = 0;
+
+        // Give this status to the SCM
+    if (!ReportStatus(
+        SERVICE_START_PENDING,  // Service state
+        NO_ERROR,                               // Exit code type
+        15000))                                 // Hint as to how long Bacula should have hung before you assume error
+        {
+        ReportStatus(
+                        SERVICE_STOPPED,
+                        g_error,
+            0);
+                return;
+        }
+
+        // Now start the service for real
+    (void)CreateThread(NULL, 0, ServiceWorkThread, NULL, 0, &dwThreadID);
+    return;
+}
+
+// SERVICE START ROUTINE - thread that calls BaculaAppMain
+//   NT ONLY !!!!
+DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam)
+{
+    // Save the current thread identifier
+    g_servicethread = GetCurrentThreadId();
+
+    // report the status to the service control manager.
+    //
+    if (!ReportStatus(
+        SERVICE_RUNNING,       // service state
+        NO_ERROR,              // exit code
+        0)) {                  // wait hint
+       MessageBox(NULL, "Report Service failure", "Bacula Service", MB_OK);
+       return 0;
+    }
+
+    // RUN!
+   BaculaAppMain();
+
+   // Mark that we're no longer running
+    g_servicethread = 0;
+
+    // Tell the service manager that we've stopped.
+    ReportStatus(
+                SERVICE_STOPPED,
+                g_error,
+                0);
+    return 0;
+}
+
+// SERVICE STOP ROUTINE - post a quit message to the relevant thread
+void ServiceStop()
+{
+   // Post a quit message to the main service thread
+   if (g_servicethread != 0) {
+      PostThreadMessage(g_servicethread, WM_QUIT, 0, 0);
+   }
+}
+
+// SERVICE INSTALL ROUTINE
+int
+bacService::InstallService()
+{
+   const int pathlength = 2048;
+   char path[pathlength];
+   char servicecmd[pathlength];
+   int len;
+
+   // Get the filename of this executable
+   if (GetModuleFileName(NULL, path, pathlength-(strlen(BaculaRunService)+2)) == 0) {
+      MessageBox(NULL, "Unable to install Bacula service", szAppName, MB_ICONEXCLAMATION | MB_OK);
+      return 0;
+   }
+
+   // Append the service-start flag to the end of the path:
+   if ((int)strlen(path) + 20 + (int)strlen(BaculaRunService) < pathlength) {
+      sprintf(servicecmd, "\"%s\" %s -c %s", path, BaculaRunService, path);
+      len = strlen(servicecmd) - 1;
+      for ( ; len > 0; len--) {
+         if (servicecmd[len] == '\\') {
+            servicecmd[len] = 0;
+            break;
+         }
+         servicecmd[len] = 0;
+      }
+      strcat(servicecmd, "\\bacula-fd.conf");
+
+   } else {
+      MessageBox(NULL, "Service command length too long. Service not registered.",
+          szAppName, MB_ICONEXCLAMATION | MB_OK);
+      return 0;
+   }
+
+   // How to add the Bacula service depends upon the OS
+   switch (g_platform_id) {
+
+           // Windows 95/98
+   case VER_PLATFORM_WIN32_WINDOWS:
+      // Locate the RunService registry entry
+      HKEY runservices;
+      if (RegCreateKey(HKEY_LOCAL_MACHINE, 
+              "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
+              &runservices) != ERROR_SUCCESS) {
+         MessageBox(NULL, "The System Registry could not be updated - the Bacula service was not installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
+         break;
+      }
+
+      // Attempt to add a Bacula key
+      if (RegSetValueEx(runservices, szAppName, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS) {
+         RegCloseKey(runservices);
+         MessageBox(NULL, "The Bacula service could not be installed", szAppName, MB_ICONEXCLAMATION | MB_OK);
+         break;
+      }
+
+      RegCloseKey(runservices);
+
+      // We have successfully installed the service!
+      MessageBox(NULL,
+              "The Bacula File service was successfully installed.\n"
+              "The service may be started by double clicking on the\n"
+              "Bacula \"Start\" icon and will be automatically\n"
+              "be run the next time this machine is rebooted. ",
+              szAppName,
+              MB_ICONINFORMATION | MB_OK);
+
+#ifdef needed
+      // Run the service...
+      STARTUPINFO si;
+      si.cb = sizeof(si);
+      si.cbReserved2 = 0;
+      si.lpReserved = NULL;
+      si.lpReserved2 = NULL;
+      si.dwFlags = 0;
+      si.lpTitle = NULL;
+      PROCESS_INFORMATION pi;
+      if (!CreateProcess(NULL, servicecmd,   // Program name & path
+              NULL, NULL,                    // Security attributes
+              FALSE,                         // Inherit handles?
+              NORMAL_PRIORITY_CLASS,         // Extra startup flags
+              NULL,                          // Environment table
+              NULL,                          // Current directory
+              &si,
+              &pi
+              )) {
+         MessageBox(NULL, "CreateProcess: the Bacula service failed to start", szAppName, MB_ICONSTOP | MB_OK);
+         break;
+      }
+#endif
+      break;
+
+           // Windows NT
+   case VER_PLATFORM_WIN32_NT:
+      SC_HANDLE   hservice;
+      SC_HANDLE   hsrvmanager;
+
+      // Open the default, local Service Control Manager database
+      hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+          if (hsrvmanager == NULL) {
+             MessageBox(NULL,
+                "The Service Control Manager could not be contacted - the Bacula service was not installed",
+                szAppName, MB_ICONEXCLAMATION | MB_OK);
+             break;
+          }
+
+          // Create an entry for the Bacula service
+          hservice = CreateService(
+                  hsrvmanager,                    // SCManager database
+                  BAC_SERVICENAME,                // name of service
+                  BAC_SERVICEDISPLAYNAME,         // name to display
+                  SERVICE_ALL_ACCESS,             // desired access
+                  SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                                                          // service type
+                  SERVICE_AUTO_START,             // start type
+                  SERVICE_ERROR_NORMAL,           // error control type
+                  servicecmd,                     // service's binary
+                  NULL,                           // no load ordering group
+                  NULL,                           // no tag identifier
+                  BAC_DEPENDENCIES,               // dependencies
+                  NULL,                           // LocalSystem account
+                  NULL);                          // no password
+          CloseServiceHandle(hsrvmanager);
+          if (hservice == NULL) {
+             MessageBox(NULL,
+                 "The Bacula service could not be installed",
+                  szAppName, MB_ICONEXCLAMATION | MB_OK);
+             break;
+          }
+          CloseServiceHandle(hservice);
+
+          // Now install the servicehelper registry setting...
+          // Locate the RunService registry entry
+          HKEY runapps;
+          if (RegCreateKey(HKEY_LOCAL_MACHINE, 
+                  "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
+                  &runapps) != ERROR_SUCCESS) {
+             MessageBox(NULL, "WARNING: Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded", 
+                szAppName, MB_ICONEXCLAMATION | MB_OK);
+          } else {
+             char servicehelpercmd[pathlength];
+
+             // Append the service-helper-start flag to the end of the path:
+             if ((int)strlen(path) + 4 + (int)strlen(BaculaRunServiceHelper) < pathlength)
+                sprintf(servicehelpercmd, "\"%s\" %s", path, BaculaRunServiceHelper);
+             else
+                return 0;
+
+             // Add the upsserviceHelper entry
+             if (RegSetValueEx(runapps, szAppName, 0, REG_SZ,
+                  (unsigned char *)servicehelpercmd, strlen(servicehelpercmd)+1) != ERROR_SUCCESS)
+             {
+                MessageBox(NULL, "WARNING:Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded", szAppName, MB_ICONEXCLAMATION | MB_OK);
+             }
+             RegCloseKey(runapps);
+          }
+
+          // Everything went fine
+          MessageBox(NULL,
+                  "The Bacula File service was successfully installed.\n"
+                  "The service may be started from the Control Panel and will\n"
+                  "automatically be run the next time this machine is rebooted.",
+                  szAppName,
+                  MB_ICONINFORMATION | MB_OK);
+          break;
+   default:
+          MessageBox(NULL, 
+                   "Unknown Windows operating system.\n"     
+                   "Cannot install Bacula service.\n",
+                    szAppName, MB_ICONEXCLAMATION | MB_OK);
+           break;     
+   };
+
+   return 0;
+}
+
+// SERVICE REMOVE ROUTINE
+int
+bacService::RemoveService()
+{
+        // How to remove the Bacula service depends upon the OS
+        switch (g_platform_id) {
+
+                // Windows 95/98
+        case VER_PLATFORM_WIN32_WINDOWS:
+           // Locate the RunService registry entry
+           HKEY runservices;
+           if (RegOpenKey(HKEY_LOCAL_MACHINE, 
+                   "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
+                   &runservices) != ERROR_SUCCESS) {
+              MessageBox(NULL, 
+                 "Could not find registry entry.\nService probably not registerd - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
+           } else {
+              // Attempt to delete the Bacula key
+              if (RegDeleteValue(runservices, szAppName) != ERROR_SUCCESS) {
+                 RegCloseKey(runservices);
+                 MessageBox(NULL, "Could not delete Registry key.\nThe Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
+              }
+
+              RegCloseKey(runservices);
+              break;
+           }
+
+           // Try to kill any running copy of Bacula
+           if (!KillRunningCopy()) {
+              MessageBox(NULL,
+                  "Bacula could not be contacted, probably not running",
+                  szAppName, MB_ICONEXCLAMATION | MB_OK);
+              break;
+           }
+
+           // We have successfully removed the service!
+           MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
+           break;
+
+                // Windows NT
+        case VER_PLATFORM_WIN32_NT:
+           SC_HANDLE   hservice;
+           SC_HANDLE   hsrvmanager;
+
+           // Attempt to remove the service-helper hook
+           HKEY runapps;
+           if (RegOpenKey(HKEY_LOCAL_MACHINE, 
+                   "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
+                   &runapps) == ERROR_SUCCESS)
+           {
+                   // Attempt to delete the Bacula key
+                   if (RegDeleteValue(runapps, szAppName) != ERROR_SUCCESS)
+                   {
+                           MessageBox(NULL, "WARNING:The ServiceHelper hook entry could not be removed from the registry", szAppName, MB_ICONEXCLAMATION | MB_OK);
+                   }
+                   RegCloseKey(runapps);
+           }
+
+           // Open the SCM
+           hsrvmanager = OpenSCManager(
+              NULL,                   // machine (NULL == local)
+              NULL,                   // database (NULL == default)
+              SC_MANAGER_ALL_ACCESS   // access required
+              );
+           if (hsrvmanager) {
+              hservice = OpenService(hsrvmanager, BAC_SERVICENAME, SERVICE_ALL_ACCESS);
+              if (hservice != NULL)
+              {
+                 SERVICE_STATUS status;
+
+                 // Try to stop the Bacula service
+                 if (ControlService(hservice, SERVICE_CONTROL_STOP, &status))
+                 {
+                    while(QueryServiceStatus(hservice, &status)) {
+                            if (status.dwCurrentState == SERVICE_STOP_PENDING)
+                                    Sleep(1000);
+                            else
+                                    break;
+                    }
+
+                    if (status.dwCurrentState != SERVICE_STOPPED)
+                            MessageBox(NULL, "The Bacula service could not be stopped", szAppName, MB_ICONEXCLAMATION | MB_OK);
+                 }
+
+                 // Now remove the service from the SCM
+                 if(DeleteService(hservice))
+                    MessageBox(NULL, "The Bacula service has been removed", szAppName, MB_ICONINFORMATION | MB_OK);
+                 else
+                    MessageBox(NULL, "The Bacula service could not be removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
+
+                 CloseServiceHandle(hservice);
+              }
+              else
+                 MessageBox(NULL, "The Bacula service could not be found", szAppName, MB_ICONEXCLAMATION | MB_OK);
+
+              CloseServiceHandle(hsrvmanager);
+           }
+           else
+              MessageBox(NULL, "The SCM could not be contacted - the Bacula service was not removed", szAppName, MB_ICONEXCLAMATION | MB_OK);
+           break;
+        }
+        return 0;
+}
+
+// USEFUL SERVICE SUPPORT ROUTINES
+
+// Service control routine
+void WINAPI ServiceCtrl(DWORD ctrlcode)
+{
+        // What control code have we been sent?
+    switch(ctrlcode)
+    {
+
+        case SERVICE_CONTROL_STOP:
+                // STOP : The service must stop
+                g_srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
+        ServiceStop();
+        break;
+
+    case SERVICE_CONTROL_INTERROGATE:
+                // QUERY : Service control manager just wants to know our state
+                break;
+
+        default:
+                // Control code not recognised
+                break;
+
+    }
+
+        // Tell the control manager what we're up to.
+    ReportStatus(g_srvstatus.dwCurrentState, NO_ERROR, 0);
+}
+
+// Service manager status reporting
+BOOL ReportStatus(DWORD state,
+                  DWORD exitcode,
+                  DWORD waithint)
+{
+    static DWORD checkpoint = 1;
+    BOOL result = TRUE;
+
+    // If we're in the start state then we don't want the control manager
+    // sending us control messages because they'll confuse us.
+    if (state == SERVICE_START_PENDING)
+       g_srvstatus.dwControlsAccepted = 0;
+    else
+       g_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+
+    // Save the new status we've been given
+    g_srvstatus.dwCurrentState = state;
+    g_srvstatus.dwWin32ExitCode = exitcode;
+    g_srvstatus.dwWaitHint = waithint;
+
+    // Update the checkpoint variable to let the SCM know that we
+    // haven't died if requests take a long time
+    if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED))
+            g_srvstatus.dwCheckPoint = 0;
+    else
+    g_srvstatus.dwCheckPoint = checkpoint++;
+
+    // Tell the SCM our new status
+    if (!(result = SetServiceStatus(g_hstatus, &g_srvstatus)))
+            LogErrorMsg("SetServiceStatus failed");
+
+    return result;
+}
+
+// Error reporting
+void LogErrorMsg(char *message)
+{
+    char        msgbuff[256];
+    HANDLE      heventsrc;
+    char *      strings[2];
+
+    // Save the error code
+    g_error = GetLastError();
+
+    // Use event logging to log the error
+    heventsrc = RegisterEventSource(NULL, BAC_SERVICENAME);
+
+    sprintf(msgbuff, "%s error: %ld", BAC_SERVICENAME, g_error);
+    strings[0] = msgbuff;
+    strings[1] = message;
+
+    if (heventsrc != NULL) {
+       MessageBeep(MB_OK);
+
+       ReportEvent(
+               heventsrc,              // handle of event source
+               EVENTLOG_ERROR_TYPE,    // event type
+               0,                      // event category
+               0,                      // event ID
+               NULL,                   // current user's SID
+               2,                      // strings in 'strings'
+               0,                      // no bytes of raw data
+               (const char **)strings, // array of error strings
+               NULL);                  // no raw data
+
+       DeregisterEventSource(heventsrc);
+    }
+}
diff --git a/bacula/src/filed/win32/winservice.h b/bacula/src/filed/win32/winservice.h
new file mode 100755 (executable)
index 0000000..2747995
--- /dev/null
@@ -0,0 +1,125 @@
+//  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+//  This file is part of the ups system.
+//
+//  The ups system 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.
+//
+// If the source code for the ups system is not available from the place 
+// whence you received this file, check http://www.uk.research.att.com/vnc or contact
+// the authors on ups@uk.research.att.com for information on obtaining it.
+//
+// This file has been adapted to the Win32 version of Bacula
+// by Kern E. Sibbald.  Many thanks to ATT and James Weatherall,
+// the original author, for providing an excellent template.
+//
+// Copyright (2000) Kern E. Sibbald
+//
+
+
+// winservice.cpp
+
+// SERVICE-MODE CODE
+
+// This class provides access to service-oriented routines, under both
+// Windows NT and Windows 95.  Some routines only operate under one
+// OS, others operate under any OS.
+
+class bacService;
+
+#if (!defined(_win_bacService))
+#define _win_bacService
+
+// The NT-specific code wrapper class
+class bacService
+{
+public:
+        bacService();
+
+   // SERVICE INSTALL & START FUNCTIONS
+
+   // Routine called by WinMain to cause Bacula to be installed
+   // as a service.
+   static int BaculaServiceMain();
+
+   // Routine to install the Apcupsd service on the local machine
+   static int InstallService();
+
+   // Routine to remove the Apcupsd service from the local machine
+   static int RemoveService();
+
+   // SERVICE SUPPORT FUNCTIONS
+
+   // Routine to establish and return the currently logged in user name
+   static BOOL CurrentUser(char *buffer, UINT size);
+
+   // Routine to post a message to the currently running Apcupsd server
+   // to pass it a handle to the current user
+   static BOOL PostUserHelperMessage();
+   // Routine to process a user helper message
+   static BOOL ProcessUserHelperMessage(WPARAM wParam, LPARAM lParam);
+
+   // Routines to establish which OS we're running on
+   static BOOL IsWin95();
+   static BOOL IsWinNT();
+
+   // Routine to establish whether the current instance is running
+   // as a service or not
+   static BOOL RunningAsService();
+
+   // Routine to kill any other running copy of Apcupsd
+   static BOOL KillRunningCopy();
+
+   // Routine to set the current thread into the given desktop
+   static BOOL SelectHDESK(HDESK newdesktop);
+
+   // Routine to set the current thread into the named desktop,
+   // or the input desktop if no name is given
+   static BOOL SelectDesktop(char *name);
+
+   // Routine to establish whether the current thread desktop is the
+   // current user input one
+   static BOOL InputDesktopSelected();
+
+   // Routine to fake a CtrlAltDel to winlogon when required.
+   // *** This is a nasty little hack...
+   static BOOL SimulateCtrlAltDel();
+
+   // Routine to make any currently running version of Apcupsd show its
+   // Properties dialog, to allow the user to make changes to their settings
+   static BOOL ShowProperties();
+
+   // Routine to make any currently running version of Apcupsd show the
+   // Properties dialog for the default settings, so the user can make changes
+   static BOOL ShowDefaultProperties();
+
+   // Routine to make the an already running copy of Apcupsd bring up its
+   // About box so you can check the version!
+   static BOOL ShowAboutBox();
+
+   // Routine to make the an already running copy of Apcupsd bring up its
+   // Status dialog
+   static BOOL ShowStatus();
+
+   // Routine to make the an already running copy of Apcupsd bring up its
+   // Events dialog
+   static BOOL ShowEvents();
+
+   // Routine to make an already running copy of Apcupsd form an outgoing
+   // connection to a new ups client
+   static BOOL PostAddNewClient(unsigned long ipaddress);
+};
+
+#endif
diff --git a/bacula/src/filed/win32/winstat.cpp b/bacula/src/filed/win32/winstat.cpp
new file mode 100755 (executable)
index 0000000..a5171d8
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Bacula File daemon Status Dialog box
+ *
+ *  Inspired from the VNC code by ATT.
+ *
+ * Copyright (2000) Kern E. Sibbald
+ *
+ */
+/*
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+ */
+
+#include "winbacula.h"
+#include "winstat.h"
+
+extern void FillStatusBox(HWND hwnd, int id_list);
+
+bacStatus::bacStatus()
+{
+   visible = FALSE;
+}
+
+bacStatus::~bacStatus()
+{
+}
+
+
+/* Dialog box handling functions */
+void
+bacStatus::Show(BOOL show)
+{
+   if (show && !visible) {
+         DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_STATUS), NULL,
+             (DLGPROC)DialogProc, (LONG)this);
+   }
+}
+
+BOOL CALLBACK
+bacStatus::DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+   /* Get class pointer from user data */
+   bacStatus *_this = (bacStatus *)GetWindowLong(hwnd, GWL_USERDATA);
+
+   switch (uMsg) {
+   case WM_INITDIALOG:
+      /* Set class pointer in user data */
+      SetWindowLong(hwnd, GWL_USERDATA, lParam);
+      _this = (bacStatus *)lParam;
+
+      /* show the dialog */
+      SetForegroundWindow(hwnd);
+
+      /* Update every 5 seconds */
+      SetTimer(hwnd, 1, 5000, NULL); 
+      _this->visible = TRUE;
+      FillStatusBox(hwnd, IDC_LIST);
+      return TRUE;
+
+   case WM_TIMER:
+      FillStatusBox(hwnd, IDC_LIST);
+      return TRUE;
+
+   case WM_COMMAND:
+      switch (LOWORD(wParam)) {
+      case IDCANCEL:
+      case IDOK:
+         KillTimer(hwnd, 1);
+         EndDialog(hwnd, TRUE);
+         _this->visible = FALSE;
+         return TRUE;
+      }
+      break;
+
+   case WM_DESTROY:
+      KillTimer(hwnd, 1);
+      EndDialog(hwnd, FALSE);
+      _this->visible = FALSE;
+      return TRUE;
+   }
+   return 0;
+}
diff --git a/bacula/src/filed/win32/winstat.h b/bacula/src/filed/win32/winstat.h
new file mode 100755 (executable)
index 0000000..008ad56
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Bacula Status Dialog header file
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+ */
+
+
+class bacStatus;
+
+#ifndef _WINSTAT_H_ 
+#define _WINSTAT_H_
+
+class bacStatus
+{
+public:
+   bacStatus();
+   ~bacStatus();
+
+   /* The Windows callback routine */
+   static BOOL CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+   void Show(BOOL show);
+
+   BOOL visible;
+};
+
+#endif
diff --git a/bacula/src/filed/win32/wintray.cpp b/bacula/src/filed/win32/wintray.cpp
new file mode 100755 (executable)
index 0000000..c74c1d4
--- /dev/null
@@ -0,0 +1,368 @@
+//  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+//  This file was part of the vnc system.
+//
+//  The vnc system 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.
+//
+// If the source code for the vnc system is not available from the place 
+// whence you received this file, check http://www.uk.research.att.com/vnc or contact
+// the authors on vnc@uk.research.att.com for information on obtaining it.
+//
+// This file has been adapted to the Win32 version of Bacula
+// by Kern E. Sibbald.  Many thanks to ATT and James Weatherall,
+// the original author, for providing an excellent template.
+//
+// Copyright (2000) Kern E. Sibbald
+//
+
+
+
+// Tray
+
+// Implementation of a system tray icon & menu for Bacula
+
+#include "winbacula.h"
+#include "winservice.h"
+#include <lmcons.h>
+
+// Header
+
+#include "wintray.h"
+
+// Constants
+#ifdef properties_implemented
+const UINT MENU_PROPERTIES_SHOW = RegisterWindowMessage("Bacula.Properties.User.Show");
+const UINT MENU_DEFAULT_PROPERTIES_SHOW = RegisterWindowMessage("Bacula.Properties.Default.Show");
+#endif
+const UINT MENU_ABOUTBOX_SHOW = RegisterWindowMessage("Bacula.AboutBox.Show");
+const UINT MENU_STATUS_SHOW = RegisterWindowMessage("Bacula.Status.Show");
+const UINT MENU_EVENTS_SHOW = RegisterWindowMessage("Bacula.Events.Show");
+const UINT MENU_SERVICEHELPER_MSG = RegisterWindowMessage("Bacula.ServiceHelper.Message");
+const UINT MENU_ADD_CLIENT_MSG = RegisterWindowMessage("Bacula.AddClient.Message");
+const char *MENU_CLASS_NAME = "Bacula Tray Icon";
+
+extern char *bac_status(int stat);
+extern int bacstat;
+
+// Implementation
+
+bacMenu::bacMenu()
+{
+   // Create a dummy window to handle tray icon messages
+   WNDCLASSEX wndclass;
+
+   wndclass.cbSize                 = sizeof(wndclass);
+   wndclass.style                  = 0;
+   wndclass.lpfnWndProc    = bacMenu::WndProc;
+   wndclass.cbClsExtra             = 0;
+   wndclass.cbWndExtra             = 0;
+   wndclass.hInstance              = hAppInstance;
+   wndclass.hIcon                  = LoadIcon(NULL, IDI_APPLICATION);
+   wndclass.hCursor                = LoadCursor(NULL, IDC_ARROW);
+   wndclass.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
+   wndclass.lpszMenuName   = (const char *) NULL;
+   wndclass.lpszClassName  = MENU_CLASS_NAME;
+   wndclass.hIconSm                = LoadIcon(NULL, IDI_APPLICATION);
+
+   RegisterClassEx(&wndclass);
+
+   m_hwnd = CreateWindow(MENU_CLASS_NAME,
+                           MENU_CLASS_NAME,
+                           WS_OVERLAPPEDWINDOW,
+                           CW_USEDEFAULT,
+                           CW_USEDEFAULT,
+                           200, 200,
+                           NULL,
+                           NULL,
+                           hAppInstance,
+                           NULL);
+   if (m_hwnd == NULL) {
+      PostQuitMessage(0);
+      return;
+   }
+
+   // record which client created this window
+   SetWindowLong(m_hwnd, GWL_USERDATA, (LONG) this);
+
+   // Timer to trigger icon updating
+   SetTimer(m_hwnd, 1, 5000, NULL);
+
+   // Load the icons for the tray
+   m_idle_icon = LoadIcon(hAppInstance, MAKEINTRESOURCE(IDI_IDLE));
+   m_running_icon = LoadIcon(hAppInstance, MAKEINTRESOURCE(IDI_RUNNING));
+   m_error_icon = LoadIcon(hAppInstance, MAKEINTRESOURCE(IDI_JOB_ERROR));
+
+   // Load the popup menu
+   m_hmenu = LoadMenu(hAppInstance, MAKEINTRESOURCE(IDR_TRAYMENU));
+
+   // Install the tray icon!
+   AddTrayIcon();
+}
+
+bacMenu::~bacMenu()
+{
+   // Remove the tray icon
+   SendTrayMsg(NIM_DELETE, 0);
+        
+   // Destroy the loaded menu
+   if (m_hmenu != NULL)
+      DestroyMenu(m_hmenu);
+}
+
+void
+bacMenu::AddTrayIcon()
+{
+   SendTrayMsg(NIM_ADD, bacstat);
+}
+
+void
+bacMenu::DelTrayIcon()
+{
+   SendTrayMsg(NIM_DELETE, 0);
+}
+
+
+void
+bacMenu::UpdateTrayIcon(int bacstat)
+{
+   (void *)bac_status(0);
+   SendTrayMsg(NIM_MODIFY, bacstat);
+}
+
+void
+bacMenu::SendTrayMsg(DWORD msg, int bacstat)
+{
+   // Create the tray icon message
+   m_nid.hWnd = m_hwnd;
+   m_nid.cbSize = sizeof(m_nid);
+   m_nid.uID = IDI_BACULA;                  // never changes after construction
+   if (bacstat == 0)
+      m_nid.hIcon = m_idle_icon;
+   else if (bacstat == 1)
+      m_nid.hIcon = m_running_icon;
+   else if (bacstat < 0)
+      m_nid.hIcon = m_error_icon;
+
+   m_nid.uFlags = NIF_ICON | NIF_MESSAGE;
+   m_nid.uCallbackMessage = WM_TRAYNOTIFY;
+
+
+   // Use resource string as tip if there is one
+   if (LoadString(hAppInstance, IDI_BACULA, m_nid.szTip, sizeof(m_nid.szTip))) {
+       m_nid.uFlags |= NIF_TIP;
+   }
+
+   // Try to add the Bacula status to the tip string, if possible
+   if (m_nid.uFlags & NIF_TIP) {
+       strncpy(m_nid.szTip, bac_status(0), (sizeof(m_nid.szTip)-1));
+   }
+
+   // Send the message
+   if (Shell_NotifyIcon(msg, &m_nid)) {
+      EnableMenuItem(m_hmenu, ID_CLOSE, MF_ENABLED);
+   } else {
+      if (!bacService::RunningAsService()) {
+         if (msg == NIM_ADD) {
+            // The tray icon couldn't be created, so use the Properties dialog
+            // as the main program window
+            PostQuitMessage(0);
+         }
+      }
+   }
+}
+
+// Process window messages
+LRESULT CALLBACK bacMenu::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+        // This is a static method, so we don't know which instantiation we're 
+        // dealing with. We use Allen Hadden's (ahadden@taratec.com) suggestion 
+        // from a newsgroup to get the pseudo-this.
+        bacMenu *_this = (bacMenu *) GetWindowLong(hwnd, GWL_USERDATA);
+
+        switch (iMsg)
+        {
+
+                // Every five seconds, a timer message causes the icon to update
+        case WM_TIMER:
+                // *** HACK for running servicified
+                if (bacService::RunningAsService()) {
+                    // Attempt to add the icon if it's not already there
+                    _this->AddTrayIcon();
+                    // Trigger a check of the current user
+                    PostMessage(hwnd, WM_USERCHANGED, 0, 0);
+                }
+
+                // Update the icon
+                _this->UpdateTrayIcon(bacstat);
+                break;
+
+                // DEAL WITH NOTIFICATIONS FROM THE SERVER:
+        case WM_SRV_CLIENT_AUTHENTICATED:
+        case WM_SRV_CLIENT_DISCONNECT:
+                // Adjust the icon accordingly
+                _this->UpdateTrayIcon(bacstat);
+                return 0;
+
+                // STANDARD MESSAGE HANDLING
+        case WM_CREATE:
+                return 0;
+
+        case WM_COMMAND:
+                // User has clicked an item on the tray menu
+                switch (LOWORD(wParam))
+                {
+                case ID_STATUS:
+                        // Show the status dialog
+                        _this->m_status.Show(TRUE);
+                        _this->UpdateTrayIcon(bacstat);
+                        break;
+
+                case ID_EVENTS:
+                        // Show the Events dialog
+                        _this->m_events.Show(TRUE);
+                        _this->UpdateTrayIcon(bacstat);
+                        break;
+
+
+                case ID_KILLCLIENTS:
+                        // Disconnect all currently connected clients
+                        break;
+
+                case ID_ABOUT:
+                        // Show the About box
+                        _this->m_about.Show(TRUE);
+                        break;
+
+                case ID_CLOSE:
+                        // User selected Close from the tray menu
+                        PostMessage(hwnd, WM_CLOSE, 0, 0);
+                        break;
+
+                }
+                return 0;
+
+        case WM_TRAYNOTIFY:
+                // User has clicked on the tray icon or the menu
+                {
+                        // Get the submenu to use as a pop-up menu
+                        HMENU submenu = GetSubMenu(_this->m_hmenu, 0);
+
+                        // What event are we responding to, RMB click?
+                        if (lParam==WM_RBUTTONUP) {
+                                if (submenu == NULL) {
+                                        return 0;
+                                }
+
+                                // Make the first menu item the default (bold font)
+                                SetMenuDefaultItem(submenu, 0, TRUE);
+                                
+                                // Get the current cursor position, to display the menu at
+                                POINT mouse;
+                                GetCursorPos(&mouse);
+
+                                // There's a "bug"
+                                // (Microsoft calls it a feature) in Windows 95 that requires calling
+                                // SetForegroundWindow. To find out more, search for Q135788 in MSDN.
+                                //
+                                SetForegroundWindow(_this->m_nid.hWnd);
+
+                                // Display the menu at the desired position
+                                TrackPopupMenu(submenu,
+                                                0, mouse.x, mouse.y, 0,
+                                                _this->m_nid.hWnd, NULL);
+
+                                return 0;
+                        }
+                        
+                        // Or was there a LMB double click?
+                        if (lParam==WM_LBUTTONDBLCLK) {
+                                // double click: execute first menu item
+                                SendMessage(_this->m_nid.hWnd,
+                                                        WM_COMMAND, 
+                                                        GetMenuItemID(submenu, 0),
+                                                        0);
+                        }
+
+                        return 0;
+                }
+
+        case WM_CLOSE:
+                break;
+
+        case WM_DESTROY:
+                // The user wants Bacula to quit cleanly...
+                PostQuitMessage(0);
+                return 0;
+
+        case WM_QUERYENDSESSION:
+                // Are we running as a system service?
+                // Or is the system shutting down (in which case we should check anyway!)
+                if ((!bacService::RunningAsService()) || (lParam == 0)) {
+                        // No, so we are about to be killed
+
+                        // If there are remote connections then we should verify
+                        // that the user is happy about killing them.
+
+                        // Finally, post a quit message, just in case
+                        PostQuitMessage(0);
+                        return TRUE;
+                }
+
+                // Tell the OS that we've handled it anyway
+//              PostQuitMessage(0);
+                return TRUE;
+
+        
+        default:
+                if (iMsg == MENU_ABOUTBOX_SHOW) {
+                        // External request to show our About dialog
+                        PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_ABOUT, 0), 0);
+                        return 0;
+                }
+                if (iMsg == MENU_STATUS_SHOW) {
+                        // External request to show our status
+                        PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_STATUS, 0), 0);
+                        return 0;
+                }
+
+                if (iMsg == MENU_EVENTS_SHOW) {
+                        // External request to show our Events dialogue
+                        PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_EVENTS, 0), 0);
+                        return 0;
+                }
+
+                if (iMsg == MENU_SERVICEHELPER_MSG) {
+                        // External ServiceHelper message.
+                        // This message holds a process id which we can use to
+                        // impersonate a specific user.  In doing so, we can load their
+                        // preferences correctly
+                        bacService::ProcessUserHelperMessage(wParam, lParam);
+
+                        // - Trigger a check of the current user
+                        PostMessage(hwnd, WM_USERCHANGED, 0, 0);
+                        return 0;
+                }
+                if (iMsg == MENU_ADD_CLIENT_MSG) {
+                        // Add Client message.  This message includes an IP address
+                        // of a listening client, to which we should connect.
+
+                        return 0;
+                }
+        }
+
+        // Message not recognised
+        return DefWindowProc(hwnd, iMsg, wParam, lParam);
+}
diff --git a/bacula/src/filed/win32/wintray.h b/bacula/src/filed/win32/wintray.h
new file mode 100755 (executable)
index 0000000..34b422a
--- /dev/null
@@ -0,0 +1,93 @@
+//  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+//  This file is part of the VNC system.
+//
+//  The VNC system 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.
+//
+// If the source code for the VNC system is not available from the place 
+// whence you received this file, check http://www.uk.research.att.com/vnc or contact
+// the authors on vnc@uk.research.att.com for information on obtaining it.
+//
+// This file has been adapted to the Win32 version of Bacula
+// by Kern E. Sibbald.  Many thanks to ATT and James Weatherall,
+// the original author, for providing an excellent template.
+//
+// Copyright (2000) Kern E. Sibbald
+//
+
+
+
+// winMenu
+
+// This class handles creation of a system-tray icon & menu
+
+class bacMenu;
+
+#if (!defined(_win_bacMENU))
+#define _win_bacMENU
+
+#include <lmcons.h>
+#include "winabout.h"
+#include "winstat.h"
+#include "winevents.h"
+
+// Constants
+extern const UINT MENU_ABOUTBOX_SHOW;
+extern const UINT MENU_STATUS_SHOW;
+extern const UINT MENU_EVENTS_SHOW;
+extern const UINT MENU_SERVICEHELPER_MSG;
+extern const UINT MENU_ADD_CLIENT_MSG;
+extern const char *MENU_CLASS_NAME;
+
+// The tray menu class itself
+class bacMenu
+{
+public:
+   bacMenu();
+   ~bacMenu();
+protected:
+   // Tray icon handling
+   void AddTrayIcon();
+   void DelTrayIcon();
+   void UpdateTrayIcon(int battstat);
+   void SendTrayMsg(DWORD msg, int battstat);
+
+   // Message handler for the tray window
+   static LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
+
+   // Fields
+protected:
+
+   // About dialog for this server
+   bacAbout                m_about;
+
+   // Status dialog for this server
+   bacStatus               m_status;
+
+   bacEvents               m_events;
+
+   HWND                    m_hwnd;
+   HMENU                   m_hmenu;
+   NOTIFYICONDATA          m_nid;
+
+   // The icon handles
+   HICON                   m_idle_icon;
+   HICON                   m_running_icon;
+   HICON                   m_error_icon;
+};
+
+
+#endif
diff --git a/bacula/src/findlib/Makefile.in b/bacula/src/findlib/Makefile.in
new file mode 100644 (file)
index 0000000..be830fe
--- /dev/null
@@ -0,0 +1,93 @@
+#
+#  Find files library Makefile
+#
+@MCOMMON@
+
+srcdir =       .
+VPATH =        .
+.PATH:         .
+
+# one up
+basedir = ..
+# top dir
+topdir = ../..
+# this dir relative to top dir
+thisdir = src/findlib
+
+DEBUG=@DEBUG@
+
+first_rule: all
+dummy:
+
+#
+LIBSRCS = find.c match.c find_one.c
+LIBOBJS = find.o match.o find_one.o
+
+FINDSRCS = testfind.c
+FINDOBJS = testfind.o
+
+.SUFFIXES:     .c .o
+.PHONY:
+.DONTCARE:
+
+# inference rules
+.c.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
+#-------------------------------------------------------------------------
+all: Makefile libfind.a ../lib/libbac.a
+       @echo "==== Make of findlib is good ===="
+       @echo " "
+
+libfind.a: $(LIBOBJS) 
+       $(RMF) libfind.a
+       $(AR) cru $@ $(LIBOBJS)
+       $(RANLIB) $@
+
+testfind: libfind.a $(FINDOBJS)
+       $(CC) -g $(LDFLAGS) -L. -L../lib -o $@ $(FINDOBJS) $(LIBS) $(DLIB) -lfind -lbac -lm
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+install:
+
+uninstall:
+
+
+clean:
+       $(RMF) find testfind core a.out *.a *.o *.bak *~ *.intpro *.extpro 1 2 3
+
+realclean: clean
+       $(RMF) tags
+
+distclean: realclean
+       if test $(srcdir) = .; then $(MAKE) realclean; fi
+       (cd $(srcdir); $(RMF) Makefile)
+
+install:
+
+
+uninstall:
+
+
+
+# Semi-automatic generation of dependencies:
+# Use gcc -M  because X11 `makedepend' doesn't work on all systems
+# and it also includes system headers.
+# `semi'-automatic since dependencies are generated at distribution time.
+
+depend:
+       @$(MV) Makefile Makefile.bak
+       @$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile
+       @$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile
+       @$(CC) -S -M $(CPPFLAGS) $(XINC) -I$(srcdir) -I$(basedir) $(SQL_INC) *.c >> Makefile
+       @if test -f Makefile ; then \
+           $(RMF) Makefile.bak; \
+       else \
+          $(MV) Makefile.bak Makefile; \
+          echo -e "Something went wrong\n\a"; \
+       fi
+
+# -----------------------------------------------------------------------
+# DO NOT DELETE: nice dependency list follows
diff --git a/bacula/src/findlib/find.c b/bacula/src/findlib/find.c
new file mode 100644 (file)
index 0000000..02b4339
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Main routine for finding files on a file system.
+ *  The heart of the work is done in find_one.c
+ *
+ *  Kern E. Sibbald, MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+#include "find.h"
+
+/* Imported functions */
+int find_one_file(FF_PKT *ff, int handle_file(FF_PKT *ff_pkt, void *hpkt), 
+              void *pkt, char *p, dev_t parent_device, int top_level);
+void term_find_one(FF_PKT *ff);
+
+size_t name_max;              /* filename max length */
+size_t path_max;              /* path name max length */
+
+
+/* ****FIXME**** debug until stable */
+#undef bmalloc
+#define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
+
+
+/* 
+ * Initialize the find files "global" variables
+ */
+FF_PKT *init_find_files()
+{
+  FF_PKT *ff;   
+
+  ff = (FF_PKT *) bmalloc(sizeof(FF_PKT));
+  memset(ff, 0, sizeof(FF_PKT));
+
+  init_include_exclude_files(ff);          /* init lists */
+  ff->mtime_only = 1;
+  ff->one_file_system = 1;
+
+   /* Get system path and filename maximum lengths */
+   path_max = pathconf(".", _PC_PATH_MAX);
+   if (path_max < 1024) {
+      path_max = 1024;
+   }
+
+   name_max = pathconf(".", _PC_NAME_MAX);
+   if (name_max < 1024) {
+      name_max = 1024;
+   }
+   path_max++;                       /* add for EOS */
+   name_max++;                       /* add for EOS */
+
+  Dmsg1(100, "init_find_files ff=%p\n", ff);
+  return ff;
+}
+
+/* 
+ * Set find_files options. For the moment, we only
+ * provide for full/incremental saves, and setting
+ * of save_time. For additional options, see above
+ */
+void
+set_find_options(FF_PKT *ff, int incremental, time_t save_time)
+{
+  Dmsg0(100, "Enter set_find_options()\n");
+  ff->incremental = incremental;
+  ff->save_time = save_time;
+  Dmsg0(100, "Leave set_find_options()\n");
+}
+
+/* 
+ * Find all specified files (determined by calls to 
+ * name_add()
+ * This routine calls the (handle_file) subroutine with all
+ * sorts of good information for the final disposition of
+ * the file.
+ * 
+ * Call this subroutine with a callback subroutine as the first
+ * argument and a packet as the second argument, this packet
+ * will be passed back to the callback subroutine as the last
+ * argument.
+ *
+ * The callback subroutine gets called with:
+ *  arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
+ *  arg2 -- the user supplied packet
+ *
+ */
+int
+find_files(FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt), void *his_pkt) 
+{
+   char *file;
+   struct s_included_file *inc = NULL;
+
+   while ((inc = get_next_included_file(ff, inc))) {
+      file = inc->fname;
+      strcpy(ff->VerifyOpts, inc->VerifyOpts); /* Copy options for this file */
+      Dmsg1(50, "find_files: file=%s\n", file);
+      if (!file_is_excluded(ff, file)) {
+        if (!find_one_file(ff, callback, his_pkt, file, (dev_t)-1, 1)) {
+           return 0;                  /* error return */
+        }
+      }
+   }
+   return 1;
+}
+
+/*
+ * Terminate find_files() and release
+ * all allocated memory   
+ */
+void
+term_find_files(FF_PKT *ff)
+{
+  term_include_exclude_files(ff);
+  term_find_one(ff);
+  free(ff);
+  return;
+}
diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h
new file mode 100755 (executable)
index 0000000..15d9b11
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * File types as returned by find_files()
+ *
+ *     Kern Sibbald MIM
+ */
+/*
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+ */
+
+#ifndef __FILES_H
+#define __FILES_H
+
+#ifdef HAVE_FNMATCH
+#include <fnmatch.h>
+#else
+#include "lib/fnmatch.h"
+#endif
+
+
+/* 
+ *  NOTE!!! These go on the tape, so don't change them. If 
+ *  need be, add to them.
+ */
+#define FT_LNKSAVED   1               /* hard link to file already saved */  
+#define FT_REGE       2               /* Regular file but empty */
+#define FT_REG        3               /* Regular file */
+#define FT_LNK        4               /* Soft Link */
+#define FT_DIR        5               /* Directory */
+#define FT_SPEC       6               /* Special file -- chr, blk, fifo, sock */
+#define FT_NOACCESS   7               /* Not able to access */
+#define FT_NOFOLLOW   8               /* Could not follow link */
+#define FT_NOSTAT     9               /* Could not stat file */
+#define FT_NOCHG     10               /* Incremental option, file not changed */
+#define FT_DIRNOCHG  11               /* Incremental option, directory not changed */
+#define FT_ISARCH    12               /* Trying to save archive file */
+#define FT_NORECURSE 13               /* No recursion into directory */
+#define FT_NOFSCHG   14               /* Different file system, prohibited */
+#define FT_NOOPEN    15               /* Could not open directory */
+
+/* FileSet options */     
+#define FO_MD5      0x1               /* Do MD5 checksum */
+#define FO_GZIP     0x2               /* Do Zlib compression */
+
+
+#define OPT_compute_MD5       0x01
+#define OPT_GZIP_compression  0x02
+#define OPT_no_recursion      0x04
+
+
+struct s_included_file {
+   struct s_included_file *next;
+   int options;                       /* backup options */
+   int len;                           /* length of fname */
+   int pattern;                       /* set if pattern */
+   char VerifyOpts[20];               /* Options for verify */
+   char fname[1];
+};
+
+struct s_excluded_file {
+   struct s_excluded_file *next;
+   int len;
+   char fname[1];
+};
+
+
+/*
+ * Definition of the find_files packet passed as the
+ * first argument to the find_files callback subroutine.
+ */
+typedef struct ff {
+   char *fname;                       /* filename */
+   char *link;                        /* link if file linked */
+   struct stat statp;                 /* stat packet */
+   int type;                          /* FT_ type from above */
+   int flags;                         /* control flags */
+   int ff_errno;                      /* errno */
+   int incremental;                   /* do incremental save */
+   time_t save_time;                  /* start of incremental time */
+   int no_recursion;                  /* do not recurse into sub directories */
+   int mtime_only;                    /* incremental on mtime_only */
+   int dereference;                   /* follow links */
+   int compute_MD5;                   /* compute MD5 checksum */
+   int GZIP_compression;              /* compress the file */
+   int one_file_system;               /* do not traverse file systems */
+   int atime_preserve;                /* preserve access times */
+   int null_output_device;            /* using null output device */
+   char VerifyOpts[20];
+   struct s_included_file *included_files_list;
+   struct s_excluded_file *excluded_files_list;
+   struct s_excluded_file *excluded_paths_list;
+
+   struct f_link *linklist;           /* hard linked files */
+} FF_PKT;
+
+/* From find.c */
+FF_PKT *init_find_files();
+void set_find_options(FF_PKT *ff, int incremental, time_t mtime);
+int find_files(FF_PKT *ff, int sub(FF_PKT *ff_pkt, void *hpkt), void *pkt);
+void term_find_files(FF_PKT *ff);
+
+/* From match.c */
+void init_include_exclude_files(FF_PKT *ff);
+void term_include_exclude_files(FF_PKT *ff);
+void add_fname_to_include_list(FF_PKT *ff, int prefixed, char *fname);
+void add_fname_to_exclude_list(FF_PKT *ff, char *fname);
+struct s_included_file *get_next_included_file(
+    FF_PKT *ff, struct s_included_file *inc);
+int file_is_excluded(FF_PKT *ff, char *file);
+int file_is_included(FF_PKT *ff, char *file);
+
+#endif /* __FILES_H */
diff --git a/bacula/src/findlib/find_one.c b/bacula/src/findlib/find_one.c
new file mode 100755 (executable)
index 0000000..dcb0381
--- /dev/null
@@ -0,0 +1,351 @@
+/* 
+
+   Copyright 1988, 92,93,94,95,96,97, 1999 Free Software Foundation, Inc.
+   Written by John Gilmore, starting 1985-08-25.
+
+   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.    
+
+   Massively changed from GNU TAR source code to adapt to Bacula
+   by Kern Sibbald, MM
+
+ */
+
+#include "bacula.h"
+#include "find.h"
+#include "system.h"
+
+
+extern size_t name_max;              /* filename max length */
+extern size_t path_max;              /* path name max length */
+
+#ifndef HAVE_READDIR_R
+int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+#endif
+
+
+/* ****FIXME**** debug until stable */
+#undef bmalloc
+#define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
+
+
+/*
+ * Structure for keeping track of hard linked files
+ */
+struct f_link {
+    struct f_link *next;
+    dev_t dev;
+    ino_t ino;
+    short linkcount;
+    char name[1];
+};
+
+
+#if HAVE_UTIME_H
+# include <utime.h>
+#else
+struct utimbuf
+  {
+    long actime;
+    long modtime;
+  };
+#endif
+
+
+/*
+ * Find a single file.                       
+ * handle_file is the callback for handling the file.
+ * p is the filename
+ * parent_device is the device we are currently on 
+ * top_level is 1 when not recursing.
+ */
+int
+find_one_file(FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), void *pkt, 
+                           char *p, dev_t parent_device, int top_level)
+{
+  struct utimbuf restore_times;
+  int rtn_stat;
+
+  ff_pkt->fname = ff_pkt->link = p;
+  if (ff_pkt->compute_MD5) {
+     ff_pkt->flags |= FO_MD5;
+  }
+  if (ff_pkt->GZIP_compression) {
+     ff_pkt->flags |= FO_GZIP;
+  }
+
+  /* Use stat if following (rather than dumping) 4.2BSD's symbolic links.
+     Otherwise, use lstat (which falls back to stat if no symbolic links).  */
+
+  if (ff_pkt->dereference != 0
+#if STX_HIDDEN && !_LARGE_FILES /* AIX */
+      ? statx(p, &ff_pkt->statp, STATSIZE, STX_HIDDEN)
+      : statx(p, &ff_pkt->statp, STATSIZE, STX_HIDDEN | STX_LINK)
+#else
+      ? stat(p, &ff_pkt->statp) : lstat(p, &ff_pkt->statp)
+#endif
+      )
+    {
+      /* Cannot stat file */
+      ff_pkt->type = FT_NOSTAT;
+      ff_pkt->ff_errno = errno;
+      return handle_file(ff_pkt, pkt);
+    }
+
+Dmsg1(60, "File ----: %s\n", p);
+if (S_ISLNK(ff_pkt->statp.st_mode))
+   Dmsg1(60, "Link-------------: %s \n", p);
+
+  /* Save current times of this directory in case we need to
+   * reset them because the user doesn't want them changed.
+   */
+  restore_times.actime = ff_pkt->statp.st_atime;
+  restore_times.modtime = ff_pkt->statp.st_mtime;
+
+
+#ifdef S_ISHIDDEN
+  if (S_ISHIDDEN(ff_pkt->statp.st_mode)) {
+      char *new = alloca(strlen(p) + 2);
+      if (new) {
+         strcpy (new, p);
+          strcat (new, "@");
+         p = new;
+         ff_pkt->link = p;
+      }
+  }
+#endif
+
+  /* See if we want only new files, and check if this one is too old to
+     put in the archive.  */
+
+  if (ff_pkt->incremental && !S_ISDIR(ff_pkt->statp.st_mode)) {
+     Dmsg1(100, "Non-directory incremental: %s\n", ff_pkt->fname);
+     /* Not a directory */
+     if (ff_pkt->statp.st_mtime < ff_pkt->save_time
+        && (ff_pkt->mtime_only || 
+            ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
+       /* Incremental option, file not changed */
+       ff_pkt->type = FT_NOCHG;
+        Dmsg1(100, "File not changed: %s\n", ff_pkt->fname);
+        Dmsg4(200, "save_time=%d mtime=%d mtime_only=%d st_ctime=%d\n",
+          ff_pkt->save_time, ff_pkt->statp.st_mtime, 
+          ff_pkt->mtime_only, ff_pkt->statp.st_ctime);
+       return handle_file(ff_pkt, pkt);
+     }
+  }
+
+#if xxxxxxx
+  /* See if we are trying to dump the archive. */
+  if (ar_dev && ff_pkt->statp.st_dev == ar_dev && ff_pkt->statp.st_ino == ar_ino) {
+      ff_pkt->type = FT_ISARCH;
+      return handle_file(ff_pkt, pkt);
+  }
+#endif
+
+  /* Check for multiple links.
+     NOTE: CTG is Masscomp contiguous files  
+
+     We maintain a list of all such files that we've written so far.  Any
+     time we see another, we check the list and avoid dumping the data
+     again if we've done it once already.  */
+
+  if (ff_pkt->statp.st_nlink > 1
+      && (S_ISREG(ff_pkt->statp.st_mode)
+         || S_ISCTG(ff_pkt->statp.st_mode)
+         || S_ISCHR(ff_pkt->statp.st_mode)
+         || S_ISBLK(ff_pkt->statp.st_mode)
+         || S_ISFIFO(ff_pkt->statp.st_mode)
+         || S_ISSOCK(ff_pkt->statp.st_mode))) {
+
+      struct f_link *lp;
+
+      /* FIXME: First quick and dirty. Hashing, etc later.  */
+      for (lp = ff_pkt->linklist; lp; lp = lp->next)
+        if (lp->ino == ff_pkt->statp.st_ino && lp->dev == ff_pkt->statp.st_dev) {
+            ff_pkt->link = lp->name;
+            ff_pkt->type = FT_LNKSAVED;
+            return handle_file(ff_pkt, pkt);
+        }
+
+      /* Not found.  Add it to the list of possible links.  */
+
+      lp = (struct f_link *)bmalloc(sizeof (struct f_link) + strlen(p));
+      lp->ino = ff_pkt->statp.st_ino;
+      lp->dev = ff_pkt->statp.st_dev;
+      strcpy (lp->name, p);
+      lp->next = ff_pkt->linklist;
+      ff_pkt->linklist = lp;
+  }
+
+  /* This is not a link to a previously dumped file, so dump it.  */
+  if (S_ISREG(ff_pkt->statp.st_mode) || S_ISCTG(ff_pkt->statp.st_mode)) {
+      off_t sizeleft;
+      int header_moved;
+
+      header_moved = 0;
+
+      sizeleft = ff_pkt->statp.st_size;
+
+      /* Don't bother opening empty, world readable files.  Also do not open
+        files when archive is meant for /dev/null.  */
+      if (ff_pkt->null_output_device || (sizeleft == 0
+             && MODE_R == (MODE_R & ff_pkt->statp.st_mode))) {
+        ff_pkt->type = FT_REGE;
+      } else {
+        ff_pkt->type = FT_REG;
+      }
+      return handle_file(ff_pkt, pkt);
+
+  } else if (S_ISLNK(ff_pkt->statp.st_mode)) {
+      int size;
+      char *buffer = (char *)alloca(PATH_MAX + 1);
+
+      size = readlink(p, buffer, PATH_MAX + 1);
+      if (size < 0) {
+         /* Could not follow link */                             
+         ff_pkt->type = FT_NOFOLLOW;
+         ff_pkt->ff_errno = errno;
+         return handle_file(ff_pkt, pkt);
+      }
+      buffer[size] = '\0';
+      ff_pkt->link = buffer;
+      ff_pkt->type = FT_LNK;          /* got a real link */
+      return handle_file(ff_pkt, pkt);
+
+  } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
+      DIR *directory;
+      struct dirent *entry, *result;
+      char *namebuf;
+      size_t buflen;
+      size_t len;
+      int status;
+      dev_t our_device = ff_pkt->statp.st_dev;
+
+      if (access(p, R_OK) == -1 && geteuid () != 0) {
+         /* Could not access() directory */
+         ff_pkt->type = FT_NOACCESS;
+         ff_pkt->ff_errno = errno;
+         return handle_file(ff_pkt, pkt);
+      }
+
+      /* Build new prototype name.  Ensure exactly one trailing slash. */
+      len = strlen(p);
+      buflen = len + NAME_FIELD_SIZE;
+      namebuf = (char *)bmalloc(buflen + 2);
+      strncpy(namebuf, p, buflen);
+      while (len >= 1 && namebuf[len - 1] == '/')
+       len--;
+      namebuf[len++] = '/';
+      namebuf[len] = '\0';
+
+      ff_pkt->link = namebuf;
+      if (ff_pkt->incremental &&
+         (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
+          ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
+        /* Incremental option, directory entry not changed */
+        ff_pkt->type = FT_DIRNOCHG;
+      } else {
+        ff_pkt->type = FT_DIR;
+      }
+      handle_file(ff_pkt, pkt);       /* handle directory entry */
+
+      ff_pkt->link = ff_pkt->fname;     /* reset "link" */
+
+      /* See if we are about to recurse into a directory, and avoid doing
+        so if the user wants that we do not descend into directories.  */
+
+      if (ff_pkt->no_recursion) {
+        free(namebuf);
+        /* No recursion into this directory */
+        ff_pkt->type = FT_NORECURSE;
+        return handle_file(ff_pkt, pkt);
+      }
+
+      /* See if we are crossing from one file system to another, and
+        avoid doing so if the user only wants to dump one file system.  */
+
+      if (ff_pkt->one_file_system && !top_level
+         && parent_device != ff_pkt->statp.st_dev) {
+         free(namebuf);
+         ff_pkt->type = FT_NOFSCHG;
+         return handle_file(ff_pkt, pkt);
+      }
+
+      /* Now output all the files in the directory.  */
+
+      errno = 0;               /* FIXME: errno should be read-only */
+
+      if ((directory = opendir(p)) == NULL) {
+         free(namebuf);
+         ff_pkt->type = FT_NOOPEN;
+         ff_pkt->ff_errno = errno;
+         return handle_file(ff_pkt, pkt);
+      }
+
+      /* FIXME: Should speed this up by cd-ing into the dir.  */
+
+      rtn_stat = 1;
+      entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 10);
+      for ( ;; ) {
+         char *p;
+
+         status  = readdir_r(directory, entry, &result);
+          Dmsg3(200, "readdir stat=%d result=%x name=%s\n", status, result,
+            entry->d_name);
+         if (status != 0 || result == NULL) {
+            break;
+         }
+         p = entry->d_name;
+          /* Skip `.', `..', and excluded file names.  */
+          if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
+              (p[1] == '.' && p[2] == '\0')))) {
+            continue;
+         }
+
+         if ((int)NAMLEN(entry) + len >= buflen) {
+             buflen = len + NAMLEN(entry);
+             namebuf = (char *)brealloc(namebuf, buflen + 2);
+         }
+         strcpy(namebuf + len, entry->d_name);
+         if (!file_is_excluded(ff_pkt, namebuf)) {
+            rtn_stat = find_one_file(ff_pkt, handle_file, pkt, namebuf, our_device, 0);
+         }
+      }
+      closedir(directory);
+      free(namebuf);
+      free(entry);
+      if (ff_pkt->atime_preserve) {
+        utime(p, &restore_times);
+      }
+      return rtn_stat;
+  } /* end check for directory */
+
+  /* The only remaining types are special (character, ...) files */
+  ff_pkt->type = FT_SPEC;
+  return handle_file(ff_pkt, pkt);
+}
+
+void term_find_one(FF_PKT *ff)
+{
+  struct f_link *lp, *lc;
+  
+  /* Free up list of hard linked files */
+  for (lp = ff->linklist; lp;) {
+     lc = lp;
+     lp = lp->next;
+     if (lc)
+       free(lc);
+  }
+  return;
+}
diff --git a/bacula/src/findlib/match.c b/bacula/src/findlib/match.c
new file mode 100644 (file)
index 0000000..7b42e8e
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ *  Routines used to keep and match include and exclude
+ *   filename/pathname patterns.
+ *
+ *   Kern E. Sibbald, December MMI
+ *
+ */
+/*
+   Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "find.h"
+
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+
+#ifndef FNM_LEADING_DIR
+#define FNM_LEADING_DIR 0
+#endif
+
+#undef bmalloc
+#define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
+
+#ifdef HAVE_CYGWIN
+static int win32_client = 1;
+#else
+static int win32_client = 0;
+#endif
+
+       
+/*
+ * Initialize structures for filename matching
+ */
+void init_include_exclude_files(FF_PKT *ff)
+{
+}
+
+/*
+ * Done doing filename matching, release all 
+ *  resources used.
+ */
+void term_include_exclude_files(FF_PKT *ff)
+{
+   struct s_included_file *inc, *next_inc;
+   struct s_excluded_file *exc, *next_exc;
+
+   for (inc=ff->included_files_list; inc; ) {
+      next_inc = inc->next;
+      free(inc);
+      inc = next_inc;
+   }
+
+   for (exc=ff->excluded_files_list; exc; ) {
+      next_exc = exc->next;
+      free(exc);
+      exc = next_exc;
+   }
+
+   for (exc=ff->excluded_paths_list; exc; ) {
+      next_exc = exc->next;
+      free(exc);
+      exc = next_exc;
+   }
+   
+}
+
+/*
+ * Add a filename to list of included files
+ */
+void add_fname_to_include_list(FF_PKT *ff, int prefixed, char *fname)
+{
+   int len, j;
+   struct s_included_file *inc;
+   char *p;
+
+   len = strlen(fname);
+
+   inc =(struct s_included_file *) bmalloc(sizeof(struct s_included_file) + len + 1);
+   inc->next = ff->included_files_list;
+   inc->options = 0;
+   inc->VerifyOpts[0] = 'V'; 
+   inc->VerifyOpts[1] = ':';
+   inc->VerifyOpts[2] = 0;
+
+   /* prefixed = preceded with options */
+   if (prefixed) {
+      for (p=fname; *p && *p != ' '; p++) {
+        switch (*p) {
+            case '0':                  /* no option */
+              break;
+            case 'M':                  /* MD5 */
+              inc->options |= OPT_compute_MD5;
+              break;
+            case 'Z':                  /* gzip compression */
+              inc->options |= OPT_GZIP_compression;
+              break;
+            case 'h':                  /* no recursion */
+              inc->options |= OPT_no_recursion;
+              break;
+            case 'V':                  /* verify options */
+              /* Copy Verify Options */
+               for (j=0; *p && *p != ':'; p++) {
+                 inc->VerifyOpts[j] = *p;
+                 if (j < (int)sizeof(inc->VerifyOpts) - 1) {
+                    j++;
+                 }
+              }
+              inc->VerifyOpts[j] = 0;
+              break;
+           default:
+               Emsg1(M_ERROR, 0, "Unknown include/exclude option: %c\n", *p);
+              break;
+        }
+      }
+      /* Skip past space(s) */
+      for ( ; *p == ' '; p++)
+        {}
+   } else {
+      p = fname;
+   }
+
+   strcpy(inc->fname, p);                
+   len = strlen(p);
+   /* Zap trailing slashes.  */
+   p += len - 1;
+   while (p > inc->fname && *p == '/') {
+      *p-- = 0;
+      len--;
+   }
+   inc->len = len;
+   /* Check for wild cards */
+   inc->pattern = 0;
+   for (p=inc->fname; *p; p++) {
+      if (*p == '*' || *p == '[' || *p == '?') {
+        inc->pattern = 1;
+        break;
+      }
+   }
+   ff->included_files_list = inc;
+   Dmsg1(50, "add_fname_to_include fname=%s\n", inc->fname);
+}
+
+/*
+ * We add an exclude name to either the exclude path
+ *  list or the exclude filename list.
+ */
+void add_fname_to_exclude_list(FF_PKT *ff, char *fname)
+{
+   int len;
+   struct s_excluded_file *exc, **list;
+
+   Dmsg1(20, "Add name to exclude: %s\n", fname);
+
+   if (strchr(fname, '/')) {
+      list = &ff->excluded_paths_list;
+   } else {
+      list = &ff->excluded_files_list;
+   }
+  
+   len = strlen(fname);
+
+   exc = (struct s_excluded_file *)bmalloc(sizeof(struct s_excluded_file) + len + 1);
+   exc->next = *list;
+   exc->len = len;
+   strcpy(exc->fname, fname);                
+   *list = exc;
+}
+
+
+/*
+ * Get next included file
+ */
+struct s_included_file *get_next_included_file(FF_PKT *ff, struct s_included_file *ainc)
+{
+   struct s_included_file *inc;
+
+   if (ainc == NULL) { 
+      inc = ff->included_files_list;
+   } else {
+      inc = ainc->next;
+   }
+   if (inc) {
+      if (inc->options & OPT_compute_MD5) {
+        ff->compute_MD5 = 1;
+      } else {
+        ff->compute_MD5 = 0;
+      }
+      if (inc->options & OPT_GZIP_compression) {
+        ff->GZIP_compression = 1;
+      } else {
+        ff->GZIP_compression = 0;
+      }
+      if (inc->options & OPT_no_recursion) {
+        ff->no_recursion = 1;
+      } else {
+        ff->no_recursion = 0;
+      }
+   }
+   return inc;
+}
+
+/*
+ * Walk through the included list to see if this
+ *  file is included possibly with wild-cards.
+ */
+
+int file_is_included(FF_PKT *ff, char *file)
+{
+   struct s_included_file *inc = ff->included_files_list;
+   int len;
+
+   for ( ; inc; inc=inc->next ) {
+      if (inc->pattern) {
+        if (fnmatch(inc->fname, file, FNM_LEADING_DIR) == 0) {
+           return 1;
+        }
+        continue;
+      }                            
+      /*
+       * No wild cards. We accept a match to the
+       *  end of any component.
+       */
+      Dmsg2(900, "pat=%s file=%s\n", inc->fname, file);
+      len = strlen(file);
+      if (inc->len == len && strcmp(inc->fname, file) == 0) {
+        return 1;
+      }
+      if (inc->len < len && file[inc->len] == '/' && 
+         strncmp(inc->fname, file, inc->len) == 0) {
+        return 1;
+      }
+      if (inc->len == 1 && inc->fname[0] == '/') {
+        return 1;
+      }
+   }
+   return 0;
+}
+
+
+/*
+ * This is the workhorse of excluded_file().
+ * Determine if the file is excluded or not.
+ */
+static int
+file_in_excluded_list(struct s_excluded_file *exc, char *file)
+{
+   if (exc == NULL) {
+      Dmsg0(900, "exc is NULL\n");
+   }
+   for ( ; exc; exc=exc->next ) {
+      if (fnmatch(exc->fname, file, FNM_PATHNAME) == 0) {
+         Dmsg2(900, "Match exc pat=%s: file=%s:\n", exc->fname, file);
+        return 1;
+      }
+      Dmsg2(900, "No match exc pat=%s: file=%s:\n", exc->fname, file);
+   }
+   return 0;
+}
+
+
+/*
+ * Walk through the excluded lists to see if this
+ *  file is excluded, or if it matches a component
+ *  of an excluded directory.
+ */
+
+int file_is_excluded(FF_PKT *ff, char *file)
+{
+   char *p;
+
+   if (win32_client && file[1] == ':') {
+      file += 2;
+   }
+
+   if (file_in_excluded_list(ff->excluded_paths_list, file)) {
+      return 1;
+   }
+
+   /* Try each component */
+   for (p = file; *p; p++) {
+      /* Match from the beginning of a component only */
+      if ((p == file || (*p != '/' && *(p-1) == '/'))
+          && file_in_excluded_list(ff->excluded_files_list, p)) {
+        return 1;
+      }
+   }
+   return 0;
+}
diff --git a/bacula/src/findlib/testresults.txt b/bacula/src/findlib/testresults.txt
new file mode 100644 (file)
index 0000000..16e7900
--- /dev/null
@@ -0,0 +1,44 @@
+Ovni (Win2000 c:/) testfind results:
+Err: Could not stat /PAGEFILE.SYS: Permission denied
+Total files    : 68155
+Max file length: 69
+Max path length: 132
+Files truncated: 0
+Paths truncated: 0
+
+Minou (WinNT c:/ d:/) testfind results: 
+Err: Could not stat c:/pagefile.sys: Permission denied
+Err: Could not stat d:/pagefile.sys: Permission denied
+Total files    : 33112
+Max file length: 91
+Max path length: 85
+Files truncated: 0
+Paths truncated: 0
+
+Minimatou (Win98 c:/) testfind results:
+Total files    : 87276
+Max file length: 140
+Max path length: 107
+Files truncated: 0
+Paths truncated: 0
+
+moby (Solaris) testfind results:
+Total files    : 248263
+Max file length: 82
+Max path length: 114
+Files truncated: 0
+Paths truncated: 0
+
+polymatou (Linux) testfind results:
+Total files    : 207176
+Max file length: 82
+Max path length: 105
+Files truncated: 0
+Paths truncated: 0
+
+rufus (Linux) testfind results:
+Total files    : 170280
+Max file length: 84
+Max path length: 121
+Files truncated: 0
+Paths truncated: 0
diff --git a/bacula/src/gcc-Wall b/bacula/src/gcc-Wall
new file mode 100755 (executable)
index 0000000..9c5ccc1
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+# gcc -Wall plus other important warnings not included in -Wall
+
+for arg
+do
+    case $arg in
+       -O*) Wuninitialized=-Wuninitialized;;  # only makes sense with `-O'
+    esac
+done
+
+exec gcc \
+       -Wall $Wuninitialized \
+       -Wwrite-strings \
+       -Wcast-qual \
+       -Wbad-function-cast \
+       -Wpointer-arith \
+       -Wstrict-prototypes \
+       -Wmissing-prototypes \
+       -Wmissing-declarations \
+       -Wnested-externs \
+       -Wtraditional \
+       -Wconversion \
+       -Wcomment \
+       -Wcast-align \
+       -Winline \
+       -Wshadow \
+       -Wredundant-decls \
+       -Wid-clash-31 \
+       "$@"
+
+#    -Wall implies:
+#      -Wimplicit
+#      -Wreturn-type
+#      -Wunused
+#      -Wswitch
+#      -Wformat
+#      -Wchar-subscripts
+#      -Wparentheses
+#      -Wmissing-braces
+------------------------------------------------------------------------------
diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h
new file mode 100644 (file)
index 0000000..7557539
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Bacula JCR Structure definition for Daemons and the Library
+ *  This definition consists of a "Global" definition common
+ *  to all daemons and used by the library routines, and a
+ *  daemon specific part that is enabled with #defines.
+ *
+ * Kern Sibbald, Nov MM
+ *
+ */
+
+/*
+   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+
+   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.
+ */
+#ifndef __JCR_H_
+#define __JCR_H_ 1
+
+/* Backup/Verify level code */
+#define L_FULL                   'F'
+#define L_INCREMENTAL            'I'  /* since last backup */
+#define L_DIFFERENTIAL           'D'  /* since last full backup */
+#define L_LEVEL                  'L'
+#define L_SINCE                  'S'
+#define L_VERIFY_CATALOG         'C'  /* verify from catalog */
+#define L_VERIFY_INIT            'V'  /* verify save (init DB) */
+#define L_VERIFY_VOLUME          'O'  /* verify we can read volume */
+#define L_VERIFY_DATA            'A'  /* verify data on volume */
+
+
+/* Job Types */
+#define JT_BACKUP                'B'
+#define JT_VERIFY                'V'
+#define JT_RESTORE               'R'
+#define JT_CONSOLE               'C'  /* console program */
+
+/* Job Status */
+#define JS_Created               'C'
+#define JS_Running               'R'
+#define JS_Blocked               'B'
+#define JS_Terminated            'T'  /* terminated normally */
+#define JS_ErrorTerminated       'E'
+#define JS_Errored               'E'
+#define JS_Differences           'D'  /* Verify differences */
+#define JS_Cancelled             'A'  /* cancelled by user */
+#define JS_WaitFD                'F'  /* waiting on File daemon */
+#define JS_WaitSD                'S'  /* waiting on the Storage daemon */
+#define JS_WaitMedia             'm'  /* waiting for new media */
+#define JS_WaitMount             'M'  /* waiting for Mount */
+
+#define job_cancelled(jcr) \
+  (jcr->JobStatus == JS_Cancelled || jcr->JobStatus == JS_ErrorTerminated)
+
+typedef void (JCR_free_HANDLER)(struct s_jcr *jcr);
+
+/* Job Control Record (JCR) */
+struct s_jcr {
+   /* Global part of JCR common to all daemons */
+   struct s_jcr *next;
+   struct s_jcr *prev;
+   pthread_t my_thread_id;            /* id of thread controlling jcr */
+   pthread_mutex_t mutex;             /* jcr mutex */
+   BSOCK *dir_bsock;                  /* Director bsock or NULL if we are him */
+   BSOCK *store_bsock;                /* Storage connection socket */
+   BSOCK *file_bsock;                 /* File daemon connection socket */
+   JCR_free_HANDLER *daemon_free_jcr; /* Local free routine */
+   int use_count;                     /* use count */
+   char *errmsg;                      /* edited error message */
+   char Job[MAX_NAME_LENGTH];         /* Job name */
+   uint32_t JobId;                    /* Director's JobId */
+   uint32_t VolSessionId;
+   uint32_t VolSessionTime;
+   uint32_t JobFiles;                 /* Number of files written, this job */
+   uint32_t JobErrors;
+   uint64_t JobBytes;                 /* Number of bytes processed this job */
+   int JobStatus;                     /* ready, running, blocked, terminated */ 
+   int JobTermCode;                   /* termination code */
+   int JobType;                       /* backup, restore, verify ... */
+   int level;
+   int authenticated;                 /* set when client authenticated */
+   time_t sched_time;                 /* job schedule time, i.e. when it should start */
+   time_t start_time;                 /* when job actually started */
+   time_t run_time;                   /* used for computing speed */
+   time_t end_time;                   /* job end time */
+   char *VolumeName;                  /* Volume name desired -- pool_memory */
+   char *client_name;                 /* client name */
+   char *sd_auth_key;                 /* SD auth key */
+   DEST *dest_chain;                  /* Job message destination chain */
+   char send_msg[nbytes_for_bits(M_MAX+1)]; /* message bit mask */
+
+   /* Daemon specific part of JCR */
+   /* This should be empty in the library */
+
+#ifdef DIRECTOR_DAEMON
+   /* Director Daemon specific part of JCR */
+   pthread_t SD_msg_chan;             /* Message channel thread id */
+   pthread_cond_t term_wait;          /* Wait for job termination */
+   int msg_thread_done;               /* Set when Storage message thread terms */
+   BSOCK *ua;                         /* User agent */
+   JOB *job;                          /* Job resource */
+   STORE *store;                      /* Storage resource */
+   CLIENT *client;                    /* Client resource */
+   POOL *pool;                        /* Pool resource */
+   FILESET *fileset;                  /* FileSet resource */
+   CAT *catalog;                      /* Catalog resource */
+   int SDJobStatus;                   /* Storage Job Status */
+   int mode;                          /* manual/auto run */
+   B_DB *db;                          /* database pointer */
+   int MediaId;                       /* DB record IDs associated with this job */
+   int ClientId;                      /* Client associated with file */
+   uint32_t PoolId;                   /* Pool record id */
+   FileId_t FileId;                   /* Last file id inserted */
+   uint32_t FileIndex;                /* Last FileIndex processed */
+   char *fname;                       /* name to put into catalog */
+   int fn_printed;                    /* printed filename */
+   char *stime;                       /* start time for incremental/differential */
+   JOB_DBR jr;                        /* Job record in Database */
+   int RestoreJobId;                  /* Id specified by UA */
+   char *RestoreWhere;                /* Where to restore the files */
+#endif /* DIRECTOR_DAEMON */
+
+#ifdef FILE_DAEMON
+   /* File Daemon specific part of JCR */
+   uint32_t num_files_examined;       /* files examined this job */
+   char *last_fname;                  /* last file saved */
+   /*********FIXME********* add missing files and files to be retried */
+   int incremental;                   /* set if incremental for SINCE */
+   time_t mtime;                      /* begin time for SINCE */
+   int mode;                          /* manual/auto run */
+   int status;                        /* job status */
+   long Ticket;                       /* Ticket */
+   int save_level;                    /* save level */
+   char *big_buf;                     /* I/O buffer */
+   char *compress_buf;                /* Compression buffer */
+   char *where;                       /* Root where to restore */
+   int buf_size;                      /* length of buffer */
+   FF_PKT *ff;                        /* Find Files packet */
+   char stored_addr[MAX_NAME_LENGTH]; /* storage daemon address */
+   uint32_t StartFile;
+   uint32_t EndFile;
+   uint32_t StartBlock;
+   uint32_t EndBlock;
+#endif /* FILE_DAEMON */
+
+#ifdef STORAGE_DAEMON
+   /* Storage Daemon specific part of JCR */
+   pthread_cond_t job_start_wait;     /* Wait for FD to start Job */
+   int type;
+   DEVRES *device;                    /* device to use */
+   VOLUME_CAT_INFO VolCatInfo;        /* Catalog info for desired volume */
+   char *pool_name;                   /* pool to use */
+   char *pool_type;                   /* pool type to use */
+   char *job_name;                    /* job name */
+   char *media_type;                  /* media type */
+   char *dev_name;                    /* device name */
+   long NumVolumes;                   /* number of volumes used */
+   long CurVolume;                    /* current volume number */
+   int mode;                          /* manual/auto run */
+   int label_status;                  /* device volume label status */
+   int session_opened;
+   DEV_RECORD rec;                    /* Read/Write record */
+   long Ticket;                       /* ticket for this job */
+   uint32_t VolFirstFile;             /* First file index this Volume */
+   uint32_t start_block;              /* Start write block */
+   uint32_t start_file;               /* Start write file */
+   uint32_t end_block;                /* Ending block written */
+   uint32_t end_file;                 /* End file written */
+
+   /* Parmaters for Open Read Session */
+   uint32_t read_VolSessionId;
+   uint32_t read_VolSessionTime;
+   uint32_t read_StartFile;
+   uint32_t read_EndFile;
+   uint32_t read_StartBlock;
+   uint32_t read_EndBlock;
+
+#endif /* STORAGE_DAEMON */
+
+}; 
+
+/* 
+ * Structure for all daemons that keeps some summary
+ *  info on the last job run.
+ */
+struct s_last_job {
+   int NumJobs;
+   int JobType;
+   int JobStatus;
+   uint32_t JobId;
+   uint32_t VolSessionId;
+   uint32_t VolSessionTime;
+   uint32_t JobFiles;
+   uint64_t JobBytes;
+   time_t start_time;
+   time_t end_time;
+   char Job[MAX_NAME_LENGTH];
+};
+
+extern struct s_last_job last_job;
+
+#undef JCR
+typedef struct s_jcr JCR;
+
+
+/* The following routines are found in lib/jcr.c */
+extern JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr);
+extern void free_jcr(JCR *jcr);
+extern void free_locked_jcr(JCR *jcr);
+extern JCR *get_jcr_by_id(uint32_t JobId);
+extern JCR *get_jcr_by_partial_name(char *Job);
+extern JCR *get_jcr_by_full_name(char *Job);
+extern JCR *get_next_jcr(JCR *jcr);
+extern void lock_jcr_chain();
+extern void unlock_jcr_chain();
+
+#endif /* __JCR_H_ */
diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in
new file mode 100644 (file)
index 0000000..8332faf
--- /dev/null
@@ -0,0 +1,139 @@
+# $Id$
+@MCOMMON@
+
+CWEB = @CWEB@
+CTANGLE = $(CWEB)/ctangle
+CWEAVE = $(CWEB)/cweave
+TEXINPUTS = TEXINPUTS=.:$(CWEB):
+
+# FIXME -- These should be found by autoconf
+TEX = tex
+PDFTEX = pdftex
+XDVI = xdvi
+DVIPS = dvips
+
+srcdir =       .
+VPATH =        .
+.PATH:         .
+
+# one up
+basedir = ..
+# top dir
+topdir = ../..
+# this dir relative to top dir
+thisdir = src/lib
+
+
+DEBUG=@DEBUG@
+
+GMP_INC=@GMP_INC@
+
+first_rule: all
+dummy:
+
+LIBSRCS = alloc.c base64.c bmisc.c bnet.c bnet_server.c \
+         bshm.c btime.c \
+         cram-md5.c crc32.c create_file.c daemon.c fnmatch.c \
+         hmac.c idcache.c jcr.c lex.c  \
+         makepath.c \
+         md5.c message.c mem_pool.c parse_conf.c \
+         queue.c rwlock.c save-cwd.c serial.c \
+         signal.c smartall.c util.c watchdog.c workq.c
+
+
+#        immortal.c filesys.c
+
+LIBOBJS = alloc.o base64.o bmisc.o bnet.o bnet_server.o \
+         bshm.o btime.o \
+         cram-md5.o crc32.o create_file.o daemon.o fnmatch.o \
+         hmac.o idcache.o jcr.o lex.o  \
+         makepath.o \
+         md5.o message.o mem_pool.o parse_conf.o \
+         queue.o rwlock.o save-cwd.o serial.o \
+         signal.o smartall.o util.o watchdog.o workq.o
+
+#        immortal.o filesys.o
+
+EXTRAOBJS = @OBJLIST@
+
+
+.SUFFIXES:     .c .o .ch .dvi .pdf .tex .view .w .1
+.PHONY:
+.DONTCARE:
+
+# inference rules
+.c.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(GMP_INC) $(CFLAGS) $<
+
+.cc.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) @GMP_INC@ $(CFLAGS) $<
+
+.w.c:
+       $(CTANGLE) $<
+
+.w.tex:
+       $(CWEAVE) $<
+
+.tex.dvi:
+       ( $(TEXINPUTS) ; export TEXINPUTS; $(TEX) $< )
+
+.tex.pdf:
+       ( $(TEXINPUTS) ; export TEXINPUTS; $(PDFTEX) $< )
+
+.dvi.view:
+       $(XDVI) -s 0 $<
+
+#-------------------------------------------------------------------------
+all: Makefile libbac.a smtp
+       @echo "==== Make of lib is good ===="
+       @echo " "
+
+libbac.a: $(LIBOBJS)
+       $(AR) rcs $@ $(LIBOBJS)
+       $(RANLIB) $@
+
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+smtp:  smtp.o
+       $(CXX) $(LDFLAGS) -L. -o $@ smtp.o  \
+             $(LIBS) $(DLIB) -lbac -lm
+        
+install:
+       $(INSTALL_PROGRAM) smtp $(DESTDIR)/$(sbindir)/smtp
+
+uninstall:
+       (cd $(DESTDIR)$(sbindir); $(RMF) smtp)
+
+clean:
+       $(RMF) *.a core a.out *.o *.bak *.tex *.pdf *~ *.intpro *.extpro 1 2 3
+       $(RMF) smtp
+
+realclean: clean
+       $(RMF) tags
+
+distclean: realclean
+       if test $(srcdir) = .; then $(MAKE) realclean; fi
+       (cd $(srcdir); $(RMF) Makefile)
+
+# Semi-automatic generation of dependencies:
+# Use gcc -MM because X11 `makedepend' doesn't work on all systems
+# and it also includes system headers.
+# `semi'-automatic since dependencies are generated at distribution time.
+
+depend:
+       @$(MV) Makefile Makefile.bak
+       @$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile
+       @$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile
+       @$(CXX) -S -M $(CPPFLAGS) $(XINC) -I$(srcdir) -I$(basedir) @GMP_INC@ $(SQL_INC) *.c >> Makefile
+       @if test -f Makefile ; then \
+           $(RMF) Makefile.bak; \
+       else \
+          $(MV) Makefile.bak Makefile; \
+          echo -e "Something went wrong\n\a"; \
+       fi
+
+# -----------------------------------------------------------------------
+# DO NOT DELETE: nice dependency list follows
diff --git a/bacula/src/lib/alloc.c b/bacula/src/lib/alloc.c
new file mode 100644 (file)
index 0000000..f65c942
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+
+       Error checking memory allocator
+
+*/
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifdef NEEDED
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef TESTERR
+#undef NULL
+#define NULL  buf
+#endif
+
+/*LINTLIBRARY*/
+
+#define V       (void)
+
+#ifdef SMARTALLOC
+
+extern void *sm_malloc();
+
+/*  SM_ALLOC  --  Allocate buffer and signal on error  */
+
+void *sm_alloc(char *fname, int lineno, unsigned int nbytes)
+{
+       void *buf;
+
+       if ((buf = sm_malloc(fname, lineno, nbytes)) != NULL) {
+          return buf;
+       }
+        V fprintf(stderr, "\nBoom!!!  Memory capacity exceeded.\n");
+        V fprintf(stderr, "  Requested %u bytes at line %d of %s.\n",
+          nbytes, lineno, fname);
+       abort();
+       /*NOTREACHED*/
+}
+#else
+
+/*  ALLOC  --  Allocate buffer and signal on error  */
+
+void *alloc(unsigned int nbytes)
+{
+       void *buf;
+
+       if ((buf = malloc(nbytes)) != NULL) {
+          return buf;
+       }
+        V fprintf(stderr, "\nBoom!!!  Memory capacity exceeded.\n");
+        V fprintf(stderr, "  Requested %u bytes.\n", nbytes);
+       abort();
+       /*NOTREACHED*/
+}
+#endif
+#endif
diff --git a/bacula/src/lib/base64.c b/bacula/src/lib/base64.c
new file mode 100644 (file)
index 0000000..af47018
--- /dev/null
@@ -0,0 +1,347 @@
+/*   
+ *   Generic base 64 input and output routines
+ *
+ *    Written by Kern E. Sibbald, March MM.
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+
+#ifdef TEST_MODE
+#include <glob.h>
+#endif
+
+
+static char const base64_digits[64] =
+{
+  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+static int base64_inited = 0;
+static char base64_map[128];
+  
+
+/* Initialize the Base 64 conversion routines */
+void
+base64_init(void)
+{     
+   int i; 
+   memset(base64_map, 0, sizeof(base64_map));
+   for (i=0; i<64; i++)
+      base64_map[(int)base64_digits[i]] = i;
+   base64_inited = 1;
+}
+
+/* Convert a value to base64 characters.
+ * The result is stored in where, which
+ * must be at least 8 characters long.
+ *
+ * Returns the number of characters
+ * stored (not including the EOS).
+ */
+int
+to_base64(intmax_t value, char *where)
+{
+   uintmax_t val;
+   int i = 0;
+   int n;
+
+   /* Handle negative values */
+   if (value < 0) {
+      where[i++] = '-';
+      value = -value;
+   }
+
+   /* Determine output size */
+   val = value;
+   do {
+      val >>= 6;
+      i++;
+   } while (val);
+   n = i;
+
+   /* Output characters */
+   val = value;
+   where[i] = 0;
+   do {
+      where[--i] = base64_digits[val & (unsigned)0x3F];
+      val >>= 6;
+   } while (val);
+   return n;
+}
+
+/*
+ * Convert the Base 64 characters in where to
+ * a value. No checking is done on the validity
+ * of the characters!!
+ *
+ * Returns the value.
+ */
+int
+from_base64(intmax_t *value, char *where)
+{ 
+   uintmax_t val = 0;
+   int i, neg;
+
+   if (!base64_inited) 
+      base64_init();
+   /* Check if it is negative */
+   i = neg = 0;
+   if (where[i] == '-') {
+      i++;
+      neg = 1;
+   }
+   /* Construct value */
+   while (where[i] != 0 && where[i] != ' ') {
+      val <<= 6;
+      val += base64_map[(int)where[i++]];
+   }
+        
+   *value = neg ? -(intmax_t)val : (intmax_t)val;
+   return i;
+}
+
+/* Encode a stat structure into a base64 character string */
+void
+encode_stat(char *buf, struct stat *statp)
+{
+   char *p = buf;
+   /*
+    * NOTE: we should use rdev as major and minor device if
+    * it is a block or char device (S_ISCHR(statp->st_mode)
+    * or S_ISBLK(statp->st_mode)).  In all other cases,
+    * it is not used.  
+    *
+    */
+   p += to_base64((intmax_t)statp->st_dev, p);
+   *p++ = ' ';                        /* separate fields with a space */
+   p += to_base64((intmax_t)statp->st_ino, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_mode, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_nlink, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_uid, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_gid, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_rdev, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_size, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_blksize, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_blocks, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_atime, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_mtime, p);
+   *p++ = ' ';
+   p += to_base64((intmax_t)statp->st_ctime, p);
+   *p++ = 0;
+   return;
+}
+
+
+/* Decode a stat packet from base64 characters */
+void
+decode_stat(char *buf, struct stat *statp)
+{
+   char *p = buf;
+   intmax_t val;
+
+   p += from_base64(&val, p);
+   statp->st_dev = val;
+   p++;                              /* skip space */
+   p += from_base64(&val, p);
+   statp->st_ino = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_mode = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_nlink = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_uid = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_gid = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_rdev = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_size = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_blksize = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_blocks = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_atime = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_mtime = val;
+   p++;
+   p += from_base64(&val, p);
+   statp->st_ctime = val;
+   p++;
+}
+
+/*
+ * Encode binary data in bin of len bytes into
+ * buf as base64 characters.
+ *
+ *  Returns: the number of characters stored not
+ *          including the EOS
+ */
+int
+bin_to_base64(char *buf, char *bin, int len)
+{
+   unsigned int reg, save, mask;
+   int rem, i;
+   int j = 0;
+
+   reg = 0;
+   rem = 0;
+   for (i=0; i<len; ) {
+      if (rem < 6) {
+        reg <<= 8;
+        reg |= bin[i++];
+        rem += 8;
+      }
+      save = reg;
+      reg >>= (rem - 6);
+      buf[j++] = base64_digits[reg & (unsigned)0x3F];
+      reg = save;
+      rem -= 6;
+   }
+   if (rem) {
+      mask = 1;
+      for (i=1; i<rem; i++) {
+        mask = (mask << 1) | 1;
+      }
+      buf[j++] = base64_digits[reg & mask];
+   }
+   buf[j] = 0;
+   return j;
+}
+
+#ifdef BIN_TEST
+int main(int argc, char *argv[])
+{
+   int xx = 0;
+   int len;
+   char buf[100];
+   char junk[100];
+   int i;
+
+   for (i=0; i < 100; i++) {
+      bin_to_base64(buf, (char *)&xx, 4);
+      printf("xx=%s\n", buf);
+      xx++;
+   }
+   len = bin_to_base64(buf, junk, 16);
+   printf("len=%d junk=%s\n", len, buf);
+   return 0;
+}
+#endif
+
+#ifdef TEST_MODE
+static int errfunc(const char *epath, int eernoo)
+{
+  Dmsg0(-1, "in errfunc\n");
+  return 1;
+}
+
+
+/*
+ * Test the base64 routines by encoding and decoding
+ * lstat() packets.
+ */
+int main(int argc, char *argv[]) 
+{
+   char where[500];
+   int i;
+   glob_t my_glob;
+   char *fname;
+   struct stat statp;
+   struct stat statn;
+   int debug_level = 0;
+
+   if (argc > 1 && strcmp(argv[1], "-v") == 0)
+      debug_level++;  
+
+   base64_init();
+
+   my_glob.gl_offs = 0;
+   glob("/etc/*", GLOB_MARK, errfunc, &my_glob);
+
+   for (i=0; my_glob.gl_pathv[i]; i++) {
+      fname = my_glob.gl_pathv[i];
+      if (lstat(fname, &statp) < 0) {
+         printf("Cannot stat %s: %s\n", fname, strerror(errno));
+        continue;
+      }
+      encode_stat(where, &statp);
+
+      if (debug_level)
+         printf("%s: len=%d val=%s\n", fname, strlen(where), where);
+      
+      decode_stat(where, &statn);
+
+      if (statp.st_dev != statn.st_dev || 
+         statp.st_ino != statn.st_ino ||
+         statp.st_mode != statn.st_mode ||
+         statp.st_nlink != statn.st_nlink ||
+         statp.st_uid != statn.st_uid ||
+         statp.st_gid != statn.st_gid ||
+         statp.st_rdev != statn.st_rdev ||
+         statp.st_size != statn.st_size ||
+         statp.st_blksize != statn.st_blksize ||
+         statp.st_blocks != statn.st_blocks ||
+         statp.st_atime != statn.st_atime ||
+         statp.st_mtime != statn.st_mtime ||
+         statp.st_ctime != statn.st_ctime) {
+
+         printf("%s: %s\n", fname, where);
+        encode_stat(where, &statn);
+         printf("%s: %s\n", fname, where);
+         printf("NOT EQAL\n");
+      }
+
+   }
+   globfree(&my_glob);
+
+   printf("%d files examined\n", i);
+
+   return 0;
+}   
+#endif
diff --git a/bacula/src/lib/bits.h b/bacula/src/lib/bits.h
new file mode 100644 (file)
index 0000000..ef88741
--- /dev/null
@@ -0,0 +1,59 @@
+/* Some elementary bit manipulations
+ *
+ *   Kern Sibbald, MM
+ *
+ *  NOTE:  base 0
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef __BITS_H_
+#define __BITS_H_
+
+/* number of bytes to hold n bits */
+#define nbytes_for_bits(n) ((((n)-1)>>3)+1) 
+
+/* test if bit is set */
+#define bit_is_set(b, var) ((var)[(b)>>3] & (1<<((b)&0x7)))
+
+/* set bit */
+#define set_bit(b, var) ((var)[(b)>>3] |= (1<<((b)&0x7)))
+
+/* clear bit */
+#define clear_bit(b, var) ((var)[(b)>>3] &= ~(1<<((b)&0x7)))
+
+/* clear all bits */
+#define clear_all_bits(b, var) memset(var, 0, nbytes_for_bits(b))
+
+/* set range of bits */
+#define set_bits(f, l, var) { \
+   int i; \
+   for (i=f; i<=l; i++)  \
+      set_bit(i, var); \
+}
+/* clear range of bits */
+#define clear_bits(f, l, var) { \
+   int i; \
+   for (i=f; i<=l; i++)  \
+      clear_bit(i, var); \
+}
+
+#endif /* __BITS_H_ */
diff --git a/bacula/src/lib/bnet.c b/bacula/src/lib/bnet.c
new file mode 100644 (file)
index 0000000..def42e8
--- /dev/null
@@ -0,0 +1,632 @@
+/*
+ * Network Utility Routines
+ *
+ *  by Kern Sibbald
+ *
+ * Adapted and enhanced for Bacula, originally written 
+ * for inclusion in the Apcupsd package
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+
+extern time_t watchdog_time;
+
+#ifndef   INADDR_NONE
+#define   INADDR_NONE   -1
+#endif
+
+#ifndef ENODATA                      /* not defined on BSD systems */
+#define ENODATA EPIPE
+#endif
+
+
+/*
+ * Read a nbytes from the network.
+ * It is possible that the total bytes require in several
+ * read requests
+ */
+
+static int32_t read_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
+{
+   int32_t nleft, nread;
+      
+   nleft = nbytes;
+   while (nleft > 0) {
+      do {
+        errno = 0;
+        nread = read(bsock->fd, ptr, nleft);    
+      } while (!bsock->timed_out && nread == -1 && (errno == EINTR || errno == EAGAIN));
+      if (nread <= 0) {
+        return nread;               /* error, or EOF */
+      }
+      nleft -= nread;
+      ptr += nread;
+   }
+   return nbytes - nleft;           /* return >= 0 */
+}
+
+/*
+ * Write nbytes to the network.
+ * It may require several writes.
+ */
+
+static int32_t write_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes)
+{
+   int32_t nleft, nwritten;
+
+   nleft = nbytes;
+   while (nleft > 0) {
+      do {
+        errno = 0;
+        nwritten = write(bsock->fd, ptr, nleft);
+      } while (!bsock->timed_out && nwritten == -1 && (errno == EINTR || errno == EAGAIN));
+      if (nwritten <= 0) {
+        return nwritten;            /* error */
+      }
+      nleft -= nwritten;
+      ptr += nwritten;
+   }
+   return nbytes-nleft;
+}
+
+/* 
+ * Receive a message from the other end. Each message consists of
+ * two packets. The first is a header that contains the size
+ * of the data that follows in the second packet.
+ * Returns number of bytes read
+ * Returns 0 on end of file
+ * Returns -1 on hard end of file (i.e. network connection close)
+ * Returns -2 on error
+ */
+/* EXTPROTO */
+int32_t 
+bnet_recv(BSOCK *bsock)
+{
+   int32_t nbytes;
+   int32_t pktsiz;
+
+   if (bsock->errors) {
+      return -2;
+   }
+
+   bsock->read_seqno++;              /* bump sequence number */
+   bsock->timer_start = watchdog_time; /* set start wait time */
+   bsock->timed_out = 0;
+   /* get data size -- in int32_t */
+   if ((nbytes = read_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t))) <= 0) {
+      bsock->timer_start = 0;        /* clear timer */
+      /* probably pipe broken because client died */
+      if (errno == 0) {
+        bsock->b_errno = ENODATA;
+      } else {
+        bsock->b_errno = errno;
+      }
+      bsock->errors++;
+      return -1;                     /* assume hard EOF received */
+   }
+   bsock->timer_start = 0;           /* clear timer */
+   if (nbytes != sizeof(int32_t)) {
+      bsock->errors++;
+      bsock->b_errno = EIO;
+      Emsg3(M_ERROR, 0, "Read %d expected %d from %s\n", nbytes, sizeof(int32_t),
+           bsock->who);
+      return -2;
+   }
+
+   pktsiz = ntohl(pktsiz);           /* decode no. of bytes that follow */
+
+   if (pktsiz <= 0) {
+      bsock->b_errno = ENODATA;
+      bsock->msglen = pktsiz;        /* return size */
+      return 0;                      /* soft EOF */
+   }
+   /* For big packet size, something went wrong */
+   if (pktsiz > 10000000) {
+      bsock->b_errno = ENODATA;
+      bsock->msglen = pktsiz;        /* return size */
+      return 0;                      /* soft EOF */
+   }
+
+   /* Make sure the buffer is big enough + one byte for EOS */
+   if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) {
+      bsock->msg = (char *) realloc_pool_memory(bsock->msg, pktsiz + 100);
+   }
+
+   bsock->timer_start = watchdog_time; /* set start wait time */
+   bsock->timed_out = 0;
+   /* now read the actual data */
+   if ((nbytes = read_nbytes(bsock, bsock->msg, pktsiz)) <=  0) {
+      bsock->timer_start = 0;        /* clear timer */
+      if (errno == 0) {
+        bsock->b_errno = ENODATA;
+      } else {
+        bsock->b_errno = errno;
+      }
+      bsock->errors++;
+      Emsg4(M_ERROR, 0, "Read error from %s:%s:%d: ERR=%s\n", 
+           bsock->who, bsock->host, bsock->port, bnet_strerror(bsock));
+      return -2;
+   }
+   bsock->timer_start = 0;           /* clear timer */
+   bsock->in_msg_no++;
+   bsock->msglen = nbytes;
+   if (nbytes != pktsiz) {
+      bsock->b_errno = EIO;
+      bsock->errors++;
+      Emsg5(M_ERROR, 0, "Read expected %d got %d from %s:%s:%d\n", pktsiz, nbytes,
+           bsock->who, bsock->host, bsock->port);
+      return -2;
+   }
+   /* always add a zero by to properly terminate any
+    * string that was send to us. Note, we ensured above that the
+    * buffer is atleast one byte longer than the message length.
+    */
+   bsock->msg[nbytes] = 0;           /* terminate in case it is a string */
+   sm_check(__FILE__, __LINE__, False);
+   return nbytes;                    /* return actual length of message */
+}
+
+/*
+ * Send a message over the network. The send consists of
+ * two network packets. The first is sends a 32 bit integer containing
+ * the length of the data packet which follows.
+ *
+ * Returns: 0 on failure
+ *         1 on success
+ */
+int
+bnet_send(BSOCK *bsock)
+{
+   int32_t rc;
+   int32_t pktsiz;
+
+   if (bsock->errors) {
+      return 0;
+   }
+   pktsiz = htonl((int32_t)bsock->msglen);
+   /* send int32_t containing size of data packet */
+   bsock->timer_start = watchdog_time; /* start timer */
+   bsock->timed_out = 0;              
+   rc = write_nbytes(bsock, (char *)&pktsiz, sizeof(int32_t));
+   bsock->timer_start = 0;           /* clear timer */
+   if (rc != sizeof(int32_t)) {
+      bsock->errors++;
+      if (errno == 0) {
+        bsock->b_errno = EIO;
+      } else {
+        bsock->b_errno = errno;
+      }
+      if (rc < 0) {
+        /****FIXME***** use Mmsg */
+         Emsg4(M_ERROR, 0, "Write error sending to %s:%s:%d: ERR=%s\n", 
+              bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
+      } else {
+         Emsg5(M_ERROR, 0, "Wrote %d bytes to %s:%s:%d, but only %d accepted.\n", 
+              bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
+      }
+      return 0;
+   }
+
+   bsock->out_msg_no++;              /* increment message number */
+   if (bsock->msglen <= 0) {         /* length only? */
+      return 1;                      /* yes, no data */
+   }
+
+   /* send data packet */
+   bsock->timer_start = watchdog_time; /* start timer */
+   bsock->timed_out = 0;              
+   rc = write_nbytes(bsock, bsock->msg, bsock->msglen);
+   bsock->timer_start = 0;           /* clear timer */
+   if (rc != bsock->msglen) {
+      bsock->errors++;
+      if (errno == 0) {
+        bsock->b_errno = EIO;
+      } else {
+        bsock->b_errno = errno;
+      }
+      if (rc < 0) {
+        /************FIXME********* use Pmsg() **/
+         Emsg4(M_ERROR, 0, "Write error sending to %s:%s:%d: ERR=%s\n", 
+              bsock->who, bsock->host, bsock->port,  bnet_strerror(bsock));
+      } else {
+         Emsg5(M_ERROR, 0, "Wrote %d bytes to %s:%s:%d, but only %d accepted.\n", 
+              bsock->who, bsock->host, bsock->port, bsock->msglen, rc);
+      }
+      return 0;
+   }
+   return 1;
+}
+
+/*
+ * Wait for a specified time for data to appear on
+ * the BSOCK connection.
+ *
+ *   Returns: 1 if data available
+ *           0 if timeout
+ *          -1 if error
+ */
+int 
+bnet_wait_data(BSOCK *bsock, int sec)
+{
+   fd_set fdset;
+   struct timeval tv;
+
+   FD_ZERO(&fdset);
+   FD_SET(bsock->fd, &fdset);
+   tv.tv_sec = sec;
+   tv.tv_usec = 0;
+   for ( ;; ) {
+      switch(select(bsock->fd + 1, &fdset, NULL, NULL, &tv)) {
+        case 0:                         /* timeout */
+           bsock->b_errno = 0;
+           return 0;
+        case -1:
+           bsock->b_errno = errno;
+           if (errno == EINTR || errno == EAGAIN) {
+              continue;
+           }
+           return -1;                  /* error return */
+        default:
+           bsock->b_errno = 0;
+           return 1;
+      }
+   }
+}
+
+/*
+ * Convert a hostname or dotted IP address into   
+ * a s_addr.  We handle only IPv4.
+ */
+static uint32_t *bget_host_ip(char *host)
+{
+   struct in_addr inaddr;
+   uint32_t *addr_list;              /* this really should be struct in_addr */
+   struct hostent *hp;
+   char **p;
+   int i;
+
+   if ((inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
+      addr_list = (uint32_t *) malloc(sizeof(uint32_t) * 2);
+      addr_list[0] = inaddr.s_addr;
+      addr_list[1] = (uint32_t) -1;
+   } else {
+      /******FIXME***** use gethostbyname_r or mutex ****/
+      if ((hp = gethostbyname(host)) == NULL) {
+         Dmsg2(0, "gethostbyname() for %s failed: ERR=%s\n", host, strerror(errno));
+        return NULL;
+      }
+      if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) {
+          Emsg2(M_WARNING, 0, "gethostbyname() network address length error.\n\
+Wanted %d got %d bytes for s_addr.\n", sizeof(inaddr.s_addr), hp->h_length);
+         return NULL;
+      }
+      i = 0;
+      for (p = hp->h_addr_list; *p != 0; p++) {
+        i++;
+      }
+      i++;
+      addr_list = (uint32_t *) malloc(sizeof(uint32_t) * i);
+      i = 0;
+      for (p = hp->h_addr_list; *p != 0; p++) {
+        addr_list[i++] = (*(struct in_addr **)p)->s_addr;
+      }
+      addr_list[i] = (uint32_t) -1;
+   }
+   return addr_list;
+}
+
+/*     
+ * Open a TCP connection to the UPS network server
+ * Returns NULL
+ * Returns BSOCK * pointer on success
+ *
+ *  ***FIXME*** implement service from /etc/services
+ */
+static BSOCK *
+bnet_open(char *name, char *host, char *service, int port)
+{
+   int sockfd;
+   struct sockaddr_in tcp_serv_addr;    /* socket information */
+   uint32_t *addr_list;
+   int i, connected = 0;
+   int turnon = 1;
+
+   /* 
+    * Fill in the structure serv_addr with the address of
+    * the server that we want to connect with.
+    */
+   memset((char *)&tcp_serv_addr, 0,  sizeof(tcp_serv_addr));
+   tcp_serv_addr.sin_family = AF_INET;
+   tcp_serv_addr.sin_port = htons(port);
+
+   if ((addr_list=bget_host_ip(host)) == NULL) {
+     return NULL;
+   }
+
+   /* Open a TCP socket */
+   if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+      free(addr_list);
+      return NULL;
+   }
+
+   /*
+    * Receive notification when connection dies.
+    */
+   if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
+      Emsg1(M_WARNING, 0, "Cannot set SO_KEEPALIVE on socket: %s\n" , strerror(errno));
+   }
+   
+   for (i = 0; addr_list[i] != ((uint32_t) -1); i++) {
+      /* connect to server */
+      tcp_serv_addr.sin_addr.s_addr = addr_list[i];
+      if (connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)) < 0) {
+        continue;
+      }
+      connected = 1;
+      break;
+   }
+
+   free(addr_list);
+   if (!connected) {
+      close(sockfd);
+      return NULL;
+   }
+   return init_bsock(sockfd, name, host, port);
+}
+
+/*
+ * Try to connect to host for max_retry_time at retry_time intervals.
+ */
+BSOCK *
+bnet_connect(void *jcr, int retry_interval, int max_retry_time, char *name,
+            char *host, char *service, int port, int verbose)
+{
+   int i;
+   BSOCK *bsock;
+
+   for (i=0; (bsock = bnet_open(name, host, service, port)) == NULL; i -= retry_interval) {
+      if (i <= 0) {
+        i = 60 * 5;                  /* complain again in 5 minutes */
+        if (verbose)
+            Jmsg(jcr, M_WARNING, 0, "Could not connect to %s on %s:%d. ERR=%s\n\
+Retrying ...\n", name, host, port, strerror(errno));
+      }
+      sleep(retry_interval);
+      max_retry_time -= retry_interval;
+      if (max_retry_time <= 0) {
+         Jmsg(jcr, M_FATAL, 0, "Unable to connect to %s on %s:%d.\n", 
+             name, host, port);
+        return NULL;
+      }
+   }
+   return bsock;
+}
+
+
+/*
+ * Return the string for the error that occurred
+ * on the socket. Only the first error is retained.
+ */
+char *bnet_strerror(BSOCK *bsock)
+{
+   /*  ***FIXME*** not thread safe */
+   return strerror(bsock->b_errno);
+}
+
+/*
+ * Format and send a message
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int
+bnet_fsend(BSOCK *bs, char *fmt, ...)
+{
+   va_list arg_ptr;
+   int maxlen;
+
+   /* This probably won't work, but we vsnprintf, then if we
+    * get a negative length or a length greater than our buffer
+    * (depending on which library is used), the printf was truncated, so
+    * get a biger buffer and try again.
+    */
+again:
+   maxlen = sizeof_pool_memory(bs->msg) - 1;
+   va_start(arg_ptr, fmt);
+   bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
+   va_end(arg_ptr);
+   if (bs->msglen < 0 || bs->msglen >= maxlen) {
+      bs->msg = (char *) realloc_pool_memory(bs->msg, maxlen + 200);
+      goto again;
+   }
+   return bnet_send(bs) < 0 ? 0 : 1;
+}
+
+/* 
+ * Set the network buffer size, suggested size is in size.
+ *  Actual size obtained is returned in bs->msglen
+ *
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw)
+{
+   uint32_t dbuf_size;
+#if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
+   int opt;
+
+    opt = IPTOS_THROUGHPUT;
+    setsockopt(bs->fd, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt));
+#endif
+
+   dbuf_size = size;
+   if ((bs->msg = (char *) realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) {
+      Emsg0(M_FATAL, 0, "Could not malloc 32K BSOCK data buffer\n");
+      return 0;
+   }
+   if (rw & BNET_SETBUF_READ) {
+      while ((dbuf_size > TAPE_BSIZE) &&
+        (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
+         Emsg1(M_ERROR, 0, "sockopt error: %s\n", strerror(errno));
+        dbuf_size -= TAPE_BSIZE;
+      }
+      Dmsg1(20, "set network buffer size=%d\n", dbuf_size);
+      if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
+         Emsg1(M_WARNING, 0, "Warning network buffer = %d bytes not max size.\n", dbuf_size);
+      if (dbuf_size % TAPE_BSIZE != 0) {
+         Emsg1(M_ABORT, 0, "Network buffer size %d not multiple of tape block size.\n",
+             dbuf_size);
+      }
+   }
+   dbuf_size = size;
+   if (rw & BNET_SETBUF_WRITE) {
+      while ((dbuf_size > TAPE_BSIZE) &&
+        (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) {
+         Emsg1(M_ERROR, 0, "sockopt error: %s\n", strerror(errno));
+        dbuf_size -= TAPE_BSIZE;
+      }
+      Dmsg1(20, "set network buffer size=%d\n", dbuf_size);
+      if (dbuf_size != MAX_NETWORK_BUFFER_SIZE)
+         Emsg1(M_WARNING, 0, "Warning network buffer = %d bytes not max size.\n", dbuf_size);
+      if (dbuf_size % TAPE_BSIZE != 0) {
+         Emsg1(M_ABORT, 0, "Network buffer size %d not multiple of tape block size.\n",
+             dbuf_size);
+      }
+   }
+
+   bs->msglen = dbuf_size;
+   return 1;
+}
+
+/*
+ * Send a network "signal" to the other end 
+ *  This consists of sending a negative packet length
+ *
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int bnet_sig(BSOCK *bs, int sig)
+{
+   bs->msglen = sig;
+   return bnet_send(bs);
+}
+
+/*
+ * Convert a network "signal" code into
+ * human readable ASCII.
+ */
+char *bnet_sig_to_ascii(BSOCK *bs)
+{
+   static char buf[30];
+   switch (bs->msglen) {
+      case BNET_EOF:
+         return "BNET_EOF";
+      case BNET_EOD:
+         return "BNET_EOD";
+      case BNET_EOD_POLL:
+         return "BNET_EOD_POLL";
+      case BNET_STATUS:
+         return "BNET_STATUS";
+      case BNET_TERMINATE:
+         return "BNET_TERMINATE";
+      case BNET_POLL:
+         return "BNET_POLL";
+      case BNET_HEARTBEAT:
+         return "BNET_HEARTBEAT";
+      case BNET_HB_RESPONSE:
+         return "BNET_HB_RESPONSE";
+      case BNET_PROMPT:
+         return "BNET_PROMPT";
+      default:
+         sprintf(buf, "Unknown sig %d", bs->msglen);
+        return buf;
+   }
+}
+
+
+/* Initialize internal socket structure.  
+ *  This probably should be done in net_open
+ */
+BSOCK *
+init_bsock(int sockfd, char *who, char *host, int port) 
+{
+   BSOCK *bsock = (BSOCK *) malloc(sizeof(BSOCK));
+   if (bsock == NULL) {
+      Emsg0(M_ABORT, 0, "Out of memory in init_bsock.\n");
+   }
+   memset(bsock, 0, sizeof(BSOCK));
+   bsock->fd = sockfd;
+   bsock->errors = 0;
+   bsock->msg = (char *) get_pool_memory(PM_MESSAGE);
+   bsock->who = bstrdup(who);
+   bsock->host = bstrdup(host);
+   bsock->port = port;
+   /*
+    * ****FIXME**** reduce this to a few hours once   
+    *  heartbeats are implemented
+    */
+   bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */
+   return bsock;
+}
+
+BSOCK *
+dup_bsock(BSOCK *osock)
+{
+   BSOCK *bsock = (BSOCK *) malloc(sizeof(BSOCK));
+   if (bsock == NULL) {
+      Emsg0(M_ABORT, 0, "Out of memory in dup_bsock.\n");
+   }
+   memcpy(bsock, osock, sizeof(BSOCK));
+   bsock->msg = (char *) get_pool_memory(PM_MESSAGE);
+   bsock->duped = TRUE;
+   return bsock;
+}
+
+/* Close the network connection */
+void 
+bnet_close(BSOCK *bsock)
+{
+   BSOCK *next;
+
+   for ( ; bsock != NULL; bsock = next) {
+      next = bsock->next;
+      if (!bsock->duped) {
+        shutdown(bsock->fd, SHUT_RDWR);
+        close(bsock->fd);
+        term_bsock(bsock);
+      } else {
+        free(bsock);
+      }
+   }
+   return;
+}
+
+void
+term_bsock(BSOCK *bsock)
+{
+   free_pool_memory(bsock->msg);
+   free(bsock->who);
+   free(bsock->host);
+   free(bsock);
+}
diff --git a/bacula/src/lib/bnet_server.c b/bacula/src/lib/bnet_server.c
new file mode 100644 (file)
index 0000000..ef9bc47
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+ /* 
+  * Originally written by Kern Sibbald for inclusion in apcupsd.
+  */
+
+#include "bacula.h"
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef HAVE_LIBWRAP
+#include "tcpd.h"
+int allow_severity = LOG_NOTICE;
+int deny_severity = LOG_WARNING;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+/* Become Threaded Network Server */
+void
+bnet_thread_server(int port, int max_clients, workq_t *client_wq, 
+                  void handle_client_request(void *bsock))
+{
+   int newsockfd, sockfd, stat;
+   socklen_t clilen;
+   struct sockaddr_in cli_addr;       /* client's address */
+   struct sockaddr_in serv_addr;      /* our address */
+   int tlog;
+   fd_set ready, sockset;
+   int turnon = 1;
+   char *caller;
+#ifdef HAVE_LIBWRAP
+   struct request_info request;
+#endif
+
+   /*
+    * Open a TCP socket  
+    */
+   for (tlog=0; (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 10 ) {
+      if (tlog <= 0) {
+        tlog = 60; 
+         Emsg1(M_ERROR, 0, "Cannot open stream socket: %s. Retrying ...\n", strerror(errno));
+      }
+      sleep(10);
+   }
+
+   /*
+    * Reuse old sockets 
+    */
+   if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &turnon, sizeof(turnon)) < 0) {
+      Emsg1(M_WARNING, 0, "Cannot set SO_REUSEADDR on socket: %s\n" , strerror(errno));
+   }
+
+   /* 
+    * Bind our local address so that the client can send to us.
+    */
+   bzero((char *) &serv_addr, sizeof(serv_addr));
+   serv_addr.sin_family = AF_INET;
+   serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+   serv_addr.sin_port = htons(port);
+
+   for (tlog=0; bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0; tlog -= 5 ) {
+      if (tlog <= 0) {
+        tlog = 2*60;                 /* Complain every 2 minutes */
+         Emsg2(M_WARNING, 0, "Cannot bind port %d: %s. Retrying ...\n", port, strerror(errno));
+      }
+      sleep(5);
+   }
+   listen(sockfd, 5);                /* tell system we are ready */
+
+   FD_ZERO(&sockset);
+   FD_SET(sockfd, &sockset);
+
+   /* Start work queue thread */
+   if ((stat = workq_init(client_wq, max_clients, handle_client_request)) != 0) {
+      Emsg1(M_ABORT, 0, "Could not init client queue: ERR=%s\n", strerror(stat));
+   }
+
+   for (;;) {
+      /* 
+       * Wait for a connection from a client process.
+       */
+      ready = sockset;
+      if ((stat = select(sockfd+1, &ready, NULL, NULL, NULL)) < 0) {
+        if (errno == EINTR || errno == EAGAIN) {
+           errno = 0;
+           continue;
+        }
+        close(sockfd);
+         Emsg1(M_FATAL, 0, "Error in select: %s\n", strerror(errno));
+        break;
+      }
+      clilen = sizeof(cli_addr);
+      newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
+
+#ifdef HAVE_LIBWRAP
+      P(mutex);                      /* hosts_access is not thread safe */
+      request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
+      fromhost(&request);
+      if (!hosts_access(&request)) {
+        V(mutex);
+         Emsg2(M_WARNING, 0, "Connection from %s:%d refused by hosts.access",
+              inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
+        close(newsockfd);
+        continue;
+      }
+      V(mutex);
+#endif
+
+      /*
+       * Receive notification when connection dies.
+       */
+      if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
+         Emsg1(M_WARNING, 0, "Cannot set SO_KEEPALIVE on socket: %s\n" , strerror(errno));
+      }
+
+      /* see who client is. i.e. who connected to us. */
+      caller = inet_ntoa(cli_addr.sin_addr);
+      if (caller == NULL) {
+         caller = "unknown client";
+      }
+
+      /* Queue client to be served */
+      if ((stat = workq_add(client_wq, 
+            (void *)init_bsock(newsockfd, "client", caller, port))) != 0) {
+         Emsg1(M_ABORT, 0, "Could not add job to client queue: ERR=%s\n", strerror(stat));
+      }
+   }
+}   
+
+
+/*
+ * Bind an address so that we may accept connections
+ * one at a time.
+ */
+BSOCK *
+bnet_bind(int port)
+{
+   int sockfd;
+   struct sockaddr_in serv_addr;      /* our address */
+   int tlog;
+   int turnon = 1;
+
+   /*
+    * Open a TCP socket  
+    */
+   for (tlog=0; (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 10 ) {
+      if (tlog <= 0) {
+        tlog = 2*60; 
+         Emsg1(M_ERROR, 0, "Cannot open stream socket: %s\n", strerror(errno));
+      }
+      sleep(60);
+   }
+
+   /*
+    * Reuse old sockets 
+    */
+   if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &turnon, sizeof(turnon)) < 0) {
+      Emsg1(M_WARNING, 0, "Cannot set SO_REUSEADDR on socket: %s\n" , strerror(errno));
+   }
+
+   /* 
+    * Bind our local address so that the client can send to us.
+    */
+   bzero((char *) &serv_addr, sizeof(serv_addr));
+   serv_addr.sin_family = AF_INET;
+   serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+   serv_addr.sin_port = htons(port);
+
+   for (tlog=0; bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0; tlog -= 5 ) {
+      if (tlog <= 0) {
+        tlog = 2*60;
+         Emsg2(M_WARNING, 0, "Cannot bind port %d: %s: retrying ...\n", port, strerror(errno));
+      }
+      sleep(5);
+   }
+   listen(sockfd, 1);                /* tell system we are ready */
+   return init_bsock(sockfd, "Server socket", "client", port);
+}
+
+/*
+ * Accept a single connection 
+ */
+BSOCK *
+bnet_accept(BSOCK *bsock, char *who)
+{
+   fd_set ready, sockset;
+   int newsockfd, stat, len;
+   socklen_t clilen;
+   struct sockaddr_in cli_addr;       /* client's address */
+   char *caller, *buf;
+   BSOCK *bs;
+   int turnon = 1;
+#ifdef HAVE_LIBWRAP
+   struct request_info request;
+#endif
+
+   /* 
+    * Wait for a connection from the client process.
+    */
+   FD_ZERO(&sockset);
+   FD_SET(bsock->fd, &sockset);
+
+   for (;;) {
+      /* 
+       * Wait for a connection from a client process.
+       */
+      ready = sockset;
+      if ((stat = select(bsock->fd+1, &ready, NULL, NULL, NULL)) < 0) {
+        if (errno == EINTR || errno == EAGAIN) {
+           errno = 0;
+           continue;
+        }
+         Emsg1(M_FATAL, 0, "Error in select: %s\n", strerror(errno));
+        newsockfd = -1;
+        break;
+      }
+      clilen = sizeof(cli_addr);
+      newsockfd = accept(bsock->fd, (struct sockaddr *)&cli_addr, &clilen);
+      break;
+   }
+
+#ifdef HAVE_LIBWRAP
+   P(mutex);
+   request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
+   fromhost(&request);
+   if (!hosts_access(&request)) {
+      V(mutex);
+      Emsg2(M_WARNING, 0, "Connection from %s:%d refused by hosts.access",
+           inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
+      close(newsockfd);
+      return NULL;
+   }
+   V(mutex);
+#endif
+
+   /*
+    * Receive notification when connection dies.
+    */
+   if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
+      Emsg1(M_WARNING, 0, "Cannot set SO_KEEPALIVE on socket: %s\n" , strerror(errno));
+   }
+
+   /* see who client is. I.e. who connected to us.
+    * return it in the input message buffer.
+    */
+   if ((caller = inet_ntoa(cli_addr.sin_addr)) != NULL) {
+      strcpy(bsock->msg, caller);
+   } else {
+      bsock->msg[0] = 0;
+   }
+   bsock->msglen = strlen(bsock->msg);
+
+   if (newsockfd < 0) {
+      Emsg2(M_FATAL, 0, "Socket accept error for %s. ERR=%s\n", who,
+           strerror(errno));
+      return NULL;
+   } else {
+      if (caller == NULL) {
+         caller = "unknown";
+      }
+      len = strlen(caller) + strlen(who) + 3;
+      buf = (char *) malloc(len);
+      strcpy(buf, who);
+      strcat(buf, ": ");
+      strcat(buf, caller);
+      bs = init_bsock(newsockfd, "client", buf, bsock->port);
+      free(buf);
+      return bs;                     /* return new BSOCK */
+   }
+}   
+
+
+
+
+/*
+ * The following code will soon be deleted, don't attempt
+ * to use it.
+ */
+#ifdef dont_have_threads_junk
+
+/*
+ * This routine is called by the main process to
+ * track its children. On CYGWIN, the child processes
+ * don't always exit when the other end of the socket
+ * hangs up. Thus they remain hung on a read(). After
+ * 30 seconds, we send them a SIGTERM signal, which 
+ * causes them to wake up to the reality of the situation.
+ *
+ * Also, on certain Unix systems such as SunOS, we must
+ * explicitly do the wait, otherwise, the child that dies
+ * remains a zombie potentially remaining bound to the
+ * port.
+ */
+
+#ifdef HAVE_SUN_OS
+
+static void reap_children(int childpid)
+{
+   static int pids[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+   static int times[10];
+   int i;
+   time_t now;
+
+   time(&now);
+   for (i=0; i<10; i++) {
+      if (pids[i] && (waitpid(pids[i], NULL, WNOHANG) == pids[i])) {
+        pids[i] = 0;
+      } else {
+        if (pids[i] && ((now - times[i]) > 30))
+           kill(pids[i], SIGTERM);
+      }
+   }
+   for (i=0; i<10; i++) {
+      if (pids[i] && (waitpid(pids[i], NULL, WNOHANG) == pids[i])) {
+        pids[i] = 0;
+      }
+      if (childpid && (pids[i] == 0)) {
+        pids[i] = childpid;
+        times[i] = now;
+        childpid = 0;
+      }
+   }
+}
+
+#endif /* HAVE_SUN_OS */
+
+/* Become network server */
+void
+bnet_server(int port, void handle_client_request(BSOCK *bsock))
+{
+   int newsockfd, sockfd, clilen, childpid, stat;
+   struct sockaddr_in cli_addr;       /* client's address */
+   struct sockaddr_in serv_addr;      /* our address */
+   int tlog;
+   fd_set ready, sockset;
+   int turnon = 1;
+   char *caller;
+#ifdef HAVE_LIBWRAP
+   struct request_info request;
+#endif
+
+   /* **** FIXME **** handle BSD too */
+   signal(SIGCHLD, SIG_IGN);
+   
+   /*
+    * Open a TCP socket  
+    */
+   for (tlog=0; (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 10 ) {
+      if (tlog <= 0) {
+        tlog = 60; 
+         Emsg1(M_ERROR, 0, "Cannot open stream socket: %s. Retrying ...\n", strerror(errno));
+      }
+      sleep(10);
+   }
+
+   /*
+    * Reuse old sockets 
+    */
+   if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &turnon, sizeof(turnon)) < 0) {
+      Emsg1(M_WARNING, 0, "Cannot set SO_REUSEADDR on socket: %s\n" , strerror(errno));
+   }
+
+   /*
+    * Receive notification when connection dies.
+    */
+   if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
+      Emsg1(M_WARNING, 0, "Cannot set SO_KEEPALIVE on socket: %s\n" , strerror(errno));
+   }
+
+   /* 
+    * Bind our local address so that the client can send to us.
+    */
+   bzero((char *) &serv_addr, sizeof(serv_addr));
+   serv_addr.sin_family = AF_INET;
+   serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+   serv_addr.sin_port = htons(port);
+
+   for (tlog=0; bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0; tlog -= 5 ) {
+      if (tlog <= 0) {
+        tlog = 2*60;                 /* Complain every 2 minutes */
+         Emsg2(M_WARNING, 0, "Cannot bind port %d: %s. Retrying ...\n", port, strerror(errno));
+      }
+      sleep(5);
+   }
+   listen(sockfd, 5);                /* tell system we are ready */
+
+   FD_ZERO(&sockset);
+   FD_SET(sockfd, &sockset);
+
+   for (;;) {
+      /* 
+       * Wait for a connection from a client process.
+       */
+      ready = sockset;
+      if ((stat = select(sockfd+1, &ready, NULL, NULL, NULL)) < 0) {
+        if (errno == EINTR || errno == EAGAIN) {
+           errno = 0;
+           continue;
+        }
+        close(sockfd);
+         Emsg1(M_FATAL, 0, "Error in select: %s\n", strerror(errno));
+        break;
+      }
+      clilen = sizeof(cli_addr);
+      newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
+
+#ifdef HAVE_LIBWRAP
+      request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
+      fromhost(&request);
+      if (!hosts_access(&request)) {
+         Emsg2(M_WARNING, 0, "Connection from %s:%d refused by hosts.access",
+              inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
+        close(newsockfd);
+        continue;
+      }
+#endif
+
+      /*
+       * Receive notification when connection dies.
+       */
+      if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) {
+         Emsg1(M_WARNING, 0, "Cannot set SO_KEEPALIVE on socket: %s\n" , strerror(errno));
+      }
+
+
+      /* see who client is. i.e. who connected to us. */
+      caller = inet_ntoa(cli_addr.sin_addr);
+      if (caller == NULL) {
+         caller = "client";
+      }
+
+#ifdef HAVE_CYGWIN
+      childpid = 0;
+      handle_client_request(init_bsock(newsockfd, "client", caller, port));
+#else
+      /* fork to provide the response */
+      for (tlog=0; (childpid = fork()) < 0; tlog -= 5*60 ) {
+        if (tlog <= 0) {
+           tlog = 60*60; 
+            Emsg1(M_FATAL, 0, "Fork error: %s\n", strerror(errno));
+        }
+        sleep(5*60);
+      } 
+      if (childpid == 0) {     /* child process */
+        close(sockfd);              /* close original socket */
+         handle_client_request(init_bsock(newsockfd, "client", caller, port));    /* process the request */
+         Dmsg0(99, "back from handle request\n");
+        close(newsockfd);
+        exit(0);
+      }
+#endif
+
+      close(newsockfd);             /* parent process */
+#ifdef HAVE_SUN_OS
+      reap_children(childpid);
+#endif /* HAVE_SUN_OS */
+    }
+}   
+
+#endif /* no threads -- not supported any more sorry! */
diff --git a/bacula/src/lib/bshm.c b/bacula/src/lib/bshm.c
new file mode 100644 (file)
index 0000000..5af8277
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *   Bacula shared memory routines
+ *
+ * To avoid problems with several return arguments, we
+ * pass a packet.
+ *
+ *  BSHM definition is in bshm.h  
+ *
+ *  By Kern Sibbald, May MM
+ *
+ *  Note, this routine was originally written so that the DEVICE structures
+ *  could be shared between the child processes.  Now that the Storage
+ *  daemon is threaded, these routines are no longer needed. Rather than
+ *  rewrite all the code, I simply #ifdef it on NEED_SHARED_MEMORY, and
+ *  when not defined, I simply malloc() a buffer, which is, of course,
+ *  available to all the threads.
+ *
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+
+#ifndef HAVE_CYGWIN
+
+#ifdef NEED_SHARED_MEMORY
+#define SHM_KEY 0x0BACB01           /* key for shared memory */
+static key_t shmkey = SHM_KEY;
+#define MAX_TRIES 1000
+
+#else /* threaded model */
+/* Multiple thread protection */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+
+/* Create shared memory segment defined by BSHM */
+void shm_create(BSHM *shm)
+{
+#ifdef NEED_SHARED_MEMORY
+   int shmid, i;
+   int not_found = TRUE;
+
+   Dmsg1(110, "shm_create size=%d\n", shm->size);
+   for (i=0; i<MAX_TRIES; i++) {
+      if ((shmid = shmget(shmkey, shm->size, shm->perms | IPC_CREAT)) < 0) {
+         Emsg1(M_WARN, 0, "shmget failure key = %x\n", shmkey);
+        shmkey++;
+        continue;
+      }
+      not_found = FALSE;
+      break;
+   }
+   if (not_found) 
+      Emsg2(M_ABORT, 0, "Could not get %d bytes of shared memory: %s\n", shm->size, strerror(errno));
+   shm->shmkey = shmkey;
+   shm->shmid = shmid;
+   Dmsg2(110, "shm_create return key=%x id=%d\n", shmkey, shmid);
+   shmkey++;                         /* leave set for next time */
+#else 
+   shm->shmbuf = NULL;
+   shm->shmkey = 0;                  /* reference count */
+#endif
+}
+
+/* Attach to shared memory segement defined in BSHM */
+void *shm_open(BSHM *shm)
+{
+#ifdef NEED_SHARED_MEMORY
+   int shmid;
+   char *shmbuf;
+
+   Dmsg2(110, "shm_open key=%x size=%d\n", shm->shmkey, shm->size);
+   if ((shmid = shmget(shm->shmkey, shm->size, 0)) < 0)
+      Emsg2(M_ABORT, 0, "Could not get %d bytes of shared memory: %s\n", shm->size, strerror(errno));
+   Dmsg1(110, "shm_open shmat with id=%d\n", shmid);
+   shmbuf = shmat(shmid, NULL, 0);     
+   Dmsg1(110, "shm_open buf=%x\n", shmbuf);
+   if (shmbuf == (char *) -1)
+      Emsg1(M_ABORT, 0, "Could not attach shared memory: %s\n", strerror(errno));
+   shm->shmbuf = shmbuf;
+   shm->shmid = shmid;
+   return shmbuf;
+#else
+   P(mutex);
+   if (!shm->shmbuf) {
+      shm->shmbuf = bmalloc(shm->size);
+   }
+   shm->shmkey++;                    /* reference count */
+   V(mutex);
+   return shm->shmbuf;
+#endif
+}
+
+/* Detach from shared memory segement */
+void shm_close(BSHM *shm)
+{
+#ifdef NEED_SHARED_MEMORY
+   if (shm->size) {
+      if (shmdt(shm->shmbuf) < 0) {
+         Emsg1(M_ERROR, 0, "Error detaching shared memory: %s\n", strerror(errno));
+      }
+   }
+#else
+   P(mutex);
+   shm->shmkey--;                    /* reference count */
+   V(mutex);
+#endif
+}
+
+/* Destroy the shared memory segment */
+void shm_destroy(BSHM *shm)
+{
+#ifdef NEED_SHARED_MEMORY
+   if (shm->size) {
+      if (shmctl(shm->shmid, IPC_RMID, NULL) < 0) {
+         Emsg1(M_ERROR, 0, "Could not destroy shared memory: %s\n", strerror(errno));
+      }
+   }
+#else
+   /* We really should check that the ref count is zero */
+   P(mutex);
+   if (shm->shmbuf) {
+      free(shm->shmbuf);
+      shm->shmbuf = NULL;
+   }
+   V(mutex);
+#endif
+}
+
+#endif /* ! HAVE_CYGWIN */
diff --git a/bacula/src/lib/bshm.h b/bacula/src/lib/bshm.h
new file mode 100644 (file)
index 0000000..3d901b2
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Bacula Shared Memory structure
+ *
+ *  Kern Sibbald, May MM
+ *
+ *     NB: these items are deprecated.  Shared memory was
+ *         used in a first version of the Storage daemon
+ *         when it forked. Since then it has been converted
+ *         to use threads.  However, there are still some
+ *         vestiges of the shared memory code that remain and
+ *         can be removed.
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+typedef struct s_bshm {
+   int size;                          /* length desired */
+   int perms;                         /* permissions desired */
+
+   int shmid;                         /* id set by shm_create and shm_open */
+   key_t shmkey;                      /* key set by shm_create */
+   void *shmbuf;                      /* set by shm_open */
+} BSHM;
diff --git a/bacula/src/lib/bsock.h b/bacula/src/lib/bsock.h
new file mode 100644 (file)
index 0000000..c9ed782
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Bacula Sock Structure definition
+ *
+ * Kern Sibbald, May MM
+ *
+ * Zero msglen from other end indicates soft eof (usually
+ *   end of some binary data stream, but not end of conversation).
+ *
+ * Negative msglen, is special "signal" (no data follows).
+ *   See below for SIGNAL codes.
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+typedef struct s_bsock {
+   uint64_t read_seqno;               /* read sequence number */
+   uint32_t in_msg_no;                /* intput message number */
+   uint32_t out_msg_no;               /* output message number */
+   int fd;                            /* socket file descriptor */
+   int32_t msglen;                    /* message length */
+   int port;                          /* desired port */
+   int errors;                        /* set if errors on socket */
+   int b_errno;                       /* bsock errno */
+   time_t timer_start;                /* time started read/write */
+   int timed_out;                     /* timed out in read/write */
+   int timeout;                       /* time out after this value */
+   int terminated;                    /* set when BNET_TERMINATE arrives */
+   int duped;                         /* set if duped BSOCK */
+   char *msg;                         /* message pool buffer */
+   char *who;                         /* Name of daemon to which we are talking */
+   char *host;                        /* Host name/IP */
+   char *errmsg;                      /* edited error message (to be implemented) */
+   RES *res;                          /* Resource to which we are connected */
+   struct s_bsock *next;              /* next BSOCK if duped */
+} BSOCK;
+
+/* Signal definitions for use in bnet_sig() */
+#define BNET_EOF          0           /* Deprecated, use BNET_EOD */
+#define BNET_EOD         -1           /* End of data stream, new data may follow */
+#define BNET_EOD_POLL    -2           /* End of data and poll all in one */
+#define BNET_STATUS      -3           /* Send full status */
+#define BNET_TERMINATE   -4           /* Conversation terminated, doing close() */
+#define BNET_POLL        -5           /* Poll request, I'm hanging on a read */
+#define BNET_HEARTBEAT   -6           /* Heartbeat Response requested */
+#define BNET_HB_RESPONSE -7           /* Only response permited to HB */
+#define BNET_PROMPT      -8           /* Prompt for UA */
+
+#define BNET_SETBUF_READ  1           /* Arg for bnet_set_buffer_size */
+#define BNET_SETBUF_WRITE 2           /* Arg for bnet_set_buffer_size */
diff --git a/bacula/src/lib/btime.c b/bacula/src/lib/btime.c
new file mode 100644 (file)
index 0000000..c3f1b31
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Bacula time and date routines -- John Walker
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+#include <math.h>
+
+void bstrftime(char *dt, int maxlen, uint32_t tim)
+{
+   time_t ttime = tim;
+   struct tm tm;
+   
+   /* ***FIXME**** the format and localtime_r() should be user configurable */
+   localtime_r(&ttime, &tm);
+   strftime(dt, maxlen, "%d-%b-%Y %H:%M", &tm);
+}
+
+void get_current_time(struct date_time *dt)
+{
+   struct tm tm;
+   time_t now;
+
+   now = time(NULL);
+   gmtime_r(&now, &tm);
+   Dmsg6(200, "m=%d d=%d y=%d h=%d m=%d s=%d\n", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900,
+      tm.tm_hour, tm.tm_min, tm.tm_sec);
+   tm_encode(dt, &tm);
+#ifdef DEBUG
+   Dmsg2(200, "jday=%f jmin=%f\n", dt->julian_day_number, dt->julian_day_fraction);
+   tm_decode(dt, &tm);
+   Dmsg6(200, "m=%d d=%d y=%d h=%d m=%d s=%d\n", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900,
+      tm.tm_hour, tm.tm_min, tm.tm_sec);
+#endif
+}
+
+
+/*  date_encode  --  Encode civil date as a Julian day number. */
+
+fdate_t date_encode(uint32_t year, uint8_t month, uint8_t day)
+{
+
+    /* Algorithm as given in Meeus, Astronomical Algorithms, Chapter 7, page 61 */
+
+    int32_t a, b, m;
+    uint32_t y;
+
+    ASSERT(month < 13);
+    ASSERT(day > 0 && day < 32);
+
+    m = month;
+    y = year;
+
+    if (m <= 2) {
+       y--;
+       m += 12;
+    }
+
+    /* Determine whether date is in Julian or Gregorian calendar based on
+       canonical date of calendar reform. */
+
+    if ((year < 1582) || ((year == 1582) && ((month < 9) || (month == 9 && day < 5)))) {
+       b = 0;
+    } else {
+       a = ((int) (y / 100));
+       b = 2 - a + (a / 4);
+    }
+
+    return (((int32_t) (365.25 * (y + 4716))) + ((int) (30.6001 * (m + 1))) +
+               day + b - 1524.5);
+}
+
+/*  time_encode  --  Encode time from hours, minutes, and seconds
+                    into a fraction of a day.  */
+
+ftime_t time_encode(uint8_t hour, uint8_t minute, uint8_t second,
+                  float32_t second_fraction)
+{
+    ASSERT((second_fraction >= 0.0) || (second_fraction < 1.0));
+    return (ftime_t) (((second + 60L * (minute + 60L * hour)) / 86400.0)) +
+                    second_fraction;
+}
+
+/*  date_time_encode  --  Set day number and fraction from date
+                         and time.  */
+
+void date_time_encode(struct date_time *dt,
+                     uint32_t year, uint8_t month, uint8_t day,
+                     uint8_t hour, uint8_t minute, uint8_t second,
+                     float32_t second_fraction)
+{
+    dt->julian_day_number = date_encode(year, month, day);
+    dt->julian_day_fraction = time_encode(hour, minute, second, second_fraction);
+}
+
+/*  date_decode  --  Decode a Julian day number into civil date.  */
+
+void date_decode(fdate_t date, uint32_t *year, uint8_t *month,
+                uint8_t *day)
+{
+    fdate_t z, f, a, alpha, b, c, d, e;
+
+    date += 0.5;
+    z = floor(date);
+    f = date - z;
+
+    if (z < 2299161.0) {
+       a = z;
+    } else {
+       alpha = floor((z - 1867216.25) / 36524.25);
+       a = z + 1 + alpha - floor(alpha / 4);
+    }
+
+    b = a + 1524;
+    c = floor((b - 122.1) / 365.25);
+    d = floor(365.25 * c);
+    e = floor((b - d) / 30.6001);
+
+    *day = (uint8_t) (b - d - floor(30.6001 * e) + f);
+    *month = (uint8_t) ((e < 14) ? (e - 1) : (e - 13));
+    *year = (uint32_t) ((*month > 2) ? (c - 4716) : (c - 4715));
+}
+
+/*  time_decode  --  Decode a day fraction into civil time.  */
+
+void time_decode(ftime_t time, uint8_t *hour, uint8_t *minute,
+                uint8_t *second, float32_t *second_fraction)
+{
+    uint32_t ij;
+
+    ij = (uint32_t) ((time - floor(time)) * 86400.0);
+    *hour = (uint8_t) (ij / 3600L);
+    *minute = (uint8_t) ((ij / 60L) % 60L);
+    *second = (uint8_t) (ij % 60L);
+    if (second_fraction != NULL) {
+       *second_fraction = time - floor(time);
+    }
+}
+
+/*  date_time_decode  --  Decode a Julian day and day fraction
+                         into civil date and time.  */
+
+void date_time_decode(struct date_time *dt,
+                     uint32_t *year, uint8_t *month, uint8_t *day,
+                     uint8_t *hour, uint8_t *minute, uint8_t *second,
+                     float32_t *second_fraction)
+{
+    date_decode(dt->julian_day_number, year, month, day);
+    time_decode(dt->julian_day_fraction, hour, minute, second, second_fraction);
+}
+
+/*  tm_encode  --  Encode a civil date and time from a tm structure   
+ *                to a Julian day and day fraction.
+ */
+
+void tm_encode(struct date_time *dt,
+                     struct tm *tm) 
+{
+    uint32_t year;
+    uint8_t month, day, hour, minute, second;
+
+    year = tm->tm_year + 1900;
+    month = tm->tm_mon + 1;
+    day = tm->tm_mday;
+    hour = tm->tm_hour;
+    minute = tm->tm_min;
+    second = tm->tm_sec;
+    dt->julian_day_number = date_encode(year, month, day);
+    dt->julian_day_fraction = time_encode(hour, minute, second, 0.0);
+}
+
+
+/*  tm_decode  --  Decode a Julian day and day fraction
+                  into civil date and time in tm structure */
+
+void tm_decode(struct date_time *dt,
+                     struct tm *tm) 
+{
+    uint32_t year;
+    uint8_t month, day, hour, minute, second;
+
+    date_decode(dt->julian_day_number, &year, &month, &day);
+    time_decode(dt->julian_day_fraction, &hour, &minute, &second, NULL);
+    tm->tm_year = year - 1900;
+    tm->tm_mon = month - 1;
+    tm->tm_mday = day;
+    tm->tm_hour = hour;
+    tm->tm_min = minute;
+    tm->tm_sec = second;
+}
+
+
+/*  date_time_compare  --  Compare two dates and times and return
+                          the relationship as follows:
+
+                                   -1    dt1 < dt2
+                                    0    dt1 = dt2
+                                    1    dt1 > dt2
+*/
+
+int date_time_compare(struct date_time *dt1, struct date_time *dt2)
+{
+    if (dt1->julian_day_number == dt2->julian_day_number) {
+       if (dt1->julian_day_fraction == dt2->julian_day_fraction) {
+           return 0;
+       }
+       return (dt1->julian_day_fraction < dt2->julian_day_fraction) ? -1 : 1;
+    }
+    return (dt1->julian_day_number - dt2->julian_day_number) ? -1 : 1;
+}
diff --git a/bacula/src/lib/btime.h b/bacula/src/lib/btime.h
new file mode 100644 (file)
index 0000000..b298279
--- /dev/null
@@ -0,0 +1,79 @@
+
+/*  Time and date structures and functions.
+    Date and time are always represented internally
+    as 64 bit floating point Julian day numbers and
+    fraction.  The day number and fraction are kept
+    as separate quantities to avoid round-off of
+    day fraction. John Walker */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#ifndef __btime_INCLUDED
+#define __btime_INCLUDED
+
+typedef float64_t fdate_t;             /* Date type */
+typedef float64_t ftime_t;             /* Time type */
+
+struct date_time {
+    fdate_t julian_day_number;         /* Julian day number */
+    ftime_t julian_day_fraction;       /* Julian day fraction */
+};
+
+/*  In arguments and results of the following functions,
+    quantities are expressed as follows.
+
+        year    Year in the Common Era.  The canonical
+                date of adoption of the Gregorian calendar
+                (October 5, 1582 in the Julian calendar)
+                is assumed.
+
+        month   Month index with January 0, December 11.
+
+        day     Day number of month, 1 to 31.
+
+*/
+
+extern void bstrftime(char *dt, int maxlen, uint32_t tim);
+
+extern fdate_t date_encode(uint32_t year, uint8_t month, uint8_t day);
+extern ftime_t time_encode(uint8_t hour, uint8_t minute, uint8_t second,
+                          float32_t second_fraction);
+extern void date_time_encode(struct date_time *dt,
+                             uint32_t year, uint8_t month, uint8_t day,
+                             uint8_t hour, uint8_t minute, uint8_t second,
+                             float32_t second_fraction);
+
+extern void date_decode(fdate_t date, uint32_t *year, uint8_t *month,
+                        uint8_t *day);
+extern void time_decode(ftime_t time, uint8_t *hour, uint8_t *minute,
+                        uint8_t *second, float32_t *second_fraction);
+extern void date_time_decode(struct date_time *dt,
+                             uint32_t *year, uint8_t *month, uint8_t *day,
+                             uint8_t *hour, uint8_t *minute, uint8_t *second,
+                             float32_t *second_fraction);
+
+extern int date_time_compare(struct date_time *dt1, struct date_time *dt2);
+
+extern void tm_encode(struct date_time *dt, struct tm *tm);
+extern void tm_decode(struct date_time *dt, struct tm *tm);
+extern void get_current_time(struct date_time *dt);
+
+#endif /* __btime_INCLUDED */
diff --git a/bacula/src/lib/cram-md5.c b/bacula/src/lib/cram-md5.c
new file mode 100644 (file)
index 0000000..e9e6cd7
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *  Challenge Response Authentication Method using MD5 (CRAM-MD5)
+ *
+ * cram-md5 is based on RFC2104.
+ * 
+ * Written for Bacula by Kern E. Sibbald, May MMI.
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+
+int cram_md5_auth(BSOCK *bs, char *password)
+{
+   struct timeval t1;
+   struct timeval t2;
+   struct timezone tz;
+   int i, ok;
+   char chal[MAXSTRING];
+   char host[MAXSTRING];
+   uint8_t hmac[20];
+
+   gettimeofday(&t1, &tz);
+   for (i=0; i<4; i++)
+      gettimeofday(&t2, &tz);
+   srandom((t1.tv_sec&0xffff) * (t2.tv_usec&0xff));
+   gethostname(host, sizeof(host));
+   sprintf((char *)chal, "<%u.%u@%s>", (uint32_t)random(), (uint32_t)time(NULL), host);
+   if (!bnet_fsend(bs, "auth cram-md5 %s\n", chal)) {
+      return 0;
+   }
+   Dmsg1(99, "%s", bs->msg);
+   if (bnet_wait_data(bs, 120) <= 0 || bnet_recv(bs) <= 0) {
+      sleep(5);
+      return 0;
+   }
+   hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
+   bin_to_base64(host, (char *)hmac, 16);
+   ok = strcmp(bs->msg, host) == 0;
+   if (ok) {
+      Dmsg3(399, "Authenticate %s: wanted %s, got %s\n", 
+            ok ? "OK" : "NOT OK", host, bs->msg);
+   } else {
+      Dmsg3(99, "Authenticate %s: wanted %s, got %s\n", 
+            ok ? "OK" : "NOT OK", host, bs->msg);
+   }
+   if (ok) {
+      bnet_fsend(bs, "1000 OK auth\n");
+   } else {
+      bnet_fsend(bs, "1999 No auth\n");
+      sleep(5);
+   }
+   return ok;
+}
+
+int cram_md5_get_auth(BSOCK *bs, char *password)
+{
+   char chal[MAXSTRING];
+   uint8_t hmac[20];
+
+   if (bnet_recv(bs) <= 0) {
+      sleep(5);
+      return 0;
+   }
+   if (sscanf(bs->msg, "auth cram-md5 %s", chal) != 1) {
+     sleep(5);
+     return 0;
+   }
+   hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
+   bs->msglen = bin_to_base64(bs->msg, (char *)hmac, 16);
+   if (!bnet_send(bs)) {
+      return 0;
+   }
+   Dmsg1(99, "sending resp to challenge: %s\n", bs->msg);
+   if (bnet_wait_data(bs, 120) <= 0 || bnet_recv(bs) <= 0) {
+      sleep(5);
+      return 0;
+   }
+   if (strcmp(bs->msg, "1000 OK auth\n") == 0) {
+      return 1;
+   }
+   sleep(5);
+   return 0;
+}
diff --git a/bacula/src/lib/crc32.c b/bacula/src/lib/crc32.c
new file mode 100644 (file)
index 0000000..81eefa7
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ *  32 bit CRC.  Algorithm from RFC 2083 (png format)
+ *
+ *   By Kern Sibbald, January 2001
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifdef GENERATE_STATIC_CRC_TABLE
+/*
+ * The following code can be used to generate the static CRC table.
+ *
+ * Note, the magic number 0xedb88320L below comes from the terms
+ * of the defining polynomial x^n, 
+ * where n=0,1,2,4,5,7,8,10,11,12,16,22,23,26
+ */
+#include <stdio.h>
+
+main()
+{
+   unsigned long crc;
+   unsigned long buf[5];
+   int i, j, k;
+   k = 0;
+   for (i = 0; i < 256; i++) {
+      crc = (unsigned long)i;
+      for (j = 0; j < 8; j++) {
+        if (crc & 1) {
+           crc = 0xedb88320L ^ (crc >> 1);
+        } else {
+           crc = crc >> 1;
+        }
+      }
+      buf[k++] = crc;
+      if (k == 5) {
+        k = 0;
+         printf("  0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x,\n", 
+           buf[0], buf[1], buf[2], buf[3], buf[4]);
+      }
+   }
+   printf("  0x%08x\n", buf[0]);
+}
+#endif
+
+#include "bacula.h"
+
+static uint32_t crc_table[256] = {
+  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+  0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+  0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+  0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+  0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+  0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+  0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+  0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+  0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+  0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+  0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+  0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+  0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+  0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+  0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+  0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+  0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+  0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+  0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+  0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+  0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+  0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+  0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+  0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+  0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+  0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+  0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+  0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+  0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+  0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+  0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+  0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+  0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+  0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+  0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+  0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+  0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+  0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+  0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+  0x2d02ef8d
+};
+
+/*
+ * Calculate the PNG 32 bit CRC on a buffer */
+uint32_t bcrc32(uint8_t *buf, int len)
+{
+  uint32_t crc = 0xFFFFFFFFL;
+  int i;
+
+  for (i=0; i < len; i++) {
+     crc = crc_table[(crc ^ buf[i]) & 0xFF] ^ (crc >> 8);
+  }
+  return crc ^ 0xFFFFFFFFL;
+}
diff --git a/bacula/src/lib/daemon.c b/bacula/src/lib/daemon.c
new file mode 100644 (file)
index 0000000..387a47b
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  daemon.c by Kern Sibbald
+ *
+ *   this code is inspired by the Prentice Hall book
+ *   "Unix Network Programming" by W. Richard Stevens
+ *   and later updated from his book "Advanced Programming
+ *   in the UNIX Environment"
+ *
+ * Initialize a daemon process completely detaching us from
+ * any terminal processes. 
+ *
+ */ 
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+
+void 
+daemon_start()
+{
+#ifndef HAVE_CYGWIN
+   int i;
+   int cpid;
+   /*
+    *  Become a daemon.
+    */
+
+   Dmsg0(200, "Enter daemon_start\n");
+   if ( (cpid = fork() ) < 0)
+      Emsg1(M_ABORT, 0, "Cannot fork to become daemon: %s\n", strerror(errno));
+   else if (cpid > 0)
+      exit(0);             /* parent exits */
+   /* Child continues */
+      
+   setsid();
+
+   /* In the PRODUCTION system, we close ALL
+    * file descriptors. It is useful
+    * for debugging to leave the standard ones open.
+    */
+   for (i=sysconf(_SC_OPEN_MAX)-1; i >=0; i--) {
+#ifdef DEBUG
+      if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO) {
+        close(i);
+      }
+#else 
+      close(i);
+#endif
+   }
+
+   /* Move to root directory. For debug we stay
+    * in current directory so dumps go there.
+    */
+#ifndef DEBUG
+   chdir("/");
+#endif
+
+   /* clear any inherited umask */ 
+   umask(0);
+
+   Dmsg0(200, "Exit daemon_start\n");
+#endif /* HAVE_CYGWIN */
+}
diff --git a/bacula/src/lib/events.c b/bacula/src/lib/events.c
new file mode 100644 (file)
index 0000000..29c0319
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *  Bacula Event File handling
+ *
+ *    Kern Sibbald, August MMI
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+
+#ifdef IMPLEMENTED
+void log_event(UPSINFO *ups, int level, char *fmt, ...)
+{
+    va_list  arg_ptr;
+    char msg[2*MAXSTRING];
+    char datetime[MAX_TIME_LENGTH];
+    int event_fd = ups->event_fd;
+
+    event_fd = ups->event_fd;
+
+    /*****FIXME***** use pool memory */
+    va_start(arg_ptr, fmt);
+    vsprintf(msg, fmt, arg_ptr);
+    va_end(arg_ptr);
+
+    syslog(level, msg);          /* log the event */
+
+    /* Write out to our temp file. LOG_INFO is DATA logging, so
+       do not write it to our temp events file. */
+    if (event_fd >= 0 && level != LOG_INFO) {
+       int lm;
+       time_t nowtime;
+       struct tm tm;
+
+       time(&nowtime);
+       localtime_r(&nowtime, &tm);
+        strftime(datetime, sizeof(datetime), "%a %b %d %X %Z %Y  ", &tm);
+       write(event_fd, datetime, strlen(datetime));
+       lm = strlen(msg);
+        if (msg[lm-1] != '\n') 
+           msg[lm++] = '\n';
+       write(event_fd, msg, lm);
+    }
+}
+
+
+#define NLE   10                     /* number of events to send and keep */
+#define MAXLE 50                     /* truncate file when this many events */
+
+/*
+ * If the EVENTS file exceeds MAXLE records, truncate it. 
+ *
+ * Returns:
+ *
+ *  0 if file not truncated
+ *  1 if file truncated
+ */
+int truncate_events_file(UPSINFO *ups)
+{
+    char *le[NLE], *buf;
+    int i, j;
+    int nrec = 0;
+    int tlen = 0;
+    int trunc = FALSE;
+    FILE *events_file;
+    int stat = 0;
+    
+    if ((events_file = fopen(ups->eventfile, "r+")) == NULL)
+       return 0;
+    for (i=0; i<NLE; i++)
+       le[i] = NULL;
+    for (i=0; i<NLE; i++)
+       if ((le[i] = malloc(MAXSTRING)) == NULL)
+           goto bailout;
+    i = 0;
+    while (fgets(le[i], MAXSTRING, events_file) != NULL) {
+       nrec++;
+       i++;
+       if (i >= NLE)                  /* wrap */
+           i = 0;
+    }
+    if (nrec > MAXLE)
+       trunc = TRUE;                  /* file too large, truncate it */
+    if (nrec > NLE) {
+       nrec = NLE;                    /* number of records to output */
+       i -= (i/NLE)*NLE;              /* first record to output */
+    } else
+       i = 0;
+    /* get total length to output */
+    for (j=0; j < nrec; j++)
+       tlen += strlen(le[j]);
+    if ((buf = malloc(tlen+1)) == NULL)
+       goto bailout;
+    *buf = 0;
+    /* Put records in single buffer in correct order */
+    for (j=0; j < nrec; j++) {
+       strcat(buf, le[i++]); 
+       if (i >= NLE)
+           i = 0;
+    }
+    if (trunc) {
+       ftruncate(fileno(events_file), 0L);
+       rewind(events_file);
+       fwrite(buf, tlen, 1, events_file); /* write last NLE records to file */
+       stat = 1;                          /* we truncated it */
+    }
+
+    free(buf);
+
+bailout:
+
+   fclose(events_file);
+   for (i=0; i<NLE; i++)
+       if (le[i] != NULL)
+          free(le[i]);
+   return stat;
+}
+
+#endif /* IMPLEMENTED */
+
+#ifdef HAVE_CYGWIN
+
+#include <windows.h>
+
+extern UPSINFO myUPS;
+extern int shm_OK;
+
+/*  
+ * Fill the Events list box with the last events
+ * 
+ */
+void FillEventsBox(HWND hwnd, int idlist)
+{
+    char buf[1000];
+    int len;
+    FILE *events_file;
+    
+    if (!shm_OK || myUPS.eventfile[0] == 0 ||
+        (events_file = fopen(myUPS.eventfile, "r")) == NULL) {
+       SendDlgItemMessage(hwnd, idlist, LB_ADDSTRING, 0, 
+           (LONG)"Events not available");
+       return;
+    }
+
+    while (fgets(buf, sizeof(buf), events_file) != NULL) {
+       len = strlen(buf);
+       /* strip trailing cr/lfs */
+        while (len > 0 && (buf[len-1] == '\n' || buf[len-1] == '\r'))
+           buf[--len] = 0;
+       SendDlgItemMessage(hwnd, idlist, LB_ADDSTRING, 0, (LONG)buf);
+    }
+    return;
+}
+
+#endif /* HAVE_CYGWIN */
diff --git a/bacula/src/lib/fnmatch.c b/bacula/src/lib/fnmatch.c
new file mode 100644 (file)
index 0000000..844add3
--- /dev/null
@@ -0,0 +1,239 @@
+/* Copyright (C) 1991, 1992, 1993, 1996, 1997 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "bacula.h"
+#ifndef HAVE_FNMATCH
+
+/* Enable GNU extensions in fnmatch.h. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE   1
+#endif
+
+#include "fnmatch.h"
+
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions. Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined _LIBC || !defined __GNU_LIBRARY__
+
+
+# if defined STDC_HEADERS || !defined isascii
+#  define ISASCII(c) 1
+# else
+#  define ISASCII(c) isascii(c)
+# endif
+
+#ifndef ISUPPER
+# define ISUPPER(c) (ISASCII (c) && isupper (c))
+#endif
+
+
+# ifndef errno
+extern int errno;
+# endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+   it matches, nonzero if not. */
+int
+fnmatch (const char *pattern, const char *string, int flags)
+{
+  register const char *p = pattern, *n = string;
+  register char c;
+
+/* Note that this evaluates C many times.  */
+# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
+
+  while ((c = *p++) != '\0')
+    {
+      c = FOLD (c);
+
+      switch (c)
+       {
+        case '?':
+          if (*n == '\0')
+           return FNM_NOMATCH;
+          else if ((flags & FNM_FILE_NAME) && *n == '/')
+           return FNM_NOMATCH;
+          else if ((flags & FNM_PERIOD) && *n == '.' &&
+                   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+           return FNM_NOMATCH;
+         break;
+
+        case '\\':
+         if (!(flags & FNM_NOESCAPE))
+           {
+             c = *p++;
+              if (c == '\0')
+                /* Trailing \ loses.  */
+               return FNM_NOMATCH;
+             c = FOLD (c);
+           }
+         if (FOLD (*n) != c)
+           return FNM_NOMATCH;
+         break;
+
+        case '*':
+          if ((flags & FNM_PERIOD) && *n == '.' &&
+              (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+           return FNM_NOMATCH;
+
+          for (c = *p++; c == '?' || c == '*'; c = *p++)
+           {
+              if ((flags & FNM_FILE_NAME) && *n == '/')
+               /* A slash does not match a wildcard under FNM_FILE_NAME.  */
+               return FNM_NOMATCH;
+              else if (c == '?')
+               {
+                 /* A ? needs to match one character.  */
+                  if (*n == '\0')
+                    /* There isn't another character; no match.  */
+                   return FNM_NOMATCH;
+                 else
+                   /* One character of the string is consumed in matching
+                       this ? wildcard, so *??? won't match if there are
+                      less than three characters.  */
+                   ++n;
+               }
+           }
+
+          if (c == '\0')
+           return 0;
+
+         {
+            char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+           c1 = FOLD (c1);
+            for (--p; *n != '\0'; ++n)
+              if ((c == '[' || FOLD (*n) == c1) &&
+                 fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+               return 0;
+           return FNM_NOMATCH;
+         }
+
+        case '[':
+         {
+           /* Nonzero if the sense of the character class is inverted.  */
+           register int not;
+
+            if (*n == '\0')
+             return FNM_NOMATCH;
+
+            if ((flags & FNM_PERIOD) && *n == '.' &&
+                (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+             return FNM_NOMATCH;
+
+            not = (*p == '!' || *p == '^');
+           if (not)
+             ++p;
+
+           c = *p++;
+           for (;;)
+             {
+               register char cstart = c, cend = c;
+
+                if (!(flags & FNM_NOESCAPE) && c == '\\')
+                 {
+                    if (*p == '\0')
+                     return FNM_NOMATCH;
+                   cstart = cend = *p++;
+                 }
+
+               cstart = cend = FOLD (cstart);
+
+                if (c == '\0')
+                 /* [ (unterminated) loses.  */
+                 return FNM_NOMATCH;
+
+               c = *p++;
+               c = FOLD (c);
+
+                if ((flags & FNM_FILE_NAME) && c == '/')
+                 /* [/] can never match.  */
+                 return FNM_NOMATCH;
+
+                if (c == '-' && *p != ']')
+                 {
+                   cend = *p++;
+                    if (!(flags & FNM_NOESCAPE) && cend == '\\')
+                     cend = *p++;
+                    if (cend == '\0')
+                     return FNM_NOMATCH;
+                   cend = FOLD (cend);
+
+                   c = *p++;
+                 }
+
+               if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
+                 goto matched;
+
+                if (c == ']')
+                 break;
+             }
+           if (!not)
+             return FNM_NOMATCH;
+           break;
+
+         matched:;
+           /* Skip the rest of the [...] that already matched.  */
+            while (c != ']')
+             {
+                if (c == '\0')
+                 /* [... (unterminated) loses.  */
+                 return FNM_NOMATCH;
+
+               c = *p++;
+                if (!(flags & FNM_NOESCAPE) && c == '\\')
+                 {
+                    if (*p == '\0')
+                     return FNM_NOMATCH;
+                   /* XXX 1003.2d11 is unclear if this is right.  */
+                   ++p;
+                 }
+             }
+           if (not)
+             return FNM_NOMATCH;
+         }
+         break;
+
+       default:
+         if (c != FOLD (*n))
+           return FNM_NOMATCH;
+       }
+
+      ++n;
+    }
+
+  if (*n == '\0')
+    return 0;
+
+  if ((flags & FNM_LEADING_DIR) && *n == '/')
+    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
+    return 0;
+
+  return FNM_NOMATCH;
+
+# undef FOLD
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+
+#endif /* !HAVE_FNMATCH */
diff --git a/bacula/src/lib/fnmatch.h b/bacula/src/lib/fnmatch.h
new file mode 100644 (file)
index 0000000..af1dcf5
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.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, 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.  */
+
+#ifndef        _FNMATCH_H
+
+#define        _FNMATCH_H      1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef __P
+#define        __P(protos)     protos
+#else /* Not C++ or ANSI C.  */
+#undef __P
+#define        __P(protos)     ()
+/* We can get away without defining `const' here only because in this file
+   it is used only inside the prototype for `fnmatch', which is elided in
+   non-ANSI C where `const' is problematical.  */
+#endif /* C++ or ANSI C.  */
+
+
+/* We #undef these before defining them because some losing systems
+   (HP-UX A.08.07 for example) define these in <unistd.h>.  */
+#undef FNM_PATHNAME
+#undef FNM_NOESCAPE
+#undef FNM_PERIOD
+
+/* Bits set in the FLAGS argument to `fnmatch'.  */
+#define        FNM_PATHNAME    (1 << 0) /* No wildcard can ever match `/'.  */
+#define        FNM_NOESCAPE    (1 << 1) /* Backslashes don't quote special chars.  */
+#define        FNM_PERIOD      (1 << 2) /* Leading `.' is matched only explicitly.  */
+
+#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE)
+#define        FNM_FILE_NAME   FNM_PATHNAME /* Preferred GNU name.  */
+#define        FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match.  */
+#define        FNM_CASEFOLD    (1 << 4) /* Compare without regard to case.  */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN.  */
+#define        FNM_NOMATCH     1
+
+/* Match STRING against the filename pattern PATTERN,
+   returning zero if it matches, FNM_NOMATCH if not.  */
+extern int fnmatch __P ((const char *__pattern, const char *__string,
+                        int __flags));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
diff --git a/bacula/src/lib/gconsole b/bacula/src/lib/gconsole
new file mode 100755 (executable)
index 0000000..1e22ee0
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+cd $HOME/bacula/k/src/gnome-console
+if [ $# = 1 ] ; then
+   echo "doing gnome-console $1.conf"
+   ./gnome-console -c $1.conf
+else
+   ./gnome-console
+fi
diff --git a/bacula/src/lib/getopt.h b/bacula/src/lib/getopt.h
new file mode 100644 (file)
index 0000000..b0147e9
--- /dev/null
@@ -0,0 +1,169 @@
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETOPT_H
+
+#ifndef __need_getopt
+# define _GETOPT_H 1
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+#ifndef __need_getopt
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument         (or 0) if the option does not take an argument,
+   required_argument   (or 1) if the option requires an argument,
+   optional_argument   (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+# if defined __STDC__ && __STDC__
+  const char *name;
+# else
+  char *name;
+# endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+# define no_argument           0
+# define required_argument     1
+# define optional_argument     2
+#endif /* need getopt */
+
+
+/* Get definitions and prototypes for functions to process the
+   arguments in ARGV (ARGC of them, minus the program name) for
+   options given in OPTS.
+
+   Return the option character from OPTS just read.  Return -1 when
+   there are no more options.  For unrecognized options, or options
+   missing arguments, `optopt' is set to the option letter, and '?' is
+   returned.
+
+   The OPTS string is a list of characters which are recognized option
+   letters, optionally followed by colons, specifying that that letter
+   takes an argument, to be placed in `optarg'.
+
+   If a letter in OPTS is followed by two colons, its argument is
+   optional.  This behavior is specific to the GNU `getopt'.
+
+   The argument `--' causes premature termination of argument
+   scanning, explicitly telling `getopt' that there are no more
+   options.
+
+   If OPTS begins with `--', then non-option arguments are treated as
+   arguments to the option '\0'.  This behavior is specific to the GNU
+   `getopt'.  */
+
+#if defined __STDC__ && __STDC__
+# ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int __argc, char *const *__argv, const char *__shortopts);
+# else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+# endif /* __GNU_LIBRARY__ */
+
+# ifndef __need_getopt
+extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts,
+                       const struct option *__longopts, int *__longind);
+extern int getopt_long_only (int __argc, char *const *__argv,
+                            const char *__shortopts,
+                            const struct option *__longopts, int *__longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int __argc, char *const *__argv,
+                            const char *__shortopts,
+                            const struct option *__longopts, int *__longind,
+                            int __long_only);
+# endif
+#else /* not __STDC__ */
+extern int getopt ();
+# ifndef __need_getopt
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+# endif
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Make sure we later can get all the definitions and declarations.  */
+#undef __need_getopt
+
+#endif /* getopt.h */
diff --git a/bacula/src/lib/hmac.c b/bacula/src/lib/hmac.c
new file mode 100644 (file)
index 0000000..bb8e465
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *  Hashed Message Authentication Code using MD5 (HMAC-MD5)
+ *
+ * hmac_md5 was based on sample code in RFC2104 (thanks guys).
+ * 
+ * Adapted to Bacula by Kern E. Sibbald, February MMI.
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+
+#define PAD_LEN 64                   /* PAD length */
+#define SIG_LEN 16                   /* MD5 signature length */
+
+void
+hmac_md5(
+    uint8_t*  text,           /* pointer to data stream */
+    int   text_len,           /* length of data stream */
+    uint8_t*  key,            /* pointer to authentication key */
+    int   key_len,            /* length of authentication key */
+    uint8_t  *hmac)           /* returned hmac-md5 */
+{
+   MD5Context md5c;
+   uint8_t k_ipad[PAD_LEN];    /* inner padding - key XORd with ipad */
+   uint8_t k_opad[PAD_LEN];    /* outer padding - key XORd with opad */
+   uint8_t keysig[SIG_LEN];
+   int i;
+
+   /* if key is longer than PAD length, reset it to key=MD5(key) */
+   if (key_len > PAD_LEN) {
+      MD5Context md5key;
+
+      MD5Init(&md5key);
+      MD5Update(&md5key, key, key_len);
+      MD5Final(keysig, &md5key);
+
+      key = keysig;
+      key_len = SIG_LEN;
+   }
+
+   /*
+    * the HMAC_MD5 transform looks like:
+    *
+    * MD5(Key XOR opad, MD5(Key XOR ipad, text))
+    *
+    * where Key is an n byte key
+    * ipad is the byte 0x36 repeated 64 times
+
+    * opad is the byte 0x5c repeated 64 times
+    * and text is the data being protected
+    */
+
+   /* Zero pads and store key */
+   memset(k_ipad, 0, PAD_LEN);
+   memcpy(k_ipad, key, key_len);
+   memcpy(k_opad, k_ipad, PAD_LEN); 
+
+   /* XOR key with ipad and opad values */
+   for (i=0; i<PAD_LEN; i++) {
+      k_ipad[i] ^= 0x36;
+      k_opad[i] ^= 0x5c;
+   }
+
+   /* perform inner MD5 */
+   MD5Init(&md5c);                   /* start inner hash */
+   MD5Update(&md5c, k_ipad, PAD_LEN); /* hash inner pad */
+   MD5Update(&md5c, text, text_len);  /* hash text */
+   MD5Final(hmac, &md5c);            /* store inner hash */
+
+   /* perform outer MD5 */
+   MD5Init(&md5c);                   /* start outer hash */
+   MD5Update(&md5c, k_opad, PAD_LEN); /* hash outer pad */
+   MD5Update(&md5c, hmac, SIG_LEN);   /* hash inner hash */
+   MD5Final(hmac, &md5c);            /* store results */
+}
+/*
+Test Vectors (Trailing '\0' of a character string not included in test):
+
+  key =        0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+  key_len =    16 bytes
+  data =        "Hi There"
+  data_len =   8  bytes
+  digest =     0x9294727a3638bb1c13f48ef8158bfc9d
+
+  key =         "Jefe"
+  data =        "what do ya want for nothing?"
+  data_len =   28 bytes
+  digest =     0x750c783e6ab0b503eaa86e310a5db738
+
+  key =        0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+  key_len      16 bytes
+  data =       0xDDDDDDDDDDDDDDDDDDDD...
+               ..DDDDDDDDDDDDDDDDDDDD...
+               ..DDDDDDDDDDDDDDDDDDDD...
+               ..DDDDDDDDDDDDDDDDDDDD...
+               ..DDDDDDDDDDDDDDDDDDDD
+  data_len =   50 bytes
+  digest =     0x56be34521d144c88dbb8c733f0e8b3f6
+*/
diff --git a/bacula/src/lib/idcache.c b/bacula/src/lib/idcache.c
new file mode 100644 (file)
index 0000000..7493435
--- /dev/null
@@ -0,0 +1,211 @@
+/* idcache.c -- map user and group IDs, cached for speed
+   Copyright (C) 1985, 1988, 1989, 1990 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define NEEDED 1
+#ifdef NEEDED
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef _POSIX_VERSION
+struct passwd *getpwuid ();
+struct passwd *getpwnam ();
+struct group *getgrgid ();
+struct group *getgrnam ();
+#endif
+
+#define xstrdup strdup
+#define xmalloc malloc
+//char *xmalloc ();
+//char *xstrdup ();
+
+struct userid
+{
+  union
+    {
+      uid_t u;
+      gid_t g;
+    } id;
+  char *name;
+  struct userid *next;
+};
+
+static struct userid *user_alist;
+
+
+
+/* The members of this list have names not in the local passwd file.  */
+static struct userid *nouser_alist;
+
+/* Translate UID to a login name or a stringified number,
+   with cache. */
+
+char *getuser (uid_t uid)
+{
+  register struct userid *tail;
+  struct passwd *pwent;
+  char usernum_string[20];
+
+  for (tail = user_alist; tail; tail = tail->next)
+    if (tail->id.u == uid)
+      return tail->name;
+
+  pwent = getpwuid (uid);
+  tail = (struct userid *) xmalloc (sizeof (struct userid));
+  tail->id.u = uid;
+  if (pwent == 0) {
+      sprintf (usernum_string, "%u", (unsigned) uid);
+      tail->name = xstrdup (usernum_string);
+  } else {
+      tail->name = xstrdup (pwent->pw_name);
+  }
+
+  /* Add to the head of the list, so most recently used is first.  */
+  tail->next = user_alist;
+  user_alist = tail;
+  return tail->name;
+}
+
+/* Translate USER to a UID, with cache.
+   Return NULL if there is no such user.
+   (We also cache which user names have no passwd entry,
+   so we don't keep looking them up.)  */
+
+uid_t *
+getuidbyname (char *user)
+{
+  register struct userid *tail;
+  struct passwd *pwent;
+
+  for (tail = user_alist; tail; tail = tail->next)
+    /* Avoid a function call for the most common case. */
+    if (*tail->name == *user && !strcmp (tail->name, user))
+      return &tail->id.u;
+
+  for (tail = nouser_alist; tail; tail = tail->next)
+    /* Avoid a function call for the most common case. */
+    if (*tail->name == *user && !strcmp (tail->name, user))
+      return 0;
+
+  pwent = getpwnam (user);
+
+  tail = (struct userid *) xmalloc (sizeof (struct userid));
+  tail->name = xstrdup (user);
+
+  /* Add to the head of the list, so most recently used is first.  */
+  if (pwent)
+    {
+      tail->id.u = pwent->pw_uid;
+      tail->next = user_alist;
+      user_alist = tail;
+      return &tail->id.u;
+    }
+
+  tail->next = nouser_alist;
+  nouser_alist = tail;
+  return 0;
+}
+
+/* Use the same struct as for userids. */
+static struct userid *group_alist;
+static struct userid *nogroup_alist;
+
+/* Translate GID to a group name or a stringified number,
+   with cache. */
+
+char *
+getgroup (gid_t gid)
+{
+  register struct userid *tail;
+  struct group *grent;
+  char groupnum_string[20];
+
+  for (tail = group_alist; tail; tail = tail->next)
+    if (tail->id.g == gid)
+      return tail->name;
+
+  grent = getgrgid (gid);
+  tail = (struct userid *) xmalloc (sizeof (struct userid));
+  tail->id.g = gid;
+  if (grent == 0)
+    {
+      sprintf (groupnum_string, "%u", (unsigned int) gid);
+      tail->name = xstrdup (groupnum_string);
+    }
+  else
+    tail->name = xstrdup (grent->gr_name);
+
+  /* Add to the head of the list, so most recently used is first.  */
+  tail->next = group_alist;
+  group_alist = tail;
+  return tail->name;
+}
+
+/* Translate GROUP to a UID, with cache.
+   Return NULL if there is no such group.
+   (We also cache which group names have no group entry,
+   so we don't keep looking them up.)  */
+
+gid_t *
+getgidbyname (char *group)
+{
+  register struct userid *tail;
+  struct group *grent;
+
+  for (tail = group_alist; tail; tail = tail->next)
+    /* Avoid a function call for the most common case. */
+    if (*tail->name == *group && !strcmp (tail->name, group))
+      return &tail->id.g;
+
+  for (tail = nogroup_alist; tail; tail = tail->next)
+    /* Avoid a function call for the most common case. */
+    if (*tail->name == *group && !strcmp (tail->name, group))
+      return 0;
+
+  grent = getgrnam (group);
+
+  tail = (struct userid *) xmalloc (sizeof (struct userid));
+  tail->name = xstrdup (group);
+
+  /* Add to the head of the list, so most recently used is first.  */
+  if (grent)
+    {
+      tail->id.g = grent->gr_gid;
+      tail->next = group_alist;
+      group_alist = tail;
+      return &tail->id.g;
+    }
+
+  tail->next = nogroup_alist;
+  nogroup_alist = tail;
+  return 0;
+}
+#endif
diff --git a/bacula/src/lib/jcr.c b/bacula/src/lib/jcr.c
new file mode 100755 (executable)
index 0000000..aeee5c9
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Manipulation routines for Job Control Records
+ *
+ *  Kern E. Sibbald, December 2000
+ *
+ *  These routines are thread safe.
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "jcr.h"
+
+struct s_last_job last_job;          /* last job run by this daemon */
+
+static JCR *jobs = NULL;             /* pointer to JCR chain */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Create a Job Control Record and link it into JCR chain
+ * Returns newly allocated JCR
+ * Note, since each daemon has a different JCR, he passes
+ *  us the size.
+ */
+JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr)
+{
+   JCR *jcr;
+
+   Dmsg0(200, "Enter new_jcr\n");
+   jcr = (JCR *) malloc(size);
+   memset(jcr, 0, size);
+   jcr->my_thread_id = pthread_self();
+   P(mutex);
+   jcr->sched_time = time(NULL);
+   jcr->daemon_free_jcr = daemon_free_jcr;    /* plug daemon free routine */
+   jcr->prev = NULL;
+   jcr->next = jobs;
+   if (jobs) {
+      jobs->prev = jcr;
+   }
+   jcr->use_count = 1;
+   pthread_mutex_init(&(jcr->mutex), NULL);
+   jcr->JobStatus = JS_Created;       /* ready to run */
+   jcr->VolumeName = (char *) get_pool_memory(PM_FNAME);
+   jcr->VolumeName[0] = 0;
+   jcr->errmsg = (char *) get_pool_memory(PM_MESSAGE);
+   jcr->errmsg[0] = 0;
+   init_msg(jcr);                    /* init job message chain */
+   jobs = jcr;
+   V(mutex);
+   return jcr;
+}
+
+
+/*
+ * Remove a JCR from the chain
+ * NOTE! The chain must be locked prior to calling
+ *      this routine.
+ */
+static void remove_jcr(JCR *jcr)
+{
+   Dmsg0(150, "Enter remove_jcr\n");
+   if (!jcr) {
+      Emsg0(M_ABORT, 0, "NULL jcr.\n");
+   }
+   if (!jcr->prev) {                 /* if no prev */
+      jobs = jcr->next;              /* set new head */
+   } else {
+      jcr->prev->next = jcr->next;    /* update prev */
+   }
+   if (jcr->next) {
+      jcr->next->prev = jcr->prev;
+   }
+   Dmsg0(150, "Leave remove_jcr\n");
+}
+
+/*
+ * Free stuff common to all JCRs
+ */
+static void free_common_jcr(JCR *jcr)
+{
+   /* Keep some statistics */
+   switch (jcr->JobType) {
+      case JT_BACKUP:
+      case JT_VERIFY:
+      case JT_RESTORE:
+        last_job.NumJobs++;
+        last_job.JobType = jcr->JobType;
+        last_job.JobId = jcr->JobId;
+        last_job.VolSessionId = jcr->VolSessionId;
+        last_job.VolSessionTime = jcr->VolSessionTime;
+        strcpy(last_job.Job, jcr->Job);
+        last_job.JobFiles = jcr->JobFiles;
+        last_job.JobBytes = jcr->JobBytes;
+        last_job.JobStatus = jcr->JobStatus;
+        last_job.start_time = jcr->start_time;
+        last_job.end_time = time(NULL);
+        break;
+      default:
+        break;
+   }
+   pthread_mutex_destroy(&jcr->mutex);
+   close_msg(jcr);                   /* close messages for this job */
+   /* do this after closing messages */
+   if (jcr->client_name) {
+      free(jcr->client_name);
+      jcr->client_name = NULL;
+   }
+
+   if (jcr->sd_auth_key) {
+      Dmsg0(200, "Free JCR sd_auth_key\n");
+      free(jcr->sd_auth_key);
+      jcr->sd_auth_key = NULL;
+   }
+   if (jcr->VolumeName) {
+      free_pool_memory(jcr->VolumeName);
+      jcr->VolumeName = NULL;
+   }
+   close_msg(jcr);                   /* close messages for this job */
+
+   if (jcr->dir_bsock) {
+      bnet_close(jcr->dir_bsock);
+      jcr->dir_bsock = NULL;
+   }
+   if (jcr->errmsg) {
+      free_pool_memory(jcr->errmsg);
+      jcr->errmsg = NULL;
+   }
+   free(jcr);
+}
+
+/* 
+ * Global routine to free a jcr
+ */
+void free_jcr(JCR *jcr)
+{
+   Dmsg0(200, "Enter free_jcr\n");
+   P(mutex);
+   jcr->use_count--;                 /* decrement use count */
+   Dmsg1(200, "Decrement jcr use_count=%d\n", jcr->use_count);
+   if (jcr->use_count > 0) {         /* if in use */
+      V(mutex);
+      Dmsg1(200, "jcr use_count=%d\n", jcr->use_count);
+      return;
+   }
+   remove_jcr(jcr);
+   V(mutex);
+   jcr->daemon_free_jcr(jcr);        /* call daemon free routine */
+   free_common_jcr(jcr);
+   Dmsg0(200, "Exit free_jcr\n");
+}
+
+
+/* 
+ * Global routine to free a jcr
+ *  JCR chain is already locked
+ */
+void free_locked_jcr(JCR *jcr)
+{
+   jcr->use_count--;                 /* decrement use count */
+   Dmsg1(200, "Decrement jcr use_count=%d\n", jcr->use_count);
+   if (jcr->use_count > 0) {         /* if in use */
+      return;
+   }
+   remove_jcr(jcr);
+   jcr->daemon_free_jcr(jcr);        /* call daemon free routine */
+   free_common_jcr(jcr);
+}
+
+
+
+
+/*
+ * Given a JobId, find the JCR     
+ *   Returns: jcr on success
+ *           NULL on failure
+ */
+JCR *get_jcr_by_id(uint32_t JobId)
+{
+   JCR *jcr;      
+
+   P(mutex);
+   for (jcr = jobs; jcr; jcr=jcr->next) {
+      if (jcr->JobId == JobId) {
+        jcr->use_count++;
+         Dmsg1(200, "Increment jcr use_count=%d\n", jcr->use_count);
+        break;
+      }
+   }
+   V(mutex);
+   return jcr; 
+}
+
+
+
+/*
+ * Given a Job, find the JCR     
+ *  compares on the number of characters in Job
+ *  thus allowing partial matches.
+ *   Returns: jcr on success
+ *           NULL on failure
+ */
+JCR *get_jcr_by_partial_name(char *Job)
+{
+   JCR *jcr;      
+   int len;
+
+   P(mutex);
+   len = strlen(Job);
+   for (jcr = jobs; jcr; jcr=jcr->next) {
+      if (strncmp(Job, jcr->Job, len) == 0) {
+        jcr->use_count++;
+         Dmsg1(200, "Increment jcr use_count=%d\n", jcr->use_count);
+        break;
+      }
+   }
+   V(mutex);
+   return jcr; 
+}
+
+
+/*
+ * Given a Job, find the JCR     
+ *  requires an exact match of names.
+ *   Returns: jcr on success
+ *           NULL on failure
+ */
+JCR *get_jcr_by_full_name(char *Job)
+{
+   JCR *jcr;      
+
+   P(mutex);
+   for (jcr = jobs; jcr; jcr=jcr->next) {
+      if (strcmp(jcr->Job, Job) == 0) {
+        jcr->use_count++;
+         Dmsg1(200, "Increment jcr use_count=%d\n", jcr->use_count);
+        break;
+      }
+   }
+   V(mutex);
+   return jcr; 
+}
+
+/* 
+ * Lock the chain
+ */
+void lock_jcr_chain()
+{
+   P(mutex);
+}
+
+/*
+ * Unlock the chain
+ */
+void unlock_jcr_chain()
+{
+   V(mutex);
+}
+
+
+JCR *get_next_jcr(JCR *jcr)
+{
+   JCR *rjcr;
+
+   if (jcr == NULL) {
+      rjcr = jobs;
+   } else {
+      rjcr = jcr->next;
+   }
+   if (rjcr) {
+      rjcr->use_count++;
+      Dmsg1(200, "Increment jcr use_count=%d\n", rjcr->use_count);
+   }
+   return rjcr;
+}
diff --git a/bacula/src/lib/lex.c b/bacula/src/lib/lex.c
new file mode 100644 (file)
index 0000000..db20bf0
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Lexical scanner for Bacula configuration file
+ *
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "lex.h"
+
+extern int debug_level;
+
+/*
+ * Free the current file, and retrieve the contents
+ * of the previous packet if any.
+ */
+LEX *
+lex_close_file(LEX *lf)
+{
+   LEX *of;
+
+   Dmsg1(20, "Close lex file: %s\n", lf->fname);
+   if (lf == NULL) {
+      Emsg0(M_ABORT, 0, "Close of NULL file\n");
+   }
+   of = lf->next;
+   fclose(lf->fd);
+   Dmsg1(29, "Close cfg file %s\n", lf->fname);
+   free(lf->fname);
+   if (of) {
+      of->options = lf->options;      /* preserve options */
+      memcpy(lf, of, sizeof(LEX));
+      Dmsg1(29, "Restart scan of cfg file %s\n", of->fname);
+   } else {
+      of = lf;
+      lf = NULL;
+   }
+   free(of);
+   return lf;
+}
+
+/*     
+ * Open a new configuration file. We push the
+ * state of the current file (lf) so that we
+ * can do includes.  This is a bit of a hammer.
+ * Instead of passing back the pointer to the
+ * new packet, I simply replace the contents
+ * of the caller's packet with the new packet,
+ * and link the contents of the old packet into
+ * the next field.
+ *
+ */
+LEX *
+lex_open_file(LEX *lf, char *filename) 
+{
+   LEX *nf;
+   FILE *fd;
+   char *fname = bstrdup(filename);
+
+   
+   if ((fd = fopen(fname, "r")) == NULL) {
+      Emsg2(M_ABORT, 0, "Cannot open config file %s: %s\n", fname, strerror(errno));
+   }
+   Dmsg1(29, "Open config file: %s\n", fname);
+   nf = (LEX *)malloc(sizeof(LEX));
+   if (lf) {    
+      memcpy(nf, lf, sizeof(LEX));
+      memset(lf, 0, sizeof(LEX));
+      lf->next = nf;                 /* if have lf, push it behind new one */
+      lf->options = nf->options;      /* preserve user options */
+   } else {
+      lf = nf;                       /* start new packet */
+      memset(lf, 0, sizeof(LEX));
+   }
+   lf->fd = fd;
+   lf->fname = fname;
+   lf->state = lex_none;
+   lf->ch = L_EOL;
+   Dmsg1(29, "Return lex=%x\n", lf);
+   return lf;
+}
+
+/*    
+ * Get the next character from the input.
+ *  Returns the character or
+ *    L_EOF if end of file
+ *    L_EOL if end of line
+ */
+int
+lex_get_char(LEX *lf)
+{
+   if (lf->ch == L_EOF)
+      Emsg0(M_ABORT, 0, "get_char: called after EOF\n");
+   if (lf->ch == L_EOL) {
+      if (fgets(lf->line, MAXSTRING, lf->fd) == NULL) {
+        lf->ch = L_EOF;
+        if (lf->next) {
+           lex_close_file(lf);
+        }
+        return lf->ch;
+      }
+      lf->line_no++;
+      lf->col_no = 0;
+   }
+   lf->ch = lf->line[lf->col_no];
+   if (lf->ch == 0) {
+      lf->ch = L_EOL;
+   } else {
+      lf->col_no++;
+   }
+   Dmsg2(900, "lex_get_char: %c %d\n", lf->ch, lf->ch);
+   return lf->ch;
+}
+
+void
+lex_unget_char(LEX *lf)
+{
+   lf->col_no--;      
+   if (lf->ch == L_EOL)
+      lf->ch = 0;
+}
+
+
+/*
+ * Add a character to the current string
+ */
+static void add_str(LEX *lf, int ch)
+{
+   if (lf->str_len >= MAXSTRING-3) {
+      Emsg2(M_ABORT, 0, "Token too long, file: %s, line %s\n", lf->fname, lf->line_no);
+   }
+   lf->str[lf->str_len++] = ch;
+   lf->str[lf->str_len] = 0;
+}
+
+/*
+ * Begin the string
+ */
+static void begin_str(LEX *lf, int ch) 
+{
+   lf->str_len = 0;
+   lf->str[0] = 0;
+   if (ch != 0)
+      add_str(lf, ch);
+}
+
+#ifdef DEBUG
+static char *
+lex_state_to_str(int state)
+{
+   switch (state) {
+      case lex_none:          return "none";
+      case lex_comment:       return "comment";
+      case lex_number:        return "number";
+      case lex_ip_addr:       return "ip_addr";
+      case lex_identifier:    return "identifier";
+      case lex_string:        return "string";
+      case lex_quoted_string: return "quoted_string";
+      default:                return "??????";
+   }
+}
+#endif
+
+/*
+ * Convert a lex token to a string
+ * used for debug/error printing.
+ */
+char *
+lex_tok_to_str(int token)
+{
+   switch(token) {
+      case L_EOF:           return "L_EOF";
+      case L_EOL:           return "L_EOL";
+      case T_NONE:          return "T_NONE";
+      case T_NUMBER:        return "T_NUMBER";
+      case T_IPADDR:        return "T_IPADDR";
+      case T_IDENTIFIER:    return "T_IDENTIFIER";
+      case T_STRING:        return "T_STRING";
+      case T_QUOTED_STRING: return "T_QUOTED_STRING";
+      case T_BOB:           return "T_BOB";
+      case T_EOB:           return "T_EOB";
+      case T_EQUALS:        return "T_EQUALS";
+      case T_ERROR:         return "T_ERROR";
+      case T_EOF:           return "T_EOF";
+      case T_COMMA:         return "T_COMMA";
+      case T_EOL:           return "T_EOL";
+      default:              return "??????";
+   }
+}
+
+/*       
+ * 
+ * Get the next token from the input
+ *
+ */
+int
+lex_get_token(LEX *lf)
+{
+   int ch;
+   int token = T_NONE;
+   int esc_next = FALSE;
+
+   Dmsg0(290, "enter lex_get_token\n");
+   while (token == T_NONE) {
+      ch = lex_get_char(lf);
+      switch (lf->state) {
+        case lex_none:
+            Dmsg2(290, "Lex state lex_none ch=%d,%x\n", ch, ch);
+           if (ISSPACE(ch))  
+              break;
+           if (ISALPHA(ch)) {
+              if (lf->options & LOPT_NO_IDENT)
+                 lf->state = lex_string;
+              else
+                 lf->state = lex_identifier;
+              begin_str(lf, ch);
+              break;
+           }
+           if (ISDIGIT(ch)) {
+              lf->state = lex_number;
+              begin_str(lf, ch);
+              break;
+           }
+            Dmsg0(290, "Enter lex_none switch\n");
+           switch (ch) {
+              case L_EOF:
+                 token = T_EOF;
+                  Dmsg0(290, "got L_EOF set token=T_EOF\n");
+                 break;
+               case '#':
+                 lf->state = lex_comment;
+                 break;
+               case '{':
+                 token = T_BOB;
+                 begin_str(lf, ch);
+                 break;
+               case '}':
+                 token = T_EOB;
+                 begin_str(lf, ch);
+                 break;
+               case '"':
+                 lf->state = lex_quoted_string;
+                 begin_str(lf, 0);
+                 break;
+               case '=': 
+                 token = T_EQUALS;
+                 begin_str(lf, ch);
+                 break;
+               case ',':
+                 token = T_COMMA;
+                 begin_str(lf, ch);
+                 break;
+               case ';':
+                 token = T_EOL;      /* treat ; like EOL */
+                 break;
+              case L_EOL:
+                  Dmsg0(290, "got L_EOL set token=T_EOL\n");
+                 token = T_EOL;
+                 break;
+               case '@':
+                 lf->state = lex_include;
+                 begin_str(lf, 0);
+                 break;
+              default:
+                 lf->state = lex_string;
+                 begin_str(lf, ch);
+                 break;
+           }
+           break;
+        case lex_comment:
+            Dmsg1(290, "Lex state lex_comment ch=%x\n", ch);
+           if (ch == L_EOL) {
+              lf->state = lex_none;
+              token = T_EOL;
+           }
+           break;
+        case lex_number:
+            Dmsg2(290, "Lex state lex_number ch=%x %c\n", ch, ch);
+           /* Might want to allow trailing specifications here */
+           if (ISDIGIT(ch)) {
+              add_str(lf, ch);
+              break;
+           }
+
+           /* A valid number can be terminated by the following */
+            if (ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
+              token = T_NUMBER;
+              lf->state = lex_none;
+           } else {
+              lf->state = lex_string;
+           }
+           lex_unget_char(lf);
+           break;
+        case lex_ip_addr:
+            Dmsg1(290, "Lex state lex_ip_addr ch=%x\n", ch);
+           break;
+        case lex_string:
+            Dmsg1(290, "Lex state lex_string ch=%x\n", ch);
+            if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
+                ch == ';' || ch == ',' || ch == '#' || (ISSPACE(ch)) ) {
+              lex_unget_char(lf);    
+              token = T_STRING;
+              lf->state = lex_none;
+              break;
+           } 
+           add_str(lf, ch);
+           break;
+        case lex_identifier:
+            Dmsg2(290, "Lex state lex_identifier ch=%x %c\n", ch, ch);
+           if (ISALPHA(ch)) {
+              add_str(lf, ch);
+              break;
+           } else if (ISSPACE(ch)) {
+              break;
+            } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
+                       ch == ';' || ch == ','   || ch == '"' || ch == '#') {
+              lex_unget_char(lf);    
+              token = T_IDENTIFIER;
+              lf->state = lex_none;
+              break;
+           } else if (ch == L_EOF) {
+              token = T_ERROR;
+              lf->state = lex_none;
+              begin_str(lf, ch);
+              break;
+           }
+           /* Some non-alpha character => string */
+           lf->state = lex_string;
+           add_str(lf, ch);
+           break;
+        case lex_quoted_string:
+            Dmsg2(290, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
+           if (ch == L_EOL) {
+              esc_next = FALSE;
+              break;
+           }
+           if (esc_next) {
+              add_str(lf, ch);
+              esc_next = FALSE;
+              break;
+           }
+            if (ch == '\\') {
+              esc_next = TRUE;
+              break;
+           }
+            if (ch == '"') {
+              token = T_QUOTED_STRING;
+              lf->state = lex_none;
+              break;
+           }
+           add_str(lf, ch);
+           break;
+        case lex_include:            /* scanning a filename */
+            if (ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
+                ch == ';' || ch == ','   || ch == '"' || ch == '#') {
+              lf->state = lex_none;
+              lf = lex_open_file(lf, lf->str);
+              break;
+           }
+           add_str(lf, ch);
+           break;
+      }
+      Dmsg4(290, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
+       lex_tok_to_str(token), ch);
+   }
+   Dmsg2(290, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
+   lf->token = token;
+   return token;
+}
diff --git a/bacula/src/lib/lex.h b/bacula/src/lib/lex.h
new file mode 100644 (file)
index 0000000..e295c2d
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *   lex.h  
+ *
+ *    Lexial scanning of configuration files, used by parsers.
+ *
+ *   Kern Sibbald, MM  
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef _LEX_H
+#define _LEX_H
+
+/* Lex get_char() return values */
+#define L_EOF                         (-1)
+#define L_EOL                         (-2)
+
+/* Internal tokens */
+#define T_NONE                        100                              
+
+/* Tokens returned by get_token() */
+#define T_EOF                         101
+#define T_NUMBER                      102
+#define T_IPADDR                      103
+#define T_IDENTIFIER                  104
+#define T_STRING                      105
+#define T_QUOTED_STRING               106
+#define T_BOB                         108  /* begin block */
+#define T_EOB                         109  /* end of block */
+#define T_EQUALS                      110
+#define T_COMMA                       111
+#define T_EOL                         112
+#define T_SEMI                        113
+#define T_ERROR                       200
+
+/* Lexical state */
+enum lex_state {
+   lex_none,
+   lex_comment,
+   lex_number,
+   lex_ip_addr,
+   lex_identifier,
+   lex_string,
+   lex_quoted_string,
+   lex_include
+};
+
+/* Lex scan options */
+#define LOPT_NO_IDENT            0x1  /* No Identifiers -- use string */
+
+/* Lexical context */
+typedef struct s_lex_context {
+   int options;                       /* scan options */
+   char *fname;                       /* filename */
+   FILE *fd;                          /* file descriptor */
+   char line[MAXSTRING];              /* input line */
+   char str[MAXSTRING];               /* string being scanned */
+   int str_len;                       /* length of string */
+   int line_no;                       /* file line number */
+   int col_no;                        /* char position on line */
+   enum lex_state state;              /* lex_state variable */
+   int ch;                            /* last char/L_VAL returned by get_char */
+   int token;
+   struct s_lex_context *next;        /* pointer to next lexical context */
+} LEX;
+
+#endif /* _LEX_H */
diff --git a/bacula/src/lib/lib.h b/bacula/src/lib/lib.h
new file mode 100644 (file)
index 0000000..b3dc512
--- /dev/null
@@ -0,0 +1,43 @@
+/* 
+ * Library includes for Bacula lib directory
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bits.h"
+#include "btime.h"
+#include "smartall.h"
+#include "mem_pool.h"
+#include "message.h"
+#include "lex.h"
+#include "parse_conf.h"
+#include "bsock.h"
+#include "bshm.h"
+#include "workq.h"
+#include "queue.h"
+#include "serial.h"
+#ifndef HAVE_FNMATCH
+#include "fnmatch.h"
+#endif
+#include "md5.h"
+
+#include "protos.h"
+
diff --git a/bacula/src/lib/md5.c b/bacula/src/lib/md5.c
new file mode 100644 (file)
index 0000000..9ea7671
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* Brutally hacked by John Walker back from ANSI C to K&R (no
+   prototypes) to maintain the tradition that Netfone will compile
+   with Sun's original "cc". */
+
+#include "bacula.h"
+
+#ifdef sgi
+#define HIGHFIRST
+#endif
+
+#ifdef sun
+#define HIGHFIRST
+#endif
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len)  /* Nothing */
+#else
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32_t t;
+    do {
+       t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+           ((unsigned) buf[1] << 8 | buf[0]);
+       *(uint32_t *) buf = t;
+       buf += 4;
+    } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len)
+{
+    uint32_t t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+       ctx->bits[1]++;         /* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;       /* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+       unsigned char *p = (unsigned char *) ctx->in + t;
+
+       t = 64 - t;
+       if (len < t) {
+           memcpy(p, buf, len);
+           return;
+       }
+       memcpy(p, buf, t);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+       buf += t;
+       len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+       memcpy(ctx->in, buf, 64);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+       buf += 64;
+       len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+       /* Two lots of padding:  Pad the first block to 64 bytes */
+       memset(p, 0, count);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+       /* Now fill the next block with 56 bytes */
+       memset(ctx->in, 0, 56);
+    } else {
+       /* Pad block to 56 bytes */
+       memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+    ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->buf, 16);
+    memset(ctx, 0, sizeof(ctx));        /* In case it's sensitive */
+}
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32_t buf[4], uint32_t in[16])
+{
+    register uint32_t a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
diff --git a/bacula/src/lib/md5.h b/bacula/src/lib/md5.h
new file mode 100644 (file)
index 0000000..2a39ad1
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Bacula MD5 definitions
+ *
+ *  Kern Sibbald, 2001
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef __BMD5_H
+#define __BMD5_H
+
+struct MD5Context {
+   uint32_t buf[4];
+   uint32_t bits[2];
+   uint8_t  in[64];
+};
+
+typedef struct MD5Context MD5Context;
+
+extern void MD5Init(struct MD5Context *ctx);
+extern void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len);
+extern void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
+extern void MD5Transform(uint32_t buf[4], uint32_t in[16]);
+
+#endif /* !__BMD5_H */
diff --git a/bacula/src/lib/mem_pool.c b/bacula/src/lib/mem_pool.c
new file mode 100644 (file)
index 0000000..251d5dc
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ *  Bacula memory pool routines. 
+ *
+ *  The idea behind these routines is that there will be
+ *  pools of memory that are pre-allocated for quick
+ *  access. The pools will have a fixed memory size on allocation
+ *  but if need be, the size can be increased. This is 
+ *  particularly useful for filename
+ *  buffers where 256 bytes should be sufficient in 99.99%
+ *  of the cases, but when it isn't we want to be able to
+ *  increase the size.
+ *
+ *  A major advantage of the pool memory aside from the speed
+ *  is that the buffer carrys around its size, so to ensure that
+ *  there is enough memory, simply call the check_pool_memory_size()
+ *  with the desired size and it will adjust only if necessary.
+ *
+ *          Kern E. Sibbald
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+
+struct s_pool_ctl {
+   size_t size;                      /* default size */
+   size_t max_size;                  /* max allocated */
+   size_t max_used;                  /* max buffers used */
+   size_t in_use;                    /* number in use */
+   struct abufhead *free_buf;        /* pointer to free buffers */
+};
+
+static struct s_pool_ctl pool_ctl[] = {
+   {  256,  256, 0, 0, NULL },       /* PM_NOPOOL no pooling */
+   {  256,  256, 0, 0, NULL },       /* PM_FNAME filename buffers */
+   {  512,  512, 0, 0, NULL },       /* PM_MESSAGE message buffer */
+   { 1024, 1024, 0, 0, NULL }        /* PM_EMSG error message buffer */
+};
+
+/*  Memory allocation control structures and storage.  */
+struct abufhead {
+   size_t ablen;                     /* Buffer length in bytes */
+   int32_t pool;                     /* pool */
+   struct abufhead *next;            /* pointer to next free buffer */
+};
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+#ifdef SMARTALLOC
+
+#define HEAD_SIZE BALIGN(sizeof(struct abufhead))
+
+extern void *sm_malloc(char *fname, int lineno, int nbytes);
+
+void *sm_get_pool_memory(char *fname, int lineno, int pool)
+{
+   struct abufhead *buf;
+
+   sm_check(fname, lineno, True);
+   if (pool > PM_MAX) {
+      Emsg2(M_ABORT, 0, "MemPool index %d larger than max %d\n", pool, PM_MAX);
+   }
+   P(mutex);
+   if (pool_ctl[pool].free_buf) {
+      buf = pool_ctl[pool].free_buf;
+      pool_ctl[pool].free_buf = buf->next;
+      pool_ctl[pool].in_use++;
+      if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
+        pool_ctl[pool].max_used = pool_ctl[pool].in_use;
+      }
+      V(mutex);
+      Dmsg3(150, "sm_get_pool_memory reuse %x to %s:%d\n", buf, fname, lineno);
+      sm_new_owner(fname, lineno, (char *)buf);
+      return (void *)((char *)buf+HEAD_SIZE);
+   }
+      
+   if ((buf = (struct abufhead *) sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
+      V(mutex);
+      Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
+   }
+   buf->ablen = pool_ctl[pool].size;
+   buf->pool = pool;
+   pool_ctl[pool].in_use++;
+   if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
+      pool_ctl[pool].max_used = pool_ctl[pool].in_use;
+   }
+   V(mutex);
+   Dmsg3(150, "sm_get_pool_memory give %x to %s:%d\n", buf, fname, lineno);
+   return (void *)((char *)buf+HEAD_SIZE);
+}
+
+/* Get nonpool memory of size requested */
+void *sm_get_memory(char *fname, int lineno, size_t size)
+{
+   struct abufhead *buf;
+   int pool = 0;
+
+   sm_check(fname, lineno, True);
+   if ((buf = (struct abufhead *) sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
+      Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
+   }
+   buf->ablen = size;
+   buf->pool = pool;
+   buf->next = NULL;
+   pool_ctl[pool].in_use++;
+   if (pool_ctl[pool].in_use > pool_ctl[pool].max_used)
+      pool_ctl[pool].max_used = pool_ctl[pool].in_use;
+   return (void *)(((char *)buf)+HEAD_SIZE);
+}
+
+#else
+
+void *get_pool_memory(int pool)
+{
+   struct abufhead *buf;
+
+   P(mutex);
+   if (pool_ctl[pool].free_buf) {
+      buf = pool_ctl[pool].free_buf;
+      pool_ctl[pool].free_buf = buf->next;
+      V(mutex);
+      return (void *)((char *)buf+HEAD_SIZE);
+   }
+      
+   if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
+      V(mutex);
+      Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
+   }
+   buf->ablen = pool_ctl[pool].size;
+   buf->pool = pool;
+   buf->next = NULL;
+   pool_ctl[pool].in_use++;
+   if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
+      pool_ctl[pool].max_used = pool_ctl[pool].in_use;
+   }
+   V(mutex);
+   return (void *)(((char *)buf)+HEAD_SIZE);
+}
+
+/* Get nonpool memory of size requested */
+void *get_memory(size_t size)
+{
+   struct abufhead *buf;
+   int pool = 0;
+
+   if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
+      Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
+   }
+   buf->ablen = size;
+   buf->pool = pool;
+   buf->next = NULL;
+   pool_ctl[pool].in_use++;
+   if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
+      pool_ctl[pool].max_used = pool_ctl[pool].in_use;
+   }
+   return (void *)(((char *)buf)+HEAD_SIZE);
+}
+#endif /* SMARTALLOC */
+
+
+
+/* Free a memory buffer */
+void free_pool_memory(void *obuf)
+{
+   struct abufhead *buf;
+   int pool;
+
+   sm_check(__FILE__, __LINE__, False);
+   ASSERT(obuf);
+   P(mutex);
+   buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
+   pool = buf->pool;
+   pool_ctl[pool].in_use--;
+   if (pool == 0) {
+      free((char *)buf);             /* free nonpooled memory */
+   } else {                          /* otherwise link it to the free pool chain */
+      buf->next = pool_ctl[pool].free_buf;
+      pool_ctl[pool].free_buf = buf;
+   }
+   Dmsg2(150, "free_pool_memory %x pool=%d\n", buf, pool);
+   V(mutex);
+}
+
+
+/* Return the size of a memory buffer */
+size_t sizeof_pool_memory(void *obuf)
+{
+   char *cp = (char *)obuf;
+
+   sm_check(__FILE__, __LINE__, False);
+   ASSERT(obuf);
+   cp -= HEAD_SIZE;
+   return ((struct abufhead *)cp)->ablen;
+}
+
+/* Realloc pool memory buffer */
+void *realloc_pool_memory(void *obuf, size_t size)
+{
+   char *cp = (char *)obuf;
+   void *buf;
+   int pool;
+
+   sm_check(__FILE__, __LINE__, False);
+   ASSERT(obuf);
+   P(mutex);
+   cp -= HEAD_SIZE;
+   buf = realloc(cp, size+HEAD_SIZE);
+   if (buf == NULL) {
+      V(mutex);
+      Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
+   }
+   ((struct abufhead *)buf)->ablen = size;
+   pool = ((struct abufhead *)buf)->pool;
+   if (size > pool_ctl[pool].max_size) {
+      pool_ctl[pool].max_size = size;
+   }
+   V(mutex);
+   sm_check(__FILE__, __LINE__, False);
+   return (void *)(((char *)buf)+HEAD_SIZE);
+}
+
+void *check_pool_memory_size(void *obuf, size_t size)
+{
+   sm_check(__FILE__, __LINE__, False);
+   ASSERT(obuf);
+   if (size <= sizeof_pool_memory(obuf)) {
+      return obuf;
+   }
+   return realloc_pool_memory(obuf, size);
+}
+
+/* Release all pooled memory */
+void close_memory_pool()
+{
+   struct abufhead *buf, *next;
+   int i;
+
+   sm_check(__FILE__, __LINE__, False);
+   P(mutex);
+   for (i=1; i<=PM_MAX; i++) {
+      buf = pool_ctl[i].free_buf;
+      while (buf) {
+        next = buf->next;
+        free((char *)buf);
+        buf = next;
+      }
+   }
+   V(mutex);
+}
+
+#ifdef DEBUG
+
+static char *pool_name(int pool)
+{
+   static char *name[] = {"NoPool", "FNAME ", "MSG   ", "EMSG  "};
+   static char buf[30];
+
+   if (pool >= 0 && pool <= PM_MAX) {
+      return name[pool];
+   }
+   sprintf(buf, "%-6d", pool);
+   return buf;
+}
+   
+/* Print staticstics on memory pool usage   
+ */ 
+void print_memory_pool_stats()
+{
+   int i;
+
+   Dmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
+   for (i=0; i<=PM_MAX; i++)
+      Dmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_size,
+        pool_ctl[i].max_used, pool_ctl[i].in_use);
+
+   Dmsg0(-1, "\n");
+}
+
+#else
+void print_memory_pool_stats() {} 
+#endif /* DEBUG */
diff --git a/bacula/src/lib/mem_pool.h b/bacula/src/lib/mem_pool.h
new file mode 100644 (file)
index 0000000..9bccd8b
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Memory Pool prototypes
+ *
+ *  Kern Sibbald, 2000
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifdef SMARTALLOC
+
+#define get_pool_memory(pool) sm_get_pool_memory(__FILE__, __LINE__, pool)
+extern void *sm_get_pool_memory(char *file, int line, int pool);
+#define get_memory(size) sm_get_memory(__FILE__, __LINE__, size)
+extern void *sm_get_memory(char *fname, int line, size_t size);
+
+#else
+
+extern void *get_pool_memory(int pool);
+extern void *get_memory(size_t size);
+
+#endif
+#define free_memory(x) free_pool_memory(x)
+extern void   free_pool_memory(void *buf);
+extern size_t sizeof_pool_memory(void *buf);
+extern void  *realloc_pool_memory(void *buf, size_t size);
+extern void  *check_pool_memory_size(void *buf, size_t size);
+extern void  close_memory_pool();
+extern void  print_memory_pool_stats();
+
+#define PM_NOPOOL  0                  /* nonpooled memory */
+#define PM_FNAME   1                  /* file name buffer */
+#define PM_MESSAGE 2                  /* daemon message */
+#define PM_EMSG    3                  /* error message */
+#define PM_MAX     PM_EMSG            /* Number of types */
diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c
new file mode 100755 (executable)
index 0000000..622f5ed
--- /dev/null
@@ -0,0 +1,947 @@
+/*
+ * Bacula message handling routines
+ *
+ *   Kern Sibbald, April 2000 
+ *
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+#include "jcr.h"
+
+#define FULL_LOCATION 1              /* set for file:line in Debug messages */
+
+char *working_directory = NULL;       /* working directory path stored here */
+int debug_level = 5;                 /* debug level */
+time_t daemon_start_time = 0;        /* Daemon start time */
+
+char my_name[20];                    /* daemon name is stored here */
+char *exepath = (char *)NULL;
+char *exename = (char *)NULL;
+int console_msg_pending = 0;
+char con_fname[1000];
+FILE *con_fd = NULL;
+
+/* Forward referenced functions */
+
+/* Imported functions */
+
+/* This chain contains all the possible destinations */
+DEST *dest_chain = NULL;
+/* 
+ * send_msg has a bit set for each type that has a 
+ * message destination. The info in send_msg[] is 
+ * contained in the dest structures,
+ * but we keep it here for speed so that we don't have to
+ * search all the structures in all the cases. 
+ */
+char send_msg[nbytes_for_bits(M_MAX+1)];
+
+/* 
+ * Set daemon name. Also, find canonical execution
+ *  path.  Note, exepath has spare room for tacking on
+ *  the exename so that we can reconstruct the full name.
+ *
+ * Note, this routine can get called multiple times
+ *  The second time is to put the name as found in the
+ *  Resource record. On the second call, generally,
+ *  argv is NULL to avoid doing the path code twice.
+ */
+#define BTRACE_EXTRA 20
+void my_name_is(int argc, char *argv[], char *name)
+{
+   char *l, *p, *q;
+   char cpath[400], npath[400];
+   int len;
+
+   strncpy(my_name, name, sizeof(my_name));
+   my_name[sizeof(my_name)-1] = 0;
+   if (argc>0 && argv && argv[0]) {
+      /* strip trailing filename and save exepath */
+      for (l=p=argv[0]; *p; p++) {
+         if (*p == '/') {
+           l = p;                       /* set pos of last slash */
+        }
+      }
+      if (*l == '/') {
+        l++;
+      } else {
+        l = argv[0];
+#ifdef HAVE_CYGWIN
+        /* On Windows allow c: junk */
+         if (l[1] == ':') {
+           l += 2;
+        }
+#endif
+      }
+      len = strlen(l) + 1;
+      if (exename) {
+        free(exename);
+      }
+      exename = (char *)malloc(len);
+      strcpy(exename, l);
+      if (exepath) {
+        free(exepath);
+      }
+      exepath = (char *)malloc(strlen(argv[0]) + 1 + len);
+      for (p=argv[0],q=exepath; p < l; ) {
+        *q++ = *p++;
+      }
+      *q = 0;
+      Dmsg1(200, "exepath=%s\n", exepath);
+      if (strchr(exepath, '.') || exepath[0] != '/') {
+        npath[0] = 0;
+        if (getcwd(cpath, sizeof(cpath))) {
+           if (chdir(exepath) == 0) {
+              if (!getcwd(npath, sizeof(npath))) {
+                 npath[0] = 0;
+              }
+              chdir(cpath);
+           }
+           if (npath[0]) {
+              free(exepath);
+              exepath = (char *)malloc(strlen(npath) + 1 + len);
+              strcpy(exepath, npath);
+           }
+        }
+         Dmsg1(200, "Normalized exepath=%s\n", exepath);
+      }
+   }
+}
+
+/* Initialize message handler */
+void
+init_msg(void *vjcr)
+{
+   DEST *d, *dnew, *temp_chain = NULL;
+   JCR *jcr = (JCR *)vjcr;
+
+   if (!jcr) { 
+      memset(send_msg, 0, sizeof(send_msg));  /* init daemon stuff */
+   } else {                                  /* init for job */
+      /* Walk down the global chain duplicating it
+       * for the current Job.  No need to duplicate
+       * the attached strings.
+       */
+      for (d=dest_chain; d; d=d->next) {
+        dnew = (DEST *) malloc(sizeof(DEST));
+        memcpy(dnew, d, sizeof(DEST));
+        dnew->next = temp_chain;
+        dnew->fd = NULL;
+        temp_chain = dnew;
+      }
+
+      jcr->dest_chain = temp_chain;
+      memcpy(jcr->send_msg, send_msg, sizeof(send_msg));
+   }
+}
+
+/* Initialize so that the console (User Agent) can
+ * receive messages -- stored in a file.
+ */
+void init_console_msg(char *wd)
+{
+   int fd;
+
+   sprintf(con_fname, "%s/%s.conmsg", wd, my_name);
+   fd = open(con_fname, O_CREAT|O_RDWR|O_BINARY, 0600);
+   if (fd == -1) {
+       Emsg2(M_ABORT, 0, "Could not open console message file %s: ERR=%s\n",
+         con_fname, strerror(errno));
+   }
+   if (lseek(fd, 0, SEEK_END) > 0) {
+      console_msg_pending = 1;
+   }
+   close(fd);
+   con_fd = fopen(con_fname, "a+");
+   if (!con_fd) {
+       Emsg2(M_ERROR, 0, "Could not open console message file %s: ERR=%s\n",
+         con_fname, strerror(errno));
+   }
+}
+
+/* 
+ * Called only during parsing of the config file.
+ *
+ * Add a message destination. I.e. associate a message type with
+ *  a destination (code).
+ * Note, where in the case of dest_code FILE is a filename,
+ *  but in the case of MAIL is a space separated list of
+ *  email addresses, ...
+ */
+void add_msg_dest(int dest_code, int msg_type, char *where, char *mail_cmd)
+{
+   DEST *d; 
+
+   /* First search the existing chain and see if we
+    * can simply add this msg_type to an existing entry.
+    */
+   for (d=dest_chain; d; d=d->next) {
+      if (dest_code == d->dest_code && ((where == NULL && d->where == NULL) ||
+                    (strcmp(where, d->where) == 0))) {  
+         Dmsg4(200, "Add to existing d=%x msgtype=%d destcode=%d where=%s\n", 
+            d, msg_type, dest_code, where);
+        set_bit(msg_type, d->msg_types);
+        set_bit(msg_type, send_msg);  /* set msg_type bit in our local */
+        return;
+      }
+   }
+   /* Not found, create a new entry */
+   d = (DEST *) malloc(sizeof(DEST));
+   memset(d, 0, sizeof(DEST));
+   d->next = dest_chain;
+   d->dest_code = dest_code;
+   set_bit(msg_type, d->msg_types);     /* set type bit in structure */
+   set_bit(msg_type, send_msg);         /* set type bit in our local */
+   if (where) {
+      d->where = bstrdup(where);
+   }
+   if (mail_cmd) {
+      d->mail_cmd = bstrdup(mail_cmd);
+   }
+   Dmsg5(200, "add new d=%x msgtype=%d destcode=%d where=%s mailcmd=%s\n", 
+          d, msg_type, dest_code, where?where:"(null)", 
+          d->mail_cmd?d->mail_cmd:"(null)");
+   dest_chain = d;
+}
+
+/* 
+ * Called only during parsing of the config file.
+ *
+ * Remove a message destination   
+ */
+void rem_msg_dest(int dest_code, int msg_type, char *where)
+{
+   DEST *d;
+
+   for (d=dest_chain; d; d=d->next) {
+      Dmsg2(200, "Remove_msg_dest d=%x where=%s\n", d, d->where);
+      if (bit_is_set(msg_type, d->msg_types) && (dest_code == d->dest_code) &&
+         ((where == NULL && d->where == NULL) ||
+                    (strcmp(where, d->where) == 0))) {  
+         Dmsg3(200, "Found for remove d=%x msgtype=%d destcode=%d\n", 
+              d, msg_type, dest_code);
+        clear_bit(msg_type, d->msg_types);
+         Dmsg0(200, "Return rem_msg_dest\n");
+        return;
+      }
+   }
+}
+
+/*
+ * Concatenate a string (str) onto a message (msg)
+ *  return new message pointer
+ */
+static void add_str(char **base, char **msg, char *str)
+{
+   int len = strlen(str) + 1;
+   char *b, *m;
+
+   b = *base;
+   *base = (char *) check_pool_memory_size(*base, len);
+   m = *base - b + *msg;
+   while (*str) {
+      *m++ = *str++;
+   }
+   *msg = m;
+}
+
+/*
+ * Convert Job Termination Status into a string
+ */
+static char *job_status_to_str(int stat) 
+{
+   char *str;
+
+   switch (stat) {
+   case JS_Terminated:
+      str = "OK";
+      break;
+   case JS_Errored:
+      str = "Error";
+      break;
+   case JS_Cancelled:
+      str = "Cancelled";
+      break;
+   case JS_Differences:
+      str = "Differences";
+      break;
+   default:
+      str = "Unknown term code";
+      break;
+   }
+   return str;
+}
+
+
+/*
+ * Convert Job Type into a string
+ */
+static char *job_type_to_str(int type) 
+{
+   char *str;
+
+   switch (type) {
+   case JT_BACKUP:
+      str = "Backup";
+      break;
+   case JT_VERIFY:
+      str = "Verify";
+      break;
+   case JT_RESTORE:
+      str = "Restore";
+      break;
+   default:
+      str = "Unknown Job Type";
+      break;
+   }
+   return str;
+}
+
+/*
+ * Convert Job Level into a string
+ */
+static char *job_level_to_str(int level) 
+{
+   char *str;
+
+   switch (level) {
+   case L_FULL:
+      str = "full";
+      break;
+   case L_INCREMENTAL:
+      str = "incremental";
+      break;
+   case L_DIFFERENTIAL:
+      str = "differential";
+      break;
+   case L_LEVEL:
+      str = "level";
+      break;
+   case L_SINCE:
+      str = "since";
+      break;
+   case L_VERIFY_CATALOG:
+      str = "verify catalog";
+      break;
+   case L_VERIFY_INIT:
+      str = "verify init";
+      break;
+   case L_VERIFY_VOLUME:
+      str = "verify volume";
+      break;
+   case L_VERIFY_DATA:
+      str = "verify data";
+      break;
+   default:
+      str = "Unknown Job level";
+      break;
+   }
+   return str;
+}
+
+
+/*
+ * Edit job codes into main command line
+ *  %% = %
+ *  %j = Job name
+ *  %t = Job type (Backup, ...)
+ *  %e = Job Exit code
+ *  %l = job level
+ *  %c = Client's name
+ *  %r = Recipients
+ *  %d = Director's name
+ */
+static char *edit_job_codes(JCR *jcr, char *omsg, char *imsg, char *to)   
+{
+   char *p, *o, *str;
+   char add[3];
+
+   Dmsg1(200, "edit_job_codes: %s\n", imsg);
+   add[2] = 0;
+   o = omsg;
+   for (p=imsg; *p; p++) {
+      if (*p == '%') {
+        switch (*++p) {
+         case '%':
+            add[0] = '%';
+           add[1] = 0;
+           str = add;
+           break;
+         case 'j':                    /* Job name */
+           str = jcr->Job;
+           break;
+         case 'e':
+           str = job_status_to_str(jcr->JobStatus); 
+           break;
+         case 't':
+           str = job_type_to_str(jcr->JobType);
+           break;
+         case 'r':
+           str = to;
+           break;
+         case 'l':
+           str = job_level_to_str(jcr->level);
+           break;
+         case 'c':
+           str = jcr->client_name;
+           if (!str) {
+               str = "";
+           }
+           break;
+         case 'd':
+            str = my_name;            /* Director's name */
+           break;
+        default:
+            add[0] = '%';
+           add[1] = *p;
+           str = add;
+           break;
+        }
+      } else {
+        add[0] = *p;
+        add[1] = 0;
+        str = add;
+      }
+      Dmsg1(200, "add_str %s\n", str);
+      add_str(&omsg, &o, str);
+      *o = 0;
+      Dmsg1(200, "omsg=%s\n", omsg);
+   }
+   *o = 0;
+   return omsg;
+}
+
+/*
+ * Create a unique filename for the mail command
+ */
+static void make_unique_mail_filename(JCR *jcr, char **name, DEST *d)
+{
+   if (jcr) {
+      Mmsg(name, "%s/%s.mail.%s.%d", working_directory, my_name,
+                jcr->Job, (int)d);
+   } else {
+      Mmsg(name, "%s/%s.mail.%s.%d", working_directory, my_name,
+                my_name, (int)d);
+   }
+   Dmsg1(200, "mailname=%s\n", *name);
+}
+
+/*
+ * Open a mail pipe
+ */
+static FILE *open_mail_pipe(JCR *jcr, char **cmd, DEST *d)
+{
+   FILE *pfd;
+
+   if (d->mail_cmd && jcr) {
+      *cmd = edit_job_codes(jcr, *cmd, d->mail_cmd, d->where);
+   } else {
+      Mmsg(cmd, "mail -s \"Bacula Message\" %s", d->where);
+   }
+   Dmsg1(200, "mailcmd=%s\n", cmd);
+   pfd = popen(*cmd, "w");
+   if (!pfd) {
+      Emsg2(M_ERROR, 0, "popen %s failed: ERR=%s\n", cmd, strerror(errno));
+      if (jcr) {
+         Jmsg(jcr, M_ERROR, 0, "mail popen %s failed: ERR=%s\n", cmd, strerror(errno));
+      }
+   } 
+   return pfd;
+}
+
+/* 
+ * Close the messages for this job, which means to close
+ *  any open files, and dispatch any pending email messages.
+ *     
+ * This closes messages only for this job, other jobs can   
+ *   still send messages.
+ * 
+ * Note, we free our local message destination chain, but
+ * the global chain remains allowing other jobs to
+ * start.
+ */
+void close_msg(void *vjcr)
+{
+   DEST *d, *old;
+   FILE *pfd;
+   char *cmd, *line;
+   int len;
+   JCR *jcr = (JCR *)vjcr;
+   
+   Dmsg0(200, "Close_msg\n");
+   cmd = (char *)get_pool_memory(PM_MESSAGE);
+   for (d=jcr->dest_chain; d; ) {
+      if (d->fd) {
+        switch (d->dest_code) {
+        case MD_FILE:
+        case MD_APPEND:
+           if (d->fd) {
+              fclose(d->fd);            /* close open file descriptor */
+           }
+           break;
+        case MD_MAIL:
+        case MD_MAIL_ON_ERROR:
+           if (!d->fd) {
+              break;
+           }
+           if (d->dest_code == MD_MAIL_ON_ERROR && 
+               jcr->JobStatus == JS_Terminated) {
+              goto rem_temp_file;
+           }
+           
+           pfd = open_mail_pipe(jcr, &cmd, d);
+           if (!pfd) {
+              goto rem_temp_file;
+           }
+           len = d->max_len+10;
+           line = (char *)get_memory(len);
+           rewind(d->fd);
+           while (fgets(line, len, d->fd)) {
+              fputs(line, pfd);
+           }
+           pclose(pfd);            /* close pipe, sending mail */
+           free_memory(line);
+rem_temp_file:
+           /* Remove temp file */
+           fclose(d->fd);
+           make_unique_mail_filename(jcr, &cmd, d);
+            Dmsg1(200, "unlink: %s\n", cmd);
+           unlink(cmd);
+           break;
+        default:
+           break;
+        }
+        d->fd = 0;
+      }
+      old = d;                       /* save pointer to release */
+      d = d->next;                   /* point to next buffer */
+      free(old);                     /* free the destination item */
+   }
+   free_pool_memory(cmd);
+   jcr->dest_chain = NULL;
+}
+
+
+/* 
+ * Terminate the message handler for good. 
+ * Release the global destination chain.
+ */
+void term_msg()
+{
+   DEST *d, *n;
+   
+   for (d=dest_chain; d; d=n) {
+      if (d->fd) {
+        if (d->dest_code == MD_FILE || d->dest_code == MD_APPEND) {
+           fclose(d->fd);            /* close open file descriptor */
+        } else if (d->dest_code == MD_MAIL || d->dest_code == MD_MAIL_ON_ERROR) {
+           pclose(d->fd);            /* close open pipe */
+        }
+      }
+      n = d->next;
+      if (d->where)
+        free(d->where);              /* free destination address */
+      if (d->mail_cmd)
+        free(d->mail_cmd);
+      free(d);
+   }
+   if (con_fd) {
+      fflush(con_fd);
+      fclose(con_fd);
+      con_fd = NULL;
+   }
+   if (exepath) {
+      free(exepath);
+      exepath = NULL;
+   }
+   if (exename) {
+      free(exename);
+      exename = NULL;
+   }
+}
+
+
+
+/*
+ * Handle sending the message to the appropriate place
+ */
+void dispatch_message(void *vjcr, int type, int level, char *buf)
+{
+    DEST *d;   
+    char cmd[MAXSTRING], *mcmd;
+    JCR *jcr = (JCR *) vjcr;
+    int len;
+
+    Dmsg2(200, "Enter dispatch_msg type=%d msg=%s\n", type, buf);
+
+    if (type == M_ABORT) {
+       fprintf(stdout, buf);         /* print this here to INSURE that it is printed */
+    }
+
+    /* Now figure out where to send the message */
+    if (jcr) {
+       d = jcr->dest_chain;          /* use job message chain */
+    } else {
+       d = dest_chain;               /* use global chain */
+    }
+    for ( ; d; d=d->next) {
+       if (bit_is_set(type, d->msg_types)) {
+         switch (d->dest_code) {
+            case MD_CONSOLE:
+                Dmsg1(200, "CONSOLE for following err: %s\n", buf);
+               if (!con_fd) {
+                   con_fd = fopen(con_fname, "a+");
+                   Dmsg0(200, "Console file not open.\n");
+               }
+               if (con_fd) {
+                  fcntl(fileno(con_fd), F_SETLKW);
+                  errno = 0;
+                  bstrftime(cmd, sizeof(cmd), time(NULL));
+                  len = strlen(cmd);
+                   cmd[len++] = ' ';
+                  fwrite(cmd, len, 1, con_fd);
+                  len = strlen(buf);
+                   if (len > 0 && buf[len-1] != '\n') {
+                      buf[len++] = '\n';
+                     buf[len] = 0;
+                  }
+                  fwrite(buf, len, 1, con_fd);
+                  fflush(con_fd);
+                  fcntl(fileno(con_fd), F_UNLCK);
+                  console_msg_pending = TRUE;
+               }
+               break;
+            case MD_SYSLOG:
+                Dmsg1(200, "SYSLOG for following err: %s\n", buf);
+               /* We really should do an openlog() here */
+               syslog(LOG_DAEMON|LOG_ERR, buf);
+               break;
+            case MD_OPERATOR:
+                Dmsg1(200, "OPERATOR for following err: %s\n", buf);
+               mcmd = (char *) get_pool_memory(PM_MESSAGE);
+               d->fd = open_mail_pipe(jcr, &mcmd, d);
+               free_pool_memory(mcmd);
+               if (d->fd) {
+                  fputs(buf, d->fd);
+                  /* Messages to the operator go one at a time */
+                  pclose(d->fd);
+               }
+               break;
+            case MD_MAIL:
+            case MD_MAIL_ON_ERROR:
+                Dmsg1(200, "MAIL for following err: %s\n", buf);
+               if (!d->fd) {
+                  char *name  = (char *) get_pool_memory(PM_MESSAGE);
+                  make_unique_mail_filename(jcr, &name, d);
+                   d->fd = fopen(name, "w+");
+                   Dmsg2(100, "Open mail file %d: %s\n", d->fd, name);
+                  if (!d->fd) {
+                      Emsg2(M_ERROR, 0, "fopen %s failed: ERR=%s\n", name, strerror(errno));
+                     free_pool_memory(name);
+                     break;
+                  }
+                  free_pool_memory(name);
+               }
+               len = strlen(buf);
+               if (len > d->max_len) {
+                  d->max_len = len;      /* keep max line length */
+               }
+               fputs(buf, d->fd);
+               break;
+            case MD_FILE:
+                Dmsg1(200, "FILE for following err: %s\n", buf);
+               if (!d->fd) {
+                   d->fd = fopen(d->where, "w+");
+                  if (!d->fd) {
+                      Emsg2(M_ERROR, 0, "fopen %s failed: ERR=%s\n", d->where, strerror(errno));
+                     break;
+                  }
+               }
+               fputs(buf, d->fd);
+               break;
+            case MD_APPEND:
+                Dmsg1(200, "APPEND for following err: %s\n", buf);
+               if (!d->fd) {
+                   d->fd = fopen(d->where, "a");
+                  if (!d->fd) {
+                      Emsg2(M_ERROR, 0, "fopen %s failed: ERR=%s\n", d->where, strerror(errno));
+                     break;
+                  }
+               }
+               fputs(buf, d->fd);
+               break;
+            case MD_DIRECTOR:
+                Dmsg1(200, "DIRECTOR for following err: %s\n", buf);
+               if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) {
+
+                  jcr->dir_bsock->msglen = Mmsg(&(jcr->dir_bsock->msg),
+                        "Jmsg Job=%s type=%d level=%d %s", jcr->Job,
+                        type, level, buf) + 1;
+                  bnet_send(jcr->dir_bsock);
+               }
+               break;
+            case MD_STDOUT:
+                Dmsg1(200, "STDOUT for following err: %s\n", buf);
+               if (type != M_ABORT && type != M_FATAL)  /* already printed */
+                  fprintf(stdout, buf);
+               break;
+            case MD_STDERR:
+                Dmsg1(200, "STDERR for following err: %s\n", buf);
+               fprintf(stderr, buf);
+               break;
+            default:
+               break;
+         }
+       }
+    }
+}
+
+
+/*********************************************************************
+ *
+ *  subroutine prints a debug message if the level number
+ *  is less than or equal the debug_level. File and line numbers
+ *  are included for more detail if desired, but not currently
+ *  printed.
+ *  
+ *  If the level is negative, the details of file and line number
+ *  are not printed.
+ */
+void 
+d_msg(char *file, int line, int level, char *fmt,...)
+{
+    char      buf[MAXSTRING];
+    int       i;
+    va_list   arg_ptr;
+    int       details = TRUE;
+
+    if (level < 0) {
+       details = FALSE;
+       level = -level;
+    }
+
+/*  printf("level=%d debug=%d fmt=%s\n", level, debug_level, fmt); */
+
+    if (level <= debug_level) {
+#ifdef FULL_LOCATION
+       if (details) {
+          sprintf(buf, "%s: %s:%d ", my_name, file, line);
+         i = strlen(buf);
+       } else {
+         i = 0;
+       }
+#else
+       i = 0;
+#endif
+       va_start(arg_ptr, fmt);
+       bvsnprintf(buf+i, sizeof(buf)-i, (char *)fmt, arg_ptr);
+       va_end(arg_ptr);
+
+       fprintf(stdout, buf);
+    }
+}
+
+
+/* *********************************************************
+ *
+ * print an error message
+ *
+ */
+void 
+e_msg(char *file, int line, int type, int level, char *fmt,...)
+{
+    char     buf[1000];
+    va_list   arg_ptr;
+    int i;
+
+    /* 
+     * Check if we have a message destination defined. 
+     * We always report M_ABORT 
+     */
+    if (type != M_ABORT && !bit_is_set(type, send_msg))
+       return;                       /* no destination */
+    switch (type) {
+       case M_ABORT:
+          sprintf(buf, "%s ABORTING due to ERROR in %s:%d\n", 
+                 my_name, file, line);
+         break;
+       case M_FATAL:
+         if (level == -1)            /* skip details */
+             sprintf(buf, "%s: Fatal Error because: ", my_name);
+         else
+             sprintf(buf, "%s: Fatal Error at %s:%d because:\n", my_name, file, line);
+         break;
+       case M_ERROR:
+         if (level == -1)            /* skip details */
+             sprintf(buf, "%s: Error: ", my_name);
+         else
+             sprintf(buf, "%s: Error in %s:%d ", my_name, file, line);
+         break;
+       case M_WARNING:
+          sprintf(buf, "%s: Warning: ", my_name);
+         break;
+       default:
+          sprintf(buf, "%s: ", my_name);
+         break;
+    }
+
+    i = strlen(buf);
+    va_start(arg_ptr, fmt);
+    bvsnprintf(buf+i, sizeof(buf)-i, (char *)fmt, arg_ptr);
+    va_end(arg_ptr);
+
+    dispatch_message(NULL, type, level, buf);
+
+    if (type == M_ABORT) {
+       abort();
+    }
+}
+
+/* *********************************************************
+ *
+ * Generate a Job message
+ *
+ */
+void 
+Jmsg(void *vjcr, int type, int level, char *fmt,...)
+{
+    char     rbuf[2000];
+    char     *buf;
+    va_list   arg_ptr;
+    int i, len;
+    JCR *jcr = (JCR *) vjcr;
+    int typesave = type;
+
+    
+    Dmsg1(200, "Enter Jmsg type=%d\n", type);
+
+    buf = rbuf;                   /* we are the Director */
+    /* 
+     * Check if we have a message destination defined. 
+     * We always report M_ABORT 
+     */
+    if (type != M_ABORT && !bit_is_set(type, jcr->send_msg)) {
+       Dmsg1(200, "No bit set for type %d\n", type);
+       return;                       /* no destination */
+    }
+    switch (type) {
+       case M_ABORT:
+          sprintf(buf, "%s ABORTING due to ERROR\n", my_name);
+         break;
+       case M_FATAL:
+          sprintf(buf, "%s: Job %s Cancelled because: ", my_name, jcr->Job);
+         break;
+       case M_ERROR:
+          sprintf(buf, "%s: Job %s Error: ", my_name, jcr->Job);
+         break;
+       case M_WARNING:
+          sprintf(buf, "%s: Job %s Warning: ", my_name, jcr->Job);
+         break;
+       default:
+          sprintf(buf, "%s: ", my_name);
+         break;
+    }
+
+    i = strlen(buf);
+    va_start(arg_ptr, fmt);
+    len = bvsnprintf(buf+i, sizeof(rbuf)-i, fmt, arg_ptr);
+    va_end(arg_ptr);
+
+    ASSERT(typesave==type);          /* type trashed, compiler bug???? */
+    dispatch_message(jcr, type, level, rbuf);
+
+    Dmsg3(500, "i=%d sizeof(rbuf)-i=%d len=%d\n", i, sizeof(rbuf)-i, len);
+
+    if (type == M_ABORT)
+       abort();
+}
+
+/*
+ * Edit a message into a Pool memory buffer, with file:lineno
+ */
+int m_msg(char *file, int line, char **pool_buf, char *fmt, ...)
+{
+   va_list   arg_ptr;
+   int i, len, maxlen;
+
+   sprintf(*pool_buf, "%s:%d ", file, line);
+   i = strlen(*pool_buf);
+
+again:
+   maxlen = sizeof_pool_memory(*pool_buf) - i - 1; 
+   va_start(arg_ptr, fmt);
+   len = bvsnprintf(*pool_buf+i, maxlen, fmt, arg_ptr);
+   va_end(arg_ptr);
+   if (len < 0 || len >= maxlen) {
+      *pool_buf = (char *) realloc_pool_memory(*pool_buf, maxlen + i + 200);
+      goto again;
+   }
+   return len;
+}
+
+/*
+ * Edit a message into a Pool Memory buffer NO file:lineno
+ *  Returns: string length of what was edited.
+ */
+int Mmsg(char **pool_buf, char *fmt, ...)
+{
+   va_list   arg_ptr;
+   int len, maxlen;
+
+again:
+   maxlen = sizeof_pool_memory(*pool_buf) - 1; 
+   va_start(arg_ptr, fmt);
+   len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr);
+   va_end(arg_ptr);
+   if (len < 0 || len >= maxlen) {
+      *pool_buf = (char *) realloc_pool_memory(*pool_buf, maxlen + 200);
+      goto again;
+   }
+   return len;
+}
+
+
+void j_msg(char *file, int line, void *jcr, int type, int level, char *fmt,...)
+{
+   va_list   arg_ptr;
+   int i, len, maxlen;
+   char *pool_buf;
+
+   pool_buf = (char *) get_pool_memory(PM_EMSG);
+   sprintf(pool_buf, "%s:%d ", file, line);
+   i = strlen(pool_buf);
+
+again:
+   maxlen = sizeof_pool_memory(pool_buf) - i - 1; 
+   va_start(arg_ptr, fmt);
+   len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr);
+   va_end(arg_ptr);
+   if (len < 0 || len >= maxlen) {
+      pool_buf = (char *) realloc_pool_memory(pool_buf, maxlen + i + 200);
+      goto again;
+   }
+
+   Jmsg(jcr, type, level, pool_buf);
+   free_memory(pool_buf);
+}
diff --git a/bacula/src/lib/message.h b/bacula/src/lib/message.h
new file mode 100644 (file)
index 0000000..99e5ed5
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Define Message Types for Bacula
+ *    Kern Sibbald, 2000
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bits.h"
+
+#undef  M_DEBUG
+#undef  M_ABORT
+#undef  M_FATAL
+#undef  M_ERROR
+#undef  M_WARNING
+#undef  M_INFO
+#undef  M_MOUNT
+#undef  M_TERM
+
+#define M_DEBUG     1                 /* debug message */
+#define M_ABORT     2                 /* MUST abort immediately */
+#define M_FATAL     3                 /* Fatal error, stopping job */
+#define M_ERROR     4                 /* Error, but recoverable */
+#define M_WARNING   5                 /* Warning message */
+#define M_INFO      6                 /* Informational message */
+#define M_SAVED     7                 /* Info on saved file */
+#define M_NOTSAVED  8                 /* Info on notsaved file */
+#define M_SKIPPED   9                 /* File skipped by option setting */
+#define M_MOUNT    10                 /* Mount requests */
+#define M_TERM     11                 /* Termination request */
+
+#define M_MAX      M_TERM             /* keep this updated ! */
+
+/* Define message destination structure */
+/* *** FIXME **** where should be extended to handle multiple values */
+typedef struct s_dest {
+   struct s_dest *next;
+   int dest_code;                     /* destination (one of the MD_ codes) */
+   int max_len;                       /* max mail line length */
+   FILE *fd;                          /* file descriptor */
+   char msg_types[nbytes_for_bits(M_MAX+1)]; /* message type mask */
+   char *where;                       /* filename/program name */
+   char *mail_cmd;                    /* mail command */
+} DEST;
+
+/* Message Destination values for dest field of DEST */
+#define MD_SYSLOG    1                /* send msg to syslog */
+#define MD_MAIL      2                /* email group of messages */
+#define MD_FILE      3                /* write messages to a file */
+#define MD_APPEND    4                /* append messages to a file */
+#define MD_STDOUT    5                /* print messages */
+#define MD_STDERR    6                /* print messages to stderr */
+#define MD_DIRECTOR  7                /* send message to the Director */
+#define MD_OPERATOR  8                /* email a single message to the operator */
+#define MD_CONSOLE   9                /* send msg to UserAgent or console */
+#define MD_MAIL_ON_ERROR 10           /* email messages if job errors */
+
+
+void d_msg(char *file, int line, int level, char *fmt,...);
+void e_msg(char *file, int line, int type, int level, char *fmt,...);
+void Jmsg(void *vjcr, int type, int level, char *fmt,...);
+
+extern int debug_level;
+extern char my_name[];
+extern char *working_directory;
+extern time_t daemon_start_time;
diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c
new file mode 100755 (executable)
index 0000000..5017929
--- /dev/null
@@ -0,0 +1,865 @@
+/*
+ *   Master Configuration routines.
+ *  
+ *   This file contains the common parts of the Bacula
+ *   configuration routines.
+ *
+ *   Note, the configuration file parser consists of three parts
+ *
+ *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
+ *
+ *   2. The generic config  scanner in lib/parse_conf.c and 
+ *     lib/parse_conf.h.
+ *     These files contain the parser code, some utility
+ *     routines, and the common store routines (name, int,
+ *     string).
+ *
+ *   3. The daemon specific file, which contains the Resource
+ *     definitions as well as any specific store routines
+ *     for the resource records.
+ *
+ *     Kern Sibbald, January MM
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+
+extern int debug_level;
+
+/* Each daemon has a slightly different set of 
+ * resources, so it will define the following
+ * global values.
+ */
+extern int r_first;
+extern int r_last;
+extern pthread_mutex_t res_mutex;
+extern struct s_res resources[];
+extern CURES res_all;
+extern int res_all_size;
+
+static int res_locked = 0;            /* set when resource chains locked */
+
+/* Forward referenced subroutines */
+static void scan_types(LEX *lc, int dest, char *where, char *cmd);
+
+
+/* Common Resource definitions */
+
+/* Message resource directives
+ *  name        handler    store_addr  code   flags  default_value
+ */
+struct res_items msgs_items[] = {
+   {"name",        store_name,    ITEM(res_msgs.hdr.name),  0, 0, 0},
+   {"description", store_str,     ITEM(res_msgs.hdr.desc),  0, 0, 0},
+   {"mailcommand", store_str,     ITEM(res_msgs.mail_cmd),  0, 0, 0},
+   {"operatorcommand", store_str, ITEM(res_msgs.operator_cmd), 0, 0, 0},
+   {"syslog",      store_msgs, NULL,           MD_SYSLOG,   0, 0}, 
+   {"mail",        store_msgs, NULL,           MD_MAIL,     0, 0},
+   {"mailonerror", store_msgs, NULL,           MD_MAIL_ON_ERROR, 0, 0},
+   {"file",        store_msgs, NULL,           MD_FILE,     0, 0},
+   {"append",      store_msgs, NULL,           MD_APPEND,   0, 0},
+   {"stdout",      store_msgs, NULL,           MD_STDOUT,   0, 0},
+   {"stderr",      store_msgs, NULL,           MD_STDERR,   0, 0},
+   {"director",    store_msgs, NULL,           MD_DIRECTOR, 0, 0},
+   {"console",     store_msgs, NULL,           MD_CONSOLE,  0, 0},   
+   {"operator",    store_msgs, NULL,           MD_OPERATOR, 0, 0},
+   {NULL, NULL,    NULL, 0}
+};
+
+struct s_mtypes {      
+   char *name;
+   int token;  
+};
+/* Various message types */
+static struct s_mtypes msg_types[] = {
+   {"debug",         M_DEBUG},
+   {"abort",         M_ABORT},
+   {"fatal",         M_FATAL},
+   {"error",         M_ERROR},
+   {"warning",       M_WARNING},
+   {"info",          M_INFO},
+   {"saved",         M_SAVED},
+   {"notsaved",      M_NOTSAVED},
+   {"skipped",       M_SKIPPED},
+   {"mount",         M_MOUNT},
+   {"terminate",     M_TERM},
+   {"all",           M_MAX+1},
+   {NULL,           0}
+};
+
+
+/* Simply print a message */
+static void prtmsg(void *sock, char *fmt, ...)
+{
+   va_list arg_ptr;
+
+   va_start(arg_ptr, fmt);
+   vfprintf(stdout, fmt, arg_ptr);
+   va_end(arg_ptr);
+}
+
+#ifdef DEBUG
+char *res_to_str(int rcode)
+{
+   if (rcode < r_first || rcode > r_last) {
+      return "***UNKNOWN***";
+   } else {
+      return resources[rcode-r_first].name;
+   }
+}
+#endif /* DEBUG */
+
+
+/* 
+ * Initialize the static structure to zeros, then
+ *  apply all the default values.
+ */
+void init_resource(int type, struct res_items *items)
+{
+   int i;
+   int rindex = type - r_first;
+
+   memset(&res_all, 0, res_all_size);
+   res_all.hdr.rcode = type;
+   res_all.hdr.refcnt = 1;
+
+   for (i=0; items[i].name; i++) {
+      Dmsg3(300, "Item=%s def=%s defval=%d\n", items[i].name,
+            (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",      
+           items[i].default_value);
+      if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
+        if (items[i].handler == store_yesno) {
+           *(int *)(items[i].value) |= items[i].code;
+        } else if (items[i].handler == store_pint || 
+                   items[i].handler == store_int  ||
+                   items[i].handler == store_time) {
+           *(int *)(items[i].value) = items[i].default_value;
+        } else if (items[i].handler == store_int64) {
+           *(int64_t *)(items[i].value) = items[i].default_value;
+        } else if (items[i].handler == store_size) {
+           *(uint64_t *)(items[i].value) = items[i].default_value;
+        }
+      }
+      /* If this triggers, take a look at lib/parse_conf.h */
+      if (i >= MAX_RES_ITEMS) {
+         Emsg1(M_ABORT, 0, _("Too many items in %s resource\n"), resources[rindex]);
+      }
+   }
+}
+
+
+/* Store Messages Destination information */
+void store_msgs(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+   char *dest, *cmd;
+   int dest_len;
+
+   Dmsg2(200, "store_msgs pass=%d code=%d\n", pass, item->code);
+   if (pass == 1) {
+      switch (item->code) {
+        case MD_STDOUT:
+        case MD_STDERR:
+        case MD_SYSLOG:              /* syslog */
+        case MD_CONSOLE:
+           scan_types(lc, item->code, NULL, NULL);
+           break;
+        case MD_OPERATOR:            /* send to operator */
+        case MD_DIRECTOR:            /* send to Director */
+        case MD_MAIL:                /* mail */
+        case MD_MAIL_ON_ERROR:       /* mail if Job errors */
+           if (item->code == MD_OPERATOR) {
+              cmd = res_all.res_msgs.operator_cmd;
+           } else {
+              cmd = res_all.res_msgs.mail_cmd;
+           }
+           dest = (char *) get_pool_memory(PM_MESSAGE);
+           dest_len = 0;
+           dest[0] = 0;
+           /* Pick up comma separated list of destinations */
+           for ( ;; ) {
+              token = lex_get_token(lc);    /* scan destination */
+              if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+                  scan_err1(lc, "expected a message destination, got: %s", lc->str);
+              }
+              dest = (char *) check_pool_memory_size(dest, dest_len + lc->str_len + 2);
+              if (dest[0] != 0) {
+                  strcat(dest, " ");  /* separate multiple destinations with space */
+                 dest_len++;
+              }
+              strcat(dest, lc->str);
+              dest_len += lc->str_len;
+               Dmsg2(100, "store_msgs newdest=%s: dest=%s:\n", lc->str, dest);
+              token = lex_get_token(lc);
+              if (token == T_COMMA) { 
+                 continue;           /* get another destination */
+              }
+              if (token != T_EQUALS) {
+                  scan_err1(lc, "expected an =, got: %s", lc->str); 
+              }
+              break;
+           }
+            Dmsg1(200, "mail_cmd=%s\n", cmd);
+           scan_types(lc, item->code, dest, cmd);
+           free_pool_memory(dest);
+            Dmsg0(200, "done with dest codes\n");
+           break;
+        case MD_FILE:                /* file */
+        case MD_APPEND:              /* append */
+           dest = (char *) get_pool_memory(PM_MESSAGE);
+           /* Pick up a single destination */
+           token = lex_get_token(lc);    /* scan destination */
+           if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+               scan_err1(lc, "expected a message destination, got: %s", lc->str);
+           }
+           dest = (char *) check_pool_memory_size(dest, dest_len + lc->str_len + 2);
+           strcpy(dest, lc->str);
+           dest_len = lc->str_len;
+           token = lex_get_token(lc);
+            Dmsg1(200, "store_msgs dest=%s:\n", dest);
+           if (token != T_EQUALS) {
+               scan_err1(lc, "expected an =, got: %s", lc->str); 
+           }
+           scan_types(lc, item->code, dest, NULL);
+           free_pool_memory(dest);
+            Dmsg0(200, "done with dest codes\n");
+           break;
+
+        default:
+            scan_err1(lc, "Unknown item code: %d\n", item->code);
+           break;
+      }
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+   Dmsg0(200, "Done store_msgs\n");
+}
+
+/* 
+ * Scan for message types and add them to the message
+ * destination. The basic job here is to connect message types
+ *  (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
+ *  destination (MAIL, FILE, OPERATOR, ...)
+ */
+static void scan_types(LEX *lc, int dest_code, char *where, char *cmd)
+{
+   int token, i, found, quit, is_not;
+   int msg_type;
+   char *str;
+
+   for (quit=0; !quit;) {
+      token = lex_get_token(lc);            /* expect at least one type */       
+      if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+         scan_err1(lc, "expected a message type, got: %s", lc->str);
+      }
+      found = FALSE;
+      if (lc->str[0] == '!') {
+        is_not = TRUE;
+        str = &lc->str[1];
+      } else {
+        is_not = FALSE;
+        str = &lc->str[0];
+      }
+      for (i=0; msg_types[i].name; i++) {
+        if (strcmp(str, msg_types[i].name) == 0) {
+           msg_type = msg_types[i].token;
+           found = TRUE;
+           break;
+        }
+      }
+      if (!found) {
+         scan_err1(lc, "message type: %s not found", str);
+      }
+
+      if (msg_type == M_MAX+1) {        /* all? */
+        for (i=1; i<=M_MAX; i++) {      /* yes set all types */
+           add_msg_dest(dest_code, i, where, cmd);
+        }
+      } else {
+        if (is_not) {
+           rem_msg_dest(dest_code, msg_type, where);
+        } else {
+           add_msg_dest(dest_code, msg_type, where, cmd);
+        }
+      }
+      if (lc->ch != ',') {
+        break;
+      }
+      Dmsg0(200, "call lex_get_token() to eat comma\n");
+      token = lex_get_token(lc);         /* eat comma */
+   }
+   Dmsg0(200, "Done scan_types()\n");
+}
+
+
+/* 
+ * This routine is ONLY for resource names
+ *  Store a name at specified address.
+ */
+void store_name(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc);
+   if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+      scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
+   } else if (lc->str_len > MAX_RES_NAME_LENGTH) {
+      scan_err3(lc, "name %s length %d too long, max is %d\n", lc->str, 
+        lc->str_len, MAX_RES_NAME_LENGTH);
+   } else {
+      /* Store the name both pass 1 and pass 2 */
+      *(item->value) = bstrdup(lc->str);
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+
+/*
+ * Store a name string at specified address
+ * A name string is limited to MAX_RES_NAME_LENGTH
+ */
+void store_strname(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc);
+   if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+      scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
+   } else if (lc->str_len > MAX_RES_NAME_LENGTH) {
+      scan_err3(lc, "name %s length %d too long, max is %d\n", lc->str, 
+        lc->str_len, MAX_RES_NAME_LENGTH);
+   } else {
+      /* Store the name */
+      if (pass == 1)
+        *(item->value) = bstrdup(lc->str);
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+
+
+/* Store a string at specified address */
+void store_str(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc);
+   if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+      scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
+   } else {
+      if (pass == 1) {
+        *(item->value) = bstrdup(lc->str);
+      }
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+/* Store a directory name at specified address */
+void store_dir(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc);
+   if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+      scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
+   } else {
+      if (pass == 1) {
+        do_shell_expansion(lc->str);
+        *(item->value) = bstrdup(lc->str);
+      }
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+
+/* Store a password specified address in MD5 coding */
+void store_password(LEX *lc, struct res_items *item, int index, int pass)
+{
+   unsigned int token, i, j;
+   struct MD5Context md5c;
+   unsigned char signature[16];
+   char sig[100];
+
+
+   token = lex_get_token(lc);
+   if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+      scan_err1(lc, "expected an identifier or string, got: %s\n", lc->str);
+   } else {
+      if (pass == 1) {
+        MD5Init(&md5c);
+        MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
+        MD5Final(signature, &md5c);
+        for (i = j = 0; i < sizeof(signature); i++) {
+            sprintf(&sig[j], "%02x", signature[i]); 
+           j += 2;
+        }
+        *(item->value) = bstrdup(sig);
+      }
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+
+/* Store a resource at specified address.
+ * If we are in pass 2, do a lookup of the 
+ * resource.
+ */
+void store_res(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+   RES *res;
+
+   token = lex_get_token(lc);
+   if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+      scan_err1(lc, "expected a Resource name, got: %s", lc->str);
+   }
+   if (pass == 2) {
+     res = GetResWithName(item->code, lc->str);
+     if (res == NULL) {
+        scan_err3(lc, "Could not find Resource %s referenced on line %d : %s\n", 
+          lc->str, lc->line_no, lc->line);
+     }
+     *(item->value) = (char *)res;
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+
+/* Store an integer at specified address */
+void store_int(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc);
+   if (token != T_NUMBER) {
+      scan_err1(lc, "expected an integer number, got: %s", lc->str);
+   } else {
+      errno = 0;
+      *(int *)(item->value) = strtol(lc->str, NULL, 0);
+      if (errno != 0) {
+         scan_err1(lc, "expected an integer number, got: %s", lc->str);
+      }
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+/* Store a positive integer at specified address */
+void store_pint(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc);
+   if (token != T_NUMBER) {
+      scan_err1(lc, "expected an integer number, got: %s", lc->str);
+   } else {
+      errno = 0;
+      token = strtol(lc->str, NULL, 0);
+      if (errno != 0 || token < 0) {
+         scan_err1(lc, "expected a postive integer number, got: %s", lc->str);
+      }
+      *(int *)(item->value) = token;
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+
+/* Store an 64 bit integer at specified address */
+void store_int64(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc);
+   if (token != T_NUMBER) {
+      scan_err1(lc, "expected an integer number, got: %s", lc->str);
+   } else {
+      errno = 0;
+      *(int64_t *)(item->value) = (int64_t)strtod(lc->str, NULL);
+      if (errno != 0)
+         scan_err1(lc, "expected an integer number, got: %s", lc->str);
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+/* Store a size in bytes */
+void store_size(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token, i, ch;
+   uint64_t value;
+   int mod[]  = {'k', 'm', 'g'};
+   uint64_t mult[] = {1024,         /* kilobyte */
+                     1048576,       /* megabyte */
+                     1073741824};   /* gigabyte */
+
+#ifdef we_have_a_compiler_that_works
+   int mod[]  = {'k', 'm', 'g', 't'};
+   uint64_t mult[] = {1024,         /* kilobyte */
+                     1048576,       /* megabyte */
+                     1073741824,    /* gigabyte */
+                     1099511627776};/* terabyte */
+#endif
+
+   Dmsg0(400, "Enter store_size\n");
+   token = lex_get_token(lc);
+   errno = 0;
+   switch (token) {
+   case T_NUMBER:
+      value = (uint64_t)strtod(lc->str, NULL);
+      if (errno != 0 || token < 0) {
+         scan_err1(lc, "expected a size, got: %s", lc->str);
+      }
+      *(uint64_t *)(item->value) = value;
+      break;
+   case T_IDENTIFIER:
+   case T_STRING:
+      /* Look for modifier */
+      ch = lc->str[lc->str_len - 1];
+      i = 0;
+      if (ISALPHA(ch)) {
+        if (ISUPPER(ch)) {
+           ch = tolower(ch);
+        }
+        while (i < (int)sizeof(mod)) {
+           if (ch == mod[i]) {
+              lc->str_len--;
+              lc->str[lc->str_len] = 0; /* strip modifier */
+              break;
+           }
+           i++;
+        }
+      }
+      if (i >= (int)sizeof(mod)) {
+         scan_err1(lc, "expected a size, got: %s", lc->str);
+      }
+      value = (uint64_t)strtod(lc->str, NULL);
+      Dmsg1(400, "Int value = %d\n", (int)value);
+      if (errno != 0 || value < 0) {
+         scan_err1(lc, "expected a size, got: %s", lc->str);
+      }
+      *(uint64_t *)(item->value) = (uint64_t)(strtod(lc->str, NULL) * mult[i]);
+      Dmsg1(400, "Full value = %f\n", strtod(lc->str, NULL) * mult[i]);
+      break;
+   default:
+      scan_err1(lc, "expected a size, got: %s", lc->str);
+      break;
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+   Dmsg0(400, "Leave store_size\n");
+}
+
+
+/* Store a time period in seconds */
+void store_time(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token, i, ch, value;
+   int  mod[]  = {'s', 'm', 'h', 'd', 'w', 'o', 'q', 'y'};
+   int mult[] = {1, 60, 60*60, 60*60*24, 60*60*24*7, 60*60*24*30, 
+                 60*60*24*91, 60*60*24*365};
+
+   token = lex_get_token(lc);
+   errno = 0;
+   switch (token) {
+   case T_NUMBER:
+      token = strtol(lc->str, NULL, 0);
+      if (errno != 0 || token < 0) {
+         scan_err1(lc, "expected a time period, got: %s", lc->str);
+      }
+      *(int *)(item->value) = token;
+      break;
+   case T_IDENTIFIER:
+   case T_STRING:
+      /* Look for modifier */
+      ch = lc->str[lc->str_len - 1];
+      i = 0;
+      if (ISALPHA(ch)) {
+        if (ISUPPER(ch)) {
+           ch = tolower(ch);
+        }
+        while (i < (int)sizeof(mod)) {
+           if (ch == mod[i]) {
+              break;
+           }
+           i++;
+        }
+      }
+      if (i >= (int)sizeof(mod)) {
+         scan_err1(lc, "expected a time period, got: %s", lc->str);
+      }
+      value = strtol(lc->str, NULL, 0);
+      if (errno != 0 || value < 0) {
+         scan_err1(lc, "expected a time period, got: %s", lc->str);
+      }
+      *(int *)(item->value) = value * mult[i];
+      break;
+   default:
+      scan_err1(lc, "expected a time period, got: %s", lc->str);
+      break;
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+
+/* Store a yes/no in a bit field */
+void store_yesno(LEX *lc, struct res_items *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc);
+   lcase(lc->str);
+   if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
+      scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
+   } else if (strcmp(lc->str, "yes") == 0) {
+      *(int *)(item->value) |= item->code;
+   } else if (strcmp(lc->str, "no") == 0) {
+      *(int *)(item->value) &= ~(item->code);
+   } else {
+      scan_err1(lc, "Expect a YES or NO, got: %s", lc->str);
+   }
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
+
+
+/*
+ * Scan to "logical" end of line. I.e. end of line,
+ * or semicolon.
+ */
+void scan_to_eol(LEX *lc)
+{
+   int token;
+   Dmsg0(150, "start scan to eof\n");
+   while ((token = lex_get_token(lc)) != T_EOL) {
+   }
+   Dmsg0(150, "done scan to eof\n");
+}
+
+   
+/*
+ * Format a scanner error message 
+ */
+void s_err(char *file, int line, LEX *lc, char *msg, ...)
+{
+   va_list arg_ptr;
+   char buf[MAXSTRING];
+
+   va_start(arg_ptr, msg);
+   bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
+   va_end(arg_ptr);
+     
+   e_msg(file, line, M_ABORT, 0, "Config error: %s,\n\
+            : Line %d, col %d of file %s\n%s\n",
+      buf, lc->line_no, lc->col_no, lc->fname, lc->line);
+}
+
+void LockRes()
+{
+   P(res_mutex);
+   res_locked = 1;
+}
+
+void UnlockRes()
+{
+   res_locked = 0;
+   V(res_mutex);
+}
+
+/*
+ * Return resource of type rcode that matches name
+ */
+RES *
+GetResWithName(int rcode, char *name)
+{
+   RES *res;
+   int rindex = rcode - r_first;
+
+   LockRes();
+   res = resources[rindex].res_head;
+   while (res) {
+      if (strcmp(res->name, name) == 0) {
+        break;
+      }
+      res = res->next;
+   }
+   UnlockRes();
+   return res;
+   
+}
+
+/*
+ * Return next resource of type rcode. On first
+ * call second arg (res) is NULL, on subsequent
+ * calls, it is called with previous value.
+ */
+RES *
+GetNextRes(int rcode, RES *res)
+{
+   RES *nres;
+   int rindex = rcode - r_first;
+       
+
+   if (!res_locked) {
+      Emsg0(M_ABORT, 0, "Resource chain not locked.\n");
+   }
+   if (res == NULL) {
+      nres = resources[rindex].res_head;
+   } else {
+      nres = res->next;
+   }
+   return nres;
+}
+
+
+/* Parser state */
+enum parse_state {
+   p_none,
+   p_resource
+};
+
+/*********************************************************************
+ *
+ *     Parse configuration file
+ *
+ */
+void 
+parse_config(char *cf)
+{
+   LEX *lc = NULL;
+   int token, i, res_type, pass;
+   enum parse_state state = p_none;
+   struct res_items *items;
+   int level = 0;
+
+   /* Make two passes. The first builds the name symbol table,
+    * and the second picks up the items. 
+    */
+   Dmsg0(200, "Enter parse_config()\n");
+   for (pass=1; pass<= 2; pass++) {
+      Dmsg1(200, "parse_config pass %d\n", pass);
+      lc = lex_open_file(lc, cf);
+      while ((token=lex_get_token(lc)) != T_EOF) {
+         Dmsg1(150, "parse got token=%s\n", lex_tok_to_str(token));
+        switch (state) {
+           case p_none:
+              if (token == T_EOL) {
+                 break;
+              }
+              if (token != T_IDENTIFIER) {
+                  scan_err1(lc, "Expected a Resource name identifier, got: %s", lc->str);
+              }
+              lcase(lc->str);
+              for (i=0; resources[i].name; i++)
+                 if (strcmp(resources[i].name, lc->str) == 0) {
+                    state = p_resource;
+                    items = resources[i].items;
+                    res_type = resources[i].rcode;
+                    init_resource(res_type, items);
+                    break;
+                 }
+              if (state == p_none) {
+                  scan_err1(lc, "expected resource name, got: %s", lc->str);
+              }
+              break;
+           case p_resource:
+              switch (token) {
+                 case T_BOB:
+                    level++;
+                    break;
+                 case T_IDENTIFIER:
+                    if (level != 1) {
+                        scan_err1(lc, "not in resource definition: %s", lc->str);
+                    }
+                    lcase(lc->str);
+                    for (i=0; items[i].name; i++) {
+                       if (strcmp(items[i].name, lc->str) == 0) {
+                          token = lex_get_token(lc);
+                           Dmsg1 (150, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
+                          if (token != T_EQUALS) {
+                              scan_err1(lc, "expected an equals, got: %s", lc->str);
+                          }
+                           Dmsg1(150, "calling handler for %s\n", items[i].name);
+                          /* Call item handler */
+                          items[i].handler(lc, &items[i], i, pass);
+                          i = -1;
+                          break;
+                       }
+                    }
+                    if (i >= 0) {
+                        Dmsg2(150, "level=%d id=%s\n", level, lc->str);
+                        Dmsg1(150, "Keyword = %s\n", lc->str);
+                        scan_err1(lc, "Keyword %s not permitted in this resource", lc->str);
+                    }
+                    break;
+
+                 case T_EOB:
+                    level--;
+                    state = p_none;
+                     Dmsg0(150, "T_EOB => define new resource\n");
+                    save_resource(res_type, items, pass);  /* save resource */
+                    break;
+
+                 case T_EOL:
+                    break;
+
+                 default:
+                     scan_err2(lc, "unexpected token %d %s in resource definition",    
+                       token, lex_tok_to_str(token));
+              }
+              break;
+           default:
+               scan_err1(lc, "Unknown parser state %d\n", state);
+        }
+      }
+      if (debug_level > 50 && pass == 2) {
+        int i;
+        for (i=r_first; i<=r_last; i++) {
+           dump_resource(i, resources[i-r_first].res_head, prtmsg, NULL);
+        }
+      }
+      lc = lex_close_file(lc);
+   }
+   Dmsg0(200, "Leave parse_config()\n");
+}
+
+/*********************************************************************
+ *
+ *     Free configuration resources
+ *
+ */
+void 
+free_config_resources()
+{
+   int i;
+   for (i=r_first; i<=r_last; i++) {
+      free_resource(i);
+   }
+}
diff --git a/bacula/src/lib/parse_conf.h b/bacula/src/lib/parse_conf.h
new file mode 100644 (file)
index 0000000..aec3519
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+struct res_items;                   /* Declare forward referenced structure */ 
+typedef void (MSG_RES_HANDLER)(LEX *lc, struct res_items *item, int index, int pass);
+
+/* This is the structure that defines
+ * the record types (items) permitted within each
+ * resource. It is used to define the configuration
+ * tables.
+ */
+struct res_items {
+   char *name;                        /* Resource name i.e. Director, ... */
+   MSG_RES_HANDLER *handler;          /* Routine storing the resource item */
+   void **value;                      /* Where to store the item */
+   int  code;                         /* item code/additional info */
+   int  flags;                        /* flags: default, required, ... */
+   int  default_value;                /* default value */
+};
+
+/* For storing name_addr items in res_items table */
+#define ITEM(x) ((void **)&res_all.x)
+
+#define MAX_RES_ITEMS 32              /* maximum resource items per RES */
+
+/* This is the universal header that is
+ * at the beginning of every resource
+ * record.
+ */
+struct s_reshdr {
+   char *name;                        /* resource name */
+   char *desc;                        /* resource description */
+   int   rcode;                       /* resource id or type */
+   int   refcnt;                      /* reference count for releasing */
+   char  item_present[MAX_RES_ITEMS]; /* set if item is present in conf file */
+   struct s_reshdr *next;             /* pointer to next resource of this type */
+};
+
+typedef struct s_reshdr RES;
+
+/* 
+ * Master Resource configuration structure definition
+ * This is the structure that defines the
+ * resources that are available to this daemon.
+ */
+struct s_res {       
+   char *name;                        /* resource name */
+   struct res_items *items;           /* list of resource keywords */
+   int rcode;                         /* code if needed */
+   RES *res_head;                     /* where to store it */
+};
+
+/* Common Resource definitions */
+
+#define MAX_RES_NAME_LENGTH MAX_NAME_LENGTH-1       /* maximum resource name length */
+
+#define ITEM_REQUIRED 0x1             /* item required */
+#define ITEM_DEFAULT  0x2             /* default supplied */
+
+/* Message Resource */
+struct s_res_msgs {
+   RES   hdr;
+   char *mail_cmd;                    /* mail command */
+   char *operator_cmd;                /* Operator command */
+   DEST *dest_chain;                  /* chain of destinations */
+   char send_msg[nbytes_for_bits(M_MAX+1)];  /* bit array of types */
+};
+typedef struct s_res_msgs MSGS;
+
+
+/* Define the Union of all the above common
+ * resource structure definitions.
+ */
+union cu_res {
+   struct s_res_msgs    res_msgs;
+   RES hdr;
+};
+
+typedef union cu_res CURES;
+
+
+/* Configuration routines */
+void  parse_config            __PROTO((char *cf));
+void  free_config_resources   __PROTO(());
+
+/* Resource routines */
+RES *GetResWithName(int rcode, char *name);
+RES *GetNextRes(int rcode, RES *res);
+void LockRes(void);
+void UnlockRes(void);
+void dump_resource(int type, RES *res, void sendmsg(void *sock, char *fmt, ...), void *sock);
+void free_resource(int type);
+void init_resource(int type, struct res_items *item);
+void save_resource(int type, struct res_items *item, int pass);
+
+
+void scan_error(LEX *lc, char *msg, ...);  /* old way, do not use */
+void scan_to_eol(LEX *lc);
+char *res_to_str(int rcode);
+
+void store_str(LEX *lc, struct res_items *item, int index, int pass);
+void store_dir(LEX *lc, struct res_items *item, int index, int pass);
+void store_password(LEX *lc, struct res_items *item, int index, int pass);
+void store_name(LEX *lc, struct res_items *item, int index, int pass);
+void store_strname(LEX *lc, struct res_items *item, int index, int pass);
+void store_res(LEX *lc, struct res_items *item, int index, int pass);
+void store_int(LEX *lc, struct res_items *item, int index, int pass);
+void store_pint(LEX *lc, struct res_items *item, int index, int pass);
+void store_msgs(LEX *lc, struct res_items *item, int index, int pass);
+void store_int64(LEX *lc, struct res_items *item, int index, int pass);
+void store_yesno(LEX *lc, struct res_items *item, int index, int pass);
+void store_time(LEX *lc, struct res_items *item, int index, int pass);
+void store_size(LEX *lc, struct res_items *item, int index, int pass);
+
+/* Lexical scanning errors in parsing conf files */
+#define scan_err0(lc, msg) s_err(__FILE__, __LINE__, lc, msg)
+#define scan_err1(lc, msg, a1) s_err(__FILE__, __LINE__, lc, msg, a1)
+#define scan_err2(lc, msg, a1, a2) s_err(__FILE__, __LINE__, lc, msg, a1, a2)
+#define scan_err3(lc, msg, a1, a2, a3) s_err(__FILE__, __LINE__, lc, msg, a1, a2, a3)
+#define scan_err4(lc, msg, a1, a2, a3, a4) s_err(__FILE__, __LINE__, lc, msg, a1, a2, a3, a4)
+#define scan_err5(lc, msg, a1, a2, a3, a4, a5) s_err(__FILE__, __LINE__, lc, msg, a1, a2, a3, a4, a5)
+#define scan_err6(lc, msg, a1, a2, a3, a4, a5, a6) s_err(__FILE__, __LINE__, lc, msg, a1, a2, a3, a4, a5, a6)
+
+void s_err(char *file, int line, LEX *lc, char *msg,...);
diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h
new file mode 100644 (file)
index 0000000..fb1091c
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Prototypes for lib directory of Bacula
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/* base64.c */
+void     base64_init            __PROTO((void));
+int      to_base64              __PROTO((intmax_t value, char *where));
+int      from_base64            __PROTO((intmax_t *value, char *where));
+void     encode_stat            __PROTO((char *buf, struct stat *statp));
+void     decode_stat            __PROTO((char *buf, struct stat *statp));
+int      bin_to_base64          __PROTO((char *buf, char *bin, int len));
+
+/* bmisc.c */
+void    *b_malloc               (char *file, int line, size_t size);
+#ifndef DEBUG
+void    *bmalloc                (size_t size);
+#endif
+void    *brealloc               (void *buf, size_t size);
+void    *bcalloc                (size_t size1, size_t size2);
+int      bsnprintf              (char *str, size_t size, const  char  *format, ...);
+int      bvsnprintf             (char *str, size_t size, const char  *format, va_list ap);
+int      pool_sprintf           (char *pool_buf, char *fmt, ...);
+int      create_pid_file        (char *dir, char *progname, int port, char *errmsg);
+int      delete_pid_file        (char *dir, char *progname, int port);
+
+/* bnet.c */
+int32_t    bnet_recv            __PROTO((BSOCK *bsock));
+int       bnet_send             __PROTO((BSOCK *bsock));
+int       bnet_fsend              (BSOCK *bs, char *fmt, ...);
+int       bnet_set_buffer_size    (BSOCK *bs, uint32_t size, int rw);
+int       bnet_sig                (BSOCK *bs, int sig);
+BSOCK *    bnet_connect           (void *jcr, int retry_interval,
+              int max_retry_time, char *name, char *host, char *service, 
+              int port, int verbose);
+int       bnet_wait_data         (BSOCK *bsock, int sec);
+void      bnet_close            __PROTO((BSOCK *bsock));
+BSOCK *    init_bsock           __PROTO((int sockfd, char *who, char *ip, int port));
+BSOCK *    dup_bsock            __PROTO((BSOCK *bsock));
+void      term_bsock            __PROTO((BSOCK *bsock));
+char *    bnet_strerror         __PROTO((BSOCK *bsock));
+char *    bnet_sig_to_ascii     __PROTO((BSOCK *bsock));
+int       bnet_wait_data        __PROTO((BSOCK *bsock, int sec));
+
+
+/* cram-md5.c */
+int cram_md5_get_auth(BSOCK *bs, char *password);
+int cram_md5_auth(BSOCK *bs, char *password);
+void hmac_md5(uint8_t* text, int text_len, uint8_t*  key,
+             int key_len, uint8_t *hmac);
+
+/* create_file.c */
+int create_file(void *jcr, char *fname, char *ofile, char *lname,
+                      int type, struct stat *statp, int *ofd);
+int set_statp(void *jcr, char *fname, char *ofile, char *lname, int type, 
+                      struct stat *statp);
+
+
+/* crc32.c */
+uint32_t bcrc32(uint8_t *buf, int len);
+
+/* daemon.c */
+void    daemon_start            __PROTO(());
+
+/* lex.c */
+LEX *    lex_close_file         __PROTO((LEX *lf));
+LEX *    lex_open_file          __PROTO((LEX *lf, char *fname));
+int      lex_get_char           __PROTO((LEX *lf));
+void     lex_unget_char         __PROTO((LEX *lf));
+char *   lex_tok_to_str         __PROTO((int token));
+int      lex_get_token          __PROTO((LEX *lf));
+
+/* makepath.c */
+int make_path(
+          void *jcr,
+          const char *argpath,
+          int mode,
+          int parent_mode,
+          uid_t owner,
+          gid_t group,
+          int preserve_existing,
+          char *verbose_fmt_string);
+
+
+/* message.c */
+void      my_name_is            __PROTO((int argc, char *argv[], char *name));
+void      init_msg              __PROTO((void *jcr));
+void      term_msg              __PROTO((void));
+void      close_msg             __PROTO((void *jcr));
+void      add_msg_dest          __PROTO((int dest, int type, char *where, char *dest_code));
+void      rem_msg_dest          __PROTO((int dest, int type, char *where));
+void      Jmsg                  (void *jcr, int type, int level, char *fmt, ...);
+void      dispatch_message      __PROTO((void *jcr, int type, int level, char *buf));
+void      init_console_msg      __PROTO((char *wd));
+
+
+/* bnet_server.c */
+void      bnet_thread_server(int port, int max_clients, workq_t *client_wq, 
+                  void handle_client_request(void *bsock));
+void            bnet_server             __PROTO((int port, void handle_client_request(BSOCK *bsock)));
+int             net_connect             __PROTO((int port));
+BSOCK *         bnet_bind               __PROTO((int port));
+BSOCK *         bnet_accept             __PROTO((BSOCK *bsock, char *who));
+
+/* signal.c */
+void            init_signals             __PROTO((void terminate(int sig)));
+void            init_stack_dump          (void);
+
+/* util.c */
+void            lcase                   __PROTO((char *str));
+void            bash_spaces             __PROTO((char *str));
+void            unbash_spaces           __PROTO((char *str));
+void            strip_trailing_junk     __PROTO((char *str));
+void            strip_trailing_slashes  __PROTO((char *dir));
+int             skip_spaces             __PROTO((char **msg));
+int             skip_nonspaces          __PROTO((char **msg));
+int             fstrsch                 __PROTO((char *a, char *b));
+char *          encode_time             __PROTO((time_t time, char *buf));
+char *          encode_mode             __PROTO((mode_t mode, char *buf));
+char *          edit_uint_with_commas   __PROTO((uint64_t val, char *buf));
+char *          add_commas              __PROTO((char *val, char *buf));
+int do_shell_expansion(char *name);
+/*
+ *void          print_ls_output         __PROTO((char *fname, char *lname, int type, struct stat *statp));
+ */
+
+/* watchdog.c */
+int init_watchdog(void);
+int term_watchdog(void);
diff --git a/bacula/src/lib/queue.c b/bacula/src/lib/queue.c
new file mode 100644 (file)
index 0000000..d799d10
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+
+                        Q U E U E
+                    Queue Handling Routines
+
+       Taken from smartall by John Walker.
+
+                 http://www.fourmilab.ch/smartall/
+
+*/
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+
+/*  General purpose queue  */
+
+#ifdef REALLY_NEEDED
+struct b_queue {
+       struct b_queue *qnext,       /* Next item in queue */
+                    *qprev;       /* Previous item in queue */
+};
+#endif
+
+/* 
+ * To define a queue, use the following
+ *
+ *  static BQUEUE xyz = { &xyz, &xyz }; 
+ *
+ *   Also, note, that the only real requirement is that
+ *   the object that is passed to these routines contain
+ *   a BQUEUE object as the very first member. The
+ *   rest of the structure may be anything.
+ *
+ *   NOTE!!!! The casting here is REALLY painful, but this avoids
+ *           doing ugly casting every where else in the code.
+ */
+
+
+/*  Queue manipulation functions.  */
+
+
+/*  QINSERT  --  Insert object at end of queue */
+
+void qinsert(BQUEUE *qhead, BQUEUE *object)
+{
+#define qh ((BQUEUE *)qhead)
+#define obj ((BQUEUE *)object)
+
+       ASSERT(qh->qprev->qnext == qh);
+       ASSERT(qh->qnext->qprev == qh);
+
+       obj->qnext = qh;
+       obj->qprev = qh->qprev;
+       qh->qprev = obj;
+       obj->qprev->qnext = obj;
+#undef qh
+#undef obj
+}
+
+
+/*  QREMOVE  --  Remove next object from the queue given
+                the queue head (or any item). 
+     Returns NULL if queue is empty  */
+
+BQUEUE *qremove(BQUEUE *qhead)
+{
+#define qh ((BQUEUE *)qhead)
+       BQUEUE *object;
+
+       ASSERT(qh->qprev->qnext == qh);
+       ASSERT(qh->qnext->qprev == qh);
+
+       if ((object = qh->qnext) == qh)
+          return NULL;
+       qh->qnext = object->qnext;
+       object->qnext->qprev = qh;
+       return object;
+#undef qh
+}
+
+/*  QNEXT   --  Return next item from the queue
+ *              returns NULL at the end of the queue.
+ *              If qitem is NULL, the first item from
+ *              the queue is returned.
+ */
+
+BQUEUE *qnext(BQUEUE *qhead, BQUEUE *qitem)
+{
+#define qh ((BQUEUE *)qhead)
+#define qi ((BQUEUE *)qitem)
+
+       BQUEUE *object;
+
+       if (qi == NULL)
+          qitem = qhead;
+       ASSERT(qi->qprev->qnext == qi);
+       ASSERT(qi->qnext->qprev == qi);
+       
+       if ((object = qi->qnext) == qh)
+          return NULL;
+       return object;
+#undef qh
+#undef qi
+}         
+
+
+/*  QDCHAIN  --  Dequeue an item from the middle of a queue.  Passed
+                the queue item, returns the (now dechained) queue item. */
+
+BQUEUE *qdchain(BQUEUE *qitem)
+{
+#define qi ((BQUEUE *)qitem)
+
+       ASSERT(qi->qprev->qnext == qi);
+       ASSERT(qi->qnext->qprev == qi);
+
+       return qremove(qi->qprev);
+#undef qi
+}
diff --git a/bacula/src/lib/queue.h b/bacula/src/lib/queue.h
new file mode 100644 (file)
index 0000000..e9afef4
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+
+/*  General purpose queue  */
+
+struct b_queue {
+        struct b_queue *qnext,     /* Next item in queue */
+                     *qprev;       /* Previous item in queue */
+};
+
+typedef struct b_queue BQUEUE;
+
+/*  Queue functions  */
+
+void    qinsert(BQUEUE *qhead, BQUEUE *object);
+BQUEUE *qnext(BQUEUE *qhead, BQUEUE *qitem);
+BQUEUE *qdchain(BQUEUE *qitem);
+BQUEUE *qremove(BQUEUE *qhead);
diff --git a/bacula/src/lib/rwlock.c b/bacula/src/lib/rwlock.c
new file mode 100644 (file)
index 0000000..81850c9
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Bacula Thread Read/Write locking code. It permits
+ *  multiple readers but only one writer.                
+ *
+ *  Kern Sibbald, January MMI
+ *
+ *  This code adapted from "Programming with POSIX Threads", by
+ *    David R. Butenhof
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+
+#ifdef REALLY_IMPLEMENTED
+
+/*   
+ * Initialize a read/write lock
+ *
+ *  Returns: 0 on success
+ *          errno on failure
+ */
+int rwl_init(rwlock_t *rwl)
+{
+   int stat;
+                       
+   rwl->r_active = rwl->w_active = 0;
+   rwl->r_wait = rwl->w_wait = 0;
+   if ((stat = pthread_mutex_init(&rwl->mutex, NULL)) != 0) {
+      return stat;
+   }
+   if ((stat = pthread_cond_init(&rwl->read, NULL)) != 0) {
+      pthread_mutex_destroy(&rwl->mutex);
+      return stat;
+   }
+   if ((stat = pthread_cond_init(&rwl->write, NULL)) != 0) {
+      pthread_cond_destroy(&rwl->read);
+      pthread_mutex_destroy(&rwl->mutex);
+      return stat;
+   }
+   rwl->valid = RWLOCK_VALID;
+   return 0;
+}
+
+/*
+ * Destroy a read/write lock
+ *
+ * Returns: 0 on success
+ *         errno on failure
+ */
+int rwl_destroy(rwlock_t *rwl)
+{
+   int stat, stat1, stat2;
+
+  if (rwl->valid != RWLOCK_VALID) {
+     return EINVAL;
+  }
+  if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) {
+     return stat;
+  }
+
+  /* 
+   * If any threads are active, report EBUSY
+   */
+  if (rwl->r_active > 0 || rwl->w_active) {
+     pthread_mutex_unlock(&rwl->mutex);
+     return EBUSY;
+  }
+
+  /*
+   * If any threads are waiting, report EBUSY
+   */
+  if (rwl->r_wait > 0 || rwl->w_wait > 0) { 
+     pthread_mutex_unlock(&rwl->mutex);
+     return EBUSY;
+  }
+
+  rwl->valid = 0;
+  if ((stat = pthread_mutex_unlock(&rwl->mutex)) != 0) {
+     return stat;
+  }
+  stat = pthread_mutex_destroy(&rwl->mutex);
+  stat1 = pthread_cond_destroy(&rwl->read);
+  stat2 = pthread_cond_destroy(&rwl->write);
+  return (stat != 0 ? stat : (stat1 != 0 ? stat1 : stat2));
+}
+
+/*
+ * Handle cleanup when the read lock condition variable
+ * wait is released.
+ */
+static void rwl_read_release(void *arg)
+{
+   rwlock_t *rwl = (rwlock_t *)arg;
+
+   rwl->r_wait--;
+   pthread_mutex_unlock(&rwl->mutex);
+}
+
+/*
+ * Handle cleanup when the write lock condition variable wait
+ * is released.
+ */
+static void rwl_write_release(void *arg)
+{
+   rwlock_t *rwl = (rwlock_t *)arg;
+
+   rwl->w_wait--;
+   pthread_mutex_unlock(&rwl->mutex);
+}
+
+/*
+ * Lock for read access, wait until locked (or error).
+ */
+int rwl_readlock(rwlock_t *rwl)
+{
+   int stat;
+    
+   if (rwl->valid != RWLOCK_VALID) {
+      return EINVAL;
+   }
+   if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) {
+      return stat;
+   }
+   if (rwl->w_active) {
+      rwl->r_wait++;                 /* indicate that we are waiting */
+      pthread_cleanup_push(rwl_read_release, (void *)rwl);
+      while (rwl->w_active) {
+        stat = pthread_cond_wait(&rwl->read, &rwl->mutex);
+        if (stat != 0) {
+           break;                    /* error, bail out */
+        }
+      }
+      pthread_cleanup_pop(0);
+      rwl->r_wait--;                 /* we are no longer waiting */
+   }
+   if (stat == 0) {
+      rwl->r_active++;               /* we are running */
+   }
+   pthread_mutex_unlock(&rwl->mutex);
+   return stat;
+}
+
+/* 
+ * Attempt to lock for read access, don't wait
+ */
+int rwl_readtrylock(rwlock_t *rwl)
+{
+   int stat, stat2;
+    
+   if (rwl->valid != RWLOCK_VALID) {
+      return EINVAL;
+   }
+   if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) {
+      return stat;
+   }
+   if (rwl->w_active) {
+      stat = EBUSY;
+   } else {
+      rwl->r_active++;               /* we are running */
+   }
+   stat2 = pthread_mutex_unlock(&rwl->mutex);
+   return (stat == 0 ? stat2 : stat);
+}
+   
+/* 
+ * Unlock read lock
+ */
+int rwl_readunlock(rwlock_t *rwl)
+{
+   int stat, stat2;
+    
+   if (rwl->valid != RWLOCK_VALID) {
+      return EINVAL;
+   }
+   if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) {
+      return stat;
+   }
+   rwl->r_active--;
+   if (rwl->r_active == 0 && rwl->w_wait > 0) { /* if writers waiting */
+      stat = pthread_cond_signal(&rwl->write);
+   }
+   stat2 = pthread_mutex_unlock(&rwl->mutex);
+   return (stat == 0 ? stat2 : stat);
+}
+
+
+/*
+ * Lock for write access, wait until locked (or error).
+ */
+int rwl_writelock(rwlock_t *rwl)
+{
+   int stat;
+    
+   if (rwl->valid != RWLOCK_VALID) {
+      return EINVAL;
+   }
+   if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) {
+      return stat;
+   }
+   if (rwl->w_active || rwl->r_active > 0) {
+      rwl->w_wait++;                 /* indicate that we are waiting */
+      pthread_cleanup_push(rwl_write_release, (void *)rwl);
+      while (rwl->w_active || rwl->r_active > 0) {
+        stat = pthread_cond_wait(&rwl->write, &rwl->mutex);
+        if (stat != 0) {
+           break;                    /* error, bail out */
+        }
+      }
+      pthread_cleanup_pop(0);
+      rwl->w_wait--;                 /* we are no longer waiting */
+   }
+   if (stat == 0) {
+      rwl->w_active = 1;             /* we are running */
+   }
+   pthread_mutex_unlock(&rwl->mutex);
+   return stat;
+}
+
+/* 
+ * Attempt to lock for write access, don't wait
+ */
+int rwl_writetrylock(rwlock_t *rwl)
+{
+   int stat, stat2;
+    
+   if (rwl->valid != RWLOCK_VALID) {
+      return EINVAL;
+   }
+   if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) {
+      return stat;
+   }
+   if (rwl->w_active || rwl->r_active > 0) {
+      stat = EBUSY;
+   } else {
+      rwl->w_active = 1;             /* we are running */
+   }
+   stat2 = pthread_mutex_unlock(&rwl->mutex);
+   return (stat == 0 ? stat2 : stat);
+}
+   
+/* 
+ * Unlock write lock
+ *  Start any waiting writers in preference to waiting readers
+ */
+int rwl_writeunlock(rwlock_t *rwl)
+{
+   int stat, stat2;
+    
+   if (rwl->valid != RWLOCK_VALID) {
+      return EINVAL;
+   }
+   if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) {
+      return stat;
+   }
+   rwl->w_active = 0;
+   if (rwl->w_wait > 0) {            /* if writers waiting */
+      stat = pthread_cond_signal(&rwl->write);
+   } else if (rwl->r_wait > 0) {
+      stat = pthread_cond_broadcast(&rwl->read);
+   }
+   stat2 = pthread_mutex_unlock(&rwl->mutex);
+   return (stat == 0 ? stat2 : stat);
+}
+
+#endif
diff --git a/bacula/src/lib/rwlock.h b/bacula/src/lib/rwlock.h
new file mode 100644 (file)
index 0000000..8ba9e98
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Bacula Thread Read/Write locking code. It permits
+ *  multiple readers but only one writer.                 
+ *
+ *  Kern Sibbald, January MMI
+ *
+ *  This code adapted from "Programming with POSIX Threads", by
+ *    David R. Butenhof
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef __RWLOCK_H 
+#define __RWLOCK_H 1
+
+typedef struct rwlock_tag {
+   pthread_mutex_t   mutex;
+   pthread_cond_t    read;            /* wait for read */
+   pthread_cond_t    write;           /* wait for write */
+   int               valid;           /* set when valid */
+   int               r_active;        /* readers active */
+   int               w_active;        /* writers active */
+   int               r_wait;          /* readers waiting */
+   int               w_wait;          /* writers waiting */
+} rwlock_t;
+
+#define RWLOCK_VALID  0xfacade
+
+#define RWL_INIIALIZER \
+   {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \
+    PTHREAD_COND_INITIALIZER, RWLOCK_VALID, 0, 0, 0, 0}
+
+/* 
+ * read/write lock prototypes
+ */
+extern int rwl_init(rwlock_t *wrlock);
+extern int rwl_destroy(rwlock_t *rwlock);
+extern int rwl_readlock(rwlock_t *rwlock);
+extern int rwl_readtrylock(rwlock_t *rwlock);
+extern int rwl_readunlock(rwlock_t *rwlock);
+extern int rwl_writelock(rwlock_t *rwlock);
+extern int rwl_writetrylock(rwlock_t *rwlock);
+extern int rwl_writeunlock(rwlock_t *rwlock);
+
+#endif /* __RWLOCK_H */
diff --git a/bacula/src/lib/serial.c b/bacula/src/lib/serial.c
new file mode 100644 (file)
index 0000000..c1e5c3f
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+
+                  Serialisation Support Functions
+                         John Walker
+
+*/
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+#include "serial.h"
+
+/*
+
+       NOTE:  The following functions should work on any
+              vaguely contemporary platform.  Production
+              builds should use optimised macros (void
+              on platforms with network byte order and IEEE
+              floating point format as native.
+
+*/
+
+/*  serial_int16  --  Serialise a signed 16 bit integer.  */
+
+void serial_int16(uint8_t * * const ptr, const int16_t v)
+{
+    int16_t vo = htons(v);
+
+    memcpy(*ptr, &vo, sizeof vo);
+    *ptr += sizeof vo;
+}
+
+/*  serial_uint16  --  Serialise an unsigned 16 bit integer.  */
+
+void serial_uint16(uint8_t * * const ptr, const uint16_t v)
+{
+    uint16_t vo = htons(v);
+
+    memcpy(*ptr, &vo, sizeof vo);
+    *ptr += sizeof vo;
+}
+
+/*  serial_int32  --  Serialise a signed 32 bit integer.  */
+
+void serial_int32(uint8_t * * const ptr, const int32_t v)
+{
+    int32_t vo = htonl(v);
+
+    memcpy(*ptr, &vo, sizeof vo);
+    *ptr += sizeof vo;
+}
+
+/*  serial_uint32  --  Serialise an unsigned 32 bit integer.  */
+
+void serial_uint32(uint8_t * * const ptr, const uint32_t v)
+{
+    uint32_t vo = htonl(v);
+
+    memcpy(*ptr, &vo, sizeof vo);
+    *ptr += sizeof vo;
+}
+
+/*  serial_int64  --  Serialise a signed 64 bit integer.  */
+
+void serial_int64(uint8_t * * const ptr, const int64_t v)
+{
+    if (htonl(1) == 1L) {
+       memcpy(*ptr, &v, sizeof(int64_t));
+    } else {
+       int i;
+       uint8_t rv[sizeof(int64_t)];
+       uint8_t *pv = (uint8_t *) &v;
+
+       for (i = 0; i < 8; i++) {
+           rv[i] = pv[7 - i];
+       }
+       memcpy(*ptr, &rv, sizeof(int64_t));
+    }
+    *ptr += sizeof(int64_t);
+}
+
+
+/*  serial_uint64  --  Serialise an unsigned 64 bit integer.  */
+
+void serial_uint64(uint8_t * * const ptr, const uint64_t v)
+{
+    if (htonl(1) == 1L) {
+       memcpy(*ptr, &v, sizeof(uint64_t));
+    } else {
+       int i;
+       uint8_t rv[sizeof(uint64_t)];
+       uint8_t *pv = (uint8_t *) &v;
+
+       for (i = 0; i < 8; i++) {
+           rv[i] = pv[7 - i];
+       }
+       memcpy(*ptr, &rv, sizeof(uint64_t));
+    }
+    *ptr += sizeof(uint64_t);
+}
+
+
+/*  serial_float64  -- Serialise a 64 bit IEEE floating point number.
+                       This code assumes that the host floating point
+                       format is IEEE and that floating point quantities
+                       are stored in IEEE format either LSB first or MSB
+                       first.  More creative host formats will require
+                       additional transformations here.  */
+
+void serial_float64(uint8_t * * const ptr, const float64_t v)
+{
+    if (htonl(1) == 1L) {
+       memcpy(*ptr, &v, sizeof(float64_t));
+    } else {
+       int i;
+       uint8_t rv[sizeof(float64_t)];
+       uint8_t *pv = (uint8_t *) &v;
+
+       for (i = 0; i < 8; i++) {
+           rv[i] = pv[7 - i];
+       }
+       memcpy(*ptr, &rv, sizeof(float64_t));
+    }
+    *ptr += sizeof(float64_t);
+}
+
+int serial_string(uint8_t * const ptr, char * const str)
+{
+   int len = strlen((const char *) str) + 1;
+   memcpy(ptr, str, len);
+   return len;
+}
+
+
+/*  unserial_int16  -- Unserialise a signed 16 bit integer.  */
+
+int16_t unserial_int16(uint8_t * * const ptr)
+{
+    int16_t vo;
+
+    memcpy(&vo, *ptr, sizeof vo);
+    *ptr += sizeof vo;
+    return ntohs(vo);
+}
+
+/*  unserial_uint16  --  Unserialise an unsigned 16 bit integer.  */
+
+uint16_t unserial_uint16(uint8_t * * const ptr)
+{
+    uint16_t vo;
+
+    memcpy(&vo, *ptr, sizeof vo);
+    *ptr += sizeof vo;
+    return ntohs(vo);
+}
+
+/*  unserial_int32  -- Unserialise a signed 32 bit integer.  */
+
+int32_t unserial_int32(uint8_t * * const ptr)
+{
+    int32_t vo;
+
+    memcpy(&vo, *ptr, sizeof vo);
+    *ptr += sizeof vo;
+    return ntohl(vo);
+}
+
+/*  unserial_uint32  --  Unserialise an unsigned 32 bit integer.  */
+
+uint32_t unserial_uint32(uint8_t * * const ptr)
+{
+    uint32_t vo;
+
+    memcpy(&vo, *ptr, sizeof vo);
+    *ptr += sizeof vo;
+    return ntohl(vo);
+}
+
+/*  unserial_int64  -- Unserialise a signed 64 bit integer.  */
+
+int64_t unserial_int64(uint8_t * * const ptr)
+{
+    int64_t v;
+
+    if (htonl(1) == 1L) {
+       memcpy(&v, *ptr, sizeof(int64_t));
+    } else {
+       int i;
+       uint8_t rv[sizeof(int64_t)];
+       uint8_t *pv = (uint8_t *) &v;
+
+       memcpy(&v, *ptr, sizeof(int64_t));
+       for (i = 0; i < 8; i++) {
+           rv[i] = pv[7 - i];
+       }
+       memcpy(&v, &rv, sizeof(int64_t));
+    }
+    *ptr += sizeof(int64_t);
+    return v;
+}
+
+/*  unserial_uint64  --  Unserialise an unsigned 64 bit integer.  */
+
+uint64_t unserial_uint64(uint8_t * * const ptr)
+{
+    uint64_t v;
+
+    if (htonl(1) == 1L) {
+       memcpy(&v, *ptr, sizeof(uint64_t));
+    } else {
+       int i;
+       uint8_t rv[sizeof(uint64_t)];
+       uint8_t *pv = (uint8_t *) &v;
+
+       memcpy(&v, *ptr, sizeof(uint64_t));
+       for (i = 0; i < 8; i++) {
+           rv[i] = pv[7 - i];
+       }
+       memcpy(&v, &rv, sizeof(uint64_t));
+    }
+    *ptr += sizeof(uint64_t);
+    return v;
+}
+
+
+/*  unserial_float64  --  Unserialise a 64 bit IEEE floating point number.
+                        This code assumes that the host floating point
+                        format is IEEE and that floating point quantities
+                        are stored in IEEE format either LSB first or MSB
+                        first.  More creative host formats will require
+                        additional transformations here.  */
+
+float64_t unserial_float64(uint8_t * * const ptr)
+{
+    float64_t v;
+
+    if (htonl(1) == 1L) {
+       memcpy(&v, *ptr, sizeof(float64_t));
+    } else {
+       int i;
+       uint8_t rv[sizeof(float64_t)];
+       uint8_t *pv = (uint8_t *) &v;
+
+       memcpy(&v, *ptr, sizeof(float64_t));
+       for (i = 0; i < 8; i++) {
+           rv[i] = pv[7 - i];
+       }
+       memcpy(&v, &rv, sizeof(float64_t));
+    }
+    *ptr += sizeof(float64_t);
+    return v;
+}
+
+int unserial_string(uint8_t  * const ptr, char * const str)
+{
+   int len = strlen((char *)ptr) + 1;
+   memcpy(str, ptr, len);
+   return len;
+}
diff --git a/bacula/src/lib/serial.h b/bacula/src/lib/serial.h
new file mode 100644 (file)
index 0000000..7066e77
--- /dev/null
@@ -0,0 +1,150 @@
+
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/*  Serialisation support functions from serial.c.  */
+
+extern void serial_int16(uint8_t * * ptr, int16_t v);
+extern void serial_uint16(uint8_t * * ptr, uint16_t v);
+extern void serial_int32(uint8_t * * ptr, int32_t v);
+extern void serial_uint32(uint8_t * * ptr, uint32_t v);
+extern void serial_int64(uint8_t * * ptr, int64_t v);
+extern void serial_uint64(uint8_t * * ptr, uint64_t v);
+extern void serial_float64(uint8_t * * ptr, float64_t v);
+extern int  serial_string(uint8_t * ptr, char * str);
+extern int16_t unserial_int16(uint8_t * * ptr);
+extern uint16_t unserial_uint16(uint8_t * * ptr);
+extern int32_t unserial_int32(uint8_t * * ptr);
+extern uint32_t unserial_uint32(uint8_t * * ptr);
+extern int64_t unserial_int64(uint8_t * * ptr);
+extern uint64_t unserial_uint64(uint8_t * * ptr);
+extern float64_t unserial_float64(uint8_t * * ptr);
+extern int unserial_string(uint8_t * ptr, char * str);
+
+/*
+
+                         Serialisation Macros
+
+    These macros use a uint8_t pointer, ser_ptr, which must be
+    defined by the code which uses them.
+
+*/
+
+#ifndef __SERIAL_H_
+#define __SERIAL_H_ 1
+
+/*  ser_declare  --  Declare ser_ptr locally within a function.  */
+#define ser_declare     uint8_t *ser_ptr
+#define unser_declare   uint8_t *ser_ptr
+
+/*  ser_begin(x, s)  --  Begin serialisation into a buffer x of size s.  */
+#define ser_begin(x, s) ser_ptr = ((uint8_t *)(x))
+#define unser_begin(x, s) ser_ptr = ((uint8_t *)(x))
+
+/*  ser_length  --  Determine length in bytes of serialised into a
+                    buffer x.  */
+#define ser_length(x)  (ser_ptr - (uint8_t *)(x))
+#define unser_length(x)  (ser_ptr - (uint8_t *)(x))
+
+/*  ser_end(x, s)  --  End serialisation into a buffer x of size s.  */
+#define ser_end(x, s)   ASSERT(ser_length(x) <= (s))
+#define unser_end(x, s)   ASSERT(ser_length(x) <= (s))
+
+/*  ser_check(x, s)  --  Verify length of serialised data in buffer x is
+                         expected length s.  */
+#define ser_check(x, s) ASSERT(ser_length(x) == (s))
+
+/*                          Serialisation                   */
+
+/*  8 bit signed integer  */
+#define ser_int8(x)     *ser_ptr++ = (x)
+/*  8 bit unsigned integer  */
+#define ser_uint8(x)    *ser_ptr++ = (x)
+
+/*  16 bit signed integer  */
+#define ser_int16(x)    serial_int16(&ser_ptr, x)
+/*  16 bit unsigned integer  */
+#define ser_uint16(x)   serial_uint16(&ser_ptr, x)
+
+/*  32 bit signed integer  */
+#define ser_int32(x)    serial_int32(&ser_ptr, x)
+/*  32 bit unsigned integer  */
+#define ser_uint32(x)   serial_uint32(&ser_ptr, x)
+
+/*  64 bit signed integer  */
+#define ser_int64(x)    serial_int64(&ser_ptr, x)
+/*  64 bit unsigned integer  */
+#define ser_uint64(x)   serial_uint64(&ser_ptr, x)
+
+
+/*  64 bit IEEE floating point number  */
+#define ser_float64(x)  serial_float64(&ser_ptr, x)
+
+/*  128 bit signed integer  */
+#define ser_int128(x)   memcpy(ser_ptr, x, sizeof(int128_t)), ser_ptr += sizeof(int128_t)
+
+/*  Binary byte stream len bytes not requiring serialisation  */
+#define ser_bytes(x, len) memcpy(ser_ptr, (x), (len)), ser_ptr += (len)
+
+/*  Binary byte stream not requiring serialisation (length obtained by sizeof)  */
+#define ser_buffer(x)   ser_bytes((x), (sizeof (x)))
+
+/* Binary string not requiring serialization */
+#define ser_string(x)   ser_ptr += serial_string(ser_ptr, (x))
+
+/*                         Unserialisation                  */
+
+/*  8 bit signed integer  */
+#define unser_int8(x)   (x) = *ser_ptr++
+/*  8 bit unsigned integer  */
+#define unser_uint8(x)  (x) = *ser_ptr++
+
+/*  16 bit signed integer  */
+#define unser_int16(x)  (x) = unserial_int16(&ser_ptr)
+/*  16 bit unsigned integer  */
+#define unser_uint16(x) (x) = unserial_uint16(&ser_ptr)
+
+/*  32 bit signed integer  */
+#define unser_int32(x)  (x) = unserial_int32(&ser_ptr)
+/*  32 bit unsigned integer  */
+#define unser_uint32(x) (x) = unserial_uint32(&ser_ptr)
+
+/*  64 bit signed integer  */
+#define unser_int64(x)  (x) = unserial_int64(&ser_ptr)
+/*  64 bit unsigned integer  */
+#define unser_uint64(x) (x) = unserial_uint64(&ser_ptr)
+
+/*  64 bit IEEE floating point number  */
+#define unser_float64(x)(x) = unserial_float64(&ser_ptr)
+
+/*  128 bit signed integer  */
+#define unser_int128(x) memcpy(ser_ptr, x, sizeof(int128_t)), ser_ptr += sizeof(int128_t)
+
+/*  Binary byte stream len bytes not requiring serialisation  */
+#define unser_bytes(x, len) memcpy((x), ser_ptr, (len)), ser_ptr += (len)
+
+/*  Binary byte stream not requiring serialisation (length obtained by sizeof)  */
+#define unser_buffer(x)  unser_bytes((x), (sizeof (x)))
+
+/* Binary string not requiring serialization */
+#define unser_string(x) ser_ptr += unserial_string(ser_ptr, (x))
+
+#endif /* __SERIAL_H_ */
diff --git a/bacula/src/lib/signal.c b/bacula/src/lib/signal.c
new file mode 100644 (file)
index 0000000..e4d41b6
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  Signal handlers for Bacula daemons
+ *
+ *   Kern Sibbald, April 2000
+ * 
+ * Note, we probably should do a core dump for the serious
+ * signals such as SIGBUS, SIGPFE, ... 
+ * Also, for SIGHUP and SIGUSR1, we should re-read the 
+ * configuration file.  However, since this is a "general"  
+ * routine, we leave it to the individual daemons to
+ * tweek their signals after calling this routine.
+ *
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+
+#ifndef _NSIG
+#define BA_NSIG 100
+#else
+#define BA_NSIG _NSIG
+#endif
+
+extern char my_name[];
+extern char *exepath;
+extern char *exename;
+
+static const char *sig_names[BA_NSIG+1];
+
+typedef void (SIG_HANDLER)(int sig);
+static SIG_HANDLER *exit_handler;
+
+/* main process id */
+static pid_t main_pid = 0;
+
+/* 
+ * Handle signals here
+ */
+static void signal_handler(int sig)
+{
+   static int already_dead = FALSE;
+   struct sigaction sigdefault;
+
+   if (already_dead) {
+      abort();
+   }
+   already_dead = TRUE;
+   if (sig == SIGTERM) {
+      Emsg1(M_TERM, -1, "Shutting down Bacula service: %s ...\n", my_name);
+   } else {
+      Emsg2(M_FATAL, -1, "Interrupted by signal %d: %s\n", sig, sig_names[sig]);
+   }
+
+#ifdef TRACEBACK
+   if (sig != SIGTERM) {
+      static char *argv[4];
+      static char pid_buf[20];
+      static char btpath[400];
+      pid_t pid;
+
+      Dmsg1(000, "Kaboom! Got signal %d. Attempting traceback\n", sig);
+      if (strlen(exepath) + 12 > (int)sizeof(btpath)) {
+         strcpy(btpath, "btraceback");
+      } else {
+        strcpy(btpath, exepath);
+         strcat(btpath, "/btraceback");
+      }
+      strcat(exepath, "/");
+      strcat(exepath, exename);
+      if (chdir(working_directory) !=0) {  /* dump in working directory */
+         Dmsg1(000, "chdir failed. ERR=%s\n", strerror(errno));
+      }
+      unlink("./core");               /* get rid of any old core file */
+      sprintf(pid_buf, "%d", main_pid);
+      Dmsg1(300, "Working=%s\n", working_directory);
+      Dmsg1(300, "btpath=%s\n", btpath);
+      Dmsg1(300, "exepath=%s\n", exepath);
+      switch (pid = fork()) {
+      case -1:                       /* error */
+        break;
+      case 0:                        /* child */
+        argv[0] = btpath;            /* path to btraceback */
+        argv[1] = exepath;           /* path to exe */
+        argv[2] = pid_buf;
+        argv[3] = (char *)NULL;
+        if (execv(btpath, argv) != 0) {
+            printf("execv: %s failed: ERR=%s\n", btpath, strerror(errno));
+        }
+        exit(-1);
+      default:                       /* parent */
+        break;
+      }
+      sigdefault.sa_flags = 0;
+      sigdefault.sa_handler = SIG_DFL;
+      sigfillset(&sigdefault.sa_mask);
+
+      sigaction(sig,  &sigdefault, NULL);
+      if (pid > 0) {
+         Dmsg0(500, "Doing waitpid\n");
+        waitpid(pid, NULL, 0);       /* wait for child to produce dump */
+         Dmsg0(500, "Done waitpid\n");
+        exit_handler(1);             /* clean up if possible */
+         Dmsg0(500, "Done exit_handler\n");
+      } else {
+         Dmsg0(500, "Doing sleep\n");
+        sleep(30);
+      }
+      abort();                       /* produce dump */
+   }
+#endif
+
+   exit_handler(1);
+}
+
+/*
+ * Init stack dump by saving main process id --
+ *   needed by debugger to attach to this program.
+ */
+void init_stack_dump(void)
+{
+   main_pid = getpid();               /* save main thread's pid */
+}
+
+/*
+ * Initialize signals
+ */
+void init_signals(void terminate(int sig))
+{
+   struct sigaction sighandle;
+   struct sigaction sigignore;
+   struct sigaction sigdefault;
+#ifdef _sys_nsig
+   int i;
+
+   exit_handler = terminate;
+   if (BA_NSIG < _sys_nsig)
+      Emsg2(M_ABORT, 0, "BA_NSIG too small (%d) should be (%d)\n", BA_NSIG, _sys_nsig);
+
+   for (i=0; i<_sys_nsig; i++)
+      sig_names[i] = _sys_siglist[i];
+#else
+   exit_handler = terminate;
+   sig_names[0]         = "UNKNOWN SIGNAL";
+   sig_names[SIGHUP]    = "Hangup";
+   sig_names[SIGINT]    = "Interrupt";
+   sig_names[SIGQUIT]   = "Quit";
+   sig_names[SIGILL]    = "Illegal instruction";;
+   sig_names[SIGTRAP]   = "Trace/Breakpoint trap";
+   sig_names[SIGABRT]   = "Abort";
+#ifdef SIGEMT
+   sig_names[SIGEMT]    = "EMT instruction (Emulation Trap)";
+#endif
+#ifdef SIGIOT
+   sig_names[SIGIOT]    = "IOT trap";
+#endif
+   sig_names[SIGBUS]    = "BUS error";
+   sig_names[SIGFPE]    = "Floating-point exception";
+   sig_names[SIGKILL]   = "Kill, unblockable";
+   sig_names[SIGUSR1]   = "User-defined signal 1";
+   sig_names[SIGSEGV]   = "Segmentation violation";
+   sig_names[SIGUSR2]   = "User-defined signal 2";
+   sig_names[SIGPIPE]   = "Broken pipe";
+   sig_names[SIGALRM]   = "Alarm clock";
+   sig_names[SIGTERM]   = "Termination";
+#ifdef SIGSTKFLT
+   sig_names[SIGSTKFLT] = "Stack fault";
+#endif
+   sig_names[SIGCHLD]   = "Child status has changed";
+   sig_names[SIGCONT]   = "Continue";
+   sig_names[SIGSTOP]   = "Stop, unblockable";
+   sig_names[SIGTSTP]   = "Keyboard stop";
+   sig_names[SIGTTIN]   = "Background read from tty";
+   sig_names[SIGTTOU]   = "Background write to tty";
+   sig_names[SIGURG]    = "Urgent condition on socket";
+   sig_names[SIGXCPU]   = "CPU limit exceeded";
+   sig_names[SIGXFSZ]   = "File size limit exceeded";
+   sig_names[SIGVTALRM] = "Virtual alarm clock";
+   sig_names[SIGPROF]   = "Profiling alarm clock";
+   sig_names[SIGWINCH]  = "Window size change";
+   sig_names[SIGIO]     = "I/O now possible";
+#ifdef SIGPWR
+   sig_names[SIGPWR]    = "Power failure restart";
+#endif
+#ifdef SIGWAITING
+   sig_names[SIGWAITING] = "No runnable lwp";
+#endif
+#ifdef SIGLWP
+   sig_name[SIGLWP]     = "SIGLWP special signal used by thread library";
+#endif
+#ifdef SIGFREEZE
+   sig_names[SIGFREEZE] = "Checkpoint Freeze";
+#endif
+#ifdef SIGTHAW
+   sig_names[SIGTHAW]   = "Checkpoint Thaw";
+#endif
+#ifdef SIGCANCEL
+   sig_names[SIGCANCEL] = "Thread Cancellation";
+#endif
+#ifdef SIGLOST
+   sig_names[SIGLOST]   = "Resource Lost (e.g. record-lock lost)";
+#endif
+#endif
+
+
+/* Now setup signal handlers */
+   sighandle.sa_flags = 0;
+   sighandle.sa_handler = signal_handler;
+   sigfillset(&sighandle.sa_mask);
+   sigignore.sa_flags = 0;
+   sigignore.sa_handler = SIG_IGN;      
+   sigfillset(&sigignore.sa_mask);
+   sigdefault.sa_flags = 0;
+   sigdefault.sa_handler = SIG_DFL;
+   sigfillset(&sigdefault.sa_mask);
+
+
+   sigaction(SIGPIPE,  &sigignore, NULL);
+   sigaction(SIGCHLD,  &sigignore, NULL);
+   sigaction(SIGCONT,  &sigignore, NULL);
+   sigaction(SIGPROF,  &sigignore, NULL);
+   sigaction(SIGWINCH, &sigignore, NULL);
+   sigaction(SIGIO,    &sighandle, NULL);     
+
+   sigaction(SIGINT,   &sigdefault, NULL);    
+   sigaction(SIGXCPU,  &sigdefault, NULL);
+   sigaction(SIGXFSZ,  &sigdefault, NULL);
+
+   sigaction(SIGHUP,   &sighandle, NULL);
+   sigaction(SIGQUIT,  &sighandle, NULL);   
+   sigaction(SIGILL,   &sighandle, NULL);    
+   sigaction(SIGTRAP,  &sighandle, NULL);   
+/* sigaction(SIGABRT,  &sighandle, NULL);   */
+#ifdef SIGEMT
+   sigaction(SIGEMT,   &sighandle, NULL);
+#endif
+#ifdef SIGIOT
+/* sigaction(SIGIOT,   &sighandle, NULL);  used by debugger */
+#endif
+   sigaction(SIGBUS,   &sighandle, NULL);    
+   sigaction(SIGFPE,   &sighandle, NULL);    
+   sigaction(SIGKILL,  &sighandle, NULL);   
+   sigaction(SIGUSR1,  &sighandle, NULL);   
+   sigaction(SIGSEGV,  &sighandle, NULL);   
+   sigaction(SIGUSR2,  &sighandle, NULL);
+   sigaction(SIGALRM,  &sighandle, NULL);   
+   sigaction(SIGTERM,  &sighandle, NULL);   
+#ifdef SIGSTKFLT
+   sigaction(SIGSTKFLT, &sighandle, NULL); 
+#endif
+   sigaction(SIGSTOP,  &sighandle, NULL);   
+   sigaction(SIGTSTP,  &sighandle, NULL);   
+   sigaction(SIGTTIN,  &sighandle, NULL);   
+   sigaction(SIGTTOU,  &sighandle, NULL);   
+   sigaction(SIGURG,   &sighandle, NULL);    
+   sigaction(SIGVTALRM, &sighandle, NULL); 
+#ifdef SIGPWR
+   sigaction(SIGPWR,   &sighandle, NULL);    
+#endif
+#ifdef SIGWAITING
+   sigaction(SIGWAITING,&sighandle, NULL);
+#endif
+#ifdef SIGLWP
+   sigaction(SIGLWP,   &sighandle, NULL);
+#endif
+#ifdef SIGFREEZE
+   sigaction(SIGFREEZE, &sighandle, NULL);
+#endif
+#ifdef SIGTHAW
+   sigaction(SIGTHAW,  &sighandle, NULL);
+#endif
+#ifdef SIGCANCEL
+   sigaction(SIGCANCEL, &sighandle, NULL);
+#endif
+#ifdef SIGLOST
+   sigaction(SIGLOST,  &sighandle, NULL);
+#endif
+}
diff --git a/bacula/src/lib/smartall.c b/bacula/src/lib/smartall.c
new file mode 100644 (file)
index 0000000..cbde11d
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+
+                        S M A R T A L L O C
+                       Smart Memory Allocator
+
+       Evolved   over   several  years,  starting  with  the  initial
+       SMARTALLOC code for AutoSketch in 1986, guided  by  the  Blind
+       Watchbreaker,  John  Walker.  Isolated in this general-purpose
+       form in  September  of  1989.   Updated  with  be  more  POSIX
+       compliant  and  to  include Web-friendly HTML documentation in
+       October  of  1998  by  the  same  culprit.    For   additional
+       information and the current version visit the Web page:
+
+                 http://www.fourmilab.ch/smartall/
+
+*/
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+/* Use the real routines here */
+#undef realloc
+#undef calloc
+#undef malloc
+#undef free
+      
+#define FULL_SM_CHECK 1
+
+/*LINTLIBRARY*/
+
+
+#ifdef SMARTALLOC
+
+extern char my_name[];               /* daemon name */
+
+typedef unsigned short sm_ushort;
+
+#define EOS      '\0'              /* End of string sentinel */
+#define sm_min(a, b) ((a) < (b) ? (a) : (b))
+
+/*  Queue data structures  */
+
+/*  Memory allocation control structures and storage.  */
+
+struct abufhead {
+       struct b_queue abq;          /* Links on allocated queue */
+       unsigned ablen;            /* Buffer length in bytes */
+       char *abfname;             /* File name pointer */
+       sm_ushort ablineno;        /* Line number of allocation */ 
+};
+
+static struct b_queue abqueue = {    /* Allocated buffer queue */
+       &abqueue, &abqueue
+};
+
+static Boolean bufimode = False;   /* Buffers not tracked when True */
+
+#define HEAD_SIZE BALIGN(sizeof(struct abufhead))
+
+
+/*  SMALLOC  --  Allocate buffer, enqueing on the orphaned buffer
+                tracking list.  */
+
+static void *smalloc(char *fname, int lineno, unsigned int nbytes)
+{
+       char *buf;
+
+       /* Note:  Unix  MALLOC  actually  permits  a zero length to be
+          passed and allocates a valid block with  zero  user  bytes.
+          Such  a  block  can  later  be expanded with realloc().  We
+           disallow this based on the belief that it's better to  make
+          a  special case and allocate one byte in the rare case this
+          is desired than to miss all the erroneous occurrences where
+          buffer length calculation code results in a zero.  */
+
+       ASSERT(nbytes > 0);
+
+       nbytes += HEAD_SIZE + 1;
+       if ((buf = (char *) malloc(nbytes)) != NULL) {
+          /* Enqueue buffer on allocated list */
+          qinsert(&abqueue, (struct b_queue *) buf);
+          ((struct abufhead *) buf)->ablen = nbytes;
+          ((struct abufhead *) buf)->abfname = bufimode ? NULL : fname;
+          ((struct abufhead *) buf)->ablineno = (sm_ushort) lineno;
+          /* Emplace end-clobber detector at end of buffer */
+          buf[nbytes - 1] = (((long) buf) & 0xFF) ^ 0xC5;
+          buf += HEAD_SIZE;  /* Increment to user data start */
+       }
+#ifdef FULL_SM_CHECK
+       sm_check(fname, lineno, True);
+#endif
+        Dmsg4(1150, "smalloc %d at %x from %s:%d\n", nbytes, buf, fname, lineno);
+       return (void *) buf;
+}
+
+/*  SM_NEW_OWNER -- Update the File and line number for a buffer
+                   This is to accomodate mem_pool. */
+
+void sm_new_owner(char *fname, int lineno, char *buf)
+{
+       buf -= HEAD_SIZE;  /* Decrement to header */
+       ((struct abufhead *) buf)->abfname = bufimode ? NULL : fname;
+       ((struct abufhead *) buf)->ablineno = (sm_ushort) lineno;
+       return;
+}
+
+/*  SM_FREE  --  Update free pool availability.  FREE is never called
+                except  through  this interface or by actuallyfree().
+                free(x)  is  defined  to  generate  a  call  to  this
+                routine.  */
+
+void sm_free(char *file, int line, void *fp)
+{
+       char *cp = (char *) fp;
+       struct b_queue *qp;
+
+#ifdef FULL_SM_CHECK
+       sm_check(__FILE__, __LINE__, True);
+#endif
+       if (cp == NULL) {
+           Emsg2(M_ABORT, 0, "Attempt to free NULL called from %s:%d\n", file, line);
+       }
+
+       cp -= HEAD_SIZE;
+       qp = (struct b_queue *) cp;
+
+        Dmsg4(1150, "sm_free %d at %x from %s:%d\n", 
+             ((struct abufhead *)cp)->ablen, fp, 
+             ((struct abufhead *)cp)->abfname, ((struct abufhead *)cp)->ablineno);
+
+       /* The following assertions will catch virtually every release
+           of an address which isn't an allocated buffer. */
+       if (qp->qnext->qprev != qp) {
+           Emsg2(M_ABORT, 0, "qp->qnext->qprev != qp called from %s:%d\n", file, line);
+       }
+       if (qp->qprev->qnext != qp) {
+           Emsg2(M_ABORT, 0, "qp->qprev->qnext != qp called from %s:%d\n", file, line);
+       }
+
+       /* The following assertion detects storing off the  end  of  the
+          allocated  space in the buffer by comparing the end of buffer
+          checksum with the address of the buffer.  */
+
+       if (((unsigned char *) cp)[((struct abufhead *) cp)->ablen - 1] !=
+                ((((long) cp) & 0xFF) ^ 0xC5)) {
+           Emsg2(M_ABORT, 0, "Buffer overrun called from %s:%d\n", file, line);
+       }
+
+
+       qdchain(qp);
+
+       /* Now we wipe the contents of  the  just-released  buffer  with
+           "designer  garbage"  (Duff  Kurland's  phrase) of alternating
+          bits.  This is intended to ruin the day for any miscreant who
+           attempts to access data through a pointer into storage that's
+          been previously released. */
+
+       memset(cp, 0xAA, (int) ((struct abufhead *) cp)->ablen);
+
+       free(cp);
+}
+
+/*  SM_MALLOC  --  Allocate buffer.  NULL is returned if no memory
+                  was available.  */
+
+void *sm_malloc(char *fname, int lineno, unsigned int nbytes)
+{
+       void *buf;
+
+       if ((buf = smalloc(fname, lineno, nbytes)) != NULL) {
+
+          /* To catch sloppy code that assumes  buffers  obtained  from
+             malloc()  are  zeroed,  we  preset  the buffer contents to
+              "designer garbage" consisting of alternating bits.  */
+
+          memset(buf, 0x55, (int) nbytes);
+       }
+       return buf;
+}
+
+/*  SM_CALLOC  --  Allocate an array and clear it to zero.  */
+
+void *sm_calloc(char *fname, int lineno,
+               unsigned int nelem, unsigned int elsize)
+{
+       void *buf;
+
+       if ((buf = smalloc(fname, lineno, nelem * elsize)) != NULL) {
+          memset(buf, 0, (int) (nelem * elsize));
+       }
+       return buf;
+}
+
+/*  SM_REALLOC --  Adjust the size of a  previously  allocated  buffer.
+                    Note  that  the trick of "resurrecting" a previously
+                   freed buffer with realloc() is NOT supported by this
+                   function.   Further, because of the need to maintain
+                   our control storage, SM_REALLOC must always allocate
+                   a  new  block  and  copy  the data in the old block.
+                   This may result in programs which make heavy use  of
+                   realloc() running much slower than normally.  */
+
+void *sm_realloc(char *fname, int lineno, void *ptr, unsigned int size)
+{
+       unsigned osize;
+       void *buf;
+       char *cp = (char *) ptr;
+
+#ifdef FULL_SM_CHECK
+       sm_check(fname, lineno, True);
+#endif
+       if (size <= 0) {
+           e_msg(fname, lineno, M_ABORT, 0, "sm_realloc size: %d\n", size);
+       }
+
+       /*  If  the  old  block  pointer  is  NULL, treat realloc() as a
+          malloc().  SVID is silent  on  this,  but  many  C  libraries
+          permit this.  */
+
+       if (ptr == NULL)
+          return sm_malloc(fname, lineno, size);
+
+       /* If the old and new sizes are the same, be a nice guy and just
+          return the buffer passed in.  */
+
+       cp -= HEAD_SIZE;
+       osize = ((struct abufhead *) cp)->ablen -
+               (HEAD_SIZE + 1);
+       if (size == osize) {
+          return ptr;
+       }
+
+       /* Sizes differ.  Allocate a new buffer of the  requested  size.
+           If  we  can't  obtain  such a buffer, act as defined in SVID:
+          return NULL from  realloc()  and  leave  the  buffer  in  PTR
+          intact.  */
+
+       if ((buf = smalloc(fname, lineno, size)) != NULL) {
+          memcpy(buf, ptr, (int) sm_min(size, osize));
+          /* If the new buffer is larger than the old, fill the balance
+              of it with "designer garbage". */
+          if (size > osize) {
+             memset(((char *) buf) + osize, 0x55, (int) (size - osize));
+          }
+
+          /* All done.  Free and dechain the original buffer. */
+
+          sm_free(__FILE__, __LINE__, ptr);
+       }
+        Dmsg4(150, "sm_realloc %d at %x from %s:%d\n", size, buf, fname, lineno);
+#ifdef FULL_SM_CHECK
+       sm_check(fname, lineno, True);
+#endif
+       return buf;
+}
+
+/*  ACTUALLYMALLOC  -- Call the system malloc() function to obtain
+                       storage which will eventually be released
+                       by system or library routines not compiled
+                       using SMARTALLOC.  */
+
+void *actuallymalloc(unsigned int size)
+{
+       return malloc(size);
+}
+
+/*  ACTUALLYCALLOC  -- Call the system calloc() function to obtain
+                       storage which will eventually be released
+                       by system or library routines not compiled
+                       using SMARTALLOC.  */
+
+void *actuallycalloc(unsigned int nelem, unsigned int elsize)
+{
+       return calloc(nelem, elsize);
+}
+
+/*  ACTUALLYREALLOC  --  Call the system realloc() function to obtain
+                        storage which will eventually be released
+                        by system or library routines not compiled
+                        using SMARTALLOC.  */
+
+void *actuallyrealloc(void *ptr, unsigned int size)
+{
+       return realloc(ptr, size);
+}
+
+/*  ACTUALLYFREE  --  Interface to system free() function to release
+                     buffers allocated by low-level routines. */
+
+void actuallyfree(void *cp)
+{
+       free(cp);
+}
+
+/*  SM_DUMP  --  Print orphaned buffers (and dump them if BUFDUMP is
+                True). */
+
+void sm_dump(Boolean bufdump)
+{
+       struct abufhead *ap = (struct abufhead *) abqueue.qnext;
+
+       while (ap != (struct abufhead *) &abqueue) {
+
+          if ((ap == NULL) ||
+              (ap->abq.qnext->qprev != (struct b_queue *) ap) || 
+              (ap->abq.qprev->qnext != (struct b_queue *) ap)) {
+             fprintf(stderr,
+                 "\nOrphaned buffers exist.  Dump terminated following\n");
+             fprintf(stderr,
+                 "  discovery of bad links in chain of orphaned buffers.\n");
+             fprintf(stderr,
+                 "  Buffer address with bad links: %lx\n", (long) ap);
+             break;
+          }
+
+          if (ap->abfname != NULL) {
+             unsigned memsize = ap->ablen - (HEAD_SIZE + 1);
+             char errmsg[80];
+
+             sprintf(errmsg,
+                "Orphaned buffer:  %6u bytes allocated at line %d of %s %s\n",
+                memsize, ap->ablineno, my_name, ap->abfname
+             );
+              fprintf(stderr, "%s", errmsg);
+             if (bufdump) {
+                unsigned llen = 0;
+                char *cp = ((char *) ap) + HEAD_SIZE;
+
+                errmsg[0] = EOS;
+                while (memsize) {
+                   if (llen >= 16) {
+                       strcat(errmsg, "\n");
+                      llen = 0;
+                       fprintf(stderr, "%s", errmsg);
+                      errmsg[0] = EOS;
+                   }
+                    sprintf(errmsg + strlen(errmsg), " %02X",
+                      (*cp++) & 0xFF);
+                   llen++;
+                   memsize--;
+                }
+                 fprintf(stderr, "%s\n", errmsg);
+             }
+          }
+          ap = (struct abufhead *) ap->abq.qnext;
+       }
+}
+
+/*  SM_CHECK --  Check the buffers and dump if any damage exists. */
+void sm_check(char *fname, int lineno, Boolean bufdump)
+{
+       if (!sm_check_rtn(fname, lineno, bufdump)) {
+           Emsg2(M_ABORT, 0, "Damaged buffer found. Called from %s:%d\n",
+             fname, lineno);
+       }
+}
+
+/*  SM_CHECK_RTN -- Check the buffers and return 1 if OK otherwise 0 */
+int sm_check_rtn(char *fname, int lineno, Boolean bufdump)
+{
+       struct abufhead *ap = (struct abufhead *) abqueue.qnext;
+       int bad, badbuf = 0;
+
+       while (ap != (struct abufhead *) &abqueue) {
+          bad = 0;
+          if ((ap == NULL) ||
+              (ap->abq.qnext->qprev != (struct b_queue *) ap)) {
+             bad = 0x1;
+          }
+          if (ap->abq.qprev->qnext != (struct b_queue *) ap) { 
+             bad |= 0x2;
+          }
+          if (((unsigned char *) ap)[((struct abufhead *) ap)->ablen - 1] !=
+               ((((long) ap) & 0xFF) ^ 0xC5)) {
+             bad |= 0x4;
+          }
+          badbuf |= bad;
+          if (bad) {
+             Emsg2(M_FATAL, 0, 
+                 "\nDamaged buffers found at %s:%d\n", fname, lineno);
+             if (bad & 0x1) {
+                 Emsg0(M_FATAL, 0, "  discovery of bad prev link.\n");
+             }
+             if (bad & 0x2) {
+                 Emsg0(M_FATAL, 0, "  discovery of bad next link.\n");
+             }
+             if (bad & 0x4) {
+                 Emsg0(M_FATAL, 0, "  discovery of data overrun.\n");
+             }
+
+              Emsg1(M_FATAL, 0, "  Buffer address: %lx\n", (long) ap);
+
+             if (ap->abfname != NULL) {
+                unsigned memsize = ap->ablen - (HEAD_SIZE + 1);
+                char errmsg[80];
+
+                sprintf(errmsg,
+                   "Damaged buffer:  %6u bytes allocated at line %d of %s %s\n",
+                   memsize, ap->ablineno, my_name, ap->abfname
+                );
+                 Emsg1(M_FATAL, 0, "%s", errmsg);
+                if (bufdump) {
+                   unsigned llen = 0;
+                   char *cp = ((char *) ap) + HEAD_SIZE;
+
+                   errmsg[0] = EOS;
+                   while (memsize) {
+                      if (llen >= 16) {
+                          strcat(errmsg, "\n");
+                         llen = 0;
+                          fprintf(stderr, "%s", errmsg);
+                         errmsg[0] = EOS;
+                      }
+                      if (*cp < 0x20) {
+                          sprintf(errmsg + strlen(errmsg), " %02X",
+                            (*cp++) & 0xFF);
+                      } else {
+                          sprintf(errmsg + strlen(errmsg), " %c ",
+                            (*cp++) & 0xFF);
+                      }
+                      llen++;
+                      memsize--;
+                   }
+                    Emsg1(M_FATAL, 0, "%s\n", errmsg);
+                }
+             }
+          }
+          ap = (struct abufhead *) ap->abq.qnext;
+       }
+       return badbuf ? 0 : 1;
+}
+
+
+/*  SM_STATIC  --  Orphaned buffer detection can be disabled  (for  such
+                  items  as buffers allocated during initialisation) by
+                  calling   sm_static(1).    Normal   orphaned   buffer
+                  detection  can be re-enabled with sm_static(0).  Note
+                  that all the other safeguards still apply to  buffers
+                  allocated  when  sm_static(1)  mode is in effect.  */
+
+void sm_static(int mode)
+{
+       bufimode = (Boolean) (mode != 0);
+}
+
+#endif
diff --git a/bacula/src/lib/smartall.h b/bacula/src/lib/smartall.h
new file mode 100644 (file)
index 0000000..13acdf0
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+
+        Definitions for the smart memory allocator
+
+*/
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#ifdef SMARTALLOC
+
+typedef enum {False = 0, True = 1} Boolean;
+
+extern void *sm_malloc(char *fname, int lineno, unsigned int nbytes),
+            *sm_calloc(char *fname, int lineno,
+                unsigned int nelem, unsigned int elsize),
+            *sm_realloc(char *fname, int lineno, void *ptr, unsigned int size),
+            *actuallymalloc(unsigned int size),
+            *actuallycalloc(unsigned int nelem, unsigned int elsize),
+            *actuallyrealloc(void *ptr, unsigned int size);
+extern void sm_free(char *fname, int lineno, void *fp);
+extern void actuallyfree(void *cp),
+            sm_dump(Boolean bufdump), sm_static(int mode);
+extern void sm_new_owner(char *fname, int lineno, char *buf);
+
+#ifdef SMCHECK
+extern void sm_check(char *fname, int lineno, Boolean bufdump);
+extern int sm_check_rtn(char *fname, int lineno, Boolean bufdump);
+#else
+#define sm_check(f, l, fl)
+#define sm_check_rtn(f, l, fl) 1
+#endif
+
+
+/* Redefine standard memory allocator calls to use our routines
+   instead. */
+
+#define free(x)        sm_free(__FILE__, __LINE__, (x))
+#define cfree(x)       sm_free(__FILE__, __LINE__, (x))
+#define malloc(x)      sm_malloc(__FILE__, __LINE__, (x))
+#define calloc(n,e)    sm_calloc(__FILE__, __LINE__, (n), (e))
+#define realloc(p,x)   sm_realloc(__FILE__, __LINE__, (p), (x))
+
+#else
+
+/* If SMARTALLOC is disabled, define its special calls to default to
+   the standard routines.  */
+
+#define actuallyfree(x)      free(x)
+#define actuallymalloc(x)    malloc(x)
+#define actuallycalloc(x,y)  calloc(x,y)
+#define actuallyrealloc(x,y) realloc(x,y)
+#define sm_dump(x)
+#define sm_static(x)
+#define sm_new_owner(a, b, c)
+#define sm_malloc(f, l, n) malloc(n)
+
+#define sm_check(f, l, fl)
+#define sm_check_rtn(f, l, fl) 1
+
+extern void *b_malloc();
+#define malloc(x) b_malloc(__FILE__, __LINE__, (x))                  
+
+
+#endif
diff --git a/bacula/src/lib/tcpd.h b/bacula/src/lib/tcpd.h
new file mode 100644 (file)
index 0000000..f281b9c
--- /dev/null
@@ -0,0 +1,235 @@
+ /*
+  * @(#) tcpd.h 1.5 96/03/19 16:22:24
+  * 
+  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+  */
+
+/* 
+ * This version of the file has been hacked over by 
+ *   Kern Sibbald to make it compatible with C++ for 
+ *   the few functions that Bacula uses.  19 April 2002
+ *  It now compiles with C++ but remains untested.
+ *  A correct fix would require significantly more work.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Structure to describe one communications endpoint. */
+
+#define STRING_LENGTH   128             /* hosts, users, processes */
+
+struct host_info {
+    char    name[STRING_LENGTH];        /* access via eval_hostname(host) */
+    char    addr[STRING_LENGTH];        /* access via eval_hostaddr(host) */
+    struct sockaddr_in *sin;            /* socket address or 0 */
+    struct t_unitdata *unit;            /* TLI transport address or 0 */
+    struct request_info *request;       /* for shared information */
+};
+
+/* Structure to describe what we know about a service request. */
+
+struct request_info {
+    int     fd;                         /* socket handle */
+    char    user[STRING_LENGTH];        /* access via eval_user(request) */
+    char    daemon[STRING_LENGTH];      /* access via eval_daemon(request) */
+    char    pid[10];                    /* access via eval_pid(request) */
+    struct host_info client[1];         /* client endpoint info */
+    struct host_info server[1];         /* server endpoint info */
+    void  (*sink) ();                   /* datagram sink function or 0 */
+    void  (*hostname) ();               /* address to printable hostname */
+    void  (*hostaddr) ();               /* address to printable address */
+    void  (*cleanup) ();                /* cleanup function or 0 */
+    struct netconfig *config;           /* netdir handle */
+};
+
+/* Common string operations. Less clutter should be more readable. */
+
+#define STRN_CPY(d,s,l) { strncpy((d),(s),(l)); (d)[(l)-1] = 0; }
+
+#define STRN_EQ(x,y,l)  (strncasecmp((x),(y),(l)) == 0)
+#define STRN_NE(x,y,l)  (strncasecmp((x),(y),(l)) != 0)
+#define STR_EQ(x,y)     (strcasecmp((x),(y)) == 0)
+#define STR_NE(x,y)     (strcasecmp((x),(y)) != 0)
+
+ /*
+  * Initially, all above strings have the empty value. Information that
+  * cannot be determined at runtime is set to "unknown", so that we can
+  * distinguish between `unavailable' and `not yet looked up'. A hostname
+  * that we do not believe in is set to "paranoid".
+  */
+
+#define STRING_UNKNOWN  "unknown"       /* lookup failed */
+#define STRING_PARANOID "paranoid"      /* hostname conflict */
+
+extern char unknown[];
+extern char paranoid[];
+
+#define HOSTNAME_KNOWN(s) (STR_NE((s),unknown) && STR_NE((s),paranoid))
+
+#define NOT_INADDR(s) (s[strspn(s,"01234567890./")] != 0)
+
+/* Global functions. */
+
+#if defined(TLI) || defined(PTX) || defined(TLI_SEQUENT)
+extern void fromhost();                 /* get/validate client host info */
+#else
+#define fromhost sock_host              /* no TLI support needed */
+#endif
+
+extern int hosts_access(struct request_info *); /* access control */
+extern void shell_cmd();                /* execute shell command */
+extern char *percent_x();               /* do %<char> expansion */
+extern void rfc931();                   /* client name from RFC 931 daemon */
+extern void clean_exit();               /* clean up and exit */
+extern void refuse();                   /* clean up and exit */
+extern char *xgets();                   /* fgets() on steroids */
+extern char *split_at();                /* strchr() and split */
+extern unsigned long dot_quad_addr();   /* restricted inet_addr() */
+
+/* Global variables. */
+
+extern int allow_severity;              /* for connection logging */
+extern int deny_severity;               /* for connection logging */
+extern char *hosts_allow_table;         /* for verification mode redirection */
+extern char *hosts_deny_table;          /* for verification mode redirection */
+extern int hosts_access_verbose;        /* for verbose matching mode */
+extern int rfc931_timeout;              /* user lookup timeout */
+extern int resident;                    /* > 0 if resident process */
+
+ /*
+  * Routines for controlled initialization and update of request structure
+  * attributes. Each attribute has its own key.
+  */
+
+#ifdef __STDC__
+extern struct request_info *request_init(struct request_info *,...);
+extern struct request_info *request_set(struct request_info *,...);
+#else
+extern struct request_info *request_init();     /* initialize request */
+extern struct request_info *request_set();      /* update request structure */
+#endif
+
+#define RQ_FILE         1               /* file descriptor */
+#define RQ_DAEMON       2               /* server process (argv[0]) */
+#define RQ_USER         3               /* client user name */
+#define RQ_CLIENT_NAME  4               /* client host name */
+#define RQ_CLIENT_ADDR  5               /* client host address */
+#define RQ_CLIENT_SIN   6               /* client endpoint (internal) */
+#define RQ_SERVER_NAME  7               /* server host name */
+#define RQ_SERVER_ADDR  8               /* server host address */
+#define RQ_SERVER_SIN   9               /* server endpoint (internal) */
+
+ /*
+  * Routines for delayed evaluation of request attributes. Each attribute
+  * type has its own access method. The trivial ones are implemented by
+  * macros. The other ones are wrappers around the transport-specific host
+  * name, address, and client user lookup methods. The request_info and
+  * host_info structures serve as caches for the lookup results.
+  */
+
+extern char *eval_user();               /* client user */
+extern char *eval_hostname();           /* printable hostname */
+extern char *eval_hostaddr();           /* printable host address */
+extern char *eval_hostinfo();           /* host name or address */
+extern char *eval_client();             /* whatever is available */
+extern char *eval_server();             /* whatever is available */
+#define eval_daemon(r)  ((r)->daemon)   /* daemon process name */
+#define eval_pid(r)     ((r)->pid)      /* process id */
+
+/* Socket-specific methods, including DNS hostname lookups. */
+
+extern void sock_host(struct request_info *); 
+extern void sock_hostname();            /* translate address to hostname */
+extern void sock_hostaddr();            /* address to printable address */
+#define sock_methods(r) \
+        { (r)->hostname = sock_hostname; (r)->hostaddr = sock_hostaddr; }
+
+/* The System V Transport-Level Interface (TLI) interface. */
+
+#if defined(TLI) || defined(PTX) || defined(TLI_SEQUENT)
+extern void tli_host();                 /* look up endpoint addresses etc. */
+#endif
+
+ /*
+  * Problem reporting interface. Additional file/line context is reported
+  * when available. The jump buffer (tcpd_buf) is not declared here, or
+  * everyone would have to include <setjmp.h>.
+  */
+
+#ifdef __STDC__
+extern void tcpd_warn(char *, ...);     /* report problem and proceed */
+extern void tcpd_jump(char *, ...);     /* report problem and jump */
+#else
+extern void tcpd_warn();
+extern void tcpd_jump();
+#endif
+
+struct tcpd_context {
+    char   *file;                       /* current file */
+    int     line;                       /* current line */
+};
+extern struct tcpd_context tcpd_context;
+
+ /*
+  * While processing access control rules, error conditions are handled by
+  * jumping back into the hosts_access() routine. This is cleaner than
+  * checking the return value of each and every silly little function. The
+  * (-1) returns are here because zero is already taken by longjmp().
+  */
+
+#define AC_PERMIT       1               /* permit access */
+#define AC_DENY         (-1)            /* deny_access */
+#define AC_ERROR        AC_DENY         /* XXX */
+
+ /*
+  * In verification mode an option function should just say what it would do,
+  * instead of really doing it. An option function that would not return
+  * should clear the dry_run flag to inform the caller of this unusual
+  * behavior.
+  */
+
+extern void process_options();          /* execute options */
+extern int dry_run;                     /* verification flag */
+
+/* Bug workarounds. */
+
+#ifdef INET_ADDR_BUG                    /* inet_addr() returns struct */
+#define inet_addr fix_inet_addr
+extern long fix_inet_addr();
+#endif
+
+#ifdef BROKEN_FGETS                     /* partial reads from sockets */
+#define fgets fix_fgets
+extern char *fix_fgets();
+#endif
+
+#ifdef RECVFROM_BUG                     /* no address family info */
+#define recvfrom fix_recvfrom
+extern int fix_recvfrom();
+#endif
+
+#ifdef GETPEERNAME_BUG                  /* claims success with UDP */
+#define getpeername fix_getpeername
+extern int fix_getpeername();
+#endif
+
+#ifdef SOLARIS_24_GETHOSTBYNAME_BUG     /* lists addresses as aliases */
+#define gethostbyname fix_gethostbyname
+extern struct hostent *fix_gethostbyname();
+#endif
+
+#ifdef USE_STRSEP                       /* libc calls strtok() */
+#define strtok  fix_strtok
+extern char *fix_strtok();
+#endif
+
+#ifdef LIBC_CALLS_STRTOK                /* libc calls strtok() */
+#define strtok  my_strtok
+extern char *my_strtok();
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c
new file mode 100644 (file)
index 0000000..ab82295
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ *   util.c  miscellaneous utility subroutines for Bacula
+ * 
+ *    Kern Sibbald, MM
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "findlib/find.h"
+
+/*
+ * Various Bacula Utility subroutines
+ *
+ */
+
+/*
+ * Edit a number with commas, the supplied buffer
+ * must be at least 27 bytes long.
+ */
+char *edit_uint_with_commas(uint64_t val, char *buf)
+{
+   sprintf(buf, "%" lld, val);
+   return add_commas(buf, buf);
+}
+
+char *add_commas(char *val, char *buf)
+{
+   int len, nc;
+   char *p, *q;
+   int i;
+
+   if (val != buf) {
+      strcpy(buf, val);
+   }
+   len = strlen(buf);
+   if (len < 1) {
+      len = 1;
+   }
+   nc = (len - 1) / 3;
+   p = buf+len;
+   q = p + nc;
+   *q-- = *p--;
+   for ( ; nc; nc--) {
+      for (i=0; i < 3; i++) {
+         *q-- = *p--;
+      }
+      *q-- = ',';
+   }   
+   return buf;
+}
+
+
+/* Convert a string in place to lower case */
+void 
+lcase(char *str)
+{
+   while (*str) {
+      if (ISUPPER(*str))
+        *str = tolower((int)(*str));
+       str++;
+   }
+}
+
+/* Convert spaces to non-space character. 
+ * This makes scanf of fields containing spaces easier.
+ */
+void
+bash_spaces(char *str)
+{
+   while (*str) {
+      if (*str == ' ')
+        *str = 0x1;
+      str++;
+   }
+}
+
+/* Convert non-space characters (0x1) back into spaces */
+void
+unbash_spaces(char *str)
+{
+   while (*str) {
+     if (*str == 0x1)
+        *str = ' ';
+     str++;
+   }
+}
+
+/* Strip any trailing junk from the command */
+void strip_trailing_junk(char *cmd)
+{
+   char *p;
+   p = cmd + strlen(cmd) - 1;
+
+   /* strip trailing junk from command */
+   while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' '))
+      *p-- = 0;
+}
+
+/* Strip any trailing slashes from a directory path */
+void strip_trailing_slashes(char *dir)
+{
+   char *p;
+   p = dir + strlen(dir) - 1;
+
+   /* strip trailing slashes */
+   while ((p >= dir) && (*p == '/'))
+      *p-- = 0;
+}
+
+/*
+ * Skip spaces
+ *  Returns: 0 on failure (EOF)            
+ *          1 on success
+ *          new address in passed parameter 
+ */
+int skip_spaces(char **msg)
+{
+   char *p = *msg;
+   if (!p) {
+      return 0;
+   }
+   while (*p && *p == ' ') {
+      p++;
+   }
+   *msg = p;
+   return *p ? 1 : 0;
+}
+
+/*
+ * Skip nonspaces
+ *  Returns: 0 on failure (EOF)            
+ *          1 on success
+ *          new address in passed parameter 
+ */
+int skip_nonspaces(char **msg)
+{
+   char *p = *msg;
+
+   if (!p) {
+      return 0;
+   }
+   while (*p && *p != ' ') {
+      p++;
+   }
+   *msg = p;
+   return *p ? 1 : 0;
+}
+
+/* folded search for string - case insensitive */
+int
+fstrsch(char *a, char *b)   /* folded case search */
+{
+   register char *s1,*s2;
+   register char c1, c2;
+
+   s1=a;
+   s2=b;
+   while (*s1) {                     /* do it the fast way */
+      if ((*s1++ | 0x20) != (*s2++ | 0x20))
+        return 0;                    /* failed */
+   }
+   while (*a) {                      /* do it over the correct slow way */
+      if (ISUPPER(c1 = *a)) {
+        c1 = tolower((int)c1);
+      }
+      if (ISUPPER(c2 = *b)) {
+        c2 = tolower((int)c2);
+      }
+      if (c1 != c2) {
+        return 0;
+      }
+      a++;
+      b++;
+   }
+   return 1;
+}
+
+
+char *encode_time(time_t time, char *buf)
+{
+   struct tm tm;
+   int n;
+
+   if (localtime_r(&time, &tm)) {
+      n = sprintf(buf, "%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);
+   }
+   return buf+n;
+}
+
+/***********************************************************************
+ * Encode the mode bits into a 10 character string like LS does
+ ***********************************************************************/
+
+char *encode_mode(mode_t mode, char *buf)
+{
+  char *cp = buf;  
+
+  *cp++ = S_ISDIR(mode) ? 'd' : S_ISBLK(mode) ? 'b' : S_ISCHR(mode) ? 'c' :
+          S_ISLNK(mode) ? 'l' : '-';
+  *cp++ = mode & S_IRUSR ? 'r' : '-';
+  *cp++ = mode & S_IWUSR ? 'w' : '-';
+  *cp++ = (mode & S_ISUID
+               ? (mode & S_IXUSR ? 's' : 'S')
+               : (mode & S_IXUSR ? 'x' : '-'));
+  *cp++ = mode & S_IRGRP ? 'r' : '-';
+  *cp++ = mode & S_IWGRP ? 'w' : '-';
+  *cp++ = (mode & S_ISGID
+               ? (mode & S_IXGRP ? 's' : 'S')
+               : (mode & S_IXGRP ? 'x' : '-'));
+  *cp++ = mode & S_IROTH ? 'r' : '-';
+  *cp++ = mode & S_IWOTH ? 'w' : '-';
+  *cp++ = (mode & S_ISVTX
+               ? (mode & S_IXOTH ? 't' : 'T')
+               : (mode & S_IXOTH ? 'x' : '-'));
+  *cp = '\0';
+  return cp;
+}
+
+#ifdef WORKING
+extern char *getuser(uid_t uid);
+extern char *getgroup(gid_t gid);
+
+void print_ls_output(char *fname, char *lname, int type, struct stat *statp)
+{
+   char buf[1000]; 
+   char *p, *f;
+   int n;
+
+   p = encode_mode(statp->st_mode, buf);
+   n = sprintf(p, "  %2d ", (uint32_t)statp->st_nlink);
+   p += n;
+   n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid));
+   p += n;
+   n = sprintf(p, "%8ld  ", statp->st_size);
+   p += n;
+   p = encode_time(statp->st_ctime, p);
+   *p++ = ' ';
+   *p++ = ' ';
+   for (f=fname; *f; )
+      *p++ = *f++;
+   if (type == FT_LNK) {
+      *p++ = ' ';
+      *p++ = '-';
+      *p++ = '>';
+      *p++ = ' ';
+      /* Copy link name */
+      for (f=lname; *f; )
+        *p++ = *f++;
+   }
+   *p++ = '\n';
+   *p = 0;
+   fputs(buf, stdout);
+}
+#endif
+
+int do_shell_expansion(char *name)
+{
+/*  ****FIXME***** this should work for Win32 too */
+#define UNIX
+#ifdef UNIX
+#ifndef PATH_MAX
+#define PATH_MAX 512
+#endif
+
+   int pid, wpid, stat;
+   int waitstatus;
+   char *shellcmd;
+   void (*istat)(int), (*qstat)(int);
+   int i;
+   char echout[PATH_MAX + 256];
+   int pfd[2];
+   static char meta[] = "~\\$[]*?`'<>\"";
+   int found = FALSE;
+   int len;
+
+   /* Check if any meta characters are present */
+   len = strlen(meta);
+   for (i = 0; i < len; i++) {
+      if (strchr(name, meta[i])) {
+        found = TRUE;
+        break;
+      }
+   }
+   stat = 0;
+   if (found) {
+#ifdef nt
+       /* If the filename appears to be a DOS filename,
+          convert all backward slashes \ to Unix path
+          separators / and insert a \ infront of spaces. */
+       len = strlen(name);
+       if (len >= 3 && name[1] == ':' && name[2] == '\\') {
+         for (i=2; i<len; i++)
+             if (name[i] == '\\')
+                name[i] = '/';
+       }
+#else
+       /* Pass string off to the shell for interpretation */
+       if (pipe(pfd) == -1)
+         return 0;
+       switch(pid = fork()) {
+       case -1:
+         break;
+
+       case 0:                           /* child */
+         /* look for shell */
+          if ((shellcmd = getenv("SHELL")) == NULL)
+             shellcmd = "/bin/sh";
+         close(1); dup(pfd[1]);          /* attach pipes to stdin and stdout */
+         close(2); dup(pfd[1]);
+         for (i = 3; i < 32; i++)        /* close everything else */
+            close(i);
+          strcpy(echout, "echo ");        /* form echo command */
+         strcat(echout, name);
+          execl(shellcmd, shellcmd, "-c", echout, NULL); /* give to shell */
+          exit(127);                      /* shouldn't get here */
+
+       default:                          /* parent */
+         /* read output from child */
+         i = read(pfd[0], echout, sizeof echout);
+         echout[--i] = 0;                /* set end of string */
+         /* look for first word or first line. */
+         while (--i >= 0) {
+             if (echout[i] == ' ' || echout[i] == '\n')
+               echout[i] = 0;            /* keep only first one */
+         }
+         istat = signal(SIGINT, SIG_IGN);
+         qstat = signal(SIGQUIT, SIG_IGN);
+         /* wait for child to exit */
+         while ((wpid = wait(&waitstatus)) != pid && wpid != -1)
+            { ; }
+         signal(SIGINT, istat);
+         signal(SIGQUIT, qstat);
+         strcpy(name, echout);
+         stat = 1;
+         break;
+       }
+       close(pfd[0]);                    /* close pipe */
+       close(pfd[1]);
+#endif /* nt */
+   }
+   return stat;
+
+#endif /* UNIX */
+
+#if  MSC | MSDOS | __WATCOMC__
+
+   char prefix[100], *env, *getenv();
+
+   /* Home directory reference? */
+   if (*name == '~' && (env=getenv("HOME"))) {
+      strcpy(prefix, env);           /* copy HOME directory name */
+      name++;                        /* skip over ~ in name */
+      strcat(prefix, name);
+      name--;                        /* get back to beginning */
+      strcpy(name, prefix);          /* move back into name */
+   }
+   return 1;
+#endif
+
+}
diff --git a/bacula/src/lib/waitq.h b/bacula/src/lib/waitq.h
new file mode 100644 (file)
index 0000000..152b66e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Bacula wait queue routines. Permits waiting for something
+ *   to be done. I.e. for operator to mount new volume.
+ *
+ *  Kern Sibbald, March MMI
+ *
+ *  This code inspired from "Programming with POSIX Threads", by
+ *    David R. Butenhof
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef __WAITQ_H 
+#define __WAITQ_H 1
+
+/* 
+ * Structure to keep track of wait queue request
+ */
+typedef struct waitq_ele_tag {
+   struct waitq_ele_tag *next;
+   int               done_flag;       /* predicate for wait */
+   pthread_cont_t    done;            /* wait for completion */
+   void             *msg;             /* message to be passed */
+} waitq_ele_t;
+
+/* 
+ * Structure describing a wait queue
+ */
+typedef struct workq_tag {
+   pthread_mutex_t   mutex;           /* queue access control */
+   pthread_cond_t    wait_req;        /* wait for OK */
+   int               num_msgs;        /* number of waiters */
+   waitq_ele_t       *first;          /* wait queue first item */
+   waitq_ele_t       *last;           /* wait queue last item */
+} workq_t;
+
+extern int waitq_init(waitq_t *wq);
+extern int waitq_destroy(waitq_t *wq);
+extern int waitq_add(waitq_t *wq, void *msg);
+
+#endif /* __WAITQ_H */
diff --git a/bacula/src/lib/watchdog.c b/bacula/src/lib/watchdog.c
new file mode 100755 (executable)
index 0000000..1bcccc4
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Bacula thread watchdog routine. General routine that monitors
+ *  the daemon and signals a thread if it is blocked on a BSOCK
+ *  too long. This prevents catastropic long waits -- generally
+ *  due to Windows "hanging" the app.
+ *
+ *  Kern Sibbald, January MMII
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "jcr.h"
+
+/* Exported globals */
+time_t watchdog_time;                /* this has granularity of SLEEP_TIME */
+
+
+#define TIMEOUT_SIGNAL SIGUSR2
+#define SLEEP_TIME 30                /* examine things every 30 seconds */
+
+/* Forward referenced functions */
+static void *watchdog_thread(void *arg);
+
+/* Static globals */
+static pthread_mutex_t mutex;
+static pthread_cond_t  timer;
+static int quit;
+
+
+/*
+ * Timeout signal comes here
+ */
+static void timeout_handler(int sig)
+{
+   return;                           /* thus interrupting the function */
+}
+
+
+/*   
+ * Initialize watchdog thread
+ *
+ *  Returns: 0 on success
+ *          errno on failure
+ */
+int init_watchdog(void)
+{
+   int stat;
+   pthread_t wdid;
+   struct sigaction sigtimer;
+                       
+   sigtimer.sa_flags = 0;
+   sigtimer.sa_handler = timeout_handler;
+   sigfillset(&sigtimer.sa_mask);
+   sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL);
+   watchdog_time = time(NULL);
+   if ((stat = pthread_mutex_init(&mutex, NULL)) != 0) {
+      return stat;
+   }
+   if ((stat = pthread_cond_init(&timer, NULL)) != 0) {
+      pthread_mutex_destroy(&mutex);
+      return stat;
+   }
+   quit = FALSE;
+   if ((stat = pthread_create(&wdid, NULL, watchdog_thread, (void *)NULL)) != 0) {
+      pthread_mutex_destroy(&mutex);
+      pthread_cond_destroy(&timer);
+      return stat;
+   }
+   return 0;
+}
+
+/*
+ * Terminate the watchdog thread
+ *
+ * Returns: 0 on success
+ *         errno on failure
+ */
+int term_watchdog(void)
+{
+   int stat;
+
+   if ((stat = pthread_mutex_lock(&mutex)) != 0) {
+      return stat;
+   }
+   quit = TRUE;
+
+   if ((stat = pthread_cond_signal(&timer)) != 0) {
+      pthread_mutex_unlock(&mutex);
+      return stat;
+   }
+   if ((stat = pthread_mutex_unlock(&mutex)) != 0) {
+      return stat;
+   }
+   return 0;
+}
+
+
+/* 
+ * This is the actual watchdog thread.
+ */
+static void *watchdog_thread(void *arg)
+{
+   struct timespec timeout;
+   int stat;
+   JCR *jcr;
+   BSOCK *fd;
+
+   Dmsg0(200, "Start watchdog thread\n");
+   pthread_detach(pthread_self());
+
+   if ((stat = pthread_mutex_lock(&mutex)) != 0) {
+      return NULL;
+   }
+
+   for ( ;!quit; ) {
+      struct timeval tv;
+      struct timezone tz;
+
+      Dmsg0(200, "Top of for loop\n");
+
+      watchdog_time = time(NULL);     /* update timer */
+
+      /* Walk through all JCRs checking if any one is 
+       * blocked for more than specified max time.
+       */
+      lock_jcr_chain();
+      for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
+        free_locked_jcr(jcr);
+        if (jcr->JobId == 0) {
+           continue;
+        }
+        fd = jcr->store_bsock;
+        if (fd && fd->timer_start && (watchdog_time - fd->timer_start) > fd->timeout) {
+           fd->timed_out = TRUE;
+            Jmsg(jcr, M_ERROR, 0, "Watchdog sending kill to thread stalled reading Storage daemon.\n");
+           pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
+        }
+        fd = jcr->file_bsock;
+        if (fd && fd->timer_start && (watchdog_time - fd->timer_start) > fd->timeout) {
+           fd->timed_out = TRUE;
+            Jmsg(jcr, M_ERROR, 0, "Watchdog sending kill to thread stalled reading File daemon.\n");
+           pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
+        }
+        fd = jcr->dir_bsock;
+        if (fd && fd->timer_start && (watchdog_time - fd->timer_start) > fd->timeout) {
+           fd->timed_out = TRUE;
+            Jmsg(jcr, M_ERROR, 0, "Watchdog sending kill to thread stalled reading Director.\n");
+           pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
+        }
+
+      }
+      unlock_jcr_chain();
+
+      gettimeofday(&tv, &tz);
+      timeout.tv_nsec = 0;
+      timeout.tv_sec = tv.tv_sec + SLEEP_TIME;
+
+      Dmsg1(200, "pthread_cond_timedwait sec=%d\n", timeout.tv_sec);
+#ifdef xxxxxxxxxxxxxxx_was_HAVE_CYGWIN
+      /* CYGWIN dies with a page fault the second
+       * time that pthread_cond_timedwait() is called
+       * so fake it out.
+       */
+      sleep(SLEEP_TIME); 
+#else
+      stat = pthread_cond_timedwait(&timer, &mutex, &timeout);
+      Dmsg1(200, "pthread_cond_timedwait stat=%d\n", stat);
+#endif
+      
+   } /* end of big for loop */
+
+   Dmsg0(200, "End watchdog\n");
+   return NULL;
+}
diff --git a/bacula/src/lib/workq.c b/bacula/src/lib/workq.c
new file mode 100755 (executable)
index 0000000..2a5d512
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Bacula work queue routines. Permits passing work to
+ *  multiple threads.
+ *
+ *  Kern Sibbald, January MMI
+ *
+ *  This code adapted from "Programming with POSIX Threads", by
+ *    David R. Butenhof
+ *
+ * Example:
+ *
+ * static workq_t job_wq;    define work queue
+ *
+ *  Initialize queue
+ *  if ((stat = workq_init(&job_wq, max_workers, job_thread)) != 0) {
+ *     Emsg1(M_ABORT, 0, "Could not init job work queue: ERR=%s\n", strerror(errno));
+ *   }
+ *
+ *  Add an item to the queue
+ *  if ((stat = workq_add(&job_wq, (void *)jcr)) != 0) {
+ *      Emsg1(M_ABORT, 0, "Could not add job to work queue: ERR=%s\n", strerror(errno));
+ *   }
+ *
+ *  Terminate the queue
+ *  workq_destroy(workq_t *wq);
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+
+/* Forward referenced functions */
+static void *workq_server(void *arg);
+
+/*   
+ * Initialize a work queue
+ *
+ *  Returns: 0 on success
+ *          errno on failure
+ */
+int workq_init(workq_t *wq, int threads, void (*engine)(void *arg))
+{
+   int stat;
+                       
+   if ((stat = pthread_attr_init(&wq->attr)) != 0) {
+      return stat;
+   }
+   if ((stat = pthread_attr_setdetachstate(&wq->attr, PTHREAD_CREATE_DETACHED)) != 0) {
+      pthread_attr_destroy(&wq->attr);
+      return stat;
+   }
+   if ((stat = pthread_mutex_init(&wq->mutex, NULL)) != 0) {
+      pthread_attr_destroy(&wq->attr);
+      return stat;
+   }
+   if ((stat = pthread_cond_init(&wq->work, NULL)) != 0) {
+      pthread_mutex_destroy(&wq->mutex);
+      pthread_attr_destroy(&wq->attr);
+      return stat;
+   }
+   wq->quit = 0;
+   wq->first = wq->last = NULL;
+   wq->max_workers = threads;        /* max threads to create */
+   wq->num_workers = 0;              /* no threads yet */
+   wq->idle_workers = 0;             /* no idle threads */
+   wq->engine = engine;              /* routine to run */
+   wq->valid = WORKQ_VALID; 
+   return 0;
+}
+
+/*
+ * Destroy a work queue
+ *
+ * Returns: 0 on success
+ *         errno on failure
+ */
+int workq_destroy(workq_t *wq)
+{
+   int stat, stat1, stat2;
+
+  if (wq->valid != WORKQ_VALID) {
+     return EINVAL;
+  }
+  if ((stat = pthread_mutex_lock(&wq->mutex)) != 0) {
+     return stat;
+  }
+  wq->valid = 0;                     /* prevent any more operations */
+
+  /* 
+   * If any threads are active, wake them 
+   */
+  if (wq->num_workers > 0) {
+     wq->quit = 1;
+     if (wq->idle_workers) {
+       if ((stat = pthread_cond_broadcast(&wq->work)) != 0) {
+          pthread_mutex_unlock(&wq->mutex);
+          return stat;
+       }
+     }
+     while (wq->num_workers > 0) {
+       if ((stat = pthread_cond_wait(&wq->work, &wq->mutex)) != 0) {
+          pthread_mutex_unlock(&wq->mutex);
+          return stat;
+       }
+     }
+  }
+  if ((stat = pthread_mutex_unlock(&wq->mutex)) != 0) {
+     return stat;
+  }
+  stat = pthread_mutex_destroy(&wq->mutex);
+  stat1 = pthread_cond_destroy(&wq->work);
+  stat2 = pthread_attr_destroy(&wq->attr);
+  return (stat != 0 ? stat : (stat1 != 0 ? stat1 : stat2));
+}
+
+
+/*
+ *  Add work to a queue
+ */
+int workq_add(workq_t *wq, void *element)
+{
+   int stat;
+   workq_ele_t *item;
+   pthread_t id;
+    
+   Dmsg0(200, "workq_add\n");
+   if (wq->valid != WORKQ_VALID) {
+      return EINVAL;
+   }
+
+   if ((item = (workq_ele_t *) malloc(sizeof(workq_ele_t))) == NULL) {
+      return ENOMEM;
+   }
+   item->data = element;
+   item->next = NULL;
+   if ((stat = pthread_mutex_lock(&wq->mutex)) != 0) {
+      free(item);
+      return stat;
+   }
+
+   Dmsg0(200, "add item to queue\n");
+   /* Add the new item to the end of the queue */
+   if (wq->first == NULL) {
+      wq->first = item;
+   } else {
+      wq->last->next = item;
+   }
+   wq->last = item;
+
+   /* if any threads are idle, wake one */
+   if (wq->idle_workers > 0) {
+      Dmsg0(200, "Signal worker\n");
+      if ((stat = pthread_cond_signal(&wq->work)) != 0) {
+        pthread_mutex_unlock(&wq->mutex);
+        return stat;
+      }
+   } else if (wq->num_workers < wq->max_workers) {
+      Dmsg0(200, "Create worker thread\n");
+      /* No idle threads so create a new one */
+      set_thread_concurrency(wq->max_workers + 1);
+      if ((stat = pthread_create(&id, &wq->attr, workq_server, (void *)wq)) != 0) {
+        pthread_mutex_unlock(&wq->mutex);
+        return stat;
+      }
+      wq->num_workers++;
+   }
+   pthread_mutex_unlock(&wq->mutex);
+   Dmsg0(200, "Return workq_add\n");
+   return stat;
+}
+
+/* 
+ * This is the worker thread that serves the work queue.
+ * In due course, it will call the user's engine.
+ */
+static void *workq_server(void *arg)
+{
+   struct timespec timeout;
+   workq_t *wq = (workq_t *)arg;
+   workq_ele_t *we;
+   int stat, timedout;
+
+   Dmsg0(200, "Start workq_server\n");
+   if ((stat = pthread_mutex_lock(&wq->mutex)) != 0) {
+      return NULL;
+   }
+
+   for (;;) {
+      struct timeval tv;
+      struct timezone tz;
+
+      Dmsg0(200, "Top of for loop\n");
+      timedout = 0;
+      Dmsg0(200, "gettimeofday()\n");
+      gettimeofday(&tv, &tz);
+      timeout.tv_nsec = 0;
+      timeout.tv_sec = tv.tv_sec + 2;
+
+      while (wq->first == NULL && !wq->quit) {
+        /*
+         * Wait 2 seconds, then if no more work, exit
+         */
+         Dmsg0(200, "pthread_cond_timedwait()\n");
+#ifdef xxxxxxxxxxxxxxxx_was_HAVE_CYGWIN
+        /* CYGWIN dies with a page fault the second
+         * time that pthread_cond_timedwait() is called
+         * so fake it out.
+         */
+        pthread_mutex_lock(&wq->mutex);
+        stat = ETIMEDOUT;
+#else
+        stat = pthread_cond_timedwait(&wq->work, &wq->mutex, &timeout);
+#endif
+         Dmsg1(200, "timedwait=%d\n", stat);
+        if (stat == ETIMEDOUT) {
+           timedout = 1;
+           break;
+        } else if (stat != 0) {
+            /* This shouldn't happen */
+            Dmsg0(200, "This shouldn't happen\n");
+           wq->num_workers--;
+           pthread_mutex_unlock(&wq->mutex);
+           return NULL;
+        }
+      } 
+      we = wq->first;
+      if (we != NULL) {
+        wq->first = we->next;
+        if (wq->last == we) {
+           wq->last = NULL;
+        }
+        if ((stat = pthread_mutex_unlock(&wq->mutex)) != 0) {
+           return NULL;
+        }
+         /* Call user's routine here */
+         Dmsg0(200, "Calling user engine.\n");
+        wq->engine(we->data);
+         Dmsg0(200, "Back from user engine.\n");
+        free(we);                    /* release work entry */
+         Dmsg0(200, "relock mutex\n"); 
+        if ((stat = pthread_mutex_lock(&wq->mutex)) != 0) {
+           return NULL;
+        }
+         Dmsg0(200, "Done lock mutex\n");
+      }
+      /*
+       * If no more work request, and we are asked to quit, then do it
+       */
+      if (wq->first == NULL && wq->quit) {
+        wq->num_workers--;
+        if (wq->num_workers == 0) {
+            Dmsg0(200, "Wake up destroy routine\n");
+           /* Wake up destroy routine if he is waiting */
+           pthread_cond_broadcast(&wq->work);
+        }
+         Dmsg0(200, "Unlock mutex\n");
+        pthread_mutex_unlock(&wq->mutex);
+         Dmsg0(200, "Return from workq_server\n");
+        return NULL;
+      }
+      Dmsg0(200, "Check for work request\n");
+      /* 
+       * If no more work requests, and we waited long enough, quit
+       */
+      Dmsg1(200, "wq->first==NULL = %d\n", wq->first==NULL);
+      Dmsg1(200, "timedout=%d\n", timedout);
+      if (wq->first == NULL && timedout) {
+         Dmsg0(200, "break big loop\n");
+        wq->num_workers--;
+        break;
+      }
+      Dmsg0(200, "Loop again\n");
+   } /* end of big for loop */
+
+   Dmsg0(200, "unlock mutex\n");
+   pthread_mutex_unlock(&wq->mutex);
+   Dmsg0(200, "End workq_server\n");
+   return NULL;
+}
diff --git a/bacula/src/lib/workq.h b/bacula/src/lib/workq.h
new file mode 100644 (file)
index 0000000..a0226f2
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Bacula work queue routines. Permits passing work to
+ *  multiple threads.
+ *
+ *  Kern Sibbald, January MMI
+ *
+ *  This code adapted from "Programming with POSIX Threads", by
+ *    David R. Butenhof
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef __WORKQ_H 
+#define __WORKQ_H 1
+
+/* 
+ * Structure to keep track of work queue request
+ */
+typedef struct workq_ele_tag {
+   struct workq_ele_tag *next;
+   void                 *data;
+} workq_ele_t;
+
+/* 
+ * Structure describing a work queue
+ */
+typedef struct workq_tag {
+   pthread_mutex_t   mutex;           /* queue access control */
+   pthread_cond_t    work;            /* wait for work */
+   pthread_attr_t    attr;            /* create detached threads */
+   workq_ele_t       *first, *last;   /* work queue */
+   int               valid;           /* queue initialized */
+   int               quit;            /* workq should quit */
+   int               max_workers;     /* max threads */
+   int               num_workers;     /* current threads */
+   int               idle_workers;    /* idle threads */
+   void              (*engine)(void *arg); /* user engine */
+} workq_t;
+
+#define WORKQ_VALID  0xdec1992
+
+extern int workq_init(
+              workq_t *wq,
+              int     threads,        /* maximum threads */
+              void    (*engine)(void *)   /* engine routine */
+                    );
+extern int workq_destroy(workq_t *wq);
+extern int workq_add(workq_t *wq, void *data);
+
+#endif /* __WORKQ_H */
diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in
new file mode 100644 (file)
index 0000000..0500e1e
--- /dev/null
@@ -0,0 +1,147 @@
+# $Id$
+@MCOMMON@
+
+srcdir =       .
+VPATH =        .
+.PATH:         .
+
+# one up
+basedir = ..
+# top dir
+topdir = ../..
+# this dir relative to top dir
+thisdir = src/stored
+
+DEBUG=@DEBUG@
+
+first_rule: all
+dummy:
+
+#
+SVRSRCS = stored.c append.c askdir.c authenticate.c block.c dev.c \
+         device.c dircmd.c fd_cmds.c fdmsg.c job.c \
+         label.c read.c record.c stored_conf.c 
+SVROBJS = stored.o append.o askdir.o authenticate.o block.o dev.o \
+         device.o dircmd.o fd_cmds.o fdmsg.o job.o \
+         label.o read.o record.o stored_conf.o 
+
+# bpool is depricated
+#POOLSRCS = bpool.c block.c dev.c device.c askdir.c label.c \
+#          record.c stored_conf.c 
+#POOLOBJS = bpool.o block.o dev.o device.o askdir.o label.o \
+#          record.o stored_conf.o 
+
+#
+TAPESRCS = btape.c block.c dev.c device.c askdir.c label.c \
+          record.c stored_conf.c 
+TAPEOBJS = btape.o block.o dev.o device.o askdir.o label.o \
+          record.o stored_conf.o 
+
+BLSOBJS = bls.o block.o device.o dev.o askdir.o label.o record.o
+
+BEXTOBJS = bextract.o block.o device.o dev.o askdir.o label.o record.o
+
+SCNOBJS = bscan.o block.o device.o dev.o askdir.o label.o record.o
+
+
+
+# it was ``be kind to gmake week''.  Now it's ``autoconf week''
+#OBJS = $(SRCS:S,.c,.o,)
+# these are the objects that are changed by the .configure process
+EXTRAOBJS = @OBJLIST@
+
+FDLIBS=@FDLIBS@
+
+
+.SUFFIXES:     .c .o
+.PHONY:
+.DONTCARE:
+
+# inference rules
+.c.o:
+       $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
+#-------------------------------------------------------------------------
+all: Makefile bacula-sd bls bextract bscan btape 
+       @echo "===== Make of stored is good ===="
+       @echo " "
+
+bacula-sd: $(SVROBJS) ../lib/libbac.a
+       $(CXX) $(LDFLAGS) -L../lib -o $@ $(SVROBJS) $(LIBS) $(DLIB) $(FDLIBS) -lbac -lm
+
+#bpool:  $(POOLOBJS) ../lib/libbac.a ../cats/libsql.a
+#       $(CXX) $(LDFLAGS) -L../lib -L../cats  -o $@ $(POOLOBJS) -lsql $(LIBS) $(DLIB) -lbac -lm
+
+btape: $(TAPEOBJS) ../lib/libbac.a ../cats/libsql.a
+       $(CXX) $(LDFLAGS) -L../lib -L../cats  -o $@ $(TAPEOBJS) -lsql $(LIBS) $(DLIB) -lbac -lm
+
+bls:   ../findlib/libfind.a $(BLSOBJS) ../lib/libbac.a
+       $(CXX) $(LDFLAGS) -L../lib -L../findlib -o $@ $(BLSOBJS) $(LIBS) $(DLIB) -lbac -lfind -lm
+
+bextract: ../findlib/libfind.a $(BEXTOBJS)
+       $(CXX) $(LDFLAGS) -L../lib -L../findlib -o $@ $(BEXTOBJS) $(LIBS) $(DLIB) $(FDLIBS) -lbac -lfind -lm
+
+bscan: ../findlib/libfind.a $(SCNOBJS) ../cats/libsql.a
+       $(CXX) $(LDFLAGS) -L../lib -L../cats -L../findlib -o $@ $(SCNOBJS) -lsql $(LIBS) $(DLIB) $(FDLIBS) -lbac -lfind -lm
+
+
+
+
+Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
+       cd $(topdir) \
+         && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+install: all
+       $(INSTALL_PROGRAM) bacula-sd $(DESTDIR)$(sbindir)/bacula-sd
+       $(INSTALL_PROGRAM) bls $(DESTDIR)$(sbindir)/bls
+       $(INSTALL_PROGRAM) bextract $(DESTDIR)$(sbindir)/bextract
+#      $(INSTALL_PROGRAM) bpool $(DESTDIR)$(sbindir)/bpool
+       $(INSTALL_PROGRAM) btape $(DESTDIR)$(sbindir)/btape
+       @srcconf=bacula-sd.conf; \
+       if  test -f ${DESTDIR}${sysconfdir}/$$srcconf; then \
+          destconf=$$srcconf.new; \
+          echo "  ==> Found existing $$srcconf, installing new conf file as $$destconf"; \
+       else \
+          destconf=$$srcconf; \
+       fi; \
+       echo "${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf"; \
+       ${INSTALL_DATA} $$srcconf ${DESTDIR}${sysconfdir}/$$destconf
+
+uninstall:
+       (cd $(DESTDIR)$(sbindir); $(RMF) bacula-sd)
+       (cd $(DESTDIR)$(sbindir); $(RMF) bls)
+       (cd $(DESTDIR)$(sbindir); $(RMF) bextract)
+#      (cd $(DESTDIR)$(sbindir); $(RMF) bpool)
+       (cd $(DESTDIR)$(sysconfdir); $(RMF) bacula-sd.conf)
+
+
+clean:
+       @$(RMF) bacula-sd stored bls bextract bpool btape shmfree core core.* a.out *.o *.bak *~ *.intpro *.extpro 1 2 3
+       @$(RMF) bscan
+
+realclean: clean
+       @$(RMF) tags bacula-sd.conf
+
+distclean: realclean
+       if test $(srcdir) = .; then $(MAKE) realclean; fi
+       (cd $(srcdir); $(RMF) Makefile)
+
+
+# Semi-automatic generation of dependencies:
+# Use cc -M because X11 `makedepend' doesn't work on all systems
+# and it also includes system headers.
+# `semi'-automatic since dependencies are generated at distribution time.
+
+depend:
+       @$(MV) Makefile Makefile.bak
+       @$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile
+       @$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile
+       @$(CC) -S -M $(CPPFLAGS) $(XINC) -I$(srcdir) -I$(basedir) $(SQL_INC) *.c >> Makefile
+       @if test -f Makefile ; then \
+           $(RMF) Makefile.bak; \
+       else \
+          $(MV) Makefile.bak Makefile; \
+          echo -e "Something went wrong with make depend\n\a"; \
+       fi
+
+# -----------------------------------------------------------------------
+# DO NOT DELETE: nice dependency list follows
diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c
new file mode 100644 (file)
index 0000000..83f9567
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Append code for Storage daemon
+ *  Kern Sibbald, May MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+extern int  FiledDataChan;           /* File daemon data channel (port) */
+extern int BaculaTapeVersion;        /* Version number */
+extern char BaculaId[];              /* Id string */
+
+/* Responses sent to the File daemon */
+static char OK_data[]    = "3000 OK data\n";
+
+/* 
+ *  Append Data sent from File daemon  
+ *
+ */
+int do_append_data(JCR *jcr) 
+{
+   int32_t n;
+   long file_index, stream, last_file_index;
+   BSOCK *ds;
+   BSOCK *fd_sock = jcr->file_bsock;
+   int ok = TRUE;
+   DEVICE *dev = jcr->device->dev;
+   DEV_RECORD rec;
+   DEV_BLOCK  *block;
+   
+   Dmsg0(10, "Start append data.\n");
+
+   /* Tell File daemon to send data */
+   bnet_fsend(fd_sock, OK_data);
+
+   sm_check(__FILE__, __LINE__, False);
+
+   ds = fd_sock;
+
+   if (!bnet_set_buffer_size(ds, MAX_NETWORK_BUFFER_SIZE, BNET_SETBUF_WRITE)) {
+      jcr->JobStatus = JS_Cancelled;
+      Jmsg(jcr, M_FATAL, 0, _("Unable to set network buffer size.\n"));
+      return 0;
+   }
+
+   Dmsg1(20, "Begin append device=%s\n", dev_name(dev));
+
+   block = new_block(dev);
+
+   /* 
+    * Acquire output device for writing.  Note, after acquiring a
+    *  device, we MUST release it, which is done at the end of this
+    *  subroutine.
+    */
+   Dmsg0(100, "just before acquire_device\n");
+   if (!acquire_device_for_append(jcr, dev, block)) {
+      jcr->JobStatus = JS_Cancelled;
+      free_block(block);
+      return 0;
+   }
+   sm_check(__FILE__, __LINE__, False);
+
+   Dmsg0(100, "Just after acquire_device_for_append\n");
+   /*
+    * Write Begin Session Record
+    */
+   if (!write_session_label(jcr, block, SOS_LABEL)) {
+      jcr->JobStatus = JS_Cancelled;
+      Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"),
+        strerror_dev(dev));
+      ok = FALSE;
+   }
+
+   sm_check(__FILE__, __LINE__, False);
+
+   memset(&rec, 0, sizeof(rec));
+
+   /* 
+    * Get Data from File daemon, write to device   
+    */
+   jcr->VolFirstFile = 0;
+   time(&jcr->run_time);             /* start counting time for rates */
+   for (last_file_index = 0; ok && !job_cancelled(jcr); ) {
+      char info[100];
+
+      /* Read Stream header from the File daemon.
+       *  The stream header consists of the
+       *
+       *   file_index (sequential Bacula file index)
+       *   stream     (arbitrary Bacula number to distinguish parts of data)
+       *   info       (Info for Storage daemon -- compressed, encryped, ...)
+       */
+      if ((n=bget_msg(ds)) < 0) { 
+         Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"),
+           bnet_strerror(ds));
+        ok = FALSE;
+        break;
+      }
+      if (n == 0) {                  /* End of conversation */
+        break;                       /* all done */
+      }
+      sm_check(__FILE__, __LINE__, False);
+      ds->msg[ds->msglen] = 0;
+      if (sscanf(ds->msg, "%ld %ld %100s", &file_index, &stream, info) != 3) {
+         Jmsg1(jcr, M_FATAL, 0, _("Malformed data header from FD: %s\n"), ds->msg);
+        ok = FALSE;
+        break;
+      }
+      Dmsg2(190, "<filed: Header FilInx=%d stream=%d\n", file_index, stream);
+
+      if (!(file_index > 0 && (file_index == last_file_index ||
+         file_index == last_file_index + 1))) {
+         Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n"));
+        ok = FALSE;
+        break;
+      }
+      if (file_index != last_file_index) {
+        jcr->JobFiles = file_index;
+        if (jcr->VolFirstFile == 0) {
+           jcr->VolFirstFile = file_index;
+        }
+        last_file_index = file_index;
+      }
+      
+      /* Read data stream from the File daemon.
+       *  The data stream is just raw bytes
+       */
+      sm_check(__FILE__, __LINE__, False);
+      while ((n=bget_msg(ds)) > 0 && !job_cancelled(jcr)) {
+        char *dsmsg = ds->msg;
+
+        sm_check(__FILE__, __LINE__, False);
+        rec.VolSessionId = jcr->VolSessionId;
+        rec.VolSessionTime = jcr->VolSessionTime;
+        rec.FileIndex = file_index;
+        rec.Stream = stream;
+        rec.data_len = ds->msglen;
+        rec.data = ds->msg;            /* use message buffer */
+
+         Dmsg4(250, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
+           rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream), 
+           rec.data_len);
+         
+        while (!write_record_to_block(block, &rec)) {
+            Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
+                      rec.remainder);
+           if (!write_block_to_device(jcr, dev, block)) {
+               Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
+                 dev_name(dev), strerror_dev(dev));
+               Jmsg(jcr, M_FATAL, 0, _("Cannot fixup device error. %s\n"),
+                    strerror_dev(dev));
+              ok = FALSE;
+              break;
+           }
+        }
+        sm_check(__FILE__, __LINE__, False);
+        if (!ok) {
+           break;
+        }
+        jcr->JobBytes += rec.data_len;   /* increment bytes this job */
+         Dmsg4(190, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
+           FI_to_ascii(rec.FileIndex), rec.VolSessionId, 
+           stream_to_ascii(rec.Stream), rec.data_len);
+        /* Send attributes and MD5 to Director for Catalog */
+        if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_MD5_SIGNATURE) {
+           if (!dir_update_file_attributes(jcr, &rec)) {
+              ok = FALSE;
+              break;
+           }
+        }
+        ASSERT(dsmsg == ds->msg);
+        ASSERT(dsmsg == rec.data);
+        sm_check(__FILE__, __LINE__, False);
+      }
+      if (n < 0) {
+         Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"),
+           bnet_strerror(ds));
+        ok = FALSE;
+        break;
+      }
+   }
+   /* 
+    *******FIXME***** we should put the ok status in the End of
+    * session label 
+    *
+    *   We probably need a new flag that says "Do not attempt
+    *   to write because there is no tape".
+    */
+   sm_check(__FILE__, __LINE__, False);
+   Dmsg0(90, "Write_end_session_label()\n");
+   if (!write_session_label(jcr, block, EOS_LABEL)) {
+      Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"),
+         strerror_dev(dev));
+      ok = FALSE;
+   }
+   /* Write out final block of this session */
+   if (!write_block_to_device(jcr, dev, block)) {
+      Dmsg0(0, "Set ok=FALSE after write_block_to_device.\n");
+      ok = FALSE;
+   }
+
+   /* Release the device */
+   if (!release_device(jcr, dev, block)) {
+      Dmsg0(0, "Error in release_device\n");
+      ok = FALSE;
+   }
+
+   free_block(block);
+   Dmsg0(90, "return from do_append_data()\n");
+   return ok ? 1 : 0;
+}
diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c
new file mode 100644 (file)
index 0000000..a7d3c19
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+ *  Subroutines to handle Catalog reqests sent to the Director
+ *   Reqests/commands from the Director are handled in dircmd.c
+ *
+ *   Kern Sibbald, December 2000
+ *                           
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"                   /* pull in global headers */
+#include "stored.h"                   /* pull in Storage Deamon headers */
+
+/* Requests sent to the Director */
+static char Find_media[]    = "CatReq Job=%s FindMedia=%d\n";
+static char Find_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s\n";
+
+static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s\
+ VolJobs=%d VolFiles=%d VolBlocks=%d VolBytes=%" lld " VolMounts=%d\
+ VolErrors=%d VolWrites=%d VolMaxBytes=%" lld " EndTime=%d VolStatus=%s\
+ FirstIndex=%d LastIndex=%d StartFile=%d EndFile=%d \
+ StartBlock=%d EndBlock=%d\n";
+
+static char FileAttributes[] = "UpdCat Job=%s FileAttributes ";
+
+static char Job_status[]   = "3012 Job %s jobstatus %d\n";
+
+
+/* Responses received from the Director */
+static char OK_media[] = "1000 OK VolName=%127s VolJobs=%d VolFiles=%d\
+ VolBlocks=%d VolBytes=%" lld " VolMounts=%d VolErrors=%d VolWrites=%d\
+ VolMaxBytes=%" lld " VolCapacityBytes=%" lld "\n";
+
+static char OK_update[] = "1000 OK UpdateMedia\n";
+
+
+/*
+ * Send current JobStatus to Director
+ */
+int dir_send_job_status(JCR *jcr)
+{
+   return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus);
+}
+
+/*
+ * Common routine for:
+ *   dir_get_volume_info()
+ * and
+ *   dir_find_next_appendable_volume()
+ */
+static int do_request_volume_info(JCR *jcr)
+{
+    BSOCK *dir = jcr->dir_bsock;
+    VOLUME_CAT_INFO *vol = &jcr->VolCatInfo;
+
+    jcr->VolumeName[0] = 0;          /* No volume */
+    if (bnet_recv(dir) <= 0) {
+       Dmsg0(30, "getvolname error bnet_recv\n");
+       return 0;
+    }
+    if (sscanf(dir->msg, OK_media, vol->VolCatName, 
+              &vol->VolCatJobs, &vol->VolCatFiles,
+              &vol->VolCatBlocks, &vol->VolCatBytes, 
+              &vol->VolCatMounts, &vol->VolCatErrors,
+              &vol->VolCatWrites, &vol->VolCatMaxBytes, 
+              &vol->VolCatCapacityBytes) != 10) {
+       Dmsg1(30, "Bad response from Dir: %s\n", dir->msg);
+       return 0;
+    }
+    unbash_spaces(vol->VolCatName);
+    strcpy(jcr->VolumeName, vol->VolCatName); /* set desired VolumeName */
+    
+    Dmsg1(200, "Got Volume=%s\n", vol->VolCatName);
+    strcpy(vol->VolCatStatus, "Append");
+    return 1;
+}
+
+
+/*
+ * Get Volume info for a specific volume from the Director's Database
+ *
+ * Returns: 1 on success   (not Director guarantees that Pool and MediaType
+ *                         are correct and VolStatus==Append)
+ *         0 on failure
+ *
+ *         Volume information returned in jcr
+ */
+int dir_get_volume_info(JCR *jcr)
+{
+    BSOCK *dir = jcr->dir_bsock;
+
+    strcpy(jcr->VolCatInfo.VolCatName, jcr->VolumeName);
+    Dmsg1(200, "dir_get_volume_info=%s\n", jcr->VolCatInfo.VolCatName);
+    bash_spaces(jcr->VolCatInfo.VolCatName);
+    bnet_fsend(dir, Find_Vol_Info, jcr->Job, jcr->VolCatInfo.VolCatName);
+    return do_request_volume_info(jcr);
+}
+
+
+
+/*
+ * Get info on the next appendable volume in the Director's database
+ * Returns: 1 on success
+ *         0 on failure
+ *
+ *         Volume information returned in jcr
+ *
+ */
+int dir_find_next_appendable_volume(JCR *jcr)
+{
+    BSOCK *dir = jcr->dir_bsock;
+
+    Dmsg0(200, "dir_find_next_appendable_volume\n");
+    bnet_fsend(dir, Find_media, jcr->Job, 1);
+    return do_request_volume_info(jcr);
+}
+
+    
+/*
+ * After writing a Volume, send the updated statistics
+ * back to the director.
+ */
+int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   time_t EndTime = time(NULL);
+
+   if (vol->VolCatName[0] == 0) {
+      Emsg0(M_ERROR, 0, "NULL Volume name. This shouldn't happen!!!\n");
+   }
+   bnet_fsend(dir, Update_media, jcr->Job, 
+      vol->VolCatName, vol->VolCatJobs, vol->VolCatFiles,
+      vol->VolCatBlocks, vol->VolCatBytes, 
+      vol->VolCatMounts, vol->VolCatErrors,
+      vol->VolCatWrites, vol->VolCatMaxBytes, EndTime, 
+      vol->VolCatStatus, 
+      jcr->VolFirstFile, jcr->JobFiles,
+      jcr->start_file, jcr->end_file,
+      jcr->start_block, jcr->end_block);
+   Dmsg1(20, "update_volume_data(): %s", dir->msg);
+   if (bnet_recv(dir) <= 0) {
+      Dmsg0(90, "updateVolCatInfo error bnet_recv\n");
+      return 0;
+   }
+   Dmsg1(20, "Updatevol: %s", dir->msg);
+   if (strcmp(dir->msg, OK_update) != 0) {
+      Dmsg1(30, "Bad response from Dir: %s\n", dir->msg);
+      Jmsg(jcr, M_ERROR, 0, "Error updating Volume Info: %s\n", 
+        dir->msg);
+      return 0;
+   }
+   return 1;
+}
+
+/* 
+ * Update File Attribute data
+ */
+int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   ser_declare;
+
+   dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
+   dir->msg = (char *) check_pool_memory_size(dir->msg, dir->msglen + 
+               sizeof(DEV_RECORD) + rec->data_len);
+   ser_begin(dir->msg + dir->msglen, 0);
+   ser_uint32(rec->VolSessionId);
+   ser_uint32(rec->VolSessionTime);
+   ser_int32(rec->FileIndex);
+   ser_int32(rec->Stream);
+   ser_uint32(rec->data_len);
+   ser_bytes(rec->data, rec->data_len);
+   dir->msglen = ser_length(dir->msg);
+   return bnet_send(dir);
+}
+
+
+/*
+ *   
+ *   Entered with device blocked.
+ *   Leaves with device blocked.
+ *
+ *   Returns: 1 on success (operator issues a mount command)
+ *           0 on failure
+ *             Note, must create dev->errmsg on error return.
+ *
+ *    On success, jcr->VolumeName and jcr->VolCatInfo contain
+ *     information on suggested volume, but this may not be the
+ *     same as what is actually mounted.
+ */
+int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev)
+{
+   struct timeval tv;
+   struct timezone tz;
+   struct timespec timeout;
+   int stat, jstat;
+   /* ******FIXME******* put these on config variable */
+   int min_wait = 60 * 60;
+   int max_wait = 24 * 60 * 60;
+   int max_num_wait = 9;             /* 5 waits =~ 1 day, then 1 day at a time */
+
+   int wait_sec;
+   int num_wait = 0;
+   int dev_blocked;
+   char *msg;
+
+   Dmsg0(30, "enter dir_ask_sysop_to_mount_next_volume\n");
+   ASSERT(dev->dev_blocked);
+   wait_sec = min_wait;
+   for ( ;; ) {
+      if (job_cancelled(jcr)) {
+         Mmsg(&dev->errmsg, "Job %s cancelled while waiting for mount on Storage Device \"%s\".\n", 
+             jcr->Job, jcr->dev_name);
+        return 0;
+      }
+      if (dir_find_next_appendable_volume(jcr)) {    /* get suggested volume */
+        jstat = JS_WaitMount;
+        /*
+         * If we have a valid volume name and we are not
+         * removable media, return now, otherwise wait
+         * for the operator to mount the media.
+         */
+        if (jcr->VolumeName[0] && !(dev->capabilities & CAP_REM) &&      
+             dev->capabilities & CAP_LABEL) {
+            Dmsg0(90, "Return 1 from mount without wait.\n");
+           return 1;
+        }
+        if (dev->capabilities & CAP_ANONVOLS) {
+            msg = "Suggest mounting";
+        } else {
+            msg = "Please mount";
+        }
+         Jmsg(jcr, M_MOUNT, 0, "%s Volume \"%s\" on Storage Device \"%s\" for Job %s\n",
+             msg, jcr->VolumeName, jcr->dev_name, jcr->Job);
+         Dmsg3(90, "Mount %s on %s for Job %s\n",
+               jcr->VolumeName, jcr->dev_name, jcr->Job);
+      } else {
+        jstat = JS_WaitMedia;
+         Jmsg(jcr, M_MOUNT, 0, "Job %s waiting. Cannot find any appendable volumes.\n\
+Please use the \"unmount\" and \"label\"  commands to create new Volumes for:\n\
+   Storage Device \"%s\" with Pool \"%s\" and Media type \"%s\".\n\
+Use \"mount\" to resume the job.\n",
+             jcr->Job, jcr->dev_name, jcr->pool_name, jcr->media_type);
+      }
+      /*
+       * Wait then send message again
+       */
+      gettimeofday(&tv, &tz);
+      timeout.tv_nsec = tv.tv_usec * 1000;
+      timeout.tv_sec = tv.tv_sec + wait_sec;
+
+      P(dev->mutex);
+      dev_blocked = dev->dev_blocked;
+      dev->dev_blocked = BST_WAITING_FOR_SYSOP; /* indicate waiting for mount */
+      jcr->JobStatus = jstat;
+      dir_send_job_status(jcr);
+
+      for ( ;!job_cancelled(jcr); ) {
+         Dmsg1(90, "I'm going to sleep on device %s\n", dev->dev_name);
+        stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
+        if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
+           break;
+        }
+        /*         
+         * Someone other than us blocked the device (probably the
+         *  user via the Console program.   
+         * So, we continue waiting.
+         */
+        gettimeofday(&tv, &tz);
+        timeout.tv_nsec = 0;
+        timeout.tv_sec = tv.tv_sec + 10; /* wait 10 seconds */
+      }
+      dev->dev_blocked = dev_blocked;
+      V(dev->mutex);
+
+      if (stat == ETIMEDOUT) {
+        wait_sec *= 2;               /* double wait time */
+        if (wait_sec > max_wait) {   /* but not longer than maxtime */
+           wait_sec = max_wait;
+        }
+        num_wait++;
+        if (num_wait >= max_num_wait) {
+            Mmsg(&dev->errmsg, "Gave up waiting to mount Storage Device \"%s\" for Job %s\n", 
+                jcr->dev_name, jcr->Job);
+            Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+            Dmsg1(90, "Gave up waiting on device %s\n", dev->dev_name);
+           return 0;                 /* exceeded maximum waits */
+        }
+        continue;
+      }
+      if (stat == EINVAL) {
+         Mmsg2(&dev->errmsg, "pthread error in mount_next_volume stat=%d ERR=%s\n",      
+              stat, strerror(stat));
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+        return 0;
+      }
+      if (stat != 0) {
+         Jmsg(jcr, M_ERROR, 0, "pthread error in mount_next_volume stat=%d ERR=%s\n", stat,
+           strerror(stat));
+      }
+      Dmsg1(90, "Someone woke me for device %s\n", dev->dev_name);
+
+      /* Restart wait counters */
+      wait_sec = min_wait;
+      num_wait = 0;
+      /* If no VolumeName, and cannot get one, try again */
+      if (jcr->VolumeName[0] == 0 && 
+         !dir_find_next_appendable_volume(jcr)) {
+        Jmsg(jcr, M_MOUNT, 0, 
+"You woke me up, but I cannot find any appendable\n\
+volumes for Job=%s.\n", jcr->Job);
+        continue;
+      }       
+      break;
+   }
+   jcr->JobStatus = JS_Running;
+   dir_send_job_status(jcr);
+   Dmsg0(30, "leave dir_ask_sysop_to_mount_next_volume\n");
+   return 1;
+}
+
+/*
+ *   
+ *   Entered with device blocked and jcr->VolumeName is desired
+ *     volume.
+ *   Leaves with device blocked.
+ *
+ *   Returns: 1 on success (operator issues a mount command)
+ *           0 on failure
+ *             Note, must create dev->errmsg on error return.
+ *
+ */
+int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
+{
+   int stat, jstat;
+   /* ******FIXME******* put these on config variable */
+   int min_wait = 60 * 60;
+   int max_wait = 24 * 60 * 60;
+   int max_num_wait = 9;             /* 5 waits =~ 1 day, then 1 day at a time */
+   int wait_sec;
+   int num_wait = 0;
+   int dev_blocked;
+   char *msg;
+   struct timeval tv;
+   struct timezone tz;
+   struct timespec timeout;
+
+   Dmsg0(30, "enter dir_ask_sysop_to_mount_next_volume\n");
+   if (!jcr->VolumeName[0]) {
+      Mmsg0(&dev->errmsg, "Cannot request another volume: no volume name given.\n");
+      return 0;
+   }
+   ASSERT(dev->dev_blocked);
+   wait_sec = min_wait;
+   for ( ;; ) {
+      if (job_cancelled(jcr)) {
+         Mmsg(&dev->errmsg, "Job %s cancelled while waiting for mount on Storage Device \"%s\".\n", 
+             jcr->Job, jcr->dev_name);
+        return 0;
+      }
+      msg = "Please mount";
+      Jmsg(jcr, M_MOUNT, 0, "%s Volume \"%s\" on Storage Device \"%s\" for Job %s\n",
+          msg, jcr->VolumeName, jcr->dev_name, jcr->Job);
+      Dmsg3(90, "Mount %s on %s for Job %s\n",
+           jcr->VolumeName, jcr->dev_name, jcr->Job);
+
+      /*
+       * Wait then send message again
+       */
+      gettimeofday(&tv, &tz);
+      timeout.tv_nsec = tv.tv_usec * 1000;
+      timeout.tv_sec = tv.tv_sec + wait_sec;
+
+      P(dev->mutex);
+      dev_blocked = dev->dev_blocked;
+      dev->dev_blocked = BST_WAITING_FOR_SYSOP; /* indicate waiting for mount */
+      jcr->JobStatus = jstat;
+      dir_send_job_status(jcr);
+
+      for ( ;!job_cancelled(jcr); ) {
+         Dmsg1(90, "I'm going to sleep on device %s\n", dev->dev_name);
+        stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
+        if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
+           break;
+        }
+        /*         
+         * Someone other than us blocked the device (probably the
+         *  user via the Console program.   
+         * So, we continue waiting.
+         */
+        gettimeofday(&tv, &tz);
+        timeout.tv_nsec = 0;
+        timeout.tv_sec = tv.tv_sec + 10; /* wait 10 seconds */
+      }
+      dev->dev_blocked = dev_blocked;
+      V(dev->mutex);
+
+      if (stat == ETIMEDOUT) {
+        wait_sec *= 2;               /* double wait time */
+        if (wait_sec > max_wait) {   /* but not longer than maxtime */
+           wait_sec = max_wait;
+        }
+        num_wait++;
+        if (num_wait >= max_num_wait) {
+            Mmsg(&dev->errmsg, "Gave up waiting to mount Storage Device \"%s\" for Job %s\n", 
+                jcr->dev_name, jcr->Job);
+            Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+            Dmsg1(90, "Gave up waiting on device %s\n", dev->dev_name);
+           return 0;                 /* exceeded maximum waits */
+        }
+        continue;
+      }
+      if (stat == EINVAL) {
+         Mmsg2(&dev->errmsg, "pthread error in mount_volume stat=%d ERR=%s\n",      
+              stat, strerror(stat));
+         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+        return 0;
+      }
+      if (stat != 0) {
+         Jmsg(jcr, M_ERROR, 0, "pthread error in mount_next_volume stat=%d ERR=%s\n", stat,
+           strerror(stat));
+      }
+      Dmsg1(90, "Someone woke me for device %s\n", dev->dev_name);
+
+      /* Restart wait counters */
+      wait_sec = min_wait;
+      num_wait = 0;
+      break;
+   }
+   jcr->JobStatus = JS_Running;
+   dir_send_job_status(jcr);
+   Dmsg0(30, "leave dir_ask_sysop_to_mount_next_volume\n");
+   return 1;
+}
diff --git a/bacula/src/stored/authenticate.c b/bacula/src/stored/authenticate.c
new file mode 100644 (file)
index 0000000..dd76c76
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Authenticate caller
+ *
+ *   Kern Sibbald, October 2000
+ * 
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+  
+#include "bacula.h"
+#include "stored.h"
+
+static char Dir_sorry[] = "3999 No go\n";
+static char OK_hello[]  = "3000 OK Hello\n";
+
+
+/********************************************************************* 
+ *
+ *
+ */
+static int authenticate(int rcode, BSOCK *bs)
+{
+   char *name;
+   DIRRES *director;
+
+   if (rcode != R_DIRECTOR) {
+      Emsg1(M_FATAL, 0, _("I only authenticate Directors, not %d\n"), rcode);
+      return 0;
+   }
+   name = (char *) get_pool_memory(PM_MESSAGE);
+   name = (char *) check_pool_memory_size(name, bs->msglen);
+
+   if (sscanf(bs->msg, "Hello Director %127s calling\n", name) != 1) {
+      free_pool_memory(name);
+      Emsg1(M_FATAL, 0, _("Authentication failure: %s\n"), bs->msg);
+      return 0;
+   }
+   director = NULL;
+   LockRes();
+   while ((director=(DIRRES *)GetNextRes(rcode, (RES *)director))) {
+      if (strcmp(director->hdr.name, name) == 0)
+        break;
+   }
+   UnlockRes();
+   if (director && (!cram_md5_auth(bs, director->password) ||
+       !cram_md5_get_auth(bs, director->password))) {
+      director = NULL;
+   }
+   free_pool_memory(name);
+   return (director != NULL);
+}
+
+/*
+ * Inititiate the message channel with the Director.
+ * He has made a connection to our server.
+ * 
+ * Basic tasks done here:
+ *   Assume the Hello message is already in the input
+ *     buffer. We then authenticate him.
+ *   Get device, media, and pool information from Director
+ *
+ *   This is the channel across which we will send error
+ *     messages and job status information.
+ */
+int authenticate_director(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+
+   if (!authenticate(R_DIRECTOR, dir)) {
+      bnet_fsend(dir, "%s", Dir_sorry);
+      Emsg0(M_ERROR, 0, _("Unable to authenticate Director\n"));
+      return 0;
+   }
+   return bnet_fsend(dir, "%s", OK_hello);
+}
+
+int authenticate_filed(JCR *jcr)
+{
+   BSOCK *fd = jcr->file_bsock;
+
+   if (cram_md5_auth(fd, jcr->sd_auth_key) &&
+       cram_md5_get_auth(fd, jcr->sd_auth_key)) {
+      jcr->authenticated = TRUE;
+   }
+   return jcr->authenticated;
+}
diff --git a/bacula/src/stored/bacula-sd.conf.in b/bacula/src/stored/bacula-sd.conf.in
new file mode 100644 (file)
index 0000000..f3952d5
--- /dev/null
@@ -0,0 +1,95 @@
+#
+# Default Bacula Storage Daemon Configuration file
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@ @DISTVER@
+#
+# You may need to change the name of your tape drive
+#   on the "Archive Device" directive in the Device
+#   resource.  If you change the Name and/or the 
+#   "Media Type" in the Device resource, please ensure
+#   that dird.conf has corresponding changes.
+#
+
+Storage {                             # definition of myself
+  Name = @hostname@-sd
+  Address = @hostname@
+  SDPort = @sd_port@                  # Director's port      
+  WorkingDirectory = "@working_dir@"
+  Pid Directory = "@piddir@"
+  Subsys Directory = "@subsysdir@"
+}
+
+#
+# List Directors who are permitted to contact Storage daemon
+#
+Director {
+  Name = @hostname@-dir
+  Password = "@sd_password@"
+}
+
+#
+# Devices supported by this Storage daemon
+# To connect, the Director's bacula-dir.conf must have the
+#  same Name and MediaType. 
+#
+Device {
+  Name = "HP DLT 80"
+  Media Type = DLT8000
+  Archive Device = @TAPEDRIVE@
+  AutomaticMount = yes;               # when device opened, read it
+  AlwaysOpen = yes;
+  RemovableMedia = yes;
+}
+
+#Device {
+#  Name = SDT-7000                     # 
+#  Media Type = DDS-2
+#  Archive Device = @TAPEDRIVE@
+#  AutomaticMount = yes;               # when device opened, read it
+#  AlwaysOpen = yes;
+#  RemovableMedia = yes;
+#}
+
+#Device {
+#  Name = Floppy
+#  Media Type = Floppy
+#  Archive Device = /mnt/floppy
+#  RemovableMedia = yes;
+#  Random Access = Yes;
+#  AutomaticMount = yes;               # when device opened, read it
+#  AlwaysOpen = no;
+#}
+
+#Device {
+#  Name = FileStorage
+#  Media Type = File
+#  Archive Device = /tmp
+#  LabelMedia = yes;                   # lets Bacula label unlabelled media
+#  Random Access = Yes;
+#  AutomaticMount = yes;               # when device opened, read it
+#  RemovableMedia = no;
+#  AlwaysOpen = no;
+#}
+
+#
+# A very old Exabyte with no end of media detection
+#
+#Device {
+#  Name = "Exabyte 8mm"
+#  Media Type = "8mm"
+#  Archive Device = @TAPEDRIVE@
+#  Hardware end of medium = No;
+#  AutomaticMount = yes;               # when device opened, read it
+#  AlwaysOpen = Yes;
+#  RemovableMedia = yes;
+#}
+
+# 
+# Send all messages to the Director, 
+# mount messages also are sent to the email address
+#
+Messages {
+  Name = Standard
+  director = @hostname@-dir = all
+# operator = @job_email@ = mount
+}
diff --git a/bacula/src/stored/bextract.c b/bacula/src/stored/bextract.c
new file mode 100644 (file)
index 0000000..7a20cf1
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ *
+ *  Dumb program to extract files from a Bacula backup.
+ *
+ *   Kern E. Sibbald
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+#include "findlib/find.h"
+
+static void do_extract(char *fname, char *prefix);
+static void print_ls_output(char *fname, struct stat *statp);
+
+
+static DEVICE *dev = NULL;
+static int ofd = -1;
+
+static JCR *jcr;
+static FF_PKT my_ff;
+static FF_PKT *ff = &my_ff;
+
+static void usage()
+{
+   fprintf(stderr,
+"Usage: bextract [-d debug_level] <bacula-archive> <directory-to-store-files>\n"
+"       -dnn            set debug level to nn\n"
+"       -e <file>       exclude list\n"
+"       -i <file>       include list\n"
+"       -?              print this message\n\n");
+   exit(1);
+}
+
+static void my_free_jcr(JCR *jcr)
+{
+   return;
+}
+
+int main (int argc, char *argv[])
+{
+   int ch, i;
+   FILE *fd;
+   char line[1000];
+
+   my_name_is(argc, argv, "bextract");
+
+   memset(ff, 0, sizeof(FF_PKT));
+   init_include_exclude_files(ff);
+
+   while ((ch = getopt(argc, argv, "d:e:i:?")) != -1) {
+      switch (ch) {
+         case 'd':                    /* debug level */
+           debug_level = atoi(optarg);
+           if (debug_level <= 0)
+              debug_level = 1; 
+           break;
+
+         case 'e':                    /* exclude list */
+            if ((fd = fopen(optarg, "r")) == NULL) {
+               Dmsg2(0, "Could not open exclude file: %s, ERR=%s\n",
+                 optarg, strerror(errno));
+              exit(1);
+           }
+           while (fgets(line, sizeof(line), fd) != NULL) {
+              strip_trailing_junk(line);
+               Dmsg1(900, "add_exclude %s\n", line);
+              add_fname_to_exclude_list(ff, line);
+           }
+           fclose(fd);
+           break;
+
+         case 'i':                    /* include list */
+            if ((fd = fopen(optarg, "r")) == NULL) {
+               Dmsg2(0, "Could not open include file: %s, ERR=%s\n",
+                 optarg, strerror(errno));
+              exit(1);
+           }
+           while (fgets(line, sizeof(line), fd) != NULL) {
+              strip_trailing_junk(line);
+               Dmsg1(900, "add_include %s\n", line);
+              add_fname_to_include_list(ff, 0, line);
+           }
+           fclose(fd);
+           break;
+
+         case '?':
+        default:
+           usage();
+
+      }  
+   }
+   argc -= optind;
+   argv += optind;
+
+   if (argc != 2) {
+      Dmsg0(0, "Wrong number of arguments: \n");
+      usage();
+   }
+
+   /*
+    * Ensure that every message is always printed
+    */
+   for (i=1; i<=M_MAX; i++) {
+      add_msg_dest(MD_STDOUT, i, NULL, NULL);
+   }
+
+   jcr = new_jcr(sizeof(JCR), my_free_jcr);
+   jcr->VolSessionId = 1;
+   jcr->VolSessionTime = (uint32_t)time(NULL);
+   jcr->NumVolumes = 1;
+
+   do_extract(argv[0], argv[1]);
+
+   free_jcr(jcr);
+   return 0;
+}
+  
+
+static void do_extract(char *devname, char *where)
+{
+   int n;     
+   char VolName[100];
+   char *p;
+   struct stat statp;
+   int extract = FALSE;
+   int type;
+   long record_file_index;
+   long total = 0;
+   DEV_RECORD rec;
+   DEV_BLOCK *block;
+   char *fname;                      /* original file name */
+   char *ofile;                      /* output name with prefix */
+   char *lname;                      /* link name */
+   int wherelen;                     /* prefix length */
+
+   if (strncmp(devname, "/dev/", 5) != 0) {
+      /* Try stripping file part */
+      p = devname + strlen(devname);
+      while (p >= devname && *p != '/') {
+        p--;
+      }
+      if (*p == '/') {
+        strcpy(VolName, p+1);
+        *p = 0;
+      }
+   }
+
+   dev = init_dev(NULL, devname);
+   if (!dev || !open_device(dev)) {
+      Emsg1(M_ABORT, 0, "Cannot open %s\n", devname);
+   }
+   Dmsg0(90, "Device opened for read.\n");
+
+   if (stat(where, &statp) < 0) {
+      Emsg2(M_ABORT, 0, "Cannot stat %s. It must exist. ERR=%s\n",
+        where, strerror(errno));
+   }
+   if (!S_ISDIR(statp.st_mode)) {
+      Emsg1(M_ABORT, 0, "%s must be a directory.\n", where);
+   }
+
+   wherelen = strlen(where);
+   fname = (char *)get_pool_memory(PM_FNAME);
+   ofile = (char *)get_pool_memory(PM_FNAME);
+   lname = (char *)get_pool_memory(PM_FNAME);
+
+   block = new_block(dev);
+
+   strcpy(jcr->VolumeName, VolName);
+
+   if (!acquire_device_for_read(jcr, dev, block)) {
+      Emsg1(M_ABORT, 0, "Cannot open %s\n", devname);
+   }
+
+   memset(&rec, 0, sizeof(rec));
+   rec.data = (char *) get_memory(70000);
+
+   for ( ;; ) {
+
+      if (!read_record(dev, block, &rec)) {
+        uint32_t status;
+        if (dev->state & ST_EOT) {
+           break;
+        }
+        if (dev->state & ST_EOF) {
+           continue;                 /* try again */
+        }
+         Dmsg0(0, "Read Record got a bad record\n");
+        status_dev(dev, &status);
+         Dmsg1(20, "Device status: %x\n", status);
+        if (status & MT_EOD)
+            Emsg0(M_ABORT, 0, "Unexpected End of Data\n");
+        else if (status & MT_EOT)
+            Emsg0(M_ABORT, 0, "Unexpected End of Tape\n");
+        else if (status & MT_EOF)
+            Emsg0(M_ABORT, 0, "Unexpected End of File\n");
+        else if (status & MT_DR_OPEN)
+            Emsg0(M_ABORT, 0, "Tape Door is Open\n");
+        else if (!(status & MT_ONLINE))
+            Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n");
+        else
+            Emsg3(M_ABORT, 0, "Read error %d on Record Header %s: %s\n", n, dev_name(dev), strerror(errno));
+      }
+
+
+      /* This is no longer used */
+      if (rec.VolSessionId == 0 && rec.VolSessionTime == 0) {
+         Emsg0(M_ERROR, 0, "Zero header record. This shouldn't happen.\n");
+        break;                       /* END OF FILE */
+      }
+
+      /* 
+       * Check for Start or End of Session Record 
+       *
+       */
+      if (rec.FileIndex < 0) {
+        char *rtype;
+        switch (rec.FileIndex) {
+           case PRE_LABEL:
+               rtype = "Fresh Volume Label";   
+              break;
+           case VOL_LABEL:
+               rtype = "Volume Label";
+              break;
+           case SOS_LABEL:
+               rtype = "Begin Session";
+              break;
+           case EOS_LABEL:
+               rtype = "End Session";
+              break;
+           case EOM_LABEL:
+               rtype = "End of Media";
+              break;
+           default:
+               rtype = "Unknown";
+              break;
+        }
+        if (debug_level > 0) {
+            printf("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
+              rtype, rec.VolSessionId, rec.VolSessionTime, rec.Stream, rec.data_len);
+        }
+        continue;
+      }
+
+      /* File Attributes stream */
+      if (rec.Stream == STREAM_UNIX_ATTRIBUTES) {
+        char *ap, *lp;
+
+        /* If extracting, it was from previous stream, so
+         * close the output file.
+         */
+        if (extract) {
+           if (ofd < 0) {
+               Emsg0(M_ABORT, 0, "Logic error output file should be open\n");
+           }
+           close(ofd);
+           ofd = -1;
+           extract = FALSE;
+           set_statp(jcr, fname, ofile, lname, type, &statp);
+        }
+
+        if (sizeof_pool_memory(fname) < rec.data_len) {
+           fname = (char *) realloc_pool_memory(fname, rec.data_len + 1);
+        }
+        if (sizeof_pool_memory(ofile) < sizeof_pool_memory(fname) + wherelen + 1) {
+           ofile = (char *)realloc_pool_memory(ofile, sizeof_pool_memory(fname) + wherelen + 1);
+        }
+        if (sizeof_pool_memory(lname) < rec.data_len) {
+           ofile = (char *)realloc_pool_memory(ofile, rec.data_len + 1);
+        }
+        *fname = 0;
+        *lname = 0;
+
+        /*              
+         * An Attributes record consists of:
+         *    File_index
+         *    Type   (FT_types)
+         *    Filename
+         *    Attributes
+         *    Link name (if file linked i.e. FT_LNK)
+         *
+         */
+         sscanf(rec.data, "%ld %d %s", &record_file_index, &type, fname);
+        if (record_file_index != rec.FileIndex)
+            Emsg2(M_ABORT, 0, "Record header file index %ld not equal record index %ld\n",
+              rec.FileIndex, record_file_index);
+        ap = rec.data;
+        /* Skip to attributes */
+        while (*ap++ != 0)
+           ;
+        /* Skip to Link name */
+        if (type == FT_LNK) {
+           lp = ap;
+           while (*lp++ != 0) {
+              ;
+           }
+            strcat(lname, lp);        /* "save" link name */
+        } else {
+           *lname = 0;
+        }
+
+        /* Is this the file we want? */
+        if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) {
+
+           decode_stat(ap, &statp);
+           /*
+            * Prepend the where directory so that the
+            * files are put where the user wants.
+            *
+            * We do a little jig here to handle Win32 files with
+            * a drive letter.  
+            *   If where is null and we are running on a win32 client,
+            *      change nothing.
+            *   Otherwise, if the second character of the filename is a
+            *   colon (:), change it into a slash (/) -- this creates
+            *   a reasonable pathname on most systems.
+            */
+           strcpy(ofile, where);
+            if (fname[1] == ':') {
+               fname[1] = '/';
+              strcat(ofile, fname);
+               fname[1] = ':';
+           } else {
+              strcat(ofile, fname);
+           }
+/*          Dmsg1(000, "Restoring: %s\n", ofile); */
+
+           extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd);
+
+           if (extract) {
+               print_ls_output(ofile, &statp);   
+           }
+        }
+
+      /* Data stream and extracting */
+      } else if (rec.Stream == STREAM_FILE_DATA) {
+        if (extract) {
+           total += rec.data_len;
+            Dmsg2(8, "Write %ld bytes, total=%ld\n", rec.data_len, total);
+           if ((uint32_t)write(ofd, rec.data, rec.data_len) != rec.data_len) {
+               Emsg1(M_ABORT, 0, "Write error: %s\n", strerror(errno));
+           }
+        }
+
+      /* If extracting, wierd stream (not 1 or 2), close output file anyway */
+      } else if (extract) {
+        if (ofd < 0) {
+            Emsg0(M_ABORT, 0, "Logic error output file should be open\n");
+        }
+        close(ofd);
+        ofd = -1;
+        extract = FALSE;
+        set_statp(jcr, fname, ofile, lname, type, &statp);
+      } else if (rec.Stream != STREAM_MD5_SIGNATURE) {
+         Dmsg2(0, "None of above!!! stream=%d data=%s\n", rec.Stream, rec.data);
+      }
+   }
+
+   /* If output file is still open, it was the last one in the
+    * archive since we just hit an end of file, so close the file. 
+    */
+   if (ofd >= 0) {
+      close(ofd);
+      set_statp(jcr, fname, ofile, lname, type, &statp);
+   }
+   release_device(jcr, dev, block);
+
+   free_pool_memory(fname);
+   free_pool_memory(ofile);
+   free_pool_memory(lname);
+   term_dev(dev);
+   free_block(block);
+   return;
+}
+
+extern char *getuser(uid_t uid);
+extern char *getgroup(gid_t gid);
+
+static void print_ls_output(char *fname, struct stat *statp)
+{
+   char buf[1000]; 
+   char *p, *f;
+   int n;
+
+   p = encode_mode(statp->st_mode, buf);
+   n = sprintf(p, "  %2d ", (uint32_t)statp->st_nlink);
+   p += n;
+   n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid));
+   p += n;
+   n = sprintf(p, "%8lld  ", (uint64_t)statp->st_size);
+   p += n;
+   p = encode_time(statp->st_ctime, p);
+   *p++ = ' ';
+   *p++ = ' ';
+   for (f=fname; *f; )
+      *p++ = *f++;
+   *p++ = '\n';
+   *p = 0;
+   fputs(buf, stdout);
+}
diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c
new file mode 100644 (file)
index 0000000..012014e
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ *
+ *   block.c -- tape block handling functions
+ *
+ *             Kern Sibbald, March MMI
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+#include "stored.h"
+
+extern int debug_level;
+
+/*
+ * Dump the block header, then walk through
+ * the block printing out the record headers.
+ */
+void dump_block(DEV_BLOCK *b, char *msg)
+{
+   ser_declare;
+   char *p;
+   char Id[BLKHDR_ID_LENGTH+1];
+   uint32_t CheckSum, BlockCheckSum;
+   uint32_t block_len;
+   uint32_t BlockNumber;
+   uint32_t VolSessionId, VolSessionTime, data_len;
+   int32_t  FileIndex;
+   int32_t  Stream;
+
+   unser_begin(b->buf, BLKHDR_LENGTH);
+   unser_uint32(CheckSum);
+   unser_uint32(block_len);
+   unser_uint32(BlockNumber);
+   unser_bytes(Id, BLKHDR_ID_LENGTH);
+   ASSERT(unser_length(b->buf) == BLKHDR_LENGTH);
+   Id[BLKHDR_ID_LENGTH] = 0;
+
+   if (block_len > 100000) {
+      Dmsg3(20, "Dump block %s %s blocksize too big %d\n", msg, b, block_len);
+      return;
+   }
+
+   BlockCheckSum = bcrc32((uint8_t *)b->buf+BLKHDR_CS_LENGTH,
+                        block_len-BLKHDR_CS_LENGTH);
+   Dmsg6(10, "Dump block %s %x: size=%d BlkNum=%d\n\
+               Hdrcksum=%x cksum=%x\n",
+      msg, b, block_len, BlockNumber, CheckSum, BlockCheckSum);
+   p = b->buf + BLKHDR_LENGTH;
+   while (p < (b->buf + block_len+RECHDR_LENGTH)) { 
+      unser_begin(p, RECHDR_LENGTH);
+      unser_uint32(VolSessionId);
+      unser_uint32(VolSessionTime);
+      unser_int32(FileIndex);
+      unser_int32(Stream);
+      unser_uint32(data_len);
+      Dmsg6(10, "Rec: VId=%d VT=%d FI=%s Strm=%s len=%d p=%x\n",
+          VolSessionId, VolSessionTime, FI_to_ascii(FileIndex), stream_to_ascii(Stream),
+          data_len, p);
+      p += data_len + RECHDR_LENGTH;
+  }
+
+}
+    
+/*
+ * Create a new block structure.                          
+ * We pass device so that the block can inherit the
+ * min and max block sizes.
+ */
+DEV_BLOCK *new_block(DEVICE *dev)
+{
+   DEV_BLOCK *block = (DEV_BLOCK *) get_memory(sizeof(DEV_BLOCK));
+
+   memset(block, 0, sizeof(DEV_BLOCK));
+
+   if (dev->max_block_size == 0) {
+      block->buf_len = DEFAULT_BLOCK_SIZE;
+   } else {
+      block->buf_len = dev->max_block_size;
+   }
+   if (block->buf_len % TAPE_BSIZE != 0) {
+      Mmsg2(&dev->errmsg, _("Block size %d forced to be multiple of %d\n"), 
+        block->buf_len, TAPE_BSIZE);
+      Emsg0(M_WARNING, 0, dev->errmsg);
+      block->buf_len = ((block->buf_len + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
+   }
+   block->block_len = block->buf_len;  /* default block size */
+   block->buf = (char *) get_memory(block->buf_len); 
+   if (block->buf == NULL) {
+      Mmsg0(&dev->errmsg, _("Unable to malloc block buffer.\n"));
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return NULL;
+   }
+   empty_block(block);
+   Dmsg1(90, "Returning new block=%x\n", block);
+   return block;
+}
+
+/*
+ * Free block 
+ */
+void free_block(DEV_BLOCK *block)
+{
+   Dmsg1(199, "free_block buffer %x\n", block->buf);
+   free_memory(block->buf);
+   Dmsg1(199, "free_block block %x\n", block);
+   free_memory(block);
+}
+
+/* Empty the block -- for writing */
+void empty_block(DEV_BLOCK *block)
+{
+   block->binbuf = BLKHDR_LENGTH;
+   block->bufp = block->buf + block->binbuf;
+   block->read_len = 0;
+   block->failed_write = FALSE;
+}
+
+/*
+ * Create block header just before write. The space
+ * in the buffer should have already been reserved by
+ * init_block.
+ */
+static void ser_block_header(DEV_BLOCK *block)
+{
+   ser_declare;
+   uint32_t CheckSum = 0;
+   uint32_t block_len = block->binbuf;
+   
+   Dmsg1(190, "ser_block_header: block_len=%d\n", block_len);
+   ser_begin(block->buf, BLKHDR_LENGTH);
+   ser_uint32(CheckSum);
+   ser_uint32(block_len);
+   ser_uint32(block->BlockNumber);
+   ser_bytes(BLKHDR_ID, BLKHDR_ID_LENGTH);
+   ASSERT(ser_length(block->buf) == BLKHDR_LENGTH);
+
+   /* Checksum whole block except for the checksum */
+   CheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH, 
+                block_len-BLKHDR_CS_LENGTH);
+   Dmsg1(190, "ser_bloc_header: checksum=%x\n", CheckSum);
+   ser_begin(block->buf, BLKHDR_LENGTH);
+   ser_uint32(CheckSum);
+}
+
+/*
+ * Unserialized the block header for reading block.
+ *  This includes setting all the buffer pointers correctly.
+ *
+ *  Returns: 0 on failure (not a block)
+ *          1 on success
+ */
+static int unser_block_header(DEVICE *dev, DEV_BLOCK *block)
+{
+   ser_declare;
+   char Id[BLKHDR_ID_LENGTH+1];
+   uint32_t CheckSum, BlockCheckSum;
+   uint32_t block_len;
+   uint32_t EndBlock;
+   uint32_t BlockNumber;
+
+   unser_begin(block->buf, BLKHDR_LENGTH);
+   unser_uint32(CheckSum);
+   unser_uint32(block_len);
+   unser_uint32(BlockNumber);
+   unser_bytes(Id, BLKHDR_ID_LENGTH);
+   ASSERT(unser_length(block->buf) == BLKHDR_LENGTH);
+
+   Id[BLKHDR_ID_LENGTH] = 0;
+   block->bufp = block->buf + BLKHDR_LENGTH;
+   if (strncmp(Id, BLKHDR_ID, BLKHDR_ID_LENGTH) != 0) {
+      Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"),
+        BLKHDR_ID, Id);
+      Emsg0(M_ERROR, 0, dev->errmsg);
+      return 0;
+   }
+
+   ASSERT(block_len < MAX_BLOCK_LENGTH);    /* temp sanity check */
+
+   Dmsg1(190, "unser_block_header block_len=%d\n", block_len);
+   /* Find end of block or end of buffer whichever is smaller */
+   if (block_len > block->read_len) {
+      EndBlock = block->read_len;
+   } else {
+      EndBlock = block_len;
+   }
+   block->binbuf = EndBlock - BLKHDR_LENGTH;
+   block->block_len = block_len;
+   block->BlockNumber = BlockNumber;
+   Dmsg3(190, "Read binbuf = %d %d block_len=%d\n", block->binbuf,
+      BLKHDR_LENGTH, block_len);
+   if (block_len > block->buf_len) {
+      Mmsg2(&dev->errmsg,  _("Block length %d is greater than buffer %d\n"),
+        block_len, block->buf_len);
+      Emsg0(M_ERROR, 0, dev->errmsg);
+      return 0;
+   }
+   if (block_len <= block->read_len) {
+      BlockCheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
+                        block_len-BLKHDR_CS_LENGTH);
+      if (BlockCheckSum != CheckSum) {
+         Dmsg2(00, "Block checksum mismatch: calc=%x blk=%x\n", BlockCheckSum,
+           CheckSum);
+         Mmsg2(&dev->errmsg, _("Block checksum mismatch: calc=%x blk=%x\n"), BlockCheckSum,
+           CheckSum);
+        return 0;
+      }
+   }
+   return 1;
+}
+
+/*  
+ * Write a block to the device, with locking and unlocking
+ *
+ * Returns: 1 on success
+ *       : 0 on failure
+ *
+ */
+int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   int stat = 1;
+   lock_device(dev);
+   if (!write_block_to_dev(dev, block)) {
+       stat = fixup_device_block_write_error(jcr, dev, block);
+   }
+   unlock_device(dev);
+   return stat;
+}
+
+/*
+ * Write a block to the device 
+ *
+ *  Returns: 1 on success or EOT
+ *          0 on hard error
+ */
+int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block)
+{
+   int stat = 0;
+   uint32_t wlen;                    /* length to write */
+
+   ASSERT(block->binbuf == ((uint32_t) (block->bufp - block->buf)));
+
+   /* dump_block(block, "before write"); */
+   if (dev->state & ST_WEOT) {
+      Dmsg0(90, "return write_block_to_dev with ST_WEOT\n");
+      return 0;
+   }
+   wlen = block->binbuf;
+   if (wlen <= BLKHDR_LENGTH) {       /* Does block have data in it? */
+      Dmsg0(190, "return write_block_to_dev no data to write\n");
+      return 1;
+   }
+   /* 
+    * Clear to the end of the buffer if it is not full,
+    *  and on tape devices, apply min and fixed blocking.
+    */
+   if (wlen != block->buf_len) {
+      uint32_t blen;                 /* current buffer length */
+
+      Dmsg2(200, "binbuf=%d buf_len=%d\n", block->binbuf, block->buf_len);
+      blen = wlen;
+
+      /* Adjust write size to min/max for tapes only */
+      if (dev->state & ST_TAPE) {
+        if (wlen < dev->min_block_size) {
+           wlen =  ((dev->min_block_size + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
+        }
+        if (dev->min_block_size == dev->max_block_size) {
+           wlen = block->buf_len;    /* fixed block size already rounded */
+        }
+      }
+      if (wlen-blen > 0) {
+        memset(block->bufp, 0, wlen-blen); /* clear garbage */
+      }
+   }  
+
+   dev->block_num++;
+   block->BlockNumber = dev->block_num;
+   ser_block_header(block);
+
+   /* dump_block(block, "after ser_hdr"); */
+   if ((dev->max_volume_size > 0) &&
+       ((int64_t) (dev->VolCatInfo.VolCatBytes + block->binbuf)) >= dev->max_volume_size) {
+      dev->state |= ST_WEOT;
+      Dmsg0(10, "==== Output bytes Triggered medium max capacity.\n");
+      Mmsg2(&dev->errmsg, _("Max. Volume capacity %" lld " exceeded on device %s.\n"),
+        dev->max_volume_size, dev->dev_name);
+      block->failed_write = TRUE;
+/* ****FIXME**** write EOD record here */
+      weof_dev(dev, 1);              /* end the tape */
+      weof_dev(dev, 1);              /* write second eof */
+      return 0;
+   }
+
+   dev->VolCatInfo.VolCatWrites++;
+   if ((uint32_t) (stat=write(dev->fd, block->buf, wlen)) != wlen) {
+      /* We should check for errno == ENOSPC, BUT many 
+       * devices simply report EIO when it is full.
+       * with a little more thought we may be able to check
+       * capacity and distinguish real errors and EOT
+       * conditions.  In any case, we probably want to
+       * simulate an End of Medium.
+       */
+/***FIXME**** if we wrote a partial record, back up over it */
+      dev->state |= ST_EOF | ST_EOT | ST_WEOT;
+      clrerror_dev(dev, -1);
+
+      Dmsg2(0, "=== Write error %d: ERR=%s\n", dev->dev_errno,
+        strerror(dev->dev_errno));
+
+      if (dev->dev_errno == 0) {
+        dev->dev_errno = ENOSPC;        /* out of space */
+      }
+      Mmsg2(&dev->errmsg, _("Write error on device %s. ERR=%s.\n"), 
+        dev->dev_name, strerror(dev->dev_errno));
+      block->failed_write = TRUE;
+      weof_dev(dev, 1);              /* end the tape */
+      weof_dev(dev, 1);              /* write second eof */
+      return 0;
+   }
+   dev->VolCatInfo.VolCatBytes += block->binbuf;
+   dev->VolCatInfo.VolCatBlocks++;   
+   Dmsg2(190, "write_block: wrote block %d bytes=%d\n", dev->block_num,
+      wlen);
+   empty_block(block);
+   return 1;
+}
+
+/*  
+ * Read block with locking
+ *
+ */
+int read_block_from_device(DEVICE *dev, DEV_BLOCK *block)
+{
+   int stat;
+   Dmsg0(90, "Enter read_block_from_device\n");
+   lock_device(dev);
+   stat = read_block_from_dev(dev, block);
+   unlock_device(dev);
+   Dmsg0(90, "Leave read_block_from_device\n");
+   return stat;
+}
+
+/*
+ * Read the next block into the block structure and unserialize
+ *  the block header.  For a file, the block may be partially
+ *  or completely in the current buffer.
+ */
+int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block)
+{
+   int stat;
+
+   Dmsg0(90, "Full read() in read_block_from_device()\n");
+   if ((stat=read(dev->fd, block->buf, block->buf_len)) < 0) {
+
+/* ***FIXME****  add code to detect buffer too small, and
+   reallocate buffer, backspace, and reread.
+   ENOMEM
+ */
+
+      Dmsg1(90, "Read device got: ERR=%s\n", strerror(errno));
+      clrerror_dev(dev, -1);
+      block->read_len = 0;
+      Mmsg2(&dev->errmsg, _("Read error on device %s. ERR=%s.\n"), 
+        dev->dev_name, strerror(dev->dev_errno));
+      return 0;
+   }
+   Dmsg1(90, "Read device got %d bytes\n", stat);
+   if (stat == 0) {            /* Got EOF ! */
+      dev->block_num = block->read_len = 0;
+      Mmsg1(&dev->errmsg, _("Read zero bytes on device %s.\n"), dev->dev_name);
+      if (dev->state & ST_EOF) { /* EOF alread read? */
+        dev->state |= ST_EOT;  /* yes, 2 EOFs => EOT */
+        return 0;
+      }
+      dev->file++;             /* increment file */
+      dev->state |= ST_EOF;    /* set EOF read */
+      return 0;                /* return eof */
+   }
+   /* Continue here for successful read */
+   block->read_len = stat;     /* save length read */
+   if (block->read_len < BLKHDR_LENGTH) {
+      Mmsg2(&dev->errmsg, _("Very short block of %d bytes on device %s discarded.\n"), 
+        block->read_len, dev->dev_name);
+      dev->state |= ST_SHORT;  /* set short block */
+      block->read_len = block->binbuf = 0;
+      return 0;                /* return error */
+   }  
+   if (!unser_block_header(dev, block)) {
+      return 0;
+   }
+
+   if (block->block_len > block->read_len) {
+      Mmsg2(&dev->errmsg, _("Short block of %d bytes on device %s discarded.\n"), 
+        block->read_len, dev->dev_name);
+      dev->state |= ST_SHORT;  /* set short block */
+      block->read_len = block->binbuf = 0;
+      return 0;                /* return error */
+   }  
+
+   /* Make sure block size is not too big (temporary
+    * sanity check) and that we read the full block.
+    */
+   ASSERT(block->block_len < MAX_BLOCK_LENGTH);
+
+   dev->state &= ~(ST_EOF|ST_SHORT); /* clear EOF and short block */
+   dev->block_num++;
+
+   /*
+    * If we read a short block on disk,
+    * seek to beginning of next block. This saves us
+    * from shuffling blocks around in the buffer. Take a
+    * look at this from an efficiency stand point later, but
+    * it should only happen once at the end of each job.
+    */
+   Dmsg0(200, "At end of read block\n");
+   if (block->read_len > block->block_len && !(dev->state & ST_TAPE)) {
+
+      Dmsg3(200, "Block: %d read_len %d > %d block_len\n", dev->block_num,
+block->read_len, block->block_len);
+      lseek(dev->fd, block->block_len-block->read_len, SEEK_CUR);   
+      Dmsg2(90, "Did lseek blk_size=%d rdlen=%d\n", block->block_len,
+           block->read_len);
+   }
+   Dmsg2(200, "Exit read_block read_len=%d block_len=%d\n",
+      block->read_len, block->block_len);
+   return 1;
+}
diff --git a/bacula/src/stored/block.h b/bacula/src/stored/block.h
new file mode 100644 (file)
index 0000000..b376f3b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Block definitions for Bacula media data format.
+ *
+ *    Kern Sibbald
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#ifndef __BLOCK_H
+#define __BLOCK_H 1
+
+#define MAX_BLOCK_LENGTH    500001      /* this is a sort of sanity check */
+#define DEFAULT_BLOCK_SIZE (512 * 126)  /* 64,512 N.B. do not use 65,636 here */
+
+/* Block Header definitions. */
+#define BLKHDR_ID        "BB01"
+#define BLKHDR_ID_LENGTH  4
+#define BLKHDR_CS_LENGTH  4             /* checksum length */
+#define BLKHDR_LENGTH    16             /* Total length */
+
+/*
+ * This is the Media structure for a block header
+ *  Note, when written, it is serialized.
+ */
+typedef struct s_block_hdr {
+   uint32_t CheckSum;
+   uint32_t block_size;
+   uint32_t BlockNumber;
+   char     Id[BLKHDR_ID_LENGTH+1];
+} BLOCK_HDR;
+
+/*
+ * DEV_BLOCK for reading and writing blocks.
+ * This is the basic unit that is written to the device, and
+ * it contains a Block Header followd by Records.  Note,
+ * at times (when reading a file), this block may contain
+ * multiple blocks.
+ *
+ *  This is the memory structure for a device block.
+ */
+typedef struct s_dev_block {
+   struct s_dev_block *next;          /* pointer to next one */
+   /* binbuf is the number of bytes remaining
+    * in the buffer. For writes, it is bytes not yet written.
+    * For reads, it is remaining bytes not yet read.
+    */
+   uint32_t binbuf;                   /* bytes in buffer */
+   uint32_t block_len;                /* length of current block read */
+   uint32_t buf_len;                  /* max/default block length */
+   uint32_t BlockNumber;              /* sequential block number */
+   uint32_t read_len;                 /* bytes read into buffer */  
+   int failed_write;                  /* set if write failed */
+   char *bufp;                        /* pointer into buffer */
+   char *buf;                         /* actual data buffer. This is a 
+                                       * Pool buffer!   
+                                       */
+} DEV_BLOCK;
+
+#endif
diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c
new file mode 100644 (file)
index 0000000..de60d1a
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ *
+ *  Dumb program to do an "ls" of a Bacula 1.0 mortal file.
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+#include "findlib/find.h"
+
+static void do_blocks(char *infname);
+static void do_jobs(char *infname);
+static void do_ls(char *fname);
+static void print_ls_output(char *fname, char *link, int type, struct stat *statp);
+
+static DEVICE *dev;
+static int default_tape = FALSE;
+static int dump_label = FALSE;
+static int list_blocks = FALSE;
+static int list_jobs = FALSE;
+static int verbose = 0;
+
+extern char BaculaId[];
+
+static FF_PKT ff;
+
+static void usage()
+{
+   fprintf(stderr,
+"Usage: bls [-d debug_level] <physical-device-name>\n"
+"       -b              list blocks\n"
+"       -e <file>       exclude list\n"
+"       -i <file>       include list\n"
+"       -j              list jobs\n"
+"       -L              list tape label\n"
+"    (none of above)    list saved files\n"
+"       -t              use default tape device\n"
+"       -v              be verbose\n"
+"       -?              print this message\n\n");
+   exit(1);
+}
+
+
+int main (int argc, char *argv[])
+{
+   int i, ch;
+   FILE *fd;
+   char line[1000];
+
+   my_name_is(argc, argv, "bls");
+
+   memset(&ff, 0, sizeof(ff));
+   init_include_exclude_files(&ff);
+
+   while ((ch = getopt(argc, argv, "bd:e:i:jLtv?")) != -1) {
+      switch (ch) {
+         case 'b':
+           list_blocks = TRUE;
+           break;
+         case 'd':                    /* debug level */
+           debug_level = atoi(optarg);
+           if (debug_level <= 0)
+              debug_level = 1; 
+           break;
+
+         case 'e':                    /* exclude list */
+            if ((fd = fopen(optarg, "r")) == NULL) {
+               Dmsg2(0, "Could not open exclude file: %s, ERR=%s\n",
+                 optarg, strerror(errno));
+              exit(1);
+           }
+           while (fgets(line, sizeof(line), fd) != NULL) {
+              strip_trailing_junk(line);
+               Dmsg1(000, "add_exclude %s\n", line);
+              add_fname_to_exclude_list(&ff, line);
+           }
+           fclose(fd);
+           break;
+
+         case 'i':                    /* include list */
+            if ((fd = fopen(optarg, "r")) == NULL) {
+               Dmsg2(0, "Could not open include file: %s, ERR=%s\n",
+                 optarg, strerror(errno));
+              exit(1);
+           }
+           while (fgets(line, sizeof(line), fd) != NULL) {
+              strip_trailing_junk(line);
+               Dmsg1(000, "add_include %s\n", line);
+              add_fname_to_include_list(&ff, 0, line);
+           }
+           fclose(fd);
+           break;
+
+         case 'j':
+           list_jobs = TRUE;
+           break;
+
+         case 'L':
+           dump_label = TRUE;
+           break;
+
+         case 't':
+           default_tape = TRUE;
+           break;
+
+         case 'v':
+           verbose++;
+           break;
+
+         case '?':
+        default:
+           usage();
+
+      }  
+   }
+   argc -= optind;
+   argv += optind;
+
+   if (!argc && !default_tape) {
+      Dmsg0(0, "No archive name specified\n");
+      usage();
+   }
+
+   if (ff.included_files_list == NULL) {
+      add_fname_to_include_list(&ff, 0, "/");
+   }
+
+   /*
+    * Ensure that every message is always printed
+    */
+   for (i=1; i<=M_MAX; i++) {
+      add_msg_dest(MD_STDOUT, i, NULL, NULL);
+   }
+
+   /* Try default device */
+   if (default_tape) {
+      do_ls(DEFAULT_TAPE_DRIVE);
+      return 0;
+   }
+
+
+   for (i=0; i < argc; i++) {
+      if (list_blocks) {
+        do_blocks(argv[i]);
+      } else if (list_jobs) {
+        do_jobs(argv[i]);
+      } else {
+        do_ls(argv[i]);
+      }
+   }
+
+   return 0;
+}
+
+static void my_free_jcr(JCR *jcr)
+{
+   return;
+}
+
+/* List just block information */
+static void do_blocks(char *infname)
+{
+   char Vol[2000];
+   char *VolName;
+   char *p;
+   DEV_RECORD *rec;
+   DEV_BLOCK *block;
+   int NumVolumes, CurVolume;
+   JCR *jcr;
+
+   jcr = new_jcr(sizeof(JCR), my_free_jcr);
+   VolName = Vol;
+   VolName[0] = 0;
+   if (strncmp(infname, "/dev/", 5) != 0) {
+      /* Try stripping file part */
+      p = infname + strlen(infname);
+      while (p >= infname && *p != '/')
+        p--;
+      if (*p == '/') {
+        strcpy(VolName, p+1);
+        *p = 0;
+      }
+   }
+   Dmsg2(10, "Device=%s, Vol=%s.\n", infname, VolName);
+   dev = init_dev(NULL, infname);
+   if (!dev) {
+      Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
+   }
+   /* ***FIXME**** init capabilities */
+   if (!open_device(dev)) {
+      Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
+   }
+   Dmsg0(90, "Device opened for read.\n");
+
+   rec = new_record();
+   block = new_block(dev);
+
+   NumVolumes = 0;
+   CurVolume = 1;
+   for (p = VolName; p && *p; ) {
+      p = strchr(p, '^');
+      if (p) {
+        *p++ = 0;
+      }
+      NumVolumes++;
+   }
+
+   jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, strlen(VolName)+1);
+   strcpy(jcr->VolumeName, VolName);
+   if (!acquire_device_for_read(jcr, dev, block)) {
+      Emsg0(M_ERROR, 0, dev->errmsg);
+      exit(1);
+   }
+
+   dump_volume_label(dev);
+
+   /* Assume that we have already read the volume label.
+    * If on second or subsequent volume, adjust buffer pointer 
+    */
+   if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
+      Dmsg1(0, "\n\
+Warning, this Volume is a continuation of Volume %s\n",
+               dev->VolHdr.PrevVolName);
+   }
+   for ( ;; ) {
+
+      if (!read_block_from_device(dev, block)) {
+        uint32_t status;
+         Dmsg0(20, "!read_record()\n");
+        if (dev->state & ST_EOT) {
+           if (rec->remainder) {
+               Dmsg0(20, "Not end of record.\n");
+           }
+            Dmsg2(20, "NumVolumes=%d CurVolume=%d\n", NumVolumes, CurVolume);
+           if (NumVolumes > 1 && CurVolume < NumVolumes) {
+              p = VolName;
+              while (*p++)  
+                 { }
+              CurVolume++;
+               Dmsg1(20, "There is another volume %s.\n", p);
+              VolName = p;
+              close_dev(dev);
+              jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, 
+                                  strlen(VolName)+1);
+              strcpy(jcr->VolumeName, VolName);
+               printf("Mount Volume %s on device %s and press return when ready.",
+                 VolName, infname);
+              getchar();   
+              block->binbuf = 0;     /* consumed all bytes */
+              if (!ready_dev_for_read(jcr, dev, block)) {
+                  Emsg2(M_ABORT, 0, "Cannot open Dev=%s, Vol=%s\n", infname, VolName);
+              }
+              continue;
+           }
+            printf("End of Device reached.\n");
+           break;
+        }
+        if (dev->state & ST_EOF) {
+            Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
+            Dmsg0(20, "read_record got eof. try again\n");
+           continue;
+        }
+        if (dev->state & ST_SHORT) {
+           Emsg0(M_INFO, 0, dev->errmsg);
+           continue;
+        }
+        Emsg0(M_ERROR, 0, dev->errmsg);
+        status_dev(dev, &status);
+         Dmsg1(20, "Device status: %x\n", status);
+        if (status & MT_EOD)
+            Emsg0(M_ABORT, 0, "Unexpected End of Data\n");
+        else if (status & MT_EOT)
+            Emsg0(M_ABORT, 0, "Unexpected End of Tape\n");
+        else if (status & MT_EOF)
+            Emsg0(M_ABORT, 0, "Unexpected End of File\n");
+        else if (status & MT_DR_OPEN)
+            Emsg0(M_ABORT, 0, "Tape Door is Open\n");
+        else if (!(status & MT_ONLINE))
+            Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n");
+        else
+            Emsg2(M_ABORT, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno));
+        break;
+      }
+
+      printf("Block: %d size=%d\n", block->BlockNumber, block->block_len);
+
+   }
+   term_dev(dev);
+   free_record(rec);
+   free_block(block);
+   free_jcr(jcr);
+   return;
+}
+
+/* Do list job records */
+static void do_jobs(char *infname)
+{
+   char Vol[2000];
+   char *VolName;
+   char *p;
+   DEV_RECORD *rec;
+   DEV_BLOCK *block;
+   int NumVolumes, CurVolume;
+   JCR *jcr;
+
+   jcr = new_jcr(sizeof(JCR), my_free_jcr);
+   VolName = Vol;
+   VolName[0] = 0;
+   if (strncmp(infname, "/dev/", 5) != 0) {
+      /* Try stripping file part */
+      p = infname + strlen(infname);
+      while (p >= infname && *p != '/')
+        p--;
+      if (*p == '/') {
+        strcpy(VolName, p+1);
+        *p = 0;
+      }
+   }
+   Dmsg2(10, "Device=%s, Vol=%s.\n", infname, VolName);
+   dev = init_dev(NULL, infname);
+   if (!dev) {
+      Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
+   }
+   /* ***FIXME**** init capabilities */
+   if (!open_device(dev)) {
+      Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
+   }
+   Dmsg0(90, "Device opened for read.\n");
+
+   rec = new_record();
+   block = new_block(dev);
+
+   NumVolumes = 0;
+   CurVolume = 1;
+   for (p = VolName; p && *p; ) {
+      p = strchr(p, '^');
+      if (p) {
+        *p++ = 0;
+      }
+      NumVolumes++;
+   }
+
+   jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, strlen(VolName)+1);
+   strcpy(jcr->VolumeName, VolName);
+   if (!acquire_device_for_read(jcr, dev, block)) {
+      Emsg0(M_ERROR, 0, dev->errmsg);
+      exit(1);
+   }
+
+   /* Assume that we have already read the volume label.
+    * If on second or subsequent volume, adjust buffer pointer 
+    */
+   if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
+      Dmsg1(0, "\n\
+Warning, this Volume is a continuation of Volume %s\n",
+               dev->VolHdr.PrevVolName);
+   }
+   for ( ;; ) {
+      DEV_RECORD *record;
+
+      if (!read_record(dev, block, rec)) {
+        uint32_t status;
+         Dmsg0(20, "!read_record()\n");
+        if (dev->state & ST_EOT) {
+           if (rec->remainder) {
+               Dmsg0(20, "Not end of record.\n");
+           }
+            Dmsg2(20, "NumVolumes=%d CurVolume=%d\n", NumVolumes, CurVolume);
+           if (NumVolumes > 1 && CurVolume < NumVolumes) {
+              p = VolName;
+              while (*p++)  
+                 { }
+              CurVolume++;
+               Dmsg1(20, "There is another volume %s.\n", p);
+              VolName = p;
+              close_dev(dev);
+              jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, 
+                    strlen(VolName)+1);
+              strcpy(jcr->VolumeName, VolName);
+               printf("Mount Volume %s on device %s and press return when ready.",
+                 VolName, infname);
+              getchar();   
+              if (!ready_dev_for_read(jcr, dev, block)) {
+                  Emsg2(M_ABORT, 0, "Cannot open Dev=%s, Vol=%s\n", infname, VolName);
+              }
+              record = new_record();
+              read_record(dev, block, record); /* read vol label */
+              dump_label_record(dev, record, verbose);
+              free_record(record);
+              continue;
+           }
+            printf("End of Device reached.\n");
+           break;
+        }
+        if (dev->state & ST_EOF) {
+            Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
+            Dmsg0(20, "read_record got eof. try again\n");
+           continue;
+        }
+        if (dev->state & ST_SHORT) {
+           Emsg0(M_INFO, 0, dev->errmsg);
+           continue;
+        }
+        Emsg0(M_ERROR, 0, dev->errmsg);
+        status_dev(dev, &status);
+         Dmsg1(20, "Device status: %x\n", status);
+        if (status & MT_EOD)
+            Emsg0(M_ABORT, 0, "Unexpected End of Data\n");
+        else if (status & MT_EOT)
+            Emsg0(M_ABORT, 0, "Unexpected End of Tape\n");
+        else if (status & MT_EOF)
+            Emsg0(M_ABORT, 0, "Unexpected End of File\n");
+        else if (status & MT_DR_OPEN)
+            Emsg0(M_ABORT, 0, "Tape Door is Open\n");
+        else if (!(status & MT_ONLINE))
+            Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n");
+        else
+            Emsg2(M_ABORT, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno));
+        break;
+      }
+
+      if (debug_level >= 30) {
+         Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId,
+              FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream), 
+              rec->data_len);
+      }
+
+
+      /*  
+       * Check for End of File record (all zeros)
+       *    NOTE: this no longer exists
+       */
+      if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
+         Emsg0(M_ABORT, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n");
+      }
+
+      /* 
+       * Check for Start or End of Session Record 
+       *
+       */
+      if (rec->FileIndex < 0) {
+        dump_label_record(dev, rec, verbose);
+        continue;
+      }
+   }
+   term_dev(dev);
+   free_record(rec);
+   free_block(block);
+   free_jcr(jcr);
+   return;
+}
+
+/* Do an ls type listing of an archive */
+static void do_ls(char *infname)
+{
+   char fname[1000];
+   char Vol[2000];
+   char *VolName;
+   char *p;
+   struct stat statp;
+   int type;
+   long record_file_index;
+   DEV_RECORD *rec;
+   DEV_BLOCK *block;
+   int NumVolumes, CurVolume;
+   JCR *jcr;
+
+   jcr = new_jcr(sizeof(JCR), my_free_jcr);
+   VolName = Vol;
+   VolName[0] = 0;
+   if (strncmp(infname, "/dev/", 5) != 0) {
+      /* Try stripping file part */
+      p = infname + strlen(infname);
+      while (p >= infname && *p != '/')
+        p--;
+      if (*p == '/') {
+        strcpy(VolName, p+1);
+        *p = 0;
+      }
+   }
+   Dmsg2(10, "Device=%s, Vol=%s.\n", infname, VolName);
+   dev = init_dev(NULL, infname);
+   if (!dev) {
+      Emsg1(M_ABORT, 0, "Cannot open %s\n", infname);
+   }
+   /* ***FIXME**** init capabilities */
+   if (!open_device(dev)) {
+      Emsg1(M_ERROR, 0, "Cannot open %s\n", infname);
+      exit(1);
+   }
+   Dmsg0(90, "Device opened for read.\n");
+
+   rec = new_record();
+   block = new_block(dev);
+
+   NumVolumes = 0;
+   CurVolume = 1;
+   for (p = VolName; p && *p; ) {
+      p = strchr(p, '^');
+      if (p) {
+        *p++ = 0;
+      }
+      NumVolumes++;
+   }
+
+   jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, strlen(VolName)+1);
+   strcpy(jcr->VolumeName, VolName);
+   if (!acquire_device_for_read(jcr, dev, block)) {
+      Emsg0(M_ERROR, 0, dev->errmsg);
+      exit(1);
+   }
+
+   if (dump_label) {
+      dump_volume_label(dev);
+      term_dev(dev);
+      free_record(rec);
+      free_block(block);
+      return;
+   }
+
+   /* Assume that we have already read the volume label.
+    * If on second or subsequent volume, adjust buffer pointer 
+    */
+   if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
+      Dmsg1(0, "\n\
+Warning, this Volume is a continuation of Volume %s\n",
+               dev->VolHdr.PrevVolName);
+   }
+   for ( ;; ) {
+      DEV_RECORD *record;
+
+      if (!read_record(dev, block, rec)) {
+        uint32_t status;
+         Dmsg0(20, "!read_record()\n");
+        if (dev->state & ST_EOT) {
+           if (rec->remainder) {
+               Dmsg0(20, "Not end of record.\n");
+           }
+            Dmsg2(20, "NumVolumes=%d CurVolume=%d\n", NumVolumes, CurVolume);
+           if (NumVolumes > 1 && CurVolume < NumVolumes) {
+              p = VolName;
+              while (*p++)  
+                 { }
+              CurVolume++;
+               Dmsg1(20, "There is another volume %s.\n", p);
+              VolName = p;
+              close_dev(dev);
+              jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, 
+                   strlen(VolName)+1);
+              strcpy(jcr->VolumeName, VolName);
+               printf("Mount Volume %s on device %s and press return when ready.",
+                 VolName, infname);
+              getchar();   
+              if (!ready_dev_for_read(jcr, dev, block)) {
+                  Emsg2(M_ABORT, 0, "Cannot open Dev=%s, Vol=%s\n", infname, VolName);
+              }
+              record = new_record();
+              read_record(dev, block, record); /* read vol label */
+              dump_label_record(dev, record, 0);
+              free_record(record);
+              continue;
+           }
+            printf("End of Device reached.\n");
+           break;
+        }
+        if (dev->state & ST_EOF) {
+            Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
+            Dmsg0(20, "read_record got eof. try again\n");
+           continue;
+        }
+        if (dev->state & ST_SHORT) {
+           Emsg0(M_INFO, 0, dev->errmsg);
+           continue;
+        }
+        Emsg0(M_ERROR, 0, dev->errmsg);
+        status_dev(dev, &status);
+         Dmsg1(20, "Device status: %x\n", status);
+        if (status & MT_EOD)
+            Emsg0(M_ABORT, 0, "Unexpected End of Data\n");
+        else if (status & MT_EOT)
+            Emsg0(M_ABORT, 0, "Unexpected End of Tape\n");
+        else if (status & MT_EOF)
+            Emsg0(M_ABORT, 0, "Unexpected End of File\n");
+        else if (status & MT_DR_OPEN)
+            Emsg0(M_ABORT, 0, "Tape Door is Open\n");
+        else if (!(status & MT_ONLINE))
+            Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n");
+        else
+            Emsg2(M_ABORT, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno));
+        break;
+      }
+
+      if (debug_level >= 30) {
+         Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId,
+              FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream), 
+              rec->data_len);
+      }
+
+
+      /*  
+       * Check for End of File record (all zeros)
+       *    NOTE: this no longer exists
+       */
+      if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
+         Emsg0(M_ABORT, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n");
+      }
+
+      /* 
+       * Check for Start or End of Session Record 
+       *
+       */
+      if (rec->FileIndex < 0) {
+        dump_label_record(dev, rec, 0);
+        continue;
+      }
+
+      /* File Attributes stream */
+      if (rec->Stream == STREAM_UNIX_ATTRIBUTES) {
+        char *ap;
+         sscanf(rec->data, "%ld %d %s", &record_file_index, &type, fname);
+        if (record_file_index != rec->FileIndex) {
+            Emsg2(M_ABORT, 0, "Record header file index %ld not equal record index %ld\n",
+              rec->FileIndex, record_file_index);
+        }
+        ap = rec->data;
+        /* Skip to attributes */
+        while (*ap++ != 0)
+           ;
+        decode_stat(ap, &statp);
+        /* Skip to link name */  
+        while (*ap++ != 0)
+           ;
+        print_ls_output(fname, ap, type, &statp);
+      }
+   }
+   term_dev(dev);
+   free_record(rec);
+   free_block(block);
+   free_jcr(jcr);
+   return;
+}
+
+extern char *getuser(uid_t uid);
+extern char *getgroup(gid_t gid);
+
+static void print_ls_output(char *fname, char *link, int type, struct stat *statp)
+{
+   char buf[1000]; 
+   char *p, *f;
+   int n;
+
+   if (!file_is_included(&ff, fname) || file_is_excluded(&ff, fname)) {
+      return;
+   }
+   p = encode_mode(statp->st_mode, buf);
+   n = sprintf(p, "  %2d ", (uint32_t)statp->st_nlink);
+   p += n;
+   n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid));
+   p += n;
+   n = sprintf(p, "%8" lld " ", (uint64_t)statp->st_size);
+   p += n;
+   p = encode_time(statp->st_ctime, p);
+   *p++ = ' ';
+   *p++ = ' ';
+   /* Copy file name */
+   for (f=fname; *f; )
+      *p++ = *f++;
+   if (type == FT_DIR) {
+      *p++ = '/';
+   }
+   if (type == FT_LNK) {
+      *p++ = ' ';
+      *p++ = '-';
+      *p++ = '>';
+      *p++ = ' ';
+      /* Copy link name */
+      for (f=link; *f; )
+        *p++ = *f++;
+   }
+   *p++ = '\n';
+   *p = 0;
+   fputs(buf, stdout);
+}
diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c
new file mode 100644 (file)
index 0000000..7804241
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ *
+ *  Program to scan a Bacula tape and compare it with
+ *    the catalog and optionally synchronize the catalog
+ *    with the tape.
+ *
+ *   Kern E. Sibbald, December 2001
+ *
+ */
+/*
+   Copyright (C) 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+#include "findlib/find.h"
+#include "cats/cats.h"
+
+static void do_scan(char *fname);
+static void print_ls_output(char *fname, struct stat *statp);
+
+
+static DEVICE *dev = NULL;
+static B_DB *db;
+static JCR *jcr;
+
+static void usage()
+{
+   fprintf(stderr,
+"Usage: bscan [-d debug_level] <bacula-archive>\n"
+"       -dnn            set debug level to nn\n"
+"       -?              print this message\n\n");
+   exit(1);
+}
+
+static void my_free_jcr(JCR *jcr)
+{
+   return;
+}
+
+int main (int argc, char *argv[])
+{
+   int ch, i;
+
+   my_name_is(argc, argv, "bscan");
+
+
+   while ((ch = getopt(argc, argv, "d:?")) != -1) {
+      switch (ch) {
+         case 'd':                    /* debug level */
+           debug_level = atoi(optarg);
+           if (debug_level <= 0)
+              debug_level = 1; 
+           break;
+
+         case '?':
+        default:
+           usage();
+
+      }  
+   }
+   argc -= optind;
+   argv += optind;
+
+   if (argc != 1) {
+      Dmsg0(0, "Wrong number of arguments: \n");
+      usage();
+   }
+
+   /*
+    * Ensure that every message is always printed
+    */
+   for (i=1; i<=M_MAX; i++) {
+      add_msg_dest(MD_STDOUT, i, NULL, NULL);
+   }
+
+   jcr = new_jcr(sizeof(JCR), my_free_jcr);
+   jcr->VolSessionId = 1;
+   jcr->VolSessionTime = (uint32_t)time(NULL);
+   jcr->NumVolumes = 1;
+
+   /* *** FIXME **** need to put in corect db, user, and password */
+   if ((db=db_init_database("bacula", "bacula", "")) == NULL) {
+      Emsg0(M_ABORT, 0, "Could not init Bacula database\n");
+   }
+   if (!db_open_database(db)) {
+      Emsg0(M_ABORT, 0, db_strerror(db));
+   }
+   Dmsg0(200, "Database opened\n");
+
+
+   do_scan(argv[0]);
+
+   free_jcr(jcr);
+   return 0;
+}
+  
+
+static void do_scan(char *devname)            
+{
+   int n;     
+   char VolName[100];
+   char *p;
+   struct stat statp;
+   int type;
+   long record_file_index;
+   DEV_RECORD rec;
+   DEV_BLOCK *block;
+   char *fname;                      /* original file name */
+   char *ofile;                      /* output name with prefix */
+   char *lname;                      /* link name */
+   MEDIA_DBR mr;
+   POOL_DBR pr;
+   JOB_DBR jr;
+
+   if (strncmp(devname, "/dev/", 5) != 0) {
+      /* Try stripping file part */
+      p = devname + strlen(devname);
+      while (p >= devname && *p != '/') {
+        p--;
+      }
+      if (*p == '/') {
+        strcpy(VolName, p+1);
+        *p = 0;
+      }
+   }
+
+   dev = init_dev(NULL, devname);
+   if (!dev || !open_device(dev)) {
+      Emsg1(M_ABORT, 0, "Cannot open %s\n", devname);
+   }
+   Dmsg0(90, "Device opened for read.\n");
+
+   fname = (char *)get_pool_memory(PM_FNAME);
+   ofile = (char *)get_pool_memory(PM_FNAME);
+   lname = (char *)get_pool_memory(PM_FNAME);
+
+   block = new_block(dev);
+
+   strcpy(jcr->VolumeName, VolName);
+
+   if (!acquire_device_for_read(jcr, dev, block)) {
+      Emsg1(M_ABORT, 0, "Cannot open %s\n", devname);
+   }
+
+   memset(&rec, 0, sizeof(rec));
+   rec.data = (char *)get_memory(70000);
+
+   memset(&mr, 0, sizeof(mr));
+   memset(&pr, 0, sizeof(pr));
+
+   for ( ;; ) {
+      if (!read_record(dev, block, &rec)) {
+        uint32_t status;
+        if (dev->state & ST_EOT) {
+           break;
+        }
+        if (dev->state & ST_EOF) {
+           continue;                 /* try again */
+        }
+         Dmsg0(0, "Read Record got a bad record\n");
+        status_dev(dev, &status);
+         Dmsg1(20, "Device status: %x\n", status);
+        if (status & MT_EOD)
+            Emsg0(M_ABORT, 0, "Unexpected End of Data\n");
+        else if (status & MT_EOT)
+            Emsg0(M_ABORT, 0, "Unexpected End of Tape\n");
+        else if (status & MT_EOF)
+            Emsg0(M_ABORT, 0, "Unexpected End of File\n");
+        else if (status & MT_DR_OPEN)
+            Emsg0(M_ABORT, 0, "Tape Door is Open\n");
+        else if (!(status & MT_ONLINE))
+            Emsg0(M_ABORT, 0, "Unexpected Tape is Off-line\n");
+        else
+            Emsg3(M_ABORT, 0, "Read error %d on Record Header %s: %s\n", n, dev_name(dev), strerror(errno));
+      }
+
+
+      /* This is no longer used */
+      if (rec.VolSessionId == 0 && rec.VolSessionTime == 0) {
+         Emsg0(M_ERROR, 0, "Zero header record. This shouldn't happen.\n");
+        break;                       /* END OF FILE */
+      }
+
+      /* 
+       * Check for Start or End of Session Record 
+       *
+       */
+      if (rec.FileIndex < 0) {
+        SESSION_LABEL label, elabel;
+
+        if (debug_level > 1) {
+           dump_label_record(dev, &rec, 1);
+        }
+        switch (rec.FileIndex) {
+           case PRE_LABEL:
+               Dmsg0(000, "Volume is prelabeled. This tape cannot be scanned.\n");
+              return;
+              break;
+           case VOL_LABEL:
+              unser_volume_label(dev, &rec);
+              strcpy(mr.VolumeName, dev->VolHdr.VolName);
+              if (!db_get_media_record(db, &mr)) {
+                  Dmsg1(000, "VOL_LABEL: Media record not found for Volume: %s\n",
+                    mr.VolumeName);
+                 continue;
+              }
+              if (strcmp(mr.MediaType, dev->VolHdr.MediaType) != 0) {
+                  Dmsg2(000, "VOL_LABEL: MediaType mismatch. DB=%s Vol=%s\n",
+                    mr.MediaType, dev->VolHdr.MediaType);
+                 continue;
+              }
+              strcpy(pr.Name, dev->VolHdr.PoolName);
+              if (!db_get_pool_record(db, &pr)) {
+                  Dmsg1(000, "VOL_LABEL: Pool record not found for Pool: %s\n",
+                    pr.Name);
+                 continue;
+              }
+              if (strcmp(pr.PoolType, dev->VolHdr.PoolType) != 0) {
+                  Dmsg2(000, "VOL_LABEL: PoolType mismatch. DB=%s Vol=%s\n",
+                    pr.PoolType, dev->VolHdr.PoolType);
+                 continue;
+              }
+               Dmsg1(000, "VOL_LABEL: OK for Volume: %s\n", mr.VolumeName);
+              break;
+           case SOS_LABEL:
+              unser_session_label(&label, &rec);
+              memset(&jr, 0, sizeof(jr));
+              jr.JobId = label.JobId;
+              if (!db_get_job_record(db, &jr)) {
+                  Dmsg1(000, "SOS_LABEL: Job record not found for JobId: %d\n",
+                    jr.JobId);
+                 continue;
+              }
+              if (rec.VolSessionId != jr.VolSessionId) {
+                  Dmsg2(000, "SOS_LABEL: VolSessId mismatch. DB=%d Vol=%d\n",
+                    jr.VolSessionId, rec.VolSessionId);
+                 continue;
+              }
+              if (rec.VolSessionTime != jr.VolSessionTime) {
+                  Dmsg2(000, "SOS_LABEL: VolSessTime mismatch. DB=%d Vol=%d\n",
+                    jr.VolSessionTime, rec.VolSessionTime);
+                 continue;
+              }
+              if (jr.PoolId != pr.PoolId) {
+                  Dmsg2(000, "SOS_LABEL: PoolId mismatch. DB=%d Vol=%d\n",
+                    jr.PoolId, pr.PoolId);
+                 continue;
+              }
+              break;
+           case EOS_LABEL:
+              unser_session_label(&elabel, &rec);
+              if (elabel.JobId != label.JobId) {
+                  Dmsg2(000, "EOS_LABEL: Start/End JobId mismatch. Start=%d End=%d\n",
+                    label.JobId, elabel.JobId);
+                 continue;
+              }
+              if (elabel.JobFiles != jr.JobFiles) {
+                  Dmsg2(000, "EOS_LABEL: JobFiles mismatch. DB=%d EOS=%d\n",
+                    jr.JobFiles, elabel.JobFiles);
+                 continue;
+              }                                 
+              if (elabel.JobBytes != jr.JobBytes) {
+                  Dmsg2(000, "EOS_LABEL: JobBytes mismatch. DB=%d EOS=%d\n",
+                    jr.JobBytes, elabel.JobBytes);
+                 continue;
+              }                                 
+               Dmsg1(000, "EOS_LABEL: OK for JobId=%d\n", elabel.JobId);
+              break;
+           case EOM_LABEL:
+              break;
+           default:
+              break;
+        }
+        continue;
+      }
+
+      /* File Attributes stream */
+      if (rec.Stream == STREAM_UNIX_ATTRIBUTES) {
+        char *ap, *lp;
+
+        if (sizeof_pool_memory(fname) < rec.data_len) {
+           fname = (char *)realloc_pool_memory(fname, rec.data_len + 1);
+        }
+        if (sizeof_pool_memory(lname) < rec.data_len) {
+           ofile = (char *)realloc_pool_memory(ofile, rec.data_len + 1);
+        }
+        *fname = 0;
+        *lname = 0;
+
+        /*              
+         * An Attributes record consists of:
+         *    File_index
+         *    Type   (FT_types)
+         *    Filename
+         *    Attributes
+         *    Link name (if file linked i.e. FT_LNK)
+         *
+         */
+         sscanf(rec.data, "%ld %d %s", &record_file_index, &type, fname);
+        if (record_file_index != rec.FileIndex)
+            Emsg2(M_ABORT, 0, "Record header file index %ld not equal record index %ld\n",
+              rec.FileIndex, record_file_index);
+        ap = rec.data;
+        /* Skip to attributes */
+        while (*ap++ != 0)
+           ;
+        /* Skip to Link name */
+        if (type == FT_LNK) {
+           lp = ap;
+           while (*lp++ != 0) {
+              ;
+           }
+            strcat(lname, lp);        /* "save" link name */
+        } else {
+           *lname = 0;
+        }
+
+
+        decode_stat(ap, &statp);
+/*       Dmsg1(000, "Restoring: %s\n", ofile); */
+
+        if (debug_level > 1) {
+           print_ls_output(fname, &statp);   
+        }
+
+      /* Data stream and extracting */
+      } else if (rec.Stream == STREAM_FILE_DATA) {
+
+      } else if (rec.Stream != STREAM_MD5_SIGNATURE) {
+         Dmsg2(0, "None of above!!! stream=%d data=%s\n", rec.Stream, rec.data);
+      }
+   }
+
+   release_device(jcr, dev, block);
+
+   free_pool_memory(fname);
+   free_pool_memory(ofile);
+   free_pool_memory(lname);
+   term_dev(dev);
+   free_block(block);
+   return;
+}
+
+extern char *getuser(uid_t uid);
+extern char *getgroup(gid_t gid);
+
+static void print_ls_output(char *fname, struct stat *statp)
+{
+   char buf[1000]; 
+   char *p, *f;
+   int n;
+
+   p = encode_mode(statp->st_mode, buf);
+   n = sprintf(p, "  %2d ", (uint32_t)statp->st_nlink);
+   p += n;
+   n = sprintf(p, "%-8.8s %-8.8s", getuser(statp->st_uid), getgroup(statp->st_gid));
+   p += n;
+   n = sprintf(p, "%8lld  ", (uint64_t)statp->st_size);
+   p += n;
+   p = encode_time(statp->st_ctime, p);
+   *p++ = ' ';
+   *p++ = ' ';
+   for (f=fname; *f; )
+      *p++ = *f++;
+   *p++ = '\n';
+   *p = 0;
+   fputs(buf, stdout);
+}
diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c
new file mode 100644 (file)
index 0000000..8aa3b4b
--- /dev/null
@@ -0,0 +1,1079 @@
+/*
+ *
+ *   Bacula Tape manipulation program
+ *
+ *    Has various tape manipulation commands -- mostly for
+ *    use in determining how tapes really work.
+ *
+ *     Kern Sibbald, April MM
+ *
+ *   Note, this program reads stored.conf, and will only
+ *     talk to devices that are configured.
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+
+/* External subroutines */
+extern void free_config_resources();
+
+/* Exported variables */
+int quit = 0;
+char buf[100000];
+int bsize = TAPE_BSIZE;
+char VolName[100];
+
+DEVICE *dev = NULL;
+DEVRES *device = NULL;
+
+           
+/* Forward referenced subroutines */
+static void do_tape_cmds();
+static void helpcmd();
+static void scancmd();
+static void rewindcmd();
+static void clearcmd();
+static void wrcmd();
+static void eodcmd();
+static int find_device_res();
+
+
+#define CONFIG_FILE "stored.conf"
+
+static char *configfile;
+static char cmd[1000];
+static int signals = TRUE;
+static int default_tape = FALSE;
+
+static JCR *jcr;
+
+
+static void usage();
+static void terminate_btape(int sig);
+int get_cmd(char *prompt);
+
+static void my_free_jcr(JCR *jcr)
+{
+   return;
+}
+
+int write_dev(DEVICE *dev, char *buf, size_t len) 
+{
+   Emsg0(M_ABORT, 0, "write_dev not implemented.\n");
+   return 0;
+}
+
+int read_dev(DEVICE *dev, char *buf, size_t len)
+{
+   Emsg0(M_ABORT, 0, "read_dev not implemented.\n");
+   return 0;
+}
+
+
+/*********************************************************************
+ *
+ *        Main Bacula Pool Creation Program
+ *
+ */
+int main(int argc, char *argv[])
+{
+   int ch, i;
+
+   /* Sanity checks */
+   if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) {
+      Emsg2(M_ABORT, 0, "Tape block size (%d) not multiple of system size (%d)\n",
+        TAPE_BSIZE, DEV_BSIZE);
+   }
+   if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) {
+      Emsg1(M_ABORT, 0, "Tape block size (%d) is not a power of 2\n", TAPE_BSIZE);
+   }
+
+   printf("Tape block size is %d bytes.\n", TAPE_BSIZE);
+
+   while ((ch = getopt(argc, argv, "c:d:st?")) != -1) {
+      switch (ch) {
+         case 'c':                    /* specify config file */
+           if (configfile != NULL) {
+              free(configfile);
+           }
+           configfile = bstrdup(optarg);
+           break;
+
+         case 'd':                    /* set debug level */
+           debug_level = atoi(optarg);
+           if (debug_level <= 0) {
+              debug_level = 1; 
+           }
+           break;
+
+         case 't':
+           default_tape = TRUE;
+           break;
+
+         case 's':
+           signals = FALSE;
+           break;
+
+         case '?':
+        default:
+           helpcmd();
+           exit(0);
+
+      }  
+   }
+   argc -= optind;
+   argv += optind;
+
+
+   my_name_is(argc, argv, "btape");
+   
+   if (signals) {
+      init_signals(terminate_btape);
+   }
+
+   if (configfile == NULL) {
+      configfile = bstrdup(CONFIG_FILE);
+   }
+
+   daemon_start_time = time(NULL);
+
+   parse_config(configfile);
+
+   /*
+    * Ensure that every message is always printed
+    */
+   for (i=1; i<=M_MAX; i++) {
+      add_msg_dest(MD_STDOUT, i, NULL, NULL);
+   }
+
+
+   /* See if we can open a device */
+   if (argc) {
+      if (!(dev = init_dev(NULL, *argv))) {
+        usage();
+        exit(1);
+      }
+   }
+
+   /* Try default device */
+   if (!dev && default_tape) {
+      dev = init_dev(NULL, DEFAULT_TAPE_DRIVE);
+   }
+
+   if (dev) {
+      if (!find_device_res()) {
+        exit(1);
+      }
+      if (!open_device(dev)) {
+         Dmsg1(0, "Warning could not open device. ERR=%s", strerror_dev(dev));
+        term_dev(dev);
+        dev = NULL;
+      }
+   }
+
+   jcr = new_jcr(sizeof(JCR), my_free_jcr);
+   jcr->VolSessionId = 1;
+   jcr->VolSessionTime = (uint32_t)time(NULL);
+   jcr->NumVolumes = 1;
+
+
+   Dmsg0(200, "Do tape commands\n");
+   do_tape_cmds();
+  
+   terminate_btape(0);
+   return 0;
+}
+
+static void terminate_btape(int stat)
+{
+
+   sm_check(__FILE__, __LINE__, False);
+   if (configfile) {
+      free(configfile);
+   }
+   free_config_resources();
+
+   if (dev) {
+      term_dev(dev);
+   }
+
+   if (debug_level > 10)
+      print_memory_pool_stats(); 
+
+   free_jcr(jcr);
+   jcr = NULL;
+
+   term_msg();
+   close_memory_pool();              /* free memory in pool */
+
+   sm_dump(False);
+   exit(stat);
+}
+
+void quitcmd()
+{
+   quit = 1;
+}
+
+/*
+ * Get a new device name 
+ *  Normally given on the command line
+ */
+static void devicecmd()
+{
+   if (dev) {
+      term_dev(dev);
+      dev = NULL;
+   }
+   if (!get_cmd("Enter Device Name: ")) {
+      return;
+   }
+   dev = init_dev(NULL, cmd);
+   if (dev) {
+      if (!find_device_res()) {
+        return;
+      }
+      if (!open_device(dev)) {
+         Dmsg1(0, "Device open failed. ERR=%s\n", strerror_dev(dev));
+      }
+   } else {
+      Dmsg0(0, "Device init failed.\n");                          
+   }
+}
+
+/*
+ * Write a label to the tape   
+ */
+static void labelcmd()
+{
+   DEVRES *device;
+   int found = 0;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+
+   LockRes();
+   for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
+      if (strcmp(device->device_name, dev->dev_name) == 0) {
+        jcr->device = device;        /* Arggg a bit of duplication here */
+        device->dev = dev;
+        dev->device = device;
+        found = 1;
+        break;
+      }
+   } 
+   UnlockRes();
+   if (!found) {
+      Dmsg2(0, "Could not find device %s in %s\n", dev->dev_name, configfile);
+      return;
+   }
+
+   if (!get_cmd("Enter Volume Name: ")) {
+      return;
+   }
+        
+   if (!(dev->state & ST_OPENED)) {
+      if (!open_device(dev)) {
+         Dmsg1(0, "Device open failed. ERR=%s\n", strerror_dev(dev));
+      }
+   }
+   write_volume_label_to_dev(jcr, device, cmd, "Default");
+}
+
+/*
+ * Read the tape label  
+ */
+static void readlabelcmd()
+{
+   int save_debug_level = debug_level;
+   int stat;
+   DEV_BLOCK *block;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   block = new_block(dev);
+   stat = read_dev_volume_label(jcr, dev, block);
+   switch (stat) {
+      case VOL_NO_LABEL:
+         Dmsg0(0, "Volume has no label.\n");
+        break;
+      case VOL_OK:
+         Dmsg0(0, "Volume label read correctly.\n");
+        break;
+      case VOL_IO_ERROR:
+         Dmsg1(0, "I/O error on device: ERR=%s", strerror_dev(dev));
+        break;
+      case VOL_NAME_ERROR:
+         Dmsg0(0, "Volume name error\n");
+        break;
+      case VOL_CREATE_ERROR:
+         Dmsg1(0, "Error creating label. ERR=%s", strerror_dev(dev));
+        break;
+      case VOL_VERSION_ERROR:
+         Dmsg0(0, "Volume version error.\n");
+        break;
+      case VOL_LABEL_ERROR:
+         Dmsg0(0, "Bad Volume label type.\n");
+        break;
+      default:
+         Dmsg0(0, "Unknown error.\n");
+        break;
+   }
+
+   debug_level = 20;
+   dump_volume_label(dev); 
+   debug_level = save_debug_level;
+   free_block(block);
+}
+
+
+/*
+ * Search for device resource that corresponds to 
+ * device name on command line (or default).
+ *      
+ * Returns: 0 on failure
+ *         1 on success
+ */
+static int find_device_res()
+{
+   int found = 0;
+
+   LockRes();
+   for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
+      if (strcmp(device->device_name, dev->dev_name) == 0) {
+        device->dev = dev;
+        dev->capabilities = device->cap_bits;
+        found = 1;
+        break;
+      }
+   } 
+   UnlockRes();
+   if (!found) {
+      Dmsg2(0, "Could not find device %s in %s\n", dev->dev_name, configfile);
+      return 0;
+   }
+   Dmsg1(0, "Using device: %s\n", dev->dev_name);
+   return 1;
+}
+
+/*
+ * Load the tape should have prevously been taken
+ * off line, otherwise this command is not necessary.
+ */
+static void loadcmd()
+{
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if (!load_dev(dev)) {
+      Dmsg1(0, "Bad status from load. ERR=%s\n", strerror_dev(dev));
+   } else
+      Dmsg1(0, "Loaded %s\n", dev_name(dev));
+}
+
+/*
+ * Rewind the tape.   
+ */
+static void rewindcmd()
+{
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if (!rewind_dev(dev)) {
+      Dmsg1(0, "Bad status from rewind. ERR=%s\n", strerror_dev(dev));
+      clrerror_dev(dev, -1);
+   } else
+      Dmsg1(0, "Rewound %s\n", dev_name(dev));
+}
+
+/*
+ * Clear any tape error   
+ */
+static void clearcmd()
+{
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   clrerror_dev(dev, -1);
+}
+
+/*
+ * Write and end of file on the tape   
+ */
+static void weofcmd()
+{
+   int stat;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if ((stat = weof_dev(dev, 1)) < 0) {
+      Dmsg2(0, "Bad status from weof %d. ERR=%s\n", stat, strerror_dev(dev));
+      return;
+   } else {
+      Dmsg1(0, "Wrote EOF to %s\n", dev_name(dev));
+   }
+}
+
+/*
+ * Test on uninitialized tape 
+ *  Destroys tape contents !!!! Including Bacula label.
+ */
+static void rawtestcmd()
+{
+#ifdef xxxx
+   int i, j, k;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if (!rewind_dev(dev)) {
+      Dmsg1(0, "Bad status from rewind. ERR=%s\n", strerror_dev(dev));
+      return;
+   }
+   Dmsg0(0, "Rewound, now writing 100 blocks\n");
+   for (i=0; i<100; i++) {
+      j = 10000 + i;
+      memset(buf, i, j);
+      if (!write_dev(dev, buf, j)) {
+         Dmsg1(0, "Bad status from write. ERR=%s\n", strerror_dev(dev));
+        return;
+      }
+     Dmsg2(10, "Wrote %d bytes of %d\n", j, i);
+   }
+   Dmsg0(0, "100 Blocks written, flushing buffers and writing EOF\n");
+   if (flush_dev(dev) != 0) {
+      Dmsg1(0, "Error writing flushing. ERR=%s\n", strerror(errno));
+      return;
+   }
+   if (weof_dev(dev, 1) != 0) {
+      Dmsg1(0, "Error writing eof. ERR=%s\n", strerror(errno));
+      return;
+   }
+   Dmsg0(0, "Rewinding ...\n");
+   if (!rewind_dev(dev)) {
+      Dmsg1(0, "Bad status from rewind. ERR=%s\n", strerror_dev(dev));
+      return;
+   }
+
+
+   Dmsg0(0, "Read and verify data ...\n");
+   for (i=0; i<100; i++) {
+      j = 10000 + i;
+      if (!read_dev(dev, buf, j)) {
+         Dmsg1(0, "Bad status from read. ERR=%s\n", strerror_dev(dev));
+        return;
+      }
+      for (k=0; k<j; k++) {
+        if (buf[k] != i) {
+            Dmsg5(0, "Data read expected %d got %d at byte %d, block %d size %d\n", 
+            i, buf[k], k, i, j);
+           return;
+        }
+      }     
+      Dmsg3(10, "Successful read block %d of %d bytes of %d\n", i, j, i);   
+   }
+   Dmsg0(0, "Read OK!\n");
+   Dmsg0(0, "Rewinding ...\n");
+   if (!rewind_dev(dev)) {
+      Dmsg1(0, "Bad status from rewind. ERR=%s\n", strerror_dev(dev));
+      return;
+   }
+#else
+   printf("Rawtest command no longer implemented.\n");
+#endif
+}
+
+/* Go to the end of the medium -- raw command  
+ * The idea was orginally that the end of the Bacula
+ * medium would be flagged differently. This is not
+ * currently the case. So, this is identical to the
+ * eodcmd().
+ */
+static void eomcmd()
+{
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if (!eod_dev(dev)) {
+      Dmsg1(0, "Bad status from eod. ERR=%s\n", strerror_dev(dev));
+      return;
+   } else {
+      Dmsg0(0, "Moved to end of media\n");
+   }
+}
+
+/*
+ * Go to the end of the media (either hardware determined
+ *  or defined by two eofs.
+ */
+static void eodcmd()
+{
+   eomcmd();
+}
+
+/*
+ * Backspace file   
+ */
+static void bsfcmd()
+{
+   int stat;
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if ((stat=bsf_dev(dev, 1)) < 0) {
+      Dmsg1(0, "Bad status from bsf. ERR=%s\n", strerror(errno));
+   } else {
+      Dmsg0(0, "Back spaced one file.\n");
+   }
+}
+
+/*
+ * Backspace record   
+ */
+static void bsrcmd()
+{
+   int stat;
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if ((stat=bsr_dev(dev, 1)) < 0) {
+      Dmsg1(0, "Bad status from bsr. ERR=%s\n", strerror(errno));
+   } else {
+      Dmsg0(0, "Back spaced one record.\n");
+   }
+}
+
+/*
+ * List device capabilities as defined in the 
+ *  stored.conf file.
+ */
+static void capcmd()
+{
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   Dmsg0(0, "Device capabilities: ");
+   printf("%sEOF ", dev->capabilities & CAP_EOF ? "" : "!");
+   printf("%sBSR ", dev->capabilities & CAP_BSR ? "" : "!");
+   printf("%sBSF ", dev->capabilities & CAP_BSF ? "" : "!");
+   printf("%sFSR ", dev->capabilities & CAP_FSR ? "" : "!");
+   printf("%sFSF ", dev->capabilities & CAP_FSF ? "" : "!");
+   printf("%sEOM ", dev->capabilities & CAP_EOM ? "" : "!");
+   printf("%sREM ", dev->capabilities & CAP_REM ? "" : "!");
+   printf("%sRACCESS ", dev->capabilities & CAP_RACCESS ? "" : "!");
+   printf("%sAUTOMOUNT ", dev->capabilities & CAP_AUTOMOUNT ? "" : "!");
+   printf("%sLABEL ", dev->capabilities & CAP_LABEL ? "" : "!");
+   printf("%sANONVOLS ", dev->capabilities & CAP_ANONVOLS ? "" : "!");
+   printf("%sALWAYSOPEN ", dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
+   printf("\n");
+}
+
+/*
+ * Test writting larger and larger records.  
+ * This is a torture test for records.
+ */
+static void rectestcmd()
+{
+   DEV_BLOCK *block;
+   DEV_RECORD *rec;
+   int i, blkno = 0;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+
+   Dmsg0(0, "Test writting larger and larger records.\n\
+This is a torture test for records. \n");
+
+   sm_check(__FILE__, __LINE__, False);
+   block = new_block(dev);
+   rec = new_record();
+
+   for (i=1; i<500000; i++) {
+      rec->data = (char *) check_pool_memory_size(rec->data, i);
+      memset(rec->data, i & 0xFF, i);
+      rec->data_len = i;
+      sm_check(__FILE__, __LINE__, False);
+      while (!write_record_to_block(block, rec)) {
+        empty_block(block);
+        blkno++;
+         Dmsg2(0, "Block %d i=%d\n", blkno, i);
+      }
+      sm_check(__FILE__, __LINE__, False);
+   }
+   free_record(rec);
+   free_block(block);
+   sm_check(__FILE__, __LINE__, False);
+}
+
+/* 
+ * This is a general test of Bacula's functions
+ *   needed to read and write the tape.
+ */
+static void testcmd()
+{
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   Dmsg0(0, "Append files test.\n\n\
+I'm going to write one record  in file 0,\n\
+                   two records in file 1,\n\
+             and three records in file 2\n\n");
+   rewindcmd();
+   wrcmd();
+   weofcmd();     /* end file 0 */
+   wrcmd();
+   wrcmd();
+   weofcmd();     /* end file 1 */
+   wrcmd();
+   wrcmd();
+   wrcmd();
+   weofcmd();    /* end file 2 */
+//   weofcmd();
+   rewindcmd();
+   Dmsg0(0, "Now moving to end of media.\n");
+   eodcmd();
+   Dmsg2(0, "\nWe should be in file 3. I am at file %d. This is %s\n\n", 
+      dev->file, dev->file == 3 ? "correct!" : "NOT correct!!!!");
+
+   Dmsg0(0, "\nNow I am going to attempt to append to the tape.\n");
+   wrcmd(); 
+   weofcmd();
+//   weofcmd();
+   rewindcmd();
+   scancmd();
+   Dmsg0(0, "The above scan should have four files of:\n\
+One record, two records, three records, and one record respectively.\n\n");
+
+
+   Dmsg0(0, "Append block test.\n\n\
+I'm going to write a block, an EOF, rewind, go to EOM,\n\
+then backspace over the EOF and attempt to append a\
+second block in the first file.\n\n");
+   rewindcmd();
+   wrcmd();
+   weofcmd();
+//   weofcmd();
+   rewindcmd();
+   eodcmd();
+   Dmsg2(0, "We should be at file 1. I am at EOM File=%d. This is %s\n",
+      dev->file, dev->file == 1 ? "correct!" : "NOT correct!!!!");
+   Dmsg0(0, "Doing backspace file.\n");
+   bsfcmd();
+   Dmsg0(0, "Write second block, hoping to append to first file.\n");
+   wrcmd();
+   weofcmd();
+   rewindcmd();
+   Dmsg0(0, "Done writing, scanning results\n");
+   scancmd();
+   Dmsg0(0, "The above should have one file of two blocks.\n");
+}
+
+
+static void fsfcmd()
+{
+   int stat;
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if ((stat=fsf_dev(dev, 1)) < 0) {
+      Dmsg2(0, "Bad status from fsf %d. ERR=%s\n", stat, strerror_dev(dev));
+      return;
+   }
+   Dmsg0(0, "Forward spaced one file.\n");
+}
+
+static void fsrcmd()
+{
+   int stat;
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if ((stat=fsr_dev(dev, 1)) < 0) {
+      Dmsg2(0, "Bad status from fsr %d. ERR=%s\n", stat, strerror_dev(dev));
+      return;
+   }
+   Dmsg0(0, "Forward spaced one record.\n");
+}
+
+static void rdcmd()
+{
+#ifdef xxxxx
+   int stat;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   if (!read_dev(dev, buf, 512*126)) {
+      Dmsg1(0, "Bad status from read. ERR=%s\n", strerror_dev(dev));
+      return;
+   }
+   Dmsg1(10, "Read %d bytes\n", stat);
+#else
+   printf("Rdcmd no longer implemented.\n");
+#endif
+}
+
+
+static void wrcmd()
+{
+   DEV_BLOCK *block;
+   DEV_RECORD *rec;
+   int i;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   sm_check(__FILE__, __LINE__, False);
+   block = new_block(dev);
+   rec = new_record();
+
+   i = 32001;
+   rec->data = (char *) check_pool_memory_size(rec->data, i);
+   memset(rec->data, i & 0xFF, i);
+   rec->data_len = i;
+   sm_check(__FILE__, __LINE__, False);
+   if (!write_record_to_block(block, rec)) {
+      Dmsg0(0, "Error writing record to block.\n"); 
+      return;
+   }
+   if (!write_block_to_dev(dev, block)) {
+      Dmsg0(0, "Error writing block to device.\n"); 
+      return;
+   } else {
+      Dmsg1(0, "Wrote one record of %d bytes.\n",
+        ((i+TAPE_BSIZE-1)/TAPE_BSIZE) * TAPE_BSIZE);
+   }
+
+   sm_check(__FILE__, __LINE__, False);
+   free_record(rec);
+   free_block(block);
+   sm_check(__FILE__, __LINE__, False);
+   Dmsg0(0, "Wrote block to device.\n");
+}
+
+
+/*
+ * Scan tape by reading block by block. Report what is
+ * on the tape.
+ */
+static void scancmd()
+{
+   int stat;
+   int blocks, tot_blocks, tot_files;
+   int block_size;
+   uint64_t bytes;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   blocks = block_size = tot_blocks = 0;
+   bytes = 0;
+   if (dev->state & ST_EOT) {
+      Dmsg0(0, "End of tape\n");
+      return; 
+   }
+   update_pos_dev(dev);
+   tot_files = dev->file;
+   for (;;) {
+      if ((stat = read(dev->fd, buf, sizeof(buf))) < 0) {
+        clrerror_dev(dev, -1);
+         Mmsg2(&dev->errmsg, "read error on %s. ERR=%s.\n",
+           dev->dev_name, strerror(dev->dev_errno));
+         Dmsg2(0, "Bad status from read %d. ERR=%s\n", stat, strerror_dev(dev));
+        if (blocks > 0)
+            printf("%d block%s of %d bytes in file %d\n",        
+                    blocks, blocks>1?"s":"", block_size, dev->file);
+        return;
+      }
+      Dmsg1(200, "read status = %d\n", stat);
+/*    sleep(1); */
+      if (stat != block_size) {
+        update_pos_dev(dev);
+        if (blocks > 0) {
+            printf("%d block%s of %d bytes in file %d\n", 
+                 blocks, blocks>1?"s":"", block_size, dev->file);
+           blocks = 0;
+        }
+        block_size = stat;
+      }
+      if (stat == 0) {               /* EOF */
+        update_pos_dev(dev);
+         printf("End of File mark.\n");
+        /* Two reads of zero means end of tape */
+        if (dev->state & ST_EOF)
+           dev->state |= ST_EOT;
+        else {
+           dev->state |= ST_EOF;
+           dev->file++;
+        }
+        if (dev->state & ST_EOT) {
+            printf("End of tape\n");
+           break;
+        }
+      } else {                       /* Got data */
+        dev->state &= ~ST_EOF;
+        blocks++;
+        tot_blocks++;
+        bytes += stat;
+      }
+   }
+   update_pos_dev(dev);
+   tot_files = dev->file - tot_files;
+   printf("Total files=%d, blocks=%d, bytes = %" lld "\n", tot_files, tot_blocks, bytes);
+}
+
+static void statcmd()
+{
+   int stat;
+   int debug;
+   uint32_t status;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+   debug = debug_level;
+   debug_level = 30;
+   if (!status_dev(dev, &status)) {
+      Dmsg2(0, "Bad status from status %d. ERR=%s\n", stat, strerror_dev(dev));
+   }
+#ifdef xxxx
+   dump_volume_label(dev);
+#endif
+   debug_level = debug;
+}
+
+
+/*
+ * Test on labeled tape. Preserves Bacula label.
+ */
+static void appendcmd()
+{
+
+#ifdef xxxx_this_code_turned_off
+
+   int i, j, k;
+   int file;
+   DEV_BLOCK *block;
+
+   if (!dev) {
+      Dmsg0(0, "No device: Use device command.\n");
+      return;
+   }
+
+   block = new_block(dev);
+
+   if (!ready_device_for_append(jcr, dev, block, VolName)) {
+      Dmsg0(0, "Cannot append, not a Bacula tape.\n");
+      return;
+   }
+
+   file = dev_file(dev);
+   Dmsg1(0, "Begin write test data in file %d\n", file);
+
+   /* Write our test data */
+   for (i=0; i<100; i++) {
+      j = 10000 + i;
+      memset(buf, i, j);
+      if (!write_dev(dev, buf, j)) {
+         Dmsg1(0, "Bad status from write. ERR=%s\n", strerror_dev(dev));
+        return;
+      }
+     Dmsg2(10, "Wrote %d bytes of %d\n", j, i);
+   }
+
+   if (flush_dev(dev) != 0) {                 /* ensure written to tape */
+      Dmsg1(0, "Flush error: %s\n", strerror(errno));
+   }
+   if (weof_dev(dev, 1) != 0) { 
+      Dmsg1(0, "EOF error: %s\n", strerror(errno));
+   }
+
+   Dmsg0(0, "Rewind and reread label\n");
+   if (read_dev_volume_label(dev, VolName) != VOL_OK) {
+      return;
+   }
+
+   if (file != 0) { 
+      Dmsg1(0, "FSF %d files\n", file);
+      fsf_dev(dev, file);
+   }
+      
+   file = dev_file(dev);
+   Dmsg1(0, "Begin read/test from file %d\n", file);
+   /* Now read our test data and make sure it is what we wrote */
+   for (i=0; i<100; i++) {
+      j = 10000 + i;
+      if (!read_dev(dev, buf, j)) {
+         Dmsg1(0, "Bad status from read. ERR=%s\n", strerror_dev(dev));
+        return;
+      }
+      for (k=0; k<j; k++) {
+        if (buf[k] != i) {
+            Dmsg5(0, "Data read expected %d got %d at byte %d, block %d size %d\n", 
+            i, buf[k], k, i, j);
+           return;
+        }
+      }     
+      Dmsg3(10, "Successful read block %d of %d bytes of %d\n", i, j, i);
+   }
+
+   Dmsg0(0, "Reread test data successfully.\n");
+#else 
+   printf("append command no longer implemented.\n");
+#endif
+}
+
+
+
+struct cmdstruct { char *key; void (*func)(); char *help; }; 
+static struct cmdstruct commands[] = {
+ {"append",     appendcmd,    "append and read test data on a Bacula labeled tape"},
+ {"bsf",        bsfcmd,       "backspace file"},
+ {"bsr",        bsrcmd,       "backspace record"},
+ {"cap",        capcmd,       "list device capabilities"},
+ {"clear",      clearcmd,     "clear tape errors"},
+ {"device",     devicecmd,    "specify the tape device name"},
+ {"eod",        eodcmd,       "go to end of Bacula data for append"},
+ {"test",       testcmd,      "General test Bacula tape functions"},
+ {"eom",        eomcmd,       "go to the physical end of medium"},
+ {"fsf",        fsfcmd,       "forward space a file"},
+ {"fsr",        fsrcmd,       "forward space a record"},
+ {"help",       helpcmd,      "print this command"},
+ {"label",      labelcmd,     "write a Bacula label to the tape"},
+ {"load",       loadcmd,      "load a tape"},
+ {"quit",       quitcmd,      "quit btape"},   
+ {"rawtest",    rawtestcmd,   "write and read test data on unlabeled tape"},     
+ {"rd",         rdcmd,        "read tape"},
+ {"readlabel",  readlabelcmd, "read and print the Bacula tape label"},
+ {"rectest",    rectestcmd,   "test record handling functions"},
+ {"rewind",     rewindcmd,    "rewind the tape"},
+ {"scan",       scancmd,      "read tape block by block to EOT and report"}, 
+ {"status",     statcmd,      "print tape status"},
+ {"weof",       weofcmd,      "write an EOF on the tape"},
+ {"wr",         wrcmd,        "write a single record of 2048 bytes"}, 
+            };
+#define comsize (sizeof(commands)/sizeof(struct cmdstruct))
+
+static void
+do_tape_cmds()
+{
+   unsigned int i;
+   int found;
+
+   while (get_cmd("*")) {
+      sm_check(__FILE__, __LINE__, False);
+      found = 0;
+      for (i=0; i<comsize; i++)       /* search for command */
+        if (fstrsch(cmd,  commands[i].key)) {
+           (*commands[i].func)();    /* go execute command */
+           found = 1;
+           break;
+        }
+      if (!found)
+         Dmsg1(0, "%s is an illegal command\n", cmd);
+      if (quit)
+        break;
+   }
+}
+
+static void helpcmd()
+{
+   unsigned int i;
+   usage();
+   printf("  Command    Description\n  =======    ===========\n");
+   for (i=0; i<comsize; i++)
+      printf("  %-10s %s\n", commands[i].key, commands[i].help);
+   printf("\n");
+}
+
+static void usage()
+{
+   fprintf(stderr,
+"\n"
+"Usage: btape [-c config_file] [-d debug_level] [device_name]\n"
+"       -c <file>   set configuration file to file\n"
+"       -dnn        set debug level to nn\n"
+"       -s          turn off signals\n"
+"       -t          open the default tape device\n"
+"       -?          print this message.\n"  
+"\n");
+
+}
+
+/*     
+ * Get next input command from terminal.  This
+ * routine is REALLY primitive, and should be enhanced
+ * to have correct backspacing, etc.
+ */
+int 
+get_cmd(char *prompt)
+{
+   int i = 0;
+   int ch;
+   fprintf(stdout, prompt);
+
+   /* We really should turn off echoing and pretty this
+    * up a bit.
+    */
+   cmd[i] = 0;
+   while ((ch = fgetc(stdin)) != EOF) { 
+      if (ch == '\n') {
+        strip_trailing_junk(cmd);
+        return 1;
+      } else if (ch == 4 || ch == 0xd3 || ch == 0x8) {
+        if (i > 0)
+           cmd[--i] = 0;
+        continue;
+      } 
+        
+      cmd[i++] = ch;
+      cmd[i] = 0;
+   }
+   quit = 1;
+   return 0;
+}
diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c
new file mode 100644 (file)
index 0000000..5333f91
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ *
+ *   dev.c  -- low level operations on device (storage device)
+ *
+ *             Kern Sibbald
+ *
+ *     NOTE!!!! None of these routines are reentrant. You must
+ *       use lock_device() and unlock_device() at a higher level,
+ *       or use the xxx_device() equivalents.  By moving the
+ *       thread synchronization to a higher level, we permit
+ *        the higher level routines to "seize" the device and 
+ *       to carry out operations without worrying about who
+ *       set what lock (i.e. race conditions).
+ *
+ *     Note, this is the device dependent code, and my have
+ *          to be modified for each system, but is meant to
+ *           be as "generic" as possible.
+ * 
+ *     The purpose of this code is to develop a SIMPLE Storage
+ *     daemon. More complicated coding (double buffering, writer
+ *     thread, ...) is left for a later version.
+ *
+ *     Unfortunately, I have had to add more and more complication
+ *     to this code. This was not foreseen as noted above, and as
+ *     a consequence has lead to something more contored than is
+ *     really necessary -- KES.  Note, this contortion has been
+ *     corrected to a large extent by a rewrite (Apr MMI).
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+/*
+ * Handling I/O errors and end of tape conditions is a bit tricky.
+ * This is how it is currently done when writting.
+ * On either an I/O error or end of tape,
+ * we will stop writing on the physical device (no I/O recovery is
+ * attempted at least in this daemon). The state flag will be sent
+ * to include ST_EOT, which is ephimeral, and ST_WEOT, which is
+ * persistent. Lots of routines clear ST_EOT, but ST_WEOT is
+ * cleared only when the problem goes away.  Now when ST_WEOT
+ * is set all calls to write_dev() are handled as usual. However,
+ * in write_block() instead of attempting to write the block to
+ * the physical device, it is chained into a list of blocks written
+ * after the EOT condition.  In addition, all threads are blocked
+ * from writing on the tape by calling lock(), and thread other
+ * than the first thread to hit the EOT will block on a condition
+ * variable. The first thread to hit the EOT will continue to
+ * be able to read and write the tape (he sort of tunnels through
+ * the locking mechanism -- see lock() for details).
+ *
+ * Now presumably somewhere higher in the chain of command 
+ * (device.c), someone will notice the EOT condition and 
+ * get a new tape up, get the tape label read, and mark 
+ * the label for rewriting. Then this higher level routine 
+ * will write the unwritten buffer to the new volume.
+ * Finally, he will release
+ * any blocked threads by doing a broadcast on the condition
+ * variable.  At that point, we should be totally back in 
+ * business with no lost data.
+ */
+
+
+#include "bacula.h"
+#include "stored.h"
+
+/* Forward referenced functions */
+int dev_is_tape(DEVICE *dev);
+void clrerror_dev(DEVICE *dev, int func);
+int fsr_dev(DEVICE *dev, int num);
+
+extern int debug_level;
+
+/* 
+ * Allocate and initialize the DEVICE structure
+ * Note, if dev is non-NULL, it is already allocated,
+ * thus we neither allocate it nor free it. This allows
+ * the caller to put the packet in shared memory.
+ *
+ *  Note, for a tape, the dev_name is the device name
+ *     (e.g. /dev/nst0), and for a file, the device name
+ *     is the directory in which the file will be placed.
+ *
+ */
+DEVICE *
+init_dev(DEVICE *dev, char *dev_name)
+{
+   struct stat statp;
+   int tape;
+   int errstat;
+
+   /* Check that device is available */
+   if (stat(dev_name, &statp) < 0) {
+      if (dev) {
+        dev->dev_errno = errno;
+      } 
+      Emsg2(M_FATAL, 0, "Unable to stat device %s : %s\n", dev_name, strerror(errno));
+      return NULL;
+   }
+   tape = FALSE;
+   if (S_ISDIR(statp.st_mode)) {
+      tape = FALSE;
+   } else if (S_ISCHR(statp.st_mode)) {
+      tape = TRUE;
+   } else {
+      if (dev) {
+        dev->dev_errno = ENODEV;
+      }
+      Emsg2(M_FATAL, 0, "%s is an unknown device type. Must be tape or directory. st_mode=%x\n", 
+        dev_name, statp.st_mode);
+      return NULL;
+   }
+   if (!dev) {
+      dev = (DEVICE *)get_memory(sizeof(DEVICE));
+      memset(dev, 0, sizeof(DEVICE));
+      dev->state = ST_MALLOC;
+   } else {
+      memset(dev, 0, sizeof(DEVICE));
+   }
+   if (tape) {
+      dev->state |= ST_TAPE;
+   }
+   dev->dev_name = (char *) get_memory(strlen(dev_name)+1);
+   strcpy(dev->dev_name, dev_name);
+
+   dev->errmsg = (char *) get_pool_memory(PM_EMSG);
+   *dev->errmsg = 0;
+
+   if ((errstat = pthread_mutex_init(&dev->mutex, NULL)) != 0) {
+      dev->dev_errno = errstat;
+      Mmsg1(&dev->errmsg, "Unable to init mutex: ERR=%s\n", strerror(errstat));
+      Emsg0(M_FATAL, 0, dev->errmsg);
+   }
+   if ((errstat = pthread_cond_init(&dev->wait, NULL)) != 0) {
+      dev->dev_errno = errstat;
+      Mmsg1(&dev->errmsg, "Unable to init cond variable: ERR=%s\n", strerror(errstat));
+      Emsg0(M_FATAL, 0, dev->errmsg);
+   }
+   if ((errstat = pthread_cond_init(&dev->wait_next_vol, NULL)) != 0) {
+      dev->dev_errno = errstat;
+      Mmsg1(&dev->errmsg, "Unable to init cond variable: ERR=%s\n", strerror(errstat));
+      Emsg0(M_FATAL, 0, dev->errmsg);
+   }
+   dev->fd = -1;
+   Dmsg2(29, "init_dev: tape=%d dev_name=%s\n", dev_is_tape(dev), dev->dev_name);
+   return dev;
+}
+
+/* Open the device with the operating system and
+ * initialize buffer pointers.
+ *
+ * Note, for a tape, the VolName is the name we give to the
+ *    volume (not really used here), but for a file, the
+ *    VolName represents the name of the file to be created/opened.
+ *    In the case of a file, the full name is the device name
+ *    (archive_name) with the VolName concatenated.
+ */
+int
+open_dev(DEVICE *dev, char *VolName, int mode)
+{
+   char *archive_name;
+
+   if (dev->state & ST_OPENED) {
+      /*
+       *  *****FIXME***** how to handle two threads wanting
+       *  different volumes mounted???? E.g. one is waiting
+       *  for the next volume to be mounted, and a new job
+       *  starts and snatches up the device.
+       */
+      if (VolName && strcmp(dev->VolCatInfo.VolCatName, VolName) != 0) {
+        return -1;
+      }
+      dev->use_count++;
+      Mmsg2(&dev->errmsg, "WARNING!!!! device %s opened %d times!!!\n", 
+           dev->dev_name, dev->use_count);
+      Emsg0(M_WARNING, 0, dev->errmsg);
+      return dev->fd;
+   }
+   if (VolName) {
+      strcpy(dev->VolCatInfo.VolCatName, VolName);
+   }
+
+   Dmsg3(29, "open_dev: tape=%d dev_name=%s vol=%s\n", dev_is_tape(dev), 
+        dev->dev_name, dev->VolCatInfo.VolCatName);
+   dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
+   if (dev->state & ST_TAPE) {
+      Dmsg0(29, "open_dev: device is tape\n");
+      if (mode == READ_WRITE) {
+        dev->mode = O_RDWR | O_BINARY;
+      } else {
+        dev->mode = O_RDONLY | O_BINARY;
+      }
+      if ((dev->fd = open(dev->dev_name, dev->mode, MODE_RW)) < 0) {
+        dev->dev_errno = errno;
+         Mmsg2(&dev->errmsg, "stored: unable to open device %s: ERR=%s\n", 
+              dev->dev_name, strerror(dev->dev_errno));
+        Emsg0(M_FATAL, 0, dev->errmsg);
+      } else {
+        dev->dev_errno = 0;
+        dev->state |= ST_OPENED;
+        dev->use_count++;
+        update_pos_dev(dev);             /* update position */
+      }
+      Dmsg1(29, "open_dev: tape %d opened\n", dev->fd);
+   } else {
+      archive_name = (char *) get_pool_memory(PM_FNAME);
+      strcpy(archive_name, dev->dev_name);
+      if (archive_name[strlen(archive_name)] != '/') {
+         strcat(archive_name, "/");
+      }
+      strcat(archive_name, VolName);
+      Dmsg1(29, "open_dev: device is disk %s\n", archive_name);
+      if (mode == READ_WRITE) {
+        dev->mode = O_CREAT | O_RDWR | O_BINARY;
+      } else {
+        dev->mode = O_RDONLY | O_BINARY;
+      }
+      if ((dev->fd = open(archive_name, dev->mode, MODE_RW)) < 0) {
+        dev->dev_errno = errno;
+         Mmsg2(&dev->errmsg, "Could not open: %s, ERR=%s\n", archive_name, strerror(dev->dev_errno));
+        Emsg0(M_FATAL, 0, dev->errmsg);
+      } else {
+        dev->dev_errno = 0;
+        dev->state |= ST_OPENED;
+        dev->use_count++;
+        update_pos_dev(dev);                /* update position */
+      }
+      Dmsg1(29, "open_dev: disk fd=%d opened\n", dev->fd);
+      free_pool_memory(archive_name);
+   }
+   return dev->fd;
+}
+
+/*
+ * Rewind the device.
+ *  Returns: 1 on success
+ *          0 on failure
+ */
+int rewind_dev(DEVICE *dev)
+{
+   struct mtop mt_com;
+   unsigned int i;
+
+   Dmsg0(29, "rewind_dev\n");
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg1(&dev->errmsg, "Bad call to rewind_dev. Device %s not open\n",
+           dev->dev_name);
+      Emsg0(M_ABORT, 0, dev->errmsg);
+      return 0;
+   }
+   dev->state &= ~(ST_APPEND|ST_READ|ST_EOT | ST_EOF | ST_WEOT);  /* remove EOF/EOT flags */
+   dev->block_num = dev->file = 0;
+   if (dev->state & ST_TAPE) {
+      mt_com.mt_op = MTREW;
+      mt_com.mt_count = 1;
+      /* If we get an I/O error on rewind, it is probably because
+       * the drive is actually busy. We loop for (about 5 minutes)
+       * retrying every 5 seconds.
+       */
+      for (i=dev->max_rewind_wait; ; i -= 5) {
+        if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+           if (i == dev->max_rewind_wait) {
+               Dmsg1(200, "Rewind error, %s. retrying ...\n", strerror(errno));
+           }
+           clrerror_dev(dev, MTREW);
+           if (dev->dev_errno == EIO && i > 0) {
+               Dmsg0(200, "Sleeping 5 seconds.\n");
+              sleep(5);
+              continue;
+           }
+            Mmsg2(&dev->errmsg, "Rewind error on %s. ERR=%s.\n",
+              dev->dev_name, strerror(dev->dev_errno));
+           return 0;
+        }
+        break;
+      }
+   } else {
+      if (lseek(dev->fd, 0, SEEK_SET) < 0) {
+        dev->dev_errno = errno;
+         Mmsg2(&dev->errmsg, "lseek error on %s. ERR=%s.\n",
+           dev->dev_name, strerror(dev->dev_errno));
+        return 0;
+      }
+   }
+   return 1;
+}
+
+/* 
+ * Position device to end of medium (end of data)
+ *  Returns: 1 on succes
+ *          0 on error
+ */
+int 
+eod_dev(DEVICE *dev)
+{
+   struct mtop mt_com;
+   struct mtget mt_stat;
+   int stat = 0;
+   int32_t pos;
+
+   Dmsg0(29, "eod_dev\n");
+   if (dev->state & ST_EOT) {
+      return 1;
+   }
+   dev->state &= ~(ST_EOF);  /* remove EOF flags */
+   dev->block_num = dev->file = 0;
+   if (!(dev->state & ST_TAPE)) {
+      pos = lseek(dev->fd, 0, SEEK_END);
+      if (pos > 0) {
+        update_pos_dev(dev);
+        dev->state |= ST_EOT;
+        return 1;
+      }
+      return 0;
+   }
+   if (dev->capabilities & CAP_EOM) {
+      mt_com.mt_op = MTEOM;
+      mt_com.mt_count = 1;
+      if ((stat=ioctl(dev->fd, MTIOCTOP, (char *)&mt_com)) < 0) {
+         Dmsg1(50, "ioctl error: %s\n", strerror(dev->dev_errno));
+        clrerror_dev(dev, mt_com.mt_op);
+        update_pos_dev(dev);
+         Mmsg2(&dev->errmsg, "ioctl MTEOM error on %s. ERR=%s.\n",
+           dev->dev_name, strerror(dev->dev_errno));
+        return 0;
+      }
+      if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
+        dev->dev_errno = errno;
+         Mmsg2(&dev->errmsg, "ioctl MTIOCGET error on %s. ERR=%s.\n",
+           dev->dev_name, strerror(dev->dev_errno));
+        return 0;
+      }
+      Dmsg2(200, "EOD file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
+      dev->file = mt_stat.mt_fileno;
+
+   /*
+    * Rewind then use FSF until EOT reached
+    */
+   } else {
+      if (!rewind_dev(dev)) {
+        return 0;
+      }
+      while (!(dev->state & ST_EOT)) {
+         Dmsg0(200, "Do fsf 1\n");
+        if (fsf_dev(dev, 1) < 0) {
+            Dmsg0(200, "fsf_dev return < 0\n");
+           return 0;
+        }
+      }
+   }
+   update_pos_dev(dev);                     /* update position */
+   Dmsg1(200, "EOD dev->file=%d\n", dev->file);
+   return 1;
+}
+
+/*
+ * Set the position of the device.
+ *  Returns: 1 on succes
+ *          0 on error
+ */
+int update_pos_dev(DEVICE *dev)
+{
+#ifdef xxxx
+   struct mtget mt_stat;
+#endif
+   int32_t pos;
+   int stat = 0;
+
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, "Bad device call. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return 0;
+   }
+
+   /* Find out where we are */
+   if (!(dev->state & ST_TAPE)) {
+      dev->file = 0;
+      pos = lseek(dev->fd, 0, SEEK_CUR);
+      if (pos < 0) {
+         Dmsg1(200, "Seek error: ERR=%s\n", strerror(dev->dev_errno));
+        pos = 0;
+        dev->dev_errno = errno;
+         Mmsg2(&dev->errmsg, "lseek error on %s. ERR=%s.\n",
+           dev->dev_name, strerror(dev->dev_errno));
+      } else {
+        stat = 1;
+      }
+      return stat;
+   }
+
+#ifdef REALLY_IMPLEMENTED
+   if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
+      Dmsg1(50, "MTIOCGET error: %s\n", strerror(dev->dev_errno));
+      dev->dev_errno = errno;
+      Mmsg2(&dev->errmsg, "ioctl MTIOCGET error on %s. ERR=%s.\n",
+        dev->dev_name, strerror(dev->dev_errno));
+   } else {
+      stat = 1;
+   }
+   return stat;
+#endif
+   return 1;
+}
+
+
+/* 
+ * Return the status of the device.  This was meant
+ * to be a generic routine. Unfortunately, it doesn't
+ * seem possible (at least I do not know how to do it
+ * currently), which means that for the moment, this
+ * routine has very little value.
+ *
+ *   Returns: 1 on success
+ *           0 on error
+ */
+int
+status_dev(DEVICE *dev, uint32_t *status)
+{
+   struct mtget mt_stat;
+   uint32_t stat = 0;
+
+   if (dev->state & (ST_EOT | ST_WEOT)) {
+      stat |= MT_EOD;
+      Dmsg0(-20, " EOD");
+   }
+   if (dev->state & ST_EOF) {
+      stat |= MT_EOF;
+      Dmsg0(-20, " EOF");
+   }
+   if (dev->state & ST_TAPE) {
+      stat |= MT_TAPE;
+      Dmsg0(-20," Driver status:");
+      Dmsg2(-20," file=%d block=%d\n", dev->file, dev->block_num);
+      if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
+        dev->dev_errno = errno;
+         Mmsg2(&dev->errmsg, "ioctl MTIOCGET error on %s. ERR=%s.\n",
+           dev->dev_name, strerror(dev->dev_errno));
+        return 0;
+      }
+      Dmsg0(-20, " Device status:");
+
+#if defined(HAVE_LINUX_OS)
+      if (GMT_EOF(mt_stat.mt_gstat)) {
+        stat |= MT_EOF;
+         Dmsg0(-20, " EOF");
+      }
+      if (GMT_BOT(mt_stat.mt_gstat)) {
+        stat |= MT_BOT;
+         Dmsg0(-20, " BOT");
+      }
+      if (GMT_EOT(mt_stat.mt_gstat)) {
+        stat |= MT_EOT;
+         Dmsg0(-20, " EOT");
+      }
+      if (GMT_SM(mt_stat.mt_gstat)) {
+        stat |= MT_SM;
+         Dmsg0(-20, " SM");
+      }
+      if (GMT_EOD(mt_stat.mt_gstat)) {
+        stat |= MT_EOD;
+         Dmsg0(-20, " EOD");
+      }
+      if (GMT_WR_PROT(mt_stat.mt_gstat)) {
+        stat |= MT_WR_PROT;
+         Dmsg0(-20, " WR_PROT");
+      }
+      if (GMT_ONLINE(mt_stat.mt_gstat)) {
+        stat |= MT_ONLINE;
+         Dmsg0(-20, " ONLINE");
+      }
+      if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
+        stat |= MT_DR_OPEN;
+         Dmsg0(-20, " DR_OPEN");       
+      }
+      if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
+        stat |= MT_IM_REP_EN;
+         Dmsg0(-20, " IM_REP_EN");
+      }
+#endif /* !SunOS && !OSF */
+      Dmsg2(-20, " file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
+   } else {
+      stat |= MT_ONLINE | MT_BOT;
+   }
+   *status = stat; 
+   return 1;
+}
+
+
+/*
+ * Load medium in device
+ *  Returns: 1 on success
+ *          0 on failure
+ */
+int load_dev(DEVICE *dev)
+{
+#ifdef MTLOAD
+   struct mtop mt_com;
+#endif
+
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, "Bad call to load_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return 0;
+   }
+   if (!(dev->state & ST_TAPE)) {
+      return 1;
+   }
+#ifndef MTLOAD
+   Dmsg0(200, "stored: MTLOAD command not available\n");
+   dev->dev_errno = ENOTTY;          /* function not available */
+   Mmsg2(&dev->errmsg, "ioctl MTLOAD error on %s. ERR=%s.\n",
+        dev->dev_name, strerror(dev->dev_errno));      return 0;
+   return 0;
+#else
+
+   dev->block_num = dev->file = 0;
+   mt_com.mt_op = MTLOAD;
+   mt_com.mt_count = 1;
+   if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+      dev->dev_errno = errno;
+      Mmsg2(&dev->errmsg, "ioctl MTLOAD error on %s. ERR=%s.\n",
+        dev->dev_name, strerror(dev->dev_errno));      return 0;
+   }
+   return 1;
+#endif
+}
+
+/*
+ * Rewind device and put it offline
+ *  Returns: 1 on success
+ *          0 on failure
+ */
+int offline_dev(DEVICE *dev)
+{
+   struct mtop mt_com;
+
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, "Bad call to load_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return 0;
+   }
+   if (!(dev->state & ST_TAPE)) {
+      return 1;
+   }
+
+   dev->block_num = dev->file = 0;
+   mt_com.mt_op = MTOFFL;
+   mt_com.mt_count = 1;
+   if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+      dev->dev_errno = errno;
+      Mmsg2(&dev->errmsg, "ioctl MTOFFL error on %s. ERR=%s.\n",
+        dev->dev_name, strerror(dev->dev_errno));
+      return 0;
+   }
+   return 1;
+}
+
+
+/* 
+ * Foward space a file 
+ */
+int
+fsf_dev(DEVICE *dev, int num)
+{ 
+   struct mtop mt_com;
+   int stat;
+   char rbuf[1024];
+
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return -1;
+   }
+
+   if (!(dev->state & ST_TAPE)) {
+      return 0;
+   }
+   if (dev->state & ST_EOT) {
+      dev->dev_errno = 0;
+      Mmsg1(&dev->errmsg, "Device %s at End of Tape.\n", dev->dev_name);
+      return -1;
+   }
+   if (dev->state & ST_EOF)
+      Dmsg0(200, "ST_EOF set on entry to FSF\n");
+   if (dev->state & ST_EOT)
+      Dmsg0(200, "ST_EOT set on entry to FSF\n");
+      
+   Dmsg0(29, "fsf_dev\n");
+   dev->block_num = 0;
+   if (dev->capabilities & CAP_FSF) {
+      Dmsg0(200, "FSF has cap_fsf\n");
+      mt_com.mt_op = MTFSF;
+      mt_com.mt_count = 1;
+      while (num-- && !(dev->state & ST_EOT)) {
+         Dmsg0(200, "Doing read for fsf\n");
+        if ((stat = read(dev->fd, rbuf, sizeof(rbuf))) < 0) {
+           if (errno == ENOMEM) {     /* tape record exceeds buf len */
+              stat = sizeof(rbuf);   /* This is OK */
+           } else {
+              dev->state |= ST_EOT;
+              clrerror_dev(dev, -1);
+               Dmsg1(200, "Set ST_EOT read error %d\n", dev->dev_errno);
+               Mmsg2(&dev->errmsg, "read error on %s. ERR=%s.\n",
+                 dev->dev_name, strerror(dev->dev_errno));
+               Dmsg1(200, "%s", dev->errmsg);
+              break;
+           }
+        }
+        if (stat == 0) {                /* EOF */
+           update_pos_dev(dev);
+            Dmsg1(200, "End of File mark from read. File=%d\n", dev->file+1);
+           /* Two reads of zero means end of tape */
+           if (dev->state & ST_EOF) {
+              dev->state |= ST_EOT;
+               Dmsg0(200, "Set ST_EOT\n");
+              break;
+           } else {
+              dev->state |= ST_EOF;
+              dev->file++;
+              continue;
+           }
+        } else {                        /* Got data */
+           dev->state &= ~(ST_EOF|ST_EOT);
+        }
+
+         Dmsg0(200, "Doing MT_FSF\n");
+        stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+        if (stat < 0) {                 /* error => EOT */
+           dev->state |= ST_EOT;
+            Dmsg0(200, "Set ST_EOT\n");
+           clrerror_dev(dev, MTFSF);
+            Mmsg2(&dev->errmsg, "ioctl MTFSF error on %s. ERR=%s.\n",
+              dev->dev_name, strerror(dev->dev_errno));
+            Dmsg0(200, "Got < 0 for MT_FSF\n");
+            Dmsg1(200, "%s", dev->errmsg);
+        } else {
+           dev->state |= ST_EOF;     /* just read EOF */
+           dev->file++;
+        }   
+      }
+   
+   /*
+    * No FSF, so use FSR to simulate it
+    */
+   } else {
+      Dmsg0(200, "Doing FSR for FSF\n");
+      while (num-- && !(dev->state & ST_EOT)) {
+        fsr_dev(dev, INT32_MAX);    /* returns -1 on EOF or EOT */
+      }
+      if (dev->state & ST_EOT) {
+        dev->dev_errno = 0;
+         Mmsg1(&dev->errmsg, "Device %s at End of Tape.\n", dev->dev_name);
+        stat = -1;
+      } else {
+        stat = 0;
+      }
+   }
+   update_pos_dev(dev);
+   Dmsg1(200, "Return %d from FSF\n", stat);
+   if (dev->state & ST_EOF)
+      Dmsg0(200, "ST_EOF set on exit FSF\n");
+   if (dev->state & ST_EOT)
+      Dmsg0(200, "ST_EOT set on exit FSF\n");
+   Dmsg1(200, "Return from FSF file=%d\n", dev->file);
+   return stat;
+}
+
+/* 
+ * Backward space a file  
+ */
+int
+bsf_dev(DEVICE *dev, int num)
+{ 
+   struct mtop mt_com;
+   int stat;
+
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return -1;
+   }
+
+   if (!(dev->state & ST_TAPE)) {
+      return 0;
+   }
+   Dmsg0(29, "bsf_dev\n");
+   dev->state &= ~(ST_EOT|ST_EOF);
+   dev->file -= num;
+   mt_com.mt_op = MTBSF;
+   mt_com.mt_count = num;
+   stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+   if (stat < 0) {
+      clrerror_dev(dev, MTBSF);
+      Mmsg2(&dev->errmsg, "ioctl MTBSF error on %s. ERR=%s.\n",
+        dev->dev_name, strerror(dev->dev_errno));
+   }
+   update_pos_dev(dev);
+   return stat;
+}
+
+
+/* 
+ * Foward space a record
+ */
+int
+fsr_dev(DEVICE *dev, int num)
+{ 
+   struct mtop mt_com;
+   int stat;
+
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return -1;
+   }
+
+   if (!(dev->state & ST_TAPE)) {
+      return 0;
+   }
+   Dmsg0(29, "fsr_dev\n");
+   dev->block_num += num;
+   mt_com.mt_op = MTFSR;
+   mt_com.mt_count = num;
+   stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+   if (stat == 0) {
+      dev->state &= ~ST_EOF;
+   } else {
+      if (dev->state & ST_EOF) {
+        dev->state |= ST_EOT;
+      } else {
+        dev->state |= ST_EOF;           /* assume EOF */
+        dev->file++;
+      }
+      clrerror_dev(dev, MTFSR);
+      Mmsg2(&dev->errmsg, "ioctl MTFSR error on %s. ERR=%s.\n",
+        dev->dev_name, strerror(dev->dev_errno));
+   }
+   update_pos_dev(dev);
+   return stat;
+}
+
+/* 
+ * Backward space a record
+ */
+int
+bsr_dev(DEVICE *dev, int num)
+{ 
+   struct mtop mt_com;
+   int stat;
+
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return -1;
+   }
+
+   if (!(dev->state & ST_TAPE)) {
+      return 0;
+   }
+   Dmsg0(29, "bsr_dev\n");
+   dev->block_num -= num;
+   dev->state &= ~(ST_EOF|ST_EOT|ST_EOF);
+   mt_com.mt_op = MTBSR;
+   mt_com.mt_count = num;
+   stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+   if (stat < 0) {
+      clrerror_dev(dev, MTBSR);
+      Mmsg2(&dev->errmsg, "ioctl MTBSR error on %s. ERR=%s.\n",
+        dev->dev_name, strerror(dev->dev_errno));
+   }
+   update_pos_dev(dev);
+   return stat;
+}
+
+
+
+/*
+ * Write an end of file on the device
+ */
+int 
+weof_dev(DEVICE *dev, int num)
+{ 
+   struct mtop mt_com;
+   int stat;
+
+   if (dev->fd < 0) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return -1;
+   }
+
+   if (!(dev->state & ST_TAPE)) {
+      return 0;
+   }
+   dev->state &= ~(ST_EOT | ST_EOF);  /* remove EOF/EOT flags */
+   dev->block_num = 0;
+   Dmsg0(29, "weof_dev\n");
+   mt_com.mt_op = MTWEOF;
+   mt_com.mt_count = num;
+   stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+   if (stat == 0) {
+      dev->file++;
+   } else {
+      clrerror_dev(dev, MTWEOF);
+      Mmsg2(&dev->errmsg, "ioctl MTWEOF error on %s. ERR=%s.\n",
+        dev->dev_name, strerror(dev->dev_errno));
+   }
+   return stat;
+}
+
+/*
+ * Return string message with last error in English
+ *  Be careful not to call this routine from within dev.c
+ *  while editing an Mmsg(&) or you will end up in a recursive
+ *  loop creating a Segmentation Violation.
+ */
+char *
+strerror_dev(DEVICE *dev)
+{
+   return dev->errmsg;
+}
+
+
+/*
+ * If implemented in system, clear the tape
+ * error status.
+ */
+void
+clrerror_dev(DEVICE *dev, int func)
+{
+   char *msg = NULL;
+
+   dev->dev_errno = errno;        /* save errno */
+   if (errno == EIO) {
+      dev->VolCatInfo.VolCatErrors++;
+   }
+
+   if (!(dev->state & ST_TAPE)) {
+      return;
+   }
+   if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
+      switch (func) {
+        case -1:
+            Emsg0(M_ABORT, 0, "Got ENOTTY on read/write!\n");
+           break;
+        case MTWEOF:
+            msg = "WTWEOF";
+           dev->capabilities &= ~CAP_EOF; /* turn off feature */
+           break;
+        case MTEOM:
+            msg = "WTEOM";
+           dev->capabilities &= ~CAP_EOM; /* turn off feature */
+           break;
+        case MTFSF:
+            msg = "MTFSF";
+           dev->capabilities &= ~CAP_FSF; /* turn off feature */
+           break;
+        case MTBSF:
+            msg = "MTBSF";
+           dev->capabilities &= ~CAP_BSF; /* turn off feature */
+           break;
+        case MTFSR:
+            msg = "MTFSR";
+           dev->capabilities &= ~CAP_FSR; /* turn off feature */
+           break;
+        case MTBSR:
+            msg = "MTBSR";
+           dev->capabilities &= ~CAP_BSR; /* turn off feature */
+           break;
+        default:
+            msg = "Unknown";
+           break;
+      }
+      if (msg != NULL) {
+        dev->dev_errno = ENOSYS;
+         Mmsg1(&dev->errmsg, "This device does not support %s.\n", msg);
+        Emsg0(M_ERROR, 0, dev->errmsg);
+      }
+   }
+#ifdef MTIOCLRERR
+{
+   struct mtop mt_com;
+   int stat;
+   mt_com.mt_op = MTIOCLRERR;
+   mt_com.mt_count = 1;
+   stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+   Dmsg0(200, "Did MTIOCLRERR\n");
+}
+#endif
+}
+
+/*
+ * Flush buffer contents
+ *  No longer used.
+ */
+int flush_dev(DEVICE *dev)
+{
+   return 1;
+}
+
+static void do_close(DEVICE *dev)
+{
+   Dmsg0(29, "really close_dev\n");
+   close(dev->fd);
+   /* Clean up device packet so it can be reused */
+   dev->fd = -1;
+   dev->state &= ~(ST_OPENED|ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
+   dev->block_num = 0;
+   dev->file = 0;
+   dev->LastBlockNumWritten = 0;
+   memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
+   memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
+}
+
+/* 
+ * Close the device
+ */
+void
+close_dev(DEVICE *dev)
+{
+   if (!dev) {
+      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return;
+   }
+   if (dev->fd >= 0 && dev->use_count == 1) {
+      do_close(dev);
+   } else {    
+      Dmsg0(29, "close_dev but in use so leave open.\n");
+   }
+   dev->use_count--;
+}
+
+void force_close_dev(DEVICE *dev)
+{
+   if (!dev) {
+      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return;
+   }
+   Dmsg0(29, "really close_dev\n");
+   do_close(dev);
+   dev->use_count--;
+}
+
+int 
+dev_is_tape(DEVICE *dev)
+{  
+   return (dev->state & ST_TAPE) ? 1 : 0;
+}
+
+char *
+dev_name(DEVICE *dev)
+{
+   return dev->dev_name;
+}
+
+char *
+dev_vol_name(DEVICE *dev)
+{
+   return dev->VolCatInfo.VolCatName;
+}
+
+uint32_t dev_block(DEVICE *dev)
+{
+   update_pos_dev(dev);
+   return dev->block_num;
+}
+
+uint32_t dev_file(DEVICE *dev)
+{
+   update_pos_dev(dev);
+   return dev->file;
+}
+
+/* 
+ * Free memory allocated for the device
+ */
+void
+term_dev(DEVICE *dev)
+{
+   if (!dev) {
+      dev->dev_errno = EBADF;
+      Mmsg0(&dev->errmsg, "Bad call to fsf_dev. Archive not open\n");
+      Emsg0(M_FATAL, 0, dev->errmsg);
+      return;
+   }
+   close_dev(dev);
+   Dmsg0(29, "term_dev\n");
+   if (dev->dev_name) {
+      free_memory(dev->dev_name);
+      dev->dev_name = NULL;
+   }
+   if (dev->errmsg) {
+      free_memory(dev->errmsg);
+      dev->errmsg = NULL;
+   }
+   pthread_mutex_destroy(&dev->mutex);
+   pthread_cond_destroy(&dev->wait);
+   pthread_cond_destroy(&dev->wait_next_vol);
+   if (dev->state & ST_MALLOC) {
+      free_memory(dev);
+   }
+}
diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h
new file mode 100644 (file)
index 0000000..ead1ddf
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Definitions for using the Device functions in Bacula
+ *  Tape and File storage access
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#ifndef __DEV_H
+#define __DEV_H 1
+
+/* Arguments to open_dev() */
+#define READ_WRITE 0
+#define READ_ONLY  1
+
+/* Generic status bits returned from status_dev() */
+#define MT_TAPE      (1<<0)                /* is tape device */
+#define MT_EOF       (1<<1)                /* just read EOF */
+#define MT_BOT       (1<<2)                /* at beginning of tape */
+#define MT_EOT       (1<<3)                /* end of tape reached */
+#define MT_SM        (1<<4)                /* DDS setmark */
+#define MT_EOD       (1<<5)                /* DDS at end of data */
+#define MT_WR_PROT   (1<<6)                /* tape write protected */
+#define MT_ONLINE    (1<<7)                /* tape online */
+#define MT_DR_OPEN   (1<<8)                /* tape door open */
+#define MT_IM_REP_EN (1<<9)                /* immediate report enabled */
+
+
+/* Bits for device capabilities */
+#define CAP_EOF        0x001          /* has MTWEOF */
+#define CAP_BSR        0x002          /* has MTBSR */
+#define CAP_BSF        0x004          /* has MTBSF */
+#define CAP_FSR        0x008          /* has MTFSR */
+#define CAP_FSF        0x010          /* has MTFSF */
+#define CAP_EOM        0x020          /* has MTEOM */
+#define CAP_REM        0x040          /* is removable media */
+#define CAP_RACCESS    0x080          /* is random access device */
+#define CAP_AUTOMOUNT  0x100          /* Read device at start to see what is there */
+#define CAP_LABEL      0x200          /* Label blank tapes */
+#define CAP_ANONVOLS   0x400          /* Mount without knowing volume name */
+#define CAP_ALWAYSOPEN 0x800          /* always keep device open */
+
+
+/* Tape state bits */
+#define ST_OPENED    0x001            /* set when device opened */
+#define ST_TAPE      0x002            /* is a tape device */  
+#define ST_LABEL     0x004            /* label found */
+#define ST_MALLOC    0x008            /* dev packet malloc'ed in init_dev() */
+#define ST_APPEND    0x010            /* ready for Bacula append */
+#define ST_READ      0x020            /* ready for Bacula read */
+#define ST_EOT       0x040            /* at end of tape */
+#define ST_WEOT      0x080            /* Got EOT on write */
+#define ST_EOF       0x100            /* Read EOF i.e. zero bytes */
+#define ST_NEXTVOL   0x200            /* Start writing on next volume */
+#define ST_SHORT     0x400            /* Short block read */
+
+/* dev_blocked states (mutually exclusive) */
+#define BST_NOT_BLOCKED       0       /* not blocked */
+#define BST_UNMOUNTED         1       /* User unmounted device */
+#define BST_WAITING_FOR_SYSOP 2       /* Waiting for operator to mount tape */
+#define BST_DOING_ACQUIRE     3       /* Opening/validating/moving tape */
+#define BST_WRITING_LABEL     4       /* Labeling a tape */  
+#define BST_UNMOUNTED_WAITING_FOR_SYSOP 5 /* Closed by user during mount request */
+
+/* Volume Catalog Information structure definition */
+typedef struct s_volume_catalog_info {
+   /* Media info for the current Volume */
+   uint32_t VolCatJobs;               /* number of jobs on this Volume */
+   uint32_t VolCatFiles;              /* Number of files */
+   uint32_t VolCatBlocks;             /* Number of blocks */
+   uint64_t VolCatBytes;              /* Number of bytes written */
+   uint32_t VolCatMounts;             /* Number of mounts this volume */
+   uint32_t VolCatErrors;             /* Number of errors this volume */
+   uint32_t VolCatWrites;             /* Number of writes this volume */
+   uint32_t VolCatReads;              /* Number of reads this volume */
+   uint64_t VolCatMaxBytes;           /* max bytes to write */
+   uint64_t VolCatCapacityBytes;      /* capacity estimate */
+   char VolCatStatus[20];             /* Volume status */
+   char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
+} VOLUME_CAT_INFO;
+
+
+/* Device structure definition */
+typedef struct s_device {
+   struct s_device *next;             /* pointer to next open device */
+   pthread_mutex_t mutex;             /* access control */
+   pthread_cond_t wait;               /* thread wait variable */
+   pthread_cond_t wait_next_vol;      /* wait for tape to be mounted */
+   pthread_t no_wait_id;              /* this thread must not wait */
+   int dev_blocked;                   /* set if we must wait (i.e. change tape) */
+   int num_waiting;                   /* number of threads waiting */
+   int num_writers;                   /* number of writing threads */
+   int use_count;                     /* usage count on this device */
+   int fd;                            /* file descriptor */
+   int capabilities;                  /* capabilities mask */
+   int state;                         /* state mask */
+   int dev_errno;                     /* Our own errno */
+   int mode;                          /* read/write modes */
+   char *dev_name;                    /* device name */
+   char *errmsg;                      /* nicely edited error message */
+   uint32_t block_num;                /* current block number base 0 */
+   uint32_t file;                     /* current file number base 0 */
+   uint32_t LastBlockNumWritten;      /* last block written */
+   uint32_t min_block_size;           /* min block size */
+   uint32_t max_block_size;           /* max block size */
+   uint32_t max_volume_jobs;          /* max jobs to put on one volume */
+   int64_t max_volume_files;          /* max files to put on one volume */
+   int64_t max_volume_size;           /* max bytes to put on one volume */
+   int64_t max_file_size;             /* max file size in bytes */
+   int64_t volume_capacity;           /* advisory capacity */
+   uint32_t max_rewind_wait;          /* max secs to allow for rewind */
+   void *device;                      /* pointer to Device Resource */
+
+   VOLUME_CAT_INFO VolCatInfo;        /* Volume Catalog Information */
+   struct Volume_Label VolHdr;        /* Actual volume label */
+
+} DEVICE;
+
+
+
+
+#ifdef SunOS
+#define DEFAULT_TAPE_DRIVE "/dev/rmt/0cbn"
+#endif
+#ifdef AIX
+#define DEFAULT_TAPE_DRIVE "/dev/rmt0.1"
+#endif
+#ifdef SGI
+#define DEFAULT_TAPE_DRIVE "/dev/tps0d4nr"
+#endif
+#ifdef Linux
+#define DEFAULT_TAPE_DRIVE "/dev/nst0"
+#endif
+#ifdef OSF
+#define DEFAULT_TAPE_DRIVE "/dev/nrmt0"
+#endif
+#ifdef HPUX
+#define DEFAULT_TAPE_DRIVE "/dev/rmt/0hnb"
+#endif
+#ifdef FreeBSD
+#define DEFAULT_TAPE_DRIVE "/dev/nrst0"
+#endif
+
+/* Default default */
+#ifndef DEFAULT_TAPE_DRIVE
+#define DEFAULT_TAPE_DRIVE "/dev/nst0"
+#endif
+
+/* Get some definition of function to position
+ *  to the end of the medium in MTEOM. System
+ *  dependent. Arrgggg!
+ */
+#ifndef MTEOM
+#ifdef  MTSEOD
+#define MTEOM MTSEOD
+#endif
+#ifdef MTEOD
+#undef MTEOM
+#define MTEOM MTEOD
+#endif
+#endif
+
+#endif
diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c
new file mode 100644 (file)
index 0000000..f92081f
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+ *
+ *  Higher Level Device routines. 
+ *  Knows about Bacula tape labels and such  
+ *
+ *  NOTE! In general, subroutines that have the word
+ *        "device" in the name do locking.  Subroutines
+ *        that have the word "dev" in the name do not
+ *       do locking.  Thus if xxx_device() calls
+ *       yyy_dev(), all is OK, but if xxx_device()
+ *       calls yyy_device(), everything will hang.
+ *       Obviously, no zzz_dev() is allowed to call
+ *       a www_device() or everything falls apart. 
+ *
+ * Concerning the routines lock_device() and block_device()
+ *  see the end of this module for details.  In general,
+ *  blocking a device leaves it in a state where all threads
+ *  other than the current thread block when they attempt to 
+ *  lock the device. They remain suspended (blocked) until the device
+ *  is unblocked. So, a device is blocked during an operation
+ *  that takes a long time (initialization, mounting a new
+ *  volume, ...) locking a device is done for an operation
+ *  that takes a short time such as writing data to the   
+ *  device.
+ *
+ *
+ *   Kern Sibbald, MM, MMI
+ *                           
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"                   /* pull in global headers */
+#include "stored.h"                   /* pull in Storage Deamon headers */
+
+/* Forward referenced functions */
+static int ready_dev_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+static int mount_next_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *label_blk);
+
+extern char my_name[];
+extern int debug_level;
+
+
+/********************************************************************* 
+ * Acquire device for reading. We permit (for the moment)
+ *  only one reader.  We read the Volume label from the block and
+ *  leave the block pointers just after the label.
+ *
+ *  Returns: 0 if failed for any reason
+ *          1 if successful
+ */
+int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   int stat;
+
+   lock_device(dev);
+   if (dev->state & ST_READ || dev->num_writers > 0) {
+      Jmsg(jcr, M_FATAL, 0, _("Device %s is busy.\n"), dev_name(dev));
+      unlock_device(dev);
+      return 0;
+   }
+   dev->state &= ~ST_LABEL;          /* force reread of label */
+   block_device(dev, BST_DOING_ACQUIRE);
+   unlock_device(dev);
+   stat = ready_dev_for_read(jcr, dev, block); 
+   P(dev->mutex); 
+   unblock_device(dev);
+   V(dev->mutex);
+   return stat;
+}
+
+/*
+ * Acquire device for writing. We permit multiple writers.
+ *  If this is the first one, we read the label.
+ *
+ *  Returns: 0 if failed for any reason
+ *          1 if successful
+ */
+int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+
+   lock_device(dev);
+   Dmsg1(90, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk");
+   if (!(dev->state & ST_APPEND)) {
+      if (dev->state & ST_READ) {
+         Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev));
+        unlock_device(dev);
+        return 0;
+      } 
+      ASSERT(dev->num_writers == 0);
+      block_device(dev, BST_DOING_ACQUIRE);
+      unlock_device(dev);
+      if (!ready_dev_for_append(jcr, dev, block)) {
+         Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
+           dev_name(dev));
+        P(dev->mutex);
+        unblock_device(dev);
+        V(dev->mutex);
+        return 0;
+      }
+      P(dev->mutex);
+      dev->VolCatInfo.VolCatJobs++;        /* increment number of jobs on this media */
+      dev->num_writers = 1;
+      if (jcr->NumVolumes == 0) {
+        jcr->NumVolumes = 1;
+      }
+      unblock_device(dev);
+      V(dev->mutex);
+      return 1;
+   } else { 
+      /* 
+       * Device already in append mode  
+       *
+       * Check if we have the right Volume mounted   
+       *  OK if AnonVols and volume info OK
+       *  OK if next volume matches current volume
+       *  otherwise mount desired volume obtained from
+       *    dir_find_next_appendable_volume
+       */
+      strcpy(jcr->VolumeName, dev->VolHdr.VolName);
+      if (((dev->capabilities & CAP_ANONVOLS) &&
+           !dir_get_volume_info(jcr)) ||
+         (!dir_find_next_appendable_volume(jcr) || 
+           strcmp(dev->VolHdr.VolName, jcr->VolumeName) != 0)) { /* wrong tape mounted */
+        if (dev->num_writers != 0) {
+            Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing with another Volume.\n"), dev_name(dev));
+           unlock_device(dev);
+           return 0;
+        }
+        /* Wrong tape currently mounted */  
+        block_device(dev, BST_DOING_ACQUIRE);
+        unlock_device(dev);
+        if (!mount_next_volume(jcr, dev, block)) {
+            Jmsg(jcr, M_FATAL, 0, _("Unable to mount desired volume.\n"));
+           P(dev->mutex);
+           unblock_device(dev);
+           V(dev->mutex);
+           return 0;
+        }
+        P(dev->mutex);
+        unblock_device(dev);
+      }
+   }
+   dev->VolCatInfo.VolCatJobs++;           /* increment number of jobs on this media */
+   dev->num_writers++;
+   if (dev->num_writers > 1) {
+      Dmsg2(0, "Hey!!!! There are %d writers on device %s\n", dev->num_writers,
+        dev_name(dev));
+   }
+   if (jcr->NumVolumes == 0) {
+      jcr->NumVolumes = 1;
+   }
+   unlock_device(dev);
+   return 1;                         /* got it */
+}
+
+/*
+ * This job is done, so release the device. From a Unix standpoint,
+ *  the device remains open.
+ *
+ */
+int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   P(dev->mutex);
+   Dmsg1(90, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk");
+   if (dev->state & ST_READ) {
+      dev->state &= ~ST_READ;        /* clear read bit */
+      if (!dev_is_tape(dev)) {
+        close_dev(dev);
+      }
+      /******FIXME**** send read volume info to director */
+
+   } else if (dev->num_writers > 0) {
+      dev->num_writers--;
+      Dmsg1(90, "There are %d writers in release_device\n", dev->num_writers);
+      if (dev->num_writers == 0) {
+        weof_dev(dev, 1);
+        dev->VolCatInfo.VolCatFiles++;             /* increment number of files */
+        /* Note! do volume update before close, which zaps VolCatInfo */
+        dir_update_volume_info(jcr, &dev->VolCatInfo);   /* send Volume info to Director */
+        if (!dev_is_tape(dev)) {
+           close_dev(dev);
+        } else {
+            Dmsg0(90, "Device is tape leave open in release_device\n");
+        }
+      } else {
+        dir_update_volume_info(jcr, &dev->VolCatInfo);   /* send Volume info to Director */
+      }
+   } else {
+      Emsg1(M_ERROR, 0, _("BAD ERROR: release_device %s not in use.\n"), dev_name(dev));
+   }
+   V(dev->mutex);
+   return 1;
+}
+
+
+
+/*
+ * We rewind the current volume, which we no longer want, and
+ *  ask the user (console) to mount the next volume.
+ *
+ *  Continue trying until we get it, and we call
+ *  ready_dev_for_append() so that we can write on it.
+ *
+ * This routine retuns a 0 only if it is REALLY
+ *  impossible to get the requested Volume.
+ */
+static int mount_next_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *label_blk)
+{
+   Dmsg0(90, "Enter mount_next_volume()\n");
+
+   /* 
+    * First erase all memory of the current volume   
+    */
+   dev->block_num = 0;
+   dev->file = 0;
+   dev->LastBlockNumWritten = 0;
+   memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
+   memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
+
+   /* Keep trying until we get something good mounted */
+   for ( ;; ) {
+      if (job_cancelled(jcr)) {
+         Mmsg0(&dev->errmsg, "Job cancelled.\n");
+        return 0;
+      }
+
+      if (dev->state & ST_OPENED && !rewind_dev(dev)) {
+         Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), 
+              dev_name(dev), strerror_dev(dev));
+      }
+
+      /*
+       * Ask to mount and wait if necessary   
+       */
+      if (!dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
+         Jmsg(jcr, M_FATAL, 0, _("Unable to mount next Volume on device %s\n"),
+           dev_name(dev));
+        return 0;
+      }
+
+      /* 
+       * Ready output device for writing
+       */
+      Dmsg1(120, "just before ready_dev_for_append dev=%x\n", dev);
+      if (!ready_dev_for_append(jcr, dev, label_blk)) {
+        continue;
+      }
+      dev->VolCatInfo.VolCatMounts++;
+      jcr->VolFirstFile = 0;
+      break;                      /* Got new volume, continue */
+   }
+   return 1;
+}
+
+
+/*
+ * This routine ensures that the device is ready for
+ * writing. We start from the assumption that there
+ * may not be a tape mounted. 
+ *
+ * If the device is a file, we create the output
+ * file. If it is a tape, we check the volume name
+ * and move the tape to the end of data.
+ *
+ * It assumes that the device is not already in use!
+ *
+ *  Returns 0 on failure
+ *  Returns 1 on success
+ */
+static int ready_dev_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   int mounted = 0;
+
+   Dmsg0(100, "Enter ready_dev_for_append\n");
+
+   dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
+
+
+   for ( ;; ) {
+      if (job_cancelled(jcr)) {
+         Mmsg(&dev->errmsg, "Job %s cancelled.\n", jcr->Job);
+        return 0;
+      }
+
+      /* 
+       * Ask Director for Volume Info (Name, attributes) to use.        
+       */
+      if (!dir_find_next_appendable_volume(jcr)) {
+        if (!dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
+            Jmsg1(jcr, M_ERROR, 0, _("Unable to mount desired Volume for device %s.\n"),
+              dev_name(dev));
+           return 0;              /* error return */
+        }
+      }
+      Dmsg1(200, "want vol=%s\n", jcr->VolumeName);
+
+      /* Open device */
+      for ( ; !(dev->state & ST_OPENED); ) {
+         if (open_dev(dev, jcr->VolCatInfo.VolCatName, READ_WRITE) < 0) {
+            if (dev->dev_errno == EAGAIN || dev->dev_errno == EBUSY) {
+               sleep(30);
+            }
+             Jmsg2(jcr, M_ERROR, 0, _("Unable to open device %s. ERR=%s\n"), 
+               dev_name(dev), strerror_dev(dev));
+            return 0;
+         }
+      }
+
+      /*
+       * Now make sure we have the right tape mounted
+       */
+      switch (read_dev_volume_label(jcr, dev, block)) {
+        case VOL_OK:
+            Dmsg1(200, "Vol OK name=%s\n", jcr->VolumeName);
+           memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo));
+           break;                    /* got it */
+        case VOL_NAME_ERROR:
+           /* Check if we can accept this as an anonymous volume */
+           strcpy(jcr->VolumeName, dev->VolHdr.VolName);
+           if (!dev->capabilities & CAP_ANONVOLS ||
+               !dir_get_volume_info(jcr)) {
+              goto mount_next_vol;
+           }
+            Dmsg1(200, "want new name=%s\n", jcr->VolumeName);
+           memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo));
+           break;
+
+        case VOL_NO_LABEL:
+        case VOL_IO_ERROR:
+           /* If permitted, create a label */
+           if (dev->capabilities & CAP_LABEL) {
+               Dmsg0(90, "Create volume label\n");
+              if (!write_volume_label_to_dev(jcr, (DEVRES *)dev->device, jcr->VolumeName,
+                     jcr->pool_name)) {
+                 return 0;
+              }
+               Jmsg(jcr, M_INFO, 0, _("Created Volume label %s on device %s.\n"),
+                 jcr->VolumeName, dev_name(dev));
+              mounted = 1;
+              continue;              /* read label we just wrote */
+           } 
+           /* NOTE! Fall-through wanted. */
+        default:
+mount_next_vol:
+           /* Send error message generated by read_dev_volume_label() */
+            Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);                         
+           rewind_dev(dev);
+           if (!dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
+               Jmsg1(jcr, M_ERROR, 0, _("Unable to mount desired Volume for device %s.\n"),
+                 dev_name(dev));
+              return 0;              /* error return */
+           }
+           mounted = 1;
+           continue;                 /* try reading again */
+      }
+      break;
+   }
+   if (mounted) {
+      dev->VolCatInfo.VolCatMounts++;
+   }
+
+   /* 
+    * See if we have a fresh tape or tape with data.
+    *
+    * Note, if the LabelType is PRE_LABEL, it was labeled
+    *  but never written. If so, rewrite the label but set as
+    *  VOL_LABEL.  We rewind and return the label (reconstructed)
+    *  in the block so that in the case of a new tape, data can
+    *  be appended just after the block label. If we are writing
+    *  an second volume, the calling routine will write the label
+    *  before writing the overflow block.
+    */
+   if (dev->VolHdr.LabelType == PRE_LABEL) {     /* fresh tape */
+      Dmsg1(90, "ready_for_append found freshly labeled volume. dev=%x\n", dev);
+      dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
+      write_volume_label_to_block(jcr, dev, block);
+      /*
+       * Write the block now to ensure we have write permission.
+       *  It is better to find out now rather than later.
+       */
+      dev->VolCatInfo.VolCatBytes = 0;
+      if (!rewind_dev(dev)) {
+         Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), 
+              dev_name(dev), strerror_dev(dev));
+      }
+      if (!write_block_to_dev(dev, block)) {
+         Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s. ERR=%s\n"),
+           dev_name(dev), strerror_dev(dev));
+        return 0;
+      }
+      if (!rewind_dev(dev)) {
+         Jmsg2(jcr, M_ERROR, 0, _("Unable to rewind device %s. ERR=%s\n"),
+           dev_name(dev), strerror_dev(dev));
+        return 0;
+      }
+      /* Recreate a correct volume label and return it in the block */
+      write_volume_label_to_block(jcr, dev, block);
+      dev->VolCatInfo.VolCatJobs = 1;
+      dev->VolCatInfo.VolCatFiles = 1;
+      dev->VolCatInfo.VolCatMounts = 1;
+      dev->VolCatInfo.VolCatErrors = 0;
+      dev->VolCatInfo.VolCatWrites = 1;
+      dev->VolCatInfo.VolCatBlocks = 1;
+      dir_update_volume_info(jcr, &dev->VolCatInfo);
+      Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume %s on device %s\n"),
+        jcr->VolumeName, dev_name(dev));
+
+   } else {
+      /* OK, at this point, we have a valid Bacula label, but
+       * we need to position to the end of the volume.
+       */
+      Dmsg0(20, "Device previously written, moving to end of data\n");
+      Jmsg(jcr, M_INFO, 0, _("Volume %s previously written, moving to end of data.\n"),
+        jcr->VolumeName);
+      if (!eod_dev(dev)) {
+         Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data %s. ERR=%s\n"),
+           dev_name(dev), strerror_dev(dev));
+         Jmsg(jcr, M_INFO, 0, _("Marking Volume %s in Error in Catalog.\n"),
+           jcr->VolumeName);
+         strcpy(dev->VolCatInfo.VolCatStatus, "Error");
+        dir_update_volume_info(jcr, &dev->VolCatInfo);
+        return 0;
+      }
+      /* *****FIXME**** we might do some checking for files too */
+      if (dev_is_tape(dev)) {
+         Jmsg(jcr, M_INFO, 0, _("Ready to write at EOM File=%d\n"), dev_file(dev));
+        if (dev->VolCatInfo.VolCatFiles != dev_file(dev) + 1) {
+           /* ****FIXME**** this should refuse to write on tape */
+            Jmsg(jcr, M_INFO, 0, _("Hey! Num files mismatch! Catalog Files=%d\n"), dev->VolCatInfo.VolCatFiles);
+        }
+      }
+      /* Return an empty block */
+      empty_block(block);            /* we used it for reading so set for write */
+   }
+   dev->state |= ST_APPEND;
+   Dmsg0(100, "Normal return from read_dev_for_append\n");
+   return 1; 
+}
+
+/*
+ * This routine ensures that the device is ready for
+ * reading. If it is a file, it opens it.
+ * If it is a tape, it checks the volume name 
+ *
+ *  Returns 0 on failure
+ *  Returns 1 on success
+ */
+int ready_dev_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   if (!(dev->state & ST_OPENED)) {
+       Dmsg1(20, "bstored: open vol=%s\n", jcr->VolumeName);
+       if (open_dev(dev, jcr->VolumeName, READ_ONLY) < 0) {
+          Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"), 
+             dev_name(dev), jcr->VolumeName, strerror_dev(dev));
+         return 0;
+       }
+       Dmsg1(29, "open_dev %s OK\n", dev_name(dev));
+   }
+
+   for (;;) {
+      if (job_cancelled(jcr)) {
+         Mmsg0(&dev->errmsg, _("Job cancelled.\n"));
+        return 0;
+      }
+      if (!rewind_dev(dev)) {
+         Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), 
+              dev_name(dev), strerror_dev(dev));
+      }
+      switch (read_dev_volume_label(jcr, dev, block)) {
+        case VOL_OK:
+           break;                    /* got it */
+        default:
+           /* Send error message generated by read_dev_volume_label() */
+            Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);                         
+           if (!rewind_dev(dev)) {
+               Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), 
+                    dev_name(dev), strerror_dev(dev));
+           }
+           if (!dir_ask_sysop_to_mount_volume(jcr, dev)) {
+              return 0;              /* error return */
+           }
+           continue;                 /* try reading again */
+      }
+      break;
+   }
+
+   dev->state |= ST_READ;
+   return 1; 
+}
+
+/*
+ * This is the dreaded moment. We either have an end of
+ * medium condition or worse, and error condition.
+ * Attempt to "recover" by obtaining a new Volume.
+ *
+ * We enter with device locked, and 
+ *     exit with device locked.
+ *
+ * Note, we are called only from one place in block.c
+ *
+ *  Returns: 1 on success
+ *          0 on failure
+ */
+int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   uint32_t stat = 0;                  
+   char PrevVolName[MAX_NAME_LENGTH];
+   DEV_BLOCK *label_blk;
+   char b1[30], b2[30];
+   time_t wait_time;
+
+   wait_time = time(NULL);
+   status_dev(dev, &stat);
+   if (stat & MT_EOD) {
+      Dmsg0(90, "======= Got EOD ========\n");
+
+      block_device(dev, BST_DOING_ACQUIRE);
+
+      strcpy(dev->VolCatInfo.VolCatStatus, "Full");
+      Dmsg0(90, "Call update_vol_info\n");
+      if (!dir_update_volume_info(jcr, &dev->VolCatInfo)) {    /* send Volume info to Director */
+         Jmsg(jcr, M_ERROR, 0, _("Could not update Volume info Volume=%s Job=%s\n"),
+           dev->VolCatInfo.VolCatName, jcr->Job);
+        return 0;                    /* device locked */
+      }
+      Dmsg0(90, "Back from update_vol_info\n");
+
+      strcpy(PrevVolName, dev->VolCatInfo.VolCatName);
+      strcpy(dev->VolHdr.PrevVolName, PrevVolName);
+
+      label_blk = new_block(dev);
+
+      /* Inform User about end of media */
+      Jmsg(jcr, M_INFO, 0, _("End of media on Volume %s Bytes=%s Blocks=%s.\n"), 
+          PrevVolName, edit_uint_with_commas(dev->VolCatInfo.VolCatBytes, b1),
+          edit_uint_with_commas(dev->VolCatInfo.VolCatBlocks, b2));
+
+      if (!dev_is_tape(dev)) {          /* If file, */
+        close_dev(dev);                 /* yes, close it */
+      }
+
+      /* Unlock, but leave BLOCKED */
+      unlock_device(dev);
+      if (!mount_next_volume(jcr, dev, label_blk)) {
+        P(dev->mutex);
+        unblock_device(dev);
+        return 0;                    /* device locked */
+      }
+
+      P(dev->mutex);                 /* lock again */
+
+      Jmsg(jcr, M_INFO, 0, _("New volume %s mounted on device %s\n"),
+        jcr->VolumeName, dev_name(dev));
+
+      /* 
+       * If this is a new tape, the label_blk will contain the
+       *  label, so write it now. If this is a previously
+       *  used tape, mount_next_volume() will return an
+       *  empty label_blk, and nothing will be written.
+       */
+      Dmsg0(90, "write label block to dev\n");
+      if (!write_block_to_dev(dev, label_blk)) {
+         Dmsg1(0, "write_block_to_device Volume label failed. ERR=%s",
+          strerror_dev(dev));
+        free_block(label_blk);
+        unblock_device(dev);
+        return 0;                    /* device locked */
+      }
+
+      /* Write overflow block to tape */
+      Dmsg0(90, "Write overflow block to dev\n");
+      if (!write_block_to_dev(dev, block)) {
+         Dmsg1(0, "write_block_to_device overflow block failed. ERR=%s",
+          strerror_dev(dev));
+        free_block(label_blk);
+        unblock_device(dev);
+        return 0;                    /* device locked */
+      }
+
+      jcr->NumVolumes++;
+      Dmsg0(90, "Wake up any waiting threads.\n");
+      free_block(label_blk);
+      unblock_device(dev);
+      jcr->run_time += time(NULL) - wait_time; /* correct run time */
+      return 1;                               /* device locked */
+   }
+   free_block(label_blk);
+   return 0;                         /* device locked */
+}
+
+
+/*
+ *   Open the device. Expect dev to already be initialized.  
+ *
+ *   This routine is used only when the Storage daemon starts 
+ *   and always_open is set, and in the stand-alone utility
+ *   routines such as bextract.
+ *
+ *   Note, opening of a normal file is deferred to later so
+ *    that we can get the filename; the device_name for
+ *    a file is the directory only. 
+ *
+ *   Retuns: 0 on failure
+ *          1 on success
+ */
+int open_device(DEVICE *dev)
+{
+   Dmsg0(20, "start open_output_device()\n");
+   if (!dev) {
+      return 0;
+   }
+
+   lock_device(dev);
+
+   /* Defer opening files */
+   if (!dev_is_tape(dev)) {
+      Dmsg0(29, "Device is file, deferring open.\n");
+      unlock_device(dev);
+      return 1;
+   }
+
+   if (!(dev->state & ST_OPENED)) {
+      Dmsg0(29, "Opening device.\n");
+      if (open_dev(dev, NULL, READ_WRITE) < 0) {
+         Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
+        unlock_device(dev);
+        return 0;
+      }
+   }
+   Dmsg1(29, "open_dev %s OK\n", dev_name(dev));
+
+   unlock_device(dev);
+   return 1;
+}
+
+
+/* 
+ * When dev_blocked is set, all threads EXCEPT thread with id no_wait_id
+ * must wait. The no_wait_id thread is out obtaining a new volume
+ * and preparing the label.
+ */
+void lock_device(DEVICE *dev)
+{
+   int stat;
+
+   Dmsg1(90, "lock %d\n", dev->dev_blocked);
+   P(dev->mutex);
+   if (dev->dev_blocked && !pthread_equal(dev->no_wait_id, pthread_self())) {
+      dev->num_waiting++;            /* indicate that I am waiting */
+      while (dev->dev_blocked) {
+        if ((stat = pthread_cond_wait(&dev->wait, &dev->mutex)) != 0) {
+           V(dev->mutex);
+            Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
+              strerror(stat));
+        }
+      }
+      dev->num_waiting--;            /* no longer waiting */
+   }
+}
+
+void unlock_device(DEVICE *dev) 
+{
+   Dmsg0(90, "unlock\n");
+   V(dev->mutex);
+}
+
+/* 
+ * Block all other threads from using the device
+ *  Device must already be locked.  After this call,
+ *  the device is blocked to any thread calling lock_device(),
+ *  but the device is not locked (i.e. no P on device).  Also,
+ *  the current thread can do slip through the lock_device()
+ *  calls without blocking.
+ */
+void block_device(DEVICE *dev, int state)
+{
+   Dmsg1(90, "block set %d\n", state);
+   ASSERT(dev->dev_blocked == BST_NOT_BLOCKED);
+   dev->dev_blocked = state;         /* make other threads wait */
+   dev->no_wait_id = pthread_self();  /* allow us to continue */
+}
+
+/*
+ * Unblock the device, and wake up anyone who went to sleep.
+ */
+void unblock_device(DEVICE *dev)
+{
+   Dmsg1(90, "unblock %d\n", dev->dev_blocked);
+   ASSERT(dev->dev_blocked);
+   dev->dev_blocked = BST_NOT_BLOCKED;
+   if (dev->num_waiting > 0) {
+      pthread_cond_broadcast(&dev->wait); /* wake them up */
+   }
+}
diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c
new file mode 100644 (file)
index 0000000..a2d0b62
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ *  This file handles accepting Director Commands
+ *
+ *    Most Director commands are handled here, with the 
+ *    exception of the Job command command and subsequent 
+ *    subcommands that are handled
+ *    in job.c.  
+ *
+ *    File daemon commands are handled in fdcmd.c
+ *
+ *     Kern Sibbald, May MMI
+ *  
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+/* Exported variables */
+
+/* Imported variables */
+extern BSOCK *filed_chan;
+extern int r_first, r_last;
+extern struct s_res resources[];
+extern char my_name[];
+extern time_t daemon_start_time;
+extern struct s_last_job last_job;
+
+/* Static variables */
+static char derrmsg[]       = "3900 Invalid command\n";
+static char OKsetdebug[]   = "3000 OK setdebug=%d\n";
+
+
+/* Imported functions */
+extern void terminate_child();
+extern int job_cmd(JCR *jcr);
+
+/* Forward referenced functions */
+static int label_cmd(JCR *jcr);
+static int setdebug_cmd(JCR *jcr);
+static int cancel_cmd(JCR *cjcr);
+static int mount_cmd(JCR *jcr);
+static int unmount_cmd(JCR *jcr);
+static int status_cmd(JCR *sjcr);
+static void label_device_if_ok(JCR *jcr, DEVICE *dev, char *vname, char *poolname);
+
+struct s_cmds {
+   char *cmd;
+   int (*func)(JCR *jcr);
+};
+
+/*  
+ * The following are the recognized commands from the Director. 
+ */
+static struct s_cmds cmds[] = {
+   {"JobId=",    job_cmd},            /* start Job */
+   {"setdebug=", setdebug_cmd},       /* set debug level */
+   {"cancel",    cancel_cmd},
+   {"label",     label_cmd},          /* label a tape */
+   {"mount",     mount_cmd},
+   {"unmount",   unmount_cmd},
+   {"status",    status_cmd},
+   {NULL,       NULL}                /* list terminator */
+};
+
+
+/* 
+ * Connection request. We accept connections either from the 
+ *  Director or a Client.
+ * 
+ * Note, we are running as a seperate thread of the Storage daemon.
+ *  and it is because a Director has made a connection with
+ *  us on the "Message" channel.    
+ *
+ * Basic tasks done here:  
+ *  - Create a JCR record
+ *  - Authenticate the Director
+ *  - We wait for a command
+ *  - We execute the command
+ *  - We continue or exit depending on the return status
+ */
+void connection_request(void *arg)
+{
+   BSOCK *bs = (BSOCK *)arg;
+   JCR *jcr;
+   int i, found, quit;
+   int bnet_stat;
+   char name[MAX_NAME_LENGTH];
+
+   if (bnet_recv(bs) <= 0) {
+      Emsg0(M_ERROR, 0, "Connection request failed.\n");
+      return;
+   }
+
+   /* 
+    * See if this is a File daemon connection
+    */
+   if (sscanf(bs->msg, "Hello Start Job %127s calling\n", name) == 1) {
+      handle_filed_connection(bs, name);
+      return;
+   }
+   
+   jcr = new_jcr(sizeof(JCR), stored_free_jcr);     /* create Job Control Record */
+   jcr->dir_bsock = bs;              /* save Director bsock */
+
+   Dmsg0(1000, "stored in start_job\n");
+
+   /*
+    * Authenticate the Director
+    */
+   if (!authenticate_director(jcr)) {
+      Emsg0(M_FATAL, 0, _("Unable to authenticate Director\n"));
+      free_jcr(jcr);
+      return;
+   }
+   Dmsg0(90, "Message channel init completed.\n");
+
+   for (quit=0; !quit;) {
+
+      /* Read command */
+      if ((bnet_stat = bnet_recv(bs)) <= 0) {
+        break;                       /* connection terminated */
+      }
+      Dmsg1(9, "<dird: %s\n", bs->msg);
+      found = FALSE;
+      for (i=0; cmds[i].cmd; i++) {
+        if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) {
+           if (!cmds[i].func(jcr)) {    /* do command */
+              quit = TRUE;              /* error, get out */
+               Dmsg1(90, "Command %s requsts quit\n", cmds[i].cmd);
+           }
+           found = TRUE;            /* indicate command found */
+           break;
+        }
+      }
+      if (!found) {                  /* command not found */
+        bnet_fsend(bs, derrmsg);
+        quit = TRUE;
+        break;
+      }
+   }
+   if (bnet_stat != BNET_TERMINATE) {
+      bnet_sig(bs, BNET_TERMINATE);
+   }
+   free_jcr(jcr);
+   return;
+}
+
+/*
+ * Set debug level as requested by the Director
+ *
+ */
+static int setdebug_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   int level;
+
+   Dmsg1(10, "setdebug_cmd: %s", dir->msg);
+   if (sscanf(dir->msg, "setdebug=%d", &level) != 1 || level < 0) {
+      bnet_fsend(dir, "3991 Bad setdebug command: %s\n", dir->msg);
+      return 0;
+   }
+   debug_level = level;
+   return bnet_fsend(dir, OKsetdebug, level);
+}
+
+
+/*
+ * Cancel a Job
+ */
+static int cancel_cmd(JCR *cjcr)
+{
+   BSOCK *dir = cjcr->dir_bsock;
+   int oldStatus;
+   char Job[MAX_NAME_LENGTH];
+   JCR *jcr;
+
+   if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
+      if (!(jcr=get_jcr_by_full_name(Job))) {
+         bnet_fsend(dir, _("3992 Job %s not found.\n"), Job);
+      } else {
+        P(jcr->mutex);
+        oldStatus = jcr->JobStatus;
+        jcr->JobStatus = JS_Cancelled;
+        if (!jcr->authenticated && jcr->JobStatus == JS_WaitFD) {
+           pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */
+        }
+        V(jcr->mutex);
+        if (jcr->file_bsock) {
+           bnet_sig(jcr->file_bsock, BNET_TERMINATE);
+        }
+         bnet_fsend(dir, _("3000 Job %s Status=%c marked to be cancelled.\n"), 
+           jcr->Job, oldStatus);
+        free_jcr(jcr);
+      }
+   } else {
+      bnet_fsend(dir, _("3993 Error scanning cancel command.\n"));
+   }
+   bnet_sig(dir, BNET_EOF);
+   return 1;
+}
+
+/*
+ * Label a tape
+ *
+ */
+static int label_cmd(JCR *jcr) 
+{
+   char *dname, *volname, *poolname, *mtype;
+   BSOCK *dir = jcr->dir_bsock;
+   DEVRES *device;
+   DEVICE *dev;
+   int found = 0;
+
+   dname = (char *) get_memory(dir->msglen+1);
+   volname = (char *) get_memory(dir->msglen+1);
+   poolname = (char *) get_memory(dir->msglen+1);
+   mtype = (char *) get_memory(dir->msglen+1);
+   if (sscanf(dir->msg, "label %s VolumeName=%s PoolName=%s MediaType=%s", 
+       dname, volname, poolname, mtype) == 4) {
+      unbash_spaces(dname);
+      unbash_spaces(volname);
+      unbash_spaces(poolname);
+      unbash_spaces(mtype);
+      device = NULL;
+      LockRes();
+      while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
+        /* Find resource, and make sure we were able to open it */
+        if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
+            Dmsg1(20, "Found device %s\n", device->hdr.name);
+           found = 1;
+           break;
+        }
+      }
+      UnlockRes();
+      if (found) {
+        /******FIXME**** compare MediaTypes */
+        jcr->device = device;
+        dev = device->dev;
+        P(dev->mutex);
+        if (!(dev->state & ST_OPENED)) {
+           if (open_dev(dev, volname, READ_WRITE) < 0) {
+               bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
+           } else {
+              label_device_if_ok(jcr, dev, volname, poolname);
+              force_close_dev(dev);
+           }
+        } else if (dev->dev_blocked && 
+                   dev->dev_blocked != BST_DOING_ACQUIRE) {  /* device blocked? */
+           label_device_if_ok(jcr, dev, volname, poolname);
+        } else if (dev->state & ST_READ || dev->num_writers) {
+           if (dev->state & ST_READ) {
+                bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"),
+                  dev_name(dev));
+           } else {
+                bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"),
+                  dev_name(dev), dev->num_writers);
+           }
+        } else {                     /* device not being used */
+           label_device_if_ok(jcr, dev, volname, poolname);
+        }
+        V(dev->mutex);
+      } else {
+         bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
+      }
+   } else {
+      /* NB dir->msg gets clobbered in bnet_fsend, so save command */
+      strcpy(dname, dir->msg);
+      bnet_fsend(dir, _("3903 Error scanning label command: %s\n"), dname);
+   }
+   free_memory(dname);
+   free_memory(volname);
+   free_memory(poolname);
+   free_memory(mtype);
+   bnet_sig(dir, BNET_EOF);
+   return 1;
+}
+
+/* 
+ * Read the tape label and determine if we can safely
+ * label the tape (not a Bacula volume), then label it.
+ *
+ *  Enter with the mutex set
+ */
+static void label_device_if_ok(JCR *jcr, DEVICE *dev, char *vname, char *poolname)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   DEV_BLOCK *block;
+   int blocked;
+   pthread_t no_wait_id;
+   
+   blocked = dev->dev_blocked;       /* save any prev blocked state */
+   no_wait_id = dev->no_wait_id;
+   dev->dev_blocked = BST_WRITING_LABEL;
+   dev->no_wait_id = pthread_self();  /* let us use the tape */
+   V(dev->mutex);                    /* release lock */
+   
+   strcpy(jcr->VolumeName, vname);
+   block = new_block(dev);
+   switch (read_dev_volume_label(jcr, dev, block)) {               
+      case VOL_NAME_ERROR:
+      case VOL_VERSION_ERROR:
+      case VOL_LABEL_ERROR:
+      case VOL_OK:
+         bnet_fsend(dir, _("3901 Cannot label Volume because it is \
+already labeled: %s\n"), dev->VolHdr.VolName);
+        break;
+      case VOL_IO_ERROR:
+      case VOL_NO_LABEL:
+        write_volume_label_to_dev(jcr, jcr->device, vname, poolname);
+        strcpy(jcr->VolumeName, vname);
+         bnet_fsend(dir, _("3000 OK label. Volume=%s Device=%s\n"), 
+           vname, dev->dev_name);
+        break;
+      default:
+         bnet_fsend(dir, _("3902 Cannot label Volume. \
+Unknown status %d from read_volume_label()\n"), jcr->label_status);
+        break;
+   }
+   free_block(block);
+   P(dev->mutex);
+   dev->dev_blocked = blocked;       /* reset blocked state */
+   dev->no_wait_id = no_wait_id;      /* reset blocking thread id */
+}
+
+
+/* 
+ * Read the tape label
+ *
+ *  Enter with the mutex set
+ */
+static int read_label(JCR *jcr, DEVICE *dev)
+{
+   BSOCK *dir = jcr->dir_bsock;
+   DEV_BLOCK *block;
+   int blocked;
+   pthread_t no_wait_id;
+   int stat;
+   
+   blocked = dev->dev_blocked;       /* save any prev blocked state */
+   no_wait_id = dev->no_wait_id;
+   dev->dev_blocked = BST_DOING_ACQUIRE;
+   dev->no_wait_id = pthread_self();  /* let us use the tape */
+   V(dev->mutex);                    /* release lock */
+   
+   jcr->VolumeName[0] = 0;
+   block = new_block(dev);
+   dev->state &= ~ST_LABEL;          /* force read of label */
+   switch (read_dev_volume_label(jcr, dev, block)) {               
+      case VOL_OK:
+         bnet_fsend(dir, _("3001 Mounted Volume: %s\n"), dev->VolHdr.VolName);
+        stat = 1;
+        break;
+      default:
+         bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s\n"),
+           dev->dev_name, jcr->errmsg);
+        stat = 0;
+        break;
+   }
+   free_block(block);
+   P(dev->mutex);
+   dev->dev_blocked = blocked;       /* reset blocked state */
+   dev->no_wait_id = no_wait_id;      /* reset blocking thread id */
+   return stat;
+}
+
+/*
+ * Mount command from Director
+ */
+static int mount_cmd(JCR *jcr)
+{
+   char *dev_name;
+   BSOCK *dir = jcr->dir_bsock;
+   DEVRES *device;
+   DEVICE *dev;
+   int found = 0;
+
+   dev_name = (char *) get_memory(dir->msglen);
+   if (sscanf(dir->msg, "mount %s", dev_name) == 1) {
+      unbash_spaces(dev_name);
+      device = NULL;
+      LockRes();
+      while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
+        /* Find resource, and make sure we were able to open it */
+        if (strcmp(device->hdr.name, dev_name) == 0 && device->dev) {
+            Dmsg1(20, "Found device %s\n", device->hdr.name);
+           found = 1;
+           break;
+        }
+      }
+      UnlockRes();
+      if (found) {
+        jcr->device = device;
+        dev = device->dev;
+        P(dev->mutex);
+        switch (dev->dev_blocked) {         /* device blocked? */
+           DEV_BLOCK *block;
+           case BST_WAITING_FOR_SYSOP:
+              /* Someone is waiting, wake him */
+               Dmsg0(90, "Waiting for mount attempt to wake thread\n");
+              pthread_cond_signal(&dev->wait_next_vol);
+               bnet_fsend(dir, "3001 OK mount. Device=%s\n", dev->dev_name);
+              break;
+
+           case BST_UNMOUNTED_WAITING_FOR_SYSOP:
+           case BST_UNMOUNTED:
+              /* We freed the device, so reopen it and wake any waiting threads */
+              if (open_dev(dev, NULL, READ_WRITE) < 0) {
+                  bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), 
+                    strerror_dev(dev));
+                 break;
+              }
+              block = new_block(dev);
+              read_dev_volume_label(jcr, dev, block);
+              free_block(block);
+              if (dev->dev_blocked == BST_UNMOUNTED) {
+                  Dmsg0(90, "Unmounted unblocking device\n");
+                 read_label(jcr, dev);
+                 unblock_device(dev);
+              } else {
+                  Dmsg0(90, "Unmounted waiting for mount attempt to wake thread\n");
+                 dev->dev_blocked = BST_WAITING_FOR_SYSOP;
+                 pthread_cond_signal(&dev->wait_next_vol);
+              }
+              if (dev->state & ST_LABEL) {
+                  bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"), 
+                    dev->dev_name, dev->VolHdr.VolName);
+              } else {
+                  bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
+                            dev->dev_name);
+              }
+              break;
+
+           case BST_DOING_ACQUIRE:
+               bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"), 
+                         dev->dev_name);
+              break;
+
+           case BST_WRITING_LABEL:
+               bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev->dev_name);
+              break;
+
+           case BST_NOT_BLOCKED:
+              if (dev->state & ST_OPENED) {
+                 if (dev->state & ST_LABEL) {
+                     bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"),
+                       dev->dev_name, dev->VolHdr.VolName);
+                 } else {
+                     bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
+                               dev->dev_name);
+                 }
+              } else {
+                 if (!dev_is_tape(dev)) {
+                     bnet_fsend(dir, _("3906 cannot mount non-tape.\n"));
+                    break;
+                 }
+                 if (open_dev(dev, NULL, READ_WRITE) < 0) {
+                     bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), 
+                       strerror_dev(dev));
+                    break;
+                 }
+                 read_label(jcr, dev);
+                 if (dev->state & ST_LABEL) {
+                     bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"), 
+                       dev->dev_name, dev->VolHdr.VolName);
+                 } else {
+                     bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
+                               dev->dev_name);
+                 }
+              }
+              break;
+
+           default:
+               bnet_fsend(dir, _("3905 Bizarre wait state %d\n"), dev->dev_blocked);
+              break;
+        }
+        V(dev->mutex);
+      } else {
+         bnet_fsend(dir, _("3999 Device %s not found\n"), dev_name);
+      }
+   } else {
+      strcpy(dev_name, dir->msg);
+      bnet_fsend(dir, _("3906 Error scanning mount command: %s\n"), dev_name);
+   }
+   free_memory(dev_name);
+   bnet_sig(dir, BNET_EOF);
+   return 1;
+}
+
+/*
+ * unmount command from Director
+ */
+static int unmount_cmd(JCR *jcr)
+{
+   char *dname;
+   BSOCK *dir = jcr->dir_bsock;
+   DEVRES *device;
+   DEVICE *dev;
+   int found = 0;
+
+   dname = (char *) get_memory(dir->msglen+1);
+   if (sscanf(dir->msg, "unmount %s", dname) == 1) {
+      unbash_spaces(dname);
+      device = NULL;
+      LockRes();
+      while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
+        /* Find resource, and make sure we were able to open it */
+        if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
+            Dmsg1(20, "Found device %s\n", device->hdr.name);
+           found = 1;
+           break;
+        }
+      }
+      UnlockRes();
+      if (found) {
+        jcr->device = device;
+        dev = device->dev;
+        P(dev->mutex);
+        if (!(dev->state & ST_OPENED)) {
+            Dmsg0(90, "Device already unmounted\n");
+            bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"), dev_name(dev));
+
+        } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
+            Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
+              dev->dev_blocked);
+           force_close_dev(dev);
+           dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
+            bnet_fsend(dir, _("3001 Device %s unmounted.\n"), dev_name(dev));
+
+        } else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
+            bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"),
+              dev_name(dev));
+
+        } else if (dev->dev_blocked == BST_WRITING_LABEL) {
+            bnet_fsend(dir, _("3903 Device %s is being labeled.\n"),
+              dev_name(dev));
+
+        } else if (dev->state & ST_READ || dev->num_writers) {
+           if (dev->state & ST_READ) {
+                Dmsg0(90, "Device in read mode\n");
+                bnet_fsend(dir, _("3904 Device %s is busy with 1 reader.\n"),
+                  dev_name(dev));
+           } else {
+                Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
+                bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"),
+                  dev_name(dev), dev->num_writers);
+           }
+
+        } else {                     /* device not being used */
+            Dmsg0(90, "Device not in use, unmounting\n");
+           block_device(dev, BST_UNMOUNTED);
+           force_close_dev(dev);
+            bnet_fsend(dir, _("3002 Device %s unmounted.\n"), dev_name(dev));
+        }
+        V(dev->mutex);
+      } else {
+         bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
+      }
+   } else {
+      /* NB dir->msg gets clobbered in bnet_fsend, so save command */
+      strcpy(dname, dir->msg);
+      bnet_fsend(dir, _("3907 Error scanning unmount command: %s\n"), dname);
+   }
+   free_memory(dname);
+   bnet_sig(dir, BNET_EOF);
+   return 1;
+}
+
+/*
+ * Status command from Director
+ */
+static int status_cmd(JCR *jcr)
+{
+   DEVRES *device;
+   DEVICE *dev;
+   int found, bps, sec, bpb;
+   BSOCK *user = jcr->dir_bsock;
+   char dt[MAX_TIME_LENGTH];
+   char b1[30], b2[30], b3[30];
+
+   bnet_fsend(user, "\n%s Version: " VERSION " (" DATE ")\n", my_name);
+   bstrftime(dt, sizeof(dt), daemon_start_time);
+   bnet_fsend(user, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs,
+        last_job.NumJobs == 1 ? "" : "s");
+   if (last_job.NumJobs > 0) {
+      char *termstat, jstat[2];
+
+      bstrftime(dt, sizeof(dt), last_job.end_time);
+      bnet_fsend(user, _("Last Job %s finished at %s\n"), last_job.Job, dt);
+      switch (last_job.JobStatus) {
+        case JS_Terminated:
+            termstat = _("OK");
+           break;
+       case JS_ErrorTerminated:
+            termstat = _("Error");
+           break;
+       default:
+           jstat[0] = last_job.JobStatus;
+           jstat[1] = 0;
+           termstat = jstat;
+           break;
+      }
+          
+      bnet_fsend(user, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
+          edit_uint_with_commas(last_job.JobFiles, b1),
+          edit_uint_with_commas(last_job.JobBytes, b2),
+          termstat);
+   }
+
+   LockRes();
+   for (device=NULL;  (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
+      dev = device->dev;
+      if (dev) {
+        if (dev->state & ST_OPENED) {
+           if (dev->state & ST_LABEL) {
+               bnet_fsend(user, _("Device %s is mounted with Volume %s\n"), 
+                 dev_name(dev), dev->VolHdr.VolName);
+           } else {
+               bnet_fsend(user, _("Device %s open but no Bacula volume is mounted.\n"), dev_name(dev));
+           }
+           switch (dev->dev_blocked) {
+              case BST_UNMOUNTED:
+                  bnet_fsend(user, _("    Deviced is blocked. User unmounted.\n"));
+                 break;
+              case BST_UNMOUNTED_WAITING_FOR_SYSOP:
+                  bnet_fsend(user, _("    Deviced is blocked. User unmounted during wait for media/mount.\n"));
+                 break;
+              case BST_WAITING_FOR_SYSOP:
+                 if (jcr->JobStatus == JS_WaitMount) {
+                     bnet_fsend(user, _("    Device is blocked waiting for mount.\n"));
+                 } else {
+                     bnet_fsend(user, _("    Device is blocked waiting for appendable media.\n"));
+                 }
+                 break;
+              case BST_DOING_ACQUIRE:
+                  bnet_fsend(user, _("    Device is being initialized.\n"));
+                 break;
+              case BST_WRITING_LABEL:
+                  bnet_fsend(user, _("    Device is blocked labeling a Volume.\n"));
+                 break;
+              default:
+                 break;
+           }
+           bpb = dev->VolCatInfo.VolCatBlocks;
+           if (bpb <= 0) {
+              bpb = 1;
+           }
+           bpb = dev->VolCatInfo.VolCatBytes / bpb;
+            bnet_fsend(user, _("    Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
+              edit_uint_with_commas(dev->VolCatInfo.VolCatBytes, b1),
+              edit_uint_with_commas(dev->VolCatInfo.VolCatBlocks, b2), 
+              edit_uint_with_commas(bpb, b3));
+            bnet_fsend(user, _("    Positioned at File=%s Block=%s\n"), 
+              edit_uint_with_commas(dev->file, b1),
+              edit_uint_with_commas(dev->block_num, b2));
+
+        } else {
+            bnet_fsend(user, _("Device %s is not open.\n"), dev_name(dev));
+        }
+      }
+   }
+   UnlockRes();
+
+   found = 0;
+   lock_jcr_chain();
+   /* NOTE, we reuse a calling argument jcr. Be warned! */ 
+   for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
+      if (jcr->JobStatus == JS_WaitFD) {
+         bnet_fsend(user, _("Job %s is waiting for the Client connection.\n"),
+           jcr->Job);
+      }
+      if (jcr->device) {
+         bnet_fsend(user, _("Job %s is using device %s\n"), 
+                  jcr->Job, jcr->device->device_name);
+        sec = time(NULL) - jcr->run_time;
+        if (sec <= 0) {
+           sec = 1;
+        }
+        bps = jcr->JobBytes / sec;
+         bnet_fsend(user, _("    Files=%s Bytes=%s Bytes/sec=%s\n"), 
+           edit_uint_with_commas(jcr->JobFiles, b1),
+           edit_uint_with_commas(jcr->JobBytes, b2),
+           edit_uint_with_commas(bps, b3));
+        found = 1;
+#ifdef DEBUG
+        if (jcr->file_bsock) {
+            bnet_fsend(user, "    FDReadSeqNo=%" lld " fd=%d\n", 
+              jcr->file_bsock->read_seqno, jcr->file_bsock->fd);
+        } else {
+            bnet_fsend(user, "    FDSocket closed\n");
+        }
+#endif
+      }
+      free_locked_jcr(jcr);
+   }
+   unlock_jcr_chain();
+   if (!found) {
+      bnet_fsend(user, _("No jobs running.\n"));
+   }
+
+#ifdef full_status
+   bnet_fsend(user, "\n\n");
+   dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user);
+#endif
+   bnet_fsend(user, "====\n");
+
+   bnet_sig(user, BNET_EOF);
+   return 1;
+}
diff --git a/bacula/src/stored/fd_cmds.c b/bacula/src/stored/fd_cmds.c
new file mode 100644 (file)
index 0000000..1e4a3ec
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * This file handles commands from the File daemon.
+ *
+ * We get here because the Director has initiated a Job with
+ *  the Storage daemon, then done the same with the File daemon,
+ *  then when the Storage daemon receives a proper connection from
+ *  the File daemon, control is passed here to handle the 
+ *  subsequent File daemon commands.
+ * 
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+/* Imported variables */
+
+/* Static variables */
+static char ferrmsg[]      = "3900 Invalid command\n";
+
+/* Imported functions */
+extern int do_append_data(JCR *jcr);
+extern int do_read_data(JCR *jcr);
+
+/* Forward referenced functions */
+
+
+/* Forward referenced FD commands */
+static int append_open_session(JCR *jcr);
+static int append_close_session(JCR *jcr);
+static int append_data_cmd(JCR *jcr);
+static int append_end_session(JCR *jcr);
+static int read_open_session(JCR *jcr);
+static int read_data_cmd(JCR *jcr);
+static int read_close_session(JCR *jcr);
+
+struct s_cmds {
+   char *cmd;
+   int (*func)(JCR *jcr);
+};
+
+/*  
+ * The following are the recognized commands from the File daemon
+ */
+static struct s_cmds fd_cmds[] = {
+   {"append open",  append_open_session},
+   {"append data",  append_data_cmd},
+   {"append end",   append_end_session},
+   {"append close", append_close_session},
+   {"read open",    read_open_session},
+   {"read data",    read_data_cmd},
+   {"read close",   read_close_session},
+   {NULL,          NULL}                  /* list terminator */
+};
+
+/* Commands from the File daemon that require additional scanning */
+/*  static char append_open[]  = "append open session\n"; */
+static char read_open[]    = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
+
+/* Responses sent to the File daemon */
+static char NO_open[]      = "3901 Error session already open\n";
+static char NOT_opened[]   = "3902 Error session not opened\n";
+static char OK_end[]       = "3000 OK end\n";
+static char OK_close[]     = "3000 OK close Volumes = %d\n";
+static char OK_open[]      = "3000 OK open ticket = %d\n";
+static char OK_append[]    = "3000 OK append data\n";
+static char ERROR_append[] = "3903 Error append data\n";
+
+/* Information sent to the Director */
+static char Job_start[] = "3010 Job %s start\n";
+static char Job_end[]  = 
+   "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%" lld "\n";
+
+/*
+ * Run a File daemon Job -- File daemon already authorized
+ *
+ * Basic task here is:
+ * - Read a command from the File daemon
+ * - Execute it
+ *
+ */
+void run_job(JCR *jcr)
+{
+   int i, found, quit;
+   BSOCK *fd = jcr->file_bsock;
+   BSOCK *dir = jcr->dir_bsock;
+
+
+   Dmsg1(20, "Start run Job=%s\n", jcr->Job);
+   bnet_fsend(dir, Job_start, jcr->Job); 
+   time(&jcr->start_time);
+   jcr->run_time = jcr->start_time;
+   jcr->JobStatus = JS_Running;
+   dir_send_job_status(jcr);         /* update director */
+   for (quit=0; !quit;) {
+
+      /* Read command coming from the File daemon */
+      if (bnet_recv(fd) <= 0) {
+        break;                       /* connection terminated */
+      }
+      Dmsg1(10, "<filed: %s", fd->msg);
+      found = 0;
+      for (i=0; fd_cmds[i].cmd; i++) {
+        if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) {
+           found = 1;               /* indicate command found */
+           if (!fd_cmds[i].func(jcr)) {    /* do command */
+              jcr->JobStatus = JS_ErrorTerminated;
+              quit = 1;
+           }
+           break;
+        }
+      }
+      if (!found) {                  /* command not found */
+         Dmsg1(10, "<filed: Command not found: %s\n", fd->msg);
+        bnet_fsend(fd, ferrmsg);
+        break;
+      }
+   }
+   time(&jcr->end_time);
+   if (!job_cancelled(jcr)) {
+      jcr->JobStatus = JS_Terminated;
+   }
+   bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
+      jcr->JobBytes);
+
+   bnet_sig(dir, BNET_EOF);          /* send EOF to Director daemon */
+   return;
+}
+
+       
+/*
+ *   Append Data command
+ *     Open Data Channel and receive Data for archiving
+ *     Write the Data to the archive device
+ */
+static int append_data_cmd(JCR *jcr)
+{
+   BSOCK *fd = jcr->file_bsock;
+
+   Dmsg1(20, "Append data: %s", fd->msg);
+   if (jcr->session_opened) {
+      Dmsg1(10, "<bfiled: %s", fd->msg);
+      if (do_append_data(jcr)) {
+        bnet_fsend(fd, OK_append);
+        jcr->JobType = JT_BACKUP;
+        return 1;
+      } else {
+        bnet_fsend(fd, ERROR_append);
+        return 0;
+      }
+   } else {
+      bnet_fsend(fd, NOT_opened);
+      return 0;
+   }
+}
+
+static int append_end_session(JCR *jcr)
+{
+   BSOCK *fd = jcr->file_bsock;
+
+   Dmsg1(20, "store<file: %s", fd->msg);
+   if (!jcr->session_opened) {
+      bnet_fsend(fd, NOT_opened);
+      return 0;
+   }
+   return bnet_fsend(fd, OK_end);
+}
+
+
+/* 
+ * Append Open session command
+ *
+ */
+static int append_open_session(JCR *jcr)
+{
+   BSOCK *fd = jcr->file_bsock;
+
+   Dmsg1(20, "Append open session: %s", fd->msg);
+   if (jcr->session_opened) {
+      bnet_fsend(fd, NO_open);
+      return 0;
+   }
+
+   Dmsg1(10, "Append open session: %s\n", dev_name(jcr->device->dev));
+   jcr->session_opened = TRUE;
+
+   /* Send "Ticket" to File Daemon */
+   bnet_fsend(fd, OK_open, jcr->VolSessionId);
+   Dmsg1(10, ">filed: %s", fd->msg);
+
+   return 1;
+}
+
+/*
+ *   Append Close session command
+ *     Close the append session and send back Statistics     
+ *        (need to fix statistics)
+ */
+static int append_close_session(JCR *jcr)
+{
+   BSOCK *fd = jcr->file_bsock;
+
+   Dmsg1(20, "<filed: %s\n", fd->msg);
+   if (!jcr->session_opened) {
+      bnet_fsend(fd, NOT_opened);
+      return 0;
+   }
+   /* Send final statistics to File daemon */
+   bnet_fsend(fd, OK_close, jcr->NumVolumes);
+   Dmsg1(60, ">filed: %s\n", fd->msg);
+
+   bnet_sig(fd, BNET_EOF);           /* send EOF to File daemon */
+       
+   Dmsg1(10, "Append close session: %s\n", dev_name(jcr->device->dev));
+
+   if (jcr->JobStatus != JS_ErrorTerminated) {
+      jcr->JobStatus = JS_Terminated;
+   }
+   jcr->session_opened = FALSE;
+   return 1;
+}
+
+/*
+ *   Read Data command
+ *     Open Data Channel, read the data from  
+ *     the archive device and send to File
+ *     daemon.
+ */
+static int read_data_cmd(JCR *jcr)
+{
+   BSOCK *fd = jcr->file_bsock;
+
+   Dmsg1(20, "Read data: %s\n", fd->msg);
+   if (jcr->session_opened) {
+      Dmsg1(20, "<bfiled: %s", fd->msg);
+      return do_read_data(jcr);
+   } else {
+      bnet_fsend(fd, NOT_opened);
+      return 0;
+   }
+}
+
+/* 
+ * Read Open session command
+ *
+ *  We need to scan for the parameters of the job
+ *    to be restored.
+ */
+static int read_open_session(JCR *jcr)
+{
+   BSOCK *fd = jcr->file_bsock;
+
+   Dmsg1(20, "%s\n", fd->msg);
+   if (jcr->session_opened) {
+      bnet_fsend(fd, NO_open);
+      return 0;
+   }
+
+   if (sscanf(fd->msg, read_open, jcr->VolumeName, &jcr->read_VolSessionId,
+        &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
+        &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
+      if (jcr->session_opened) {
+        bnet_fsend(fd, NOT_opened);
+        return 0;
+      }
+      Dmsg4(0, "Got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
+        jcr->JobId, jcr->VolumeName, jcr->read_VolSessionId, 
+        jcr->read_VolSessionTime);
+      Dmsg4(0, "  StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
+        jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
+        jcr->read_EndBlock);
+   }
+
+   Dmsg1(10, "Read open session: %s\n", dev_name(jcr->device->dev));
+
+   jcr->session_opened = TRUE;
+   jcr->JobType = JT_RESTORE;
+
+   /* Send "Ticket" to File Daemon */
+   bnet_fsend(fd, OK_open, jcr->VolSessionId);
+   Dmsg1(10, ">filed: %s", fd->msg);
+
+   return 1;
+}
+
+/*
+ *   Read Close session command
+ *     Close the read session
+ */
+static int read_close_session(JCR *jcr)
+{
+   BSOCK *fd = jcr->file_bsock;
+
+   Dmsg1(20, "Read close session: %s\n", fd->msg);
+   if (!jcr->session_opened) {
+      bnet_fsend(fd, NOT_opened);
+      return 0;
+   }
+   /* Send final statistics to File daemon */
+   bnet_fsend(fd, OK_close);
+   Dmsg1(60, ">filed: %s\n", fd->msg);
+
+   bnet_sig(fd, BNET_EOF);         /* send EOF to File daemon */
+       
+   jcr->session_opened = FALSE;
+   return 1;
+}
diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c
new file mode 100644 (file)
index 0000000..2866a1f
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ *   Job control and execution for Storage Daemon
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+/* Imported variables */
+extern uint32_t VolSessionTime;
+
+/* Imported functions */
+extern uint32_t newVolSessionId();
+
+/* Forward referenced functions */
+static int use_device_cmd(JCR *jcr);
+
+/* Requests from the Director daemon */
+static char jobcmd[]     = "JobId=%d job=%127s job_name=%127s client_name=%127s Allow=";
+static char use_device[] = "use device=%s media_type=%s pool_name=%s pool_type=%s\n";
+
+/* Responses sent to Director daemon */
+static char OKjob[]     = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
+static char OK_device[] = "3000 OK use device\n";
+static char NO_device[] = "3904 Device not available\n";
+static char BAD_use[]   = "3903 Bad use command\n";
+static char BAD_job[]   = "3905 Bad Job command\n";
+
+
+
+/*
+ * Director requests us to start a job
+ * Basic tasks done here:
+ *  - We pickup the JobId to be run from the Director.
+ *  - We pickup the device, media, and pool from the Director
+ *  - Wait for a connection from the File Daemon (FD)
+ *  - Accept commands from the FD (i.e. run the job)
+ *  - Return when the connection is terminated or
+ *    there is an error.
+ */
+int job_cmd(JCR *jcr)
+{
+   int JobId, errstat;
+   char auth_key[100];
+   BSOCK *dir = jcr->dir_bsock;
+   char *job_name, *client_name, *job;
+   struct timeval tv;
+   struct timezone tz;
+   struct timespec timeout;
+
+   /*
+    * Get JobId and permissions from Director
+    */
+
+   Dmsg1(30, "Job_cmd: %s\n", dir->msg);
+   job = (char *) get_memory(dir->msglen);
+   job_name = (char *) get_memory(dir->msglen);
+   client_name = (char *)get_memory(dir->msglen);
+   if (sscanf(dir->msg, jobcmd, &JobId, job, job_name, client_name) != 4) {
+      bnet_fsend(dir, BAD_job);
+      Emsg1(M_FATAL, 0, _("Bad Job Command from Director: %s\n"), dir->msg);
+      free_memory(job);
+      free_memory(job_name);
+      free_memory(client_name);
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+   jcr->JobId = JobId;
+   jcr->VolSessionId = newVolSessionId();
+   jcr->VolSessionTime = VolSessionTime;
+   strcpy(jcr->Job, job);
+   unbash_spaces(job_name);
+   jcr->job_name = (char *) get_memory(strlen(job_name) + 1);
+   strcpy(jcr->job_name, job_name);
+   unbash_spaces(client_name);
+   jcr->client_name = bstrdup(client_name);
+   free_memory(job);
+   free_memory(job_name);
+   free_memory(client_name);
+
+   /* Initialize FD start condition variable */
+   if ((errstat = pthread_cond_init(&jcr->job_start_wait, NULL)) != 0) {
+      Emsg1(M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat));
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+   jcr->authenticated = FALSE;
+
+   /*
+    * Pass back an authorization key for the File daemon
+    */
+   gettimeofday(&tv, &tz);
+   srandom(tv.tv_usec + tv.tv_sec);
+   sprintf(auth_key, "%ld", (long)random());
+   bnet_fsend(dir, OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
+   Dmsg1(10, ">dird: %s", dir->msg);
+   jcr->sd_auth_key = bstrdup(auth_key);
+
+   /*
+    * Wait for the device, media, and pool information
+    */
+   if (!use_device_cmd(jcr)) {
+      jcr->JobStatus = JS_ErrorTerminated;
+      return 0;
+   }
+
+   jcr->JobStatus = JS_WaitFD;       /* wait for FD to connect */
+   dir_send_job_status(jcr);
+
+   gettimeofday(&tv, &tz);
+   timeout.tv_nsec = tv.tv_usec * 1000; 
+   timeout.tv_sec = tv.tv_sec + 30 * 60;       /* wait 30 minutes */
+
+
+   Dmsg1(200, "%s waiting on job_start_wait\n", jcr->Job);
+   P(jcr->mutex);
+   for ( ;!job_cancelled(jcr); ) {
+      errstat = pthread_cond_timedwait(&jcr->job_start_wait, &jcr->mutex, &timeout);
+      if (errstat == 0 || errstat == ETIMEDOUT) {
+        break;
+      }
+   }
+   V(jcr->mutex);
+
+   if (jcr->authenticated && !job_cancelled(jcr)) {
+      run_job(jcr);                  /* Run the job */
+   }
+   return 0;
+}
+
+/*
+ * This entry point is only called if we have a separate
+ *   Storage Daemon Data port. Otherwise, the connection
+ *   is made to the main port, and if it is a File daemon
+ *   calling, handl_filed_connection() is called directly.
+ */
+void connection_from_filed(void *arg)
+{
+   BSOCK *fd = (BSOCK *)arg;
+   char job_name[MAX_NAME_LENGTH];
+
+   Dmsg0(200, "enter connection_from_filed\n");
+   if (bnet_recv(fd) <= 0) {
+      Emsg0(M_ERROR, 0, "Unable to authenticate Client.\n");
+      return;
+   }
+   Dmsg1(100, "got: %s\n", fd->msg);
+
+   if (sscanf(fd->msg, "Hello Start Job %127s\n", job_name) != 1) {
+      Emsg1(M_ERROR, 0, _("Authentication failure: %s"), fd->msg);
+      return;
+   }
+   handle_filed_connection(fd, job_name);
+   return;
+}
+
+void handle_filed_connection(BSOCK *fd, char *job_name)
+{
+   JCR *jcr;
+
+   if (!(jcr=get_jcr_by_full_name(job_name))) {
+      Emsg1(M_ERROR, 0, "Job name not found: %s", job_name);
+      return;
+   }
+
+   jcr->file_bsock = fd;
+
+   Dmsg1(100, "Found Job %s\n", job_name);
+
+   if (jcr->authenticated) {
+      Dmsg2(000, "Hey!!!! JobId %d Job %s already authenticated.\n", 
+        jcr->JobId, jcr->Job);
+   }
+  
+   /*
+    * Authenticate the File daemon
+    */
+   if (jcr->authenticated || !authenticate_filed(jcr)) {
+      Dmsg1(100, "Authentication failed Job %s\n", jcr->Job);
+      Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
+   } else {
+      jcr->authenticated = TRUE;
+      Dmsg1(100, "OK Authentication Job %s\n", jcr->Job);
+   }
+
+   P(jcr->mutex);
+   if (!jcr->authenticated) {
+      jcr->JobStatus = JS_ErrorTerminated;
+   }
+   pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
+   V(jcr->mutex);
+   free_jcr(jcr);
+   return;
+}
+
+
+/*  
+ *   Use Device command from Director
+ *   He tells is what Device Name to use, the Media Type, 
+ *     the Pool Name, and the Pool Type.
+ *
+ *    Ensure that the device exists and is opened, then store
+ *     the media and pool info in the JCR.
+ */
+static int use_device_cmd(JCR *jcr)
+{
+   char *dev_name, *media_type, *pool_name, *pool_type;
+   BSOCK *dir = jcr->dir_bsock;
+   DEVRES *device;
+
+   if (bnet_recv(dir) <= 0) {
+      Emsg0(M_FATAL, 0, "No Device from Director\n");
+      return 0;
+   }
+   
+   Dmsg1(20, "Use device: %s", dir->msg);
+   dev_name = (char *) get_memory(dir->msglen);
+   media_type = (char *) get_memory(dir->msglen);
+   pool_name = (char *) get_memory(dir->msglen);
+   pool_type = (char *) get_memory(dir->msglen);
+   if (sscanf(dir->msg, use_device, dev_name, media_type, pool_name, pool_type) == 4) {
+      unbash_spaces(dev_name);
+      unbash_spaces(media_type);
+      unbash_spaces(pool_name);
+      unbash_spaces(pool_type);
+      device = NULL;
+      LockRes();
+      while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
+        /* Find resource, and make sure we were able to open it */
+        if (strcmp(device->hdr.name, dev_name) == 0 && device->dev) {
+            Dmsg1(20, "Found device %s\n", device->hdr.name);
+           jcr->pool_name = (char *) get_memory(strlen(pool_name) + 1);
+           strcpy(jcr->pool_name, pool_name);
+           jcr->pool_type = (char *) get_memory(strlen(pool_type) + 1);
+           strcpy(jcr->pool_type, pool_type);
+           jcr->media_type = (char *) get_memory(strlen(media_type) + 1);
+           strcpy(jcr->media_type, media_type);
+           jcr->dev_name = (char *) get_memory(strlen(dev_name) + 1);
+           strcpy(jcr->dev_name, dev_name);
+           jcr->device = device;
+           Dmsg4(20, use_device, dev_name, media_type, pool_name, pool_type);
+           free_memory(dev_name);
+           free_memory(media_type);
+           free_memory(pool_name);
+           free_memory(pool_type);
+           UnlockRes();
+           return bnet_fsend(dir, OK_device);
+        }
+      }
+      UnlockRes();
+      Jmsg(jcr, M_FATAL, 0, _("Requested device %s not found. Cannot continue.\n"),
+          dev_name);
+      bnet_fsend(dir, NO_device);
+   } else {
+      Emsg1(M_FATAL, 0, _("store<dir: Bad Use Device command: %s\n"), dir->msg);
+      bnet_fsend(dir, BAD_use);
+   }
+
+   free_memory(dev_name);
+   free_memory(media_type);
+   free_memory(pool_name);
+   free_memory(pool_type);
+   return 0;                         /* ERROR return */
+}
+
+/* 
+ * Destroy the Job Control Record and associated
+ * resources (sockets).
+ */
+void stored_free_jcr(JCR *jcr) 
+{
+   if (jcr->file_bsock) {
+      bnet_close(jcr->file_bsock);
+   }
+   if (jcr->pool_name) {
+      free_memory(jcr->pool_name);
+   }
+   if (jcr->pool_type) {
+      free_memory(jcr->pool_type);
+   }
+   if (jcr->media_type) {
+      free_memory(jcr->media_type);
+   }
+   if (jcr->dev_name) {
+      free_memory(jcr->dev_name);
+   }
+   if (jcr->job_name) {
+      free_pool_memory(jcr->job_name);
+   }
+   return;
+}
diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c
new file mode 100644 (file)
index 0000000..45e22a9
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ *
+ *  label.c  Bacula routines to handle labels 
+ *
+ *   Kern Sibbald, MM
+ *                           
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"                   /* pull in global headers */
+#include "stored.h"                   /* pull in Storage Deamon headers */
+
+/* Forward referenced functions */
+static int create_volume_label(DEVICE *dev, char *VolName);
+static void create_volume_label_record(JCR *jcr, DEVICE *dev, DEV_RECORD *rec);
+
+extern char my_name[];
+extern int debug_level;
+
+char BaculaId[] =  "Bacula 0.9 mortal\n";
+unsigned int BaculaTapeVersion = 9;
+
+
+/*
+ * Read the volume label
+ *
+ *  If jcr->VolumeName == NULL, we accept any Bacula Volume
+ *  If jcr->VolumeName[0] == 0, we accept any Bacula Volume
+ *  otherwise jcr->VolumeName must match the Volume.
+ *
+ *  If VolName given, ensure that it matches   
+ *
+ *  Returns VOL_  code as defined in record.h
+ *    VOL_NOT_READ
+ *    VOL_OK
+ *    VOL_NO_LABEL
+ *    VOL_IO_ERROR
+ *    VOL_NAME_ERROR
+ *    VOL_CREATE_ERROR
+ *    VOL_VERSION_ERROR
+ *    VOL_LABEL_ERROR
+ */  
+int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   char *VolName = jcr->VolumeName;
+   DEV_RECORD *record;
+
+   Dmsg2(30, "Enter read_volume_label device=%s vol=%s\n", 
+      dev_name(dev), VolName);
+
+   if (dev->state & ST_LABEL) {       /* did we already read label? */
+      /* Compare Volume Names */
+      if (VolName && *VolName && strcmp(dev->VolHdr.VolName, VolName) != 0) {
+         Mmsg(&jcr->errmsg, _("Volume name mismatch on device %s: Wanted %s got %s\n"),
+           dev_name(dev), VolName, dev->VolHdr.VolName);
+
+        return jcr->label_status = VOL_NAME_ERROR;
+      }
+      Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
+      return jcr->label_status = VOL_OK;       /* label already read */
+   }
+
+   dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ);  /* set no label, no append */
+
+   if (!rewind_dev(dev)) {
+      Mmsg(&jcr->errmsg, _("Couldn't rewind device %s ERR=%s\n"), dev_name(dev),
+        strerror_dev(dev));
+      return jcr->label_status = VOL_IO_ERROR;
+   }
+   strcpy(dev->VolHdr.Id, "**error**");
+
+   /* Read the device label block */
+   record = new_record();
+   Dmsg0(90, "Big if statement in read_volume_label\n");
+   if (!read_block_from_dev(dev, block) || 
+       !read_record_from_block(block, record) ||
+       !unser_volume_label(dev, record) || 
+       strcmp(dev->VolHdr.Id, BaculaId) != 0) {
+
+      Mmsg(&jcr->errmsg, _("Volume on %s is not a Bacula labeled Volume, \
+because:\n   %s"), dev_name(dev), strerror_dev(dev));
+      free_record(record);
+      empty_block(block);
+      rewind_dev(dev);
+      return jcr->label_status = VOL_NO_LABEL;
+   }
+
+   free_record(record);
+   empty_block(block);
+   rewind_dev(dev);
+
+   if (dev->VolHdr.VerNum != BaculaTapeVersion) {
+      Mmsg(&jcr->errmsg, _("Volume on %s has wrong Bacula version. Wanted %d got %d\n"),
+        dev_name(dev), BaculaTapeVersion, dev->VolHdr.VerNum);
+      return jcr->label_status = VOL_VERSION_ERROR;
+   }
+
+   /* Compare Volume Names */
+   Dmsg2(30, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolName);
+   if (VolName && *VolName && strcmp(dev->VolHdr.VolName, VolName) != 0) {
+      Mmsg(&jcr->errmsg, _("Volume name mismatch. Wanted %s got %s\n"),
+        VolName, dev->VolHdr.VolName);
+      return jcr->label_status = VOL_NAME_ERROR;
+   }
+   Dmsg1(30, "Copy vol_name=%s\n", dev->VolHdr.VolName);
+
+   /* We are looking for either an unused Bacula tape (PRE_LABEL) or
+    * a Bacula volume label (VOL_LABEL)
+    */
+   if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) {
+      Mmsg(&jcr->errmsg, _("Volume on %s has bad Bacula label type: %x\n"), 
+         dev_name(dev), dev->VolHdr.LabelType);
+      return jcr->label_status = VOL_LABEL_ERROR;
+   }
+
+   dev->state |= ST_LABEL;           /* set has Bacula label */
+   if (debug_level >= 10) {
+      dump_volume_label(dev);
+   }
+   Dmsg0(30, "Leave read_volume_label() VOL_OK\n");
+   return jcr->label_status = VOL_OK;
+}
+
+/*  unser_volume_label 
+ *  
+ * Unserialize the Volume label into the device Volume_Label
+ * structure.
+ *
+ * Assumes that the record is already read.
+ *
+ * Returns: 0 on error
+ *         1 on success
+*/
+
+int unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
+{
+   ser_declare;
+
+   if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
+      Mmsg3(&dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"), 
+             FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream), 
+             rec->data_len);
+      return 0;
+   }
+
+   dev->VolHdr.LabelType = rec->FileIndex;
+   dev->VolHdr.LabelSize = rec->data_len;
+
+
+  /* Unserialize the record into the Volume Header */
+  ser_begin(rec->data, SER_LENGTH_Volume_Label);
+#define Fld(x) (dev->VolHdr.x)
+   unser_string(Fld(Id));
+
+   unser_uint32(Fld(VerNum));
+
+   unser_float64(Fld(label_date));
+   unser_float64(Fld(label_time));
+   unser_float64(Fld(write_date));
+   unser_float64(Fld(write_time));
+
+   unser_string(Fld(VolName));
+   unser_string(Fld(PrevVolName));
+   unser_string(Fld(PoolName));
+   unser_string(Fld(PoolType));
+   unser_string(Fld(MediaType));
+
+   unser_string(Fld(HostName));
+   unser_string(Fld(LabelProg));
+   unser_string(Fld(ProgVersion));
+   unser_string(Fld(ProgDate));
+
+   ser_end(rec->data, SER_LENGTH_Volume_Label);
+#undef Fld
+   Dmsg0(90, "ser_read_vol\n");
+   if (debug_level >= 90) {
+      dump_volume_label(dev);     
+   }
+   return 1;
+}
+
+/*
+ * Put a volume label into the block
+ *
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   DEV_RECORD rec;
+
+   Dmsg0(20, "write Label in write_volume_label_to_block()\n");
+   memset(&rec, 0, sizeof(rec));
+   rec.data = (char *) get_memory(SER_LENGTH_Volume_Label);
+
+   create_volume_label_record(jcr, dev, &rec);
+
+   empty_block(block);               /* Volume label always at beginning */
+   if (!write_record_to_block(block, &rec)) {
+      free_pool_memory(rec.data);
+      Emsg1(M_ERROR, 0, _("Cannot write Volume label to block for device %s\n"),
+        dev_name(dev));
+      return 0;
+   } else {
+      Dmsg1(90, "Wrote label of %d bytes to block\n", rec.data_len);
+   }
+   free_pool_memory(rec.data);
+   return 1;
+}
+
+/* 
+ *  create_volume_label_record
+ *   Serialize label (from dev->VolHdr structure) into device record.
+ *   Assumes that the dev->VolHdr structure is properly 
+ *   initialized.
+*/
+static void create_volume_label_record(JCR *jcr, DEVICE *dev, DEV_RECORD *rec)
+{
+   ser_declare;
+   struct date_time dt;
+
+   /* Serialize the label into the device record. */
+
+   ser_begin(rec->data, SER_LENGTH_Volume_Label);
+#define Fld(x) (dev->VolHdr.x)
+   ser_string(Fld(Id));
+
+   ser_uint32(Fld(VerNum));
+
+   ser_float64(Fld(label_date));
+   ser_float64(Fld(label_time));
+
+   get_current_time(&dt);
+   Fld(write_date) = dt.julian_day_number;
+   Fld(write_time) = dt.julian_day_fraction;
+
+   ser_float64(Fld(write_date));
+   ser_float64(Fld(write_time));
+
+   ser_string(Fld(VolName));
+   ser_string(Fld(PrevVolName));
+   ser_string(Fld(PoolName));
+   ser_string(Fld(PoolType));
+   ser_string(Fld(MediaType));
+
+   ser_string(Fld(HostName));
+   ser_string(Fld(LabelProg));
+   ser_string(Fld(ProgVersion));
+   ser_string(Fld(ProgDate));
+
+   ser_end(rec->data, SER_LENGTH_Volume_Label);
+   rec->data_len = ser_length(rec->data);
+   rec->FileIndex = Fld(LabelType);
+   rec->VolSessionId = jcr->VolSessionId;
+   rec->VolSessionTime = jcr->VolSessionTime;
+   rec->Stream = jcr->NumVolumes;
+   Dmsg2(100, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(rec->FileIndex),
+      rec->data_len);
+#undef Fld
+}     
+
+
+/*
+ * Create a volume label in memory
+ *  Returns: 0 on error
+ *          1 on success
+ */
+static int create_volume_label(DEVICE *dev, char *VolName)
+{
+   struct date_time dt;
+   DEVRES *device = (DEVRES *)dev->device;
+
+   Dmsg0(90, "Start create_volume_label()\n");
+
+   ASSERT(dev != NULL);
+
+   memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
+
+   /* ***FIXME*** we really need to get the volume name,    
+    * pool name, and pool type from the database.
+    * We also need to pickup the MediaType.
+    */
+   strcpy(dev->VolHdr.Id, BaculaId);
+   dev->VolHdr.VerNum = BaculaTapeVersion;
+   dev->VolHdr.LabelType = PRE_LABEL;  /* Mark tape as unused */
+   strcpy(dev->VolHdr.VolName, VolName);
+   strcpy(dev->VolHdr.PoolName, "Default");
+   strcpy(dev->VolHdr.MediaType, device->media_type);
+   strcpy(dev->VolHdr.PoolType, "Backup");
+
+   /* Put label time/date in header */
+   get_current_time(&dt);
+   dev->VolHdr.label_date = dt.julian_day_number;
+   dev->VolHdr.label_time = dt.julian_day_fraction;
+
+   strcpy(dev->VolHdr.LabelProg, my_name);
+   sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, DATE);
+   sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
+   dev->state |= ST_LABEL;           /* set has Bacula label */
+   if (debug_level >= 90) {
+      dump_volume_label(dev);
+   }
+   return 1;
+}
+
+/*
+ * Write a Volume Label
+ *  !!! Note, this is ONLY used for writing
+ *           a fresh volume label.  Any data
+ *           after the label will be destroyed,
+ *           in fact, we write the label 5 times !!!!
+ * 
+ *  This routine expects that open_device() was previously called.
+ *
+ *  This routine should be used only when labeling a blank tape.
+ */
+int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName)
+{
+   DEVICE *dev = device->dev;
+   DEV_RECORD rec;   
+   DEV_BLOCK *block;
+   int stat = 1;
+
+
+   Dmsg0(99, "write_volume_label()\n");
+   if (!create_volume_label(dev, VolName)) {
+      return 0;
+   }
+   strcpy(dev->VolHdr.MediaType, device->media_type);
+   strcpy(dev->VolHdr.VolName, VolName);
+   strcpy(dev->VolHdr.PoolName, PoolName);
+
+   if (!rewind_dev(dev)) {
+      Dmsg2(30, "Bad status on %s from rewind. ERR=%s\n", dev_name(dev), strerror_dev(dev));
+      return 0;
+   }
+
+   block = new_block(dev);
+   memset(&rec, 0, sizeof(rec));
+   rec.data = (char *) get_memory(SER_LENGTH_Volume_Label);
+   create_volume_label_record(jcr, dev, &rec);
+   rec.Stream = 0;
+
+   if (!write_record_to_block(block, &rec)) {
+      Dmsg2(30, "Bad Label write on %s. ERR=%s\n", dev_name(dev), strerror_dev(dev));
+      free_block(block);
+      free_pool_memory(rec.data);
+      return 0;
+   } else {
+      Dmsg2(30, "Wrote label of %d bytes to %s\n", rec.data_len, dev_name(dev));
+   }
+   free_pool_memory(rec.data);
+      
+   Dmsg0(99, "Call write_block_to_device()\n");
+   if (!write_block_to_dev(dev, block)) {
+      Dmsg2(30, "Bad Label write on %s. ERR=%s\n", dev_name(dev), strerror_dev(dev));
+      stat = 9;
+   }
+   Dmsg0(99, " Wrote block to device\n");
+     
+   flush_dev(dev);
+   weof_dev(dev, 1);
+   dev->state |= ST_LABEL;
+
+   if (debug_level >= 00)  {
+      dump_volume_label(dev);
+   }
+   free_block(block);
+   return stat;
+}     
+
+
+/*
+ * Create session label
+ *  The pool memory must be released by the calling program
+ */
+void create_session_label(JCR *jcr, DEV_RECORD *rec, int label)
+{
+   ser_declare;
+   struct date_time dt;
+
+   rec->sync          = 1;         /* wait for completion */
+   rec->VolSessionId   = jcr->VolSessionId;
+   rec->VolSessionTime = jcr->VolSessionTime;
+   rec->Stream        = jcr->JobId;
+
+   ser_begin(rec->data, SER_LENGTH_Session_Label);
+   ser_string(BaculaId);
+   ser_uint32(BaculaTapeVersion);
+
+   ser_uint32(jcr->JobId);
+
+   get_current_time(&dt);
+   ser_float64(dt.julian_day_number);
+   ser_float64(dt.julian_day_fraction);
+
+   ser_string(jcr->pool_name);
+   ser_string(jcr->pool_type);
+   ser_string(jcr->job_name);
+   ser_string(jcr->client_name);
+   if (label == EOS_LABEL) {
+      ser_uint32(jcr->JobFiles);
+      ser_uint64(jcr->JobBytes);
+      ser_uint32(jcr->start_block);
+      ser_uint32(jcr->end_block);
+      ser_uint32(jcr->start_file);
+      ser_uint32(jcr->end_file);
+      ser_uint32(jcr->JobErrors);
+   }
+   ser_end(rec->data, SER_LENGTH_Session_Label);
+   rec->data_len = ser_length(rec->data);
+}
+
+/* Write session label
+ *  Returns: 0 on failure
+ *          1 on success 
+ */
+int write_session_label(JCR *jcr, DEV_BLOCK *block, int label)
+{
+   DEVICE *dev = jcr->device->dev;
+   DEV_RECORD *rec;
+
+   rec = new_record();
+   Dmsg1(90, "session_label record=%x\n", rec);
+   switch (label) {
+      case SOS_LABEL:
+        jcr->start_block = dev->block_num;
+        jcr->start_file  = dev->file;
+        break;
+      case EOS_LABEL:
+        jcr->end_block = dev->block_num;
+        jcr->end_file = dev->file;
+        break;
+      default:
+         Emsg1(M_ABORT, 0, _("Bad session label = %d\n"), label);
+        break;
+   }
+   create_session_label(jcr, rec, label);
+   rec->FileIndex = label;
+
+   if (!write_record_device(jcr, dev, block, rec)) {
+      Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"), 
+                       dev_vol_name(dev), strerror(errno));
+      free_record(rec);
+      return 0;
+   }
+
+   Dmsg1(90, "session_label record=%x\n", rec);
+   Dmsg5(90, "sesson_label record FI=%s SessId=%d Strm=%s len=%d\n\
+remainder=%d\n",
+      FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
+      stream_to_ascii(rec->Stream), rec->data_len,
+      rec->remainder);
+
+   free_record(rec);
+   Dmsg2(20, "Leave write_session_label Block=%d File=%d\n", 
+      dev->block_num, dev->file);
+   return 1;
+}
+
+void dump_volume_label(DEVICE *dev)
+{
+   int dbl;
+   uint32_t File;
+   char *LabelType, buf[30];
+   struct tm tm;
+   struct date_time dt;
+
+   File = dev->file;
+   switch (dev->VolHdr.LabelType) {
+      case PRE_LABEL:
+         LabelType = "PRE_LABEL";
+        break;
+      case VOL_LABEL:
+         LabelType = "VOL_LABEL";
+        break;
+      case EOM_LABEL:
+         LabelType = "EOM_LABEL";
+        break;
+      case SOS_LABEL:
+         LabelType = "SOS_LABEL";
+        break;
+      case EOS_LABEL:
+         LabelType = "EOS_LABEL";
+        break;
+      default:
+        LabelType = buf;
+         sprintf(buf, "Unknown %d", dev->VolHdr.LabelType);
+        break;
+   }
+             
+   
+   dbl = debug_level;
+   debug_level = 1;
+   Dmsg11(-1, "\nVolume Label:\n\
+Id                : %s\
+VerNo             : %d\n\
+VolName           : %s\n\
+PrevVolName       : %s\n\
+VolFile           : %d\n\
+LabelType         : %s\n\
+LabelSize         : %d\n\
+PoolName          : %s\n\
+MediaType         : %s\n\
+PoolType          : %s\n\
+HostName          : %s\n\
+",
+            dev->VolHdr.Id, dev->VolHdr.VerNum,
+            dev->VolHdr.VolName, dev->VolHdr.PrevVolName,
+            File, LabelType, dev->VolHdr.LabelSize, 
+            dev->VolHdr.PoolName, dev->VolHdr.MediaType, 
+            dev->VolHdr.PoolType, dev->VolHdr.HostName);
+
+   dt.julian_day_number   = dev->VolHdr.label_date;
+   dt.julian_day_fraction = dev->VolHdr.label_time;
+   tm_decode(&dt, &tm);
+   Dmsg5(-1, "\
+Date label written: %04d-%02d-%02d at %02d:%02d\n", 
+      tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
+   debug_level = dbl;
+}
+
+int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec) 
+{
+   ser_declare;
+
+   unser_begin(rec->data, SER_LENGTH_Session_Label);
+   unser_string(label->Id);
+   unser_uint32(label->VerNum);
+   unser_uint32(label->JobId);
+   unser_float64(label->write_date);
+   unser_float64(label->write_time);
+   unser_string(label->PoolName);
+   unser_string(label->PoolType);
+   unser_string(label->JobName);
+   unser_string(label->ClientName);
+   if (rec->FileIndex == EOS_LABEL) {
+      unser_uint32(label->JobFiles);
+      unser_uint64(label->JobBytes);
+      unser_uint32(label->start_block);
+      unser_uint32(label->end_block);
+      unser_uint32(label->start_file);
+      unser_uint32(label->end_file);
+      unser_uint32(label->JobErrors);
+   }     
+   return 1;
+}
+
+
+static void dump_session_label(DEV_RECORD *rec, char *type)
+{
+   int dbl;
+   struct date_time dt;
+   struct tm tm;
+   SESSION_LABEL label;
+   char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], ec6[30], ec7[30];
+
+
+   unser_session_label(&label, rec);
+   dbl = debug_level;
+   debug_level = 1;
+   Dmsg6(-1, "\n%s Record:\n\
+JobId             : %d\n\
+PoolName          : %s\n\
+PoolType          : %s\n\
+JobName           : %s\n\
+ClientName        : %s\n\
+",    type, 
+      label.JobId, label.PoolName, label.PoolType,
+      label.JobName, label.ClientName);
+
+   if (rec->FileIndex == EOS_LABEL) {
+      Dmsg7(-1, "\
+JobFiles          : %s\n\
+JobBytes          : %s\n\
+StartBlock        : %s\n\
+EndBlock          : %s\n\
+StartFile         : %s\n\
+EndFile           : %s\n\
+JobErrors         : %s\n\
+",
+        edit_uint_with_commas(label.JobFiles, ec1),
+        edit_uint_with_commas(label.JobBytes, ec2),
+        edit_uint_with_commas(label.start_block, ec3),
+        edit_uint_with_commas(label.end_block, ec4),
+        edit_uint_with_commas(label.start_file, ec5),
+        edit_uint_with_commas(label.end_file, ec6),
+        edit_uint_with_commas(label.JobErrors, ec7));
+   }
+   dt.julian_day_number   = label.write_date;
+   dt.julian_day_fraction = label.write_time;
+   tm_decode(&dt, &tm);
+   Dmsg5(-1, "\
+Date written      : %04d-%02d-%02d at %02d:%02d\n", 
+      tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
+
+   debug_level = dbl;
+}
+
+void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose)
+{
+   char *type;
+   int dbl;
+
+   dbl = debug_level;
+   debug_level = 1;
+   switch (rec->FileIndex) {
+      case PRE_LABEL:
+         type = "Fresh Volume";   
+        break;
+      case VOL_LABEL:
+         type = "Volume";
+        break;
+      case SOS_LABEL:
+         type = "Begin Session";
+        break;
+      case EOS_LABEL:
+         type = "End Session";
+        break;
+      case EOM_LABEL:
+         type = "End of Media";
+        break;
+      default:
+         type = "Unknown";
+        break;
+   }
+   if (verbose) {
+      switch (rec->FileIndex) {
+        case PRE_LABEL:
+        case VOL_LABEL:
+           unser_volume_label(dev, rec);
+           dump_volume_label(dev);
+           break;
+        case SOS_LABEL:
+           dump_session_label(rec, type);
+           break;
+        case EOS_LABEL:
+           dump_session_label(rec, type);
+           break;
+        case EOM_LABEL:
+            Dmsg5(-1, "%s Record: VSessId=%d VSessTime=%d JobId=%d DataLen=%d\n",
+              type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
+           break;
+        default:
+            Dmsg5(-1, "%s Record: VSessId=%d VSessTime=%d JobId=%d DataLen=%d\n",
+              type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
+           break;
+      }
+   } else {
+      Dmsg5(-1, "%s Record: VSessId=%d VSessTime=%d JobId=%d DataLen=%d\n",
+        type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
+   }
+   debug_level = dbl;
+}
diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h
new file mode 100644 (file)
index 0000000..f76b898
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Protypes for stored
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+   
+/* From stored.c */
+uint32_t new_VolSessionId();
+
+/* From askdir.c */
+int    dir_get_volume_info(JCR *jcr);
+int    dir_find_next_appendable_volume(JCR *jcr);
+int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol);
+int    dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev);
+int    dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev);
+int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec);
+int    dir_send_job_status(JCR *jcr);
+
+/* authenticate.c */
+int    authenticate_director(JCR *jcr);
+int    authenticate_filed(JCR *jcr);
+
+/* From block.c */
+void   dump_block(DEV_BLOCK *b, char *msg);
+DEV_BLOCK *new_block(DEVICE *dev);
+void   init_block_write(DEV_BLOCK *block);
+void   empty_block(DEV_BLOCK *block);
+void   free_block(DEV_BLOCK *block);
+int    write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int    write_block_to_dev(DEVICE *dev, DEV_BLOCK *block);
+int    read_block_from_device(DEVICE *dev, DEV_BLOCK *block);
+int    read_block_from_dev(DEVICE *dev, DEV_BLOCK *block);
+
+
+/* From dev.c */
+DEVICE *init_dev(DEVICE *dev, char *device);
+int     open_dev(DEVICE *dev, char *VolName, int mode);
+void    close_dev(DEVICE *dev);
+void    force_close_dev(DEVICE *dev);
+void    term_dev(DEVICE *dev);
+char *  strerror_dev(DEVICE *dev);
+void    clrerror_dev(DEVICE *dev, int func);
+int     update_pos_dev(DEVICE *dev);
+int     rewind_dev(DEVICE *dev);
+int     load_dev(DEVICE *dev);
+int     offline_dev(DEVICE *dev);
+int     flush_dev(DEVICE *dev);
+int     weof_dev(DEVICE *dev, int num);
+int     write_block(DEVICE *dev);
+int     write_dev(DEVICE *dev, char *buf, size_t len);
+int     read_dev(DEVICE *dev, char *buf, size_t len);
+int     status_dev(DEVICE *dev, uint32_t *status);
+int     eod_dev(DEVICE *dev);
+int     fsf_dev(DEVICE *dev, int num);
+int     fsr_dev(DEVICE *dev, int num);
+int     bsf_dev(DEVICE *dev, int num);
+int     bsr_dev(DEVICE *dev, int num);
+
+/* Get info about device */
+char *  dev_name(DEVICE *dev);
+char *  dev_vol_name(DEVICE *dev);
+uint32_t dev_block(DEVICE *dev);
+uint32_t dev_file(DEVICE *dev);
+int     dev_is_tape(DEVICE *dev);
+
+/* From device.c */
+int     open_device(DEVICE *dev);
+int     acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int     acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int     ready_dev_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int     release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void    block_device(DEVICE *dev, int state);
+void    unblock_device(DEVICE *dev);
+void    lock_device(DEVICE *dev);
+void    unlock_device(DEVICE *dev);
+int     fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+
+/* From dircmd.c */
+void    connection_request(void *arg); 
+
+
+/* From fd_cmds.c */
+void    run_job(JCR *jcr);
+
+/* From fdmsg.c */
+int     bget_msg(BSOCK *sock);
+
+/* From job.c */
+void    stored_free_jcr(JCR *jcr);
+void    connection_from_filed(void *arg);     
+void    handle_filed_connection(BSOCK *fd, char *job_name);
+
+/* From label.c */
+int     read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void    create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
+int     write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName);
+int     write_session_label(JCR *jcr, DEV_BLOCK *block, int label);
+int     write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void    dump_volume_label(DEVICE *dev);
+void    dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
+int     unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
+int     unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec);
+
+/* From record.c */
+char   *FI_to_ascii(int fi);
+char   *stream_to_ascii(int stream);
+int    write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int    read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); 
+DEV_RECORD *new_record();
+void   free_record(DEV_RECORD *rec);
+int    read_record(DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record);
+int    write_record_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record);
diff --git a/bacula/src/stored/read.c b/bacula/src/stored/read.c
new file mode 100644 (file)
index 0000000..8309a65
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Read code for Storage daemon
+ *     Kern Sibbald, November MM
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+/* Forward referenced subroutines */
+
+/* Variables used by Child process */
+/* Global statistics */
+/* Note, these probably should be in shared memory so that 
+ * they are truly global for all processes
+ */
+extern struct s_shm *shm;            /* shared memory structure */
+extern int  FiledDataChan;           /* File daemon data channel (port) */
+
+
+/* Responses sent to the File daemon */
+static char OK_data[]    = "3000 OK data\n";
+static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
+
+/* 
+ *  Read Data and send to File Daemon
+ *   Returns: 0 on failure
+ *           1 on success
+ */
+int do_read_data(JCR *jcr) 
+{
+   BSOCK *ds;
+   BSOCK *fd_sock = jcr->file_bsock;
+   int ok = TRUE;
+   DEVICE *dev;
+   DEV_RECORD rec;
+   DEV_BLOCK *block;
+   char *hdr, *p;
+
+   
+   Dmsg0(20, "Start read data.\n");
+
+   dev = jcr->device->dev;
+
+   /* Tell File daemon we will send data */
+   bnet_fsend(fd_sock, OK_data);
+   Dmsg1(10, "bstored>filed: %s\n", fd_sock->msg);
+
+   ds = fd_sock;
+
+   if (!bnet_set_buffer_size(ds, MAX_NETWORK_BUFFER_SIZE, BNET_SETBUF_READ)) {
+      return 0;
+   }
+
+
+   Dmsg1(20, "Begin read device=%s\n", dev_name(dev));
+
+   block = new_block(dev);
+
+   /* Find out if we were passed multiple volumes */
+   jcr->NumVolumes = 1;
+   jcr->CurVolume = 1;
+   /* Scan through VolumeNames terminating them and counting them */
+   for (p = jcr->VolumeName; p && *p; ) {
+      p = strchr(p, '|');             /* volume name separator */
+      if (p) {
+        *p++ = 0;                    /* Terminate name */
+        jcr->NumVolumes++;
+      }
+   }
+
+   Dmsg1(20, "Found %d volumes names to restore.\n", jcr->NumVolumes);
+
+   /* 
+    * Ready device for reading, and read records
+    */
+   if (!acquire_device_for_read(jcr, dev, block)) {
+      free_block(block);
+      return 0;
+   }
+
+   memset(&rec, 0, sizeof(rec));
+   rec.data = ds->msg;               /* use socket message buffer */
+   hdr = (char *) get_pool_memory(PM_MESSAGE);
+
+   /*
+    * ****FIXME**** enhance this to look for 
+    *              more things than just a session.
+    */
+   for ( ;ok; ) {
+      DEV_RECORD *record;            /* for reading label of multi-volumes */
+
+      if (job_cancelled(jcr)) {
+        ok = FALSE;
+        break;
+      }
+      /* Read Record */
+      Dmsg1(500, "Main read_record. rem=%d\n", rec.remainder);
+      if (!read_record(dev, block, &rec)) {
+         Dmsg1(500, "Main read record failed. rem=%d\n", rec.remainder);
+        if (dev->state & ST_EOT) {
+           if (rec.remainder) {
+               Dmsg0(500, "Not end of record.\n");
+           }
+            Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume);
+           if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) {
+              close_dev(dev);
+              for (p=jcr->VolumeName; *p++; ) /* skip to next volume name */
+                 { }
+              jcr->CurVolume++;
+               Dmsg1(20, "There is another volume %s.\n", p);
+              strcpy(jcr->VolumeName, p);
+              dev->state &= ~ST_READ; 
+              if (!acquire_device_for_read(jcr, dev, block)) {
+                  Emsg2(M_ERROR, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), p);
+                 ok = FALSE;
+                 break;
+              }
+              record = new_record();
+               Dmsg1(500, "read record after new tape. rem=%d\n", record->remainder);
+              read_record(dev, block, record); /* read vol label */
+              dump_label_record(dev, record, 0);
+              free_record(record);
+              continue;
+           }
+            Dmsg0(90, "End of Device reached.\n");
+           break;                    /* End of Tape */
+        }
+        if (dev->state & ST_EOF) {
+            Dmsg0(90, "Got End of File. Trying again ...\n");
+           continue;                 /* End of File */
+        }
+
+         Emsg2(M_ABORT, 0, "Read error on Record Header %s ERR=%s\n", dev_name(dev), strerror(errno));
+      }
+
+      /* Some sort of label? */ 
+      if (rec.FileIndex < 0) {
+         Dmsg1(40, "Got label = %d\n", rec.FileIndex);
+        if (rec.FileIndex == EOM_LABEL) { /* end of tape? */
+            Dmsg0(40, "Get EOM LABEL\n");
+           break;                         /* yes, get out */
+        }
+        continue;                         /* ignore other labels */
+      }
+
+      if (rec.VolSessionId != jcr->read_VolSessionId ||
+         rec.VolSessionTime != jcr->read_VolSessionTime) {
+         Dmsg0(50, "Ignore record ids not equal\n");
+        continue;                    /* ignore */
+      }
+       
+      /* Generate Header parameters and send to File daemon
+       * Note, we build header in hdr buffer to avoid wiping
+       * out the data record
+       */
+      ds->msg = hdr;
+      if (!bnet_fsend(ds, rec_header, rec.VolSessionId, rec.VolSessionTime,
+            rec.FileIndex, rec.Stream, rec.data_len)) {
+         Dmsg1(30, ">filed: Error Hdr=%s\n", ds->msg);
+        ds->msg = rec.data;
+        ok = FALSE;
+        break;
+      } else {
+         Dmsg1(30, ">filed: Hdr=%s\n", ds->msg);
+      }
+
+      ds->msg = rec.data;            /* restore data record address */
+
+      /* Send data record to File daemon */
+      ds->msglen = rec.data_len;
+      Dmsg1(40, ">filed: send %d bytes data.\n", ds->msglen);
+      if (!bnet_send(ds)) {
+         Dmsg0(0, "Error sending to FD\n");
+         Jmsg1(jcr, M_FATAL, 0, _("Error sending to File daemon. ERR=%s\n"),
+           bnet_strerror(ds));
+        ok = FALSE;
+      }
+   }
+   /* Send end of data to FD */
+   bnet_sig(ds, BNET_EOF);
+
+   if (!release_device(jcr, dev, block)) {
+      ok = FALSE;
+   }
+   free_pool_memory(hdr);
+   free_block(block);
+   Dmsg0(30, "Done reading.\n");
+   return ok ? 1 : 0;
+}
diff --git a/bacula/src/stored/record.c b/bacula/src/stored/record.c
new file mode 100644 (file)
index 0000000..2b021fb
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ *
+ *   record.c -- tape record handling functions
+ *
+ *             Kern Sibbald, April MMI
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#include "bacula.h"
+#include "stored.h"
+
+extern int debug_level;
+
+/*
+ * Convert a FileIndex into a printable
+ * ASCII string.  Not reentrant.
+ */
+char *FI_to_ascii(int fi)
+{
+   static char buf[20];
+   if (fi >= 0) {
+      sprintf(buf, "%d", fi);
+      return buf;
+   }
+   switch (fi) {
+   case PRE_LABEL:
+      return "PRE_LABEL";
+   case VOL_LABEL:
+      return "VOL_LABEL";
+   case EOM_LABEL:
+      return "EOM_LABEL";
+   case SOS_LABEL:
+      return "SOS_LABEL";
+   case EOS_LABEL:
+      return "EOS_LABEL";
+   default:
+     sprintf(buf, "unknown: %d", fi);
+     return buf;
+   }
+}
+
+
+/* 
+ * Convert a Stream ID into a printable
+ * ASCII string.  Not reentrant.
+ */
+char *stream_to_ascii(int stream)
+{
+    static char buf[20];
+    switch (stream) {
+    case STREAM_UNIX_ATTRIBUTES:
+       return "UATTR";
+    case STREAM_FILE_DATA:
+       return "DATA";
+    case STREAM_MD5_SIGNATURE:
+       return "MD5";
+    case STREAM_GZIP_DATA:
+       return "GZIP";
+    default:
+       sprintf(buf, "%d", stream);
+       return buf;     
+    }
+}
+
+/* 
+ * Return a new record entity
+ */
+DEV_RECORD *new_record(void)
+{
+   DEV_RECORD *rec;
+
+   rec = (DEV_RECORD *) get_memory(sizeof(DEV_RECORD));
+   memset(rec, 0, sizeof(DEV_RECORD));
+   rec->data = (char *) get_pool_memory(PM_MESSAGE);
+   return rec;
+}
+
+/*
+ * Free the record entity 
+ *
+ */
+void free_record(DEV_RECORD *rec) 
+{
+   Dmsg0(150, "Enter free_record.\n");
+   free_pool_memory(rec->data);
+   Dmsg0(150, "Data buf is freed.\n");
+   free_pool_memory(rec);
+   Dmsg0(150, "Leave free_record.\n");
+} 
+
+/*
+ * Read a record from a block
+ *   if necessary, read the block from the device without locking
+ *   if necessary, handle getting a new Volume
+ *
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int read_record(DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record)
+{
+   Dmsg2(90, "read_record() dev=%x state=%x\n", dev, dev->state);
+
+   while (!read_record_from_block(block, record)) {
+      Dmsg2(90, "!read_record_from_block data_len=%d rem=%d\n", record->data_len,
+               record->remainder);
+      if (!read_block_from_dev(dev, block)) {
+        /**** ****FIXME**** handle getting a new Volume */
+         Dmsg0(200, "===== Got read block I/O error ======\n");
+        return 0;
+      }
+   }
+   Dmsg4(90, "read_record FI=%s SessId=%d Strm=%s len=%d\n",
+             FI_to_ascii(record->FileIndex), record->VolSessionId, 
+             stream_to_ascii(record->Stream), record->data_len);
+   return 1;
+}
+
+
+/*
+ * Write a record to block 
+ *   if necessary, write the block to the device with locking
+ *   if necessary, handle getting a new Volume
+ *
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int write_record_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record)
+{
+   Dmsg2(190, "write_device() dev=%x state=%x\n", dev, dev->state);
+
+   while (!write_record_to_block(block, record)) {
+      Dmsg2(190, "!write_record data_len=%d rem=%d\n", record->data_len,
+                record->remainder);
+      if (!write_block_to_device(jcr, dev, block)) {
+         Dmsg0(90, "Got write_block_to_dev error.\n");
+        return 0;
+      }
+   }
+   Dmsg4(190, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
+      FI_to_ascii(record->FileIndex), record->VolSessionId, 
+      stream_to_ascii(record->Stream), record->data_len);
+   return 1;
+}
+
+/*
+ * Write a Record to the block
+ *
+ *  Returns: 0 on failure (none or partially written)
+ *          1 on success (all bytes written)
+ *
+ *  and remainder returned in packet.
+ *
+ *  We require enough room for the header, and we deal with
+ *  two special cases. 1. Only part of the record may have
+ *  been transferred the last time (when remainder is
+ *  non-zero), and 2. The remaining bytes to write may not
+ *  all fit into the block.
+ */
+int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
+{
+   ser_declare;
+   uint32_t remlen;
+
+   sm_check(__FILE__, __LINE__, False);
+   remlen = block->buf_len - block->binbuf;
+
+   ASSERT(block->binbuf == (uint32_t) (block->bufp - block->buf));
+   ASSERT(remlen >= 0);
+
+   Dmsg6(190, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n\
+rem=%d remainder=%d\n",
+      FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
+      stream_to_ascii(rec->Stream), rec->data_len,
+      remlen, rec->remainder);
+
+   if (rec->remainder == 0) {
+      /* Require enough room to write a full header */
+      if (remlen >= RECHDR_LENGTH) {
+        ser_begin(block->bufp, RECHDR_LENGTH);
+        ser_uint32(rec->VolSessionId);
+        ser_uint32(rec->VolSessionTime);
+        ser_int32(rec->FileIndex);
+        ser_int32(rec->Stream);
+        ser_uint32(rec->data_len);
+        ASSERT(ser_length(block->bufp) == RECHDR_LENGTH);
+
+        block->bufp += RECHDR_LENGTH;
+        block->binbuf += RECHDR_LENGTH;
+        remlen -= RECHDR_LENGTH;
+        rec->remainder = rec->data_len;
+      } else {
+        rec->remainder = rec->data_len + RECHDR_LENGTH;
+        sm_check(__FILE__, __LINE__, False);
+        return 0;
+      }
+   } else {
+      /* 
+       * We are here to write unwritten bytes from a previous
+       * time. Presumably we have a new buffer (possibly 
+       * containing a volume label), so the new header 
+       * should be able to fit in the block -- otherwise we have
+       * an error.  Note, we may have to continue splitting the
+       * data record though.
+       * 
+       *  First, write the header, then write as much as 
+       * possible of the data record.
+       */
+      ser_begin(block->bufp, RECHDR_LENGTH);
+      ser_uint32(rec->VolSessionId);
+      ser_uint32(rec->VolSessionTime);
+      ser_int32(rec->FileIndex);
+      if (rec->remainder > rec->data_len) {
+        ser_int32(rec->Stream);      /* normal full header */
+        ser_uint32(rec->data_len);
+        rec->remainder = rec->data_len; /* must still do data record */
+      } else {
+        ser_int32(-rec->Stream);     /* mark this as a continuation record */
+        ser_uint32(rec->remainder);  /* bytes to do */
+      }
+      ASSERT(ser_length(block->bufp) == RECHDR_LENGTH);
+
+      /* Require enough room to write a full header */
+      ASSERT(remlen >= RECHDR_LENGTH);
+
+      block->bufp += RECHDR_LENGTH;
+      block->binbuf += RECHDR_LENGTH;
+      remlen -= RECHDR_LENGTH;
+   }
+   if (remlen == 0) {
+      sm_check(__FILE__, __LINE__, False);
+      return 0;                      /* partial transfer */
+   }
+
+   /* Now deal with data record.
+    * Part of it may have already been transferred, and we 
+    * may not have enough room to transfer the whole this time.
+    */
+   if (rec->remainder > 0) {
+      /* Write as much of data as possible */
+      if (remlen >= rec->remainder) {
+        memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
+               rec->remainder);
+        block->bufp += rec->remainder;
+        block->binbuf += rec->remainder;
+      } else {
+        memcpy(block->bufp, rec->data+rec->data_len-rec->remainder, 
+               remlen);
+        if (!sm_check_rtn(__FILE__, __LINE__, False)) {
+           /* We damaged a buffer */
+            Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n\
+rem=%d remainder=%d\n",
+              FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
+              stream_to_ascii(rec->Stream), rec->data_len,
+              remlen, rec->remainder);
+            Dmsg5(0, "Damaged block: bufp=%x binbuf=%d buf_len=%d rem=%d moved=%d\n",
+              block->bufp, block->binbuf, block->buf_len, block->buf_len-block->binbuf,
+              remlen);
+            Dmsg2(0, "Damaged block: buf=%x binbuffrombuf=%d \n",
+              block->buf, block->bufp-block->buf);
+
+               Emsg0(M_ABORT, 0, "Damaged buffer\n");
+        }
+
+        block->bufp += remlen;
+        block->binbuf += remlen;
+        rec->remainder -= remlen;
+        return 0;                    /* did partial transfer */
+      }
+   }
+   rec->remainder = 0;               /* did whole transfer */
+   sm_check(__FILE__, __LINE__, False);
+   return 1;
+}
+
+
+/*
+ * Read a Record from the block
+ *  Returns: 0 on failure
+ *          1 on success
+ */
+int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec)
+{
+   ser_declare;
+   uint32_t data_bytes;
+   int32_t Stream;
+   uint32_t remlen;
+
+   remlen = block->binbuf;
+
+   /* 
+    * Get the header. There is always a full header,
+    * otherwise we find it in the next block.
+    */
+   if (remlen >= RECHDR_LENGTH) {
+      Dmsg3(90, "read_record_block: remlen=%d data_len=%d rem=%d\n", 
+           remlen, rec->data_len, rec->remainder);
+/*    memcpy(rec->ser_buf, block->bufp, RECHDR_LENGTH); */
+
+      unser_begin(block->bufp, RECHDR_LENGTH);
+      unser_uint32(rec->VolSessionId);
+      unser_uint32(rec->VolSessionTime);
+      unser_int32(rec->FileIndex);
+      unser_int32(Stream);
+      unser_uint32(data_bytes);
+
+      ASSERT(unser_length(block->bufp) == RECHDR_LENGTH);
+      block->bufp += RECHDR_LENGTH;
+      block->binbuf -= RECHDR_LENGTH;
+      remlen -= RECHDR_LENGTH;
+
+      if (Stream < 0) {              /* continuation record? */
+         Dmsg1(500, "Got negative Stream => continuation. remainder=%d\n", 
+           rec->remainder);
+        /* ****FIXME**** add code to verify that this
+         *  is the correct continuation of the previous
+         *  record.
+         */
+         if (!rec->remainder) {       /* if we didn't read previously */
+           rec->data_len = 0;        /* simply return data */
+        }
+        rec->Stream = -Stream;       /* set correct Stream */
+      } else {                       /* Regular record */
+        rec->Stream = Stream;
+        rec->data_len = 0;           /* transfer to beginning of data */
+      }
+      Dmsg6(90, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%d\n\
+remlen=%d data_len=%d\n",
+        FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
+        stream_to_ascii(rec->Stream), data_bytes, remlen, rec->data_len);
+   } else {
+      Dmsg0(90, "read_record_block: nothing\n");
+      if (!rec->remainder) {
+        rec->remainder = 1;          /* set to expect continuation */
+        rec->data_len = 0;           /* no data transferred */
+      }
+      return 0;
+   }
+
+   ASSERT(data_bytes < MAX_BLOCK_LENGTH);      /* temp sanity check */
+
+   rec->data = (char *) check_pool_memory_size(rec->data, rec->data_len+data_bytes);
+   
+   /*
+    * At this point, we have read the header, now we
+    * must transfer as much of the data record as 
+    * possible taking into account: 1. A partial
+    * data record may have previously been transferred,
+    * 2. The current block may not contain the whole data
+    * record.
+    */
+   if (remlen >= data_bytes) {
+      /* Got whole record */
+      memcpy(rec->data+rec->data_len, block->bufp, data_bytes);
+      block->bufp += data_bytes;
+      block->binbuf -= data_bytes;
+      rec->data_len += data_bytes;
+   } else {
+      /* Partial record */
+      memcpy(rec->data+rec->data_len, block->bufp, remlen);
+      block->bufp += remlen;
+      block->binbuf -= remlen;
+      rec->data_len += remlen;
+      rec->remainder = 1;            /* partial record transferred */
+      Dmsg1(90, "read_record_block: partial xfered=%d\n", rec->data_len);
+      return 0;
+   }
+   rec->remainder = 0;
+   Dmsg4(90, "Rtn full rd_rec_blk FI=%s SessId=%d Strm=%s len=%d\n",
+      FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
+      stream_to_ascii(rec->Stream), rec->data_len);
+   return 1;                         /* transferred full record */
+}
diff --git a/bacula/src/stored/record.h b/bacula/src/stored/record.h
new file mode 100644 (file)
index 0000000..6cf5c1f
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Record, and label definitions for Bacula
+ *  media data format.
+ *
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+
+#ifndef __RECORD_H
+#define __RECORD_H 1
+
+/* Return codes from read_device_volume_label() */
+#define VOL_NOT_READ      0               /* Volume label not read */
+#define VOL_OK            1               /* volume name OK */
+#define VOL_NO_LABEL      2               /* volume not labeled */
+#define VOL_IO_ERROR      3               /* volume I/O error */
+#define VOL_NAME_ERROR    4               /* Volume name mismatch */
+#define VOL_CREATE_ERROR  5               /* Error creating label */
+#define VOL_VERSION_ERROR 6               /* Bacula version error */
+#define VOL_LABEL_ERROR   7               /* Bad label type */
+
+
+/* Length of Record Header (5 * 4 bytes) */
+#define RECHDR_LENGTH 20
+
+/*
+ * This is the Media structure for a record header.
+ *  NB: when it is written it is serialized.
+ */
+typedef struct s_record_hdr {
+   uint32_t VolSessionId;
+   uint32_t VolSessionTime;
+   int32_t  FileIndex;
+   int32_t  Stream;
+   uint32_t data_len;
+} RECORD_HDR;
+
+/*
+ * DEV_RECORD for reading and writing records.
+ * It consists of a Record Header, and the Record Data
+ * 
+ *  This is the memory structure for the record header.
+ */
+typedef struct s_dev_rec {
+   int      sync;                     /* synchronous */
+   uint32_t File;                     /* File number, returned if sync set */
+   uint32_t Block;                    /* Block number, returned if sync set */
+   uint32_t VolSessionId;             /* sequential id within this session */
+   uint32_t VolSessionTime;           /* session start time */
+   int32_t  FileIndex;                /* sequential file number */
+   int32_t  Stream;                   /* stream number */
+   uint32_t data_len;                 /* current record length */
+   uint32_t remainder;                /* remaining bytes to read/write */
+   uint8_t  ser_buf[RECHDR_LENGTH];   /* serialized record header goes here */
+   char *data;                        /* Record data. This MUST be a memory pool item */
+} DEV_RECORD;
+
+
+/*
+ * Values for LabelType that are put into the FileIndex field
+ * Note, these values are negative to distinguish them
+ * from user records where the FileIndex is forced positive.
+ */
+#define PRE_LABEL   -1                /* Vol label on unwritten tape */
+#define VOL_LABEL   -2                /* Volume label first file */
+#define EOM_LABEL   -3                /* Writen at end of tape */        
+#define SOS_LABEL   -4                /* Start of Session */
+#define EOS_LABEL   -5                /* End of Session */
+
+/* 
+ *   Volume Label Record
+ */
+struct Volume_Label {
+  /*  
+   * The first items in this structure are saved
+   * in the DEVICE buffer, but are not actually written
+   * to the tape.
+   */
+  int32_t LabelType;                  /* This is written in header only */
+  uint32_t LabelSize;                 /* length of serialized label */
+  /*
+   * The items below this line are stored on 
+   * the tape
+   */
+  char Id[32];                        /* Bacula Immortal ... */
+
+  uint32_t VerNum;                    /* Label version number */
+
+  float64_t label_date;               /* Date tape labeled */
+  float64_t label_time;               /* Time tape labeled */
+  float64_t write_date;               /* Date this label written */
+  float64_t write_time;               /* Time this label written */
+
+  char VolName[MAX_NAME_LENGTH];      /* Volume name */
+  char PrevVolName[MAX_NAME_LENGTH];  /* Previous Volume Name */
+  char PoolName[MAX_NAME_LENGTH];     /* Pool name */
+  char PoolType[MAX_NAME_LENGTH];     /* Pool type */
+  char MediaType[MAX_NAME_LENGTH];    /* Type of this media */
+
+  char HostName[MAX_NAME_LENGTH];     /* Host name of writing computer */
+  char LabelProg[32];                 /* Label program name */
+  char ProgVersion[32];               /* Program version */
+  char ProgDate[32];                  /* Program build date/time */
+};
+
+#define SER_LENGTH_Volume_Label 1024   /* max serialised length of volume label */
+#define SER_LENGTH_Session_Label 1024  /* max serialised length of session label */
+
+typedef struct Volume_Label VOLUME_LABEL;
+
+/*
+ * Session Start/End Label
+ *  This record is at the beginning and end of each session
+ */
+struct Session_Label {
+  char Id[32];                        /* Bacula Immortal ... */
+
+  uint32_t VerNum;                    /* Label version number */
+
+  uint32_t JobId;                     /* Job id */
+  uint32_t VolumeIndex;               /* Sequence no of volume for this job */
+
+  float64_t write_date;               /* Date this label written */
+  float64_t write_time;               /* Time this label written */
+
+  char PoolName[MAX_NAME_LENGTH];     /* Pool name */
+  char PoolType[MAX_NAME_LENGTH];     /* Pool type */
+  char JobName[MAX_NAME_LENGTH];
+  char ClientName[MAX_NAME_LENGTH];
+  uint32_t JobFiles;
+  uint64_t JobBytes;
+  uint32_t start_block;
+  uint32_t end_block;
+  uint32_t start_file;
+  uint32_t end_file;
+  uint32_t JobErrors;
+
+};
+typedef struct Session_Label SESSION_LABEL;
+
+#define SERIAL_BUFSIZE  1024          /* volume serialisation buffer size */
+
+#endif
diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c
new file mode 100644 (file)
index 0000000..eabbd18
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Second generation Storage daemon.
+ *
+ * It accepts a number of simple commands from the File daemon
+ * and acts on them. When a request to append data is made,
+ * it opens a data channel and accepts data from the
+ * File daemon. 
+ * 
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+/* Imported functions */
+
+
+/* Forward referenced functions */
+void terminate_stored(int sig);
+static void check_config();
+static void *director_thread(void *arg);
+
+#define CONFIG_FILE "bacula-sd.conf"  /* Default config file */
+
+
+/* Global variables exported */
+
+
+struct s_shm *shm;                   /* memory shared with children */
+BSHM bshm;                           /* shared memory control packet */
+
+
+/* This is our own global resource */
+static STORES *me;
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static uint32_t VolSessionId = 0;
+uint32_t VolSessionTime;
+
+static char *configfile;
+static int foreground = 0;
+
+static workq_t dird_workq;           /* queue for processing connections */
+static workq_t filed_workq;          /* queue for processing connections */
+
+
+static void usage()
+{
+   fprintf(stderr, _(
+"\nVersion: " VERSION " (" DATE ")\n\n"
+"Usage: stored [-s -f ] [-c config_file] [-d debug_level]  [config_file]\n"
+"        -c <file>   use <file> as configuration file\n"
+"        -dnn        set debug level to nn\n"
+"        -f          run in foreground (for debugging)\n"
+"        -s          no signals (for debugging)\n"
+"        -t          test - read config and exit\n"
+"        -?          print this message.\n"
+"\n"));
+   exit(1);
+}
+
+/********************************************************************* 
+ *
+ *  Main Bacula Unix Storage Daemon
+ *
+ */
+int main (int argc, char *argv[])
+{
+   int ch, i;
+   int no_signals = FALSE;
+   int test_config = FALSE;
+   DEVRES *device;
+   pthread_t dirid;
+   int status;
+
+   init_stack_dump();
+   my_name_is(argc, argv, "stored");
+   daemon_start_time = time(NULL);
+   memset(&last_job, 0, sizeof(last_job));
+
+   /* Sanity checks */
+   if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) {
+      Emsg2(M_ABORT, 0, "Tape block size (%d) not multiple of system size (%d)\n",
+        TAPE_BSIZE, DEV_BSIZE);
+   }
+   if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) {
+      Emsg1(M_ABORT, 0, "Tape block size (%d) is not a power of 2\n", TAPE_BSIZE);
+   }
+
+   while ((ch = getopt(argc, argv, "c:d:fst?")) != -1) {
+      switch (ch) {
+         case 'c':                    /* configuration file */
+           if (configfile != NULL) {
+              free(configfile);
+           }
+           configfile = bstrdup(optarg);
+           break;
+
+         case 'd':                    /* debug level */
+           debug_level = atoi(optarg);
+           if (debug_level <= 0) {
+              debug_level = 1; 
+           }
+           break;
+
+         case 'f':                    /* run in foreground */
+           foreground = TRUE;
+           break;
+
+         case 's':                    /* no signals */
+           no_signals = TRUE;
+           break;
+
+         case 't':
+           test_config = TRUE;
+           break;
+
+         case '?':
+        default:
+           usage();
+
+      }  
+   }
+   argc -= optind;
+   argv += optind;
+
+   if (argc) {
+      if (configfile != NULL) {
+        free(configfile);
+      }
+      configfile = bstrdup(*argv);
+      argc--; 
+      argv++;
+   }
+   if (argc)
+      usage();
+
+   if (!no_signals) {
+      init_signals(terminate_stored);
+   }
+
+
+   if (configfile == NULL) {
+      configfile = bstrdup(CONFIG_FILE);
+   }
+
+   init_msg(NULL);
+   parse_config(configfile);
+   check_config();
+
+   bshm.size = 0;
+   if (test_config) {
+      terminate_stored(0);
+   }
+
+   if (!foreground) {
+      daemon_start();                /* become daemon */
+      init_stack_dump();             /* pick up new pid */
+   }
+
+   /*  ****FIXME**** clean this up */
+   /* Create and attach to shared memory. This is a
+    * hold over from the days of child processes. 
+    * Note, in reality all memory is shared. This
+    * is just a global buffer for the device packets.
+    */
+   shm = (s_shm *) malloc(sizeof(struct s_shm));
+   /* Zero shared memory */
+   memset(shm, 0, sizeof(struct s_shm));
+
+   /* Ensure that Volume Session Time and Id are both
+    * set and are both non-zero.
+    */
+   VolSessionTime = (long)daemon_start_time;
+   if (VolSessionTime == 0) { /* paranoid */
+      Emsg0(M_ABORT, 0, _("Volume Session Time is ZERO!\n"));
+   }
+
+   LockRes();
+   for (device=NULL,i=0;  (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); i++) {
+      if (i >= MAX_DEVICES) {
+        UnlockRes();
+         Emsg1(M_ABORT, 0, _("Too many Device Resources. Max=%d\n"), MAX_DEVICES);
+      }
+      Dmsg1(90, "calling init_dev %s\n", device->device_name);
+      device->dev = init_dev(&shm->dev[i], device->device_name);
+      /* Copy some attributes from the Device Resource to the DEV structure */
+      if (device->dev) {
+        device->dev->capabilities = device->cap_bits;
+        device->dev->min_block_size = device->min_block_size;
+        device->dev->max_block_size = device->max_block_size;
+        device->dev->max_volume_jobs = device->max_volume_jobs;
+        device->dev->max_volume_files = device->max_volume_files;
+        device->dev->max_volume_size = device->max_volume_size;
+        device->dev->max_file_size = device->max_file_size;
+        device->dev->volume_capacity = device->volume_capacity;
+        device->dev->max_rewind_wait = device->max_rewind_wait;
+        device->dev->device = device;
+      }
+      Dmsg1(10, "Init done %s\n", device->device_name);
+      if (!device->dev) {
+         Emsg1(M_ERROR, 0, _("Could not initialize %s\n"), device->device_name);
+      }
+      if (device->cap_bits & CAP_ALWAYSOPEN) {
+         Dmsg1(20, "calling open_device %s\n", device->device_name);
+        if (!open_device(device->dev)) {
+            Emsg1(M_ERROR, 0, _("Could not open device %s\n"), device->device_name);
+        }
+      }
+      if (device->cap_bits & CAP_AUTOMOUNT && device->dev && 
+         device->dev->state & ST_OPENED) {
+        DEV_BLOCK *block;
+        JCR *jcr;
+        block = new_block(device->dev);
+        jcr = new_jcr(sizeof(JCR), stored_free_jcr);
+        switch (read_dev_volume_label(jcr, device->dev, block)) {
+           case VOL_OK:
+              break;
+           default:
+               Emsg1(M_WARNING, 0, _("Could not mount device %s\n"), device->device_name);
+              break;
+        }
+        free_jcr(jcr);
+        free_block(block);
+      }
+   } 
+   UnlockRes();
+   device = NULL;
+
+   init_watchdog();                  /* start watchdog thread */
+
+   /*
+    * Here we support either listening on one port or on two ports
+    */
+   if (me->SDDport == 0 || me->SDDport == me->SDport) {
+      /* Single server used for Director and File daemon */
+      bnet_thread_server(me->SDport, 20, &dird_workq, connection_request);
+   } else {
+      /* Start the Director server */
+      set_thread_concurrency(10);
+      if ((status=pthread_create(&dirid, NULL, director_thread,        
+          (void *)me->SDport)) != 0) {
+         Emsg1(M_ABORT, 0, _("Cannot create Director thread: %s\n"), strerror(status));
+      }
+      /* Start File daemon server */
+      bnet_thread_server(me->SDDport, 10, &filed_workq, connection_from_filed);
+      /* never returns */
+   }
+
+   exit(1);                          /* to keep compiler quiet */
+}
+
+static void *director_thread(void *arg)
+{
+   int dir_port = (int)arg;
+   pthread_detach(pthread_self());
+   bnet_thread_server(dir_port, 10, &dird_workq, connection_request);
+   return NULL;
+}
+
+/* Return a new Session Id */
+uint32_t newVolSessionId()
+{
+   uint32_t Id;
+
+   P(mutex);
+   VolSessionId++;
+   Id = VolSessionId;
+   V(mutex);
+   return Id;
+}
+
+/* Check Configuration file for necessary info */
+static void check_config()
+{
+   struct stat stat_buf; 
+
+   LockRes();
+   me = (STORES *)GetNextRes(R_STORAGE, NULL);
+   if (!me) {
+      UnlockRes();
+      Emsg1(M_ABORT, 0, _("No Storage resource defined in %s. Cannot continue.\n"),
+        configfile);
+   }
+
+   my_name_is(0, (char **)NULL, me->hdr.name);    /* Set our real name */
+
+   if (GetNextRes(R_STORAGE, (RES *)me) != NULL) {
+      UnlockRes();
+      Emsg1(M_ABORT, 0, _("Only one Storage resource permitted in %s\n"), 
+        configfile);
+   }
+   if (GetNextRes(R_DIRECTOR, NULL) == NULL) {
+      UnlockRes();
+      Emsg1(M_ABORT, 0, _("No Director resource defined in %s. Cannot continue.\n"),
+        configfile);
+   }
+   if (GetNextRes(R_DEVICE, NULL) == NULL){
+      UnlockRes();
+      Emsg1(M_ABORT, 0, _("No Device resource defined in %s. Cannot continue.\n"),
+          configfile);
+   }
+
+   UnlockRes();
+
+   if (!me->working_directory) {
+      Emsg1(M_ABORT, 0, _("No Working Directory defined in %s. Cannot continue.\n"),
+        configfile);
+   }
+   if (stat(me->working_directory, &stat_buf) != 0) {
+      Emsg1(M_ABORT, 0, _("Working Directory: %s not found. Cannot continue.\n"),
+        me->working_directory);
+   }
+   if (!S_ISDIR(stat_buf.st_mode)) {
+      Emsg1(M_ABORT, 0, _("Working Directory: %s is not a directory. Cannot continue.\n"),
+        me->working_directory);
+   }
+   working_directory = me->working_directory;
+}
+
+/* Clean up and then exit */
+void terminate_stored(int sig)
+{
+   static int in_here = FALSE;
+   DEVRES *device;
+
+   if (in_here) {                    /* prevent loops */
+      exit(1);
+   }
+   in_here = TRUE;
+
+   term_watchdog();
+
+   Dmsg0(200, "In terminate_stored()\n");
+
+   LockRes();
+   for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
+      if (device->dev) {
+        term_dev(device->dev);
+      }
+   } 
+   UnlockRes();
+
+   if (configfile)
+   free(configfile);
+   free_config_resources();
+
+   if (debug_level > 10)
+      print_memory_pool_stats();
+   close_memory_pool();
+
+   if (shm)
+   free(shm);
+   term_msg();
+
+   sm_dump(False);                   /* dump orphaned buffers */
+   exit(1);
+}
diff --git a/bacula/src/stored/stored.conf.in b/bacula/src/stored/stored.conf.in
new file mode 100644 (file)
index 0000000..6aa82cd
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# Kern's Bacula Storage Daemon Configuration file
+#
+#  For Bacula release @VERSION@ (@DATE@) -- @DISTNAME@ @DISTVER@
+#
+#
+# "Global" Storage daemon configuration specifications
+#
+Storage {
+  Name = "Storage daemon"
+  Address = @hostname@
+  SDPort = @sd_port@                  # Directors port      
+  WorkingDirectory = "@working_dir@"
+  Pid Directory = "@piddir@"
+  Subsys Directory = "@subsysdir@"
+}
+
+#
+# List Directors who are permitted to contact Storage daemon
+#
+Director {
+  Name = @hostname@-dir
+  Password = local_storage_password
+}
+
+#
+# Devices supported by this Storage daemon
+# To connect, the Director must have the same Name and MediaType,
+#  which are sent to the File daemon
+#
+Device {
+  Name = "HP DLT 80"
+  Media Type = DLT8000
+  Archive Device = /dev/nst0
+# LabelMedia = yes;                   # lets Bacula label unlabelled media
+  AutomaticMount = yes;               # when device opened, read it
+  AlwaysOpen = yes;
+  RemovableMedia = yes;
+}
+
+#Device {
+#  Name = "Exabyte 8mm"
+#  Media Type = "8mm"
+#  Archive Device = /dev/nst1
+#  Hardware end of medium = No;
+## LabelMedia = yes;                   # lets Bacula label unlabelled media
+#  AutomaticMount = yes;               # when device opened, read it
+#  AlwaysOpen = Yes;
+#  RemovableMedia = yes;
+#}
+
+Messages {
+  Name = Standard
+  director = @hostname@-dir = all
+  operator = @dump_email@ = mount
+}
diff --git a/bacula/src/stored/stored.h b/bacula/src/stored/stored.h
new file mode 100644 (file)
index 0000000..baa0b40
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Storage daemon specific defines and includes
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#ifndef __STORED_H_
+#define __STORED_H_
+
+#include <sys/mtio.h>
+#include "block.h"
+#include "record.h"
+#include "dev.h"
+#include "stored_conf.h"
+#include "jcr.h"
+#include "protos.h"
+
+/* **** FIXME make this dynamic ****/
+#define MAX_DEVICES 20
+
+/* 
+ * Old shared memory buffer. Shared memory no longer used,
+ *  so this just acts as a global.
+ */
+struct s_shm {
+   long VolSessionId;
+   long VolSessionTime;
+   DEVICE dev[MAX_DEVICES];
+};
+
+extern char errmsg[];                /* general error message */
+
+#endif /* __STORED_H_ */
diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c
new file mode 100644 (file)
index 0000000..7781e8c
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Configuration file parser for Bacula Storage daemon
+ *
+ *     Kern Sibbald, March MM
+ */
+
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+extern int debug_level;
+
+
+/* First and last resource ids */
+int r_first = R_FIRST;
+int r_last  = R_LAST;
+pthread_mutex_t res_mutex =  PTHREAD_MUTEX_INITIALIZER;
+
+
+/* Forward referenced subroutines */
+
+/* We build the current resource here statically,
+ * then move it to dynamic memory */
+URES res_all;
+int res_all_size = sizeof(res_all);
+
+/* Definition of records permitted within each
+ * resource with the routine to process the record 
+ * information.
+ */ 
+
+/* Globals for the Storage daemon. */
+static struct res_items store_items[] = {
+   {"name",                  store_name, ITEM(res_store.hdr.name),   0, ITEM_REQUIRED, 0},
+   {"description",           store_str,  ITEM(res_dir.hdr.desc),     0, 0, 0},
+   {"address",               store_str,  ITEM(res_store.address),    0, ITEM_REQUIRED, 0},
+   {"sdport",                store_int,  ITEM(res_store.SDport),     0, ITEM_REQUIRED, 0},
+   {"sddport",               store_int,  ITEM(res_store.SDDport),    0, 0, 0}, /* depricated */
+   {"workingdirectory",      store_dir,  ITEM(res_store.working_directory), 0, ITEM_REQUIRED, 0},
+   {"piddirectory",          store_dir,  ITEM(res_store.pid_directory), 0, ITEM_REQUIRED, 0},
+   {"subsysdirectory",       store_dir,  ITEM(res_store.subsys_directory), 0, ITEM_REQUIRED, 0},
+   {"maximumconcurrentjobs", store_int,  ITEM(res_store.max_concurrent_jobs), 0, ITEM_DEFAULT, 1},
+   {NULL, NULL, 0, 0, 0, 0} 
+};
+
+
+/* Directors that can speak to the Storage daemon */
+static struct res_items dir_items[] = {
+   {"name",        store_name,     ITEM(res_dir.hdr.name),   0, ITEM_REQUIRED, 0},
+   {"description", store_str,      ITEM(res_dir.hdr.desc),   0, 0, 0},
+   {"password",    store_password, ITEM(res_dir.password),   0, ITEM_REQUIRED, 0},
+   {"address",     store_str,      ITEM(res_dir.address),    0, 0, 0},
+   {NULL, NULL, 0, 0, 0, 0} 
+};
+
+/* Device definition */
+static struct res_items dev_items[] = {
+   {"name",                  store_name,   ITEM(res_dev.hdr.name),        0, ITEM_REQUIRED, 0},
+   {"description",           store_str,    ITEM(res_dir.hdr.desc),        0, 0, 0},
+   {"mediatype",             store_strname,ITEM(res_dev.media_type),      0, ITEM_REQUIRED, 0},
+   {"archivedevice",         store_strname,ITEM(res_dev.device_name),     0, ITEM_REQUIRED, 0},
+   {"hardwareendoffile",     store_yesno,  ITEM(res_dev.cap_bits), CAP_EOF,  ITEM_DEFAULT, 1},
+   {"hardwareendofmedium",   store_yesno,  ITEM(res_dev.cap_bits), CAP_EOM,  ITEM_DEFAULT, 1},
+   {"backwardspacerecord",   store_yesno,  ITEM(res_dev.cap_bits), CAP_BSR,  ITEM_DEFAULT, 1},
+   {"backwardspacefile",     store_yesno,  ITEM(res_dev.cap_bits), CAP_BSF,  ITEM_DEFAULT, 1},
+   {"forwardspacerecord",    store_yesno,  ITEM(res_dev.cap_bits), CAP_FSR,  ITEM_DEFAULT, 1},
+   {"forwardspacefile",      store_yesno,  ITEM(res_dev.cap_bits), CAP_FSF,  ITEM_DEFAULT, 1},
+   {"removablemedia",        store_yesno,  ITEM(res_dev.cap_bits), CAP_REM,  ITEM_DEFAULT, 1},
+   {"randomaccess",          store_yesno,  ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
+   {"automaticmount",        store_yesno,  ITEM(res_dev.cap_bits), CAP_AUTOMOUNT,  ITEM_DEFAULT, 0},
+   {"labelmedia",            store_yesno,  ITEM(res_dev.cap_bits), CAP_LABEL,      ITEM_DEFAULT, 0},
+   {"mountanonymousvolumes", store_yesno,  ITEM(res_dev.cap_bits), CAP_ANONVOLS,   ITEM_DEFAULT, 0},
+   {"alwaysopen",            store_yesno,  ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
+   {"maximumrewindwait",     store_pint,   ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
+   {"minimumblocksize",      store_pint,   ITEM(res_dev.min_block_size), 0, 0, 0},
+   {"maximumblocksize",      store_pint,   ITEM(res_dev.max_block_size), 0, 0, 0},
+   {"maximumvolumejobs",     store_pint,   ITEM(res_dev.max_volume_jobs), 0, 0, 0},
+   {"maximumvolumefiles",    store_int64,  ITEM(res_dev.max_volume_files), 0, 0, 0},
+   {"maximumvolumesize",     store_size,   ITEM(res_dev.max_volume_size), 0, 0, 0},
+   {"maximumfilesize",       store_size,   ITEM(res_dev.max_file_size), 0, 0, 0},
+   {"volumecapacity",        store_size,   ITEM(res_dev.volume_capacity), 0, 0, 0},
+   {NULL, NULL, 0, 0, 0, 0} 
+};
+
+/* Message resource */
+extern struct res_items msgs_items[];
+
+
+/* This is the master resource definition */
+struct s_res resources[] = {
+   {"director",      dir_items,   R_DIRECTOR,  NULL},
+   {"storage",       store_items, R_STORAGE,   NULL},
+   {"device",        dev_items,   R_DEVICE,    NULL},
+   {"messages",      msgs_items,  R_MSGS,      NULL},
+   {NULL,           NULL,        0,           NULL}
+};
+
+
+
+/* Dump contents of resource */
+void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...), void *sock)
+{
+   URES *res = (URES *)reshdr;
+   char buf[MAXSTRING];
+   int recurse = 1;
+   if (res == NULL) {
+      sendit(sock, _("Warning: no %s resource (%d) defined.\n"), res_to_str(type), type);
+      return;
+   }
+   sendit(sock, "dump_resource type=%d\n", type);
+   if (type < 0) {                   /* no recursion */
+      type = - type;
+      recurse = 0;
+   }
+   switch (type) {
+      case R_DIRECTOR:
+         sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
+        break;
+      case R_STORAGE:
+         sendit(sock, "Storage: name=%s address=%s SDport=%d SDDport=%d\n",
+           res->res_store.hdr.name, res->res_store.address, 
+           res->res_store.SDport, res->res_store.SDDport);
+        break;
+      case R_DEVICE:
+         sendit(sock, "Device: name=%s MediaType=%s Device=%s\n",
+           res->res_dev.hdr.name,
+           res->res_dev.media_type, res->res_dev.device_name);
+         sendit(sock, "        rew_wait=%d min_bs=%d max_bs=%d\n",
+           res->res_dev.max_rewind_wait, res->res_dev.min_block_size, 
+           res->res_dev.max_block_size);
+         sendit(sock, "        max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
+           res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
+           res->res_dev.max_volume_size);
+         sendit(sock, "        max_file_size=%" lld " capacity=%" lld "\n",
+           res->res_dev.max_file_size, res->res_dev.volume_capacity);
+         strcpy(buf, "        ");
+        if (res->res_dev.cap_bits & CAP_EOF) {
+            strcat(buf, "CAP_EOF ");
+        }
+        if (res->res_dev.cap_bits & CAP_BSR) {
+            strcat(buf, "CAP_BSR ");
+        }
+        if (res->res_dev.cap_bits & CAP_BSF) {
+            strcat(buf, "CAP_BSF ");
+        }
+        if (res->res_dev.cap_bits & CAP_FSR) {
+            strcat(buf, "CAP_FSR ");
+        }
+        if (res->res_dev.cap_bits & CAP_FSF) {
+            strcat(buf, "CAP_FSF ");
+        }
+        if (res->res_dev.cap_bits & CAP_EOM) {
+            strcat(buf, "CAP_EOM ");
+        }
+        if (res->res_dev.cap_bits & CAP_REM) {
+            strcat(buf, "CAP_REM ");
+        }
+        if (res->res_dev.cap_bits & CAP_RACCESS) {
+            strcat(buf, "CAP_RACCESS ");
+        }
+        if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
+            strcat(buf, "CAP_AUTOMOUNT ");
+        }
+        if (res->res_dev.cap_bits & CAP_LABEL) {
+            strcat(buf, "CAP_LABEL ");
+        }
+        if (res->res_dev.cap_bits & CAP_ANONVOLS) {
+            strcat(buf, "CAP_ANONVOLS ");
+        }
+        if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
+            strcat(buf, "CAP_ALWAYSOPEN ");
+        }
+         strcat(buf, "\n");
+        sendit(sock, buf);
+        break;
+      case R_MSGS:
+         sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
+        break;
+      default:
+         sendit(sock, _("Warning: unknown resource type %d\n"), type);
+        break;
+   }
+   if (recurse && res->res_dir.hdr.next)
+      dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
+}
+
+/* 
+ * Free memory of resource.  
+ * NB, we don't need to worry about freeing any references
+ * to other resources as they will be freed when that 
+ * resource chain is traversed.  Mainly we worry about freeing
+ * allocated strings (names).
+ */
+void free_resource(int type)
+{
+   URES *nres;
+   URES *res;
+   int rindex = type - r_first;
+   res = (URES *)resources[rindex].res_head;
+
+   if (res == NULL)
+      return;
+
+   /* common stuff -- free the resource name */
+   nres = (URES *)res->res_dir.hdr.next;
+   if (res->res_dir.hdr.name)
+      free(res->res_dir.hdr.name);
+
+   switch (type) {
+      case R_DIRECTOR:
+        if (res->res_dir.password)
+           free(res->res_dir.password);
+        if (res->res_dir.address)
+           free(res->res_dir.address);
+        break;
+      case R_STORAGE:
+        if (res->res_store.address)
+           free(res->res_store.address);
+        if (res->res_store.working_directory)
+           free(res->res_store.working_directory);
+        if (res->res_store.pid_directory)
+           free(res->res_store.pid_directory);
+        if (res->res_store.subsys_directory)
+           free(res->res_store.subsys_directory);
+        break;
+      case R_DEVICE:
+        if (res->res_dev.media_type)
+           free(res->res_dev.media_type);
+        if (res->res_dev.device_name)
+           free(res->res_dev.device_name);
+        break;
+      case R_MSGS:
+        if (res->res_msgs.mail_cmd)
+           free(res->res_msgs.mail_cmd);
+        if (res->res_msgs.operator_cmd)
+           free(res->res_msgs.operator_cmd);
+        break;
+      default:
+         Dmsg1(0, "Unknown resource type %d\n", type);
+        break;
+   }
+   /* Common stuff again -- free the resource, recurse to next one */
+   free(res);
+   resources[rindex].res_head = (RES *)nres;
+   if (nres)
+      free_resource(type);
+}
+
+/* Save the new resource by chaining it into the head list for
+ * the resource. If this is pass 2, we update any resource
+ * pointers (currently only in the Job resource).
+ */
+void save_resource(int type, struct res_items *items, int pass)
+{
+   URES *res;
+   int rindex = type - r_first;
+   int i, size;
+   int error = 0;
+
+   /* 
+    * Ensure that all required items are present
+    */
+   for (i=0; items[i].name; i++) {
+      if (items[i].flags & ITEM_REQUIRED) {
+        if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {  
+            Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"),
+             items[i].name, resources[rindex]);
+         }
+      }
+      /* If this triggers, take a look at lib/parse_conf.h */
+      if (i >= MAX_RES_ITEMS) {
+         Emsg1(M_ABORT, 0, _("Too many items in %s resource\n"), resources[rindex]);
+      }
+   }
+
+   /* During pass 2, we looked up pointers to all the resources
+    * referrenced in the current resource, , now we
+    * must copy their address from the static record to the allocated
+    * record.
+    */
+   if (pass == 2) {
+      switch (type) {
+        case R_DIRECTOR:
+        case R_STORAGE:
+        case R_DEVICE:
+        case R_MSGS:
+           break;
+        default:
+            printf("Unknown resource type %d\n", type);
+           error = 1;
+           break;
+      }
+      if (res_all.res_dir.hdr.name) {
+        free(res_all.res_dir.hdr.name);
+        res_all.res_dir.hdr.name = NULL;
+      }
+      if (res_all.res_dir.hdr.desc) {
+        free(res_all.res_dir.hdr.desc);
+        res_all.res_dir.hdr.desc = NULL;
+      }
+      return;
+   }
+
+   switch (type) {
+      case R_DIRECTOR:
+        size = sizeof(DIRRES);
+        break;
+      case R_STORAGE:
+        size = sizeof(STORES);
+        break;
+      case R_DEVICE:
+        size = sizeof(DEVRES);
+        break;
+      case R_MSGS:
+        size = sizeof(MSGS);   
+        break;
+      default:
+         printf("Unknown resource type %d\n", type);
+        error = 1;
+        break;
+   }
+   /* Common */
+   if (!error) {
+      res = (URES *) malloc(size);
+      memcpy(res, &res_all, size);
+      res->res_dir.hdr.next = resources[rindex].res_head;
+      resources[rindex].res_head = (RES *)res;
+   }
+}
diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h
new file mode 100644 (file)
index 0000000..7855a39
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Resource codes -- they must be sequential for indexing   
+ */
+/*
+   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+   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.
+
+ */
+
+#define R_FIRST                       3001
+
+#define R_DIRECTOR                    3001
+#define R_STORAGE                     3002
+#define R_DEVICE                      3003
+#define R_MSGS                        3004
+
+#define R_LAST                        R_MSGS
+
+
+#define R_NAME                        3020
+#define R_ADDRESS                     3021
+#define R_PASSWORD                    3022
+#define R_TYPE                        3023
+#define R_BACKUP                      3024
+
+#define STORAGE_DAEMON 1
+
+/* Definition of the contents of each Resource */
+struct s_res_dir {
+   RES   hdr;
+
+   char *password;                    /* Director password */
+   char *address;                     /* Director IP address or zero */
+};
+typedef struct s_res_dir DIRRES;
+
+
+/* Storage daemon "global" definitions */
+struct s_res_store {
+   RES   hdr;
+
+   char *address;
+   int   SDport;                      /* Where we listen for Directors */
+   int   SDDport;                     /* "Data" port where we listen for File daemons */
+   char *working_directory;           /* working directory for checkpoints */
+   char *pid_directory;
+   char *subsys_directory;
+   uint32_t max_concurrent_jobs;      /* maximum concurrent jobs to run */
+};
+typedef struct s_res_store STORES;
+
+/* Device specific definitions */
+struct s_res_dev {
+   RES   hdr;
+
+   char *media_type;
+   char *device_name;
+   int  cap_bits;
+   uint32_t max_rewind_wait;          /* maximum secs to wait for rewind */
+   uint32_t min_block_size;           /* min block size */
+   uint32_t max_block_size;           /* max block size */
+   uint32_t max_volume_jobs;          /* max jobs to put on one volume */
+   int64_t max_volume_files;          /* max files to put on one volume */
+   int64_t max_volume_size;           /* max bytes to put on one volume */
+   int64_t max_file_size;             /* max file size in bytes */
+   int64_t volume_capacity;           /* advisory capacity */
+   DEVICE *dev;
+};
+typedef struct s_res_dev DEVRES;
+
+union u_res {
+   struct s_res_dir     res_dir;
+   struct s_res_store   res_store;
+   struct s_res_dev     res_dev;
+   struct s_res_msgs    res_msgs;
+   RES hdr;
+};
+typedef union u_res URES;
diff --git a/bacula/src/version.h b/bacula/src/version.h
new file mode 100644 (file)
index 0000000..1b38e64
--- /dev/null
@@ -0,0 +1,11 @@
+/* */
+#define VERSION "1.18"
+#define VSTRING "1"
+#define DATE    "22 April 2002"
+#define LSMDATE "22Apr02"
+
+/* Debug flags */
+#define DEBUG 1
+#define TRACEBACK 1
+#define SMCHECK 1
+/*  #define DEBUG_MUTEX 1 */