--- /dev/null
+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.
+
--- /dev/null
+/*
+ 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.
+ */
--- /dev/null
+
+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
--- /dev/null
+--------------------------------------------------------------------------
+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
--- /dev/null
+#
+#
+@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
+
+# ------------------------------------------------------------------------
--- /dev/null
+
+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.
+
--- /dev/null
+# 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
+#-------------------------------------------------------------------------
--- /dev/null
+/* ------------------------------------------------------------------------- */
+/* -- 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
--- /dev/null
+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)
+])
+
--- /dev/null
+#! /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
--- /dev/null
+/* 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
--- /dev/null
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
--- /dev/null
+#! /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
--- /dev/null
+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}
+
+ "
--- /dev/null
+# 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:
--- /dev/null
+## 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
--- /dev/null
+# 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:
--- /dev/null
+# 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
+])
--- /dev/null
+#!/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
--- /dev/null
+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
+])
--- /dev/null
+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
+])
+
+
+
+
+
--- /dev/null
+# 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")
+])
--- /dev/null
+# 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"
+])
+
--- /dev/null
+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)
+])
--- /dev/null
+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])
+])
--- /dev/null
+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)
+])
--- /dev/null
+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
+])
--- /dev/null
+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)
+])
+
--- /dev/null
+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)
+])
--- /dev/null
+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)
+])
--- /dev/null
+# 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)])
+])
--- /dev/null
+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])
+])
--- /dev/null
+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)
+])
--- /dev/null
+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
+])
--- /dev/null
+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
+])
+
+
--- /dev/null
+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])
+])
--- /dev/null
+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)
+])
--- /dev/null
+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)
+])
--- /dev/null
+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
+
+])
--- /dev/null
+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)
+])
--- /dev/null
+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
+]
+)
--- /dev/null
+#! /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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#! /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}
+
+ "
--- /dev/null
+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.
--- /dev/null
+# 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:
--- /dev/null
+GNU gettext library from gettext-0.10.35
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+# 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
--- /dev/null
+/* 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));
--- /dev/null
+/* 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
--- /dev/null
+/* 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
+}
--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+/* 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
--- /dev/null
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+
+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.
--- /dev/null
+#
+# 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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+#!/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
--- /dev/null
+#
+# 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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+#
+# 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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+#
+# 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
--- /dev/null
+# 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:
--- /dev/null
+# 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:
--- /dev/null
+# List of source files containing translatable strings.
+
+src/main.c
+src/interface.c
+src/callbacks.c
+src/support.c
--- /dev/null
+# 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 ""
--- /dev/null
+/* 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;
--- /dev/null
+--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
--- /dev/null
+#
+#
+@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:
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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.
+
+ */
--- /dev/null
+l Copyright (C)
+-1
+mark
+l */
+mark
+db
+inc /home/kern/bacula/k/src/c
+e
--- /dev/null
+#
+@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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#!/bin/sh
+#
+# shell script to invoke SQLite on Bacula database
+
+@bindir@/sqlite @working_dir@/bacula.db
--- /dev/null
+<?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>
--- /dev/null
+@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
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#
+# 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
--- /dev/null
+
+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;
+
+
+
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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");
+}
--- /dev/null
+#
+# 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
+}
--- /dev/null
+/*
+ *
+ * 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));
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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;
+ }
+ }
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+: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;
--- /dev/null
+/*
+ *
+ * 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");
+}
--- /dev/null
+/*
+ *
+ * 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);
+}
--- /dev/null
+/*
+ *
+ * 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");
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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");
+}
--- /dev/null
+/*
+ *
+ * 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;
+ }
+}
--- /dev/null
+@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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#
+# 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
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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? */
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ 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);
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#
+# 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) $<
--- /dev/null
+1 ICON "apcupsd.ico"
--- /dev/null
+cd c:\bacula\bin
+c:\bacula\bin\bacula-fd.exe /install -c c:\bacula\bin\bacula-fd.conf
--- /dev/null
+cd c:\bacula\bin
+c:\bacula\bin\bacula-fd.exe /service -c c:\bacula\bin\bacula-fd.conf
--- /dev/null
+cd c:\bacula\bin
+c:\bacula\bin\bacula-fd.exe /kill
--- /dev/null
+cd c:\bacula\bin
+c:\bacula\bin\bacula-fd.exe /remove
--- /dev/null
+#!/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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+// 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+#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
--- /dev/null
+// 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);
+ }
+}
--- /dev/null
+// 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+
+ 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+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
--- /dev/null
+#!/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
+------------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+# $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
--- /dev/null
+/*
+
+ 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/* 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_ */
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ 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! */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+
+/* 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+#!/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
--- /dev/null
+/* 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 */
--- /dev/null
+/*
+ * 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
+*/
--- /dev/null
+/* 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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"
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ 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,...);
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+
+ 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
+}
--- /dev/null
+/*
+ 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);
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+
+ 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;
+}
--- /dev/null
+
+
+/*
+ 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_ */
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+
+ 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
--- /dev/null
+/*
+
+ 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
--- /dev/null
+ /*
+ * @(#) 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
--- /dev/null
+/*
+ * 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
+
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+# $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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#
+# 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
+}
--- /dev/null
+/*
+ *
+ * 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);
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ *
+ * 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);
+}
--- /dev/null
+/*
+ *
+ * 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);
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ *
+ * 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 */
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ *
+ * 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 */
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#
+# 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
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/* */
+#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 */